Line 227... |
Line 227... |
-- Seth Henry 05/21/20 Supervisor_Mode now protects the interrupt mask
|
-- Seth Henry 05/21/20 Supervisor_Mode now protects the interrupt mask
|
-- and stack pointer as well.
|
-- and stack pointer as well.
|
-- Seth Henry 05/24/20 Removed the Default_Int_Flag, as it is covered by
|
-- Seth Henry 05/24/20 Removed the Default_Int_Flag, as it is covered by
|
-- Supervisor_Mode. If Supervisor_Mode isn't set,
|
-- Supervisor_Mode. If Supervisor_Mode isn't set,
|
-- code can simply use STP to set the bit
|
-- code can simply use STP to set the bit
|
|
-- Seth Henry 06/09/20 Added ability to use unsigned index offsets for
|
|
-- LDO/SDO. Also pipelined the address calculation
|
|
-- for indexed instructions, reducing the final
|
|
-- address generator to a multiplexor fed only by
|
|
-- registers.
|
|
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_unsigned.all;
|
use ieee.std_logic_unsigned.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_arith.all;
|
Line 250... |
Line 255... |
BRK_Implements_WAI : boolean := false; -- BRK -> Wait for Int
|
BRK_Implements_WAI : boolean := false; -- BRK -> Wait for Int
|
Enable_NMI : boolean := true; -- Force INTR0 enabled
|
Enable_NMI : boolean := true; -- Force INTR0 enabled
|
Sequential_Interrupts : boolean := false; -- Interruptable ISRs
|
Sequential_Interrupts : boolean := false; -- Interruptable ISRs
|
RTI_Ignores_GP_Flags : boolean := false; -- RTI sets all flags
|
RTI_Ignores_GP_Flags : boolean := false; -- RTI sets all flags
|
Supervisor_Mode : boolean := false; -- I bit is restricted
|
Supervisor_Mode : boolean := false; -- I bit is restricted
|
|
Unsigned_Index_Offsets : boolean := false; -- Offsets are signed
|
Default_Interrupt_Mask : DATA_TYPE := x"FF"; -- Enable all Ints
|
Default_Interrupt_Mask : DATA_TYPE := x"FF"; -- Enable all Ints
|
Clock_Frequency : real -- Clock Frequency
|
Clock_Frequency : real -- Clock Frequency
|
);
|
);
|
port(
|
port(
|
Clock : in std_logic;
|
Clock : in std_logic;
|
Line 327... |
Line 333... |
signal i_Ints : INTERRUPT_BUNDLE := x"00";
|
signal i_Ints : INTERRUPT_BUNDLE := x"00";
|
signal Pending : INTERRUPT_BUNDLE := x"00";
|
signal Pending : INTERRUPT_BUNDLE := x"00";
|
signal Wait_for_FSM : std_logic := '0';
|
signal Wait_for_FSM : std_logic := '0';
|
signal Wait_for_ISR : std_logic := '0';
|
signal Wait_for_ISR : std_logic := '0';
|
|
|
|
signal IDX_Offset : ADDRESS_TYPE := x"0000";
|
|
|
|
signal IDX_Reg_l : integer := 0;
|
|
signal IDX_Reg_h : integer := 0;
|
|
|
|
signal IDX_NoOffset_Calc : ADDRESS_TYPE := x"0000";
|
|
signal IDX_Offset_Calc : ADDRESS_TYPE := x"0000";
|
|
|
begin
|
begin
|
|
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
-- Reset & uSec Tick
|
-- Reset & uSec Tick
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
Line 366... |
Line 380... |
|
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
-- Address bus selection/generation logic
|
-- Address bus selection/generation logic
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
|
|
Address_Logic: process(CPU_State, Regfile, SubOp, SubOp_p1, Operand1,
|
-- The original model treated the offset to LDO/STO as a signed value
|
Operand2, Program_Ctr, Stack_Ptr, ISR_Addr )
|
-- allowing access to locations -128 to +127 from [Rn+1:Rn]. This isn't
|
|
-- always helpful, so the generic allows the CPU to use unsigned math
|
|
-- for the offsets. This makes the range 0 to +255 instead.
|
|
Unsigned_Idx_Offsets : if( Unsigned_Index_Offsets )generate
|
|
IDX_Offset(15 downto 8) <= (others => '0');
|
|
IDX_Offset(7 downto 0) <= Operand1;
|
|
end generate;
|
|
|
|
Signed_Idx_Offsets: if( not Unsigned_Index_Offsets )generate
|
|
IDX_Offset(15 downto 8) <= (others => Operand1(7));
|
|
IDX_Offset(7 downto 0) <= Operand1;
|
|
end generate;
|
|
|
|
-- Enable_Auto_Increment uses the LSB to determine whether or not to
|
|
-- do the auto-increment, so we need to lock the LSB for each operand
|
|
-- if it is enabled. This forces [ODD:EVEN] pairing.
|
|
|
|
Auto_Incr_Set: if( Enable_Auto_Increment )generate
|
|
IDX_Reg_l <= conv_integer(SubOp(2 downto 1) & '0');
|
|
IDX_Reg_h <= conv_integer(SubOp(2 downto 1) & '1');
|
|
end generate;
|
|
|
|
Auto_Incr_Not_Set: if( not Enable_Auto_Increment )generate
|
|
IDX_Reg_l <= conv_integer(SubOp);
|
|
IDX_Reg_h <= conv_integer(SubOp_p1);
|
|
end generate;
|
|
|
|
-- Pipeline registers for the indexed and indexed with offset addresses.
|
|
Idx_Addr_Calc_proc: process( Clock, Reset )
|
variable Reg, Reg_1 : integer range 0 to 7 := 0;
|
variable Reg, Reg_1 : integer range 0 to 7 := 0;
|
variable Offset_SX : ADDRESS_TYPE;
|
|
begin
|
begin
|
|
if( Reset = Reset_Level )then
|
if( Enable_Auto_Increment )then
|
IDX_NoOffset_Calc <= x"0000";
|
Reg := conv_integer(SubOp(2 downto 1) & '0');
|
IDX_Offset_Calc <= x"0000";
|
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
|
elsif( rising_edge(Clock))then
|
else
|
IDX_NoOffset_Calc <= (Regfile(IDX_Reg_h) & Regfile(IDX_Reg_l));
|
Reg := conv_integer(SubOp);
|
IDX_Offset_Calc <= (Regfile(IDX_Reg_h) & Regfile(IDX_Reg_l)) +
|
Reg_1 := conv_integer(SubOp_p1);
|
IDX_Offset;
|
end if;
|
end if;
|
|
end process;
|
|
|
Offset_SX(15 downto 0) := (others => Operand1(7));
|
-- Address selection logic based on current CPU state. This is combinatorial,
|
Offset_SX(7 downto 0) := Operand1;
|
-- as adding pipeline registration would add a clock cycle to every instr,
|
|
-- without really adding the Fmax to compensate.
|
|
Address_Logic: process(CPU_State, Operand1, Operand2, IDX_NoOffset_Calc,
|
|
IDX_Offset_Calc, ISR_Addr, Stack_Ptr, Program_Ctr )
|
|
begin
|
case( CPU_State )is
|
case( CPU_State )is
|
|
|
when LDA_C2 | STA_C2 =>
|
when LDA_C2 | STA_C2 =>
|
Open8_Bus.Address <= Operand2 & Operand1;
|
Open8_Bus.Address <= Operand2 & Operand1;
|
|
|
when LDX_C1 | STX_C1 =>
|
when LDX_C1 | STX_C1 =>
|
Open8_Bus.Address <= (Regfile(Reg_1) & Regfile(Reg));
|
Open8_Bus.Address <= IDX_NoOffset_Calc;
|
|
|
when LDO_C1 | STO_C1 =>
|
when LDO_C2 | STO_C2 =>
|
Open8_Bus.Address <= (Regfile(Reg_1) & Regfile(Reg)) + Offset_SX;
|
Open8_Bus.Address <= IDX_Offset_Calc;
|
|
|
when ISR_C1 | ISR_C2 =>
|
when ISR_C1 | ISR_C2 =>
|
Open8_Bus.Address <= ISR_Addr;
|
Open8_Bus.Address <= ISR_Addr;
|
|
|
when PSH_C1 | POP_C1 | ISR_C3 | JSR_C1 | JSR_C2 | RTS_C1 | RTS_C2 | RTS_C3 =>
|
when PSH_C1 | POP_C1 | ISR_C3 | JSR_C1 | JSR_C2 | RTS_C1 | RTS_C2 | RTS_C3 =>
|
Line 404... |
Line 449... |
|
|
when others =>
|
when others =>
|
Open8_Bus.Address <= Program_Ctr;
|
Open8_Bus.Address <= Program_Ctr;
|
|
|
end case;
|
end case;
|
|
|
end process;
|
end process;
|
|
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
-- Combinatorial portion of CPU finite state machine
|
-- Combinatorial portion of CPU finite state machine
|
-- State Logic / Instruction Decoding & Execution
|
-- State Logic / Instruction Decoding & Execution
|
Line 610... |
Line 654... |
Cache_Ctrl <= CACHE_OPER1;
|
Cache_Ctrl <= CACHE_OPER1;
|
|
|
when OP_STO =>
|
when OP_STO =>
|
CPU_Next_State <= STO_C1;
|
CPU_Next_State <= STO_C1;
|
Cache_Ctrl <= CACHE_OPER1;
|
Cache_Ctrl <= CACHE_OPER1;
|
PC_Ctrl.Offset <= PC_REV2;
|
PC_Ctrl.Offset <= PC_REV1;
|
DP_Ctrl.Src <= DATA_WR_REG;
|
|
DP_Ctrl.Reg <= ACCUM;
|
|
|
|
when OP_STX =>
|
when OP_STX =>
|
CPU_Next_State <= STX_C1;
|
CPU_Next_State <= STX_C1;
|
Cache_Ctrl <= CACHE_PREFETCH;
|
Cache_Ctrl <= CACHE_PREFETCH;
|
PC_Ctrl.Offset <= PC_REV2;
|
PC_Ctrl.Offset <= PC_REV2;
|
Line 732... |
Line 774... |
PC_Ctrl.Offset <= PC_NEXT;
|
PC_Ctrl.Offset <= PC_NEXT;
|
ALU_Ctrl.Oper <= ALU_LDI;
|
ALU_Ctrl.Oper <= ALU_LDI;
|
ALU_Ctrl.Reg <= SubOp;
|
ALU_Ctrl.Reg <= SubOp;
|
|
|
when LDO_C1 =>
|
when LDO_C1 =>
|
|
CPU_Next_State <= LDO_C2;
|
|
|
|
when LDO_C2 =>
|
CPU_Next_State <= LDX_C2;
|
CPU_Next_State <= LDX_C2;
|
PC_Ctrl.Offset <= PC_NEXT;
|
PC_Ctrl.Offset <= PC_NEXT;
|
if( Enable_Auto_Increment and SubOp(0) = '1' )then
|
if( Enable_Auto_Increment and SubOp(0) = '1' )then
|
ALU_Ctrl.Oper <= ALU_UPP;
|
ALU_Ctrl.Oper <= ALU_UPP;
|
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
|
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
|
Line 781... |
Line 826... |
CPU_Next_State <= IPF_C2;
|
CPU_Next_State <= IPF_C2;
|
Cache_Ctrl <= CACHE_PREFETCH;
|
Cache_Ctrl <= CACHE_PREFETCH;
|
PC_Ctrl.Offset <= PC_NEXT;
|
PC_Ctrl.Offset <= PC_NEXT;
|
|
|
when STO_C1 =>
|
when STO_C1 =>
|
CPU_Next_State <= IPF_C0;
|
CPU_Next_State <= STO_C2;
|
Cache_Ctrl <= CACHE_PREFETCH;
|
Cache_Ctrl <= CACHE_PREFETCH;
|
|
DP_Ctrl.Src <= DATA_WR_REG;
|
|
DP_Ctrl.Reg <= ACCUM;
|
|
|
|
when STO_C2 =>
|
|
CPU_Next_State <= IPF_C1;
|
PC_Ctrl.Offset <= PC_NEXT;
|
PC_Ctrl.Offset <= PC_NEXT;
|
if( Enable_Auto_Increment and SubOp(0) = '1' )then
|
if( Enable_Auto_Increment and SubOp(0) = '1' )then
|
CPU_Next_State <= STO_C2;
|
CPU_Next_State <= STO_C3;
|
ALU_Ctrl.Oper <= ALU_UPP;
|
ALU_Ctrl.Oper <= ALU_UPP;
|
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
|
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
|
end if;
|
end if;
|
|
|
when STO_C2 =>
|
when STO_C3 =>
|
CPU_Next_State <= IPF_C1;
|
CPU_Next_State <= IPF_C2;
|
PC_Ctrl.Offset <= PC_NEXT;
|
PC_Ctrl.Offset <= PC_NEXT;
|
ALU_Ctrl.Oper <= ALU_UPP2;
|
ALU_Ctrl.Oper <= ALU_UPP2;
|
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '1';
|
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '1';
|
|
|
when STX_C1 =>
|
when STX_C1 =>
|