Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
92 | lvd | 1 | // |
2 | // TV80 8-Bit Microprocessor Core |
||
3 | // Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org) |
||
4 | // |
||
5 | // Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org) |
||
6 | // |
||
7 | // Permission is hereby granted, free of charge, to any person obtaining a |
||
8 | // copy of this software and associated documentation files (the "Software"), |
||
9 | // to deal in the Software without restriction, including without limitation |
||
10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
11 | // and/or sell copies of the Software, and to permit persons to whom the |
||
12 | // Software is furnished to do so, subject to the following conditions: |
||
13 | // |
||
14 | // The above copyright notice and this permission notice shall be included |
||
15 | // in all copies or substantial portions of the Software. |
||
16 | // |
||
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||
18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||
20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||
21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||
23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
24 | |||
25 | module tv80_alu (/*AUTOARG*/ |
||
26 | // Outputs |
||
27 | Q, F_Out, |
||
28 | // Inputs |
||
29 | Arith16, Z16, ALU_Op, IR, ISet, BusA, BusB, F_In |
||
30 | ); |
||
31 | |||
32 | parameter Mode = 0; |
||
33 | parameter Flag_C = 0; |
||
34 | parameter Flag_N = 1; |
||
35 | parameter Flag_P = 2; |
||
36 | parameter Flag_X = 3; |
||
37 | parameter Flag_H = 4; |
||
38 | parameter Flag_Y = 5; |
||
39 | parameter Flag_Z = 6; |
||
40 | parameter Flag_S = 7; |
||
41 | |||
42 | input Arith16; |
||
43 | input Z16; |
||
44 | input [3:0] ALU_Op ; |
||
45 | input [5:0] IR; |
||
46 | input [1:0] ISet; |
||
47 | input [7:0] BusA; |
||
48 | input [7:0] BusB; |
||
49 | input [7:0] F_In; |
||
50 | output [7:0] Q; |
||
51 | output [7:0] F_Out; |
||
52 | reg [7:0] Q; |
||
53 | reg [7:0] F_Out; |
||
54 | |||
55 | function [4:0] AddSub4; |
||
56 | input [3:0] A; |
||
57 | input [3:0] B; |
||
58 | input Sub; |
||
59 | input Carry_In; |
||
60 | begin |
||
61 | AddSub4 = { 1'b0, A } + { 1'b0, (Sub)?~B:B } + {4'h0,Carry_In}; |
||
62 | end |
||
63 | endfunction // AddSub4 |
||
64 | |||
65 | function [3:0] AddSub3; |
||
66 | input [2:0] A; |
||
67 | input [2:0] B; |
||
68 | input Sub; |
||
69 | input Carry_In; |
||
70 | begin |
||
71 | AddSub3 = { 1'b0, A } + { 1'b0, (Sub)?~B:B } + {3'h0,Carry_In}; |
||
72 | end |
||
73 | endfunction // AddSub4 |
||
74 | |||
75 | function [1:0] AddSub1; |
||
76 | input A; |
||
77 | input B; |
||
78 | input Sub; |
||
79 | input Carry_In; |
||
80 | begin |
||
81 | AddSub1 = { 1'b0, A } + { 1'b0, (Sub)?~B:B } + {1'h0,Carry_In}; |
||
82 | end |
||
83 | endfunction // AddSub4 |
||
84 | |||
85 | // AddSub variables (temporary signals) |
||
86 | reg UseCarry; |
||
87 | reg Carry7_v; |
||
88 | reg OverFlow_v; |
||
89 | reg HalfCarry_v; |
||
90 | reg Carry_v; |
||
91 | reg [7:0] Q_v; |
||
92 | |||
93 | reg [7:0] BitMask; |
||
94 | |||
95 | |||
96 | always @(/*AUTOSENSE*/ALU_Op or BusA or BusB or F_In or IR) |
||
97 | begin |
||
98 | case (IR[5:3]) |
||
99 | 3'b000 : BitMask = 8'b00000001; |
||
100 | 3'b001 : BitMask = 8'b00000010; |
||
101 | 3'b010 : BitMask = 8'b00000100; |
||
102 | 3'b011 : BitMask = 8'b00001000; |
||
103 | 3'b100 : BitMask = 8'b00010000; |
||
104 | 3'b101 : BitMask = 8'b00100000; |
||
105 | 3'b110 : BitMask = 8'b01000000; |
||
106 | default: BitMask = 8'b10000000; |
||
107 | endcase // case(IR[5:3]) |
||
108 | |||
109 | UseCarry = ~ ALU_Op[2] && ALU_Op[0]; |
||
110 | { HalfCarry_v, Q_v[3:0] } = AddSub4(BusA[3:0], BusB[3:0], ALU_Op[1], ALU_Op[1] ^ (UseCarry && F_In[Flag_C]) ); |
||
111 | { Carry7_v, Q_v[6:4] } = AddSub3(BusA[6:4], BusB[6:4], ALU_Op[1], HalfCarry_v); |
||
112 | { Carry_v, Q_v[7] } = AddSub1(BusA[7], BusB[7], ALU_Op[1], Carry7_v); |
||
113 | OverFlow_v = Carry_v ^ Carry7_v; |
||
114 | end // always @ * |
||
115 | |||
116 | reg [7:0] Q_t; |
||
117 | reg [8:0] DAA_Q; |
||
118 | |||
119 | always @ (/*AUTOSENSE*/ALU_Op or Arith16 or BitMask or BusA or BusB |
||
120 | or Carry_v or F_In or HalfCarry_v or IR or ISet |
||
121 | or OverFlow_v or Q_v or Z16) |
||
122 | begin |
||
123 | Q_t = 8'hxx; |
||
124 | DAA_Q = {9{1'bx}}; |
||
125 | |||
126 | F_Out = F_In; |
||
127 | case (ALU_Op) |
||
128 | 4'b0000, 4'b0001, 4'b0010, 4'b0011, 4'b0100, 4'b0101, 4'b0110, 4'b0111 : |
||
129 | begin |
||
130 | F_Out[Flag_N] = 1'b0; |
||
131 | F_Out[Flag_C] = 1'b0; |
||
132 | |||
133 | case (ALU_Op[2:0]) |
||
134 | |||
135 | 3'b000, 3'b001 : // ADD, ADC |
||
136 | begin |
||
137 | Q_t = Q_v; |
||
138 | F_Out[Flag_C] = Carry_v; |
||
139 | F_Out[Flag_H] = HalfCarry_v; |
||
140 | F_Out[Flag_P] = OverFlow_v; |
||
141 | end |
||
142 | |||
143 | 3'b010, 3'b011, 3'b111 : // SUB, SBC, CP |
||
144 | begin |
||
145 | Q_t = Q_v; |
||
146 | F_Out[Flag_N] = 1'b1; |
||
147 | F_Out[Flag_C] = ~ Carry_v; |
||
148 | F_Out[Flag_H] = ~ HalfCarry_v; |
||
149 | F_Out[Flag_P] = OverFlow_v; |
||
150 | end |
||
151 | |||
152 | 3'b100 : // AND |
||
153 | begin |
||
154 | Q_t[7:0] = BusA & BusB; |
||
155 | F_Out[Flag_H] = 1'b1; |
||
156 | end |
||
157 | |||
158 | 3'b101 : // XOR |
||
159 | begin |
||
160 | Q_t[7:0] = BusA ^ BusB; |
||
161 | F_Out[Flag_H] = 1'b0; |
||
162 | end |
||
163 | |||
164 | default : // OR 3'b110 |
||
165 | begin |
||
166 | Q_t[7:0] = BusA | BusB; |
||
167 | F_Out[Flag_H] = 1'b0; |
||
168 | end |
||
169 | |||
170 | endcase // case(ALU_OP[2:0]) |
||
171 | |||
172 | if (ALU_Op[2:0] == 3'b111 ) |
||
173 | begin // CP |
||
174 | F_Out[Flag_X] = BusB[3]; |
||
175 | F_Out[Flag_Y] = BusB[5]; |
||
176 | end |
||
177 | else |
||
178 | begin |
||
179 | F_Out[Flag_X] = Q_t[3]; |
||
180 | F_Out[Flag_Y] = Q_t[5]; |
||
181 | end |
||
182 | |||
183 | if (Q_t[7:0] == 8'b00000000 ) |
||
184 | begin |
||
185 | F_Out[Flag_Z] = 1'b1; |
||
186 | if (Z16 == 1'b1 ) |
||
187 | begin |
||
188 | F_Out[Flag_Z] = F_In[Flag_Z]; // 16 bit ADC,SBC |
||
189 | end |
||
190 | end |
||
191 | else |
||
192 | begin |
||
193 | F_Out[Flag_Z] = 1'b0; |
||
194 | end // else: !if(Q_t[7:0] == 8'b00000000 ) |
||
195 | |||
196 | F_Out[Flag_S] = Q_t[7]; |
||
197 | case (ALU_Op[2:0]) |
||
198 | 3'b000, 3'b001, 3'b010, 3'b011, 3'b111 : // ADD, ADC, SUB, SBC, CP |
||
199 | ; |
||
200 | |||
201 | default : |
||
202 | F_Out[Flag_P] = ~(^Q_t); |
||
203 | endcase // case(ALU_Op[2:0]) |
||
204 | |||
205 | if (Arith16 == 1'b1 ) |
||
206 | begin |
||
207 | F_Out[Flag_S] = F_In[Flag_S]; |
||
208 | F_Out[Flag_Z] = F_In[Flag_Z]; |
||
209 | F_Out[Flag_P] = F_In[Flag_P]; |
||
210 | end |
||
211 | end // case: 4'b0000, 4'b0001, 4'b0010, 4'b0011, 4'b0100, 4'b0101, 4'b0110, 4'b0111 |
||
212 | |||
213 | 4'b1100 : |
||
214 | begin |
||
215 | // DAA |
||
216 | F_Out[Flag_H] = F_In[Flag_H]; |
||
217 | F_Out[Flag_C] = F_In[Flag_C]; |
||
218 | DAA_Q[7:0] = BusA; |
||
219 | DAA_Q[8] = 1'b0; |
||
220 | if (F_In[Flag_N] == 1'b0 ) |
||
221 | begin |
||
222 | // After addition |
||
223 | // Alow > 9 || H == 1 |
||
224 | if (DAA_Q[3:0] > 9 || F_In[Flag_H] == 1'b1 ) |
||
225 | begin |
||
226 | if ((DAA_Q[3:0] > 9) ) |
||
227 | begin |
||
228 | F_Out[Flag_H] = 1'b1; |
||
229 | end |
||
230 | else |
||
231 | begin |
||
232 | F_Out[Flag_H] = 1'b0; |
||
233 | end |
||
234 | DAA_Q = DAA_Q + 6; |
||
235 | end // if (DAA_Q[3:0] > 9 || F_In[Flag_H] == 1'b1 ) |
||
236 | |||
237 | // new Ahigh > 9 || C == 1 |
||
238 | if (DAA_Q[8:4] > 9 || F_In[Flag_C] == 1'b1 ) |
||
239 | begin |
||
240 | DAA_Q = DAA_Q + 96; // 0x60 |
||
241 | end |
||
242 | end |
||
243 | else |
||
244 | begin |
||
245 | // After subtraction |
||
246 | if (DAA_Q[3:0] > 9 || F_In[Flag_H] == 1'b1 ) |
||
247 | begin |
||
248 | if (DAA_Q[3:0] > 5 ) |
||
249 | begin |
||
250 | F_Out[Flag_H] = 1'b0; |
||
251 | end |
||
252 | DAA_Q[7:0] = DAA_Q[7:0] - 6; |
||
253 | end |
||
254 | if (BusA > 153 || F_In[Flag_C] == 1'b1 ) |
||
255 | begin |
||
256 | DAA_Q = DAA_Q - 352; // 0x160 |
||
257 | end |
||
258 | end // else: !if(F_In[Flag_N] == 1'b0 ) |
||
259 | |||
260 | F_Out[Flag_X] = DAA_Q[3]; |
||
261 | F_Out[Flag_Y] = DAA_Q[5]; |
||
262 | F_Out[Flag_C] = F_In[Flag_C] || DAA_Q[8]; |
||
263 | Q_t = DAA_Q[7:0]; |
||
264 | |||
265 | if (DAA_Q[7:0] == 8'b00000000 ) |
||
266 | begin |
||
267 | F_Out[Flag_Z] = 1'b1; |
||
268 | end |
||
269 | else |
||
270 | begin |
||
271 | F_Out[Flag_Z] = 1'b0; |
||
272 | end |
||
273 | |||
274 | F_Out[Flag_S] = DAA_Q[7]; |
||
275 | F_Out[Flag_P] = ~ (^DAA_Q); |
||
276 | end // case: 4'b1100 |
||
277 | |||
278 | 4'b1101, 4'b1110 : |
||
279 | begin |
||
280 | // RLD, RRD |
||
281 | Q_t[7:4] = BusA[7:4]; |
||
282 | if (ALU_Op[0] == 1'b1 ) |
||
283 | begin |
||
284 | Q_t[3:0] = BusB[7:4]; |
||
285 | end |
||
286 | else |
||
287 | begin |
||
288 | Q_t[3:0] = BusB[3:0]; |
||
289 | end |
||
290 | F_Out[Flag_H] = 1'b0; |
||
291 | F_Out[Flag_N] = 1'b0; |
||
292 | F_Out[Flag_X] = Q_t[3]; |
||
293 | F_Out[Flag_Y] = Q_t[5]; |
||
294 | if (Q_t[7:0] == 8'b00000000 ) |
||
295 | begin |
||
296 | F_Out[Flag_Z] = 1'b1; |
||
297 | end |
||
298 | else |
||
299 | begin |
||
300 | F_Out[Flag_Z] = 1'b0; |
||
301 | end |
||
302 | F_Out[Flag_S] = Q_t[7]; |
||
303 | F_Out[Flag_P] = ~(^Q_t); |
||
304 | end // case: when 4'b1101, 4'b1110 |
||
305 | |||
306 | 4'b1001 : |
||
307 | begin |
||
308 | // BIT |
||
309 | Q_t[7:0] = BusB & BitMask; |
||
310 | F_Out[Flag_S] = Q_t[7]; |
||
311 | if (Q_t[7:0] == 8'b00000000 ) |
||
312 | begin |
||
313 | F_Out[Flag_Z] = 1'b1; |
||
314 | F_Out[Flag_P] = 1'b1; |
||
315 | end |
||
316 | else |
||
317 | begin |
||
318 | F_Out[Flag_Z] = 1'b0; |
||
319 | F_Out[Flag_P] = 1'b0; |
||
320 | end |
||
321 | F_Out[Flag_H] = 1'b1; |
||
322 | F_Out[Flag_N] = 1'b0; |
||
323 | F_Out[Flag_X] = 1'b0; |
||
324 | F_Out[Flag_Y] = 1'b0; |
||
325 | if (IR[2:0] != 3'b110 ) |
||
326 | begin |
||
327 | F_Out[Flag_X] = BusB[3]; |
||
328 | F_Out[Flag_Y] = BusB[5]; |
||
329 | end |
||
330 | end // case: when 4'b1001 |
||
331 | |||
332 | 4'b1010 : |
||
333 | // SET |
||
334 | Q_t[7:0] = BusB | BitMask; |
||
335 | |||
336 | 4'b1011 : |
||
337 | // RES |
||
338 | Q_t[7:0] = BusB & ~ BitMask; |
||
339 | |||
340 | 4'b1000 : |
||
341 | begin |
||
342 | // ROT |
||
343 | case (IR[5:3]) |
||
344 | 3'b000 : // RLC |
||
345 | begin |
||
346 | Q_t[7:1] = BusA[6:0]; |
||
347 | Q_t[0] = BusA[7]; |
||
348 | F_Out[Flag_C] = BusA[7]; |
||
349 | end |
||
350 | |||
351 | 3'b010 : // RL |
||
352 | begin |
||
353 | Q_t[7:1] = BusA[6:0]; |
||
354 | Q_t[0] = F_In[Flag_C]; |
||
355 | F_Out[Flag_C] = BusA[7]; |
||
356 | end |
||
357 | |||
358 | 3'b001 : // RRC |
||
359 | begin |
||
360 | Q_t[6:0] = BusA[7:1]; |
||
361 | Q_t[7] = BusA[0]; |
||
362 | F_Out[Flag_C] = BusA[0]; |
||
363 | end |
||
364 | |||
365 | 3'b011 : // RR |
||
366 | begin |
||
367 | Q_t[6:0] = BusA[7:1]; |
||
368 | Q_t[7] = F_In[Flag_C]; |
||
369 | F_Out[Flag_C] = BusA[0]; |
||
370 | end |
||
371 | |||
372 | 3'b100 : // SLA |
||
373 | begin |
||
374 | Q_t[7:1] = BusA[6:0]; |
||
375 | Q_t[0] = 1'b0; |
||
376 | F_Out[Flag_C] = BusA[7]; |
||
377 | end |
||
378 | |||
379 | 3'b110 : // SLL (Undocumented) / SWAP |
||
380 | begin |
||
381 | if (Mode == 3 ) |
||
382 | begin |
||
383 | Q_t[7:4] = BusA[3:0]; |
||
384 | Q_t[3:0] = BusA[7:4]; |
||
385 | F_Out[Flag_C] = 1'b0; |
||
386 | end |
||
387 | else |
||
388 | begin |
||
389 | Q_t[7:1] = BusA[6:0]; |
||
390 | Q_t[0] = 1'b1; |
||
391 | F_Out[Flag_C] = BusA[7]; |
||
392 | end // else: !if(Mode == 3 ) |
||
393 | end // case: 3'b110 |
||
394 | |||
395 | 3'b101 : // SRA |
||
396 | begin |
||
397 | Q_t[6:0] = BusA[7:1]; |
||
398 | Q_t[7] = BusA[7]; |
||
399 | F_Out[Flag_C] = BusA[0]; |
||
400 | end |
||
401 | |||
402 | default : // SRL |
||
403 | begin |
||
404 | Q_t[6:0] = BusA[7:1]; |
||
405 | Q_t[7] = 1'b0; |
||
406 | F_Out[Flag_C] = BusA[0]; |
||
407 | end |
||
408 | endcase // case(IR[5:3]) |
||
409 | |||
410 | F_Out[Flag_H] = 1'b0; |
||
411 | F_Out[Flag_N] = 1'b0; |
||
412 | F_Out[Flag_X] = Q_t[3]; |
||
413 | F_Out[Flag_Y] = Q_t[5]; |
||
414 | F_Out[Flag_S] = Q_t[7]; |
||
415 | if (Q_t[7:0] == 8'b00000000 ) |
||
416 | begin |
||
417 | F_Out[Flag_Z] = 1'b1; |
||
418 | end |
||
419 | else |
||
420 | begin |
||
421 | F_Out[Flag_Z] = 1'b0; |
||
422 | end |
||
423 | F_Out[Flag_P] = ~(^Q_t); |
||
424 | |||
425 | if (ISet == 2'b00 ) |
||
426 | begin |
||
427 | F_Out[Flag_P] = F_In[Flag_P]; |
||
428 | F_Out[Flag_S] = F_In[Flag_S]; |
||
429 | F_Out[Flag_Z] = F_In[Flag_Z]; |
||
430 | end |
||
431 | end // case: 4'b1000 |
||
432 | |||
433 | |||
434 | default : |
||
435 | ; |
||
436 | |||
437 | endcase // case(ALU_Op) |
||
438 | |||
439 | Q = Q_t; |
||
440 | end // always @ (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16) |
||
441 | |||
442 | endmodule // T80_ALU |