⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpu.vhd

📁 risc5x源代码。介绍了一般微处理器核的设计原理、基本概念和方法.
💻 VHD
📖 第 1 页 / 共 2 页
字号:
    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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -