接口信号
PicoRV32 提供一个本地存储器接口,Native Memory Interface。
本地存储器接口采用 valid-ready握手信号。这种机制在axi总线中使用相同,能够实现流控,
和axi总线不同点,PicoRV32本地接口使用一组valid-ready信号,而axi总线使用多个通道,每个通道有一组valid-ready信号。
PicoRV本地接口有如下信号
output mem_valid
output mem_instr
input mem_ready
output [31:0] mem_addr
output [31:0] mem_wdata
output [ 3:0] mem_wstrb
input [31:0] mem_rdata
mem_valid :当PicoRV进行一次存储读写时候,mem_valid有效,直到mem_ready有效。当这次传输是读取cpu执行指令的时候,mem_instr有效。
mem_instr:为高表示此次传输是获取指令;为低表示此次传输是获取数据
mem_ready:当从设备准备接收和发送数据的时候,置为有效。从设备也可直接给高
mem_addr : 读取存储器的地址
mem_wdata: PicoRV32写向存储器的数据
mem_wstrb:写信号,每1bit对应的mem_wdata中的8bit,在字节写,字写中有用。只可选下列值:
4'b1111 : 32bit写
4'b1100:高16bit写
4'b0011:低16bit写
4'b1000:字节写
4'b0100:字节写
4'b0010:字节写
4'b0001:字节写
4'b0000:32bit读
mem_rdata : 读数据,外设发给PicoRV32数据
读数据传输
PicoRV32在读数据时候,mem_wstrb必须为4'b0000,此时PicoRV32未使用mem_wdata信号;
读地址在mem_addr上出现,当mem_ready为高的时候,必须把读数据放到mem_rdata数据线上。mem_ready可以做成异步信号.下图官方文档中仿真波形
上图中红色框选部分是两次读操作。
怎么确定是读还是写?
看mem_wstrb信号,如果mem_wstrb信号为4'b0000,则为读,其它值为写。
怎么确定是读指令还是读数据?
看mem_instr信号,高为读指令,低为读数据,显然第一框选为读数据,第二框选为读指令。
怎么确定读地址?
看mem_valid为高时刻,mem_addr的数据,第一框选地址为0x0000ABD4,第二框选地址为0x000009A8。
怎么确定读数据?
看mem_ready信号为高时刻,mem_rdata的数据,第一框选为0x6c6c6568,第二框选为0x05058082
数据在哪里被锁存?
看mem_ready,mem_valid同时为高,并且时钟上升沿出现时刻。
写数据传输
PicoRV32在写数据时候,mem_wstrb不为4'b0000,此时PicoRV32未使用mem_rdata信号;
写地址在mem_addr上出现,当mem_ready为高的时候,PicoRV32写数据放到mem_wdata数据线上。mem_ready可以做成异步信号,也可以直接给高电平.下图官方文档中仿真波形
怎么确定是读还是写?
看mem_wstrb信号,如果mem_wstrb信号为4'b0000,则为读,其它值为写。图中mem_wstrb为4'hf,表示32bit写
怎么确定是指令还是数据?
看mem_instr信号,高为指令,低为数据,显然图中为数据。指令只存在读,不存在写,所以写只针对写数据。
怎么确定写地址?
看mem_valid为高时刻,mem_addr的数据,图中写地址为0x10000000
怎么确定写数据?
看mem_valid信号为高时刻,mem_wdata的数据,图中数据为0x00000062
数据在哪里被锁存?
看mem_ready,mem_valid同时为高,并且时钟上升沿出现时刻。图中红色箭头指向的沿
简单从设备实现
上述说了这么多,怎么实现一个从设备,代码如下:
wire iomem_valid;
reg iomem_ready;
wire [3:0] iomem_wstrb;
wire [31:0] iomem_addr;
wire [31:0] iomem_wdata;
reg [31:0] iomem_rdata;
reg [31:0] gpio;
assign leds = gpio;
always @(posedge clk) begin
if (!resetn) begin
gpio <= 0;
end else begin
iomem_ready <= 0;
if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) begin
iomem_ready <= 1;
iomem_rdata <= gpio;
if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0];
if (iomem_wstrb[1]) gpio[15: 8] <= iomem_wdata[15: 8];
if (iomem_wstrb[2]) gpio[23:16] <= iomem_wdata[23:16];
if (iomem_wstrb[3]) gpio[31:24] <= iomem_wdata[31:24];
end
end
end
图中iomem_xxx 对应PicoRV32 mem_xxx信号
上述代码中实现一个简单led。这个led有一个32bit的寄存器 (reg [31:0] gpio),主要对这个寄存器进行读写。
地址选中 iomem_addr[31:24] == 8'h03,表示当地址为 32'h03xx_xxxx都是操作这个寄存器。
当iomem_valid有效,表示PicoRV32有读写操作发过来,如果iomem_ready为低把gpio值放到iomem_rdata上,如果iomem_wstrb有值则把对应的iomem_wdata写到gpio寄存器