diff options
Diffstat (limited to 'PIC/state_machine.vhd')
| -rw-r--r-- | PIC/state_machine.vhd | 222 |
1 files changed, 0 insertions, 222 deletions
diff --git a/PIC/state_machine.vhd b/PIC/state_machine.vhd deleted file mode 100644 index 24da581..0000000 --- a/PIC/state_machine.vhd +++ /dev/null @@ -1,222 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; -use work.alu_types.all; - -use work.decoder.all; - -entity state_machine is - port( - clk : in std_logic; - opcode : in std_logic_vector(13 downto 0); - - reset : in std_logic; - - op : out alu_op; - we_mem : out std_logic := '0'; - re_mem : out std_logic := '0'; - we_w : out std_logic := '0'; - instr_ret : out std_logic := '0'; - bit_select : out std_logic_vector(2 downto 0) := (others => '0'); - data : out std_logic_vector(7 downto 0) := (others => '0'); - pc : out std_logic_vector(12 downto 0); - addr : out std_logic_vector(6 downto 0) := (others => '0'); - - use_literal : out std_logic; - we_status : out std_logic := '0'; - - stack_push : out std_logic := '0'; - stack_pop : out std_logic := '0'; - stack_din : out std_logic_vector(12 downto 0) := (others => '0'); - stack_dout : in std_logic_vector(12 downto 0); - - alu_skip : in std_logic; - alu_result : in std_logic_vector(7 downto 0) - ); - - -end entity state_machine; - -architecture rtl of state_machine is - type state_t is (IFetch, MRead, Execute, MWrite); - - signal pc_internal : std_logic_vector(12 downto 0) := (others => '0'); - signal state : state_t := IFetch; - signal pclath : std_logic_vector(4 downto 0) := (others => '0'); - -begin - pc <= pc_internal; - - fsm : process(clk) - variable instr : instruction_t; - - -- do we do a phantom nop after this instruction? - variable do_phantom_nop : boolean := false; - variable is_phantom : boolean := false; - -- true when phantom came from DECFSZ/INCFSZ skip (must still increment PC) - -- false when phantom came from GOTO/CALL/RETURN (PC already at target) - variable is_skip_phantom : boolean := false; - begin - - if rising_edge(clk) then - - re_mem <= '0'; - we_mem <= '0'; - we_w <= '0'; - we_status <= '0'; - instr_ret <= '0'; - stack_push <= '0'; - stack_pop <= '0'; - - if reset = '1' then - pc_internal <= (others => '0'); - pclath <= (others => '0'); - state <= IFetch; - do_phantom_nop := false; - else - - case state is - when IFetch => - - -- if we had a branch before, this cycle is a NOP. - if do_phantom_nop then - instr := instruction_decode((others => '0')); - do_phantom_nop := false; - is_phantom := true; - -- is_skip_phantom carries over from whoever set do_phantom_nop - else - instr := instruction_decode(opcode); - is_phantom := false; - is_skip_phantom := false; - end if; - - -- set use_literal based on decoded instruction, holds through MWrite - if instr.class = LITERAL_OP then - use_literal <= '1'; - else - use_literal <= '0'; - end if; - - -- for literal operations - data <= instr.k(7 downto 0); - - -- for memory-read/write operations - addr <= instr.f; - - -- for bit-select operations - bit_select <= instr.b; - - state <= Mread; - - when MRead => - - -- read memory addressed by the opcode - -- MOVWF, CLRF, CLRW, NOP are write-only. - if instr.class = BIT_OP or - (instr.class = BYTE_OP and - instr.op /= MOVWF and instr.op /= CLRF and - instr.op /= CLRW and instr.op /= NOP) then - re_mem <= '1'; - end if; - - state <= Execute; - - when Execute => - - op <= instr.op; -- move the decoded instruction to the ALU - - if not is_phantom then - - -- increment PC or change address, different for different instructions. - if instr.op = GOTO then - - pc_internal <= "00" & instr.k; - do_phantom_nop := true; - is_skip_phantom := false; - - elsif instr.op = CALL then - - -- push PC+1 to the stack - stack_din <= std_logic_vector(unsigned(pc_internal) + 1); - stack_push <= '1'; - - -- go to the function we called - pc_internal <= "00" & instr.k; - do_phantom_nop := true; - is_skip_phantom := false; - - elsif instr.op = RETUR or instr.op = RETLW then - - -- pop the PC from stack. - pc_internal <= stack_dout; - stack_pop <= '1'; -- pop deferred to next cycle. - do_phantom_nop := true; - is_skip_phantom := false; - - else - pc_internal <= std_logic_vector(unsigned(pc_internal) + 1); - end if; - - elsif is_skip_phantom then - -- skip phantom: PC was at the skipped instruction, step past it - pc_internal <= std_logic_vector(unsigned(pc_internal) + 1); - end if; - -- branch phantom: PC already at target, no change needed - - state <= MWrite; - - when MWrite => - - -- write to correct memory based on class (skip for phantom NOP) - if not is_phantom then - case instr.class is - when BYTE_OP => - if instr.op /= NOP then - if instr.d = '1' then - we_mem <= '1'; - -- Write to PCLATH (addr 0x0A): latch upper PC bits - if instr.f = "0001010" then - pclath <= alu_result(4 downto 0); - end if; - -- Write to PCL (addr 0x02): redirect PC, like a GOTO - if instr.f = "0000010" then - pc_internal <= pclath & alu_result; - do_phantom_nop := true; - is_skip_phantom := false; - end if; - else - we_w <= '1'; - end if; - end if; - when BIT_OP => - -- NOT for the BTFSS or BTFSC instructions. - if instr.op = BCF or instr.op = BSF then - we_mem <= '1'; - end if; - when LITERAL_OP => - if instr.op /= NOP and instr.op /= RETUR then - we_w <= '1'; - end if; - when others => null; - end case; - end if; - - -- DECFSZ/INCFSZ/BTFSS/BTFSC: skip next instruction if ALU signals skip - if not is_phantom and - (instr.op = DECFSZ or instr.op = INCFSZ or instr.op = BTFSS or instr.op = BTFSC) and alu_skip = '1' then - do_phantom_nop := true; - is_skip_phantom := true; - end if; - - if not is_phantom then - we_status <= '1'; - instr_ret <= '1'; - end if; - state <= IFetch; - - end case; - end if; -- reset - end if; - end process fsm; - -end architecture rtl; |
