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

Subversion Repositories risc5x

[/] [risc5x/] [trunk/] [cpu.vhd] - Diff between revs 2 and 3

Show entire file | Details | Blame | View Log

Rev 2 Rev 3
Line 1... Line 1...
 
--
 
-- Risc5x
 
-- www.OpenCores.Org - November 2001
 
--
 
--
 
-- This library is free software; you can distribute it and/or modify it
 
-- under the terms of the GNU Lesser General Public License as published
 
-- by the Free Software Foundation; either version 2.1 of the License, or
 
-- (at your option) any later version.
 
--
 
-- This library is distributed in the hope that it will be useful, but
 
-- WITHOUT ANY WARRANTY; without even the implied warranty of
 
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
-- See the GNU Lesser General Public License for more details.
 
--
 
-- A RISC CPU core.
 
--
 
-- (c) Mike Johnson 2001. All Rights Reserved.
 
-- mikej@opencores.org for support or any other issues.
 
--
 
-- Revision list
 
--
 
-- version 1.1 bug fix: Used wrong bank select bits in direct addressing mode
 
--                      INDF register returns 0 when indirectly read
 
--                      FSR bit 8 always set
 
-- version 1.0 initial opencores release
 
--
 
 
 
use work.pkg_risc5x.all;
 
use work.pkg_prims.all;
 
library ieee;
 
  use ieee.std_logic_1164.all;
 
  use ieee.std_logic_arith.all;
 
  use ieee.std_logic_unsigned.all;
 
 
 
entity CPU is
 
  port (
 
    PADDR           : out std_logic_vector(10 downto 0);
 
    PDATA           : in  std_logic_vector(11 downto 0);
 
 
 
    PORTA_IN        : in    std_logic_vector(7 downto 0);
 
    PORTA_OUT       : out   std_logic_vector(7 downto 0);
 
    PORTA_OE_L      : out   std_logic_vector(7 downto 0);
 
 
 
    PORTB_IN        : in    std_logic_vector(7 downto 0);
 
    PORTB_OUT       : out   std_logic_vector(7 downto 0);
 
    PORTB_OE_L      : out   std_logic_vector(7 downto 0);
 
 
 
    PORTC_IN        : in    std_logic_vector(7 downto 0);
 
    PORTC_OUT       : out   std_logic_vector(7 downto 0);
 
    PORTC_OE_L      : out   std_logic_vector(7 downto 0);
 
 
 
    DEBUG_W         : out std_logic_vector(7 downto 0);
 
    DEBUG_PC        : out std_logic_vector(10 downto 0);
 
    DEBUG_INST      : out std_logic_vector(11 downto 0);
 
    DEBUG_STATUS    : out std_logic_vector(7 downto 0);
 
 
 
    RESET           : in  std_logic;
 
    CLK             : in  std_logic
 
    );
 
end;
 
 
 
architecture RTL of CPU is
 
 
 
-- component definitions
 
 
 
component IDEC is
 
  port (
 
    INST                : in  std_logic_vector(11 downto 0);
 
 
 
    ALU_ASEL            : out std_logic_vector(1 downto 0);
 
    ALU_BSEL            : out std_logic_vector(1 downto 0);
 
    ALU_ADDSUB          : out std_logic_vector(1 downto 0);
 
    ALU_BIT             : out std_logic_vector(1 downto 0);
 
    ALU_SEL             : out std_logic_vector(1 downto 0);
 
 
 
    WWE_OP              : out std_logic;
 
    FWE_OP              : out std_logic;
 
 
 
    ZWE                 : out std_logic;
 
    DCWE                : out std_logic;
 
    CWE                 : out std_logic;
 
    BDPOL               : out std_logic;
 
    OPTION              : out std_logic;
 
    TRIS                : out std_logic
 
    );
 
end component;
 
 
 
component ALU is
 
  port (
 
    ADDSUB          : in  std_logic_vector(1 downto 0);
 
    BIT             : in  std_logic_vector(1 downto 0);
 
    SEL             : in  std_logic_vector(1 downto 0);
 
 
 
    A               : in  std_logic_vector(7 downto 0);
 
    B               : in  std_logic_vector(7 downto 0);
 
    Y               : out std_logic_vector(7 downto 0);
 
    CIN             : in  std_logic;
 
    COUT            : out std_logic;
 
    DCOUT           : out std_logic;
 
    ZOUT            : out std_logic
 
    );
 
