外部设备的基础配置

为了让我们的 CPU 能够真正发挥功能,我们需要为开发板进行外设的适配。

更改 CPU 的组织结构

CPU 对外部设备的控制是通过写入(SW)和读取(LW)外设中的数据存储器来实现的。我们需要将外部设备和 CPU 独立开来,将时钟信号 clk 和复位信号 rst 通过一个公共的顶层模块同时引线连接在 CPU 和外部设备上面。

对于 VGA 显示来说,就是一个专有的时钟信号 clk_65m(下一节进行配置)以及 VGA 的输出引脚:

  • 横向刷新率 hs
  • 纵向刷新率 vs
  • 红色 r
  • 绿色 g
  • 蓝色 b

以及必要的存储访问引脚(类似于数据存储器 Data Memory):

  • 写使能信号:wen
  • 写入数据:wire[31:0] wdata
  • 目标地址:wire[3:0] addr
  • 读取数据:wire rdata

这样,我们再引入一个统一的顶层模块 soc,用来连接 CPU 和外设。那么,我们连接 VGA 的代码大致如下:

vga u_vga(
  .clk   (clk       ),
  .rstn  (~rst      ),
  .wen   (vga_wen   ),
  .wdata (vga_wdata ),
  .addr  (vga_addr  ),
  .rdata (vga_rdata ),
  .hs    (hs        ),
  .vs    (vs        ),
  .red   (red       ),
  .green (green     ),
  .blue  (blue      )
);

连接 CPU 的代码大致如下:

zanpu_top u_zanpu_top(
  .clk      (clk      ),
  .rst      (rst      ),
  .io_wen   (io_wen   ),
  .io_addr  (io_addr  ),
  .io_wdata (io_wdata ),
  .io_rdata (io_rdata )
);

同时,如果想要在开发板上面有相应的输入,我们需要在 soc 上面加上一个输入信号:

input wire[3:0] btn_key

可以看到,对于顶层模块 soc 来说,输入信号有:

  • 时钟信号:clk
  • 复位信号:rst
  • 按键:wire[3:0] btn_key

输出信号包括 VGA 的必要输出:

output wire      hs,
output wire      vs,
output wire[3:0] red,
output wire[3:0] green,
output wire[3:0] blue

通过规定目标写入地址范围(利用掩码进行划分),我们可以控制 CPU 的 SW 指令向正确的目标数据存储器(写入自己 CPU 的数据存储器还是外设的数据存储器)写入对应的数据。同样,我们也可也通过掩码来规定读入目标地址范围,来判断读取按键对应存储器还是外设存储器的数据。具体代码实现如下:

  • 读取按键数据存储器地址或外设(VGA)数据存储器地址(soc.v):

    assign io_rdata = (io_addr[31:6] == 26'b1111_1111_1111_1111_0000_0000_00) ? vga_rdata : {27'b0, btn_key_t};
    
  • 写入 CPU 数据存储器地址或外设(VGA)数据存储器地址(zanpu_top.v

    wire access_io = (alu_result_out[31:16] == 16'hffff) ? 1'b1 : 1'b0;
    wire[31:0] dm_rdata;
    wire dm_wen;
    assign io_wen = (access_io && en_mem_write_mem);
    assign dm_wen = (access_io == 1'b0 && en_mem_write_mem);
    
    assign read_mem_data = (access_io == 1'b1) ? io_rdata : dm_rdata;
    

接下来,我们以 VGA 为例子进行外设接口的实现。

Last Updated: 9/15/2019, 6:12:07 AM