OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 181 to Rev 182
    Reverse comparison

Rev 181 → Rev 182

/open8_urisc/trunk/VHDL/Open8.vhd
158,10 → 158,14
-- faster logic that simply does priority encoding.
-- Seth Henry 08/06/13 Removed HALT functionality
-- Seth Henry 10/29/15 Fixed inverted carry logic in CMP and SBC instrs
-- Seth Henry 12/19/19 Renamed to o8_cpu to fit "theme"
-- Seth Henry 03/09/20 Modified RSP instruction to work with a CPU flag
-- allowing true backup/restore of the stack pointer
-- Also modified LDX to reduce the compexity of the
-- address logic.
-- Seth Henry 03/11/20 Split the address logic from the main state machine
-- in order to simplify things and eliminate
-- redundancies. Came across and fixed a problem with
-- the STO instruction when Enable_Auto_Increment is
-- NOT set.
 
library ieee;
use ieee.std_logic_1164.all;
172,7 → 176,7
library work;
use work.Open8_pkg.all;
 
entity Open8_CPU is
entity Open8 is
generic(
Program_Start_Addr : ADDRESS_TYPE := x"0000"; -- Initial PC location
ISR_Start_Addr : ADDRESS_TYPE := x"FFF0"; -- Bottom of ISR vec's
196,7 → 200,7
Wr_Enable : out std_logic );
end entity;
 
architecture behave of Open8_CPU is
architecture behave of Open8 is
 
constant INT_VECTOR_0 : ADDRESS_TYPE := ISR_Start_Addr;
constant INT_VECTOR_1 : ADDRESS_TYPE := ISR_Start_Addr+2;
225,6 → 229,11
signal PC_Ctrl : PC_CTRL_TYPE;
signal Program_Ctr : ADDRESS_TYPE := x"0000";
 
signal ALU_Ctrl : ALU_CTRL_TYPE;
signal Regfile : REGFILE_TYPE;
signal Flags : FLAG_TYPE;
signal Mult : ADDRESS_TYPE := x"0000";
 
signal SP_Ctrl : SP_CTRL_TYPE;
signal Stack_Ptr : ADDRESS_TYPE := x"0000";
 
239,39 → 248,75
signal Pending : INTERRUPT_BUNDLE := x"00";
signal Wait_for_FSM : std_logic := '0';
 
signal ALU_Ctrl : ALU_CTRL_TYPE;
signal Regfile : REGFILE_TYPE;
signal Flags : FLAG_TYPE;
signal Mult : ADDRESS_TYPE := x"0000";
 
begin
 
-------------------------------------------------------------------------------
-- State Logic / Instruction Decoding & Execution
-- Combinatorial portion of CPU finite state machine
-- Address bus selection/generation logic
-------------------------------------------------------------------------------
 
