在RISC-V生态中,蜂鸟E203以其精简的两级流水线设计和高效的片上存储架构,成为嵌入式低功耗场景的典型代表。而连接内核与存储模块的ICB总线,则是整个SoC高效运转的神经脉络。本文将用Verilog代码还原ICB总线的valid-ready握手机制,通过ModelSim仿真波形直观展示地址区间寻址过程,帮助开发者掌握总线集成的核心要点。
ICB总线摒弃了传统AXI总线复杂的通道分离设计,采用命令-返回双通道结构实现全双工通信。这种设计在蜂鸟E203中展现出三大优势:
总线信号可分为三类核心组:
verilog复制// 命令通道
input icb_cmd_valid, // 主设备请求有效
output icb_cmd_ready, // 从设备准备就绪
input [31:0] icb_cmd_addr, // 字节地址
input icb_cmd_read, // 读=1/写=0
input [31:0] icb_cmd_wdata, // 写数据
input [3:0] icb_cmd_wmask, // 字节使能
// 返回通道
output icb_rsp_valid, // 从设备响应有效
input icb_rsp_ready, // 主设备接收就绪
output [31:0] icb_rsp_rdata, // 读数据
output icb_rsp_err // 错误标志
总线传输的核心在于valid-ready信号的同步控制。以下代码展示主设备发起写请求的典型场景:
verilog复制module icb_master (
input clk, rst_n,
output reg icb_cmd_valid,
input icb_cmd_ready,
output reg [31:0] cmd_addr,
output reg [31:0] cmd_wdata
);
typedef enum {IDLE, REQ, WAIT} state_t;
state_t state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
icb_cmd_valid <= 1'b0;
end else begin
case(state)
IDLE:
if (start_pulse) begin
cmd_addr <= 32'h8000_0000; // ITCM基地址
cmd_wdata <= 32'h1234_5678;
icb_cmd_valid <= 1'b1;
state <= REQ;
end
REQ:
if (icb_cmd_ready) begin
icb_cmd_valid <= 1'b0; // 握手成功
state <= WAIT;
end
WAIT:
if (done) state <= IDLE;
endcase
end
end
endmodule
关键时序要点:
注意:实际工程中需添加超时计数器,防止总线死锁
蜂鸟E203通过地址解码实现模块选择,典型地址映射如下:
| 地址范围 | 模块类型 | 访问特性 |
|---|---|---|
| 0x8000_0000~ | ITCM | 指令取指,只读 |
| 0x9000_0000~ | DTCM | 数据读写,支持非对齐 |
| 0xA000_0000~ | 快速IO | 无等待周期 |
| 0xC000_0000~ | 外设寄存器 | 按字节使能 |
解码逻辑的Verilog实现:
verilog复制module address_decoder (
input [31:0] addr,
output reg itcm_sel,
output reg dtcm_sel,
output reg io_sel
);
always @(*) begin
itcm_sel = (addr[31:28] == 4'h8);
dtcm_sel = (addr[31:28] == 4'h9);
io_sel = (addr[31:28] == 4'hA);
end
endmodule
波形调试技巧:
连接ITCM时需要特别注意的时序约束:
verilog复制module itcm_controller (
input clk, rst_n,
// ICB接口
input icb_cmd_valid,
output icb_cmd_ready,
input [31:0] icb_cmd_addr,
input icb_cmd_read,
output icb_rsp_valid,
input icb_rsp_ready,
output [31:0] icb_rsp_rdata
);
reg [31:0] mem [0:1023]; // 4KB ITCM
// 读延迟模型
assign icb_cmd_ready = ~fifo_full;
assign icb_rsp_valid = delay_cnt == 2;
always @(posedge clk) begin
if (icb_cmd_valid && icb_cmd_ready && icb_cmd_read)
rdata_buffer <= mem[icb_cmd_addr[11:2]]; // 字寻址
end
endmodule
关键参数优化:
当遇到非对齐访问时,总线需要分多次处理。例如对地址0x1003的32位写操作:
第一次传输:
第二次传输:
对应的异常处理代码:
verilog复制if (addr[1:0] != 2'b00) begin
icb_rsp_err <= 1'b1;
// 或者触发软件异常中断
end
在ModelSim中可通过force命令模拟此类场景:
code复制force /dut/icb_cmd_addr 32'h00001003
force /dut/icb_cmd_valid 1'b1
run 100ns