|
RT。VexRiscv使用了一种简单握手协议,一开始没搞懂,怎么都不正常,搞懂了之后马上就跑起来了。gcc编译裸bin,然后填充BlockRAM。多种配置都测过了,甚至我也尝试改demo DIY了一个RV32IC核,竟然也跑起来了!只是IPC略低于RV32I,慢了0.5%吧,面积比Smallest大了80%。
以下提供一些生成的代码(初始化向量BFC80000,中断BFC80020)。注意RegFile使用了外挂版本,因内嵌实现会造成更多的LUT浪费。目前仅能支持Spartan-6,针对7系列可能需要重写RegFile。
关于IBus和DBus的协议实现。注意grant表示指令已接受。同时使用grant信号产生读/写使能信号,以及pending信号,直到数据有效时撤销pending信号(如果请求无效)。流水线流起来之后是可以做到连续取指的。高性能版本的性能简单测试能达到最小配置的小3倍,但是面积快4倍了。想要明确的波形图请参考PULP RI5CY的手册,里面有几种典型波形。流水线流起来就长那样了。
SOC实现细节不讨论,有知识产权的。最上面10行是指令和数据缓存连接,带_pre的不用管,把另外一些信号直接挂到RAM上就可以跑了。注意wr是字节使能,RAM不要接data_addr[1:0],要做32位对齐。目前在2个系统工程里均实现了与以前的MIPS SOC无缝直接替换,替换之后变慢了一些(我用的Smallest),所有功能完全一致。除了在验证握手协议上花了2天,移植另一款产品(原本是8位AVR SOC)从头到尾共用了一天,虽说还有一堆适应性bug(8位/32位处理和转换),但是能用了。
这里设定RAM写入只需要1个周期,读需要1~N个周期。具体实现要做一些处理。原则上这个核不需要对Write操作响应。中断操作等未测试,需要时再做处理。ASM可以用标准的语法(毕竟是gcc),用.equ MEMEND,8192,la sp, .text + MEMEND,la a0,main,jalr a0之类可以顺利转到入口(我没有使用任何标准库)。
wire [31:0] w_instr_addr;
wire [31:0] w_instr_addr_pre;
wire [31:0] w_instr_data;
wire w_instr_ready;
wire [31:0] w_data_addr;
wire [31:0] w_data_rdata;
wire w_data_rd;
wire [31:0] w_data_wdata;
reg [3:0] w_data_wr;
wire w_data_ready;
wire [31:0] w_data_addr_pre;
wire w_data_wr_pre;
wire [31:0] w_data_wdata_pre;
wire [1:0] w_rv32_cpu_wrsize; // 0:byte, 1:word, 2:dword
wire w_ibus_cmd_valid, w_dbus_cmd_valid;
//////////////////////////////////////////////////////////////////////////////////
// On receive of IBus command, load new address and set pending bit. The grant bit won't set when IBus data is not ready.
reg [31:0] r_instr_addr = 0;
reg r_instr_pending_rdy = 0;
// Grant IBus when there's no pending command, or the last command is acked.
wire w_ibus_grant = (~r_instr_pending_rdy & w_ibus_cmd_valid) || (r_instr_pending_rdy & w_instr_ready & w_ibus_cmd_valid);
// Only respond to IBus command when there's pending request.
wire w_ibus_rsp_valid = r_instr_pending_rdy & w_instr_ready;
always @(posedge clk_i) begin
if(w_ibus_grant) begin
// On ibus request, grant immediately. Clear pending state when ready.
r_instr_addr <= w_instr_addr_pre;
r_instr_pending_rdy <= 1;
end else begin
// When RDY is not asserted while ibus request, the next request will be deasserted. Clear pending state when instr_ready..
if(w_instr_ready)
r_instr_pending_rdy <= 0;
else begin
end
end
end
assign w_instr_addr = {r_instr_addr[31:2], 2'b0};
//////////////////////////////////////////////////////////////////////////////////
// On receive of DBus command, load new address and set pending bit. The grant bit won't set when IBus data is not ready.
reg [31:0] r_data_addr = 0;
reg r_data_pending_rdy = 0;
// Grant DBus when there's no pending command, or the last command is acked.
wire w_dbus_grant = (~r_data_pending_rdy & w_dbus_cmd_valid) || (r_data_pending_rdy & w_data_ready & w_dbus_cmd_valid);
// Only respond to DBus command when there's pending request.
wire w_dbus_rsp_ready = r_data_pending_rdy & w_data_ready;
reg r_dbus_cmd_valid = 0;
reg r_data_wr_pre = 0;
reg [1:0] r_rv32_cpu_wrsize = 0; // 0:byte, 1:word, 2:dword
reg [31:0] r_data_wdata = 0;
always @(posedge clk_i) begin
if(w_dbus_grant) begin
// On dbus request, grant immediately. Clear pending state when ready.
r_data_addr <= w_data_addr_pre;
r_data_wr_pre <= w_data_wr_pre;
r_rv32_cpu_wrsize <= w_rv32_cpu_wrsize;
r_data_wdata <= w_data_wdata_pre;
r_data_pending_rdy <= 1;
end else begin
// Deassert WE when the command is issued.
r_data_wr_pre <= 0;
// When RDY is not asserted while dbus request, the next request will be deasserted. Clear pending state when data_ready.
if(w_data_ready)
r_data_pending_rdy <= 0;
else begin
end
end
// When a new command is granted, execute it in the next cycle. GPIO modules may have some synchronization issues and may be resolved later..
r_dbus_cmd_valid <= w_dbus_grant;
end
assign w_data_addr = {r_data_addr[31:2], 2'b0};
assign w_data_wdata = r_data_wdata;
// When dbus command valid, do read only once.
assign w_data_rd = r_dbus_cmd_valid && (~r_data_wr_pre);
// When dbus command valid, do write only once.
always @(*) begin
if(r_data_wr_pre && r_dbus_cmd_valid) begin
if(r_rv32_cpu_wrsize == 2'b10)
w_data_wr <= {4{r_data_wr_pre}};
else if(r_rv32_cpu_wrsize == 2'b01) begin
w_data_wr[1:0] <= (r_data_addr[1] == 0) ? {2{r_data_wr_pre}} : 2'b00;
w_data_wr[3:2] <= (r_data_addr[1] == 1) ? {2{r_data_wr_pre}} : 2'b00;
end else begin
w_data_wr[0] <= (r_data_addr[1:0] == 2'b00) && r_data_wr_pre;
w_data_wr[1] <= (r_data_addr[1:0] == 2'b01) && r_data_wr_pre;
w_data_wr[2] <= (r_data_addr[1:0] == 2'b10) && r_data_wr_pre;
w_data_wr[3] <= (r_data_addr[1:0] == 2'b11) && r_data_wr_pre;
end
end else
w_data_wr <= 4'b0000;
end
//////////////////////////////////////////////////////////////////////////////////
// Processor
VexRiscv_GenSmallestNoCsr rv32_cpu (
.iBus_cmd_valid (w_ibus_cmd_valid),
.iBus_cmd_ready (w_ibus_grant),
.iBus_cmd_payload_pc (w_instr_addr_pre),
.iBus_rsp_valid (w_ibus_rsp_valid),
.iBus_rsp_payload_error (0),
.iBus_rsp_payload_inst (w_instr_data),
//.timerInterrupt (0),
//.externalInterrupt (0),
//.debugReset (0),
//.debug_bus_cmd_valid (0),
//.debug_bus_cmd_ready (),
//.debug_bus_cmd_payload_wr (0),
//.debug_bus_cmd_payload_address(0),
//.debug_bus_cmd_payload_data (0),
//.debug_bus_rsp_data (),
//.debug_resetOut (),
.dBus_cmd_valid (w_dbus_cmd_valid),
.dBus_cmd_ready (w_dbus_grant),
.dBus_cmd_payload_wr (w_data_wr_pre),
.dBus_cmd_payload_address (w_data_addr_pre),
.dBus_cmd_payload_data (w_data_wdata_pre),
.dBus_cmd_payload_size (w_rv32_cpu_wrsize),
.dBus_rsp_ready (w_dbus_rsp_ready),
.dBus_rsp_error (0),
.dBus_rsp_data (w_data_rdata),
.clk (clk_i),
.reset (r_soc_rst[0])
);
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
|