forked from ColeTynan/cse141Lfinal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CPU.v
131 lines (110 loc) · 3.76 KB
/
CPU.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Module Name: CPU
// Project Name: CSE141L
//
// Revision Fall 2020
// Based on SystemVerilog source code provided by John Eldon
// Comment:
// This is the TopLevel of your project
// Testbench will create an instance of your CPU and test it
// You may add a LUT if needed
// Set ack to 1 to alert testbench that your CPU finishes doing a program or all 3 programs
module CPU(reset, start, clk, ack);
input reset; // init/reset, active high
input start; // start next program
input clk; // clock -- posedge used inside design
output reg ack; // done flag from DUT
wire [ 10:0] pgm_ctr; // program counter
wire [5:0] pc_targ;
wire [ 8:0] instruction; // our 9-bit instruction
wire [ 2:0] instr_opcode; // out 3-bit opcode
wire [ 7:0] read_a, read_b; // reg_file outputs
wire [ 7:0] in_a, in_b, // ALU operand inputs
ALU_out; // ALU result
wire [ 7:0] reg_write_value, // data in to reg file
mem_write_value, // data in to data_memory
mem_read_value; // data out from data_memory
wire mem_write, // data_memory write enable
reg_wr_en, // reg_file write enable
zero, // ALU output = 0 flag
branch_en, // to program counter: branch enable
load_inst,
immed;
reg [15:0] cycle_ct; // standalone; NOT PC!
wire [7:0]imm_val;
// Fetch = Program Counter + instruction ROM
// Program Counter
InstFetch IF1 (
.reset (reset ) ,
.start (start ) ,
.clk (clk ) ,
.branch_en (branch_en) , // branch enable
.ALU_flag (zero ) ,
.target (pc_targ ) ,
.prog_ctr (pgm_ctr ) // program count = index to instruction memory
);
// Control decoder
Ctrl Ctrl1 (
.instruction (instruction), // from instr_ROM
.branch_en (branch_en), // to PC
.ld_inst (load_inst),
.wrt_reg (reg_wr_en),
.wrt_mem (mem_write),
.immed (immed)
);
assign pc_targ = instruction[5:0]; //NOTE: Sign extend instead??
// instruction ROM
InstROM IR1(
.inst_address (pgm_ctr),
.inst_out (instruction)
);
always@(pgm_ctr, instr_opcode) begin
ack = (instr_opcode == 3'b0) ? 1'b1 : 1'b0;
end
assign imm_val[7:0] = {{5{instruction[2]}}, instruction[2:0]};
//Reg file
// Modify D = *Number of bits you use for each register*
// Width of register is 8 bits, do not modify
RegFile #(.W(8),.D(3)) RF1 (
.clk (clk),
.write_en (reg_wr_en),
.branch_en (branch_en),
.reset(reset),
.r_addr_a (instruction[5:3]),
.r_addr_b (instruction[2:0]),
.w_addr (instruction[5:3]),
.data_in (reg_write_value) ,
.data_out_a (read_a ) ,
.data_out_b (read_b )
);
assign imm_val = {{5{instruction[2]}}, instruction[2:0]};
//muxes
assign in_a = read_a; // connect RF out to ALU in
assign in_b = immed ? imm_val : read_b; //2:1 switch for immediate versus register out
assign instr_opcode = instruction[8:6];
assign reg_write_value = load_inst ? mem_read_value : ALU_out; // 2:1 switch into reg_file
assign mem_write_value = read_a;
// Arithmetic Logic Unit
ALU ALU1(
.input_a(in_a),
.input_b(in_b),
.OP(instr_opcode),
.out(ALU_out),
.zero(zero)
);
// Data Memory
DataMem DM1(
.data_address (read_b) ,
.write_en (mem_write),
.data_in (mem_write_value),
.data_out (mem_read_value) ,
.clk (clk) ,
.reset (reset)
);
// count number of instructions executed
// Help you with debugging
always @(posedge clk)
if (start == 1) // if(start)
cycle_ct <= 0;
else if(ack == 0) // if(!halt)
cycle_ct <= cycle_ct+16'b1;
endmodule