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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [VHDL/] [o8_cpu.vhd] - Diff between revs 10 and 151

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 10 Rev 151
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

powered by: WebSVN 2.1.0

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