summaryrefslogtreecommitdiffstats
path: root/hdl/state_machine.vhd
diff options
context:
space:
mode:
Diffstat (limited to 'hdl/state_machine.vhd')
-rw-r--r--hdl/state_machine.vhd32
1 files changed, 27 insertions, 5 deletions
diff --git a/hdl/state_machine.vhd b/hdl/state_machine.vhd
index 5b1c623..1fb5291 100644
--- a/hdl/state_machine.vhd
+++ b/hdl/state_machine.vhd
@@ -31,7 +31,11 @@ entity state_machine is
stack_dout : in std_logic_vector(12 downto 0);
alu_skip : in std_logic;
- alu_result : in std_logic_vector(7 downto 0)
+ alu_result : in std_logic_vector(7 downto 0);
+
+ irq_pending : in std_logic;
+ gie_clear : out std_logic := '0';
+ gie_set : out std_logic := '0'
);
@@ -67,6 +71,8 @@ begin
instr_ret <= '0';
stack_push <= '0';
stack_pop <= '0';
+ gie_clear <= '0';
+ gie_set <= '0';
if reset = '1' then
pc_internal <= (others => '0');
@@ -78,16 +84,30 @@ begin
case state is
when IFetch =>
+ -- Hardware interrupt: push PC, jump to vector, clear GIE
+ if irq_pending = '1' and not do_phantom_nop then
+ stack_din <= pc_internal;
+ stack_push <= '1';
+ pc_internal <= "0000000000100"; -- 0x0004
+ gie_clear <= '1';
+ instr := instruction_decode((others => '0'));
+ is_phantom := true;
+ is_skip_phantom := false;
+ do_phantom_nop := false;
+ state <= MRead;
+
-- if we had a branch before, this cycle is a NOP.
- if do_phantom_nop then
+ elsif 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
+ state <= MRead;
else
instr := instruction_decode(opcode);
is_phantom := false;
is_skip_phantom := false;
+ state <= MRead;
end if;
-- set use_literal based on decoded instruction, holds through MWrite
@@ -106,7 +126,6 @@ begin
-- for bit-select operations
bit_select <= instr.b;
- state <= Mread;
when MRead =>
@@ -145,13 +164,16 @@ begin
do_phantom_nop := true;
is_skip_phantom := false;
- elsif instr.op = RETUR or instr.op = RETLW then
+ elsif instr.op = RETUR or instr.op = RETLW or instr.op = RETFIE then
-- pop the PC from stack.
pc_internal <= stack_dout;
- stack_pop <= '1'; -- pop deferred to next cycle.
+ stack_pop <= '1';
do_phantom_nop := true;
is_skip_phantom := false;
+ if instr.op = RETFIE then
+ gie_set <= '1';
+ end if;
else
pc_internal <= std_logic_vector(unsigned(pc_internal) + 1);