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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
`define RST 5'b00000
`define GetA 5'b00001
`define GetB 5'b00010
`define operation 5'b00011
`define WriteReg 5'b00100
`define GetACMP 5'b00101
`define GetBCMP 5'b00110
`define GetBonly 5'b00111
`define IF1 5'b01000
`define IF2 5'b01001
`define UpdatePC 5'b01010
`define GetAddr 5'b01011
`define LoadAddr 5'b01100
`define StoreAddr 5'b01101
`define Dout 5'b01110
`define Dout2 5'b01111
`define Dout3 5'b10000
`define Dout4 5'b10001
`define MNONE 2'b00
`define MREAD 2'b01
`define MWRITE 2'b10
module cpu(clk,reset,read_data,write_data,mem_addr,mem_cmd,N,V,Z);
input clk, reset;
input [15:0] read_data;
output reg [15:0] write_data;
output reg [8:0] mem_addr;
output reg [1:0] mem_cmd;
output reg N, V, Z;
reg [15:0] inst_reg = 16'bx;
reg [15:0] next_inst_reg, datapath_out;
reg [2:0] opcode, readnum, writenum, Z_out;
reg [1:0] op, nsel, shift, ALUop, vsel;
reg loada, loadb, loadc, loads, write, asel, bsel,
load_ir, load_pc, reset_pc, addr_sel, load_addr;
reg [15:0] sximm8;
reg [15:0] sximm5;
reg [4:0] present_state;
reg [15:0] mdata;
reg [8:0] PC, next_pc = 9'b0;
reg [8:0] data_addr, next_data_addr;
//three more internal wires
//later change some of these to wires to make less expensive
datapath DP(clk, readnum, vsel, loada, loadb, shift, asel, bsel, ALUop,
loadc, loads, writenum, write, Z_out, datapath_out, sximm5, sximm8, mdata);
//if nsel == 00 -> rm nsel == 01 -> rd, nsel == 10 -> rn
always_comb begin
{opcode, op} = inst_reg[15:11]; //decodin like crazy here
if (opcode == 3'b100) shift = 2'b00;
else shift = inst_reg[4:3];
sximm5 = {{11{inst_reg[4]}}, inst_reg[4:0]};
sximm8 = {{8{inst_reg[7]}} , inst_reg[7:0]}; //fix this back
ALUop = op;
case (nsel)
2'b00: {readnum, writenum} = {2{inst_reg[2:0]}}; //Rm
2'b01: {readnum, writenum} = {2{inst_reg[7:5]}}; //Rd
2'b10: {readnum, writenum} = {2{inst_reg[10:8]}}; //Rn
default: {readnum, writenum} = {writenum, readnum};
endcase
{Z, V, N} = Z_out; //give out all values
write_data = datapath_out;
mdata = read_data;
next_inst_reg = load_ir ? read_data : inst_reg; //load for instructions
next_pc = reset_pc ? 9'b0 : (PC + 1'b1);
mem_addr = addr_sel ? PC : data_addr;
next_data_addr = load_addr ? datapath_out[8:0] : data_addr;
end
// next: first, second and third bit: nsel, second bit loada, third bit loadB, fouth bit asel,
// fifth bit bsel, sixth and 7th bit shift, 8th and 9th bit aluop, 10th bit loadc, 11bit vsel,
// 12bit write
always_ff @(posedge clk) begin
inst_reg = next_inst_reg;
data_addr = next_data_addr;
if (load_pc) PC = next_pc;
casex ({present_state, reset})
//all roads lead to rome (`wait)
{4'bxxxx, 1'b1} : {present_state, write, load_pc, reset_pc, load_ir} = {`RST, 4'b0110};
{`RST, 1'b0} : {present_state, write, addr_sel, load_pc, reset_pc, mem_cmd} = {`IF1, 4'b0100, `MREAD};
{`IF1, 1'b0} : {present_state, load_ir} = {`IF2, 1'b1};
{`IF2, 1'b0} : {present_state, addr_sel, load_pc, load_ir, mem_cmd} = {`UpdatePC, 3'b010, `MNONE};
//make IF1 states+, last state before below is UpdatePC
{`UpdatePC, 1'b0} : begin
casex ({opcode, op}) //op since ALUop == op
//move instructions
5'b11010: {present_state, nsel, vsel, write, load_pc} = {`WriteReg, 6'b101010}; // 2 clk cycles
5'b11000: {present_state, nsel, loada, loadb, load_pc} = {`GetBonly, 5'b00010}; // 3 clk cycles
//alu instructions
5'b101x0: {present_state, nsel, loada, load_pc} = {`GetA, 4'b1010}; //ADD & AND ---> 4 clk cycles //loads A
5'b10101: {present_state, nsel, loada, load_pc} = {`GetACMP, 4'b1010}; //CMP ---> 3 clk cycles //loads A
5'b10111: {present_state, nsel, loada, loadb, load_pc} = {`GetBonly, 5'b00010}; //MVN ---> 3 clk cycles //loads to B
//memory instructions
5'b01100: {present_state, nsel, loada, loadb, asel, bsel, load_pc, mem_cmd} = {`GetAddr, 7'b1010010, `MREAD}; //LDR
5'b10000: {present_state, nsel, loada, loadb, asel, bsel, load_pc} = {`GetAddr, 7'b1010010}; //STR
//HALT instruction
5'b111xx: {present_state, load_pc} = {`UpdatePC, 1'b0}; //will be stuck here until reset
endcase
end
//ADD & AND branch
{`GetA, 1'b0} : {present_state, nsel, loadb, loada} = {`GetB, 4'b0010}; //loads B
{`GetB, 1'b0} : {present_state, asel, bsel, loadc, loads} = {`operation, 4'b0010}; //performs operations
//for writing only from B to Rd
{`GetBonly, 1'b0} : {present_state, asel, bsel, loadc, loads} = {`operation, 4'b1010};
//Get the (shifted) memory address (LDR)
{`GetAddr, 1'b0} : begin
case (opcode)
3'b011: {present_state, loada, loadb, loadc, load_addr, addr_sel, mem_cmd} = {`Dout, 5'b00110, `MREAD}; //might need an extra state for dout
3'b100: {present_state, loada, loadb, loadc, load_addr, addr_sel} = {`StoreAddr, 5'b00110};
endcase
end
{`Dout, 1'b0} : begin //wait for RAM
case (opcode)
3'b011: present_state = `Dout2;
3'b100: {present_state, loada, loadb, loadc, load_addr, mem_cmd} = {`Dout4, 4'b0010, `MWRITE};
endcase
end
{`Dout2, 1'b0} : {present_state, load_addr} = {`LoadAddr, 1'b0};
{`LoadAddr, 1'b0} : {present_state, nsel, vsel, write, loadc, load_addr, mem_cmd} = {`Dout3, 7'b0111100, `MREAD};
{`Dout3, 1'b0} : {present_state, mem_cmd, write} = {`WriteReg, `MNONE, 1'b0};
{`StoreAddr, 1'b0} : {present_state, nsel, loada, loadb, asel, bsel, load_addr} = {`Dout, 7'b0101101};
{`Dout4, 1'b0} : {present_state, write} = {`WriteReg, 1'b0};
//CMP branch
{`GetACMP, 1'b0} : {present_state, nsel, loadb, loada} = {`GetBCMP, 4'b0010}; //loads B
{`GetBCMP, 1'b0} : {present_state, asel, bsel, loadc, loads} = {`WriteReg, 4'b0001}; //performs operations and writes into status
//write to Rd
{`operation, 1'b0} : {present_state, nsel, vsel, write} = {`WriteReg, 5'b01001}; //writing into the register
//waiter/reset
{`WriteReg, 1'b0} : {present_state, loada, loadb, loadc, loads, mem_cmd} = {`RST, 4'b0000, `MNONE}; //extra cycle for values to got through (should I go reset or IF1)
endcase
end
endmodule
|