搜索
bottom↓
回复: 15

来点干货,把VexRiscv调通了,正在全面迁移到RV32平台中。

[复制链接]

出0入442汤圆

发表于 2019-1-30 23:45:59 | 显示全部楼层 |阅读模式
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来反美的!

出0入42汤圆

发表于 2019-1-31 10:41:08 | 显示全部楼层
不知所云,楼主那个行业的?

出0入0汤圆

发表于 2019-1-31 10:48:41 | 显示全部楼层
看着很牛逼,不知道是啥,学习下

出150入640汤圆

发表于 2019-1-31 11:07:21 | 显示全部楼层
厉害了,中国芯靠你了!

出0入147汤圆

发表于 2019-1-31 12:58:48 | 显示全部楼层
liyang121316 发表于 2019-1-31 10:41
不知所云,楼主那个行业的?

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

出0入147汤圆

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

出0入442汤圆

 楼主| 发表于 2019-1-31 13:22:15 来自手机 | 显示全部楼层
dreampet 发表于 2019-1-31 13:03
楼主有没有考虑过用 SpinalHDL 这个语言? 基于Scala的语法,更加的抽象了

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

出0入0汤圆

发表于 2019-1-31 15:27:02 | 显示全部楼层
给楼主点赞

出0入4汤圆

发表于 2019-1-31 20:13:26 来自手机 | 显示全部楼层
虽然不懂,但感觉很厉害的样子。

出150入135汤圆

发表于 2019-1-31 21:12:19 来自手机 | 显示全部楼层
楼主是在做笔记

出0入12汤圆

发表于 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)
}

出0入0汤圆

发表于 2020-3-28 22:38:59 | 显示全部楼层
楼主的BSP是自己开发的吗?可以可以讲一下BSP开发和软件debug

出0入442汤圆

 楼主| 发表于 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。

出0入25汤圆

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

出0入12汤圆

发表于 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 ...

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

出0入0汤圆

发表于 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
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 14:18

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表