Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[分享]Verilog代码接入到Difftest #9

Open
YouTheFreedom1999 opened this issue Jul 23, 2021 · 26 comments
Open

[分享]Verilog代码接入到Difftest #9

YouTheFreedom1999 opened this issue Jul 23, 2021 · 26 comments
Labels
#Difftest Difftest 相关问题 #Verilog Verilog 相关问题 知识分享 该issue的主题是信息、知识分享

Comments

@YouTheFreedom1999
Copy link

YouTheFreedom1999 commented Jul 23, 2021

前言

昨天看到有老哥写了Chisel的difftest接入,心血来潮想试试Verilog怎么接入。
一定要参考Chisel的difftest接入DiffTest Usge这两篇,我算是一点点补充
水平有限,请各位多多指教。

TOP文件

首先我们要在difftest的上一层建立一个build文件夹,并新建一个 SimTop.v 并将下列内容写入,这个文件就是整个RTL仿真设计的顶层。
还要将CPU的所有RTL文件放入。(也可以考虑用 make install 自动copy)

module SimTop(
    input         clock,
    input         reset,

    input  [63:0] io_logCtrl_log_begin,
    input  [63:0] io_logCtrl_log_end,
    input  [63:0] io_logCtrl_log_level,
    input         io_perfInfo_clean,
    input         io_perfInfo_dump,

    output        io_uart_out_valid,
    output [7:0]  io_uart_out_ch,
    output        io_uart_in_valid,
    input  [7:0]  io_uart_in_ch
  // ......
);

endmodule

RAM的接入

对于DiffTest框架,提供了一块申请的8GB内存在路径,在difftest/src/test/csrc/common/ram.h中定义了仿真内存的大小,也提供了对应的读写函数,Verilog通过DPI-C的方式访问读写函数完成对仿真内存的读写,代码在difftest/src/test/vsrc/common/ram.v
下面提供的RAMHelper好像只有一读一写,而在没有Cache的情况下,没有办法让取指和访存同时访问这块内存(我在想可不可以上升取指下降访存来过渡),于是我重写了一个有一写两读的RAM模块。
其中指令端口通过一个MUX将64位数据对齐到了32位。inst_addr右移3位是因为CPU内部是以字节编址,而仿真内存是以8字节编址,MUX的选择信号是右移出去三位数据的最高位,来选择64位中的高32位/低32位。
数据的读写也是按照4字节对齐,为了适应仿真内存也要做相应的映射,详情见下述代码

