Blob


1 // Control Word
2 `define BIT_MEM_EN 0
3 `define BIT_PC_INC 1
4 `define BIT_ACC_WR 2
5 `define BIT_ACC_EN 3
6 `define BIT_LOAD_INSTR 4
7 `define BIT_MAR_WR 5
8 `define BIT_REG_WR 6
9 `define BIT_ALU_EN 7
10 `define BIT_PC_EN 8
11 `define BIT_MAR_EN 9
12 `define BIT_MEM_WR 10
13 `define BIT_PC_WR 11
14 `define BIT_FLAGS_WR 12
15 `define BIT_TIMER_RST 14
16 `define BIT_HLT 15
18 // Flags
19 `define BIT_ZERO 0
20 `define BIT_CARRY 1
22 `define MEM_EN (16'b1 << `BIT_MEM_EN)
23 `define PC_INC (16'b1 << `BIT_PC_INC)
24 `define ACC_WR (16'b1 << `BIT_ACC_WR)
25 `define ACC_EN (16'b1 << `BIT_ACC_EN)
26 `define MAR_WR (16'b1 << `BIT_MAR_WR)
27 `define LOAD_INSTR (16'b1 << `BIT_LOAD_INSTR)
28 `define REG_WR (16'b1 << `BIT_REG_WR)
29 `define ALU_EN (16'b1 << `BIT_ALU_EN)
30 `define PC_EN (16'b1 << `BIT_PC_EN)
31 `define MAR_EN (16'b1 << `BIT_MAR_EN)
32 `define MEM_WR (16'b1 << `BIT_MEM_WR)
33 `define PC_WR (16'b1 << `BIT_PC_WR)
34 `define FLAGS_WR (16'b1 << `BIT_FLAGS_WR)
35 `define TIMER_RST (16'b1 << `BIT_TIMER_RST)
36 `define HLT (16'b1 << `BIT_HLT)
38 `define ZERO (4'b1 << `BIT_ZERO)
39 `define CARRY (4'b1 << `BIT_CARRY)
41 module ProgramCounter(
42 inout [11:0] addr,
43 input inc,
44 input en,
45 input wr,
46 input clk,
47 input rst
48 );
50 reg [11:0] value = 0;
52 always@ (posedge clk or posedge rst)
53 begin
54 if (rst)
55 value <= 0;
56 else if (wr && !en)
57 value <= addr;
58 else if (inc)
59 value <= value + 1;
60 end
62 assign addr = en && !wr ? value : 12'hzzz;
64 endmodule // ProgramCounter
66 module Register(
67 output reg [7:0] data_out = 0,
68 input [7:0] data_in,
69 input wr,
70 input clk,
71 input rst
72 );
74 always@ (posedge clk or posedge rst)
75 begin
76 if (rst)
77 data_out <= 0;
78 else if (wr)
79 data_out <= data_in;
80 end
82 endmodule // Register
84 module Accumulator(
85 inout [7:0] bus,
86 output [7:0] out,
87 input clk,
88 input rst,
89 input wr,
90 input en
91 );
93 reg [7:0] value = 0;
96 always@ (posedge clk or posedge rst)
97 begin
98 if (rst)
99 value <= 0;
100 else if (wr && !en)
101 value <= bus;
102 end
104 assign out = value;
105 assign bus = (!wr && en) ? value : 8'hzz;
106 endmodule // Accumulator
108 module InstructionDecoder(
109 input [3:0] timer,
110 input [7:0] instr,
111 input clk,
112 output reg [`BIT_HLT:0] control_word
113 );
114 wire [`BIT_HLT:0] cw_instr [15:0] [15:2];
116 // hlt
117 assign cw_instr[4'b0000][4'b0010] = `HLT;
119 // lda imm8
120 assign cw_instr[4'b0001][4'b0010] = `PC_EN | `MEM_EN | `ACC_WR;
121 assign cw_instr[4'b0001][4'b0011] = `PC_INC | `TIMER_RST;
123 // alu imm8
124 assign cw_instr[4'b0010][4'b0010] = `PC_EN | `MEM_EN | `REG_WR;
125 assign cw_instr[4'b0010][4'b0011] = `PC_INC | `ALU_EN | `ACC_WR | `TIMER_RST;
127 // rb imm12
128 assign cw_instr[4'b0011][4'b0010] = `PC_EN | `MEM_EN | `MAR_WR;
129 assign cw_instr[4'b0011][4'b0011] = `PC_INC | `MAR_EN | `MEM_EN | `ACC_WR | `TIMER_RST;
131 // wb imm12
132 assign cw_instr[4'b0100][4'b0010] = `PC_EN | `MEM_EN | `MAR_WR;
133 assign cw_instr[4'b0100][4'b0011] = `PC_INC | `MAR_EN | `MEM_WR | `ACC_EN | `TIMER_RST;
135 // jmp imm12
136 assign cw_instr[4'b0101][4'b0010] = `PC_EN | `MEM_EN | `MAR_WR;
137 assign cw_instr[4'b0101][4'b0011] = `MAR_EN | `PC_WR | `TIMER_RST;
139 always@ (negedge clk)
140 case (timer)
141 4'b0000: control_word <= `PC_EN | `MEM_EN | `LOAD_INSTR;
142 4'b0001: control_word <= `PC_INC;
143 default: control_word <= cw_instr[instr[7:4]][timer];
144 endcase
146 endmodule // InstructionDecoder
148 module ALU(
149 input [7:0] in_a,
150 input [7:0] in_b,
151 input [3:0] funct,
152 input [3:0] flags_in,
153 output [7:0] out,
154 output [3:0] flags_out,
155 input en
156 );
157 reg [8:0] result;
159 always@ (*)
160 begin
161 case (funct)
162 4'b0000: result = in_a + in_b;
163 4'b0001: result = in_a - in_b;
164 4'b0010: result = { 1'b0, in_a & in_b };
165 4'b0011: result = { 1'b0, in_a | in_b };
166 4'b0100: result = { 1'b0, in_a ^ in_b };
167 4'b0101: result = { 1'b0, in_a << in_b };
168 4'b0110: result = { 1'b0, in_a >> in_b };
169 4'b0111: result = { 1'b0, in_a >>> in_b };
170 default: result = 9'bx;
171 endcase
172 end
174 assign flags_out[`BIT_ZERO] = result[7:0] == 0;
175 assign flags_out[`BIT_CARRY] = result[8];
176 assign out = en ? result[7:0] : 8'bz;
177 endmodule // ALU
179 module CPU(
180 output [11:0] addr_out,
181 inout [7:0] bus,
182 output [7:0] debug,
183 output mem_wr,
184 output mem_en,
185 output reg hlt = 0,
186 input clk,
187 input rst
188 );
189 wire [`BIT_HLT:0] control_word;
190 wire [7:0] instr;
191 wire [7:0] alu_in_a;
192 wire [7:0] alu_in_b;
193 wire [3:0] flags_alu;
194 reg [3:0] timer = 0;
195 reg [11:0] mar;
196 reg [3:0] flags;
198 assign debug = instr;
200 ProgramCounter _pc(
201 .addr(addr_out),
202 .inc(control_word[`BIT_PC_INC]),
203 .en(control_word[`BIT_PC_EN]),
204 .wr(control_word[`BIT_PC_WR]),
205 .clk(clk),
206 .rst(rst)
207 );
209 Register _ireg(
210 .data_in(bus),
211 .data_out(instr),
212 .wr(control_word[`BIT_LOAD_INSTR]),
213 .clk(clk),
214 .rst(rst)
215 );
217 InstructionDecoder _idec(
218 .instr(instr),
219 .clk(clk),
220 .timer(timer),
221 .control_word(control_word)
222 );
224 Accumulator _acc(
225 .bus(bus),
226 .out(alu_in_a),
227 .clk(clk),
228 .rst(rst),
229 .wr(control_word[`BIT_ACC_WR]),
230 .en(control_word[`BIT_ACC_EN])
231 );
233 Register _reg(
234 .data_in(bus),
235 .data_out(alu_in_b),
236 .clk(clk),
237 .rst(rst),
238 .wr(control_word[`BIT_REG_WR])
239 );
241 ALU _alu(
242 .in_a(alu_in_a),
243 .in_b(alu_in_b),
244 .funct(instr[3:0]),
245 .out(bus),
246 .flags_in(flags),
247 .flags_out(flags_alu),
248 .en(control_word[`BIT_ALU_EN])
249 );
251 assign addr_out = control_word[`BIT_MAR_EN] ? mar : 12'hzzz;
252 assign mem_wr = control_word[`BIT_MEM_WR];
253 assign mem_en = control_word[`BIT_MEM_EN];
255 always@ (posedge clk or posedge rst)
256 if (rst)
257 flags <= 0;
258 else if (control_word[`BIT_FLAGS_WR])
259 flags <= flags_alu;
261 always@ (posedge clk or posedge rst)
262 if (rst)
263 hlt <= 0;
264 else if (control_word[`BIT_HLT])
265 hlt <= 1;
267 always@ (posedge clk)
268 if (control_word[`BIT_MAR_WR])
269 mar <= { instr[3:0], bus };
271 always@ (posedge clk or posedge rst)
272 if (rst)
273 timer <= 0;
274 else if (control_word[`BIT_TIMER_RST])
275 timer <= 0;
276 else
277 timer <= timer + 1;
278 endmodule // CPU