end component;
 
 
 
component REGS is
 
  port (
 
    WE              : in  std_logic;
 
    RE              : in  std_logic;
 
    BANK            : in  std_logic_vector(1 downto 0);
 
    LOCATION        : in  std_logic_vector(4 downto 0);
 
    DIN             : in  std_logic_vector(7 downto 0);
 
    DOUT            : out std_logic_vector(7 downto 0);
 
    RESET           : in  std_logic;
 
    CLK             : in  std_logic
 
    );
 
end component;
 
 
 
-- type/constant definitions
 
  constant STATUS_RESET_VALUE : std_logic_vector(7 downto 0) := x"18";
 
  constant OPTION_RESET_VALUE : std_logic_vector(7 downto 0) := x"3F";
 
  constant INDF_ADDR     : std_logic_vector(2 downto 0) := "000";
 
  constant TMR0_ADDR     : std_logic_vector(2 downto 0) := "001";
 
  constant PCL_ADDR      : std_logic_vector(2 downto 0) := "010";
 
  constant STATUS_ADDR   : std_logic_vector(2 downto 0) := "011";
 
  constant FSR_ADDR      : std_logic_vector(2 downto 0) := "100";
 
  constant PORTA_ADDR    : std_logic_vector(2 downto 0) := "101";
 
  constant PORTB_ADDR    : std_logic_vector(2 downto 0) := "110";
 
  constant PORTC_ADDR    : std_logic_vector(2 downto 0) := "111";
 
 
 
-- signal definitions
 
  signal inst                           : std_logic_vector(11 downto 0);
 
 
 
  signal inst_k                         : std_logic_vector(7 downto 0);
 
  signal inst_fsel                      : std_logic_vector(4 downto 0);
 
  signal inst_d                         : std_logic;
 
  signal inst_b                         : std_logic_vector(2 downto 0);
 
 
 
  signal pc,next_pc                     : std_logic_vector(10 downto 0);
 
  signal pc_load_stack                  : std_logic_vector(10 downto 0);
 
  signal pc_write                       : std_logic_vector(10 downto 0);
 
  signal pc_call                        : std_logic_vector(10 downto 0);
 
  signal pc_goto                        : std_logic_vector(10 downto 0);
 
  signal pc_load                        : std_logic_vector(10 downto 0);
 
  signal pc_load_sel                    : std_logic_vector(1 downto 0);
 
  signal pc_inc                         : std_logic;
 
 
 
  signal stacklevel                     : std_logic_vector(1 downto 0);
 
  signal stack1,stack2                  : std_logic_vector(10 downto 0);
 
  signal w_reg,status,fsr,tmr0          : std_logic_vector(7 downto 0);
 
  signal prescaler,option               : std_logic_vector(7 downto 0);
 
  signal trisa,trisb,trisc              : std_logic_vector(7 downto 0);
 
 
 
  signal porta_dout                     : std_logic_vector(7 downto 0);
 
  signal portb_dout                     : std_logic_vector(7 downto 0);
 
  signal portc_dout                     : std_logic_vector(7 downto 0);
 
 
 
  signal porta_din                      : std_logic_vector(7 downto 0);
 
  signal portb_din                      : std_logic_vector(7 downto 0);
 
  signal portc_din                      : std_logic_vector(7 downto 0);
 
 
 
  signal dbus,sbus                      : std_logic_vector(7 downto 0);
 
  signal sbus_swap                      : std_logic_vector(7 downto 0);
 
  signal sbus_mux_out                   : std_logic_vector(7 downto 0);
 
 
 
  -- inst decode
 
  signal regfile_sel,special_sel        : std_logic;
 
  signal fileaddr_indirect              : std_logic;
 
  signal fileaddr_mux1                  : std_logic_vector(6 downto 0);
 
  signal fileaddr_mux0                  : std_logic_vector(6 downto 0);
 
 
 
  signal istris,isoption                : std_logic;
 
  signal fwe,wwe,zwe,dcwe,cwe           : std_logic;
 
  signal bdpol                          : std_logic;
 
  signal bd                             : std_logic_vector(7 downto 0);
 
  signal skip                           : std_logic;
 
 
 
  -- alu
 
  signal alu_asel,alu_bsel              : std_logic_vector(1 downto 0) := (others => '0');
 
  signal alu_addsub                     : std_logic_vector(1 downto 0) := (others => '0');
 
  signal alu_bit                        : std_logic_vector(1 downto 0) := (others => '0');
 
  signal alu_sel                        : std_logic_vector(1 downto 0) := (others => '0');
 
 
 
  signal alu_z,alu_dcout,alu_cout       : std_logic := '0';
 
  signal alu_a,alu_b                    : std_logic_vector(7 downto 0) := (others => '0');
 
  signal alu_out                        : std_logic_vector(7 downto 0);
 
 
 
  signal regfile_we,regfile_re          : std_logic;
 
  signal regfile_in,regfile_out         : std_logic_vector(7 downto 0);
 
  signal fileaddr                       : std_logic_vector(6 downto 0);
 
 
 
