X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;ds=sidebyside;f=de0_cv_nes%2Fmos6502.vhd;h=a2e76410c6bc89851f26735f7a18aeb908f68454;hb=1a1f7583e2c7b51135f8e9a8f82a7f71b1dc33d7;hp=d285c3077c7ffd2a10fce0fd1fb44ceaacfaa013;hpb=5c5be6c0b75dc3386908055d784c561c87f152cb;p=motonesfpga%2Fmotonesfpga.git diff --git a/de0_cv_nes/mos6502.vhd b/de0_cv_nes/mos6502.vhd index d285c30..a2e7641 100644 --- a/de0_cv_nes/mos6502.vhd +++ b/de0_cv_nes/mos6502.vhd @@ -1,6 +1,7 @@ library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.conv_std_logic_vector; entity mos6502 is port ( @@ -10,9 +11,11 @@ entity mos6502 is pi_rdy : in std_logic; pi_irq_n : in std_logic; pi_nmi_n : in std_logic; - po_r_nw : out std_logic; + po_oe_n : out std_logic; + po_we_n : out std_logic; po_addr : out std_logic_vector ( 15 downto 0); - pio_d_io : inout std_logic_vector ( 7 downto 0) + pio_d_io : inout std_logic_vector ( 7 downto 0); + po_exc_cnt : out std_logic_vector (63 downto 0) ); end mos6502; @@ -28,40 +31,71 @@ type cpu_main_state is ( ST_A1_T1, --mem data operation + --imm ST_A21_T1, + --zp ST_A22_T1, ST_A22_T2, + --abs ST_A23_T1, ST_A23_T2, ST_A23_T3, + --indir, x ST_A24_T1, ST_A24_T2, ST_A24_T3, ST_A24_T4, ST_A24_T5, + --abs xy ST_A25_T1, ST_A25_T2, ST_A25_T3, ST_A25_T4, + --zp xy ST_A26_T1, ST_A26_T2, ST_A26_T3, + --indir, y ST_A27_T1, ST_A27_T2, ST_A27_T3, ST_A27_T4, ST_A27_T5, --store op. + --zp ST_A31_T1, ST_A31_T2, + --abs ST_A32_T1, ST_A32_T2, ST_A32_T3, + --indir, x ST_A33_T1, ST_A33_T2, ST_A33_T3, ST_A33_T4, ST_A33_T5, + --abs xy ST_A34_T1, ST_A34_T2, ST_A34_T3, ST_A34_T4, + --zp xy ST_A35_T1, ST_A35_T2, ST_A35_T3, + --indir, y ST_A36_T1, ST_A36_T2, ST_A36_T3, ST_A36_T4, ST_A36_T5, --memory to memory op. + --zp ST_A41_T1, ST_A41_T2, ST_A41_T3, ST_A41_T4, + --abs ST_A42_T1, ST_A42_T2, ST_A42_T3, ST_A42_T4, ST_A42_T5, + --zp x ST_A43_T1, ST_A43_T2, ST_A43_T3, ST_A43_T4, ST_A43_T5, + --abs x ST_A44_T1, ST_A44_T2, ST_A44_T3, ST_A44_T4, ST_A44_T5, ST_A44_T6, --misc operation. + --push ST_A51_T1, ST_A51_T2, + --pull ST_A52_T1, ST_A52_T2, ST_A52_T3, + --jsr ST_A53_T1, ST_A53_T2, ST_A53_T3,ST_A53_T4, ST_A53_T5, + --rti ST_A55_T1, ST_A55_T2, ST_A55_T3, ST_A55_T4, ST_A55_T5, + --jmp abs ST_A561_T1, ST_A561_T2, + --jmp indir ST_A562_T1, ST_A562_T2, ST_A562_T3, ST_A562_T4, + --rts ST_A57_T1, ST_A57_T2, ST_A57_T3, ST_A57_T4, ST_A57_T5, + --branch ST_A58_T1, ST_A58_T2, ST_A58_T3, --reset vector. - ST_RS_T0, ST_RS_T1, ST_RS_T2, ST_RS_T3, ST_RS_T4, ST_RS_T5, ST_RS_T6, ST_RS_T7 + ST_RS_T0, ST_RS_T1, ST_RS_T2, ST_RS_T3, ST_RS_T4, ST_RS_T5, ST_RS_T6, ST_RS_T7, + + --nmi interrupt. + ST_NM_T1, ST_NM_T2, ST_NM_T3, ST_NM_T4, ST_NM_T5, ST_NM_T6, ST_NM_T7, + + --invalid state + ST_INV ); --cpu sub state. @@ -78,6 +112,89 @@ type cpu_sub_state is ( ST_SUB70, ST_SUB71, ST_SUB72, ST_SUB73 ); +type cpu_state_array is array (0 to 255) of cpu_main_state; +constant inst_decode_rom : cpu_state_array := ( + --00 01 02 03 04 05 06 07 + ST_INV, ST_A24_T1, ST_INV, ST_INV, ST_INV, ST_A22_T1, ST_A41_T1, ST_INV, + --08 09 0a 0b 0c 0d 0e 0f + ST_A51_T1, ST_A21_T1, ST_A1_T1, ST_INV, ST_INV, ST_A23_T1, ST_A42_T1, ST_INV, + --10 11 12 13 14 15 16 17 + ST_A58_T1, ST_A27_T1, ST_INV, ST_INV, ST_INV, ST_A26_T1, ST_A43_T1, ST_INV, + --18 19 1a 1b 1c 1d 1e 1f + ST_A1_T1, ST_A25_T1, ST_INV, ST_INV, ST_INV, ST_A25_T1, ST_A44_T1, ST_INV, + --20 21 22 23 24 25 26 27 + ST_A53_T1, ST_A24_T1, ST_INV, ST_INV, ST_A22_T1, ST_A22_T1, ST_A41_T1, ST_INV, + --28 29 2a 2b 2c 2d 2e 2f + ST_A52_T1, ST_A21_T1, ST_A1_T1, ST_INV, ST_A23_T1, ST_A23_T1, ST_A42_T1, ST_INV, + --30 31 32 33 34 35 36 37 + ST_A58_T1, ST_A27_T1, ST_INV, ST_INV, ST_A26_T1, ST_A26_T1, ST_A43_T1, ST_INV, + --38 39 3a 3b 3c 3d 3e 3f + ST_A1_T1, ST_A25_T1, ST_INV, ST_INV, ST_INV, ST_A25_T1, ST_A44_T1, ST_INV, + --40 41 42 43 44 45 46 47 + ST_A55_T1, ST_A24_T1, ST_INV, ST_INV, ST_INV, ST_A22_T1, ST_A41_T1, ST_INV, + --48 49 4a 4b 4c 4d 4e 4f + ST_A51_T1, ST_A21_T1, ST_A1_T1, ST_INV, ST_A561_T1, ST_A23_T1, ST_A42_T1, ST_INV, + --50 51 52 53 54 55 56 57 + ST_A58_T1, ST_A27_T1, ST_INV, ST_INV, ST_A26_T1, ST_A26_T1, ST_A43_T1, ST_INV, + --58 59 5a 5b 5c 5d 5e 5f + ST_A1_T1, ST_A25_T1, ST_INV, ST_INV, ST_INV, ST_A25_T1, ST_A44_T1, ST_INV, + --60 61 62 63 64 65 66 67 + ST_A57_T1, ST_A24_T1, ST_INV, ST_INV, ST_INV, ST_A22_T1, ST_A41_T1, ST_INV, + --68 69 6a 6b 6c 6d 6e 6f + ST_A52_T1, ST_A21_T1, ST_A1_T1, ST_INV, ST_A562_T1, ST_A23_T1, ST_A42_T1, ST_INV, + --70 71 72 73 74 75 76 77 + ST_A58_T1, ST_A27_T1, ST_INV, ST_INV, ST_A26_T1, ST_A26_T1, ST_A43_T1, ST_INV, + --78 79 7a 7b 7c 7d 7e 7f + ST_A1_T1, ST_A25_T1, ST_INV, ST_INV, ST_INV, ST_A25_T1, ST_A44_T1, ST_INV, + --80 81 82 83 84 85 86 87 + ST_INV, ST_A33_T1, ST_INV, ST_INV, ST_A31_T1, ST_A31_T1, ST_A31_T1, ST_INV, + --88 89 8a 8b 8c 8d 8e 8f + ST_A1_T1, ST_INV, ST_A1_T1, ST_INV, ST_A32_T1, ST_A32_T1, ST_A32_T1, ST_INV, + --90 91 92 93 94 95 96 97 + ST_A58_T1, ST_A36_T1, ST_INV, ST_INV, ST_A35_T1, ST_A35_T1, ST_A35_T1, ST_INV, + --98 99 9a 9b 9c 9d 9e 9f + ST_A1_T1, ST_A34_T1, ST_A1_T1, ST_INV, ST_INV, ST_A34_T1, ST_INV, ST_INV, + --a0 a1 a2 a3 a4 a5 a6 a7 + ST_A21_T1, ST_A24_T1, ST_A21_T1, ST_INV, ST_A22_T1, ST_A22_T1, ST_A22_T1, ST_INV, + --a8 a9 aa ab ac ad ae af + ST_A1_T1, ST_A21_T1, ST_A1_T1, ST_INV, ST_A23_T1, ST_A23_T1, ST_A23_T1, ST_INV, + --b0 b1 b2 b3 b4 b5 b6 b7 + ST_A58_T1, ST_A27_T1, ST_INV, ST_A26_T1, ST_A26_T1, ST_A26_T1, ST_A26_T1, ST_INV, + --b8 b9 ba bb bc bd be bf + ST_A1_T1, ST_A25_T1, ST_A1_T1, ST_INV, ST_A25_T1, ST_A25_T1, ST_A25_T1, ST_INV, + --c0 c1 c2 c3 c4 c5 c6 c7 + ST_A21_T1, ST_A24_T1, ST_INV, ST_INV, ST_A22_T1, ST_A22_T1, ST_A41_T1, ST_INV, + --c8 c9 ca cb cc cd ce cf + ST_A1_T1, ST_A21_T1, ST_A1_T1, ST_INV, ST_A23_T1, ST_A23_T1, ST_A42_T1, ST_INV, + --d0 d1 d2 d3 d4 d5 d6 d7 + ST_A58_T1, ST_A27_T1, ST_INV, ST_INV, ST_A26_T1, ST_A26_T1, ST_A43_T1, ST_INV, + --d8 d9 da db dc dd de df + ST_A1_T1, ST_A25_T1, ST_INV, ST_INV, ST_INV, ST_A25_T1, ST_A44_T1, ST_INV, + --e0 e1 e2 e3 e4 e5 e6 e7 + ST_A21_T1, ST_A24_T1, ST_INV, ST_INV, ST_A22_T1, ST_A22_T1, ST_A41_T1, ST_INV, + --e8 e9 ea eb ec ed ee ef + ST_A1_T1, ST_A21_T1, ST_A1_T1, ST_INV, ST_A23_T1, ST_A23_T1, ST_A42_T1, ST_INV, + --f0 f1 f2 f3 f4 f5 f6 f7 + ST_A58_T1, ST_A27_T1, ST_INV, ST_INV, ST_INV, ST_A26_T1, ST_A43_T1, ST_INV, + --f8 f9 fa fb fc fd fe ff + ST_A1_T1, ST_A25_T1, ST_INV, ST_INV, ST_INV, ST_A25_T1, ST_A44_T1, ST_INV +); + +-- Flags (bit 7 to bit 0): +-- N .... Negative +-- V .... Overflow +-- - .... ignored -- always 1 for NES 6502 +-- B .... Break +-- D .... Decimal (use BCD for arithmetics) -- not supported. always 0. +-- I .... Interrupt (IRQ disable) +-- Z .... Zero +-- C .... Carry +constant FL_N : integer := 7; +constant FL_V : integer := 6; +constant FL_I : integer := 2; +constant FL_Z : integer := 1; +constant FL_C : integer := 0; + signal reg_main_state : cpu_main_state; signal reg_main_next_state : cpu_main_state; signal reg_sub_state : cpu_sub_state; @@ -95,19 +212,62 @@ signal reg_status : std_logic_vector (7 downto 0); signal reg_pc_l : std_logic_vector (7 downto 0); signal reg_pc_h : std_logic_vector (7 downto 0); +--tmp flag reg. +signal reg_tmp_carry : std_logic; +signal reg_tmp_ovf : std_logic; +signal reg_tmp_condition : std_logic; +signal reg_tmp_pg_crossed : std_logic; + +--tmp address reg. +signal reg_tmp_l : std_logic_vector (7 downto 0); +signal reg_tmp_h : std_logic_vector (7 downto 0); + +--tmp data reg. +signal reg_tmp_data : std_logic_vector (7 downto 0); + --bus i/o reg. -signal reg_r_nw : std_logic; +signal reg_oe_n : std_logic; +signal reg_we_n : std_logic; signal reg_addr : std_logic_vector (15 downto 0); signal reg_d_in : std_logic_vector (7 downto 0); signal reg_d_out : std_logic_vector (7 downto 0); +signal reg_nmi_handled : integer range 0 to 1; +signal reg_dma_set : integer range 0 to 1; + +--debug purpose... +signal reg_exc_cnt : std_logic_vector (63 downto 0); + +--constant INIT_ACC : std_logic_vector (7 downto 0) := "00000000"; +--constant INIT_X : std_logic_vector (7 downto 0) := "00000000"; +--constant INIT_Y : std_logic_vector (7 downto 0) := "00000000"; +--constant INIT_SP : std_logic_vector (7 downto 0) := "00000000"; +--constant INIT_STATUS : std_logic_vector (7 downto 0) := "00100000"; +--constant INIT_PCL : std_logic_vector (7 downto 0) := "00000000"; +--constant INIT_PCH : std_logic_vector (7 downto 0) := "00000000"; + +constant INIT_ACC : std_logic_vector (7 downto 0) := conv_std_logic_vector(16#95#, 8); +constant INIT_X : std_logic_vector (7 downto 0) := conv_std_logic_vector(16#0d#, 8); +constant INIT_Y : std_logic_vector (7 downto 0) := conv_std_logic_vector(16#1d#, 8); +constant INIT_SP : std_logic_vector (7 downto 0) := conv_std_logic_vector(16#fc#, 8); +constant INIT_STATUS : std_logic_vector (7 downto 0) := conv_std_logic_vector(16#a5#, 8); +constant INIT_PCL : std_logic_vector (7 downto 0) := conv_std_logic_vector(16#82#, 8); +constant INIT_PCH : std_logic_vector (7 downto 0) := conv_std_logic_vector(16#80#, 8); +constant INIT_EXC_CNT : std_logic_vector (63 downto 0) := conv_std_logic_vector(16#02bd#, 16) & conv_std_logic_vector(0, 48); + +constant DEBUG_SW : integer := 0; begin --state transition process... set_stat_p : process (pi_rst_n, pi_base_clk) begin if (pi_rst_n = '0') then - reg_main_state <= ST_IDLE; + if (DEBUG_SW = 0) then + reg_main_state <= ST_RS_T0; + else + --for test.... + reg_main_state <= ST_CM_T0; + end if; reg_sub_state <= ST_SUB00; elsif (rising_edge(pi_base_clk)) then reg_main_state <= reg_main_next_state; @@ -115,7 +275,7 @@ begin end if;--if (pi_rst_n = '0') then end process; - --state change to next. + --fixed length sub status change (0 - 31 because cpu clock is 1/32 of base clock). tx_next_sub_stat_p : process (reg_sub_state, pi_cpu_en) begin case reg_sub_state is @@ -191,88 +351,36 @@ begin end process; --state change to next. - tx_next_main_stat_p : process (reg_main_state, reg_sub_state, pi_rst_n) - ----fake docode function... -variable test_index : integer range 0 to 26 := 0; -variable next_inst_state : cpu_main_state; - -procedure get_next_inst_state is -begin - if (test_index <= 25) then - test_index := test_index + 1; - else - test_index := 1; - end if; - - if (test_index = 1) then - next_inst_state := ST_A1_T1; - elsif (test_index = 2) then - next_inst_state := ST_A22_T1; - elsif (test_index = 3) then - next_inst_state := ST_A23_T1; - elsif (test_index = 4) then - next_inst_state := ST_A24_T1; - elsif (test_index = 5) then - next_inst_state := ST_A25_T1; - elsif (test_index = 6) then - next_inst_state := ST_A26_T1; - elsif (test_index = 7) then - next_inst_state := ST_A27_T1; - elsif (test_index = 8) then - next_inst_state := ST_A31_T1; - elsif (test_index = 9) then - next_inst_state := ST_A32_T1; - elsif (test_index = 10) then - next_inst_state := ST_A33_T1; - elsif (test_index = 11) then - next_inst_state := ST_A34_T1; - elsif (test_index = 12) then - next_inst_state := ST_A35_T1; - elsif (test_index = 13) then - next_inst_state := ST_A36_T1; - elsif (test_index = 14) then - next_inst_state := ST_A41_T1; - elsif (test_index = 15) then - next_inst_state := ST_A42_T1; - elsif (test_index = 16) then - next_inst_state := ST_A43_T1; - elsif (test_index = 17) then - next_inst_state := ST_A44_T1; - elsif (test_index = 18) then - next_inst_state := ST_A51_T1; - elsif (test_index = 19) then - next_inst_state := ST_A52_T1; - elsif (test_index = 20) then - next_inst_state := ST_A53_T1; - elsif (test_index = 21) then - next_inst_state := ST_A55_T1; - elsif (test_index = 22) then - next_inst_state := ST_A561_T1; - elsif (test_index = 23) then - next_inst_state := ST_A562_T1; - elsif (test_index = 24) then - next_inst_state := ST_A57_T1; - elsif (test_index = 25) then - next_inst_state := ST_A58_T1; - else - next_inst_state := ST_IDLE; - end if; -end; + tx_next_main_stat_p : process (pi_rst_n, reg_main_state, reg_sub_state, + reg_inst, reg_tmp_condition, reg_tmp_pg_crossed, + pi_nmi_n, reg_nmi_handled, reg_dma_set, pi_rdy) begin case reg_main_state is -----idle... when ST_IDLE => if (pi_rst_n = '0') then - reg_main_next_state <= reg_main_state; + if (DEBUG_SW = 0) then + reg_main_next_state <= ST_RS_T0; + else + --for test.... + reg_main_next_state <= ST_CM_T0; + end if; + elsif (reg_sub_state = ST_SUB73 and reg_dma_set = 1 and pi_rdy = '1') then + --ST_CM_T0 is canceled when dma initiated. + --redo ST_CM_T0. + reg_main_next_state <= ST_CM_T0; else - reg_main_next_state <= ST_RS_T0; + reg_main_next_state <= reg_main_state; end if; -----reset... when ST_RS_T0 => if (reg_sub_state = ST_SUB73) then - reg_main_next_state <= ST_RS_T1; + if (pi_rst_n = '0') then + reg_main_next_state <= reg_main_state; + else + reg_main_next_state <= ST_RS_T1; + end if; else reg_main_next_state <= reg_main_state; end if; @@ -322,8 +430,17 @@ end; --instruction fetch when ST_CM_T0 => if (reg_sub_state = ST_SUB73) then - get_next_inst_state; - reg_main_next_state <= next_inst_state; + if (pi_nmi_n = '0' and reg_nmi_handled = 0) then + --nmi raised. transit to nmi state. + reg_main_next_state <= ST_NM_T1; + elsif (pi_rdy = '0') then + --dma started. + reg_main_next_state <= ST_IDLE; + else + ---instruction decode next state. + ---pc inc is executed at the end of the cycle (ST_SUB73). + reg_main_next_state <= inst_decode_rom(conv_integer(reg_inst)); + end if; else reg_main_next_state <= reg_main_state; end if; @@ -417,7 +534,12 @@ end; end if; when ST_A25_T3 => if (reg_sub_state = ST_SUB73) then - reg_main_next_state <= ST_A25_T4; + --abs xy move to next only when page crossed. + if (reg_tmp_pg_crossed = '1') then + reg_main_next_state <= ST_A25_T4; + else + reg_main_next_state <= ST_CM_T0; + end if; else reg_main_next_state <= reg_main_state; end if; @@ -465,7 +587,12 @@ end; end if; when ST_A27_T4 => if (reg_sub_state = ST_SUB73) then - reg_main_next_state <= ST_A27_T5; + --indir, y move to next only when page crossed. + if (reg_tmp_pg_crossed = '1') then + reg_main_next_state <= ST_A27_T5; + else + reg_main_next_state <= ST_CM_T0; + end if; else reg_main_next_state <= reg_main_state; end if; @@ -674,7 +801,7 @@ end; end if; when ST_A43_T2 => if (reg_sub_state = ST_SUB73) then - reg_main_next_state <= ST_CM_T0; + reg_main_next_state <= ST_A43_T3; else reg_main_next_state <= reg_main_state; end if; @@ -893,13 +1020,25 @@ end; end if; when ST_A58_T1 => if (reg_sub_state = ST_SUB73) then - reg_main_next_state <= ST_A58_T2; + if (reg_tmp_condition = '1') then + --condition met. move to branch state. + reg_main_next_state <= ST_A58_T2; + else + --condition not met. goto next inst fetch. + reg_main_next_state <= ST_CM_T0; + end if; else reg_main_next_state <= reg_main_state; end if; when ST_A58_T2 => if (reg_sub_state = ST_SUB73) then - reg_main_next_state <= ST_A58_T3; + if (reg_tmp_pg_crossed = '1') then + --page crossed. move to next. + reg_main_next_state <= ST_A58_T3; + else + --page not crossed. move to next inst fetch. + reg_main_next_state <= ST_CM_T0; + end if; else reg_main_next_state <= reg_main_state; end if; @@ -910,60 +1049,1396 @@ end; reg_main_next_state <= reg_main_state; end if; --- ---not ready yet... + -----nmi... + when ST_NM_T1 => + if (reg_sub_state = ST_SUB73) then + reg_main_next_state <= ST_NM_T2; + else + reg_main_next_state <= reg_main_state; + end if; + when ST_NM_T2 => + if (reg_sub_state = ST_SUB73) then + reg_main_next_state <= ST_NM_T3; + else + reg_main_next_state <= reg_main_state; + end if; + when ST_NM_T3 => + if (reg_sub_state = ST_SUB73) then + reg_main_next_state <= ST_NM_T4; + else + reg_main_next_state <= reg_main_state; + end if; + when ST_NM_T4 => + if (reg_sub_state = ST_SUB73) then + reg_main_next_state <= ST_NM_T5; + else + reg_main_next_state <= reg_main_state; + end if; + when ST_NM_T5 => + if (reg_sub_state = ST_SUB73) then + reg_main_next_state <= ST_NM_T6; + else + reg_main_next_state <= reg_main_state; + end if; + when ST_NM_T6 => + if (reg_sub_state = ST_SUB73) then + reg_main_next_state <= ST_NM_T7; + else + reg_main_next_state <= reg_main_state; + end if; + when ST_NM_T7 => + if (reg_sub_state = ST_SUB73) then + reg_main_next_state <= ST_CM_T0; + else + reg_main_next_state <= reg_main_state; + end if; + + --invalid state + when ST_INV => + ---failed to decode next... + reg_main_next_state <= reg_main_state; + -- when others => -- reg_main_next_state <= reg_main_state; end case; end process; + + po_oe_n <= reg_oe_n; + po_we_n <= reg_we_n; + po_addr <= reg_addr; + pio_d_io <= reg_d_out; + --addressing general process... --pc, io bus, r/w, instruction regs... ad_general_p : process (pi_rst_n, pi_base_clk) + + --address calcuratin w/ carry. + variable calc_adl : std_logic_vector(8 downto 0); + +procedure pc_inc is +begin + if (reg_pc_l = "11111111") then + --pch page next. + reg_pc_l <= "00000000"; + reg_pc_h <= reg_pc_h + 1; + else + reg_pc_l <= reg_pc_l + 1; + end if; +end; + +procedure write_enable is +begin + reg_oe_n <= '1'; + if (reg_sub_state = ST_SUB32 or + reg_sub_state = ST_SUB33 or + reg_sub_state = ST_SUB40 or + reg_sub_state = ST_SUB41 + ) then + reg_we_n <= '0'; + else + reg_we_n <= '1'; + end if; +end; + begin if (pi_rst_n = '0') then - reg_pc_l <= (others => '0'); - reg_pc_h <= (others => '0'); + reg_pc_l <= INIT_PCL; + reg_pc_h <= INIT_PCH; + reg_inst <= (others => '0'); reg_addr <= (others => 'Z'); reg_d_out <= (others => 'Z'); - reg_r_nw <= 'Z'; + reg_d_in <= (others => '0'); + reg_oe_n <= 'Z'; + reg_we_n <= 'Z'; + reg_tmp_pg_crossed <= '0'; + calc_adl := (others => '0'); elsif (rising_edge(pi_base_clk)) then + + --general input data register. + reg_d_in <= pio_d_io; + + --reset vector if (reg_main_state = ST_RS_T0) then reg_pc_l <= (others => '0'); reg_pc_h <= (others => '0'); reg_inst <= (others => '0'); reg_addr <= (others => '0'); reg_d_out <= (others => 'Z'); - reg_r_nw <= '1'; + reg_oe_n <= '1'; + reg_we_n <= '1'; + elsif (reg_main_state = ST_RS_T3) then + --dummy sp out 1. + reg_addr <= "00000001" & reg_sp; + reg_d_out <= (others => '0'); + write_enable; + elsif (reg_main_state = ST_RS_T4) then + --dummy sp out 2. + reg_addr <= "00000001" & (reg_sp - 1); + reg_d_out <= (others => '0'); + write_enable; + elsif (reg_main_state = ST_RS_T5) then + --dummy sp out 3. + reg_addr <= "00000001" & (reg_sp - 2); + reg_d_out <= (others => '0'); + write_enable; elsif (reg_main_state = ST_RS_T6) then --reset vector low... reg_addr <= "1111111111111100"; reg_d_out <= (others => 'Z'); - reg_r_nw <= '1'; + reg_oe_n <= '0'; + reg_we_n <= '1'; reg_pc_l <= reg_d_in; elsif (reg_main_state = ST_RS_T7) then --reset vector high... reg_addr <= "1111111111111101"; - reg_d_out <= (others => 'Z'); - reg_r_nw <= '1'; reg_pc_h <= reg_d_in; + + --common entry cycle. elsif (reg_main_state = ST_CM_T0) then + --init flags. + reg_tmp_pg_crossed <= '0'; + calc_adl := (others => '0'); + reg_d_out <= (others => 'Z'); + + if (pi_nmi_n = '0' and reg_nmi_handled = 0) then + --nmi raised cycle. + reg_oe_n <= '1'; + reg_we_n <= '1'; + reg_addr <= (others => 'Z'); + elsif (pi_rdy = '0') then + --dma started cycle. + reg_oe_n <= 'Z'; + reg_we_n <= 'Z'; + reg_addr <= (others => 'Z'); + else + --normal cycle. + reg_oe_n <= '0'; + reg_we_n <= '1'; + if (reg_sub_state = ST_SUB00) then + --fetch next. + reg_addr <= reg_pc_h & reg_pc_l; + elsif (reg_sub_state = ST_SUB30) then + --update instruction register. + reg_inst <= reg_d_in; + elsif (reg_sub_state = ST_SUB73) then + --pc move next. + pc_inc; + end if; + end if; + + --fetch and move next case. + elsif (reg_main_state = ST_A21_T1 or + reg_main_state = ST_A22_T1 or + reg_main_state = ST_A23_T1 or + reg_main_state = ST_A23_T2 or + reg_main_state = ST_A24_T1 or + reg_main_state = ST_A25_T1 or + reg_main_state = ST_A25_T2 or + reg_main_state = ST_A26_T1 or + reg_main_state = ST_A27_T1 or + reg_main_state = ST_A31_T1 or + reg_main_state = ST_A32_T1 or + reg_main_state = ST_A32_T2 or + reg_main_state = ST_A33_T1 or + reg_main_state = ST_A34_T1 or + reg_main_state = ST_A34_T2 or + reg_main_state = ST_A35_T1 or + reg_main_state = ST_A36_T1 or + reg_main_state = ST_A41_T1 or + reg_main_state = ST_A42_T1 or + reg_main_state = ST_A42_T2 or + reg_main_state = ST_A43_T1 or + reg_main_state = ST_A44_T1 or + reg_main_state = ST_A44_T2 or + reg_main_state = ST_A53_T1 or + reg_main_state = ST_A55_T1 or + reg_main_state = ST_A561_T1 or + reg_main_state = ST_A562_T1 or + reg_main_state = ST_A562_T2 or + reg_main_state = ST_A57_T1 or + reg_main_state = ST_A58_T1) then + if (reg_sub_state = ST_SUB00) then + --fetch next. + reg_addr <= reg_pc_h & reg_pc_l; + elsif (reg_sub_state = ST_SUB70) then + --pc move next. + pc_inc; + end if; + + --intermediate cycles.. + elsif (reg_main_state = ST_A24_T2 or + reg_main_state = ST_A26_T2 or + reg_main_state = ST_A33_T2 or + reg_main_state = ST_A35_T2 or + reg_main_state = ST_A27_T2 or + reg_main_state = ST_A36_T2 or + reg_main_state = ST_A43_T2 + ) then + --zp xy + --ind, x + -->>discarded cycle. + --ind, y + --ial cycle. + reg_addr <= "00000000" & reg_idl_l; + elsif (reg_main_state = ST_A24_T3 or + reg_main_state = ST_A33_T3 + ) then + --ind, x + --bal + x cycle. + reg_addr <= "00000000" & (reg_idl_l + reg_x); + elsif (reg_main_state = ST_A24_T4 or + reg_main_state = ST_A33_T4) then + --ind, x + --bal + x + 1 cycle. + reg_addr <= "00000000" & (reg_idl_l + reg_x + 1); + elsif (reg_main_state = ST_A25_T3 or + reg_main_state = ST_A34_T3 or + reg_main_state = ST_A44_T3 + ) then + --abs xy + --(discarded cycle for store inst..) + if (reg_inst = conv_std_logic_vector(16#be#, 8)) then + --abs y + --ldx + reg_addr <= reg_idl_h & (reg_idl_l + reg_y); + calc_adl := ("0" & reg_idl_l) + ("0" & reg_y); + elsif (reg_inst = conv_std_logic_vector(16#bc#, 8)) then + --abs x + --ldy + reg_addr <= reg_idl_h & (reg_idl_l + reg_x); + calc_adl := ("0" & reg_idl_l) + ("0" & reg_x); + elsif (reg_inst = conv_std_logic_vector(16#9d#, 8)) then + --sta, x + reg_addr <= reg_idl_h & (reg_idl_l + reg_x); + calc_adl := ("0" & reg_idl_l) + ("0" & reg_x); + elsif (reg_inst = conv_std_logic_vector(16#99#, 8)) then + --sta, y + reg_addr <= reg_idl_h & (reg_idl_l + reg_y); + calc_adl := ("0" & reg_idl_l) + ("0" & reg_y); + elsif (reg_inst(1 downto 0) = "10") then + --a4 inst. + if (reg_inst(4 downto 2) = "111") then + --abs x + reg_addr <= reg_idl_h & (reg_idl_l + reg_x); + calc_adl := ("0" & reg_idl_l) + ("0" & reg_x); + end if; + elsif (reg_inst(1 downto 0) = "01") then + --a2 inst + if (reg_inst(4 downto 2) = "110") then + --abs y + reg_addr <= reg_idl_h & (reg_idl_l + reg_y); + calc_adl := ("0" & reg_idl_l) + ("0" & reg_y); + elsif (reg_inst(4 downto 2) = "111") then + --abs x + reg_addr <= reg_idl_h & (reg_idl_l + reg_x); + calc_adl := ("0" & reg_idl_l) + ("0" & reg_x); + end if; + end if; + + reg_tmp_pg_crossed <= calc_adl(8); + elsif (reg_main_state = ST_A27_T3 or + reg_main_state = ST_A36_T3) then + --ind, y + --ial + 1 cycle. + reg_addr <= "00000000" & (reg_idl_l + 1); + elsif (reg_main_state = ST_A27_T4 or + reg_main_state = ST_A36_T4) then + --ind, y + --bal + y cycle. + reg_addr <= reg_tmp_h & (reg_tmp_l + reg_y); + calc_adl := ("0" & reg_tmp_l) + ("0" & reg_y); + reg_tmp_pg_crossed <= calc_adl(8); + elsif (reg_main_state = ST_A51_T1 or + reg_main_state = ST_A52_T1) then + --push/pull + --discard pc cycle. + reg_addr <= reg_pc_h & (reg_pc_l + 1); + elsif (reg_main_state = ST_A52_T2 or + reg_main_state = ST_A53_T2 + ) then + --pull, jsr + --discard sp cycle. + reg_addr <= "00000001" & reg_sp; + + + --a2 instructions. + elsif (reg_main_state = ST_A22_T2 or + reg_main_state = ST_A23_T3 or + reg_main_state = ST_A24_T5 or + reg_main_state = ST_A25_T4 or + reg_main_state = ST_A26_T3 or + reg_main_state = ST_A27_T5 + ) then + --execute cycle. + + --address bus out. + if (reg_main_state = ST_A22_T2) then + --zp + reg_addr <= "00000000" & reg_idl_l; + + elsif (reg_main_state = ST_A23_T3) then + --abs + reg_addr <= reg_idl_h & reg_idl_l; + + elsif (reg_main_state = ST_A24_T5) then + --ind, x + reg_addr <= reg_tmp_h & reg_tmp_l; + + elsif (reg_main_state = ST_A25_T4) then + --abs xy + if (reg_inst(1 downto 0) = "01") then + if (reg_inst(4 downto 2) = "110") then + --abs y + reg_addr <= (reg_idl_h + reg_tmp_pg_crossed) & (reg_idl_l + reg_y); + elsif (reg_inst(4 downto 2) = "111") then + --abs x + reg_addr <= (reg_idl_h + reg_tmp_pg_crossed) & (reg_idl_l + reg_x); + end if; + elsif (reg_inst = conv_std_logic_vector(16#be#, 8)) then + --abs y + --ldx + reg_addr <= (reg_idl_h + reg_tmp_pg_crossed) & (reg_idl_l + reg_y); + elsif (reg_inst = conv_std_logic_vector(16#bc#, 8)) then + --abs x + --ldy + reg_addr <= (reg_idl_h + reg_tmp_pg_crossed) & (reg_idl_l + reg_x); + end if; + + elsif (reg_main_state = ST_A26_T3) then + --zp xy + if (reg_inst(1 downto 0) = "01") then + if (reg_inst(4 downto 2) = "101") then + --zp x + reg_addr <= "00000000" & (reg_idl_l + reg_x); + end if; + elsif (reg_inst = conv_std_logic_vector(16#b6#, 8)) then + --zp y + --ldx + reg_addr <= "00000000" & (reg_idl_l + reg_y); + elsif (reg_inst = conv_std_logic_vector(16#b4#, 8)) then + --zp y + --ldy + reg_addr <= "00000000" & (reg_idl_l + reg_x); + end if; + + elsif (reg_main_state = ST_A27_T5) then + --ind y + reg_addr <= (reg_tmp_h + reg_tmp_pg_crossed) & (reg_tmp_l + reg_y); + end if; + + --a3 instructions. + --sta, stx, sty + elsif (reg_main_state = ST_A31_T2 or + reg_main_state = ST_A32_T3 or + reg_main_state = ST_A33_T5 or + reg_main_state = ST_A34_T4 or + reg_main_state = ST_A35_T3 or + reg_main_state = ST_A36_T5 + ) then + --store cycle. + --data out + if (reg_inst(1 downto 0) = "01" and reg_inst(7 downto 5) = "100") then + --sta + reg_d_out <= reg_acc; + elsif (reg_inst(1 downto 0) = "10" and reg_inst(7 downto 5) = "100") then + --stx + reg_d_out <= reg_x; + elsif (reg_inst(1 downto 0) = "00" and reg_inst(7 downto 5) = "100") then + --sty + reg_d_out <= reg_y; + end if; + + --rw ctrl + write_enable; + + --address bus out. + if (reg_main_state = ST_A31_T2) then + --zp + reg_addr <= "00000000" & reg_idl_l; + + elsif (reg_main_state = ST_A32_T3) then + --abs + reg_addr <= reg_idl_h & reg_idl_l; + + elsif (reg_main_state = ST_A33_T5) then + --ind, x + reg_addr <= reg_tmp_h & reg_tmp_l; + + elsif (reg_main_state = ST_A34_T4) then + --abs xy + if (reg_inst = conv_std_logic_vector(16#9d#, 8)) then + --sta, x + reg_addr <= (reg_idl_h + reg_tmp_pg_crossed) & (reg_idl_l + reg_x); + elsif (reg_inst = conv_std_logic_vector(16#99#, 8)) then + --sta, y + reg_addr <= (reg_idl_h + reg_tmp_pg_crossed) & (reg_idl_l + reg_y); + end if; + + elsif (reg_main_state = ST_A35_T3) then + --zp xy + --sta and sty has index x access, + --stx has index y access. + if (reg_inst = conv_std_logic_vector(16#95#, 8) or --sta + reg_inst = conv_std_logic_vector(16#94#, 8) --sty + ) then + reg_addr <= "00000000" & (reg_idl_l + reg_x); + elsif (reg_inst = conv_std_logic_vector(16#96#, 8)) then + --stx + reg_addr <= "00000000" & (reg_idl_l + reg_y); + end if; + + elsif (reg_main_state = ST_A36_T5) then + --ind y + reg_addr <= (reg_tmp_h + reg_tmp_pg_crossed) & (reg_tmp_l + reg_y); + end if; + + --a4 instructions. + --asl lsr + --dec rol + --inc ror + elsif (reg_main_state = ST_A41_T2 or + reg_main_state = ST_A42_T3 or + reg_main_state = ST_A43_T3 or + reg_main_state = ST_A44_T4 + ) then + --data fetch cycle. + + --address bus out. + if (reg_main_state = ST_A41_T2) then + --zp + reg_addr <= "00000000" & reg_idl_l; + + elsif (reg_main_state = ST_A42_T3) then + --abs + reg_addr <= reg_idl_h & reg_idl_l; + + elsif (reg_main_state = ST_A43_T3) then + --zp x + reg_addr <= "00000000" & (reg_idl_l + reg_x); + + elsif (reg_main_state = ST_A44_T4) then + --abs x + reg_addr <= (reg_idl_h + reg_tmp_pg_crossed) & (reg_idl_l + reg_x); + end if; + + elsif (reg_main_state = ST_A41_T3 or + reg_main_state = ST_A41_T4 or + reg_main_state = ST_A42_T4 or + reg_main_state = ST_A42_T5 or + reg_main_state = ST_A43_T4 or + reg_main_state = ST_A43_T5 or + reg_main_state = ST_A44_T5 or + reg_main_state = ST_A44_T6 + ) then + --data store cycle. + --data out + reg_d_out <= reg_tmp_data; + write_enable; + + --address bus out. + if (reg_main_state = ST_A41_T3 or + reg_main_state = ST_A41_T4 + ) then + --zp + reg_addr <= "00000000" & reg_idl_l; + + elsif (reg_main_state = ST_A42_T4 or + reg_main_state = ST_A42_T5 + ) then + --abs + reg_addr <= reg_idl_h & reg_idl_l; + + elsif (reg_main_state = ST_A43_T4 or + reg_main_state = ST_A43_T5 + ) then + --zp x + reg_addr <= "00000000" & (reg_idl_l + reg_x); + + elsif (reg_main_state = ST_A44_T5 or + reg_main_state = ST_A44_T6 + ) then + --abs x + reg_addr <= (reg_idl_h + reg_tmp_pg_crossed) & (reg_idl_l + reg_x); + end if; + + --a5 instruction... + --push + elsif (reg_main_state = ST_A51_T2) then + reg_addr <= "00000001" & reg_sp; + if (reg_inst = conv_std_logic_vector(16#48#, 8)) then + --pha + reg_d_out <= reg_acc; + elsif (reg_inst = conv_std_logic_vector(16#08#, 8)) then + --php + reg_d_out <= reg_status; + end if; + write_enable; + + --pull + elsif (reg_main_state = ST_A52_T3) then + reg_addr <= "00000001" & reg_sp; + + --jsr. + elsif (reg_main_state = ST_A53_T3) then + --push pch + reg_addr <= "00000001" & reg_sp; + reg_d_out <= reg_pc_h; + write_enable; + elsif (reg_main_state = ST_A53_T4) then + --push pcl + reg_addr <= "00000001" & reg_sp; + reg_d_out <= reg_pc_l; + write_enable; + elsif (reg_main_state = ST_A53_T5) then if (reg_sub_state = ST_SUB00) then + --fetch next. reg_addr <= reg_pc_h & reg_pc_l; reg_d_out <= (others => 'Z'); - reg_r_nw <= '1'; - elsif (reg_sub_state = ST_SUB60) then - reg_inst <= reg_d_in; + reg_oe_n <= '0'; + elsif (reg_sub_state = ST_SUB70) then + --go to sub-routine addr. + reg_pc_l <= reg_idl_l; + reg_pc_h <= reg_idl_h; + end if; + + --jmp abs. + elsif (reg_main_state = ST_A561_T2) then + if (reg_sub_state = ST_SUB00) then + --fetch next. + reg_addr <= reg_pc_h & reg_pc_l; + elsif (reg_sub_state = ST_SUB70) then + reg_pc_l <= reg_idl_l; + reg_pc_h <= reg_idl_h; + end if; + + --jmp (indir). + elsif (reg_main_state = ST_A562_T3) then + if (reg_sub_state = ST_SUB00) then + reg_addr <= (reg_idl_h & reg_idl_l); + elsif (reg_sub_state = ST_SUB70) then + reg_pc_l <= reg_d_in; + end if; + elsif (reg_main_state = ST_A562_T4) then + if (reg_sub_state = ST_SUB00) then + reg_addr <= (reg_idl_h & reg_idl_l) + 1; + elsif (reg_sub_state = ST_SUB70) then + reg_pc_h <= reg_d_in; + end if; + + --rts. + elsif (reg_main_state = ST_A57_T2) then + --sp out (discarded.) + reg_addr <= "00000001" & reg_sp; + elsif (reg_main_state = ST_A57_T3) then + --pull pcl + if (reg_sub_state = ST_SUB00) then + reg_addr <= "00000001" & reg_sp; + elsif (reg_sub_state = ST_SUB70) then + reg_pc_l <= reg_d_in; + end if; + elsif (reg_main_state = ST_A57_T4) then + --pull pch + if (reg_sub_state = ST_SUB00) then + reg_addr <= "00000001" & reg_sp; + elsif (reg_sub_state = ST_SUB70) then + reg_pc_h <= reg_d_in; + end if; + elsif (reg_main_state = ST_A57_T5) then + --pc out (discarded.) + if (reg_sub_state = ST_SUB00) then + reg_addr <= reg_pc_h & reg_pc_l; + elsif (reg_sub_state = ST_SUB70) then + pc_inc; + end if; + + --conditional branch. + elsif (reg_main_state = ST_A58_T2) then + if (reg_sub_state = ST_SUB10) then + calc_adl := ("0" & reg_pc_l) + ("0" & reg_idl_l); + --conditional branch is signed add. + if ((reg_idl_l(7) xor calc_adl(8)) = '1') then + reg_tmp_pg_crossed <= '1'; + else + reg_tmp_pg_crossed <= '0'; + end if; + + reg_pc_l <= calc_adl(7 downto 0); + reg_addr <= reg_pc_h & calc_adl(7 downto 0); + end if; + + --page crossed. + elsif (reg_main_state = ST_A58_T3) then + if (reg_sub_state = ST_SUB10) then + if (reg_idl_l(7) = '0') then + --page crossig forward branch. + reg_pc_h <= reg_pc_h + "1"; + reg_addr <= (reg_pc_h + "1") & reg_pc_l; + else + --page crossig backward branch. + reg_pc_h <= reg_pc_h - "1"; + reg_addr <= (reg_pc_h - "1") & reg_pc_l; + end if; + end if; + + --nmi + elsif (reg_main_state = ST_NM_T1) then + reg_inst <= (others => '0'); + reg_addr <= (others => '0'); + reg_d_out <= (others => 'Z'); + reg_oe_n <= '1'; + reg_we_n <= '1'; + elsif (reg_main_state = ST_NM_T3) then + --push pch. + reg_addr <= "00000001" & reg_sp; + reg_d_out <= reg_pc_h; + write_enable; + elsif (reg_main_state = ST_NM_T4) then + --push pcl. + reg_addr <= "00000001" & reg_sp; + reg_d_out <= reg_pc_l; + write_enable; + elsif (reg_main_state = ST_NM_T5) then + --push status. + reg_addr <= "00000001" & reg_sp; + reg_d_out <= reg_status; + write_enable; + elsif (reg_main_state = ST_NM_T6) then + --vector low... + reg_addr <= "1111111111111010"; + reg_d_out <= (others => 'Z'); + reg_oe_n <= '0'; + reg_we_n <= '1'; + reg_pc_l <= reg_d_in; + elsif (reg_main_state = ST_NM_T7) then + --vector high... + reg_addr <= "1111111111111011"; + reg_pc_h <= reg_d_in; + + --rti. + elsif (reg_main_state = ST_A55_T2) then + --sp out (discarded.) + reg_addr <= "00000001" & reg_sp; + elsif (reg_main_state = ST_A55_T3) then + --pull status + reg_addr <= "00000001" & reg_sp; + elsif (reg_main_state = ST_A55_T4) then + --pull pcl + if (reg_sub_state = ST_SUB00) then + reg_addr <= "00000001" & reg_sp; elsif (reg_sub_state = ST_SUB70) then - reg_pc_l <= reg_pc_l + 1; + reg_pc_l <= reg_d_in; + end if; + elsif (reg_main_state = ST_A55_T5) then + --pull pch + if (reg_sub_state = ST_SUB00) then + reg_addr <= "00000001" & reg_sp; + elsif (reg_sub_state = ST_SUB70) then + reg_pc_h <= reg_d_in; + end if; + + + end if;--if (reg_main_state = ST_RS_T0) then + end if;--if (pi_rst_n = '0') then + end process; + + --internal data latch... + --fetch first and second operand. + idl_p : process (pi_rst_n, pi_base_clk) + begin + if (pi_rst_n = '0') then + reg_idl_l <= (others => '0'); + reg_idl_h <= (others => '0'); + reg_tmp_l <= (others => '0'); + reg_tmp_h <= (others => '0'); + elsif (rising_edge(pi_base_clk)) then + if (reg_main_state = ST_A21_T1 or + reg_main_state = ST_A22_T1 or + reg_main_state = ST_A23_T1 or + reg_main_state = ST_A24_T1 or + reg_main_state = ST_A25_T1 or + reg_main_state = ST_A26_T1 or + reg_main_state = ST_A27_T1 or + reg_main_state = ST_A31_T1 or + reg_main_state = ST_A32_T1 or + reg_main_state = ST_A33_T1 or + reg_main_state = ST_A34_T1 or + reg_main_state = ST_A35_T1 or + reg_main_state = ST_A36_T1 or + reg_main_state = ST_A41_T1 or + reg_main_state = ST_A42_T1 or + reg_main_state = ST_A43_T1 or + reg_main_state = ST_A44_T1 or + reg_main_state = ST_A53_T1 or + reg_main_state = ST_A561_T1 or + reg_main_state = ST_A562_T1 or + reg_main_state = ST_A58_T1) then + if (reg_sub_state = ST_SUB30) then + --get low data from rom. + reg_idl_l <= reg_d_in; + end if; + elsif (reg_main_state = ST_A23_T2 or + reg_main_state = ST_A25_T2 or + reg_main_state = ST_A32_T2 or + reg_main_state = ST_A34_T2 or + reg_main_state = ST_A42_T2 or + reg_main_state = ST_A44_T2 or + reg_main_state = ST_A53_T5 or + reg_main_state = ST_A561_T2 or + reg_main_state = ST_A562_T2) then + if (reg_sub_state = ST_SUB30) then + --get high data from rom. + reg_idl_h <= reg_d_in; + end if; + elsif (reg_main_state = ST_A24_T3 or + reg_main_state = ST_A27_T2 or + reg_main_state = ST_A33_T3 or + reg_main_state = ST_A36_T2 + ) then + --a24 indr, x + --a27 indr, y + --a33 indr, x + --a36 indr, y + if (reg_sub_state = ST_SUB30) then + reg_tmp_l <= reg_d_in; + end if; + elsif (reg_main_state = ST_A24_T4 or + reg_main_state = ST_A27_T3 or + reg_main_state = ST_A33_T4 or + reg_main_state = ST_A36_T3 + ) then + --a24 indr, x + --a27 indr, y + --a33 indr, x + --a36 indr, y + if (reg_sub_state = ST_SUB30) then + reg_tmp_h <= reg_d_in; + end if; + end if;--if (reg_main_state = ST_RS_T0) + end if;--if (pi_rst_n = '0') then + end process; + + --stack pointer... + sp_p : process (pi_rst_n, pi_base_clk) + begin + if (pi_rst_n = '0') then + reg_sp <= INIT_SP; + elsif (rising_edge(pi_base_clk)) then + if (reg_main_state = ST_A1_T1) then + --txs inst. + if (reg_inst = conv_std_logic_vector(16#9a#, 8)) then + reg_sp <= reg_x; + end if; + elsif (reg_main_state = ST_A51_T2 or + reg_main_state = ST_A53_T3 or + reg_main_state = ST_A53_T4 or + reg_main_state = ST_NM_T3 or + reg_main_state = ST_NM_T4 or + reg_main_state = ST_NM_T5 + ) then + --push, jsr, nmi. + if (reg_sub_state = ST_SUB70) then + reg_sp <= reg_sp - 1; + end if; + elsif (reg_main_state = ST_A52_T2 or + reg_main_state = ST_A55_T2 or + reg_main_state = ST_A55_T3 or + reg_main_state = ST_A55_T4 or + reg_main_state = ST_A57_T2 or + reg_main_state = ST_A57_T3) then + --pull, rts, rti. + if (reg_sub_state = ST_SUB70) then + reg_sp <= reg_sp + 1; + end if; + end if;--if (reg_main_state = ST_RS_T0) + end if;--if (pi_rst_n = '0') then + end process; + + --calcuration process... + --update acc, x, y, status registers. + calc_p : process (pi_rst_n, pi_base_clk) + + variable calc_res : std_logic_vector (8 downto 0); +procedure update_status ( + d : in std_logic_vector(7 downto 0); + set_n : in integer range 0 to 1; + set_z : in integer range 0 to 1; + set_c : in integer range 0 to 1 +) is +begin + if (set_n = 1) then + if (d(7) = '1') then + reg_status(FL_N) <= '1'; + else + reg_status(FL_N) <= '0'; + end if; + end if; + if (set_z = 1) then + if (d = "00000000") then + reg_status(FL_Z) <= '1'; + else + reg_status(FL_Z) <= '0'; + end if; + end if; + if (set_c = 1) then + reg_status(FL_C) <= reg_tmp_carry; + end if; +end; + +procedure set_condition_result ( + flg : in integer range 0 to 7; + chk_val : in std_logic +) is +begin + if (reg_status(flg) = chk_val) then + reg_tmp_condition <= '1'; + else + reg_tmp_condition <= '0'; + end if; +end; + + begin + --Most instructions that explicitly reference memory locations have bit patterns of the form aaabbbcc. + if (pi_rst_n = '0') then + reg_acc <= INIT_ACC; + reg_x <= INIT_X; + reg_y <= INIT_Y; + reg_status <= INIT_STATUS; + reg_tmp_carry <= '0'; + reg_tmp_ovf <= '0'; + reg_tmp_condition <= '0'; + elsif (rising_edge(pi_base_clk)) then + --not used status pin initialize (to avoid latches). + reg_status(5 downto 3) <= "100"; + + --a1 instructions... + --asl dex nop tax tya + --clc dey rol tay + --cld inx sec tsx + --cli iny sed txa + --clv lsr sei txs + if (reg_main_state = ST_CM_T0) then + --init flag regs.. + reg_tmp_carry <= '0'; + reg_tmp_ovf <= '0'; + reg_tmp_condition <= '0'; + elsif (reg_main_state = ST_A1_T1) then + --update reg + if (reg_sub_state = ST_SUB30) then + if (reg_inst = conv_std_logic_vector(16#88#, 8)) then + --dey + reg_y <= reg_y - 1; + elsif (reg_inst = conv_std_logic_vector(16#a8#, 8)) then + --tay + reg_y <= reg_acc; + elsif (reg_inst = conv_std_logic_vector(16#c8#, 8)) then + --iny + reg_y <= reg_y + 1; + elsif (reg_inst = conv_std_logic_vector(16#e8#, 8)) then + --inx + reg_x <= reg_x + 1; + elsif (reg_inst = conv_std_logic_vector(16#18#, 8)) then + --clc + reg_status(FL_C) <= '0'; + elsif (reg_inst = conv_std_logic_vector(16#38#, 8)) then + --sec + reg_status(FL_C) <= '1'; + elsif (reg_inst = conv_std_logic_vector(16#58#, 8)) then + --cli + reg_status(FL_I) <= '0'; + elsif (reg_inst = conv_std_logic_vector(16#78#, 8)) then + --sei + reg_status(FL_I) <= '1'; + elsif (reg_inst = conv_std_logic_vector(16#98#, 8)) then + --tya + reg_acc <= reg_y; + elsif (reg_inst = conv_std_logic_vector(16#b8#, 8)) then + --clv + reg_status(FL_V) <= '0'; + elsif (reg_inst = conv_std_logic_vector(16#8a#, 8)) then + --txa + reg_acc <= reg_x; + elsif (reg_inst = conv_std_logic_vector(16#aa#, 8)) then + --tax + reg_x <= reg_acc; + elsif (reg_inst = conv_std_logic_vector(16#ba#, 8)) then + --tsx + reg_x <= reg_sp; + elsif (reg_inst = conv_std_logic_vector(16#ca#, 8)) then + --dex + reg_x <= reg_x - 1; + elsif (reg_inst = conv_std_logic_vector(16#ea#, 8)) then + --nop + --do nothing... + --case cc=10 + elsif (reg_inst(1 downto 0) = "10") then + if (reg_inst(7 downto 5) = "000") then + --asl + reg_acc <= reg_acc(6 downto 0) & "0"; + reg_tmp_carry <= reg_acc(7); + elsif (reg_inst(7 downto 5) = "001") then + --rol + reg_acc <= reg_acc(6 downto 0) & reg_status(FL_C); + reg_tmp_carry <= reg_acc(7); + elsif (reg_inst(7 downto 5) = "010") then + --lsr + reg_acc <= "0" & reg_acc(7 downto 1); + reg_tmp_carry <= reg_acc(0); + elsif (reg_inst(7 downto 5) = "011") then + --ror + reg_acc <= reg_status(FL_C) & reg_acc(7 downto 1); + reg_tmp_carry <= reg_acc(0); + elsif (reg_inst(7 downto 5) = "110") then + --dec + reg_acc <= reg_acc - 1; + elsif (reg_inst(7 downto 5) = "111") then + --inc + reg_acc <= reg_acc + 1; + end if; + end if; + + --update status reg + elsif (reg_sub_state = ST_SUB31) then + if (reg_inst = conv_std_logic_vector(16#88#, 8)) then + --dey + update_status(reg_y, 1, 1, 0); + elsif (reg_inst = conv_std_logic_vector(16#a8#, 8)) then + --tay + update_status(reg_y, 1, 1, 0); + elsif (reg_inst = conv_std_logic_vector(16#c8#, 8)) then + --iny + update_status(reg_y, 1, 1, 0); + elsif (reg_inst = conv_std_logic_vector(16#e8#, 8)) then + --inx + update_status(reg_x, 1, 1, 0); + elsif (reg_inst = conv_std_logic_vector(16#98#, 8)) then + --tya + update_status(reg_acc, 1, 1, 0); + elsif (reg_inst = conv_std_logic_vector(16#8a#, 8)) then + --txa + update_status(reg_acc, 1, 1, 0); + elsif (reg_inst = conv_std_logic_vector(16#9a#, 8)) then + --txs + update_status(reg_sp, 1, 1, 0); + elsif (reg_inst = conv_std_logic_vector(16#aa#, 8)) then + --tax + update_status(reg_x, 1, 1, 0); + elsif (reg_inst = conv_std_logic_vector(16#ba#, 8)) then + --tsx + update_status(reg_x, 1, 1, 0); + elsif (reg_inst = conv_std_logic_vector(16#ca#, 8)) then + --dex + update_status(reg_x, 1, 1, 0); + elsif (reg_inst = conv_std_logic_vector(16#ea#, 8)) then + --nop + --do nothing... + --case cc=10 + elsif (reg_inst(1 downto 0) = "10") then + if (reg_inst(7 downto 5) = "000") then + --asl + update_status(reg_acc, 1, 1, 1); + elsif (reg_inst(7 downto 5) = "001") then + --rol + update_status(reg_acc, 1, 1, 1); + elsif (reg_inst(7 downto 5) = "010") then + --lsr + update_status(reg_acc, 0, 1, 1); + elsif (reg_inst(7 downto 5) = "011") then + --ror + update_status(reg_acc, 1, 1, 1); + elsif (reg_inst(7 downto 5) = "110") then + --dec + update_status(reg_acc, 1, 1, 0); + elsif (reg_inst(7 downto 5) = "111") then + --inc + update_status(reg_acc, 1, 1, 0); + end if; + end if; + end if;--if (reg_sub_state = ST_SUB30) then + + --a2 instructions... + --adc cmp eor ldy + --and cpx lda ora + --bit cpy ldx sbc + elsif (reg_main_state = ST_A21_T1 or + reg_main_state = ST_A22_T2 or + reg_main_state = ST_A23_T3 or + reg_main_state = ST_A24_T5 or + reg_main_state = ST_A25_T3 or + reg_main_state = ST_A25_T4 or + reg_main_state = ST_A26_T3 or + reg_main_state = ST_A27_T4 or + reg_main_state = ST_A27_T5) then + + --update reg + if (reg_sub_state = ST_SUB30) then + --case cc=01 + if (reg_inst(1 downto 0) = "01") then + if (reg_inst(7 downto 5) = "000") then + --ora + reg_acc <= (reg_acc or reg_d_in); + elsif (reg_inst(7 downto 5) = "001") then + --and + reg_acc <= (reg_acc and reg_d_in); + elsif (reg_inst(7 downto 5) = "010") then + --eor + reg_acc <= (reg_acc xor reg_d_in); + elsif (reg_inst(7 downto 5) = "011") then + --adc + calc_res := ("0" & reg_acc) + ("0" & reg_d_in) + reg_status(FL_C); + reg_tmp_carry <= calc_res(8); + if ((reg_acc(7) = reg_d_in(7)) and (reg_acc(7) /= calc_res(7))) then + reg_tmp_ovf <= '1'; + else + reg_tmp_ovf <= '0'; + end if; + reg_acc <= calc_res(7 downto 0); + elsif (reg_inst(7 downto 5) = "101") then + --lda + reg_acc <= reg_d_in; + elsif (reg_inst(7 downto 5) = "110") then + --cmp + --do nothing. + elsif (reg_inst(7 downto 5) = "111") then + --sbc + ---A - M - ~C -> A + calc_res := ("0" & reg_acc) - ("0" & reg_d_in) - not reg_status(FL_C); + + --c Set if unsigned borrow not required; cleared if unsigned borrow. + reg_tmp_carry <= not calc_res(8); + --v Set if signed borrow required; cleared if no signed borrow. + if ((reg_acc(7) /= reg_d_in(7)) and (reg_acc(7) /= calc_res(7))) then + reg_tmp_ovf <= '1'; + else + reg_tmp_ovf <= '0'; + end if; + reg_acc <= calc_res(7 downto 0); + end if; + --case cc=10 + elsif (reg_inst(1 downto 0) = "10") then + if (reg_inst(7 downto 5) = "101") then + --ldx + reg_x <= reg_d_in; + end if; + --case cc=00 + elsif (reg_inst(1 downto 0) = "00") then + if (reg_inst(7 downto 5) = "001") then + --bit + --do nothing. + elsif (reg_inst(7 downto 5) = "101") then + --ldy + reg_y <= reg_d_in; + elsif (reg_inst(7 downto 5) = "110") then + --cpy + --do nothing. + elsif (reg_inst(7 downto 5) = "111") then + --cpx + --do nothing. + end if; + end if; + + --update status reg + elsif (reg_sub_state = ST_SUB31) then + --case cc=01 + if (reg_inst(1 downto 0) = "01") then + if (reg_inst(7 downto 5) = "000") then + --ora + update_status(reg_acc, 1, 1, 0); + elsif (reg_inst(7 downto 5) = "001") then + --and + update_status(reg_acc, 1, 1, 0); + elsif (reg_inst(7 downto 5) = "010") then + --eor + update_status(reg_acc, 1, 1, 0); + elsif (reg_inst(7 downto 5) = "011") then + --adc + update_status(reg_acc, 1, 1, 1); + reg_status(FL_V) <= reg_tmp_ovf; + elsif (reg_inst(7 downto 5) = "101") then + --lda + update_status(reg_acc, 1, 1, 0); + elsif (reg_inst(7 downto 5) = "110") then + --cmp + calc_res := (("0" & reg_acc) - ("0" & reg_d_in)); + if (reg_acc >= reg_d_in) then + reg_status(FL_C) <= '1'; + else + reg_status(FL_C) <= '0'; + end if; + if (calc_res(7) = '1') then + reg_status(FL_N) <= '1'; + else + reg_status(FL_N) <= '0'; + end if; + if (calc_res = "000000000") then + reg_status(FL_Z) <= '1'; + else + reg_status(FL_Z) <= '0'; + end if; + elsif (reg_inst(7 downto 5) = "111") then + --sbc + update_status(reg_acc, 1, 1, 1); + reg_status(FL_V) <= reg_tmp_ovf; + end if; + --case cc=10 + elsif (reg_inst(1 downto 0) = "10") then + if (reg_inst(7 downto 5) = "101") then + --ldx + update_status(reg_x, 1, 1, 0); + end if; + --case cc=00 + elsif (reg_inst(1 downto 0) = "00") then + if (reg_inst(7 downto 5) = "001") then + --bit + calc_res(7 downto 0) := (reg_acc and reg_d_in); + reg_status(FL_N) <= reg_d_in(7); + reg_status(FL_V) <= reg_d_in(6); + if (calc_res(7 downto 0) = "00000000") then + reg_status(FL_Z) <= '1'; + else + reg_status(FL_Z) <= '0'; + end if; + elsif (reg_inst(7 downto 5) = "101") then + --ldy + update_status(reg_y, 1, 1, 0); + elsif (reg_inst(7 downto 5) = "110") then + --cpy + calc_res := (("0" & reg_y) - ("0" & reg_d_in)); + if (reg_y >= reg_d_in) then + reg_status(FL_C) <= '1'; + else + reg_status(FL_C) <= '0'; + end if; + if (calc_res(7) = '1') then + reg_status(FL_N) <= '1'; + else + reg_status(FL_N) <= '0'; + end if; + if (calc_res = "000000000") then + reg_status(FL_Z) <= '1'; + else + reg_status(FL_Z) <= '0'; + end if; + elsif (reg_inst(7 downto 5) = "111") then + --cpx + calc_res := (("0" & reg_x) - ("0" & reg_d_in)); + if (reg_x >= reg_d_in) then + reg_status(FL_C) <= '1'; + else + reg_status(FL_C) <= '0'; + end if; + if (calc_res(7) = '1') then + reg_status(FL_N) <= '1'; + else + reg_status(FL_N) <= '0'; + end if; + if (calc_res = "000000000") then + reg_status(FL_Z) <= '1'; + else + reg_status(FL_Z) <= '0'; + end if; + end if; + end if; + end if;--if (reg_sub_state = ST_SUB30) then + + --a4 instructions. + --asl lsr + --dec rol + --inc ror + elsif (reg_main_state = ST_A41_T2 or + reg_main_state = ST_A42_T3 or + reg_main_state = ST_A43_T3 or + reg_main_state = ST_A44_T4 + ) then + --data fetch cycle. + reg_tmp_data <= reg_d_in; + + elsif (reg_main_state = ST_A41_T4 or + reg_main_state = ST_A42_T5 or + reg_main_state = ST_A43_T5 or + reg_main_state = ST_A44_T6 + ) then + --data modify cycle. + + --update reg + if (reg_sub_state = ST_SUB10) then + --case cc=10 + if (reg_inst(1 downto 0) = "10") then + if (reg_inst(7 downto 5) = "000") then + --asl + reg_tmp_data <= reg_tmp_data(6 downto 0) & "0"; + reg_tmp_carry <= reg_tmp_data(7); + elsif (reg_inst(7 downto 5) = "001") then + --rol + reg_tmp_data <= reg_tmp_data(6 downto 0) & reg_status(FL_C); + reg_tmp_carry <= reg_tmp_data(7); + elsif (reg_inst(7 downto 5) = "010") then + --lsr + reg_tmp_data <= "0" & reg_tmp_data(7 downto 1); + reg_tmp_carry <= reg_tmp_data(0); + elsif (reg_inst(7 downto 5) = "011") then + --ror + reg_tmp_data <= reg_status(FL_C) & reg_tmp_data(7 downto 1); + reg_tmp_carry <= reg_tmp_data(0); + elsif (reg_inst(7 downto 5) = "110") then + --dec + reg_tmp_data <= reg_tmp_data - 1; + elsif (reg_inst(7 downto 5) = "111") then + --inc + reg_tmp_data <= reg_tmp_data + 1; + end if; + end if; + + --update status reg + elsif (reg_sub_state = ST_SUB20) then + --case cc=10 + if (reg_inst(1 downto 0) = "10") then + if (reg_inst(7 downto 5) = "000") then + --asl + update_status(reg_tmp_data, 1, 1, 1); + elsif (reg_inst(7 downto 5) = "001") then + --rol + update_status(reg_tmp_data, 1, 1, 1); + elsif (reg_inst(7 downto 5) = "010") then + --lsr + update_status(reg_tmp_data, 0, 1, 1); + elsif (reg_inst(7 downto 5) = "011") then + --ror + update_status(reg_tmp_data, 1, 1, 1); + elsif (reg_inst(7 downto 5) = "110") then + --dec + update_status(reg_tmp_data, 1, 1, 0); + elsif (reg_inst(7 downto 5) = "111") then + --inc + update_status(reg_tmp_data, 1, 1, 0); + end if; + end if; + end if; + + --a5 instructions... + --plp, pla + elsif (reg_main_state = ST_A52_T3) then + --update reg + if (reg_sub_state = ST_SUB30) then + if (reg_inst = conv_std_logic_vector(16#28#, 8)) then + --plp + reg_status <= reg_d_in; + elsif (reg_inst = conv_std_logic_vector(16#68#, 8)) then + --pla + reg_acc <= reg_d_in; + end if; + + --update status reg + elsif (reg_sub_state = ST_SUB31) then + if (reg_inst = conv_std_logic_vector(16#68#, 8)) then + --pla + update_status(reg_acc, 1, 1, 0); + end if; + end if;--if (reg_sub_state = ST_SUB30) then + + --a58 branch inst. + --bcc bne + --bcs bpl + --beq bvc + --bmi bvs + elsif (reg_main_state = ST_A58_T1) then + if (reg_sub_state = ST_SUB30) then + if (reg_inst = conv_std_logic_vector(16#90#, 8)) then + --bcc + set_condition_result(FL_C, '0'); + + elsif (reg_inst = conv_std_logic_vector(16#b0#, 8)) then + --bcs + set_condition_result(FL_C, '1'); + + elsif (reg_inst = conv_std_logic_vector(16#f0#, 8)) then + --beq + set_condition_result(FL_Z, '1'); + + elsif (reg_inst = conv_std_logic_vector(16#30#, 8)) then + --bmi + set_condition_result(FL_N, '1'); + + elsif (reg_inst = conv_std_logic_vector(16#d0#, 8)) then + --bne + set_condition_result(FL_Z, '0'); + + elsif (reg_inst = conv_std_logic_vector(16#10#, 8)) then + --bpl + set_condition_result(FL_N, '0'); + + elsif (reg_inst = conv_std_logic_vector(16#50#, 8)) then + --bvc + set_condition_result(FL_V, '0'); + + elsif (reg_inst = conv_std_logic_vector(16#70#, 8)) then + --bvs + set_condition_result(FL_V, '1'); + end if; end if; + + elsif (reg_main_state = ST_A55_T3) then + --rti, pull status reg. + if (reg_sub_state = ST_SUB30) then + reg_status <= reg_d_in; + end if;--if (reg_sub_state = ST_SUB30) then + + + end if;--if (reg_main_state = ST_A21_T1 or... + end if;--if (pi_rst_n = '0') then + end process; + + --nmi handled flag process... + nmi_handle_p : process (pi_rst_n, pi_base_clk) + begin + if (pi_rst_n = '0') then + reg_nmi_handled <= 0; + elsif (rising_edge(pi_base_clk)) then + if (pi_nmi_n = '1') then + reg_nmi_handled <= 0; + elsif (reg_main_state = ST_NM_T7 and reg_sub_state = ST_SUB73) then + reg_nmi_handled <= 1; end if; end if;--if (pi_rst_n = '0') then end process; - po_r_nw <= reg_r_nw; - po_addr <= reg_addr; - pio_d_io <= reg_d_out; - reg_d_in <= pio_d_io; + --dma flag process... + dma_set_p : process (pi_rst_n, pi_base_clk) + begin + if (pi_rst_n = '0') then + reg_dma_set <= 0; + elsif (rising_edge(pi_base_clk)) then + if (pi_rdy = '0') then + reg_dma_set <= 1; + elsif (reg_main_state = ST_CM_T0) then + reg_dma_set <= 0; + end if; + end if;--if (pi_rst_n = '0') then + end process; + --debug cnt... + po_exc_cnt <= reg_exc_cnt; + exc_cnt_p : process (pi_rst_n, pi_base_clk) + begin + if (pi_rst_n = '0') then + if (DEBUG_SW = 0) then + reg_exc_cnt <= (others => '0'); + else + --for test.... + reg_exc_cnt <= INIT_EXC_CNT; + end if; + else + if (rising_edge(pi_base_clk)) then + if (reg_main_state = ST_CM_T0 and reg_sub_state = ST_SUB73) then + reg_exc_cnt <= reg_exc_cnt + 1; + elsif (reg_main_state = ST_NM_T7 and reg_sub_state = ST_SUB73) then + --reg_exc_cnt upper 16 bit is nmi count. + --lower 48 bit is cpu exec count from nmi initiated. + reg_exc_cnt(47 downto 0) <= (others => '0'); + reg_exc_cnt(63 downto 48) <= reg_exc_cnt(63 downto 48) + 1; + end if; + end if; + end if; + end process; end rtl;