1 ----------------------------
2 ---- 6502 ALU implementation
3 ----------------------------
5 use ieee.std_logic_1164.all;
6 use ieee.std_logic_unsigned.all;
7 use ieee.std_logic_arith.conv_std_logic_vector;
10 generic ( dsize : integer := 8
12 port ( clk : in std_logic;
13 pcl_inc_n : in std_logic;
14 pch_inc_n : in std_logic;
15 sp_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;
21 zp_xy_n : in std_logic;
22 rel_calc_n : in std_logic;
23 indir_n : in std_logic;
24 indir_x_n : in std_logic;
25 indir_y_n : in std_logic;
26 arith_en_n : in std_logic;
27 instruction : in std_logic_vector (dsize - 1 downto 0);
28 exec_cycle : in std_logic_vector (5 downto 0);
29 int_d_bus : inout std_logic_vector (dsize - 1 downto 0);
30 acc_out : in std_logic_vector (dsize - 1 downto 0);
31 index_bus : in std_logic_vector (dsize - 1 downto 0);
32 bal : in std_logic_vector (dsize - 1 downto 0);
33 bah : in std_logic_vector (dsize - 1 downto 0);
34 addr_back : out std_logic_vector (dsize - 1 downto 0);
35 acc_in : out std_logic_vector (dsize - 1 downto 0);
36 abl : out std_logic_vector (dsize - 1 downto 0);
37 abh : out std_logic_vector (dsize - 1 downto 0);
38 pcl_inc_carry : out std_logic;
39 ea_carry : out std_logic;
40 carry_in : in std_logic;
41 negative : out std_logic;
43 carry_out : out std_logic;
44 overflow : out std_logic
48 architecture rtl of alu is
59 d : in std_logic_vector (dsize - 1 downto 0);
60 q : out std_logic_vector (dsize - 1 downto 0)
64 component d_flip_flop_bit
75 component tri_state_buffer
81 d : in std_logic_vector (dsize - 1 downto 0);
82 q : out std_logic_vector (dsize - 1 downto 0)
86 component address_calculator
87 generic ( dsize : integer := 8
90 sel : in std_logic_vector (1 downto 0);
91 addr1 : in std_logic_vector (dsize - 1 downto 0);
92 addr2 : in std_logic_vector (dsize - 1 downto 0);
93 addr_out : out std_logic_vector (dsize - 1 downto 0);
94 carry_in : in std_logic;
95 carry_out : out std_logic
100 generic ( dsize : integer := 8
103 sel : in std_logic_vector (3 downto 0);
104 d1 : in std_logic_vector (dsize - 1 downto 0);
105 d2 : in std_logic_vector (dsize - 1 downto 0);
106 d_out : out std_logic_vector (dsize - 1 downto 0);
107 carry_in : in std_logic;
108 negative : out std_logic;
109 zero : out std_logic;
110 carry_out : out std_logic;
111 overflow : out std_logic
116 --------- signals for address calucuration ----------
117 signal al_buf_we_n : std_logic;
118 signal ah_buf_we_n : std_logic;
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);
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);
131 signal addr_c_in : std_logic;
132 signal addr_c : std_logic;
134 signal pcl_carry_reg_in : std_logic;
136 ----------- signals for arithmatic ----------
137 signal sel : std_logic_vector (3 downto 0);
138 signal d1 : std_logic_vector (dsize - 1 downto 0);
139 signal d2 : std_logic_vector (dsize - 1 downto 0);
140 signal d_out : std_logic_vector (dsize - 1 downto 0);
141 signal alu_out : std_logic_vector (dsize - 1 downto 0);
143 signal n : std_logic;
144 signal z : std_logic;
145 signal c : std_logic;
146 signal v : std_logic;
148 signal arith_buf_we_n : std_logic;
149 signal arith_buf_oe_n : std_logic;
150 signal arith_reg_in : std_logic_vector (dsize - 1 downto 0);
151 signal arith_reg : std_logic_vector (dsize - 1 downto 0);
152 signal arith_reg_out : std_logic_vector (dsize - 1 downto 0);
153 signal d_oe_n : std_logic;
155 signal m2m_stat_1 : std_logic;
156 signal m2m_stat_2 : std_logic;
160 ----------------------------------------
161 -- address calucurator instances ----
162 ----------------------------------------
163 al_dff : d_flip_flop generic map (dsize)
164 port map(clk, '1', '1', al_buf_we_n, al_reg_in, al_reg);
165 ah_dff : d_flip_flop generic map (dsize)
166 port map(clk, '1', '1', ah_buf_we_n, ah_reg_in, ah_reg);
168 --pcl carry flag set.
169 pcl_carry_reg_in <= addr_c when pcl_inc_n = '0' else
172 pch_carry_dff_bit : d_flip_flop_bit
173 port map(clk, '1', '1',
174 '0', pcl_carry_reg_in, pcl_inc_carry);
176 addr_calc_inst : address_calculator generic map (dsize)
177 port map (a_sel, addr1, addr2, addr_out, addr_c_in, addr_c);
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);
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);
193 -------------------------------
194 ------ alu main process -------
195 -------------------------------
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, bal, addr_c_in, addr_out, addr_c,
204 --for arithmatic operation.
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
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";
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";
230 ---for indirect addressing.
231 constant T1 : std_logic_vector (5 downto 0) := "000001";
232 constant T2 : std_logic_vector (5 downto 0) := "000010";
233 constant T3 : std_logic_vector (5 downto 0) := "000011";
234 constant T4 : std_logic_vector (5 downto 0) := "000100";
235 constant T5 : std_logic_vector (5 downto 0) := "000101";
237 procedure output_d_bus is
239 arith_buf_we_n <= '0';
240 arith_buf_oe_n <= '0';
242 arith_reg_in <= d_out;
246 int_d_bus <= arith_reg_out;
250 procedure d_print(msg : string) is
252 --use ieee.std_logic_textio.all;
253 --variable out_l : line;
255 -- write(out_l, msg);
256 -- writeline(output, out_l);
267 -------------------------------
268 ----- address calcuration -----
269 -------------------------------
270 if (pcl_inc_n = '0') then
273 addr_back <= addr_out;
275 --keep the value in the cycle
278 if (instruction = "01001100") then
279 ---exceptional case: only jmp instruction
290 elsif (pch_inc_n = '0') then
293 addr_back <= addr_out;
295 --inc pch cycle is not fetch cycle.
296 --it is special cycle.
300 elsif (sp_oe_n = '0') then
304 if (sp_push_n /= '0' and sp_pop_n /= '0') then
306 elsif (sp_pop_n = '0') then
310 addr_back <= addr_out;
323 addr_back <= addr_out;
333 elsif (zp_n = '0') then
334 if (zp_xy_n <= '0') then
347 elsif (abs_xy_n = '0') then
348 if (pg_next_n = '0') then
355 ---al is in the al_reg.
364 ---keep al for page crossed case
366 al_reg_in <= addr_out;
371 elsif (rel_calc_n = '0') then
372 if (pg_next_n = '0') then
373 if (int_d_bus(7) = '1') then
374 ---backward relative branch
377 ---forward relative branch
382 ---rel val is on the d_bus.
383 addr_back <= addr_out;
386 --keep the value in the cycle
388 ah_reg_in <= addr_out;
393 a_sel <= ADDR_SIGNED_ADD;
396 ---rel val is on the d_bus.
398 addr_back <= addr_out;
401 --keep the value in the cycle
403 al_reg_in <= addr_out;
411 elsif (indir_n = '0') then
418 --TODO: must handle page crossing case...
421 elsif (indir_x_n = '0') then
423 elsif (indir_y_n = '0') then
426 if (exec_cycle = T2) then
433 al_reg_in <= int_d_bus;
435 elsif (exec_cycle = T3) then
447 ah_reg_in <= int_d_bus;
449 elsif (exec_cycle = T4) then
466 al_reg_in <= addr_out;
469 elsif (exec_cycle = T5) then
471 if (pg_next_n = '0') then
481 end if; -- if (exec_cycle = T2) then
482 end if; --if (clk = '0') then
490 ----addr_back is always bal for jmp/jsr instruction....
491 -----TODO must check later if it's ok.
493 end if; --if (pcl_inc_n = '0') then
495 -------------------------------
496 ---- arithmatic operations-----
497 -------------------------------
498 if (arith_en_n = '0') then
500 if instruction = conv_std_logic_vector(16#ca#, dsize) then
507 elsif instruction = conv_std_logic_vector(16#88#, dsize) then
514 elsif instruction = conv_std_logic_vector(16#e8#, dsize) then
521 elsif instruction = conv_std_logic_vector(16#c8#, dsize) then
528 elsif instruction = conv_std_logic_vector(16#0a#, dsize) then
536 elsif instruction = conv_std_logic_vector(16#2a#, dsize) then
544 elsif instruction = conv_std_logic_vector(16#4a#, dsize) then
552 elsif instruction = conv_std_logic_vector(16#6a#, dsize) then
560 --instruction is aaabbbcc format.
561 elsif instruction (1 downto 0) = "01" then
562 if instruction (7 downto 5) = "000" then
571 elsif instruction (7 downto 5) = "001" then
580 elsif instruction (7 downto 5) = "010" then
589 elsif instruction (7 downto 5) = "011" then
601 elsif instruction (7 downto 5) = "110" then
610 elsif instruction (7 downto 5) = "111" then
622 end if; --if instruction (7 downto 5) = "000" then
624 elsif instruction (1 downto 0) = "10" then
626 --this group is all memory to memory instruction (except for stx/ldx).
627 --memory to memory operation takes two cycles.
628 --first is write original data
629 --second is write modified data
631 arith_reg_in <= int_d_bus;
637 if (m2m_stat_1 = '0') then
638 --first cycle. keep input variable.
639 --d_print("inc first.");
641 arith_buf_we_n <= '0';
642 arith_buf_oe_n <= '1';
648 if (clk'event and clk = '0') then
649 if (m2m_stat_2 = '0') then
650 --second cycle read from register, output modified data.
651 --d_print("inc second...");
653 arith_buf_we_n <= '1';
654 arith_buf_oe_n <= '0';
660 if instruction (7 downto 5) = "000" then
666 elsif instruction (7 downto 5) = "001" then
672 elsif instruction (7 downto 5) = "010" then
678 elsif instruction (7 downto 5) = "011" then
684 elsif instruction (7 downto 5) = "110" then
689 elsif instruction (7 downto 5) = "111" then
690 --d_print("alu inc");
694 end if; --if instruction (7 downto 5) = "000" then
696 elsif instruction (1 downto 0) = "00" then
697 if instruction (7 downto 5) = "001" then
704 elsif instruction (7 downto 5) = "110" then
712 elsif instruction (7 downto 5) = "111" then
720 end if; --if instruction (7 downto 5) = "001" then
721 end if; --if instruction = conv_std_logic_vector(16#ca#, dsize)
723 --d_print("no arith");
727 arith_buf_we_n <= '1';
728 arith_buf_oe_n <= '1';
729 int_d_bus <= (others => 'Z');
730 end if; -- if (arith_en_n = '0') then
736 -----------------------------------------
737 ---------- Address calculator------------
738 -----------------------------------------
741 use ieee.std_logic_1164.all;
742 use ieee.std_logic_unsigned.all;
744 entity address_calculator is
745 generic ( dsize : integer := 8
748 sel : in std_logic_vector (1 downto 0);
749 addr1 : in std_logic_vector (dsize - 1 downto 0);
750 addr2 : in std_logic_vector (dsize - 1 downto 0);
751 addr_out : out std_logic_vector (dsize - 1 downto 0);
752 carry_in : in std_logic;
753 carry_out : out std_logic
755 end address_calculator;
757 architecture rtl of address_calculator is
759 constant ADDR_ADC : std_logic_vector (1 downto 0) := "00";
760 constant ADDR_INC : std_logic_vector (1 downto 0) := "01";
761 constant ADDR_DEC : std_logic_vector (1 downto 0) := "10";
762 constant ADDR_SIGNED_ADD : std_logic_vector (1 downto 0) := "11";
766 alu_p : process (sel, addr1, addr2, carry_in)
767 variable res : std_logic_vector (dsize downto 0);
770 if sel = ADDR_ADC then
771 res := ('0' & addr1) + ('0' & addr2) + carry_in;
772 addr_out <= res(dsize - 1 downto 0);
773 carry_out <= res(dsize);
775 elsif sel = ADDR_SIGNED_ADD then
776 res := ('0' & addr1) + ('0' & addr2);
777 addr_out <= res(dsize - 1 downto 0);
778 -- if (addr2(dsize - 1) = '0') then
779 -- ---positive value add.
780 -- if (res(dsize) = '1') then
786 -- ---negative value add.
787 -- if (res(dsize) = '0') then
793 -->>>simplified above.
794 if ((addr2(dsize - 1) xor res(dsize)) = '1') then
800 elsif sel = ADDR_INC then
801 res := ('0' & addr1) + "000000001";
802 addr_out <= res(dsize - 1 downto 0);
803 carry_out <= res(dsize);
804 elsif sel = ADDR_DEC then
805 res := ('0' & addr1) - "000000001";
806 addr_out <= res(dsize - 1 downto 0);
807 carry_out <= res(dsize);
814 -----------------------------------------
815 ------------- ALU Core -----------------
816 -----------------------------------------
819 use ieee.std_logic_1164.all;
820 use ieee.std_logic_unsigned.all;
825 generic ( dsize : integer := 8
828 sel : in std_logic_vector (3 downto 0);
829 d1 : in std_logic_vector (dsize - 1 downto 0);
830 d2 : in std_logic_vector (dsize - 1 downto 0);
831 d_out : out std_logic_vector (dsize - 1 downto 0);
832 carry_in : in std_logic;
833 negative : out std_logic;
834 zero : out std_logic;
835 carry_out : out std_logic;
836 overflow : out std_logic
840 architecture rtl of alu_core is
842 procedure d_print(msg : string) is
844 --use ieee.std_logic_textio.all;
845 variable out_l : line;
847 -- write(out_l, msg);
848 -- writeline(output, out_l);
851 constant ALU_AND : std_logic_vector (3 downto 0) := "0000";
852 constant ALU_EOR : std_logic_vector (3 downto 0) := "0001";
853 constant ALU_OR : std_logic_vector (3 downto 0) := "0010";
854 constant ALU_BIT : std_logic_vector (3 downto 0) := "0011";
855 constant ALU_ADC : std_logic_vector (3 downto 0) := "0100";
856 constant ALU_SBC : std_logic_vector (3 downto 0) := "0101";
857 constant ALU_CMP : std_logic_vector (3 downto 0) := "0110";
858 constant ALU_ASL : std_logic_vector (3 downto 0) := "0111";
859 constant ALU_LSR : std_logic_vector (3 downto 0) := "1000";
860 constant ALU_ROL : std_logic_vector (3 downto 0) := "1001";
861 constant ALU_ROR : std_logic_vector (3 downto 0) := "1010";
862 constant ALU_INC : std_logic_vector (3 downto 0) := "1011";
863 constant ALU_DEC : std_logic_vector (3 downto 0) := "1100";
867 alu_p : process (sel, d1, d2, carry_in)
868 variable res : std_logic_vector (dsize downto 0);
870 procedure set_n (data : in std_logic_vector (dsize - 1 downto 0)) is
872 if (data(7) = '1') then
879 procedure set_z (data : in std_logic_vector (dsize - 1 downto 0)) is
881 if (data = "00000000") then
889 if sel = ALU_AND then
890 res(dsize - 1 downto 0) := d1 and d2;
891 set_n(res(dsize - 1 downto 0));
892 set_z(res(dsize - 1 downto 0));
893 d_out <= res(dsize - 1 downto 0);
895 elsif sel = ALU_EOR then
896 res(dsize - 1 downto 0) := d1 xor d2;
897 set_n(res(dsize - 1 downto 0));
898 set_z(res(dsize - 1 downto 0));
899 d_out <= res(dsize - 1 downto 0);
901 elsif sel = ALU_OR then
902 res(dsize - 1 downto 0) := d1 or d2;
903 set_n(res(dsize - 1 downto 0));
904 set_z(res(dsize - 1 downto 0));
905 d_out <= res(dsize - 1 downto 0);
907 elsif sel = ALU_BIT then
908 --transfer bit 7 and 6 of memory data to n, v flag.
911 ----zero bit after A and M.
912 res(dsize - 1 downto 0) := d1 and d2;
913 set_z(res(dsize - 1 downto 0));
915 elsif sel = ALU_ADC then
916 res := ('0' & d1) + ('0' & d2) + carry_in;
917 d_out <= res(dsize - 1 downto 0);
918 carry_out <= res(dsize);
919 if ((d1(dsize - 1) = d2(dsize - 1))
920 and (d1(dsize - 1) /= res(dsize - 1))) then
925 set_n(res(dsize - 1 downto 0));
926 set_z(res(dsize - 1 downto 0));
928 elsif sel = ALU_SBC then
930 res := ('0' & d1) - ('0' & d2) - not carry_in;
931 d_out <= res(dsize - 1 downto 0);
933 --c Set if unsigned borrow not required; cleared if unsigned borrow.
934 carry_out <= not res(dsize);
935 --v Set if signed borrow required; cleared if no signed borrow.
936 if ((d1(dsize - 1) /= d2(dsize - 1))
937 and (d1(dsize - 1) /= res(dsize - 1))) then
942 set_n(res(dsize - 1 downto 0));
943 set_z(res(dsize - 1 downto 0));
945 elsif sel = ALU_CMP then
946 res := ('0' & d1) - ('0' & d2);
952 set_n(res(dsize - 1 downto 0));
953 set_z(res(dsize - 1 downto 0));
955 elsif sel = ALU_ASL then
956 res(dsize - 1 downto 1) := d1(dsize - 2 downto 0);
959 d_out <= res(dsize - 1 downto 0);
960 set_n(res(dsize - 1 downto 0));
961 set_z(res(dsize - 1 downto 0));
962 carry_out <= d1(dsize - 1);
964 elsif sel = ALU_LSR then
965 res(dsize - 1) := '0';
966 res(dsize - 2 downto 0) := d1(dsize - 1 downto 1);
968 d_out <= res(dsize - 1 downto 0);
969 set_n(res(dsize - 1 downto 0));
970 set_z(res(dsize - 1 downto 0));
973 elsif sel = ALU_ROL then
974 res(dsize - 1 downto 1) := d1(dsize - 2 downto 0);
977 d_out <= res(dsize - 1 downto 0);
978 set_n(res(dsize - 1 downto 0));
979 set_z(res(dsize - 1 downto 0));
982 elsif sel = ALU_ROR then
983 res(dsize - 1) := carry_in;
984 res(dsize - 2 downto 0) := d1(dsize - 1 downto 1);
986 d_out <= res(dsize - 1 downto 0);
987 set_n(res(dsize - 1 downto 0));
988 set_z(res(dsize - 1 downto 0));
991 elsif sel = ALU_INC then
992 res := ('0' & d1) + "000000001";
993 d_out <= res(dsize - 1 downto 0);
994 set_n(res(dsize - 1 downto 0));
995 set_z(res(dsize - 1 downto 0));
997 elsif sel = ALU_DEC then
998 res := ('0' & d1) - "000000001";
999 d_out <= res(dsize - 1 downto 0);
1000 set_n(res(dsize - 1 downto 0));
1001 set_z(res(dsize - 1 downto 0));