wye11083 发表于 2019-1-30 23:45:59

来点干货,把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:08

不知所云,楼主那个行业的?

jackjiao 发表于 2019-1-31 10:48:41

看着很牛逼,不知道是啥,学习下

dragonlands 发表于 2019-1-31 11:07:21

厉害了,中国芯靠你了!

dreampet 发表于 2019-1-31 12:58:48

liyang121316 发表于 2019-1-31 10:41
不知所云,楼主那个行业的?

通俗的讲,楼主是用FPGA实现了一个单片机, 现在把单片机的内核升级成了开源的RISC-V内核

dreampet 发表于 2019-1-31 13:03:26

楼主有没有考虑过用 SpinalHDL 这个语言? 基于Scala的语法,更加的抽象了

wye11083 发表于 2019-1-31 13:22:15

dreampet 发表于 2019-1-31 13:03
楼主有没有考虑过用 SpinalHDL 这个语言? 基于Scala的语法,更加的抽象了

学习中。有优点也有缺点,但代码密度提升很显著。

aozima 发表于 2019-1-31 15:27:02

给楼主点赞

flyfox8 发表于 2019-1-31 20:13:26

虽然不懂,但感觉很厉害的样子。

neqee 发表于 2019-1-31 21:12:19

楼主是在做笔记

abutter 发表于 2019-8-22 15:20:26

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)
}

阿胆开工了 发表于 2020-3-28 22:38:59

楼主的BSP是自己开发的吗?可以可以讲一下BSP开发和软件debug

wye11083 发表于 2020-3-29 04:02:27

阿胆开工了 发表于 2020-3-28 22:38
楼主的BSP是自己开发的吗?可以可以讲一下BSP开发和软件debug

没有bsp,因为CPU没有需要配置的地方。只要写一下SP,GP就可以用了。主要是为了简单,而不是为了通用,因此data初始化也是单独写的一个init()函数,asm先jalr _init,再jalr _main。

hxl_led 发表于 2020-3-29 07:44:10

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
请网友指点一二

abutter 发表于 2020-3-29 17:07:27

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 ...

能贴一下具体的错误信息吗?或者简单的工程?

Eworm001 发表于 2020-9-15 16:58:43

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]
查看完整版本: 来点干货,把VexRiscv调通了,正在全面迁移到RV32平台中。