module RAM_1W2R(
    input clk,
    
    input [`BUS_WIDTH]inst_addr,
    input inst_ena,
    output [31:0]inst,

    // DATA PORT
    input ram_wr_en,
    input ram_rd_en,
    input [`BUS_WIDTH]ram_wmask,
    input [`BUS_WIDTH]ram_addr,
    input [`BUS_WIDTH]ram_wr_data,
    output reg [`BUS_WIDTH]ram_rd_data
);

    // INST PORT

    wire[`BUS_WIDTH] inst_2 = ram_read_helper(inst_ena,{3'b000,(inst_addr-64'h0000_0000_8000_0000)>>3});

    assign inst = inst_addr[2] ? inst_2[63:32] : inst_2[31:0];

    // DATA PORT 
    assign ram_rd_data = ram_read_helper(ram_rd_en, {3'b000,(ram_addr-64'h0000_0000_8000_0000)>>3});

    always @(posedge clk) begin
        ram_write_helper((ram_addr-64'h0000_0000_8000_0000)>>3, ram_wr_data, ram_wmask, ram_wr_en);
    end

endmodule

将此模块实例化到 SimTop.v 中并且将端口接入到自己设计的CPU中,这样就完成了,RAM的接入

指令的提交

Difftest通过,DifftestInstrCommit这个模块来将信号提交到DiffTest中。

module DifftestInstrCommit(InstrCommit)(
  input        clock,  // 时钟
  input [ 7:0] coreid, // 处理器核ID,多处理器有用,默认为0即可
  input [ 7:0] index,  
  input        valid,  // 提交有效信号,只有为高电平时提交才有效
  input [63:0] pc,     // PC指针的值
  input [31:0] instr,  // 对应的指令
  input        skip,   // 是否跳过此条对比
  input        isRVC,  // 是否为压缩指令
  input        scFailed,
  input        wen,    // 写回寄存器使能
  input [ 7:0] wdest,  // 写回寄存器的地址
  input [63:0] wdata   // 写回的数据
);

将需要提交的信号链接,记住手册里的一句话,在指令提交的时刻其产生的影响恰好生效

  reg r_wen;
  reg [7:0]r_wdest;
  reg [`BUS_WIDTH]r_wdata,r_pc;
  reg [31:0]r_inst;
  reg vaild;

  always @(posedge clock) begin
    if(reset)begin
      r_wen     <= 'd0;
      r_wdest   <= 'd0;
      r_wdata   <= 'd0;
      r_pc      <= 'd0;
      r_inst    <= 'd0;
      vaild     <= 'd0;
    end else begin
      r_wen     <= u_riscvcpu.regs_wr_en   ; // 这里面的u_riscvcpu 是cpu核的例化名
      r_wdest   <= {3'd0,u_riscvcpu.regs_wr_addr};
      r_wdata   <= u_riscvcpu.regs_wr_data;
      r_pc      <= {inst_addr[63:32],1'b1,inst_addr[30:0]};
      r_inst    <= inst;
      vaild     <= 1'b1;
    end
  end

DifftestInstrCommit U_inst_commit(
  .clock    ( clock ),
  .coreid   ( 8'd0 ),//8bit
  .index    ( 8'd0 ),//8bit
  .valid    ( vaild ),
  .pc       ( r_pc ),//64bit
  .instr    ( r_inst ),//32bit
  .skip     ( 1'b0 ),
  .isRVC    ( 1'b0 ),
  .scFailed ( 1'b0 ),
  .wen      ( r_wen    ),
  .wdest    ( r_wdest ),//8bit
  .wdata    ( r_wdata ) //64bit
);

REGFILE的提交

对应模块名为DifftestArchIntRegState,类似的方法接入

module DifftestArchIntRegState (
  input         clock,
  input [ 7:0]  coreid,
  input [63:0]  gpr_0,
  input [63:0]  gpr_1,
  input [63:0]  gpr_2,
  input [63:0]  gpr_3,
  input [63:0]  gpr_4,
  input [63:0]  gpr_5,
  input [63:0]  gpr_6,
  input [63:0]  gpr_7,
  input [63:0]  gpr_8,
  input [63:0]  gpr_9,
  input [63:0]  gpr_10,
  input [63:0]  gpr_11,
  input [63:0]  gpr_12,
  input [63:0]  gpr_13,
  input [63:0]  gpr_14,
  input [63:0]  gpr_15,
  input [63:0]  gpr_16,
  input [63:0]  gpr_17,
  input [63:0]  gpr_18,
  input [63:0]  gpr_19,
  input [63:0]  gpr_20,
  input [63:0]  gpr_21,
  input [63:0]  gpr_22,
  input [63:0]  gpr_23,
  input [63:0]  gpr_24,
  input [63:0]  gpr_25,
  input [63:0]  gpr_26,
  input [63:0]  gpr_27,
  input [63:0]  gpr_28,
  input [63:0]  gpr_29,
  input [63:0]  gpr_30,
  input [63:0]  gpr_31
);

编译运行

然后就可以编译emu

make -C difftest emu

运行difftest

./build/emu -i ../am-kernels/tests/cpu-tests/build/add-riscv64-mycpu.bin

根据日志可以看到已经捕获到错误的信息

Emu compiled at Jul 23 2021, 22:43:12
The image is /opt/RISCV/am-kernels/tests/cpu-tests/build/add-riscv64-mycpu.bin
Using simulated 8192MB RAM
[warning] sdcard img not found
--diff is not given, try to use $(NEMU_HOME)/build/riscv64-nemu-interpreter-so by default
Using /opt/RISCV/NEMU/build/riscv64-nemu-interpreter-so for difftest
[src/device/io/mmio.c,13,add_mmio_map] Add mmio map 'clint' at [0xa2000000, 0xa200ffff]
[src/device/io/mmio.c,13,add_mmio_map] Add mmio map 'sdhci' at [0xa3000000, 0xa300007f]
[src/device/sdcard.c,118,init_sdcard] Can not find sdcard image: /home/yzh/projectn/debian.img
pc:0000000080000000 instr:00000413 wen:1 wdest:  8 wdata:0000000000000000
The first instruction of core 0 has commited. Difftest enabled.
pc:0000000080000004 instr:00009117 wen:1 wdest:  2 wdata:0000000000009004

============== Commit Group Trace (Core 0) ==============
commit group [0]: pc 0080000000 cmtcnt 1
commit group [1]: pc 0080000004 cmtcnt 1 <--
commit group [2]: pc 0000000000 cmtcnt 0
commit group [3]: pc 0000000000 cmtcnt 0
commit group [4]: pc 0000000000 cmtcnt 0
commit group [5]: pc 0000000000 cmtcnt 0
commit group [6]: pc 0000000000 cmtcnt 0
commit group [7]: pc 0000000000 cmtcnt 0
commit group [8]: pc 0000000000 cmtcnt 0
commit group [9]: pc 0000000000 cmtcnt 0
commit group [a]: pc 0000000000 cmtcnt 0
commit group [b]: pc 0000000000 cmtcnt 0
commit group [c]: pc 0000000000 cmtcnt 0
commit group [d]: pc 0000000000 cmtcnt 0
commit group [e]: pc 0000000000 cmtcnt 0
commit group [f]: pc 0000000000 cmtcnt 0

============== Commit Instr Trace ==============
commit inst [0]: pc 0080000000 inst 00000413 wen 1 dst 00000008 data 0000000000000000
commit inst [1]: pc 0080000004 inst 00009117 wen 1 dst 00000002 data 0000000000009004 <--
commit inst [2]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [3]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [4]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [5]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [6]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [7]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [8]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [9]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [a]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [b]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [c]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [d]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [e]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000
commit inst [f]: pc 0000000000 inst 00000000 wen 0 dst 00000000 data 0000000000000000

==============  REF Regs  ==============
  $0: 0x0000000000000000   ra: 0x0000000000000000   sp: 0x0000000080009004   gp: 0x0000000000000000
  tp: 0x0000000000000000   t0: 0x0000000000000000   t1: 0x0000000000000000   t2: 0x0000000000000000
  s0: 0x0000000000000000   s1: 0x0000000000000000   a0: 0x0000000000000000   a1: 0x0000000000000000
  a2: 0x0000000000000000   a3: 0x0000000000000000   a4: 0x0000000000000000   a5: 0x0000000000000000
  a6: 0x0000000000000000   a7: 0x0000000000000000   s2: 0x0000000000000000   s3: 0x0000000000000000
  s4: 0x0000000000000000   s5: 0x0000000000000000   s6: 0x0000000000000000   s7: 0x0000000000000000
  s8: 0x0000000000000000   s9: 0x0000000000000000  s10: 0x0000000000000000  s11: 0x0000000000000000
  t3: 0x0000000000000000   t4: 0x0000000000000000   t5: 0x0000000000000000   t6: 0x0000000000000000
 ft0: 0x0000000000000000  ft1: 0x0000000000000000  ft2: 0x0000000000000000  ft3: 0x0000000000000000
 ft4: 0x0000000000000000  ft5: 0x0000000000000000  ft6: 0x0000000000000000  ft7: 0x0000000000000000
 fs0: 0x0000000000000000  fs1: 0x0000000000000000  fa0: 0x0000000000000000  fa1: 0x0000000000000000
 fa2: 0x0000000000000000  fa3: 0x0000000000000000  fa4: 0x0000000000000000  fa5: 0x0000000000000000
 fa6: 0x0000000000000000  fa7: 0x0000000000000000  fs2: 0x0000000000000000  fs3: 0x0000000000000000
 fs4: 0x0000000000000000  fs5: 0x0000000000000000  fs6: 0x0000000000000000  fs7: 0x0000000000000000
 fs8: 0x0000000000000000  fs9: 0x0000000000000000 fs10: 0x0000000000000000 fs11: 0x0000000000000000
 ft8: 0x0000000000000000  ft9: 0x0000000000000000 ft10: 0x0000000000000000 ft11: 0x0000000000000000
pc: 0x0000000080000008 mstatus: 0x0000000000000000 mcause: 0x0000000000000000 mepc: 0x0000000000000000
                       sstatus: 0x0000000000000000 scause: 0x0000000000000000 sepc: 0x0000000000000000
satp: 0x0000000000000000
mip: 0x0000000000000000 mie: 0x0000000000000000 mscratch: 0x0000000000000000 sscratch: 0x0000000000000000
mideleg: 0x0000000000000000 medeleg: 0x0000000000000000
mtval: 0x0000000000000000 stval: 0x0000000000000000mtvec: 0x0000000000000000 stvec: 0x0000000000000000
priviledgeMode: 0
     sp different at pc = 0x0080000004, right= 0x0000000080009004, wrong = 0x0000000000009004
Core 0: ABORT at pc = 0x2913c2304813023
total guest instructions = 0
instrCnt = 0, cycleCnt = 0, IPC = -nan
Seed=0 Guest cycle spent: 3 (this will be different from cycleCnt if emu loads a snapshot)
Host time spent: 10ms

Tips:
将Difftest的Makefile中clean:vcs-clean下面的一行改成

rm -rf $(filter-out $(wildcard $(BUILD_DIR)/*.v), $(wildcard $(BUILD_DIR)/*))

可以在执行make clean时不删除RTL代码

@zhangyx1998 zhangyx1998 added #Difftest Difftest 相关问题 #Verilog Verilog 相关问题 知识分享 该issue的主题是信息、知识分享 labels Jul 24, 2021
@lsyic
Copy link

lsyic commented Jul 25, 2021

大佬你好,请问是要在SimTop.v中融合原cpu中顶层.v,还是在SimTop.v中调用原顶层.v呢?

@YouTheFreedom1999
Copy link
Author

大佬你好,请问是要在SimTop.v中融合原cpu中顶层.v,还是在SimTop.v中调用原顶层.v呢?

都可以,只要能把提交信息的端口连到相应的模块就行

@lhx6355
Copy link

lhx6355 commented Jul 26, 2021

你好,请问“在指令提交的时刻其产生的影响恰好生效”,是不是要求需要实现流水线结构?

@cxxuser
Copy link

cxxuser commented Jul 27, 2021

想请问一下这里的CPU的所有RTL文件,指的是什么?是define.v,if_stage.v之类的文件吗?

@lsyic
Copy link

lsyic commented Jul 27, 2021

想请问一下这里的CPU的所有RTL文件,指的是什么?是define.v,if_stage.v之类的文件吗?

我理解是的。要把自己所有的CPU代码接入进来。

@tuuyii
Copy link

tuuyii commented Jul 28, 2021

你好,请问您这个教程中接入的CPU是单周期的吗?

@vx-zzy
Copy link

vx-zzy commented Aug 2, 2021

你好,请问这个地方为什么是写入一半数据呢
wire [BUS_WIDTH]wr_data = {mem_wr_data[31:0],mem_rd_data[63:32]};`
谢谢

@YouTheFreedom1999
Copy link
Author

你好,请问您这个教程中接入的CPU是单周期的吗?

是的,流水线的提交也是类似的

@YouTheFreedom1999
Copy link
Author

你好,请问这个地方为什么是写入一半数据呢
wire [BUS_WIDTH]wr_data = {mem_wr_data[31:0],mem_rd_data[63:32]};`
谢谢

不好意思,可能给你造成了一些误解,这个是我测试sw ld 时为了让地址对齐临时写的,我在上面已经更新代码了,我把掩码的处理和数据的对仿真内存的适应放到了一个单独的模块(只针对difftest中的仿真内存有效)。

module mem_ctrl(
    input rst,

    // CPU端接口
    input [7:0]mem_byte_enble,
    input [`BUS_WIDTH]mem_addr,
    input mem_rd_en,
    input mem_wr_en,
    input [`BUS_WIDTH]mem_wr_data,
    output reg [`BUS_WIDTH]mem_rd_data,

    // 内存接口
    output  [`BUS_WIDTH]ram_addr,
    output  ram_wr_en,
    output reg  [`BUS_WIDTH]ram_wmask,
    output reg  [`BUS_WIDTH]ram_wr_data,
    output  ram_rd_en,
    input    [`BUS_WIDTH]ram_rd_data
);  

    reg [`BUS_WIDTH] sb_ram_wmask   ;
    reg [`BUS_WIDTH] sb_ram_wr_data ;
    reg [`BUS_WIDTH] sh_ram_wmask   ;
    reg [`BUS_WIDTH] sh_ram_wr_data ;
    reg [`BUS_WIDTH] sw_ram_wmask   ;
    reg [`BUS_WIDTH] sw_ram_wr_data ;
    reg [`BUS_WIDTH] sd_ram_wmask   ;
    reg [`BUS_WIDTH] sd_ram_wr_data ;

    reg [`BUS_WIDTH] lb_ram_rd_data ;
    reg [`BUS_WIDTH] lh_ram_rd_data ;
    reg [`BUS_WIDTH] lw_ram_rd_data ;
    reg [`BUS_WIDTH] ld_ram_rd_data ;

    assign ram_addr = mem_addr;
    assign ram_wr_en = rst ? 0 : mem_wr_en;
    assign ram_rd_en = rst ? 0 : mem_rd_en;

    wire sb_signal = mem_wr_en & (mem_byte_enble == 8'b0000_0001);
    wire sh_signal = mem_wr_en & (mem_byte_enble == 8'b0000_0011);
    wire sw_signal = mem_wr_en & (mem_byte_enble == 8'b0000_1111);
    wire sd_signal = mem_wr_en & (mem_byte_enble == 8'b1111_1111);

    wire lb_signal = mem_rd_en & (mem_byte_enble == 8'b0000_0001);
    wire lh_signal = mem_rd_en & (mem_byte_enble == 8'b0000_0011);
    wire lw_signal = mem_rd_en & (mem_byte_enble == 8'b0000_1111);
    wire ld_signal = mem_rd_en & (mem_byte_enble == 8'b1111_1111);

    // 写MUX
    always @(*) begin
        if(rst)begin
            ram_wmask   = `ZERO_WORD;
            ram_wr_data = `ZERO_WORD;
        end 
        else if(sb_signal)begin
            ram_wmask   = sb_ram_wmask  ;
            ram_wr_data = sb_ram_wr_data;
        end 
        else if(sh_signal)begin
            ram_wmask   = sh_ram_wmask  ;
            ram_wr_data = sh_ram_wr_data;
        end
        else if(sw_signal)begin
            ram_wmask   = sw_ram_wmask  ;
            ram_wr_data = sw_ram_wr_data;           
        end
        else if(sd_signal)begin
            ram_wmask   = sd_ram_wmask  ;
            ram_wr_data = sd_ram_wr_data;        
        end
        else begin
            ram_wmask   = `ZERO_WORD;
            ram_wr_data = `ZERO_WORD;
        end
    end

    // 读MUX
    always @(*) begin
        if(rst)
            mem_rd_data = `ZERO_WORD;
        else if(lb_signal)
            mem_rd_data = lb_ram_rd_data;
        else if(lh_signal)
            mem_rd_data = lh_ram_rd_data;
        else if(lw_signal)
            mem_rd_data = lw_ram_rd_data;
        else if(ld_signal)
            mem_rd_data = ld_ram_rd_data;
        else
            mem_rd_data = `ZERO_WORD;
    end

    // 写字节的处理
    always @(sb_signal or mem_addr[2:0] or mem_wr_data[7:0]) begin
        if(sb_signal)begin
            case(mem_addr[2:0])
                3'd0:begin 
                    sb_ram_wmask   = 64'h0000_0000_0000_00FF;
                    sb_ram_wr_data = {56'd0,mem_wr_data[7:0]};
                end
                3'd1:begin 
                    sb_ram_wmask   = 64'h0000_0000_0000_FF00;
                    sb_ram_wr_data = {48'd0,mem_wr_data[7:0],8'd0};
                end
                3'd2:begin 
                    sb_ram_wmask   = 64'h0000_0000_00FF_0000;
                    sb_ram_wr_data = {40'd0,mem_wr_data[7:0],16'd0};
                end
                3'd3:begin 
                    sb_ram_wmask   = 64'h0000_0000_FF00_0000;
                    sb_ram_wr_data = {32'd0,mem_wr_data[7:0],24'd0};
                end
                3'd4:begin 
                    sb_ram_wmask   = 64'h0000_00FF_0000_0000;
                    sb_ram_wr_data = {24'd0,mem_wr_data[7:0],32'd0};
                end
                3'd5:begin 
                    sb_ram_wmask   = 64'h0000_FF00_0000_0000;
                    sb_ram_wr_data = {16'd0,mem_wr_data[7:0],40'd0};
                end
                3'd6:begin 
                    sb_ram_wmask   = 64'h00FF_0000_0000_0000;
                    sb_ram_wr_data = {8'd0,mem_wr_data[7:0],48'd0};
                end
                3'd7:begin 
                    sb_ram_wmask   = 64'hFF00_0000_0000_0000;
                    sb_ram_wr_data = {mem_wr_data[7:0],56'd0};
                end
            endcase
        end
        else begin
            sb_ram_wmask   = `ZERO_WORD;
            sb_ram_wr_data = `ZERO_WORD;
        end
    end

    // 写双字的处理
    always @(sh_signal or mem_addr[2:1] or mem_wr_data[15:0]) begin
        if(sh_signal)begin
            case(mem_addr[2:1])
                2'd0:begin  
                    sh_ram_wmask   = 64'h0000_0000_0000_FFFF;
                    sh_ram_wr_data = {48'd0,mem_wr_data[15:0]};
                end
                2'd1:begin  
                    sh_ram_wmask   = 64'h0000_0000_FFFF_0000;
                    sh_ram_wr_data = {32'd0,mem_wr_data[15:0],16'd0};
                end
                2'd2:begin  
                    sh_ram_wmask   = 64'h0000_FFFF_0000_0000;
                    sh_ram_wr_data = {16'd0,mem_wr_data[15:0],32'd0};
                end
                2'd3:begin  
                    sh_ram_wmask   = 64'hFFFF_0000_0000_0000;
                    sh_ram_wr_data = {mem_wr_data[15:0],48'd0};
                end
            endcase
        end
        else begin
            sh_ram_wmask   = `ZERO_WORD;
            sh_ram_wr_data = `ZERO_WORD;
        end
    end

    // 4字节写
    always @(sw_signal or mem_addr[2] or mem_wr_data[31:0]) begin
        if(sw_signal)begin
            case(mem_addr[2])
                1'b0:begin  
                    sw_ram_wmask   = 64'h0000_0000_FFFF_FFFF;
                    sw_ram_wr_data = {32'd0,mem_wr_data[31:0]};
                end
                1'b1:begin  
                    sw_ram_wmask   = 64'hFFFF_FFFF_0000_0000;
                    sw_ram_wr_data = {mem_wr_data[31:0],32'd0};
                end
            endcase
        end
        else begin
            sw_ram_wmask   = `ZERO_WORD;
            sw_ram_wr_data = `ZERO_WORD;
        end
    end

    // 8字节写
    always @(sd_signal or mem_wr_data) begin
        if(sd_signal) begin
            sd_ram_wmask   = 64'hFFFF_FFFF_FFFF_FFFF;
            sd_ram_wr_data = mem_wr_data;
        end
        else begin
            sd_ram_wmask   = `ZERO_WORD;
            sd_ram_wr_data = `ZERO_WORD;
        end
    end
    

    // 读字节处理
    always @(lb_signal or mem_addr[2:0] or ram_rd_data) begin
        if(lb_signal)
            case(mem_addr[2:0])
                3'd0:lb_ram_rd_data = {56'd0,ram_rd_data[ 7: 0]};
                3'd1:lb_ram_rd_data = {56'd0,ram_rd_data[15: 8]};
                3'd2:lb_ram_rd_data = {56'd0,ram_rd_data[23:16]};
                3'd3:lb_ram_rd_data = {56'd0,ram_rd_data[31:24]};
                3'd4:lb_ram_rd_data = {56'd0,ram_rd_data[39:32]};
                3'd5:lb_ram_rd_data = {56'd0,ram_rd_data[47:40]};
                3'd6:lb_ram_rd_data = {56'd0,ram_rd_data[55:48]};
                3'd7:lb_ram_rd_data = {56'd0,ram_rd_data[63:56]};
            endcase
        else 
            lb_ram_rd_data = `ZERO_WORD;
    end

    // 读双字节
    always @(lh_signal or mem_addr[2:1] or ram_rd_data) begin
        if(lh_signal)
            case(mem_addr[2:1])
                2'd0:lh_ram_rd_data = {48'd0,ram_rd_data[15: 0]};
                2'd1:lh_ram_rd_data = {48'd0,ram_rd_data[31:16]};
                2'd2:lh_ram_rd_data = {48'd0,ram_rd_data[47:32]};
                2'd3:lh_ram_rd_data = {48'd0,ram_rd_data[63:48]};
            endcase
        else
            lh_ram_rd_data = `ZERO_WORD;
    end
    // 读四字节
    always @(lw_signal or mem_addr[2] or ram_rd_data) begin
        if(lw_signal)
            case(mem_addr[2])
            1'b0:lw_ram_rd_data = {32'd0,ram_rd_data[31: 0]};
            1'b1:lw_ram_rd_data = {32'd0,ram_rd_data[63:32]};
            endcase
        else
            lw_ram_rd_data = `ZERO_WORD;
    end

    // 读八字节
    always @(ld_signal or ram_rd_data) begin
        if(ld_signal)
            ld_ram_rd_data = ram_rd_data;
        else
            ld_ram_rd_data = `ZERO_WORD;
    end

endmodule

@codefuturedalao
Copy link

求问如果流水线的话是不是要把wb阶段的pc接入cmt_pc,那么如果发生控制冒险清零PC,difftest报错pc不一致的问题如何处理呢,我的思路是能不能发生冒险的时候不让difftest继续比较pc的值,直到正常指令执行到wb阶段再进行比较(已经试过设置skip信号的方法,但是没有用)

@YouTheFreedom1999
Copy link
Author

YouTheFreedom1999 commented Aug 4, 2021

求问如果流水线的话是不是要把wb阶段的pc接入cmt_pc,那么如果发生控制冒险清零PC,difftest报错pc不一致的问题如何处理呢,我的思路是能不能发生冒险的时候不让difftest继续比较pc的值,直到正常指令执行到wb阶段再进行比较(已经试过设置skip信号的方法,但是没有用)

写回阶段的pc,你指的是计算出的跳转地址,还是执行到写回阶段跳转指令所在的地址呢

@codefuturedalao
Copy link

求问如果流水线的话是不是要把wb阶段的pc接入cmt_pc,那么如果发生控制冒险清零PC,difftest报错pc不一致的问题如何处理呢,我的思路是能不能发生冒险的时候不让difftest继续比较pc的值,直到正常指令执行到wb阶段再进行比较(已经试过设置skip信号的方法,但是没有用)

写回阶段的pc,你指的是计算出的跳转地址,还是执行到写回阶段跳转指令所在的地址呢

我用的是wb_pc和cmt_pc连接,也就是执行到写回阶段指令所在的地址。当出现控制冒险时,我flush了一些寄存器(包括PC,就算不flush,pc也是错误的,所以不如都flush了🤣),之后这些气泡执行到wb阶段时,wb_pc 为0,这时候difftest就会给我报错,表示this_pc出现错误,right_pc为目标指令跳转地址,wrong_pc 为000000000,但其实我跳转正确了,只是指令还没有执行到wb阶段,所以想跳过那些对于气泡的比较,不知道怎么办😂

@doubletpy
Copy link

我想请问
1.为什么ram读数据时地址要减去64'h0000_0000_8000_0000
2.ram的代码中读数据时不需要考虑是lb,lh,lw等等的这些吗,我看是直接读64位的

@codefuturedalao
Copy link

我想请问
1.为什么ram读数据时地址要减去64'h0000_0000_8000_0000
2.ram的代码中读数据时不需要考虑是lb,lh,lw等等的这些吗,我看是直接读64位的

  1. 因为RAM中的数据是加载的objdump从elf可执行文件中生成的bin文件,可执行文件中从虚拟地址64'h0000_0000_8000_0000开始重定位,分配地址,而bin文件中将指令和数据从0开始放置。举个例子,int a = b[0]假设需要lw指令将b[0]的数据从内存中加载到寄存器里面,当我们生成可执行文件后,在链接的时候会进行重定位,根据规范,编译器会假设这个程序放置在从虚拟地址64'h0000_0000_8000_0000开始的一段空间,然后我们根据b[0]在数据段中的偏移和64‘h8000_0000这两个数可以计算b[0]的虚拟地址,最后填写到lw指令中,当你自己写的CPU运行到该指令时,会很自然地想要读取RAM这个地址(大于0x8000_0000)的数据,本来按照正常情况,这个地址确实应该有你想要的数据,但是我们bin文件是假设数据从0开始放置的,所以就需要你转换一下,减去0x8000_0000。
  2. 所以需要根据lb、lh和lw生成对应的控制信号——mask掩码来选取64位数据中自己想要的数据,当你编写Axi总线的时候,也要提供这样一个信号的。

@lsyic
Copy link

lsyic commented Aug 10, 2021

请问difftest是只能对比指令和通用寄存器的差异吗?写到RAM中的数据是否正确能否对比出来呢?

@codefuturedalao
Copy link

请问difftest是只能对比指令和通用寄存器的差异吗?写到RAM中的数据是否正确能否对比出来呢?

image
是的,如上图所示,左边是difftest进行比较的函数,比较的内容是自己CPU中寄存器和NEMU中寄存器的值,具体寄存器如图右边所示,是32个gpr和一些csr寄存器,所以store指令的正确性是没办法比较出来的,但是可以根据后面的load指令来判断,如果store向一个错误地址或者正确地址写入了错误数据,后面的load取相应的数据到寄存器时自然会被difftest判断出错。QQ群里面好像有个同学给出了验证store指令的正确性的教程,可以翻一下聊天记录。
欢迎指正。

@lsyic
Copy link

lsyic commented Aug 11, 2021

请问difftest框架内的ram是不能支持既取指又读内存中的数据吗?必须要自己重新改写ram吗?

@codefuturedalao
Copy link

请问difftest框架内的ram是不能支持既取指又读内存中的数据吗?必须要自己重新改写ram吗?

应该是,这个issue也给了一写两读的RAM模块供使用

@CleanerNo7
Copy link

同学你好,我参照你的ram模块和mem_ctrl模块接入了simtop模块,也能正常difftest,但是在ld指令显示出错
第64条指令是lh指令能正常通过,应该只有ld指令出错
800001bc: 02813083 ld ra,40(sp)
x[rd] = M[x[rs1] + sext(offset)][63:0]
能识别是ld指令,应该是读内存时的问题。但查看了各个接口的数据应该是正确的,但又无法查看内存里的数据。。
查看之前的load指令,有效访问的内存地址都是后四位0xxx的,只有这条ld指令访问的是后四位8FE8,
所以怀疑是地址的问题,但根据指令查看sp,offset也是正确的。所以很奇怪,也不知道是哪里出了问题。。

Capture
2

@codefuturedalao
Copy link

同学你好,我参照你的ram模块和mem_ctrl模块接入了simtop模块,也能正常difftest,但是在ld指令显示出错
第64条指令是lh指令能正常通过,应该只有ld指令出错
800001bc: 02813083 ld ra,40(sp)
x[rd] = M[x[rs1] + sext(offset)][63:0]
能识别是ld指令,应该是读内存时的问题。但查看了各个接口的数据应该是正确的,但又无法查看内存里的数据。。
查看之前的load指令,有效访问的内存地址都是后四位0xxx的,只有这条ld指令访问的是后四位8FE8,
所以怀疑是地址的问题,但根据指令查看sp,offset也是正确的。所以很奇怪,也不知道是哪里出了问题。。

Capture
2

我刚才看了看load-store-riscv64-mycpu.txt中的汇编指令,同时也跑了一遍看了一下波形,此条指令的地址的后四位的确是8FE8,load指令如果不是自己计算地址和控制信号有错误的话,应该是前面sd的时候存了错误数据或者向错误地址写入了数据,请检查
image
这条指令的写入结果,希望对你有所帮助。

@CleanerNo7
Copy link

同学你好,我参照你的ram模块和mem_ctrl模块接入了simtop模块,也能正常difftest,但是在ld指令显示出错
第64条指令是lh指令能正常通过,应该只有ld指令出错
800001bc: 02813083 ld ra,40(sp)
x[rd] = M[x[rs1] + sext(offset)][63:0]
能识别是ld指令,应该是读内存时的问题。但查看了各个接口的数据应该是正确的,但又无法查看内存里的数据。。
查看之前的load指令,有效访问的内存地址都是后四位0xxx的,只有这条ld指令访问的是后四位8FE8,
所以怀疑是地址的问题,但根据指令查看sp,offset也是正确的。所以很奇怪,也不知道是哪里出了问题。。
Capture
2

我刚才看了看load-store-riscv64-mycpu.txt中的汇编指令,同时也跑了一遍看了一下波形,此条指令的地址的后四位的确是8FE8,load指令如果不是自己计算地址和控制信号有错误的话,应该是前面sd的时候存了错误数据或者向错误地址写入了数据,请检查
image
这条指令的写入结果,希望对你有所帮助。

好的,非常感谢大佬🙇‍

@lsyic
Copy link

lsyic commented Aug 15, 2021

请问如何编译及运行cpu_test下的全部验证程序呢?

@codefuturedalao
Copy link

请问如何编译及运行cpu_test下的全部验证程序呢?

image

@lsyic
Copy link

lsyic commented Aug 15, 2021

请问如何编译及运行cpu_test下的全部验证程序呢?

image

多谢多谢!请问这个链接是在哪里?

@codefuturedalao
Copy link

请问如何编译及运行cpu_test下的全部验证程序呢?

image

多谢多谢!请问这个链接是在哪里?

https://github.com/OSCPU/oscpu-framework repo的readme里面

@lsyic
Copy link

lsyic commented Aug 15, 2021

请问如何编译及运行cpu_test下的全部验证程序呢?

image

多谢多谢!请问这个链接是在哪里?

https://github.com/OSCPU/oscpu-framework repo的readme里面

多谢多谢!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
#Difftest Difftest 相关问题 #Verilog Verilog 相关问题 知识分享 该issue的主题是信息、知识分享
Projects
None yet
Development

No branches or pull requests

10 participants