State_Logic: process(CPU_State, Regfile, Flags, Int_Mask, Opcode,
SubOp , SubOp_p1, Operand1, Operand2, Int_Req,
Address_Logic: process(CPU_State, Regfile, SubOp, SubOp_p1, Operand1, Operand2,
Program_Ctr, Stack_Ptr, ISR_Addr )
variable Reg, Reg_1 : integer range 0 to 7 := 0;
variable Offset_SX : ADDRESS_TYPE;
begin
 
if( Enable_Auto_Increment )then
Reg := conv_integer(SubOp(2 downto 1) & '0');
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
else
Reg := conv_integer(SubOp);
Reg_1 := conv_integer(SubOp_p1);
end if;
 
Offset_SX(15 downto 0) := (others => Operand1(7));
Offset_SX(7 downto 0) := Operand1;
 
case( CPU_State )is
 
when LDA_C2 | STA_C2 =>
Address <= Operand2 & Operand1;
 
when LDX_C1 | STX_C1 =>
Address <= (Regfile(Reg_1) & Regfile(Reg));
 
when LDO_C1 | STO_C1 =>
Address <= (Regfile(Reg_1) & Regfile(Reg)) + Offset_SX;
 
when ISR_C1 | ISR_C2 =>
Address <= ISR_Addr;
 
when PSH_C1 | POP_C1 | ISR_C3 | JSR_C1 | JSR_C2 | RTS_C1 | RTS_C2 | RTS_C3 =>
Address <= Stack_Ptr;
 
when others =>
Address <= Program_Ctr;
 
end case;
 
end process;
 
-------------------------------------------------------------------------------
-- Combinatorial portion of CPU finite state machine
-- State Logic / Instruction Decoding & Execution
-------------------------------------------------------------------------------
 
State_Logic: process(CPU_State, Flags, Int_Mask, Opcode,
SubOp , SubOp_p1, Operand1, Operand2, Int_Req )
variable Reg : integer range 0 to 7 := 0;
begin
CPU_Next_State <= CPU_State;
Cache_Ctrl <= CACHE_IDLE;
--
PC_Ctrl.Oper <= PC_IDLE;
PC_Ctrl.Offset <= x"03";
PC_Ctrl.Addr <= x"0000";
--
ALU_Ctrl.Oper <= ALU_IDLE;
ALU_Ctrl.Reg <= ACCUM;
ALU_Ctrl.Data <= x"00";
--
PC_Ctrl.Oper <= PC_IDLE;
PC_Ctrl.Offset <= x"03";
PC_Ctrl.Addr <= x"0000";
--
SP_Ctrl.Oper <= SP_IDLE;
--
Address <= Program_Ctr;
--
DP_Ctrl.Src <= DATA_RD_MEM;
DP_Ctrl.Reg <= ACCUM;
--
280,12 → 325,7
INT_Ctrl.Incr_ISR <= '0';
Ack_D <= '0';
 
-- Assign the most common value of Reg and Reg1 outside the case structure
-- to simplify things.
Reg := conv_integer(SubOp);
Reg_1 := conv_integer(SubOp_p1);
Offset_SX(15 downto 0) := (others => Operand1(7));
Offset_SX(7 downto 0) := Operand1;
Reg := conv_integer(SubOp);
 
case CPU_State is
-------------------------------------------------------------------------------
389,7 → 429,7
CPU_Next_State <= JSR_C1;
Cache_Ctrl <= CACHE_OPER1;
DP_Ctrl.Src <= DATA_WR_PC;
DP_Ctrl.Reg <= ACCUM+1;
DP_Ctrl.Reg <= PC_MSB;
 
when others => null;
end case;
503,7 → 543,6
 
when LDA_C2 =>
CPU_Next_State <= LDA_C3;
Address <= Operand2 & Operand1;
 
when LDA_C3 =>
CPU_Next_State <= LDA_C4;
525,30 → 564,16
when LDO_C1 =>
CPU_Next_State <= LDX_C2;
PC_Ctrl.Oper <= PC_INCR;
if( Enable_Auto_Increment )then
Reg := conv_integer(SubOp(2 downto 1) & '0');
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
Address <= (Regfile(Reg_1) & Regfile(Reg)) + Offset_SX;
if( SubOp(0) = '1' )then
ALU_Ctrl.Oper <= ALU_UPP;
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
end if;
else
Address <= (Regfile(Reg_1) & Regfile(Reg)) + Offset_SX;
if( Enable_Auto_Increment and SubOp(0) = '1' )then
ALU_Ctrl.Oper <= ALU_UPP;
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
end if;
 
when LDX_C1 =>
CPU_Next_State <= LDX_C2;
if( Enable_Auto_Increment )then
Reg := conv_integer(SubOp(2 downto 1) & '0');
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
Address <= (Regfile(Reg_1) & Regfile(Reg));
if( SubOp(0) = '1' )then
ALU_Ctrl.Oper <= ALU_UPP;
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
end if;
else
Address <= (Regfile(Reg_1) & Regfile(Reg));
if( Enable_Auto_Increment and SubOp(0) = '1' )then
ALU_Ctrl.Oper <= ALU_UPP;
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
end if;
 
when LDX_C2 =>
557,8 → 582,8
 
when LDX_C3 =>
CPU_Next_State <= LDX_C4;
Cache_Ctrl <= CACHE_OPER1;
PC_Ctrl.Oper <= PC_INCR;
Cache_Ctrl <= CACHE_OPER1;
 
when LDX_C4 =>
CPU_Next_State <= INSTR_DECODE;
579,7 → 604,6
 
when STA_C2 =>
CPU_Next_State <= STA_C3;
Address <= Operand2 & Operand1;
PC_Ctrl.Oper <= PC_INCR;
 
when STA_C3 =>
588,24 → 612,13
PC_Ctrl.Oper <= PC_INCR;
 
when STO_C1 =>
CPU_Next_State <= PIPE_FILL_0;
Cache_Ctrl <= CACHE_PREFETCH;
PC_Ctrl.Oper <= PC_INCR;
-- If auto-increment is disabled, just load the registers normally
if( not Enable_Auto_Increment )then
CPU_Next_State <= PIPE_FILL_1;
Address <= (Regfile(Reg_1) & Regfile(Reg)) + Offset_SX;
-- Otherwise, enforce the even register rule, and check the LSB to see
-- if we should perform the auto-increment on the register pair
else
CPU_Next_State <= PIPE_FILL_0;
Reg := conv_integer(SubOp(2 downto 1) & '0');
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
Address <= (Regfile(Reg_1) & Regfile(Reg)) + Offset_SX;
if( SubOp(0) = '1' )then
CPU_Next_State <= STO_C2;
ALU_Ctrl.Oper <= ALU_UPP;
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
end if;
if( Enable_Auto_Increment and SubOp(0) = '1' )then
CPU_Next_State <= STO_C2;
ALU_Ctrl.Oper <= ALU_UPP;
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
end if;
 
when STO_C2 =>
615,23 → 628,12
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '1';
 
when STX_C1 =>
CPU_Next_State <= PIPE_FILL_1;
PC_Ctrl.Oper <= PC_INCR;
-- If auto-increment is disabled, just load the registers normally
if( not Enable_Auto_Increment )then
CPU_Next_State <= PIPE_FILL_1;
Address <= (Regfile(Reg_1) & Regfile(Reg));
-- Otherwise, enforce the even register rule, and check the LSB to see
-- if we should perform the auto-increment on the register pair
else
CPU_Next_State <= PIPE_FILL_1;
Reg := conv_integer(SubOp(2 downto 1) & '0');
Reg_1 := conv_integer(SubOp(2 downto 1) & '1');
Address <= (Regfile(Reg_1) & Regfile(Reg));
if( SubOp(0) = '1' )then
CPU_Next_State <= STX_C2;
ALU_Ctrl.Oper <= ALU_UPP;
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
end if;
if( Enable_Auto_Increment and SubOp(0) = '1' )then
CPU_Next_State <= STX_C2;
ALU_Ctrl.Oper <= ALU_UPP;
ALU_Ctrl.Reg <= SubOp(2 downto 1) & '0';
end if;
 
when STX_C2 =>
664,12 → 666,10
-------------------------------------------------------------------------------
when PSH_C1 =>
CPU_Next_State <= PIPE_FILL_1;
Address <= Stack_Ptr;
SP_Ctrl.Oper <= SP_PUSH;
 
when POP_C1 =>
CPU_Next_State <= POP_C2;
Address <= Stack_Ptr;
 
when POP_C2 =>
CPU_Next_State <= POP_C3;
692,53 → 692,46
-- Subroutines & Interrupts (RTS, JSR)
-------------------------------------------------------------------------------
when WAIT_FOR_INT => -- For soft interrupts only, halt the Program_Ctr
CPU_Next_State <= WAIT_FOR_INT;
DP_Ctrl.Src <= DATA_BUS_IDLE;
CPU_Next_State <= WAIT_FOR_INT;
 
when ISR_C1 =>
CPU_Next_State <= ISR_C2;
Address <= ISR_Addr;
INT_Ctrl.Incr_ISR <= '1';
 
when ISR_C2 =>
CPU_Next_State <= ISR_C3;
Address <= ISR_Addr;
DP_Ctrl.Src <= DATA_WR_FLAG;
 
when ISR_C3 =>
CPU_Next_State <= JSR_C1;
Cache_Ctrl <= CACHE_OPER1;
Address <= Stack_Ptr;
ALU_Ctrl.Oper <= ALU_STP;
ALU_Ctrl.Reg <= INT_FLAG;
SP_Ctrl.Oper <= SP_PUSH;
DP_Ctrl.Src <= DATA_WR_PC;
DP_Ctrl.Reg <= ACCUM+1;
ALU_Ctrl.Oper <= ALU_STP;
ALU_Ctrl.Reg <= INT_FLAG;
DP_Ctrl.Reg <= PC_MSB;
Ack_D <= '1';
 
when JSR_C1 =>
CPU_Next_State <= JSR_C2;
Cache_Ctrl <= CACHE_OPER2;
Address <= Stack_Ptr;
SP_Ctrl.Oper <= SP_PUSH;
DP_Ctrl.Src <= DATA_WR_PC;
DP_Ctrl.Reg <= ACCUM;
DP_Ctrl.Reg <= PC_LSB;
 
when JSR_C2 =>
CPU_Next_State <= PIPE_FILL_0;
Address <= Stack_Ptr;
SP_Ctrl.Oper <= SP_PUSH;
PC_Ctrl.Oper <= PC_LOAD;
PC_Ctrl.Addr <= Operand2 & Operand1;
SP_Ctrl.Oper <= SP_PUSH;
 
when RTS_C1 =>
CPU_Next_State <= RTS_C2;
Address <= Stack_Ptr;
SP_Ctrl.Oper <= SP_POP;
 
when RTS_C2 =>
CPU_Next_State <= RTS_C3;
Address <= Stack_Ptr;
-- if this is an RTI, then we need to POP the flags
if( SubOp = SOP_RTI )then
SP_Ctrl.Oper <= SP_POP;
747,9 → 740,6
when RTS_C3 =>
CPU_Next_State <= RTS_C4;
Cache_Ctrl <= CACHE_OPER1;
-- It doesn't really matter what is on the address bus for RTS, while
-- it does for RTI, so we make this the default
Address <= Stack_Ptr;
 
when RTS_C4 =>
CPU_Next_State <= RTS_C5;
784,17 → 774,17
-- states to avoid corruption due to incomplete instruction execution
if( Int_Req = '1' )then
if( CPU_State = INSTR_DECODE or CPU_State = WAIT_FOR_INT )then
CPU_Next_State <= ISR_C1;
Cache_Ctrl <= CACHE_IDLE;
-- Rewind the PC by 3 to compensate for the pipeline registers
PC_Ctrl.Oper <= PC_INCR;
PC_Ctrl.Offset <= x"FF";
-- Reset all of the sub-block controls to IDLE, to avoid unintended
-- operation due to the current instruction
ALU_Ctrl.Oper <= ALU_IDLE;
Cache_Ctrl <= CACHE_IDLE;
SP_Ctrl.Oper <= SP_IDLE;
DP_Ctrl.Src <= DATA_RD_MEM;
INT_Ctrl.Soft_Ints <= (others => '0');
-- Rewind the PC by 3 to compensate for the pipeline registers
PC_Ctrl.Oper <= PC_INCR;
PC_Ctrl.Offset <= x"FF";
CPU_Next_State <= ISR_C1;
 
end if;
end if;
801,19 → 791,10
 
end process;
 
-- We need to infer a hardware multipler, so we create a special clocked
-- process with no reset or clock enable
Multiplier_proc: process( Clock )
begin
if( rising_edge(Clock) )then
Mult <= Regfile(0) *
Regfile(conv_integer(ALU_Ctrl.Reg));
end if;
end process;
 
-------------------------------------------------------------------------------
-- Registered portion of CPU finite state machine
-------------------------------------------------------------------------------
 
CPU_Regs: process( Reset, Clock )
variable Offset_SX : ADDRESS_TYPE;
variable i_Ints : INTERRUPT_BUNDLE := (others => '0');
939,7 → 920,7
when DATA_WR_PC =>
Wr_Enable <= '1';
Wr_Data <= Program_Ctr(15 downto 8);
if( DP_Ctrl.Reg = ACCUM )then
if( DP_Ctrl.Reg = PC_LSB )then
Wr_Data <= Program_Ctr(7 downto 0);
end if;
 
954,13 → 935,6
when SP_IDLE =>
null;
 
 
-- The original RSP instruction simply reset the stack pointer to the preset
-- 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
-- the memory map. Since RSP can't have an sub-opcode, R1:R0 was chosen as
-- a fixed source
 
when SP_CLR =>
Stack_Ptr <= Stack_Start_Addr;
 
983,7 → 957,6
-------------------------------------------------------------------------------
-- The interrupt control mask is always sourced out of R0
if( INT_Ctrl.Mask_Set = '1' )then
-- If the Enable_NMI generic is set, force the LSB high
if( Enable_NMI )then
Int_Mask <= Regfile(conv_integer(ACCUM))(7 downto 1) & '1';
else
1203,4 → 1176,19
end if;
end process;
 
end architecture;
-------------------------------------------------------------------------------
-- Multiplier Logic
--
-- We need to infer a hardware multipler, so we create a special clocked
-- process with no reset or clock enable
-------------------------------------------------------------------------------
 
Multiplier_proc: process( Clock )
begin
if( rising_edge(Clock) )then
Mult <= Regfile(0) *
Regfile(conv_integer(ALU_Ctrl.Reg));
end if;
end process;
 
end architecture;
/open8_urisc/trunk/VHDL/Open8_pkg.vhd
181,6 → 181,9
Reg : SUBOP_TYPE;
end record;
 
constant PC_LSB : SUBOP_TYPE := "000";
constant PC_MSB : SUBOP_TYPE := "001";
 
type INT_CTRL_TYPE is record
Mask_Set : std_logic;
Soft_Ints : INTERRUPT_BUNDLE;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.