2014-01-06 92 views
0

我正在学习在Xilinx(VHDL)上编写代码。接下来,我想制作一个简单的微处理器/微控制器,并在途中学习一些关于切片组件的知识。所以我的目标是尝试使用AMD 2901(4位片)对8位微处理器进行编码。 (我已经有了2901的代码以及它的输入和输出信号的所有信息。)VHDL微处理器/微控制器

我知道第一步是使微处理器的架构,所以我最终得到了类似的东西(我明白总线的带宽将与我所寻找的有很大不同)。

http://www.cs.binghamton.edu/~reckert/wk15fig1.JPG (基本上所有我知道的微处理器和微控制器我把它从这里http://www.cs.binghamton.edu/~reckert/hardwire3new.html

因此,这里是准时的问题:

  1. 如何编写一个中央总线像图表现?我如何使用中央大巴士(如图)“听”和“写”我的记忆和组件?

  2. 我想使用2901 ALU(其中两个),所以我有一个8位微处理器。问题是:假设我的操作码正在使用xxxxx001(其中x是控制信号,001表示为ALU添加),因此对于ALU上的添加功能,因为我有一个slice ALU,因此我的操作码应为xxxxx001001指令给两个ALU?或者应该ALU共享相同的“001”命令? (我想这可以知道如何使用VHDL中的总线,使两个端口“听”或什么)

  3. 如果您可以与我分享一些教程或链接的信息,可以帮助我与我的目标那会很棒。我搜查了很多,发现了很少的信息。

回答

3

这个答案是关于你的问题的第三部分。

您可能会发现看看the MCPU project是有用的。这是一个采用77行VHDL代码的8位CPU。由于作者将整个设计压缩为32个宏单元,因此在某些地方代码有点棘手,但the design document有帮助。

我也创建了一个针对代码可读性的重构版本,这个版本包含在下面。请注意,我不是该项目的原创作者 - 所有的荣誉都归TimBöscke所有。

library ieee; 
use ieee.std_logic_1164.all; 
use ieee.std_logic_unsigned.all; 

entity mcpu is 
    port (
     data_bus: inout std_logic_vector(7 downto 0); 
     address: out std_logic_vector(5 downto 0); 
     n_oe: out std_logic; 
     -- Asynchronous memory interface 
     n_we: out std_logic;  
     n_reset: in std_logic; 
     clock: in std_logic 
    ); 
end; 

architecture refactored of mcpu is 
    signal accumulator: std_logic_vector(8 downto 0); 
    alias carry is accumulator(8); 
    alias result is accumulator(7 downto 0); 
    alias opcode is data_bus(7 downto 6); 

    signal address_register: std_logic_vector(5 downto 0); 
    signal pc: std_logic_vector(5 downto 0); 
    signal states: std_logic_vector(2 downto 0); 

    type cpu_state_type is (FETCH, WRITE, ALU_ADD, ALU_NOR, BRANCH_NOT_TAKEN); 
    signal cpu_state: cpu_state_type; 

    type state_encoding_type is array (cpu_state_type) of std_logic_vector(2 downto 0); 
    constant STATE_ENCODING: state_encoding_type := (
     FETCH => "000", 
     WRITE => "001", 
     ALU_ADD => "010", 
     ALU_NOR => "011", 
     BRANCH_NOT_TAKEN => "101" 
); 

begin 
    process (clock, n_reset) 
    begin 
     if not n_reset then 
      -- start execution at memory location 0 
      address_register <= (others => '0'); 
      states <= "000"; 
      cpu_state <= FETCH; 
      accumulator <= (others => '0'); 
      pc <= (others => '0'); 
     elsif rising_edge(clock) then 

      -- PC/Adress path 
      if cpu_state = FETCH then 
       pc <= address_register + 1; 
       address_register <= data_bus(5 downto 0); 
      else 
       address_register <= pc; 
      end if; 

      -- ALU/Data Path 
      case cpu_state is 
       when ALU_ADD => 
        accumulator <= ('0' & result) + ('0' & data_bus); 
       when ALU_NOR => 
        result <= result nor data_bus; 
       when BRANCH_NOT_TAKEN => 
        carry <= '0'; 
       when others => null; 
      end case; 

      -- State machine 
      if cpu_state /= FETCH then 
       cpu_state <= FETCH; 
      elsif opcode ?= "11" and carry then 
       cpu_state <= BRANCH_NOT_TAKEN; 
      else 
       states <= "0" & not opcode;  -- execute instruction 
       case opcode is 
        when "00" => cpu_state <= ALU_NOR; -- 011 
        when "01" => cpu_state <= ALU_ADD; -- 010      
        when "10" => cpu_state <= WRITE; -- 001 
        when "11" => cpu_state <= FETCH; -- 000 
        when others => null;      
       end case; 
      end if; 
     end if; 
    end process; 

    -- output 
    address <= address_register;  
    data_bus <= result when (cpu_state = WRITE) else (others => 'Z'); 

    -- output enable is active low, asserted only when 
    -- rst=1, clk=0, and state!=001(wr_acc) and state!=101(read_pc) 
    n_oe <= '1' when (clock='1' or cpu_state = WRITE or n_reset = '0' or cpu_state = BRANCH_NOT_TAKEN) else '0'; 

    -- write enable is active low, asserted only when 
    -- rst=1, clk=0, and state=001(wr_acc) 
    n_we <= '1' when (clock = '1' or cpu_state /= WRITE or n_reset = '0') else '0'; 

end;