来点干货,把VexRiscv调通了,正在全面迁移到RV32平台中。
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,要做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 w_instr_addr;
wire w_instr_addr_pre;
wire w_instr_data;
wire w_instr_ready;
wire w_data_addr;
wire w_data_rdata;
wire w_data_rd;
wire w_data_wdata;
reg w_data_wr;
wire w_data_ready;
wire w_data_addr_pre;
wire w_data_wr_pre;
wire w_data_wdata_pre;
wire 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 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, 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 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 r_rv32_cpu_wrsize = 0; // 0:byte, 1:word, 2:dword
reg 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, 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 <= (r_data_addr == 0) ? {2{r_data_wr_pre}} : 2'b00;
w_data_wr <= (r_data_addr == 1) ? {2{r_data_wr_pre}} : 2'b00;
end else begin
w_data_wr <= (r_data_addr == 2'b00) && r_data_wr_pre;
w_data_wr <= (r_data_addr == 2'b01) && r_data_wr_pre;
w_data_wr <= (r_data_addr == 2'b10) && r_data_wr_pre;
w_data_wr <= (r_data_addr == 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)
);
不知所云,楼主那个行业的? 看着很牛逼,不知道是啥,学习下 厉害了,中国芯靠你了! liyang121316 发表于 2019-1-31 10:41
不知所云,楼主那个行业的?
通俗的讲,楼主是用FPGA实现了一个单片机, 现在把单片机的内核升级成了开源的RISC-V内核 楼主有没有考虑过用 SpinalHDL 这个语言? 基于Scala的语法,更加的抽象了 dreampet 发表于 2019-1-31 13:03
楼主有没有考虑过用 SpinalHDL 这个语言? 基于Scala的语法,更加的抽象了
学习中。有优点也有缺点,但代码密度提升很显著。 给楼主点赞 虽然不懂,但感觉很厉害的样子。 楼主是在做笔记 package misc.modncounter
import spinal.core._
case class ModNCounter(limit: Int) extends Component {
val io = new Bundle {
val clear = in Bool
val tick = out Bool
}
val counter = Reg(UInt(log2Up(limit) bits)) init (0)
when(io.clear) {
counter := 0
} elsewhen (counter === U(limit)) {
counter := 0
} otherwise {
counter := counter + 1
}
io.tick := counter === U(limit)
} 楼主的BSP是自己开发的吗?可以可以讲一下BSP开发和软件debug 阿胆开工了 发表于 2020-3-28 22:38
楼主的BSP是自己开发的吗?可以可以讲一下BSP开发和软件debug
没有bsp,因为CPU没有需要配置的地方。只要写一下SP,GP就可以用了。主要是为了简单,而不是为了通用,因此data初始化也是单独写的一个init()函数,asm先jalr _init,再jalr _main。 abutter 发表于 2019-8-22 15:20
package misc.modncounter
import spinal.core._
val rs1_r= Reg( UInt(32 bits))
val rs2_r= Reg( UInt(32 bits))
if( rs1_r=== rs2_r) { lb_class_o := True}
这样比较可以吗,编译时提示type mismatch
请网友指点一二
hxl_led 发表于 2020-3-29 07:44
val rs1_r= Reg( UInt(32 bits))
val rs2_r= Reg( UInt(32 bits))
if( rs1_r=== rs2_r ...
能贴一下具体的错误信息吗?或者简单的工程? hxl_led 发表于 2020-3-29 07:44
val rs1_r= Reg( UInt(32 bits))
val rs2_r= Reg( UInt(32 bits))
if( rs1_r=== rs2_r ...
if 改为 when
页:
[1]