OSDN Git Service

page crossing conditional branch supported.
[motonesfpga/motonesfpga.git] / de1_nes / 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 use work.motonesfpga_common.all;
9
10 entity alu is 
11     generic (   dsize : integer := 8
12             );
13     port (  clk             : in std_logic;
14             pcl_inc_n       : in std_logic;
15             pch_inc_n       : in std_logic;
16             sp_oe_n         : in std_logic;
17             sp_push_n       : in std_logic;
18             sp_pop_n        : in std_logic;
19             abs_xy_n        : in std_logic;
20             pg_next_n       : in std_logic;
21             zp_n            : in std_logic;
22             zp_xy_n         : in std_logic;
23             rel_calc_n      : in std_logic;
24             indir_n         : in std_logic;
25             indir_x_n       : in std_logic;
26             indir_y_n       : in std_logic;
27             arith_en_n      : in std_logic;
28             instruction     : in std_logic_vector (dsize - 1 downto 0);
29             exec_cycle      : in std_logic_vector (5 downto 0);
30             int_d_bus       : inout std_logic_vector (dsize - 1 downto 0);
31             acc_out         : in std_logic_vector (dsize - 1 downto 0);
32             index_bus       : in std_logic_vector (dsize - 1 downto 0);
33             bal             : in std_logic_vector (dsize - 1 downto 0);
34             bah             : in std_logic_vector (dsize - 1 downto 0);
35             addr_back       : out std_logic_vector (dsize - 1 downto 0);
36             acc_in          : out std_logic_vector (dsize - 1 downto 0);
37             abl             : out std_logic_vector (dsize - 1 downto 0);
38             abh             : out std_logic_vector (dsize - 1 downto 0);
39             pcl_inc_carry   : out std_logic;
40             ea_carry        : out std_logic;
41             carry_in        : in std_logic;
42             negative        : out std_logic;
43             zero            : out std_logic;
44             carry_out       : out std_logic;
45             overflow        : out std_logic
46     );
47 end alu;
48
49 architecture rtl of alu is
50
51 component d_flip_flop
52     generic (
53             dsize : integer := 8
54             );
55     port (  
56             clk     : in std_logic;
57             res_n   : in std_logic;
58             set_n   : in std_logic;
59             we_n    : in std_logic;
60             d       : in std_logic_vector (dsize - 1 downto 0);
61             q       : out std_logic_vector (dsize - 1 downto 0)
62         );
63 end component;
64
65 component d_flip_flop_bit
66     port (  
67             clk     : in std_logic;
68             res_n   : in std_logic;
69             set_n   : in std_logic;
70             we_n    : in std_logic;
71             d       : in std_logic;
72             q       : out std_logic
73         );
74 end component;
75
76 component tri_state_buffer
77     generic (
78             dsize : integer := 8
79             );
80     port (  
81             oe_n    : in std_logic;
82             d       : in std_logic_vector (dsize - 1 downto 0);
83             q       : out std_logic_vector (dsize - 1 downto 0)
84         );
85 end component;
86
87 component address_calculator
88     generic (   dsize : integer := 8
89             );
90     port ( 
91             sel         : in std_logic_vector (1 downto 0);
92             addr1       : in std_logic_vector (dsize - 1 downto 0);
93             addr2       : in std_logic_vector (dsize - 1 downto 0);
94             addr_out    : out std_logic_vector (dsize - 1 downto 0);
95             carry_in    : in std_logic;
96             carry_out   : out std_logic
97     );
98 end component;
99
100 component alu_core
101     generic (   dsize : integer := 8
102             );
103     port ( 
104             sel         : in std_logic_vector (3 downto 0);
105             d1          : in std_logic_vector (dsize - 1 downto 0);
106             d2          : in std_logic_vector (dsize - 1 downto 0);
107             d_out       : out std_logic_vector (dsize - 1 downto 0);
108             carry_in    : in std_logic;
109             negative    : out std_logic;
110             zero        : out std_logic;
111             carry_out   : out std_logic;
112             overflow    : out std_logic
113     );
114 end component;
115
116 --------- signals for address calucuration ----------
117 signal al_buf_we_n : std_logic;
118 signal ah_buf_we_n : std_logic;
119
120 signal al_reg_in : std_logic_vector (dsize - 1 downto 0);
121 signal ah_reg_in : std_logic_vector (dsize - 1 downto 0);
122 signal al_reg : std_logic_vector (dsize - 1 downto 0);
123 signal ah_reg : std_logic_vector (dsize - 1 downto 0);
124
125
126 signal a_sel : std_logic_vector (1 downto 0);
127 signal addr1 : std_logic_vector (dsize - 1 downto 0);
128 signal addr2 : std_logic_vector (dsize - 1 downto 0);
129 signal addr_out : std_logic_vector (dsize - 1 downto 0);
130
131 signal addr_c_in : std_logic;
132 signal addr_c : std_logic;
133 signal addr_c_reg : std_logic;
134
135 signal pcl_carry_reg_in : std_logic;
136
137 ----------- signals for arithmatic ----------
138 signal sel : std_logic_vector (3 downto 0);
139 signal d1 : std_logic_vector (dsize - 1 downto 0);
140 signal d2 : std_logic_vector (dsize - 1 downto 0);
141 signal d_out : std_logic_vector (dsize - 1 downto 0);
142 signal alu_out : std_logic_vector (dsize - 1 downto 0);
143
144 signal n : std_logic;
145 signal z : std_logic;
146 signal c : std_logic;
147 signal v : std_logic;
148
149 signal arith_buf_we_n : std_logic;
150 signal arith_buf_oe_n : std_logic;
151 signal arith_reg_in : std_logic_vector (dsize - 1 downto 0);
152 signal arith_reg : std_logic_vector (dsize - 1 downto 0);
153 signal arith_reg_out : std_logic_vector (dsize - 1 downto 0);
154 signal d_oe_n : std_logic;
155
156 begin
157     ----------------------------------------
158      -- address calucurator instances ----
159     ----------------------------------------
160     al_dff : d_flip_flop generic map (dsize) 
161             port map(clk, '1', '1', al_buf_we_n, al_reg_in, al_reg);
162     ah_dff : d_flip_flop generic map (dsize) 
163             port map(clk, '1', '1', ah_buf_we_n, ah_reg_in, ah_reg);
164
165     --pcl carry flag set.
166     pcl_carry_reg_in <= addr_c when pcl_inc_n = '0' else
167                 '0';
168
169     pch_carry_dff_bit : d_flip_flop_bit 
170             port map(clk, '1', '1', 
171                     '0', pcl_carry_reg_in, pcl_inc_carry);
172
173     addr_calc_inst : address_calculator generic map (dsize)
174             port map (a_sel, addr1, addr2, addr_out, addr_c_in, addr_c);
175
176     ea_carry_dff_bit : d_flip_flop_bit 
177             port map(clk, '1', '1', 
178                     '0', addr_c, addr_c_reg);
179
180     ----------------------------------------
181      -- arithmatic operation instances ----
182     ----------------------------------------
183     arith_dff : d_flip_flop generic map (dsize) 
184             port map(clk, '1', '1', arith_buf_we_n, arith_reg_in, arith_reg);
185     arith_buf : tri_state_buffer generic map (dsize)
186             port map (arith_buf_oe_n, arith_reg, arith_reg_out);
187
188     alu_inst : alu_core generic map (dsize)
189             port map (sel, d1, d2, alu_out, carry_in, n, z, c, v);
190     alu_buf : tri_state_buffer generic map (dsize)
191             port map (d_oe_n, alu_out, d_out);
192
193     -------------------------------
194     ------ alu main process -------
195     -------------------------------
196     alu_p : process (
197                     clk, 
198                     ---for address calucuration
199                     pcl_inc_n, pch_inc_n, sp_oe_n, sp_push_n, sp_pop_n,
200                     abs_xy_n, pg_next_n, zp_n, zp_xy_n, rel_calc_n, 
201                     indir_n, indir_x_n, indir_y_n, 
202                     index_bus, bal, bah, addr_c_in, addr_out, addr_c,
203
204                     --for arithmatic operation.
205                     arith_en_n,
206                     instruction, exec_cycle, int_d_bus, acc_out, 
207                     carry_in, n, z, c, v,
208                     arith_reg, arith_reg_out, alu_out, d_out
209                     )
210
211 constant ADDR_ADC    : std_logic_vector (1 downto 0) := "00";
212 constant ADDR_INC    : std_logic_vector (1 downto 0) := "01";
213 constant ADDR_DEC    : std_logic_vector (1 downto 0) := "10";
214 constant ADDR_SIGNED_ADD : std_logic_vector (1 downto 0) := "11";
215
216 constant ALU_AND    : std_logic_vector (3 downto 0) := "0000";
217 constant ALU_EOR    : std_logic_vector (3 downto 0) := "0001";
218 constant ALU_OR     : std_logic_vector (3 downto 0) := "0010";
219 constant ALU_BIT    : std_logic_vector (3 downto 0) := "0011";
220 constant ALU_ADC    : std_logic_vector (3 downto 0) := "0100";
221 constant ALU_SBC    : std_logic_vector (3 downto 0) := "0101";
222 constant ALU_CMP    : std_logic_vector (3 downto 0) := "0110";
223 constant ALU_ASL    : std_logic_vector (3 downto 0) := "0111";
224 constant ALU_LSR    : std_logic_vector (3 downto 0) := "1000";
225 constant ALU_ROL    : std_logic_vector (3 downto 0) := "1001";
226 constant ALU_ROR    : std_logic_vector (3 downto 0) := "1010";
227 constant ALU_INC    : std_logic_vector (3 downto 0) := "1011";
228 constant ALU_DEC    : std_logic_vector (3 downto 0) := "1100";
229
230 ---for indirect addressing.
231 constant T0 : std_logic_vector (5 downto 0) := "000000";
232 constant T1 : std_logic_vector (5 downto 0) := "000001";
233 constant T2 : std_logic_vector (5 downto 0) := "000010";
234 constant T3 : std_logic_vector (5 downto 0) := "000011";
235 constant T4 : std_logic_vector (5 downto 0) := "000100";
236 constant T5 : std_logic_vector (5 downto 0) := "000101";
237
238 procedure output_d_bus is
239 begin
240     arith_buf_we_n <= '0';
241     arith_buf_oe_n <= '0';
242     d_oe_n <= '0';
243     arith_reg_in <= d_out;
244     if (clk = '0') then
245         int_d_bus <= d_out;
246     else
247         int_d_bus <= arith_reg_out;
248     end if;
249 end  procedure;
250
251 procedure set_nz is
252 begin
253     negative <= n;
254     zero <= z;
255 end procedure;
256
257     begin
258
259     -------------------------------
260     ----- address calcuration -----
261     -------------------------------
262     if (pcl_inc_n = '0') then
263         a_sel <= ADDR_INC;
264         addr1 <= bal;
265         addr_back <= addr_out;
266
267         --keep the value in the cycle
268         al_buf_we_n <= '0';
269         al_reg_in <= bal;
270         if (instruction = "01001100") then
271             ---exceptional case: only jmp instruction 
272             abl <= bal;
273         else
274             if (clk = '0') then
275                 abl <= bal;
276             else
277                 abl <= al_reg;
278             end if;
279         end if;
280         abh <= bah;
281
282     elsif (pch_inc_n = '0') then
283         a_sel <= ADDR_INC;
284         addr1 <= bah;
285         addr_back <= addr_out;
286
287         --inc pch cycle is not fetch cycle.
288         --it is special cycle.
289         abl <= bal;
290         abh <= bah;
291
292     elsif (sp_oe_n = '0') then
293         --stack operation...
294         abh <= "00000001";
295
296         if (sp_push_n /= '0' and sp_pop_n /= '0') then
297             abl <= bal;
298         elsif (sp_pop_n = '0') then
299             --case pop
300             a_sel <= ADDR_INC;
301             addr1 <= bal;
302             addr_back <= addr_out;
303
304             al_buf_we_n <= '0';
305             al_reg_in <= bal;
306             if (clk = '0') then
307                 abl <= bal;
308             else
309                 abl <= al_reg;
310             end if;
311         else
312             ---case push
313             a_sel <= ADDR_DEC;
314             addr1 <= bal;
315             addr_back <= addr_out;
316
317             al_buf_we_n <= '0';
318             al_reg_in <= bal;
319             if (clk = '0') then
320                 abl <= bal;
321             else
322                 abl <= al_reg;
323             end if;
324         end if;
325     elsif (zp_n = '0') then
326         if (zp_xy_n <= '0') then
327             a_sel <= ADDR_ADC;
328             addr1 <= bal;
329             addr2 <= index_bus;
330             addr_c_in <= '0';
331
332             abh <= "00000000";
333             abl <= addr_out;
334         else
335             abh <= "00000000";
336             abl <= bal;
337         end if;
338
339     elsif (abs_xy_n = '0') then
340         if (pg_next_n = '0') then
341             a_sel <= ADDR_INC;
342             addr1 <= bah;
343             ea_carry <= '0';
344
345             al_buf_we_n <= '1';
346             abh <= addr_out;
347             ---al is in the al_reg.
348             abl <= al_reg;
349         else
350             a_sel <= ADDR_ADC;
351             addr1 <= bal;
352             addr2 <= index_bus;
353             addr_c_in <= '0';
354             ea_carry <= addr_c;
355
356             ---keep al for page crossed case
357             al_buf_we_n <= '0';
358             al_reg_in <= addr_out;
359             abh <= bah;
360             abl <= addr_out;
361         end if;
362
363     elsif (rel_calc_n = '0') then
364         if (pg_next_n = '0') then
365             if (int_d_bus(7) = '1') then
366                 ---backward relative branch
367                 a_sel <= ADDR_DEC;
368             else
369                 ---forward relative branch
370                 a_sel <= ADDR_INC;
371             end if;
372             ---addr1 is pch.`
373             addr1 <= bah;
374             ---rel val is on the d_bus.
375             addr_back <= addr_out;
376             ea_carry <= '0'; 
377
378             --keep the value in the cycle
379             ah_buf_we_n <= '0';
380             ah_reg_in <= addr_out;
381             abh <= addr_out;
382             --al no change.
383             abl <= bal;
384         else
385             a_sel <= ADDR_SIGNED_ADD;
386             ---addr1 is pcl.`
387             addr1 <= bal;
388             ---rel val is on the d_bus.
389             addr2 <= int_d_bus;
390             addr_back <= addr_out;
391             addr_c_in <= '0';
392             ea_carry <= addr_c_reg;
393
394             --keep the value in the cycle
395             al_buf_we_n <= '0';
396             al_reg_in <= addr_out;
397             abh <= bah;
398             abl <= addr_out;
399         end if;
400     elsif (indir_n = '0') then
401         abh <= bah;
402         --get next address.
403         addr1 <= bal;
404         a_sel <= ADDR_INC;
405         abl <= addr_out;
406
407         --TODO: must handle page crossing case...
408         ea_carry <= addr_c;
409
410     elsif (indir_x_n = '0') then
411
412     elsif (indir_y_n = '0') then
413
414         if (clk = '0') then
415         if (exec_cycle = T2) then
416             ---input is IAL.
417             abh <= "00000000";
418             abl <= bal;
419
420             ---save BAL.
421             al_buf_we_n <= '0';
422             al_reg_in <= int_d_bus;
423
424         elsif (exec_cycle = T3) then
425             al_buf_we_n <= '1';
426
427             abh <= "00000000";
428
429             --input is IAL + 1
430             a_sel <= ADDR_INC;
431             addr1 <= bal;
432             abl <= addr_out;
433
434             ---save BAH.
435             ah_buf_we_n <= '0';
436             ah_reg_in <= int_d_bus;
437
438         elsif (exec_cycle = T4) then
439
440             ---add y reg.
441             a_sel <= ADDR_ADC;
442
443             --bal from al_reg.
444             addr1 <= al_reg;
445             addr2 <= index_bus;
446             addr_c_in <= '0';
447             ea_carry <= addr_c;
448
449             --bah from ah_reg
450             abh <= ah_reg;
451             abl <= addr_out;
452
453             ---save the address.
454             al_buf_we_n <= '0';
455             al_reg_in <= addr_out;
456             ah_buf_we_n <= '0';
457             ah_reg_in <= ah_reg;
458         elsif (exec_cycle = T0 and pg_next_n = '0') then
459             ea_carry <= '0';
460             a_sel <= ADDR_INC;
461             addr1 <= ah_reg;
462             ---next page.
463             abh <= addr_out;
464             abl <= al_reg;
465         end if; -- if (exec_cycle = T2) then
466         end if; --if (clk = '0') then
467     else
468         al_buf_we_n <= '1';
469         ah_buf_we_n <= '1';
470
471         abl <= bal;
472         abh <= bah;
473
474         ----addr_back is always bal for jmp/jsr instruction....
475         -----TODO must check later if it's ok.
476         addr_back <= bal;
477     end if; --if (pcl_inc_n = '0') then
478
479     -------------------------------
480     ---- arithmatic operations-----
481     -------------------------------
482     if (arith_en_n = '0') then
483
484         if instruction = conv_std_logic_vector(16#ca#, dsize) then
485             --d_print("dex");
486             sel <= ALU_DEC;
487             d1 <= index_bus;
488             set_nz;
489             output_d_bus;
490
491         elsif instruction = conv_std_logic_vector(16#88#, dsize) then
492             --d_print("dey");
493             sel <= ALU_DEC;
494             d1 <= index_bus;
495             set_nz;
496             output_d_bus;
497
498         elsif instruction = conv_std_logic_vector(16#e8#, dsize) then
499             --d_print("inx");
500             sel <= ALU_INC;
501             d1 <= index_bus;
502             set_nz;
503             output_d_bus;
504
505         elsif instruction = conv_std_logic_vector(16#c8#, dsize) then
506             --d_print("iny");
507             sel <= ALU_INC;
508             d1 <= index_bus;
509             set_nz;
510             output_d_bus;
511
512         elsif instruction = conv_std_logic_vector(16#0a#, dsize) then
513             --d_print("asl");
514             sel <= ALU_ASL;
515             d1 <= acc_out;
516             set_nz;
517             carry_out <= c;
518             output_d_bus;
519
520         elsif instruction = conv_std_logic_vector(16#2a#, dsize) then
521             --rol acc.
522             sel <= ALU_ROL;
523             d1 <= acc_out;
524             set_nz;
525             carry_out <= c;
526             output_d_bus;
527
528         elsif instruction = conv_std_logic_vector(16#4a#, dsize) then
529             --lsr acc.
530             sel <= ALU_LSR;
531             d1 <= acc_out;
532             set_nz;
533             carry_out <= c;
534             output_d_bus;
535
536         elsif instruction = conv_std_logic_vector(16#6a#, dsize) then
537             --ror acc.
538             sel <= ALU_ROR;
539             d1 <= acc_out;
540             set_nz;
541             carry_out <= c;
542             output_d_bus;
543
544         --instruction is aaabbbcc format.
545         --aaa=opcode
546         --bbb=addr mode
547         --000   #immediate
548         --001   zero page
549         --010   accumulator
550         --011   absolute
551         --101   zero page,X
552         --111   absolute,X
553         --cc=optional field.
554         elsif instruction (1 downto 0) = "01" then
555             if instruction (7 downto 5) = "000" then
556                 --d_print("ora");
557                 sel <= ALU_OR;
558                 d1 <= acc_out;
559                 d2 <= int_d_bus;
560                 d_oe_n <= '0';
561                 acc_in <= d_out;
562                 set_nz;
563
564             elsif instruction (7 downto 5) = "001" then
565                 --d_print("and");
566                 sel <= ALU_AND;
567                 d1 <= acc_out;
568                 d2 <= int_d_bus;
569                 d_oe_n <= '0';
570                 acc_in <= d_out;
571                 set_nz;
572
573             elsif instruction (7 downto 5) = "010" then
574                 --d_print("eor");
575                 sel <= ALU_EOR;
576                 d1 <= acc_out;
577                 d2 <= int_d_bus;
578                 d_oe_n <= '0';
579                 acc_in <= d_out;
580                 set_nz;
581
582             elsif instruction (7 downto 5) = "011" then
583                 --d_print("adc");
584                 sel <= ALU_ADC;
585                 d1 <= acc_out;
586                 d2 <= int_d_bus;
587                 d_oe_n <= '0';
588
589                 acc_in <= d_out;
590                 set_nz;
591                 carry_out <= c;
592                 overflow <= v;
593
594             elsif instruction (7 downto 5) = "110" then
595                 --d_print("cmp");
596                 --cmpare A - M.
597                 sel <= ALU_CMP;
598                 d1 <= acc_out;
599                 d2 <= int_d_bus;
600                 set_nz;
601                 carry_out <= c;
602
603             elsif instruction (7 downto 5) = "111" then
604                 --d_print("sbc");
605                 sel <= ALU_SBC;
606                 d1 <= acc_out;
607                 d2 <= int_d_bus;
608                 d_oe_n <= '0';
609
610                 acc_in <= d_out;
611                 set_nz;
612                 carry_out <= c;
613                 overflow <= v;
614
615             end if; --if instruction (7 downto 5) = "000" then
616
617         elsif instruction (1 downto 0) = "10" then
618
619             --this group is all memory to memory instruction (except for stx/ldx).
620             --memory to memory operation takes two cycles.
621             --first is write original data 
622             --second is write modified data
623
624             --001       zero page
625             --011       absolute
626             --101       zero page,X
627             --111       absolute,X
628             if ((exec_cycle = T3 and instruction (4 downto 2) = "001") or 
629                 (exec_cycle = T4 and instruction (4 downto 2) = "011") or 
630                 (exec_cycle = T4 and instruction (4 downto 2) = "101") or 
631                 (exec_cycle = T5 and instruction (4 downto 2) = "111")) then
632                 --first cycle. keep input variable.
633                 --d_print("inc first.");
634                 arith_buf_we_n <= '0';
635                 arith_buf_oe_n <= '1';
636                 d_oe_n <= '1';
637
638                 arith_reg_in <= int_d_bus;
639                 d1 <= arith_reg;
640             else
641                 --second cycle read from register, output modified data.
642                 --d_print("inc second...");
643                 arith_buf_we_n <= '1';
644                 arith_buf_oe_n <= '0';
645                 d_oe_n <= '0';
646
647                 int_d_bus <= d_out;
648             end if;
649
650             if instruction (7 downto 5) = "000" then
651                 --d_print("asl");
652                 sel <= ALU_ASL;
653                 set_nz;
654                 carry_out <= c;
655
656             elsif instruction (7 downto 5) = "001" then
657                 --d_print("rol");
658                 sel <= ALU_ROL;
659                 set_nz;
660                 carry_out <= c;
661
662             elsif instruction (7 downto 5) = "010" then
663                 --d_print("lsr");
664                 sel <= ALU_LSR;
665                 set_nz;
666                 carry_out <= c;
667
668             elsif instruction (7 downto 5) = "011" then
669                 --d_print("ror");
670                 sel <= ALU_ROR;
671                 set_nz;
672                 carry_out <= c;
673
674             elsif instruction (7 downto 5) = "110" then
675                 --d_print("dec");
676                 sel <= ALU_DEC;
677                 set_nz;
678
679             elsif instruction (7 downto 5) = "111" then
680                 --d_print("alu inc");
681                 sel <= ALU_INC;
682                 set_nz;
683
684             end if; --if instruction (7 downto 5) = "000" then
685
686         elsif instruction (1 downto 0) = "00" then
687             if instruction (7 downto 5) = "001" then
688                 --d_print("bit");
689                 sel <= ALU_BIT;
690                 d1 <= acc_out;
691                 d2 <= int_d_bus;
692                 set_nz;
693                 overflow <= v;
694             elsif instruction (7 downto 5) = "110" then
695                 --d_print("cpy");
696                 sel <= ALU_CMP;
697                 d1 <= index_bus;
698                 d2 <= int_d_bus;
699                 set_nz;
700                 carry_out <= c;
701
702             elsif instruction (7 downto 5) = "111" then
703                -- d_print("cpx");
704                 sel <= ALU_CMP;
705                 d1 <= index_bus;
706                 d2 <= int_d_bus;
707                 set_nz;
708                 carry_out <= c;
709
710             end if; --if instruction (7 downto 5) = "001" then
711         end if; --if instruction = conv_std_logic_vector(16#ca#, dsize) 
712     else
713         --d_print("no arith");
714         d_oe_n <= '1';
715         arith_buf_we_n <= '1';
716         arith_buf_oe_n <= '1';
717         int_d_bus <= (others => 'Z');
718     end if; -- if (arith_en_n = '0') then
719
720     end process;
721
722 end rtl;
723
724 -----------------------------------------
725 ---------- Address calculator------------
726 -----------------------------------------
727
728 library ieee;
729 use ieee.std_logic_1164.all;
730 use ieee.std_logic_unsigned.all;
731
732 entity address_calculator is 
733     generic (   dsize : integer := 8
734             );
735     port ( 
736             sel         : in std_logic_vector (1 downto 0);
737             addr1       : in std_logic_vector (dsize - 1 downto 0);
738             addr2       : in std_logic_vector (dsize - 1 downto 0);
739             addr_out    : out std_logic_vector (dsize - 1 downto 0);
740             carry_in    : in std_logic;
741             carry_out   : out std_logic
742     );
743 end address_calculator;
744
745 architecture rtl of address_calculator is
746
747 constant ADDR_ADC    : std_logic_vector (1 downto 0) := "00";
748 constant ADDR_INC    : std_logic_vector (1 downto 0) := "01";
749 constant ADDR_DEC    : std_logic_vector (1 downto 0) := "10";
750 constant ADDR_SIGNED_ADD : std_logic_vector (1 downto 0) := "11";
751
752 begin
753
754     alu_p : process (sel, addr1, addr2, carry_in)
755     variable res : std_logic_vector (dsize downto 0);
756
757     begin
758     if sel = ADDR_ADC then
759         res := ('0' & addr1) + ('0' & addr2) + carry_in;
760         addr_out <= res(dsize - 1 downto 0);
761         carry_out <= res(dsize);
762
763     elsif sel = ADDR_SIGNED_ADD then
764         res := ('0' & addr1) + ('0' & addr2);
765         addr_out <= res(dsize - 1 downto 0);
766 --        if (addr2(dsize - 1) = '0') then
767 --            ---positive value add.
768 --            if (res(dsize) = '1') then
769 --                carry_out <= '1';
770 --            else
771 --                carry_out <= '0';
772 --            end if;
773 --        else
774 --            ---negative value add.
775 --            if (res(dsize) = '0') then
776 --                carry_out <= '1';
777 --            else
778 --                carry_out <= '0';
779 --            end if;
780 --        end if;
781         -->>>simplified above.
782         if ((addr2(dsize - 1) xor res(dsize)) = '1') then
783             carry_out <= '1';
784         else
785             carry_out <= '0';
786         end if;
787
788     elsif sel = ADDR_INC then
789         res := ('0' & addr1) + "000000001";
790         addr_out <= res(dsize - 1 downto 0);
791         carry_out <= res(dsize);
792     elsif sel = ADDR_DEC then
793         res := ('0' & addr1) - "000000001";
794         addr_out <= res(dsize - 1 downto 0);
795         carry_out <= res(dsize);
796     end if;
797     end process;
798
799 end rtl;
800
801
802 -----------------------------------------
803 ------------- ALU Core -----------------
804 -----------------------------------------
805
806 library ieee;
807 use ieee.std_logic_1164.all;
808 use ieee.std_logic_unsigned.all;
809
810 ----d1 = acc
811 ----d2 = memory
812 entity alu_core is 
813     generic (   dsize : integer := 8
814             );
815     port ( 
816             sel         : in std_logic_vector (3 downto 0);
817             d1          : in std_logic_vector (dsize - 1 downto 0);
818             d2          : in std_logic_vector (dsize - 1 downto 0);
819             d_out       : out std_logic_vector (dsize - 1 downto 0);
820             carry_in    : in std_logic;
821             negative    : out std_logic;
822             zero        : out std_logic;
823             carry_out   : out std_logic;
824             overflow    : out std_logic
825     );
826 end alu_core;
827
828 architecture rtl of alu_core is
829
830 constant ALU_AND    : std_logic_vector (3 downto 0) := "0000";
831 constant ALU_EOR    : std_logic_vector (3 downto 0) := "0001";
832 constant ALU_OR     : std_logic_vector (3 downto 0) := "0010";
833 constant ALU_BIT    : std_logic_vector (3 downto 0) := "0011";
834 constant ALU_ADC    : std_logic_vector (3 downto 0) := "0100";
835 constant ALU_SBC    : std_logic_vector (3 downto 0) := "0101";
836 constant ALU_CMP    : std_logic_vector (3 downto 0) := "0110";
837 constant ALU_ASL    : std_logic_vector (3 downto 0) := "0111";
838 constant ALU_LSR    : std_logic_vector (3 downto 0) := "1000";
839 constant ALU_ROL    : std_logic_vector (3 downto 0) := "1001";
840 constant ALU_ROR    : std_logic_vector (3 downto 0) := "1010";
841 constant ALU_INC    : std_logic_vector (3 downto 0) := "1011";
842 constant ALU_DEC    : std_logic_vector (3 downto 0) := "1100";
843
844 begin
845
846     alu_p : process (sel, d1, d2, carry_in)
847     variable res : std_logic_vector (dsize downto 0);
848
849 procedure set_n (data : in std_logic_vector (dsize - 1 downto 0)) is
850 begin
851     if (data(7) = '1') then
852         negative <= '1';
853     else
854         negative <= '0';
855     end if;
856 end procedure;
857
858 procedure set_z (data : in std_logic_vector (dsize - 1 downto 0)) is
859 begin
860     if  (data = "00000000") then
861         zero <= '1';
862     else
863         zero <= '0';
864     end if;
865 end procedure;
866
867     begin
868     if sel = ALU_AND then
869         res(dsize - 1 downto 0) := d1 and d2;
870         set_n(res(dsize - 1 downto 0));
871         set_z(res(dsize - 1 downto 0));
872         d_out <= res(dsize - 1 downto 0);
873
874     elsif sel = ALU_EOR then
875         res(dsize - 1 downto 0) := d1 xor d2;
876         set_n(res(dsize - 1 downto 0));
877         set_z(res(dsize - 1 downto 0));
878         d_out <= res(dsize - 1 downto 0);
879
880     elsif sel = ALU_OR then
881         res(dsize - 1 downto 0) := d1 or d2;
882         set_n(res(dsize - 1 downto 0));
883         set_z(res(dsize - 1 downto 0));
884         d_out <= res(dsize - 1 downto 0);
885
886     elsif sel = ALU_BIT then
887         --transfer bit 7 and 6  of memory data to n, v flag.
888         negative <= d2(7);
889         overflow <= d2(6);
890         ----zero bit after A and M.
891         res(dsize - 1 downto 0) := d1 and d2;
892         set_z(res(dsize - 1 downto 0));
893
894     elsif sel = ALU_ADC then
895         res := ('0' & d1) + ('0' & d2) + carry_in;
896         d_out <= res(dsize - 1 downto 0);
897         carry_out <= res(dsize);
898         if ((d1(dsize - 1) = d2(dsize - 1)) 
899             and (d1(dsize - 1) /= res(dsize - 1))) then
900             overflow <= '1';
901         else
902             overflow <= '0';
903         end if;
904         set_n(res(dsize - 1 downto 0));
905         set_z(res(dsize - 1 downto 0));
906
907     elsif sel = ALU_SBC then
908         ---A - M - ~C -> A
909         res := ('0' & d1) - ('0' & d2) - not carry_in;
910         d_out <= res(dsize - 1 downto 0);
911
912         --c Set if unsigned borrow not required; cleared if unsigned borrow.
913         carry_out <= not res(dsize);
914         --v Set if signed borrow required; cleared if no signed borrow.
915         if ((d1(dsize - 1) /= d2(dsize - 1)) 
916             and (d1(dsize - 1) /= res(dsize - 1))) then
917             overflow <= '1';
918         else
919             overflow <= '0';
920         end if;
921         set_n(res(dsize - 1 downto 0));
922         set_z(res(dsize - 1 downto 0));
923
924     elsif sel = ALU_CMP then
925         res := ('0' & d1) - ('0' & d2);
926         if (d1 >= d2) then
927             carry_out <= '1';
928         else
929             carry_out <= '0';
930         end if;
931         set_n(res(dsize - 1 downto 0));
932         set_z(res(dsize - 1 downto 0));
933
934     elsif sel = ALU_ASL then
935         res(dsize - 1 downto 1) := d1(dsize - 2 downto 0);
936         res(0) := '0';
937
938         d_out <= res(dsize - 1 downto 0);
939         set_n(res(dsize - 1 downto 0));
940         set_z(res(dsize - 1 downto 0));
941         carry_out <= d1(dsize - 1);
942
943     elsif sel = ALU_LSR then
944         res(dsize - 1) := '0';
945         res(dsize - 2 downto 0) := d1(dsize - 1 downto 1);
946
947         d_out <= res(dsize - 1 downto 0);
948         set_n(res(dsize - 1 downto 0));
949         set_z(res(dsize - 1 downto 0));
950         carry_out <= d1(0);
951
952     elsif sel = ALU_ROL then
953         res(dsize - 1 downto 1) := d1(dsize - 2 downto 0);
954         res(0) := carry_in;
955
956         d_out <= res(dsize - 1 downto 0);
957         set_n(res(dsize - 1 downto 0));
958         set_z(res(dsize - 1 downto 0));
959         carry_out <= d1(7);
960
961     elsif sel = ALU_ROR then
962         res(dsize - 1) := carry_in;
963         res(dsize - 2 downto 0) := d1(dsize - 1 downto 1);
964
965         d_out <= res(dsize - 1 downto 0);
966         set_n(res(dsize - 1 downto 0));
967         set_z(res(dsize - 1 downto 0));
968         carry_out <= d1(0);
969
970     elsif sel = ALU_INC then
971         res := ('0' & d1) + "000000001";
972         d_out <= res(dsize - 1 downto 0);
973         set_n(res(dsize - 1 downto 0));
974         set_z(res(dsize - 1 downto 0));
975
976     elsif sel = ALU_DEC then
977         res := ('0' & d1) - "000000001";
978         d_out <= res(dsize - 1 downto 0);
979         set_n(res(dsize - 1 downto 0));
980         set_z(res(dsize - 1 downto 0));
981
982     end if;
983
984     end process;
985
986 end rtl;
987