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;
8 use work.motonesfpga_common.all;
11 generic ( dsize : integer := 8
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;
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;
44 carry_out : out std_logic;
45 overflow : out std_logic
49 architecture rtl of alu is
60 d : in std_logic_vector (dsize - 1 downto 0);
61 q : out std_logic_vector (dsize - 1 downto 0)
65 component d_flip_flop_bit
76 component tri_state_buffer
82 d : in std_logic_vector (dsize - 1 downto 0);
83 q : out std_logic_vector (dsize - 1 downto 0)
87 component address_calculator
88 generic ( dsize : integer := 8
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
101 generic ( dsize : integer := 8
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
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;
133 signal addr_c_reg : std_logic;
135 signal pcl_carry_reg_in : std_logic;
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);
144 signal n : std_logic;
145 signal z : std_logic;
146 signal c : std_logic;
147 signal v : std_logic;
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;
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);
165 --pcl carry flag set.
166 pcl_carry_reg_in <= addr_c when pcl_inc_n = '0' else
169 pch_carry_dff_bit : d_flip_flop_bit
170 port map(clk, '1', '1',
171 '0', pcl_carry_reg_in, pcl_inc_carry);
173 addr_calc_inst : address_calculator generic map (dsize)
174 port map (a_sel, addr1, addr2, addr_out, addr_c_in, addr_c);
176 ea_carry_dff_bit : d_flip_flop_bit
177 port map(clk, '1', '1',
178 '0', addr_c, addr_c_reg);
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, bah, 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 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";
238 procedure output_d_bus is
240 arith_buf_we_n <= '0';
241 arith_buf_oe_n <= '0';
243 arith_reg_in <= d_out;
247 int_d_bus <= arith_reg_out;
259 -------------------------------
260 ----- address calcuration -----
261 -------------------------------
262 if (pcl_inc_n = '0') then
265 addr_back <= addr_out;
267 --keep the value in the cycle
270 if (instruction = "01001100") then
271 ---exceptional case: only jmp instruction
282 elsif (pch_inc_n = '0') then
285 addr_back <= addr_out;
287 --inc pch cycle is not fetch cycle.
288 --it is special cycle.
292 elsif (sp_oe_n = '0') then
296 if (sp_push_n /= '0' and sp_pop_n /= '0') then
298 elsif (sp_pop_n = '0') then
302 addr_back <= addr_out;
315 addr_back <= addr_out;
325 elsif (zp_n = '0') then
326 if (zp_xy_n <= '0') then
339 elsif (abs_xy_n = '0') then
340 if (pg_next_n = '0') then
347 ---al is in the al_reg.
356 ---keep al for page crossed case
358 al_reg_in <= addr_out;
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
369 ---forward relative branch
374 ---rel val is on the d_bus.
375 addr_back <= addr_out;
378 --keep the value in the cycle
380 ah_reg_in <= addr_out;
385 a_sel <= ADDR_SIGNED_ADD;
388 ---rel val is on the d_bus.
390 addr_back <= addr_out;
392 ea_carry <= addr_c_reg;
394 --keep the value in the cycle
396 al_reg_in <= addr_out;
400 elsif (indir_n = '0') then
407 --TODO: must handle page crossing case...
410 elsif (indir_x_n = '0') then
412 elsif (indir_y_n = '0') then
415 if (exec_cycle = T2) then
422 al_reg_in <= int_d_bus;
424 elsif (exec_cycle = T3) then
436 ah_reg_in <= int_d_bus;
438 elsif (exec_cycle = T4) then
455 al_reg_in <= addr_out;
458 elsif (exec_cycle = T0 and pg_next_n = '0') then
465 end if; -- if (exec_cycle = T2) then
466 end if; --if (clk = '0') then
474 ----addr_back is always bal for jmp/jsr instruction....
475 -----TODO must check later if it's ok.
477 end if; --if (pcl_inc_n = '0') then
479 -------------------------------
480 ---- arithmatic operations-----
481 -------------------------------
482 if (arith_en_n = '0') then
484 if instruction = conv_std_logic_vector(16#ca#, dsize) then
491 elsif instruction = conv_std_logic_vector(16#88#, dsize) then
498 elsif instruction = conv_std_logic_vector(16#e8#, dsize) then
505 elsif instruction = conv_std_logic_vector(16#c8#, dsize) then
512 elsif instruction = conv_std_logic_vector(16#0a#, dsize) then
520 elsif instruction = conv_std_logic_vector(16#2a#, dsize) then
528 elsif instruction = conv_std_logic_vector(16#4a#, dsize) then
536 elsif instruction = conv_std_logic_vector(16#6a#, dsize) then
544 --instruction is aaabbbcc format.
554 elsif instruction (1 downto 0) = "01" then
555 if instruction (7 downto 5) = "000" then
564 elsif instruction (7 downto 5) = "001" then
573 elsif instruction (7 downto 5) = "010" then
582 elsif instruction (7 downto 5) = "011" then
594 elsif instruction (7 downto 5) = "110" then
603 elsif instruction (7 downto 5) = "111" then
615 end if; --if instruction (7 downto 5) = "000" then
617 elsif instruction (1 downto 0) = "10" then
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
628 if ((exec_cycle = T2 and instruction (4 downto 2) = "001") or
629 (exec_cycle = T3 and instruction (4 downto 2) = "011") or
630 (exec_cycle = T3 and instruction (4 downto 2) = "101") or
631 (exec_cycle = T4 and instruction (4 downto 2) = "111")) then
632 arith_buf_we_n <= '0';
633 arith_reg_in <= int_d_bus;
635 elsif ((exec_cycle = T3 and instruction (4 downto 2) = "001") or
636 (exec_cycle = T4 and instruction (4 downto 2) = "011") or
637 (exec_cycle = T4 and instruction (4 downto 2) = "101") or
638 (exec_cycle = T5 and instruction (4 downto 2) = "111")) then
639 --first cycle. keep input variable.
640 --d_print("inc first.");
641 arith_buf_we_n <= '1';
643 arith_buf_oe_n <= '1';
648 --second cycle read from register, output modified data.
649 --d_print("inc second...");
650 arith_buf_we_n <= '1';
651 arith_buf_oe_n <= '0';
657 if instruction (7 downto 5) = "000" then
663 elsif instruction (7 downto 5) = "001" then
669 elsif instruction (7 downto 5) = "010" then
675 elsif instruction (7 downto 5) = "011" then
681 elsif instruction (7 downto 5) = "110" then
686 elsif instruction (7 downto 5) = "111" then
687 --d_print("alu inc");
691 end if; --if instruction (7 downto 5) = "000" then
693 elsif instruction (1 downto 0) = "00" then
694 if instruction (7 downto 5) = "001" then
701 elsif instruction (7 downto 5) = "110" then
709 elsif instruction (7 downto 5) = "111" then
717 end if; --if instruction (7 downto 5) = "001" then
718 end if; --if instruction = conv_std_logic_vector(16#ca#, dsize)
720 --d_print("no arith");
722 arith_buf_we_n <= '1';
723 arith_buf_oe_n <= '1';
724 int_d_bus <= (others => 'Z');
725 end if; -- if (arith_en_n = '0') then
731 -----------------------------------------
732 ---------- Address calculator------------
733 -----------------------------------------
736 use ieee.std_logic_1164.all;
737 use ieee.std_logic_unsigned.all;
739 entity address_calculator is
740 generic ( dsize : integer := 8
743 sel : in std_logic_vector (1 downto 0);
744 addr1 : in std_logic_vector (dsize - 1 downto 0);
745 addr2 : in std_logic_vector (dsize - 1 downto 0);
746 addr_out : out std_logic_vector (dsize - 1 downto 0);
747 carry_in : in std_logic;
748 carry_out : out std_logic
750 end address_calculator;
752 architecture rtl of address_calculator is
754 constant ADDR_ADC : std_logic_vector (1 downto 0) := "00";
755 constant ADDR_INC : std_logic_vector (1 downto 0) := "01";
756 constant ADDR_DEC : std_logic_vector (1 downto 0) := "10";
757 constant ADDR_SIGNED_ADD : std_logic_vector (1 downto 0) := "11";
761 alu_p : process (sel, addr1, addr2, carry_in)
762 variable res : std_logic_vector (dsize downto 0);
765 if sel = ADDR_ADC then
766 res := ('0' & addr1) + ('0' & addr2) + carry_in;
767 addr_out <= res(dsize - 1 downto 0);
768 carry_out <= res(dsize);
770 elsif sel = ADDR_SIGNED_ADD then
771 res := ('0' & addr1) + ('0' & addr2);
772 addr_out <= res(dsize - 1 downto 0);
773 -- if (addr2(dsize - 1) = '0') then
774 -- ---positive value add.
775 -- if (res(dsize) = '1') then
781 -- ---negative value add.
782 -- if (res(dsize) = '0') then
788 -->>>simplified above.
789 if ((addr2(dsize - 1) xor res(dsize)) = '1') then
795 elsif sel = ADDR_INC then
796 res := ('0' & addr1) + "000000001";
797 addr_out <= res(dsize - 1 downto 0);
798 carry_out <= res(dsize);
799 elsif sel = ADDR_DEC then
800 res := ('0' & addr1) - "000000001";
801 addr_out <= res(dsize - 1 downto 0);
802 carry_out <= res(dsize);
809 -----------------------------------------
810 ------------- ALU Core -----------------
811 -----------------------------------------
814 use ieee.std_logic_1164.all;
815 use ieee.std_logic_unsigned.all;
820 generic ( dsize : integer := 8
823 sel : in std_logic_vector (3 downto 0);
824 d1 : in std_logic_vector (dsize - 1 downto 0);
825 d2 : in std_logic_vector (dsize - 1 downto 0);
826 d_out : out std_logic_vector (dsize - 1 downto 0);
827 carry_in : in std_logic;
828 negative : out std_logic;
829 zero : out std_logic;
830 carry_out : out std_logic;
831 overflow : out std_logic
835 architecture rtl of alu_core is
837 constant ALU_AND : std_logic_vector (3 downto 0) := "0000";
838 constant ALU_EOR : std_logic_vector (3 downto 0) := "0001";
839 constant ALU_OR : std_logic_vector (3 downto 0) := "0010";
840 constant ALU_BIT : std_logic_vector (3 downto 0) := "0011";
841 constant ALU_ADC : std_logic_vector (3 downto 0) := "0100";
842 constant ALU_SBC : std_logic_vector (3 downto 0) := "0101";
843 constant ALU_CMP : std_logic_vector (3 downto 0) := "0110";
844 constant ALU_ASL : std_logic_vector (3 downto 0) := "0111";
845 constant ALU_LSR : std_logic_vector (3 downto 0) := "1000";
846 constant ALU_ROL : std_logic_vector (3 downto 0) := "1001";
847 constant ALU_ROR : std_logic_vector (3 downto 0) := "1010";
848 constant ALU_INC : std_logic_vector (3 downto 0) := "1011";
849 constant ALU_DEC : std_logic_vector (3 downto 0) := "1100";
853 alu_p : process (sel, d1, d2, carry_in)
854 variable res : std_logic_vector (dsize downto 0);
856 procedure set_n (data : in std_logic_vector (dsize - 1 downto 0)) is
858 if (data(7) = '1') then
865 procedure set_z (data : in std_logic_vector (dsize - 1 downto 0)) is
867 if (data = "00000000") then
875 if sel = ALU_AND then
876 res(dsize - 1 downto 0) := d1 and d2;
877 set_n(res(dsize - 1 downto 0));
878 set_z(res(dsize - 1 downto 0));
879 d_out <= res(dsize - 1 downto 0);
881 elsif sel = ALU_EOR then
882 res(dsize - 1 downto 0) := d1 xor d2;
883 set_n(res(dsize - 1 downto 0));
884 set_z(res(dsize - 1 downto 0));
885 d_out <= res(dsize - 1 downto 0);
887 elsif sel = ALU_OR then
888 res(dsize - 1 downto 0) := d1 or d2;
889 set_n(res(dsize - 1 downto 0));
890 set_z(res(dsize - 1 downto 0));
891 d_out <= res(dsize - 1 downto 0);
893 elsif sel = ALU_BIT then
894 --transfer bit 7 and 6 of memory data to n, v flag.
897 ----zero bit after A and M.
898 res(dsize - 1 downto 0) := d1 and d2;
899 set_z(res(dsize - 1 downto 0));
901 elsif sel = ALU_ADC then
902 res := ('0' & d1) + ('0' & d2) + carry_in;
903 d_out <= res(dsize - 1 downto 0);
904 carry_out <= res(dsize);
905 if ((d1(dsize - 1) = d2(dsize - 1))
906 and (d1(dsize - 1) /= res(dsize - 1))) then
911 set_n(res(dsize - 1 downto 0));
912 set_z(res(dsize - 1 downto 0));
914 elsif sel = ALU_SBC then
916 res := ('0' & d1) - ('0' & d2) - not carry_in;
917 d_out <= res(dsize - 1 downto 0);
919 --c Set if unsigned borrow not required; cleared if unsigned borrow.
920 carry_out <= not res(dsize);
921 --v Set if signed borrow required; cleared if no signed borrow.
922 if ((d1(dsize - 1) /= d2(dsize - 1))
923 and (d1(dsize - 1) /= res(dsize - 1))) then
928 set_n(res(dsize - 1 downto 0));
929 set_z(res(dsize - 1 downto 0));
931 elsif sel = ALU_CMP then
932 res := ('0' & d1) - ('0' & d2);
938 set_n(res(dsize - 1 downto 0));
939 set_z(res(dsize - 1 downto 0));
941 elsif sel = ALU_ASL then
942 res(dsize - 1 downto 1) := d1(dsize - 2 downto 0);
945 d_out <= res(dsize - 1 downto 0);
946 set_n(res(dsize - 1 downto 0));
947 set_z(res(dsize - 1 downto 0));
948 carry_out <= d1(dsize - 1);
950 elsif sel = ALU_LSR then
951 res(dsize - 1) := '0';
952 res(dsize - 2 downto 0) := d1(dsize - 1 downto 1);
954 d_out <= res(dsize - 1 downto 0);
955 set_n(res(dsize - 1 downto 0));
956 set_z(res(dsize - 1 downto 0));
959 elsif sel = ALU_ROL then
960 res(dsize - 1 downto 1) := d1(dsize - 2 downto 0);
963 d_out <= res(dsize - 1 downto 0);
964 set_n(res(dsize - 1 downto 0));
965 set_z(res(dsize - 1 downto 0));
968 elsif sel = ALU_ROR then
969 res(dsize - 1) := carry_in;
970 res(dsize - 2 downto 0) := d1(dsize - 1 downto 1);
972 d_out <= res(dsize - 1 downto 0);
973 set_n(res(dsize - 1 downto 0));
974 set_z(res(dsize - 1 downto 0));
977 elsif sel = ALU_INC then
978 res := ('0' & d1) + "000000001";
979 d_out <= res(dsize - 1 downto 0);
980 set_n(res(dsize - 1 downto 0));
981 set_z(res(dsize - 1 downto 0));
983 elsif sel = ALU_DEC then
984 res := ('0' & d1) - "000000001";
985 d_out <= res(dsize - 1 downto 0);
986 set_n(res(dsize - 1 downto 0));
987 set_z(res(dsize - 1 downto 0));