forked from osresearch/risc8
-
Notifications
You must be signed in to change notification settings - Fork 0
/
risc8-alu.v
313 lines (294 loc) · 5.77 KB
/
risc8-alu.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/*
* Combinatorial 8-bit ALU
*
* This implements a simple 8-bit ALU with status register flags,
* as definied in the AVR instruction datasheet.
*
* Ra can be 8 or 16-bits, Rb is only 8 bits.
*/
`ifndef _risc8_alu_v_
`define _risc8_alu_v_
`define OP_MOVE 4'h0 // Copy the input Ra word to the output
`define OP_MOVR 4'h1 // Copy the input Rb byte to the output
`define OP_ADD 4'h2
`define OP_SUB 4'h3
`define OP_ADW 4'h4
`define OP_SBW 4'h5 // must be OP_ADW | 1
`define OP_NEG 4'h6
`define OP_SWAP 4'h7
`define OP_ASR 4'h8
`define OP_ROR 4'h9 // must be OP_ASR | 1
`define OP_LSR 4'hA
`define OP_AND 4'hB
`define OP_EOR 4'hC
`define OP_OR 4'hD
`define OP_SREG 4'hE // Update the SREG flags, uses carry input for set/clear
`define OP_MUL 4'hF // optional
// If not every status register bit is required,
// they can be toggled off here.
//`define CONFIG_SREG_SI
//`define CONFIG_SREG_ST
//`define CONFIG_SREG_SH
`define CONFIG_SREG_SS
`define CONFIG_SREG_SV
`define CONFIG_SREG_SN
`define CONFIG_SREG_SZ
`define CONFIG_SREG_SC
// And if some ALU operations are not required
// they can also be turned off.
`define CONFIG_OP_ADD
`define CONFIG_OP_SUB
`define CONFIG_OP_ADW_OR_SBW
`define CONFIG_OP_SBW
`define CONFIG_OP_NEG
`define CONFIG_OP_SWAP
`define CONFIG_OP_ASR_OR_ROR
`define CONFIG_OP_LSR
`define CONFIG_OP_AND
`define CONFIG_OP_EOR
`define CONFIG_OP_OR
`define CONFIG_OP_SREG
//`define CONFIG_OP_MUL
module risc8_alu(
input clk,
input reset,
input [15:0] Rd_in, // Might be a word register
input [7:0] Rr_in,
input [7:0] sreg_in, // carry in
input [3:0] op,
input use_carry,
input [7:0] keep_sreg,
output [15:0] R_out, // full word output register
output [7:0] sreg_out
);
reg [7:0] R;
reg [7:0] Rh;
assign R_out = { Rh, R };
wire [7:0] Rr = Rr_in;
wire [7:0] Rd = Rd_in[7:0]; // default is operate on only the bottom byte
reg SI, ST, SH, SS, SV, SN, SZ, SC;
assign sreg_out = {
`ifdef CONFIG_SREG_SI
SI,
`else
1'b0,
`endif
`ifdef CONFIG_SREG_ST
ST,
`else
1'b0,
`endif
`ifdef CONFIG_SREG_SH
SH,
`else
1'b0,
`endif
`ifdef CONFIG_SREG_SS
SS,
`else
1'b0,
`endif
`ifdef CONFIG_SREG_SV
SV,
`else
1'b0,
`endif
`ifdef CONFIG_SREG_SN
SN,
`else
1'b0,
`endif
`ifdef CONFIG_SREG_SZ
SZ,
`else
1'b0,
`endif
`ifdef CONFIG_SREG_SC
SC
`else
1'b0
`endif
};
// helpers for computing sreg updates
wire Rd3 = Rd[3];
wire Rd7 = Rd[7];
wire Rdh7 = Rd_in[15];
wire Rr3 = Rr[3];
wire Rr7 = Rr[7];
wire R3 = R_out[3];
wire R7 = R_out[7];
wire R15 = R_out[15];
wire C = sreg_in[0];
wire opt_C = use_carry ? C : 0; // Optional Carry
wire R_zero = R == 0;
always @(*) begin
{Rh, R} = Rd_in;
{ SI, ST, SH, SS, SV, SN, SZ, SC } = sreg_in;
(* fullcase *)
case(op)
`OP_MOVE: begin
// Default will copy {R,Rh} <= Rd
// Do not modify any SREG
end
`OP_MOVR: begin
// Copy the Rb input byte to the output
// Do not modify any SREG
Rh = 0;
R = Rr;
end
`ifdef CONFIG_OP_ADD
`OP_ADD: begin
R = Rd + Rr + opt_C;
SH = (Rd3 & Rr3) | (Rr3 & !R3) | (!R3 & Rd3);
SV = (Rd7 & Rr7 & !R7) | (!Rd7 & !Rr7 & R7);
SC = (Rd7 & Rr7) | (Rr7 & !R7) | (!R7 & Rd7);
SN = R7;
SS = SN^SV;
SZ = R_zero;
end
`endif
`ifdef CONFIG_OP_SUB
`OP_SUB: begin
R = Rd - Rr - opt_C;
SH = (!Rd3 & Rr3) | (Rr3 & R3) | (R3 & !Rd3);
SV = (Rd7 & !Rr7 & !R7) | (!Rd7 & Rr7 & R7);
SC = (!Rd7 & Rr7) | (Rr7 & R7) | (R7 & !Rd7);
SN = R7;
SS = SN^SV;
// SBC clears flag when result is non-zero, and keeps previous value otherwise
if(!use_carry || !R_zero)
SZ = R_zero;
end
`endif
`ifdef CONFIG_OP_ADW_OR_SBW
`OP_ADW, `OP_SBW: begin
if (op[0]) begin
// SBW
{Rh,R} = Rd_in - Rr;
SC = R15 & !Rdh7;
SV = !R15 & Rdh7;
end else begin
// ADW
{Rh,R} = Rd_in + Rr;
SC = !R15 & Rdh7;
SV = R15 & !Rdh7;
end
SN = R15;
SS = SN ^ SV;
SZ = { Rh, R } == 0;
end
`endif
`ifdef CONFIG_OP_NEG
`OP_NEG: begin
R = -Rd;
SH = R3 | Rd3;
SV = R == 8'h80;
SC = R != 0;
SN = R7;
SS = SN^SV;
SZ = R_zero;
end
`endif
`ifdef CONFIG_OP_SWAP
`OP_SWAP: begin
R = { Rd[3:0], Rd[7:4] };
// no sreg update
end
`endif
`ifdef CONFIG_OP_ASR_OR_ROR
`OP_ASR, `OP_ROR: begin
R = { op[0] ? C : Rd[7], Rd[7:1] };
SC = Rd[0];
SN = R7;
SV = SN^SC;
SS = SN^SV;
SZ = R_zero;
end
`endif
`ifdef CONFIG_OP_LSR
`OP_LSR: begin
R = { 1'b0, Rd[7:1] };
SC = Rd[0];
SN = 0;
SZ = R_zero;
SV = SN^SC;
SS = SN^SV;
end
`endif
`ifdef CONFIG_OP_AND
`OP_AND: begin
R = Rd & Rr;
SV = 0;
SN = R7;
SS = SN^SV;
SZ = R_zero;
end
`endif
`ifdef CONFIG_OP_EOR
`OP_EOR: begin
R = Rd ^ Rr;
if(use_carry) SC = 1; // For COM instruction
SV = 0;
SN = R7;
SS = SN^SV;
SZ = R_zero;
end
`endif
`ifdef CONFIG_OP_OR
`OP_OR: begin
R = Rd | Rr;
SV = 0;
SN = R7;
SS = SN^SV;
SZ = R_zero;
end
`endif
`ifdef CONFIG_OP_SREG
`OP_SREG: begin
if(Rr[3] == 0) begin
// CLX or SEX
(* full_case *)
case(Rr[2:0])
3'b000: SC = use_carry;
3'b001: SZ = use_carry;
3'b010: SN = use_carry;
3'b011: SV = use_carry;
3'b100: SS = use_carry;
3'b101: SH = use_carry;
3'b110: ST = use_carry;
3'b111: SI = use_carry;
endcase
end else
begin
if(use_carry)
// BST
ST = Rd[Rr[2:0]];
else
// BLD
R[Rr[2:0]] = ST;
end
end
`endif
`ifdef CONFIG_OP_MULU
// need to infer a multiplier
`OP_MUL: begin
{ Rh, R } = Rd * Rr;
SC = R15;
SZ = { Rh, R } == 0;
end
`endif
default: begin
// NOTHING
end
endcase
if(keep_sreg[7]) SI = sreg_in[7];
if(keep_sreg[6]) ST = sreg_in[6];
if(keep_sreg[5]) SH = sreg_in[5];
if(keep_sreg[4]) SS = sreg_in[4];
if(keep_sreg[3]) SV = sreg_in[3];
if(keep_sreg[2]) SN = sreg_in[2];
if(keep_sreg[1]) SZ = sreg_in[1];
if(keep_sreg[0]) SC = sreg_in[0];
end
endmodule
`endif