begin -- architecture
 
 
 
  u_idec : IDEC
 
    port map (
 
      INST                => inst,
 
 
 
      ALU_ASEL            => alu_asel,
 
      ALU_BSEL            => alu_bsel,
 
      ALU_ADDSUB          => alu_addsub,
 
      ALU_BIT             => alu_bit,
 
      ALU_SEL             => alu_sel,
 
 
 
      WWE_OP              => wwe,
 
      FWE_OP              => fwe,
 
 
 
      ZWE                 => zwe,
 
      DCWE                => dcwe,
 
      CWE                 => cwe,
 
      BDPOL               => bdpol,
 
      OPTION              => isoption,
 
      TRIS                => istris
 
      );
 
 
 
  u_alu : ALU
 
    port map (
 
      ADDSUB          => alu_addsub,
 
      BIT             => alu_bit,
 
      SEL             => alu_sel,
 
 
 
      A               => alu_a,
 
      B               => alu_b,
 
      Y               => alu_out,
 
      CIN             => status(0),
 
      COUT            => alu_cout,
 
      DCOUT           => alu_dcout,
 
      ZOUT            => alu_z
 
      );
 
 
 
  u_regs : REGS
 
    port map (
 
      WE              => regfile_we,
 
      RE              => regfile_re,
 
      BANK            => fileaddr(6 downto 5),
 
      LOCATION        => fileaddr(4 downto 0),
 
      DIN             => regfile_in,
 
      DOUT            => regfile_out,
 
      RESET           => RESET,
 
      CLK             => CLK
 
      );
 
 
 
  DEBUG_W <= w_reg;
 
  DEBUG_PC <= pc(10 downto 0);
 
  DEBUG_INST <= inst;
 
  DEBUG_STATUS <= status;
 
 
 
  -- *********** REGISTER FILE Addressing ****************
 
  p_addr_dec_comb : process(inst_fsel,fsr)
 
  begin
 
    if (inst_fsel = ("00" & INDF_ADDR)) then
 
      fileaddr_indirect <= '1';
 
    else
 
      fileaddr_indirect <= '0';
 
    end if;
 
 
 
    fileaddr_mux1 <= fsr(6 downto 0);
 
    fileaddr_mux0 <= (fsr(6 downto 5) & inst_fsel);
 
  end process;
 
 
 
  fileaddr_mux : MUX2
 
    generic map (
 
      WIDTH         => 7,
 
      SLICE         => 1,
 
      OP_REG        => FALSE
 
      )
 
    port map (
 
      DIN1          => fileaddr_mux1,
 
      DIN0          => fileaddr_mux0,
 
 
 
      SEL           => fileaddr_indirect,
 
      ENA           => '0', -- not used
 
      CLK           => '0', -- not used
 
 
 
      DOUT          => fileaddr
 
      );
 
 
 
  p_regfile_we_comb : process(regfile_sel,fwe,alu_asel,alu_bsel)
 
  begin
 
    regfile_we <= regfile_sel and fwe;
 
    regfile_re <= '1'; -- not used
 
  end process;
 
 
 
  p_fileaddr_dec_comb : process(fileaddr,isoption,istris)
 
  begin
 
    regfile_sel <= '1'; -- everything else;
 
    special_sel <= '0';
 
    if (fileaddr(4 downto 3) = "00") and (isoption = '0') and (istris = '0') then
 
      special_sel <= '1';  -- lower 8 addresses in ALL BANKS 1 lut
 
    end if;
 
  end process;
 
 
 
  sbus_muxa : MUX8
 
    generic map (
 
      WIDTH         => 8,
 
      OP_REG        => FALSE
 
      )
 
    port map (
 
      DIN7          => portc_din,
 
      DIN6          => portb_din,
 
      DIN5          => porta_din,
 
      DIN4          => fsr,
 
      DIN3          => status,
 
      DIN2          => pc(7 downto 0),
 
      DIN1          => tmr0,
 
      DIN0          => x"00", -- INDF returns 0
 
 
 
      SEL           => inst_fsel(2 downto 0),
 
      ENA           => '0',
 
      CLK           => '0',
 
 
 
      DOUT          => sbus_mux_out
 
      );
 
 
 
  sbus_muxb : MUX2
 
    generic map (
 
      WIDTH         => 8,
 
      SLICE         => 1,
 
      OP_REG        => FALSE
 
      )
 
    port map (
 
      DIN1          => sbus_mux_out,
 
      DIN0          => regfile_out,
 
 
 
      SEL           => special_sel,
 
      ENA           => '0',
 
      CLK           => '0',
 
 
 
      DOUT          => sbus
 
      );
 
 
 
  p_dbus_comb : process(alu_out)
 
  begin
 
    dbus <= alu_out;
 
    regfile_in <= alu_out;
 
  end process;
 
 
 
  p_paddr_comb : process(next_pc)
 
  begin
 
     PADDR <= next_pc(10 downto 0);
 
  end process;
 
 
 
  p_inst_assign_comb : process(inst)
 
  begin
 
    inst_k    <= inst(7 downto 0);
 
    inst_fsel <= inst(4 downto 0);
 
    inst_d    <= inst(5);
 
    inst_b    <= inst(7 downto 5);
 
  end process;
 
 
 
  p_bdec_assign_comb : process(inst_b,bdpol)
 
  variable bdec : std_logic_vector(7 downto 0);
 
  begin
 
    -- 1 lut
 
    bdec := "00000001";
 
    case inst_b is
 
      when "000" => bdec := "00000001";
 
      when "001" => bdec := "00000010";
 
      when "010" => bdec := "00000100";
 
      when "011" => bdec := "00001000";
 
      when "100" => bdec := "00010000";
 
      when "101" => bdec := "00100000";
 
      when "110" => bdec := "01000000";
 
      when "111" => bdec := "10000000";
 
      when others => null;
 
    end case;
 
    if (bdpol = '1') then
 
      bd <= not bdec;
 
    else
 
      bd <=     bdec;
 
    end if;
 
  end process;
 
 
 
  p_inst : process(CLK,RESET)
 
  begin
 
    if (RESET = '1') then
 
      inst <= x"000";
 
    elsif CLK'event and (CLK = '1') then
 
      if (skip = '1')  then
 
        inst <= x"000"; -- force NOP
 
      else
 
        inst <= PDATA;
 
      end if;
 
    end if;
 
  end process;
 
 
 
  p_skip_comb : process(inst,alu_z,fwe,special_sel,fileaddr)
 
  begin
 
    -- SKIP signal.
 
    -- We want to insert the NOP instruction for the following conditions:
 
    --    we have modified PCL
 
    --    GOTO,CALL and RETLW instructions
 
    --    BTFSS instruction when aluz is HI
 
    --    BTFSC instruction when aluz is LO
 
   skip <= '0';
 
 
 
    if (fwe = '1') and (special_sel = '1') and (fileaddr(2 downto 0) = PCL_ADDR) then skip <= '1'; end if;
 
    if (inst(11 downto 10) = "10") then skip <= '1'; end if;
 
    if (inst(11 downto  8) = "0110") and (alu_z = '1') then skip <= '1'; end if; -- BTFSC
 
    if (inst(11 downto  8) = "0111") and (alu_z = '0') then skip <= '1'; end if; -- BTFSS
 
    if (inst(11 downto  6) = "001011") and (alu_z = '1') then skip <= '1'; end if; -- DECFSZ
 
    if (inst(11 downto  6) = "001111") and (alu_z = '1') then skip <= '1'; end if; -- INCFSZ
 
  end process;
 
 
 
  sbus_swap <= sbus(3 downto 0) & sbus(7 downto 4);
 
 
 
  alua_mux : MUX4
 
    generic map (
 
      WIDTH         => 8,
 
      SLICE         => 1,
 
      OP_REG        => FALSE
 
      )
 
    port map (
 
      DIN3          => sbus_swap,
 
      DIN2          => inst_k,
 
      DIN1          => sbus,
 
      DIN0          => w_reg,
 
 
 
      SEL           => alu_asel,
 
      ENA           => '0',
 
      CLK           => '0',
 
 
 
      DOUT          => alu_a
 
      );
 
 
 
  alub_mux : MUX4
 
    generic map (
 
      WIDTH         => 8,
 
      SLICE         => 0,
 
      OP_REG        => FALSE
 
      )
 
    port map (
 
      DIN3          => x"01",
 
      DIN2          => bd,
 
      DIN1          => sbus,
 
      DIN0          => w_reg,
 
 
 
      SEL           => alu_bsel,
 
      ENA           => '0',
 
      CLK           => '0',
 
 
 
      DOUT          => alu_b
 
      );
 
 
 
  p_w_reg : process(CLK,RESET)
 
  begin
 
    if (RESET = '1') then
 
      w_reg <= x"00";
 
    elsif CLK'event and (CLK = '1') then
 
      if (wwe = '1')  then
 
        w_reg <= dbus;
 
      end if;
 
    end if;
 
  end process;
 
 
 
  p_tmr0 : process(CLK,RESET)
 
    variable mask : std_logic_vector(7 downto 0);
 
  begin
 
    if (RESET = '1') then
 
      tmr0 <= x"00";
 
    elsif CLK'event and (CLK = '1') then
 
      -- See if the timer register is actually being written to
 
      if (fwe = '1') and (special_sel = '1') and (fileaddr(2 downto 0) = TMR0_ADDR) then
 
        tmr0 <= dbus;
 
      else
 
        mask := "00000001";
 
        case option(2 downto 0) is
 
          when "000" => mask := "00000001";
 
          when "001" => mask := "00000011";
 
          when "010" => mask := "00000111";
 
          when "011" => mask := "00001111";
 
          when "100" => mask := "00011111";
 
          when "101" => mask := "00111111";
 
          when "110" => mask := "01111111";
 
          when "111" => mask := "11111111";
 
          when others => null;
 
        end case;
 
        if ((prescaler and mask) = "00000000") or (option(3) = '1') then
 
          tmr0 <= tmr0 + "1";
 
        end if;
 
      end if;
 
    end if;
 
  end process;
 
 
 
  p_prescaler : process(CLK,RESET)
 
  begin
 
    if (RESET = '1') then
 
      prescaler <= x"00";
 
    elsif CLK'event and (CLK = '1') then
 
      if not (option(5) = '1') then
 
        prescaler <= prescaler + "1";
 
      end if;
 
    end if;
 
  end process;
 
 
 
  p_status_reg : process(CLK,RESET)
 
    variable new_z,new_dc,new_c : std_logic;
 
  begin
 
    if (RESET = '1') then
 
      status <= STATUS_RESET_VALUE;
 
    elsif CLK'event and (CLK = '1') then
 
      -- See if the status register is actually being written to
 
      -- this is not accurate, bits 4 & 3 should be read only
 
      -- additionally, zwe,cwe and dcwe should override fwe
 
 
 
      if (fwe = '1') and (special_sel = '1') and (fileaddr(2 downto 0) = STATUS_ADDR) then
 
        status <= dbus;
 
      else
 
      -- For the carry and zero flags, each instruction has its own rule as
 
      -- to whether to update this flag or not.  The instruction decoder is
 
      -- providing us with an enable for C and Z.  Use this to decide whether
 
      -- to retain the existing value, or update with the new alu status output.
 
         if (zwe = '1') then new_z := alu_z; else new_z := status(2); end if;
 
         if (dcwe = '1') then new_dc := alu_dcout; else new_dc := status(1); end if;
 
         if (cwe = '1') then new_c := alu_cout; else new_c := status(0); end if;
 
         status <= (
 
              status(7) &                  -- BIT 7: Undefined.. (maybe use for debugging)
 
              status(6) &                  -- BIT 6: Program Page, HI bit
 
              status(5) &                  -- BIT 5: Program Page, LO bit
 
              status(4) &                  -- BIT 4: Time Out bit (not implemented at this time)
 
              status(3) &                  -- BIT 3: Power Down bit (not implemented at this time)
 
              new_z     &                  -- BIT 2: Z
 
              new_dc    &                  -- BIT 1: DC
 
              new_c);                      -- BIT 0: C
 
       end if;
 
    end if;
 
  end process;
 
 
 
  p_fsr_reg : process(CLK,RESET)
 
  begin
 
    if (RESET = '1') then
 
      fsr <= x"80";
 
    elsif CLK'event and (CLK = '1') then
 
      if (fwe = '1') and (special_sel = '1') and (fileaddr(2 downto 0) = FSR_ADDR) then
 
        fsr <= dbus;
 
      end if;
 
      fsr(7) <= '1'; --always set in real chip
 
    end if;
 
  end process;
 
 
 
  p_option_reg : process(CLK,RESET)
 
  begin
 
    if (RESET = '1') then
 
      option <= OPTION_RESET_VALUE;
 
    elsif CLK'event and (CLK = '1') then
 
      if (isoption = '1') then
 
        option <= dbus;
 
      end if;
 
    end if;
 
  end process;
 
 
 
  p_drive_ports_comb : process(porta_dout,trisa,portb_dout,trisb,portc_dout,trisc)
 
  begin
 
      PORTA_OE_L <= trisa;
 
      PORTB_OE_L <= trisb;
 
      PORTC_OE_L <= trisc;
 
 
 
      PORTA_OUT <= porta_dout;
 
      PORTB_OUT <= portb_dout;
 
      PORTC_OUT <= portc_dout;
 
 
 
  end process;
 
 
 
  port_in : process(CLK,RESET,PORTA_IN,PORTB_IN,PORTC_IN)
 
    begin
 
    -- the input registers don't exist in the real device,
 
    -- so if you read an output we have introduced a clock delay.
 
      if (RESET = '1') then
 
        porta_din <= (others => '0');
 
        portb_din <= (others => '0');
 
        portc_din <= (others => '0');
 
      elsif CLK'event and (CLK = '1') then -- comment this out for combinatorial ip
 
      --else                               -- or comment this for registered ip
 
        porta_din <= PORTA_IN;
 
        portb_din <= PORTB_IN;
 
        portc_din <= PORTC_IN;
 
      end if;
 
  end process;
 
 
 
  p_port_reg : process(CLK,RESET)
 
  begin
 
    if (RESET = '1') then
 
      trisa <= x"FF"; -- default tristate
 
      trisb <= x"FF"; -- default tristate
 
      trisc <= x"FF"; -- default tristate
 
      porta_dout <= x"00";
 
      portb_dout <= x"00";
 
      portc_dout <= x"00";
 
    elsif CLK'event and (CLK = '1') then
 
 
 
      if (fwe = '1') and (fileaddr(2 downto 0) = PORTA_ADDR) then
 
        if (istris = '0') and (special_sel = '1') then
 
          porta_dout <= dbus;
 
        elsif (istris = '1') then
 
          trisa <= dbus;
 
        end if;
 
      end if;
 
 
 
      if (fwe = '1') and (fileaddr(2 downto 0) = PORTB_ADDR) then
 
        if (istris = '0') and (special_sel = '1') then
 
          portb_dout <= dbus;
 
        elsif (istris = '1') then
 
          trisb <= dbus;
 
        end if;
 
      end if;
 
 
 
      if (fwe = '1') and (fileaddr(2 downto 0) = PORTC_ADDR) then
 
        if (istris = '0') and (special_sel = '1') then
 
          portc_dout <= dbus;
 
        elsif (istris = '1') then
 
          trisc <= dbus;
 
        end if;
 
      end if;
 
    end if;
 
  end process;
 
 
 
  -- ********** PC AND STACK *************************
 
 
 
  p_next_pc_comb : process(pc,inst,status,stacklevel,stack1,stack2,dbus,fileaddr,special_sel,fwe)
 
  begin
 
 
 
    pc_goto  <= ( status(6 downto 5) &       inst(8 downto 0));
 
    pc_call  <= ( status(6 downto 5) & '0' & inst(7 downto 0));
 
    pc_write <= (pc(10) & '0' & pc(8) & dbus);          -- set bit 9 to zero
 
 
 
    pc_inc <= '1'; -- default
 
 
 
    pc_load_sel <= "00"; -- pc write
 
    if (fwe = '1') and (special_sel = '1') and (fileaddr(2 downto 0) = PCL_ADDR) then
 
      --pc_load_sel <= "00";  default
 
      pc_inc <= '0';  -- as we have modified next_pc, must skip next instruction
 
    end if;
 
 
 
    if (inst(11 downto 9) = "101")  then pc_load_sel <= "01"; pc_inc <= '0'; end if; -- goto
 
    if (inst(11 downto 8) = "1001") then pc_load_sel <= "10"; pc_inc <= '0'; end if; -- call
 
    if (inst(11 downto 8) = "1000") then pc_load_sel <= "11"; pc_inc <= '0'; end if; -- ret
 
 
 
  end process;
 
 
 
  pc_load_mux : MUX4
 
    generic map (
 
      WIDTH         => 11,
 
      SLICE         => 0,
 
      OP_REG        => FALSE
 
      )
 
    port map (
 
      DIN3          => pc_load_stack,
 
      DIN2          => pc_call,
 
      DIN1          => pc_goto,
 
      DIN0          => pc_write,
 
 
 
      SEL           => pc_load_sel,
 
      ENA           => '0',
 
      CLK           => '0',
 
 
 
      DOUT          => pc_load
 
      );
 
 
 
  pc_mux2_add_reg : MUX2_ADD_REG
 
    generic map (
 
      WIDTH         => 11
 
      )
 
    port map (
 
      ADD_VAL       => "00000000001",  -- pc = pc + 1
 
      LOAD_VAL      => pc_load, -- branch
 
 
 
      ADD           => pc_inc,
 
 
 
      PRESET        => RESET,
 
      ENA           => '1',
 
      CLK           => CLK,
 
 
 
      DOUT          => next_pc,
 
      REG_DOUT      => pc
 
      );
 
 
 
  p_stack_comb : process(stacklevel,stack1,stack2)
 
  begin
 
    pc_load_stack <= stack1; -- default
 
    case stacklevel is
 
      when "00" => pc_load_stack <= stack1;
 
      when "01" => pc_load_stack <= stack1;
 
      when "10" => pc_load_stack <= stack2;
 
      when "11" => pc_load_stack <= stack2;
 
      when others => null;
 
    end case;
 
  end process;
 
 
 
  p_stack_reg : process(CLK,RESET)
 
  begin
 
    if (RESET = '1') then
 
      stack1 <= (others => '0');
 
      stack2 <= (others => '0');
 
    elsif CLK'event and (CLK = '1') then
 
      if (inst(11 downto 8) = "1001") then
 
        case stacklevel is
 
          when "00" => stack1 <= pc(10 downto 0);
 
          when "01" => stack2 <= pc(10 downto 0);
 
          when "10" => assert false report "Too many CALLs !" severity failure;
 
          when "11" => assert false report "Too many CALLs !" severity failure;
 
          when others => null;
 
        end case;
 
      end if;
 
    end if;
 
  end process;
 
 
 
  p_stack_level : process(CLK,RESET)
 
  begin
 
    if (RESET = '1') then
 
      stacklevel <= "00";
 
    elsif CLK'event and (CLK = '1') then
 
      stacklevel <= stacklevel;
 
      if (inst(11 downto 8) = "1001") then
 
        case stacklevel is
 
          when "00" => stacklevel <="01"; -- 1st call
 
          when "01" => stacklevel <="10"; -- 2nd call
 
          when "10" => stacklevel <="10"; -- already 2, ignore
 
          when "11" => stacklevel <="00"; -- broke
 
          when others => null;
 
        end case;
 
      elsif (inst(11 downto 8) = "1000") then
 
        case stacklevel is
 
          when "00" => stacklevel <="00"; -- broke
 
          when "01" => stacklevel <="00"; -- go back to no call
 
          when "10" => stacklevel <="01"; -- go back to 1 call
 
          when "11" => stacklevel <="10"; -- broke
 
          when others => null;
 
        end case;
 
      end if;
 
    end if;
 
  end process;
 
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.