OSDN Git Service

- cpx supported.
[motonesfpga/motonesfpga.git] / simulation / cpu / alu.vhd
1 ----------------------------
2 ---- 6502 ALU implementation
3 ----------------------------
4 library ieee;
5 use ieee.std_logic_1164.all;
6 use ieee.std_logic_unsigned.all;
7 use ieee.std_logic_arith.conv_std_logic_vector;
8
9 entity alu is 
10     generic (   dsize : integer := 8
11             );
12     port (  clk             : in std_logic;
13             pcl_inc_n       : in std_logic;
14             pch_inc_n       : in std_logic;
15             sph_oe_n        : in std_logic;
16             sp_push_n       : in std_logic;
17             sp_pop_n        : in std_logic;
18             abs_xy_n        : in std_logic;
19             pg_next_n       : in std_logic;
20             zp_n            : in std_logic;
21             zp_xy_n         : in std_logic;
22             rel_calc_n      : in std_logic;
23             arith_en_n      : in std_logic;
24             instruction     : in std_logic_vector (dsize - 1 downto 0);
25             int_d_bus       : inout std_logic_vector (dsize - 1 downto 0);
26             acc_out         : in std_logic_vector (dsize - 1 downto 0);
27             index_bus       : in std_logic_vector (dsize - 1 downto 0);
28             bal             : in std_logic_vector (dsize - 1 downto 0);
29             bah             : in std_logic_vector (dsize - 1 downto 0);
30             addr_back       : out std_logic_vector (dsize - 1 downto 0);
31             acc_in          : out std_logic_vector (dsize - 1 downto 0);
32             abl             : out std_logic_vector (dsize - 1 downto 0);
33             abh             : out std_logic_vector (dsize - 1 downto 0);
34             pcl_inc_carry   : out std_logic;
35             ea_carry        : out std_logic;
36             carry_in        : in std_logic;
37             negative        : out std_logic;
38             zero            : out std_logic;
39             carry_out       : out std_logic;
40             overflow        : out std_logic
41     );
42 end alu;
43
44 architecture rtl of alu is
45
46 component d_flip_flop
47     generic (
48             dsize : integer := 8
49             );
50     port (  
51             clk     : in std_logic;
52             res_n   : in std_logic;
53             set_n   : in std_logic;
54             we_n    : in std_logic;
55             d       : in std_logic_vector (dsize - 1 downto 0);
56             q       : out std_logic_vector (dsize - 1 downto 0)
57         );
58 end component;
59
60 component address_calculator
61     generic (   dsize : integer := 8
62             );
63     port ( 
64             sel         : in std_logic_vector (1 downto 0);
65             addr1       : in std_logic_vector (dsize - 1 downto 0);
66             addr2       : in std_logic_vector (dsize - 1 downto 0);
67             addr_out    : out std_logic_vector (dsize - 1 downto 0);
68             carry_in    : in std_logic;
69             carry_out   : out std_logic
70     );
71 end component;
72
73 component alu_core
74     generic (   dsize : integer := 8
75             );
76     port ( 
77             sel         : in std_logic_vector (3 downto 0);
78             d1          : in std_logic_vector (dsize - 1 downto 0);
79             d2          : in std_logic_vector (dsize - 1 downto 0);
80             d_out       : out std_logic_vector (dsize - 1 downto 0);
81             carry_in    : in std_logic;
82             negative    : out std_logic;
83             zero        : out std_logic;
84             carry_out   : out std_logic;
85             overflow    : out std_logic
86     );
87 end component;
88
89
90 --------- signals for address calucuration ----------
91 signal al_buf_we : std_logic;
92 signal ah_buf_we : std_logic;
93
94 signal al_reg_in : std_logic_vector (dsize - 1 downto 0);
95 signal ah_reg_in : std_logic_vector (dsize - 1 downto 0);
96 signal al_reg : std_logic_vector (dsize - 1 downto 0);
97 signal ah_reg : std_logic_vector (dsize - 1 downto 0);
98
99
100 signal a_sel : std_logic_vector (1 downto 0);
101 signal addr1 : std_logic_vector (dsize - 1 downto 0);
102 signal addr2 : std_logic_vector (dsize - 1 downto 0);
103 signal addr_out : std_logic_vector (dsize - 1 downto 0);
104
105 signal addr_c_in : std_logic;
106 signal addr_c : std_logic;
107
108 ----------- signals for arithmatic ----------
109 signal sel : std_logic_vector (3 downto 0);
110 signal d1 : std_logic_vector (dsize - 1 downto 0);
111 signal d2 : std_logic_vector (dsize - 1 downto 0);
112 signal d_out : std_logic_vector (dsize - 1 downto 0);
113
114 signal n : std_logic;
115 signal z : std_logic;
116 signal c_in : std_logic;
117 signal c : std_logic;
118 signal v : std_logic;
119
120 signal arith_reg_in : std_logic_vector (dsize - 1 downto 0);
121 signal arith_reg : std_logic_vector (dsize - 1 downto 0);
122 signal arith_buf_we : std_logic;
123
124 begin
125
126     ----------------------------------------
127      -- address calucurator instances ----
128     ----------------------------------------
129     al_buf : d_flip_flop generic map (dsize) 
130             port map(clk, '1', '1', al_buf_we, al_reg_in, al_reg);
131     ah_buf : d_flip_flop generic map (dsize) 
132             port map(clk, '1', '1', ah_buf_we, ah_reg_in, ah_reg);
133
134     addr_calc_inst : address_calculator generic map (dsize)
135             port map (a_sel, addr1, addr2, addr_out, addr_c_in, addr_c);
136
137
138     ----------------------------------------
139      -- arithmatic operation instances ----
140     ----------------------------------------
141     arith_buf : d_flip_flop generic map (dsize) 
142             port map(clk, '1', '1', arith_buf_we, arith_reg_in, arith_reg);
143
144     alu_inst : alu_core generic map (dsize)
145             port map (sel, d1, d2, d_out, c_in, n, z, c, v);
146
147
148     -------------------------------
149     ---- address calucuration -----
150     -------------------------------
151     alu_p : process (clk, 
152                     ---for address calucuration
153                     pcl_inc_n, pch_inc_n, sph_oe_n, sp_push_n, sp_pop_n,
154                     abs_xy_n, pg_next_n, zp_n, zp_xy_n, rel_calc_n, 
155                     int_d_bus, index_bus, bal, bal, addr_c_in, addr_out, addr_c,
156
157                     --for arithmatic operation.
158                     arith_en_n,
159                     instruction, int_d_bus, acc_out, index_bus, 
160                     carry_in, d_out, n, z, c, v)
161
162
163 constant ADDR_ADC    : std_logic_vector (1 downto 0) := "00";
164 constant ADDR_INC    : std_logic_vector (1 downto 0) := "01";
165 constant ADDR_DEC    : std_logic_vector (1 downto 0) := "10";
166 constant ADDR_SIGNED_ADD : std_logic_vector (1 downto 0) := "11";
167
168 constant ALU_AND    : std_logic_vector (3 downto 0) := "0000";
169 constant ALU_EOR    : std_logic_vector (3 downto 0) := "0001";
170 constant ALU_OR     : std_logic_vector (3 downto 0) := "0010";
171 constant ALU_BIT    : std_logic_vector (3 downto 0) := "0011";
172 constant ALU_ADC    : std_logic_vector (3 downto 0) := "0100";
173 constant ALU_SBC    : std_logic_vector (3 downto 0) := "0101";
174 constant ALU_CMP    : std_logic_vector (3 downto 0) := "0110";
175 constant ALU_SL     : std_logic_vector (3 downto 0) := "0111";
176 constant ALU_SR     : std_logic_vector (3 downto 0) := "1000";
177 constant ALU_RL     : std_logic_vector (3 downto 0) := "1001";
178 constant ALU_RR     : std_logic_vector (3 downto 0) := "1010";
179 constant ALU_INC    : std_logic_vector (3 downto 0) := "1011";
180 constant ALU_DEC    : std_logic_vector (3 downto 0) := "1100";
181
182 procedure output_d_bus is
183 begin
184     arith_reg_in <= d_out;
185     if (clk = '0') then
186         int_d_bus <= d_out;
187     else
188         int_d_bus <= arith_reg_in;
189     end if;
190 end  procedure;
191
192 procedure d_print(msg : string) is
193 use std.textio.all;
194 use ieee.std_logic_textio.all;
195 variable out_l : line;
196 begin
197     write(out_l, msg);
198     writeline(output, out_l);
199 end  procedure;
200
201     begin
202
203     if (pcl_inc_n = '0') then
204         a_sel <= ADDR_INC;
205         addr1 <= bal;
206         addr_back <= addr_out;
207         pcl_inc_carry <= addr_c;
208
209         --keep the value in the cycle
210         al_buf_we <= '0';
211         al_reg_in <= bal;
212         if (instruction = "01001100") then
213             ---exceptional case: only jmp instruction 
214             abl <= bal;
215         else
216             if (clk = '0') then
217                 abl <= bal;
218             else
219                 abl <= al_reg;
220             end if;
221         end if;
222         abh <= bah;
223
224         int_d_bus <= (others => 'Z');
225     elsif (pch_inc_n = '0') then
226         a_sel <= ADDR_INC;
227         addr1 <= bah;
228         addr_back <= addr_out;
229         pcl_inc_carry <= '0';
230
231         --inc pch cycle is not fetch cycle.
232         --it is special cycle.
233         abl <= bal;
234         abh <= bah;
235
236         int_d_bus <= (others => 'Z');
237     elsif (sph_oe_n = '0') then
238         --stack operation...
239         abh <= "00000001";
240         int_d_bus <= (others => 'Z');
241
242         if (sp_push_n /= '0' and sp_pop_n /= '0') then
243             abl <= bal;
244         elsif (sp_pop_n = '0') then
245             --case pop
246             a_sel <= ADDR_INC;
247             addr1 <= bal;
248             addr_back <= addr_out;
249
250             al_buf_we <= '0';
251             al_reg_in <= bal;
252             if (clk = '0') then
253                 abl <= bal;
254             else
255                 abl <= al_reg;
256             end if;
257         else
258             ---case push
259             a_sel <= ADDR_DEC;
260             addr1 <= bal;
261             addr_back <= addr_out;
262
263             al_buf_we <= '0';
264             al_reg_in <= bal;
265             if (clk = '0') then
266                 abl <= bal;
267             else
268                 abl <= al_reg;
269             end if;
270         end if;
271     elsif (zp_n = '0') then
272         abh <= "00000000";
273         abl <= bal;
274         int_d_bus <= (others => 'Z');
275
276     elsif (abs_xy_n = '0') then
277         if (pg_next_n = '0') then
278             a_sel <= ADDR_INC;
279             addr1 <= bah;
280             ea_carry <= '0';
281
282             al_buf_we <= '1';
283             abh <= addr_out;
284             ---al is in the al_reg.
285             abl <= al_reg;
286         else
287             a_sel <= ADDR_ADC;
288             addr1 <= bal;
289             addr2 <= index_bus;
290             addr_c_in <= '0';
291             ea_carry <= addr_c;
292
293             ---keep al for page crossed case
294             al_buf_we <= '0';
295             al_reg_in <= addr_out;
296             abh <= bah;
297             abl <= addr_out;
298         end if;
299
300     elsif (rel_calc_n = '0') then
301         if (pg_next_n = '1') then
302             if (int_d_bus(7) = '1') then
303                 ---backward relative branch
304                 a_sel <= ADDR_DEC;
305             else
306                 ---forward relative branch
307                 a_sel <= ADDR_INC;
308             end if;
309             ---addr1 is pch.`
310             addr1 <= bah;
311             ---rel val is on the d_bus.
312             addr_back <= addr_out;
313             ea_carry <= '0'; 
314
315             --keep the value in the cycle
316             ah_buf_we <= '0';
317             ah_reg_in <= addr_out;
318             abh <= addr_out;
319             --al no change.
320             abl <= bal;
321         else
322             a_sel <= ADDR_SIGNED_ADD;
323             ---addr1 is pcl.`
324             addr1 <= bal;
325             ---rel val is on the d_bus.
326             addr2 <= int_d_bus;
327             addr_back <= addr_out;
328             ea_carry <= addr_c;
329
330             --keep the value in the cycle
331             al_buf_we <= '0';
332             al_reg_in <= addr_out;
333             if (clk = '0') then
334                 abl <= addr_out;
335             else
336                 abl <= al_reg;
337             end if;
338             abh <= bah;
339         end if;
340         int_d_bus <= (others => 'Z');
341     else
342         al_buf_we <= '1';
343         ah_buf_we <= '1';
344
345         int_d_bus <= (others => 'Z');
346         negative <= 'Z';
347         zero <= 'Z';
348         carry_out <= 'Z';
349         overflow <= 'Z';
350
351         abl <= bal;
352         abh <= bah;
353
354         ----addr_back is always bal for jsr instruction....
355         -----TODO must check later if it's ok.
356         addr_back <= bal;
357         pcl_inc_carry <= '0';
358     end if; --if (pcl_inc_n = '0') then
359
360     -------------------------------
361     ---- arithmatic operations-----
362     -------------------------------
363     if (arith_en_n = '0') then
364
365         arith_buf_we <= '0';
366
367         if instruction = conv_std_logic_vector(16#ca#, dsize) then
368             --d_print("dex");
369             sel <= ALU_DEC;
370             d1 <= index_bus;
371             c_in <= '0';
372
373             negative <= n;
374             zero <= z;
375             output_d_bus;
376
377         elsif instruction = conv_std_logic_vector(16#88#, dsize) then
378             --d_print("dey");
379             sel <= ALU_DEC;
380             d1 <= index_bus;
381             c_in <= '0';
382
383             negative <= n;
384             zero <= z;
385             output_d_bus;
386
387         elsif instruction = conv_std_logic_vector(16#e8#, dsize) then
388             --d_print("inx");
389             sel <= ALU_INC;
390             d1 <= index_bus;
391             c_in <= '0';
392
393             negative <= n;
394             zero <= z;
395             output_d_bus;
396
397         elsif instruction = conv_std_logic_vector(16#c8#, dsize) then
398             d_print("iny");
399
400         --instruction is aaabbbcc format.
401         elsif instruction (1 downto 0) = "01" then
402             if instruction (7 downto 5) = "000" then
403                 d_print("ora");
404             elsif instruction (7 downto 5) = "001" then
405                 d_print("and");
406             elsif instruction (7 downto 5) = "010" then
407                 d_print("eor");
408             elsif instruction (7 downto 5) = "011" then
409                 d_print("adc");
410             elsif instruction (7 downto 5) = "110" then
411                 --d_print("cmp");
412                 --cmpare A - M.
413                 sel <= ALU_CMP;
414                 d1 <= acc_out;
415                 d2 <= int_d_bus;
416                 negative <= n;
417                 zero <= z;
418                 carry_out <= c;
419
420             elsif instruction (7 downto 5) = "111" then
421                 d_print("sbc");
422             end if;
423         elsif instruction (1 downto 0) = "10" then
424             if instruction (7 downto 5) = "000" then
425                 d_print("asl");
426             elsif instruction (7 downto 5) = "001" then
427                 d_print("rol");
428             elsif instruction (7 downto 5) = "010" then
429                 d_print("lsr");
430             elsif instruction (7 downto 5) = "011" then
431                 d_print("ror");
432             elsif instruction (7 downto 5) = "110" then
433                 d_print("dec");
434             elsif instruction (7 downto 5) = "111" then
435                 d_print("inc");
436             end if;
437         elsif instruction (1 downto 0) = "00" then
438             if instruction (7 downto 5) = "001" then
439                 d_print("bit");
440             elsif instruction (7 downto 5) = "110" then
441                 d_print("cpy");
442             elsif instruction (7 downto 5) = "111" then
443                -- d_print("cpx");
444                 sel <= ALU_CMP;
445                 d1 <= index_bus;
446                 d2 <= int_d_bus;
447                 negative <= n;
448                 zero <= z;
449                 carry_out <= c;
450
451             end if; --if instruction (7 downto 5) = "001" then
452         end if; --if instruction = conv_std_logic_vector(16#ca#, dsize) 
453     else
454         arith_buf_we <= '1';
455     end if; -- if (arith_en_n = '0') then
456     end process;
457
458 end rtl;
459
460 -----------------------------------------
461 ---------- Address calculator------------
462 -----------------------------------------
463
464 library ieee;
465 use ieee.std_logic_1164.all;
466 use ieee.std_logic_unsigned.all;
467
468 entity address_calculator is 
469     generic (   dsize : integer := 8
470             );
471     port ( 
472             sel         : in std_logic_vector (1 downto 0);
473             addr1       : in std_logic_vector (dsize - 1 downto 0);
474             addr2       : in std_logic_vector (dsize - 1 downto 0);
475             addr_out    : out std_logic_vector (dsize - 1 downto 0);
476             carry_in    : in std_logic;
477             carry_out   : out std_logic
478     );
479 end address_calculator;
480
481 architecture rtl of address_calculator is
482
483 constant ADDR_ADC    : std_logic_vector (1 downto 0) := "00";
484 constant ADDR_INC    : std_logic_vector (1 downto 0) := "01";
485 constant ADDR_DEC    : std_logic_vector (1 downto 0) := "10";
486 constant ADDR_SIGNED_ADD : std_logic_vector (1 downto 0) := "11";
487
488 begin
489
490     alu_p : process (sel, addr1, addr2, carry_in)
491     variable res : std_logic_vector (dsize downto 0);
492
493     begin
494     if sel = ADDR_ADC then
495         res := ('0' & addr1) + ('0' & addr2) + carry_in;
496         addr_out <= res(dsize - 1 downto 0);
497         carry_out <= res(dsize);
498
499     elsif sel = ADDR_SIGNED_ADD then
500         res := ('0' & addr1) + ('0' & addr2);
501         addr_out <= res(dsize - 1 downto 0);
502         if ((addr1(dsize - 1) = addr1(dsize - 1)) 
503                             and (addr1(dsize - 1) /= res(dsize - 1))) then
504             carry_out <= '1';
505         else
506             carry_out <= '0';
507         end if;
508
509     elsif sel = ADDR_INC then
510         res := ('0' & addr1) + "000000001";
511         addr_out <= res(dsize - 1 downto 0);
512         carry_out <= res(dsize);
513     elsif sel = ADDR_DEC then
514         res := ('0' & addr1) - "000000001";
515         addr_out <= res(dsize - 1 downto 0);
516         carry_out <= res(dsize);
517     end if;
518     end process;
519
520 end rtl;
521
522
523 -----------------------------------------
524 ------------- ALU Core -----------------
525 -----------------------------------------
526
527 library ieee;
528 use ieee.std_logic_1164.all;
529 use ieee.std_logic_unsigned.all;
530
531 ----d1 = acc
532 ----d2 = memory
533 entity alu_core is 
534     generic (   dsize : integer := 8
535             );
536     port ( 
537             sel         : in std_logic_vector (3 downto 0);
538             d1          : in std_logic_vector (dsize - 1 downto 0);
539             d2          : in std_logic_vector (dsize - 1 downto 0);
540             d_out       : out std_logic_vector (dsize - 1 downto 0);
541             carry_in    : in std_logic;
542             negative    : out std_logic;
543             zero        : out std_logic;
544             carry_out   : out std_logic;
545             overflow    : out std_logic
546     );
547 end alu_core;
548
549 architecture rtl of alu_core is
550
551 procedure d_print(msg : string) is
552 use std.textio.all;
553 use ieee.std_logic_textio.all;
554 variable out_l : line;
555 begin
556     write(out_l, msg);
557     writeline(output, out_l);
558 end  procedure;
559
560 constant ALU_AND    : std_logic_vector (3 downto 0) := "0000";
561 constant ALU_EOR    : std_logic_vector (3 downto 0) := "0001";
562 constant ALU_OR     : std_logic_vector (3 downto 0) := "0010";
563 constant ALU_BIT    : std_logic_vector (3 downto 0) := "0011";
564 constant ALU_ADC    : std_logic_vector (3 downto 0) := "0100";
565 constant ALU_SBC    : std_logic_vector (3 downto 0) := "0101";
566 constant ALU_CMP    : std_logic_vector (3 downto 0) := "0110";
567 constant ALU_SL     : std_logic_vector (3 downto 0) := "0111";
568 constant ALU_SR     : std_logic_vector (3 downto 0) := "1000";
569 constant ALU_RL     : std_logic_vector (3 downto 0) := "1001";
570 constant ALU_RR     : std_logic_vector (3 downto 0) := "1010";
571 constant ALU_INC    : std_logic_vector (3 downto 0) := "1011";
572 constant ALU_DEC    : std_logic_vector (3 downto 0) := "1100";
573
574 begin
575
576     alu_p : process (sel, d1, d2, carry_in)
577     variable res : std_logic_vector (dsize downto 0);
578
579 procedure set_n (data : in std_logic_vector (dsize - 1 downto 0)) is
580 begin
581     if (data(7) = '1') then
582         negative <= '1';
583     else
584         negative <= '0';
585     end if;
586 end procedure;
587
588 procedure set_z (data : in std_logic_vector (dsize - 1 downto 0)) is
589 begin
590     if  (data = "00000000") then
591         zero <= '1';
592     else
593         zero <= '0';
594     end if;
595 end procedure;
596
597     begin
598     if sel = ALU_AND then
599         res := d1 and d2;
600     elsif sel = ALU_EOR then
601         res := d1 xor d2;
602     elsif sel = ALU_OR then
603         res := d1 or d2;
604     elsif sel = ALU_BIT then
605         ----
606     elsif sel = ALU_ADC then
607         res := ('0' & d1) + ('0' & d2) + carry_in;
608         d_out <= res(dsize - 1 downto 0);
609         carry_out <= res(dsize);
610         if ((d1(dsize - 1) = d1(dsize - 1)) 
611                             and (d1(dsize - 1) /= res(dsize - 1))) then
612             overflow <= '1';
613         else
614             overflow <= '0';
615         end if;
616
617     elsif sel = ALU_SBC then
618         ----
619     elsif sel = ALU_CMP then
620         res := ('0' & d1) - ('0' & d2);
621         if (d1 >= d2) then
622             carry_out <= '1';
623         else
624             carry_out <= '0';
625         end if;
626     elsif sel = ALU_SL then
627         ----
628     elsif sel = ALU_SR then
629         ----
630     elsif sel = ALU_RL then
631         ----
632     elsif sel = ALU_RR then
633         ----
634     elsif sel = ALU_INC then
635         res := ('0' & d1) + "000000001";
636         d_out <= res(dsize - 1 downto 0);
637         carry_out <= res(dsize);
638     elsif sel = ALU_DEC then
639         res := ('0' & d1) - "000000001";
640         d_out <= res(dsize - 1 downto 0);
641         carry_out <= res(dsize);
642     end if;
643     set_n(res(dsize - 1 downto 0));
644     set_z(res(dsize - 1 downto 0));
645
646     end process;
647
648 end rtl;
649