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; |