Line 72... |
Line 72... |
-- Revision History
|
-- Revision History
|
-- Author Date Change
|
-- Author Date Change
|
------------------ -------- ---------------------------------------------------
|
------------------ -------- ---------------------------------------------------
|
-- Seth Henry 07/19/06 Design Start
|
-- Seth Henry 07/19/06 Design Start
|
-- Seth Henry 01/18/11 Fixed BTT instruction to match V8
|
-- Seth Henry 01/18/11 Fixed BTT instruction to match V8
|
|
-- Seth Henry 06/14/11 Fixed STO instruction to avoid register corruption
|
|
-- Fixed interrupt logic to avoid address corruption
|
|
-- when interrupt coincides with branch instruction
|
|
|
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 84... |
Line 87... |
use work.Open8_pkg.all;
|
use work.Open8_pkg.all;
|
|
|
entity Open8_CPU is
|
entity Open8_CPU is
|
generic(
|
generic(
|
Stack_Start_Addr : ADDRESS_TYPE := x"007F"; -- Top of Stack
|
Stack_Start_Addr : ADDRESS_TYPE := x"007F"; -- Top of Stack
|
Allow_Stack_Address_Move : std_logic := '0'; -- Use Normal v8 RSP
|
Allow_Stack_Address_Move : boolean := false; -- Use Normal v8 RSP
|
ISR_Start_Addr : ADDRESS_TYPE := x"0080"; -- Bottom of ISR vec's
|
ISR_Start_Addr : ADDRESS_TYPE := x"0080"; -- Bottom of ISR vec's
|
Program_Start_Addr : ADDRESS_TYPE := x"0090"; -- Initial PC location
|
Program_Start_Addr : ADDRESS_TYPE := x"0090"; -- Initial PC location
|
Default_Interrupt_Mask : DATA_TYPE := x"FF"; -- Enable all Ints
|
Default_Interrupt_Mask : DATA_TYPE := x"FF"; -- Enable all Ints
|
Enable_CPU_Halt : std_logic := '0'; -- Disable HALT pin
|
Enable_CPU_Halt : boolean := false; -- Disable HALT pin
|
Enable_Auto_Increment : std_logic := '0' ); -- Modify indexed instr
|
Enable_Auto_Increment : boolean := false; -- Modify indexed instr
|
|
Reset_Level : std_logic := '0' ); -- Active reset level
|
port(
|
port(
|
Clock : in std_logic;
|
Clock : in std_logic;
|
Reset : in std_logic;
|
Reset : in std_logic;
|
CPU_Halt : in std_logic;
|
CPU_Halt : in std_logic := '0';
|
Interrupts : in INTERRUPT_BUNDLE;
|
Interrupts : in INTERRUPT_BUNDLE;
|
--
|
--
|
Address : out ADDRESS_TYPE;
|
Address : out ADDRESS_TYPE;
|
Rd_Data : in DATA_TYPE;
|
Rd_Data : in DATA_TYPE;
|
Rd_Enable : out std_logic;
|
Rd_Enable : out std_logic;
|
Line 212... |
Line 216... |
signal SP : ADDRESS_TYPE;
|
signal SP : ADDRESS_TYPE;
|
signal ISR : ADDRESS_TYPE;
|
signal ISR : ADDRESS_TYPE;
|
signal IMM : ADDRESS_TYPE;
|
signal IMM : ADDRESS_TYPE;
|
begin
|
begin
|
|
|
Halt_Disabled_fn: if( Enable_CPU_Halt = '0' )generate
|
Halt_Disabled_fn: if( not Enable_CPU_Halt )generate
|
Halt <= '0';
|
Halt <= '0';
|
end generate;
|
end generate;
|
|
|
Halt_Enabled_fn: if( Enable_CPU_Halt = '1' )generate
|
Halt_Enabled_fn: if( Enable_CPU_Halt )generate
|
Halt <= CPU_Halt;
|
Halt <= CPU_Halt;
|
end generate;
|
end generate;
|
|
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
-- ALU (Arithmetic / Logic Unit
|
-- ALU (Arithmetic / Logic Unit
|
Line 467... |
Line 471... |
end if;
|
end if;
|
end process;
|
end process;
|
|
|
S_Regs: process( Reset, Clock )
|
S_Regs: process( Reset, Clock )
|
begin
|
begin
|
if( Reset = '1' )then
|
if( Reset = Reset_Level )then
|
for i in 0 to 7 loop
|
for i in 0 to 7 loop
|
Regfile(i) <= (others => '0');
|
Regfile(i) <= (others => '0');
|
end loop;
|
end loop;
|
Flags <= x"00";
|
Flags <= x"00";
|
elsif( rising_edge(Clock) )then
|
elsif( rising_edge(Clock) )then
|
Line 504... |
Line 508... |
if( PC_Ctrl.Oper = PC_REV2 )then
|
if( PC_Ctrl.Oper = PC_REV2 )then
|
Rewind_1_2n <= '0';
|
Rewind_1_2n <= '0';
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
Program_Counter: process( Reset, Clock, Halt, PC_Ctrl, PC_Q, Rewind_1_2n )
|
Program_Counter: process( Reset, Clock, PC_Ctrl )
|
variable PC_Offset_SX : ADDRESS_TYPE := x"0000";
|
variable PC_Offset_SX : ADDRESS_TYPE := x"0000";
|
begin
|
begin
|
PC_Offset_SX(15 downto 8):= (others => PC_Ctrl.Offset(7));
|
PC_Offset_SX(15 downto 8):= (others => PC_Ctrl.Offset(7));
|
PC_Offset_SX(7 downto 0) := PC_Ctrl.Offset;
|
PC_Offset_SX(7 downto 0) := PC_Ctrl.Offset;
|
if( Reset = '1' )then
|
if( Reset = Reset_Level )then
|
PC_Q <= Program_Start_Addr;
|
PC_Q <= Program_Start_Addr;
|
elsif( rising_edge(Clock) )then
|
elsif( rising_edge(Clock) )then
|
if( Halt = '0' )then
|
if( Halt = '0' )then
|
case PC_Ctrl.Oper is
|
case PC_Ctrl.Oper is
|
when PC_IDLE =>
|
when PC_IDLE =>
|
Line 542... |
Line 546... |
|
|
SP <= SP_Q;
|
SP <= SP_Q;
|
|
|
Stack_Pointer: process( Reset, Clock )
|
Stack_Pointer: process( Reset, Clock )
|
begin
|
begin
|
if( Reset = '1' )then
|
if( Reset = Reset_Level )then
|
SP_Q <= Stack_Start_Addr;
|
SP_Q <= Stack_Start_Addr;
|
elsif( rising_edge(Clock) )then
|
elsif( rising_edge(Clock) )then
|
if( Halt = '0' )then
|
if( Halt = '0' )then
|
case SP_Ctrl.Oper is
|
case SP_Ctrl.Oper is
|
when SP_IDLE => null;
|
when SP_IDLE => null;
|
Line 669... |
Line 673... |
end if;
|
end if;
|
end process;
|
end process;
|
|
|
S_Regs: process( Reset, Clock )
|
S_Regs: process( Reset, Clock )
|
begin
|
begin
|
if( Reset = '1' )then
|
if( Reset = Reset_Level )then
|
Int_Req <= '0';
|
Int_Req <= '0';
|
Pending <= x"00";
|
Pending <= x"00";
|
Wait_for_FSM <= '0';
|
Wait_for_FSM <= '0';
|
Mask <= Default_Interrupt_Mask(7 downto 1);
|
Mask <= Default_Interrupt_Mask(7 downto 1);
|
ISR_Q <= INT_VECTOR_0;
|
ISR_Q <= INT_VECTOR_0;
|
Line 765... |
Line 769... |
-- Branching
|
-- Branching
|
BRN_C1, DBNZ_C1, JMP_C1, JMP_C2,
|
BRN_C1, DBNZ_C1, JMP_C1, JMP_C2,
|
-- Loads
|
-- Loads
|
LDA_C1, LDA_C2, LDA_C3, LDA_C4, LDI_C1, LDO_C1, LDX_C1, LDX_C2, LDX_C3,
|
LDA_C1, LDA_C2, LDA_C3, LDA_C4, LDI_C1, LDO_C1, LDX_C1, LDX_C2, LDX_C3,
|
-- Stores
|
-- Stores
|
STA_C1, STA_C2, STA_C3, STO_C1, STX_C1, STX_C2,
|
STA_C1, STA_C2, STA_C3, STO_C1, STO_C2, STX_C1, STX_C2,
|
-- 2-cycle math
|
-- 2-cycle math
|
MUL_C1, UPP_C1,
|
MUL_C1, UPP_C1,
|
-- Stack
|
-- Stack
|
PSH_C1, POP_C1, POP_C2, POP_C3, POP_C4,
|
PSH_C1, POP_C1, POP_C2, POP_C3, POP_C4,
|
-- Subroutines & Interrupts
|
-- Subroutines & Interrupts
|
Line 936... |
Line 940... |
|
|
when OP_MUL =>
|
when OP_MUL =>
|
CPU_Next_State <= MUL_C1;
|
CPU_Next_State <= MUL_C1;
|
Cache_Ctrl <= CACHE_PREFETCH;
|
Cache_Ctrl <= CACHE_PREFETCH;
|
|
|
-- We need to back the PC up by 1, and all it to refill. An
|
-- We need to back the PC up by 1, and allow it to refill. An
|
-- unfortunate consequence of the pipelining. We can get away with
|
-- unfortunate consequence of the pipelining. We can get away with
|
-- only 1 extra clock by pre-fetching the next instruction, though
|
-- only 1 extra clock by pre-fetching the next instruction, though
|
PC_Ctrl.Oper <= PC_REV1;
|
PC_Ctrl.Oper <= PC_REV1;
|
-- Multiplication is automatic, but requires a single clock cycle.
|
-- Multiplication is automatic, but requires a single clock cycle.
|
-- We need to specify the register for Rn (R1:R0 = R0 * Rn) now,
|
-- We need to specify the register for Rn (R1:R0 = R0 * Rn) now,
|
Line 975... |
Line 979... |
PC_Ctrl.Oper <= PC_REV2;
|
PC_Ctrl.Oper <= PC_REV2;
|
AS_Ctrl.Src <= ADDR_IMM;
|
AS_Ctrl.Src <= ADDR_IMM;
|
-- If auto-increment is disabled, use the specified register pair,
|
-- If auto-increment is disabled, use the specified register pair,
|
-- otherwise, for an odd:even pair, and issue the first half of
|
-- otherwise, for an odd:even pair, and issue the first half of
|
-- a UPP instruction to the ALU
|
-- a UPP instruction to the ALU
|
if( Enable_Auto_Increment = '0' )then
|
if( not Enable_Auto_Increment )then
|
IMM <= ALU_Regs(Reg_1) & ALU_Regs(Reg);
|
IMM <= ALU_Regs(Reg_1) & ALU_Regs(Reg);
|
else
|
else
|
Reg := conv_integer(SubOp(2 downto 1) & '0');
|
Reg := conv_integer(SubOp(2 downto 1) & '0');
|
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
|
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
|
IMM <= ALU_Regs(Reg_1) & ALU_Regs(Reg);
|
IMM <= ALU_Regs(Reg_1) & ALU_Regs(Reg);
|
Line 1079... |
Line 1083... |
|
|
when LDO_C1 =>
|
when LDO_C1 =>
|
CPU_Next_State <= LDX_C1;
|
CPU_Next_State <= LDX_C1;
|
AS_Ctrl.Src <= ADDR_IMM;
|
AS_Ctrl.Src <= ADDR_IMM;
|
PC_Ctrl.Oper <= PC_INCR;
|
PC_Ctrl.Oper <= PC_INCR;
|
if( Enable_Auto_Increment = '1' )then
|
if( Enable_Auto_Increment )then
|
Reg := conv_integer(SubOp(2 downto 1) & '0');
|
Reg := conv_integer(SubOp(2 downto 1) & '0');
|
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
|
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
|
IMM <= (ALU_Regs(Reg_1) & ALU_Regs(Reg)) + Offset_SX;
|
IMM <= (ALU_Regs(Reg_1) & ALU_Regs(Reg)) + Offset_SX;
|
if( SubOp(0) = '1' )then
|
if( SubOp(0) = '1' )then
|
ALU_Ctrl.Oper<= ALU_UPP;
|
ALU_Ctrl.Oper<= ALU_UPP;
|
Line 1109... |
Line 1113... |
ALU_Ctrl.Oper <= ALU_LDX;
|
ALU_Ctrl.Oper <= ALU_LDX;
|
ALU_Ctrl.Reg <= ACCUM;
|
ALU_Ctrl.Reg <= ACCUM;
|
ALU_Ctrl.Data <= Operand1;
|
ALU_Ctrl.Data <= Operand1;
|
|
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
-- Data Storage - Load from memory (STA, STO, STX)
|
-- Data Storage - Store to memory (STA, STO, STX)
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
when STA_C1 =>
|
when STA_C1 =>
|
CPU_Next_State <= STA_C2;
|
CPU_Next_State <= STA_C2;
|
Cache_Ctrl <= CACHE_OPER2;
|
Cache_Ctrl <= CACHE_OPER2;
|
DP_Ctrl.Src <= DATA_REG;
|
DP_Ctrl.Src <= DATA_REG;
|
Line 1133... |
Line 1137... |
when STO_C1 =>
|
when STO_C1 =>
|
Cache_Ctrl <= CACHE_PREFETCH;
|
Cache_Ctrl <= CACHE_PREFETCH;
|
PC_Ctrl.Oper <= PC_INCR;
|
PC_Ctrl.Oper <= PC_INCR;
|
AS_Ctrl.Src <= ADDR_IMM;
|
AS_Ctrl.Src <= ADDR_IMM;
|
-- If auto-increment is disabled, just load the registers normally
|
-- If auto-increment is disabled, just load the registers normally
|
if( Enable_Auto_Increment = '0' )then
|
if( not Enable_Auto_Increment )then
|
CPU_Next_State <= PIPE_FILL_1;
|
CPU_Next_State <= PIPE_FILL_1;
|
IMM <= (ALU_Regs(Reg_1) & ALU_Regs(Reg)) + Offset_SX;
|
IMM <= (ALU_Regs(Reg_1) & ALU_Regs(Reg)) + Offset_SX;
|
-- Otherwise, enforce the even register rule, and check the LSB to see
|
-- Otherwise, enforce the even register rule, and check the LSB to see
|
-- if we should perform the auto-increment on the register pair
|
-- if we should perform the auto-increment on the register pair
|
else
|
else
|
CPU_Next_State <= STX_C2;
|
CPU_Next_State <= PIPE_FILL_0;
|
Reg := conv_integer(SubOp(2 downto 1) & '0');
|
Reg := conv_integer(SubOp(2 downto 1) & '0');
|
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
|
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
|
IMM <= (ALU_Regs(Reg_1) & ALU_Regs(Reg)) + Offset_SX;
|
IMM <= (ALU_Regs(Reg_1) & ALU_Regs(Reg)) + Offset_SX;
|
if( SubOp(0) = '1' )then
|
if( SubOp(0) = '1' )then
|
|
CPU_Next_State <= STO_C2;
|
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;
|
end if;
|
end if;
|
|
|
|
when STO_C2 =>
|
|
CPU_Next_State <= PIPE_FILL_1;
|
|
PC_Ctrl.Oper <= PC_INCR;
|
|
ALU_Ctrl.Oper <= ALU_UPP2;
|
|
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '1';
|
|
|
when STX_C1 =>
|
when STX_C1 =>
|
PC_Ctrl.Oper <= PC_INCR;
|
PC_Ctrl.Oper <= PC_INCR;
|
AS_Ctrl.Src <= ADDR_IMM;
|
AS_Ctrl.Src <= ADDR_IMM;
|
-- If auto-increment is disabled, just load the registers normally
|
-- If auto-increment is disabled, just load the registers normally
|
if( Enable_Auto_Increment = '0' )then
|
if( not Enable_Auto_Increment )then
|
CPU_Next_State <= PIPE_FILL_1;
|
CPU_Next_State <= PIPE_FILL_1;
|
IMM <= (ALU_Regs(Reg_1) & ALU_Regs(Reg));
|
IMM <= (ALU_Regs(Reg_1) & ALU_Regs(Reg));
|
-- Otherwise, enforce the even register rule, and check the LSB to see
|
-- Otherwise, enforce the even register rule, and check the LSB to see
|
-- if we should perform the auto-increment on the register pair
|
-- if we should perform the auto-increment on the register pair
|
else
|
else
|
CPU_Next_State <= STX_C2;
|
CPU_Next_State <= PIPE_FILL_1;
|
Reg := conv_integer(SubOp(2 downto 1) & '0');
|
Reg := conv_integer(SubOp(2 downto 1) & '0');
|
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
|
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
|
IMM <= (ALU_Regs(Reg_1) & ALU_Regs(Reg));
|
IMM <= (ALU_Regs(Reg_1) & ALU_Regs(Reg));
|
if( SubOp(0) = '1' )then
|
if( SubOp(0) = '1' )then
|
|
CPU_Next_State <= STX_C2;
|
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;
|
end if;
|
end if;
|
|
|
Line 1231... |
Line 1243... |
|
|
when ISR_C1 =>
|
when ISR_C1 =>
|
CPU_Next_State <= ISR_C2;
|
CPU_Next_State <= ISR_C2;
|
AS_Ctrl.Src <= ADDR_ISR;
|
AS_Ctrl.Src <= ADDR_ISR;
|
INT_Ctrl.Incr_ISR <= '1';
|
INT_Ctrl.Incr_ISR <= '1';
|
PC_Ctrl.Oper <= PC_INCR;
|
-- PC_Ctrl.Oper <= PC_INCR;
|
-- Rewind the PC by 3 to compensate for the pipeline registers
|
-- Rewind the PC by 3 to compensate for the pipeline registers
|
PC_Ctrl.Offset <= x"FF";
|
-- PC_Ctrl.Offset <= x"FF";
|
|
|
when ISR_C2 =>
|
when ISR_C2 =>
|
CPU_Next_State <= ISR_C3;
|
CPU_Next_State <= ISR_C3;
|
AS_Ctrl.Src <= ADDR_ISR;
|
AS_Ctrl.Src <= ADDR_ISR;
|
DP_Ctrl.Src <= DATA_FLAG;
|
DP_Ctrl.Src <= DATA_FLAG;
|
Line 1321... |
Line 1333... |
-- Interrupt service routines can only begin during the decode and wait
|
-- Interrupt service routines can only begin during the decode and wait
|
-- states to avoid corruption due to incomplete instruction execution
|
-- states to avoid corruption due to incomplete instruction execution
|
if( Int_Req = '1' )then
|
if( Int_Req = '1' )then
|
if( CPU_State = INSTR_DECODE or CPU_State = WAIT_FOR_INT )then
|
if( CPU_State = INSTR_DECODE or CPU_State = WAIT_FOR_INT )then
|
CPU_Next_State <= ISR_C1;
|
CPU_Next_State <= ISR_C1;
|
|
PC_Ctrl.Oper <= PC_INCR;
|
|
-- Rewind the PC by 3 to compensate for the pipeline registers
|
|
PC_Ctrl.Offset <= x"FF";
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
end process;
|
end process;
|
|
|
S_Regs: process( Reset, Clock )
|
S_Regs: process( Reset, Clock )
|
begin
|
begin
|
if( Reset = '1' )then
|
if( Reset = Reset_Level )then
|
CPU_State <= PIPE_FILL_0;
|
CPU_State <= PIPE_FILL_0;
|
Opcode <= OP_INC;
|
Opcode <= OP_INC;
|
SubOp <= ACCUM;
|
SubOp <= ACCUM;
|
SubOp_p1 <= ACCUM;
|
SubOp_p1 <= ACCUM;
|
Operand1 <= x"00";
|
Operand1 <= x"00";
|
Line 1390... |
Line 1405... |
-- address set at compile time. However, with little extra effort, we can
|
-- address set at compile time. However, with little extra effort, we can
|
-- modify the instruction to allow the stack pointer to be moved anywhere in
|
-- modify the instruction to allow the stack pointer to be moved anywhere in
|
-- the memory map. Since RSP can't have an sub-opcode, R1:R0 was chosen as
|
-- the memory map. Since RSP can't have an sub-opcode, R1:R0 was chosen as
|
-- a fixed source
|
-- a fixed source
|
|
|
Prog_Stack_Addr_Move_fn: if( Allow_Stack_Address_Move = '1' )generate
|
Prog_Stack_Addr_Move_fn: if( Allow_Stack_Address_Move )generate
|
SP_Ctrl.Addr <= ALU_Regs(1) & ALU_Regs(0);
|
SP_Ctrl.Addr <= ALU_Regs(1) & ALU_Regs(0);
|
end generate;
|
end generate;
|
|
|
Normal_Stack_Reset_fn: if( Allow_Stack_Address_Move = '0' )generate
|
Normal_Stack_Reset_fn: if( not Allow_Stack_Address_Move )generate
|
SP_Ctrl.Addr <= Stack_Start_Addr;
|
SP_Ctrl.Addr <= Stack_Start_Addr;
|
end generate;
|
end generate;
|
|
|
end block;
|
end block;
|
|
|
Line 1478... |
Line 1493... |
end loop;
|
end loop;
|
end process;
|
end process;
|
|
|
S_Regs: process( Reset, Clock )
|
S_Regs: process( Reset, Clock )
|
begin
|
begin
|
if( Reset = '1' )then
|
if( Reset = Reset_Level )then
|
Wr_Data <= (others => '0');
|
Wr_Data <= (others => '0');
|
Wr_Enable <= '0';
|
Wr_Enable <= '0';
|
Rd_Enable <= '1';
|
Rd_Enable <= '1';
|
elsif( rising_edge(Clock) )then
|
elsif( rising_edge(Clock) )then
|
if( Halt = '0' )then
|
if( Halt = '0' )then
|
Line 1495... |
Line 1510... |
|
|
end block;
|
end block;
|
|
|
end rtl;
|
end rtl;
|
|
|
|
|
No newline at end of file
|
No newline at end of file
|