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
117 --------- signals for address calucuration ----------
118 signal al_buf_we_n : std_logic;
119 signal ah_buf_we_n : std_logic;
121 signal al_reg_in : std_logic_vector (dsize - 1 downto 0);
122 signal ah_reg_in : std_logic_vector (dsize - 1 downto 0);
123 signal al_reg : std_logic_vector (dsize - 1 downto 0);
124 signal ah_reg : std_logic_vector (dsize - 1 downto 0);
127 signal a_sel : std_logic_vector (1 downto 0);
128 signal addr1 : std_logic_vector (dsize - 1 downto 0);
129 signal addr2 : std_logic_vector (dsize - 1 downto 0);
130 signal addr_out : std_logic_vector (dsize - 1 downto 0);
132 signal addr_c_in : std_logic;
133 signal addr_c : 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;
158 ----------------------------------------
159 -- address calucurator instances ----
160 ----------------------------------------
161 al_dff : d_flip_flop generic map (dsize)
162 port map(clk, '1', '1', al_buf_we_n, al_reg_in, al_reg);
163 ah_dff : d_flip_flop generic map (dsize)
164 port map(clk, '1', '1', ah_buf_we_n, ah_reg_in, ah_reg);
166 --pcl carry flag set.
167 pcl_carry_reg_in <= addr_c when pcl_inc_n = '0' else
170 pch_carry_dff_bit : d_flip_flop_bit
171 port map(clk, '1', '1',
172 '0', pcl_carry_reg_in, pcl_inc_carry);
174 addr_calc_inst : address_calculator generic map (dsize)
175 port map (a_sel, addr1, addr2, addr_out, addr_c_in, addr_c);
178 ----------------------------------------
179 -- arithmatic operation instances ----
180 ----------------------------------------
181 arith_dff : d_flip_flop generic map (dsize)
182 port map(clk, '1', '1', arith_buf_we_n, arith_reg_in, arith_reg);
183 arith_buf : tri_state_buffer generic map (dsize)
184 port map (arith_buf_oe_n, arith_reg, arith_reg_out);
186 alu_inst : alu_core generic map (dsize)
187 port map (sel, d1, d2, alu_out, carry_in, n, z, c, v);
188 alu_buf : tri_state_buffer generic map (dsize)
189 port map (d_oe_n, alu_out, d_out);
191 -------------------------------
192 ------ alu main process -------
193 -------------------------------
196 ---for address calucuration
197 pcl_inc_n, pch_inc_n, sp_oe_n, sp_push_n, sp_pop_n,
198 abs_xy_n, pg_next_n, zp_n, zp_xy_n, rel_calc_n,
199 indir_n, indir_x_n, indir_y_n,
200 index_bus, bal, bah, addr_c_in, addr_out, addr_c,
202 --for arithmatic operation.
204 instruction, exec_cycle, int_d_bus, acc_out,
205 carry_in, n, z, c, v,
206 arith_reg, arith_reg_out, alu_out, d_out
209 constant ADDR_ADC : std_logic_vector (1 downto 0) := "00";
210 constant ADDR_INC : std_logic_vector (1 downto 0) := "01";
211 constant ADDR_DEC : std_logic_vector (1 downto 0) := "10";
212 constant ADDR_SIGNED_ADD : std_logic_vector (1 downto 0) := "11";
214 constant ALU_AND : std_logic_vector (3 downto 0) := "0000";
215 constant ALU_EOR : std_logic_vector (3 downto 0) := "0001";
216 constant ALU_OR : std_logic_vector (3 downto 0) := "0010";
217 constant ALU_BIT : std_logic_vector (3 downto 0) := "0011";
218 constant ALU_ADC : std_logic_vector (3 downto 0) := "0100";
219 constant ALU_SBC : std_logic_vector (3 downto 0) := "0101";
220 constant ALU_CMP : std_logic_vector (3 downto 0) := "0110";
221 constant ALU_ASL : std_logic_vector (3 downto 0) := "0111";
222 constant ALU_LSR : std_logic_vector (3 downto 0) := "1000";
223 constant ALU_ROL : std_logic_vector (3 downto 0) := "1001";
224 constant ALU_ROR : std_logic_vector (3 downto 0) := "1010";
225 constant ALU_INC : std_logic_vector (3 downto 0) := "1011";
226 constant ALU_DEC : std_logic_vector (3 downto 0) := "1100";
228 ---for indirect addressing.
229 constant T0 : std_logic_vector (5 downto 0) := "000000";
230 constant T1 : std_logic_vector (5 downto 0) := "000001";
231 constant T2 : std_logic_vector (5 downto 0) := "000010";
232 constant T3 : std_logic_vector (5 downto 0) := "000011";
233 constant T4 : std_logic_vector (5 downto 0) := "000100";
234 constant T5 : std_logic_vector (5 downto 0) := "000101";
236 procedure output_d_bus is
238 arith_buf_we_n <= '0';
239 arith_buf_oe_n <= '0';
241 arith_reg_in <= d_out;
245 int_d_bus <= arith_reg_out;
257 -------------------------------
258 ----- address calcuration -----
259 -------------------------------
260 if (pcl_inc_n = '0') then
263 addr_back <= addr_out;
265 --keep the value in the cycle
268 if (instruction = "01001100") then
269 ---exceptional case: only jmp instruction
280 elsif (pch_inc_n = '0') then
283 addr_back <= addr_out;
285 --inc pch cycle is not fetch cycle.
286 --it is special cycle.
290 elsif (sp_oe_n = '0') then
294 if (sp_push_n /= '0' and sp_pop_n /= '0') then
296 elsif (sp_pop_n = '0') then
300 addr_back <= addr_out;
313 addr_back <= addr_out;
323 elsif (zp_n = '0') then
324 if (zp_xy_n <= '0') then
337 elsif (abs_xy_n = '0') then
338 if (pg_next_n = '0') then
345 ---al is in the al_reg.
354 ---keep al for page crossed case
356 al_reg_in <= addr_out;
361 elsif (rel_calc_n = '0') then
362 if (pg_next_n = '0') then
363 if (int_d_bus(7) = '1') then
364 ---backward relative branch
367 ---forward relative branch
372 ---rel val is on the d_bus.
373 addr_back <= addr_out;
376 --keep the value in the cycle
378 ah_reg_in <= addr_out;
383 a_sel <= ADDR_SIGNED_ADD;
386 ---rel val is on the d_bus.
388 addr_back <= addr_out;
391 --keep the value in the cycle
393 al_reg_in <= addr_out;
401 elsif (indir_n = '0') then
408 --TODO: must handle page crossing case...
411 elsif (indir_x_n = '0') then
413 elsif (indir_y_n = '0') then
416 if (exec_cycle = T2) then
423 al_reg_in <= int_d_bus;
425 elsif (exec_cycle = T3) then
437 ah_reg_in <= int_d_bus;
439 elsif (exec_cycle = T4) then
456 al_reg_in <= addr_out;
459 elsif (exec_cycle = T0 and pg_next_n = '0') then
466 end if; -- if (exec_cycle = T2) then
467 end if; --if (clk = '0') then
475 ----addr_back is always bal for jmp/jsr instruction....
476 -----TODO must check later if it's ok.
478 end if; --if (pcl_inc_n = '0') then
480 -------------------------------
481 ---- arithmatic operations-----
482 -------------------------------
483 if (arith_en_n = '0') then
485 if instruction = conv_std_logic_vector(16#ca#, dsize) then
492 elsif instruction = conv_std_logic_vector(16#88#, dsize) then
499 elsif instruction = conv_std_logic_vector(16#e8#, dsize) then
506 elsif instruction = conv_std_logic_vector(16#c8#, dsize) then
513 elsif instruction = conv_std_logic_vector(16#0a#, dsize) then
521 elsif instruction = conv_std_logic_vector(16#2a#, dsize) then
529 elsif instruction = conv_std_logic_vector(16#4a#, dsize) then
537 elsif instruction = conv_std_logic_vector(16#6a#, dsize) then
545 --instruction is aaabbbcc format.
555 elsif instruction (1 downto 0) = "01" then
556 if instruction (7 downto 5) = "000" then
565 elsif instruction (7 downto 5) = "001" then
574 elsif instruction (7 downto 5) = "010" then
583 elsif instruction (7 downto 5) = "011" then
595 elsif instruction (7 downto 5) = "110" then
604 elsif instruction (7 downto 5) = "111" then
616 end if; --if instruction (7 downto 5) = "000" then
618 elsif instruction (1 downto 0) = "10" then
620 --this group is all memory to memory instruction (except for stx/ldx).
621 --memory to memory operation takes two cycles.
622 --first is write original data
623 --second is write modified data
629 if ((exec_cycle = T3 and instruction (4 downto 2) = "001") or
630 (exec_cycle = T4 and instruction (4 downto 2) = "011") or
631 (exec_cycle = T4 and instruction (4 downto 2) = "101") or
632 (exec_cycle = T5 and instruction (4 downto 2) = "111")) then
633 --first cycle. keep input variable.
634 --d_print("inc first.");
635 arith_buf_we_n <= '0';
636 arith_buf_oe_n <= '1';
639 arith_reg_in <= int_d_bus;
642 --second cycle read from register, output modified data.
643 --d_print("inc second...");
644 arith_buf_we_n <= '1';
645 arith_buf_oe_n <= '0';
651 if instruction (7 downto 5) = "000" then
657 elsif instruction (7 downto 5) = "001" then
663 elsif instruction (7 downto 5) = "010" then
669 elsif instruction (7 downto 5) = "011" then
675 elsif instruction (7 downto 5) = "110" then
680 elsif instruction (7 downto 5) = "111" then
681 --d_print("alu inc");
685 end if; --if instruction (7 downto 5) = "000" then
687 elsif instruction (1 downto 0) = "00" then
688 if instruction (7 downto 5) = "001" then
695 elsif instruction (7 downto 5) = "110" then
703 elsif instruction (7 downto 5) = "111" then
711 end if; --if instruction (7 downto 5) = "001" then
712 end if; --if instruction = conv_std_logic_vector(16#ca#, dsize)
714 --d_print("no arith");
716 arith_buf_we_n <= '1';
717 arith_buf_oe_n <= '1';
718 int_d_bus <= (others => 'Z');
719 end if; -- if (arith_en_n = '0') then
725 -----------------------------------------
726 ---------- Address calculator------------
727 -----------------------------------------
730 use ieee.std_logic_1164.all;
731 use ieee.std_logic_unsigned.all;
733 entity address_calculator is
734 generic ( dsize : integer := 8
737 sel : in std_logic_vector (1 downto 0);
738 addr1 : in std_logic_vector (dsize - 1 downto 0);
739 addr2 : in std_logic_vector (dsize - 1 downto 0);
740 addr_out : out std_logic_vector (dsize - 1 downto 0);
741 carry_in : in std_logic;
742 carry_out : out std_logic
744 end address_calculator;
746 architecture rtl of address_calculator is
748 constant ADDR_ADC : std_logic_vector (1 downto 0) := "00";
749 constant ADDR_INC : std_logic_vector (1 downto 0) := "01";
750 constant ADDR_DEC : std_logic_vector (1 downto 0) := "10";
751 constant ADDR_SIGNED_ADD : std_logic_vector (1 downto 0) := "11";
755 alu_p : process (sel, addr1, addr2, carry_in)
756 variable res : std_logic_vector (dsize downto 0);
759 if sel = ADDR_ADC then
760 res := ('0' & addr1) + ('0' & addr2) + carry_in;
761 addr_out <= res(dsize - 1 downto 0);
762 carry_out <= res(dsize);
764 elsif sel = ADDR_SIGNED_ADD then
765 res := ('0' & addr1) + ('0' & addr2);
766 addr_out <= res(dsize - 1 downto 0);
767 -- if (addr2(dsize - 1) = '0') then
768 -- ---positive value add.
769 -- if (res(dsize) = '1') then
775 -- ---negative value add.
776 -- if (res(dsize) = '0') then
782 -->>>simplified above.
783 if ((addr2(dsize - 1) xor res(dsize)) = '1') then
789 elsif sel = ADDR_INC then
790 res := ('0' & addr1) + "000000001";
791 addr_out <= res(dsize - 1 downto 0);
792 carry_out <= res(dsize);
793 elsif sel = ADDR_DEC then
794 res := ('0' & addr1) - "000000001";
795 addr_out <= res(dsize - 1 downto 0);
796 carry_out <= res(dsize);
803 -----------------------------------------
804 ------------- ALU Core -----------------
805 -----------------------------------------
808 use ieee.std_logic_1164.all;
809 use ieee.std_logic_unsigned.all;
814 generic ( dsize : integer := 8
817 sel : in std_logic_vector (3 downto 0);
818 d1 : in std_logic_vector (dsize - 1 downto 0);
819 d2 : in std_logic_vector (dsize - 1 downto 0);
820 d_out : out std_logic_vector (dsize - 1 downto 0);
821 carry_in : in std_logic;
822 negative : out std_logic;
823 zero : out std_logic;
824 carry_out : out std_logic;
825 overflow : out std_logic
829 architecture rtl of alu_core is
831 constant ALU_AND : std_logic_vector (3 downto 0) := "0000";
832 constant ALU_EOR : std_logic_vector (3 downto 0) := "0001";
833 constant ALU_OR : std_logic_vector (3 downto 0) := "0010";
834 constant ALU_BIT : std_logic_vector (3 downto 0) := "0011";
835 constant ALU_ADC : std_logic_vector (3 downto 0) := "0100";
836 constant ALU_SBC : std_logic_vector (3 downto 0) := "0101";
837 constant ALU_CMP : std_logic_vector (3 downto 0) := "0110";
838 constant ALU_ASL : std_logic_vector (3 downto 0) := "0111";
839 constant ALU_LSR : std_logic_vector (3 downto 0) := "1000";
840 constant ALU_ROL : std_logic_vector (3 downto 0) := "1001";
841 constant ALU_ROR : std_logic_vector (3 downto 0) := "1010";
842 constant ALU_INC : std_logic_vector (3 downto 0) := "1011";
843 constant ALU_DEC : std_logic_vector (3 downto 0) := "1100";
847 alu_p : process (sel, d1, d2, carry_in)
848 variable res : std_logic_vector (dsize downto 0);
850 procedure set_n (data : in std_logic_vector (dsize - 1 downto 0)) is
852 if (data(7) = '1') then
859 procedure set_z (data : in std_logic_vector (dsize - 1 downto 0)) is
861 if (data = "00000000") then
869 if sel = ALU_AND then
870 res(dsize - 1 downto 0) := d1 and d2;
871 set_n(res(dsize - 1 downto 0));
872 set_z(res(dsize - 1 downto 0));
873 d_out <= res(dsize - 1 downto 0);
875 elsif sel = ALU_EOR then
876 res(dsize - 1 downto 0) := d1 xor 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_OR then
882 res(dsize - 1 downto 0) := d1 or 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_BIT then
888 --transfer bit 7 and 6 of memory data to n, v flag.
891 ----zero bit after A and M.
892 res(dsize - 1 downto 0) := d1 and d2;
893 set_z(res(dsize - 1 downto 0));
895 elsif sel = ALU_ADC then
896 res := ('0' & d1) + ('0' & d2) + carry_in;
897 d_out <= res(dsize - 1 downto 0);
898 carry_out <= res(dsize);
899 if ((d1(dsize - 1) = d2(dsize - 1))
900 and (d1(dsize - 1) /= res(dsize - 1))) then
905 set_n(res(dsize - 1 downto 0));
906 set_z(res(dsize - 1 downto 0));
908 elsif sel = ALU_SBC then
910 res := ('0' & d1) - ('0' & d2) - not carry_in;
911 d_out <= res(dsize - 1 downto 0);
913 --c Set if unsigned borrow not required; cleared if unsigned borrow.
914 carry_out <= not res(dsize);
915 --v Set if signed borrow required; cleared if no signed borrow.
916 if ((d1(dsize - 1) /= d2(dsize - 1))
917 and (d1(dsize - 1) /= res(dsize - 1))) then
922 set_n(res(dsize - 1 downto 0));
923 set_z(res(dsize - 1 downto 0));
925 elsif sel = ALU_CMP then
926 res := ('0' & d1) - ('0' & d2);
932 set_n(res(dsize - 1 downto 0));
933 set_z(res(dsize - 1 downto 0));
935 elsif sel = ALU_ASL then
936 res(dsize - 1 downto 1) := d1(dsize - 2 downto 0);
939 d_out <= res(dsize - 1 downto 0);
940 set_n(res(dsize - 1 downto 0));
941 set_z(res(dsize - 1 downto 0));
942 carry_out <= d1(dsize - 1);
944 elsif sel = ALU_LSR then
945 res(dsize - 1) := '0';
946 res(dsize - 2 downto 0) := d1(dsize - 1 downto 1);
948 d_out <= res(dsize - 1 downto 0);
949 set_n(res(dsize - 1 downto 0));
950 set_z(res(dsize - 1 downto 0));
953 elsif sel = ALU_ROL then
954 res(dsize - 1 downto 1) := d1(dsize - 2 downto 0);
957 d_out <= res(dsize - 1 downto 0);
958 set_n(res(dsize - 1 downto 0));
959 set_z(res(dsize - 1 downto 0));
962 elsif sel = ALU_ROR then
963 res(dsize - 1) := carry_in;
964 res(dsize - 2 downto 0) := d1(dsize - 1 downto 1);
966 d_out <= res(dsize - 1 downto 0);
967 set_n(res(dsize - 1 downto 0));
968 set_z(res(dsize - 1 downto 0));
971 elsif sel = ALU_INC then
972 res := ('0' & d1) + "000000001";
973 d_out <= res(dsize - 1 downto 0);
974 set_n(res(dsize - 1 downto 0));
975 set_z(res(dsize - 1 downto 0));
977 elsif sel = ALU_DEC 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));