Open YouTheFreedom1999 opened 3 years ago
大佬你好,请问是要在SimTop.v中融合原cpu中顶层.v,还是在SimTop.v中调用原顶层.v呢?
大佬你好,请问是要在SimTop.v中融合原cpu中顶层.v,还是在SimTop.v中调用原顶层.v呢?
都可以,只要能把提交信息的端口连到相应的模块就行
你好,请问“在指令提交的时刻其产生的影响恰好生效”,是不是要求需要实现流水线结构?
想请问一下这里的CPU的所有RTL文件,指的是什么?是define.v,if_stage.v之类的文件吗?
想请问一下这里的CPU的所有RTL文件,指的是什么?是define.v,if_stage.v之类的文件吗?
我理解是的。要把自己所有的CPU代码接入进来。
你好,请问您这个教程中接入的CPU是单周期的吗?
你好,请问这个地方为什么是写入一半数据呢
wire [
BUS_WIDTH]wr_data = {mem_wr_data[31:0],mem_rd_data[63:32]};`
谢谢
你好,请问您这个教程中接入的CPU是单周期的吗?
是的,流水线的提交也是类似的
你好,请问这个地方为什么是写入一半数据呢
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
求问如果流水线的话是不是要把wb阶段的pc接入cmt_pc,那么如果发生控制冒险清零PC,difftest报错pc不一致的问题如何处理呢,我的思路是能不能发生冒险的时候不让difftest继续比较pc的值,直到正常指令执行到wb阶段再进行比较(已经试过设置skip信号的方法,但是没有用)
求问如果流水线的话是不是要把wb阶段的pc接入cmt_pc,那么如果发生控制冒险清零PC,difftest报错pc不一致的问题如何处理呢,我的思路是能不能发生冒险的时候不让difftest继续比较pc的值,直到正常指令执行到wb阶段再进行比较(已经试过设置skip信号的方法,但是没有用)
写回阶段的pc,你指的是计算出的跳转地址,还是执行到写回阶段跳转指令所在的地址呢
求问如果流水线的话是不是要把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阶段,所以想跳过那些对于气泡的比较,不知道怎么办😂
我想请问 1.为什么ram读数据时地址要减去64'h0000_0000_8000_0000 2.ram的代码中读数据时不需要考虑是lb,lh,lw等等的这些吗,我看是直接读64位的
我想请问 1.为什么ram读数据时地址要减去64'h0000_0000_8000_0000 2.ram的代码中读数据时不需要考虑是lb,lh,lw等等的这些吗,我看是直接读64位的
请问difftest是只能对比指令和通用寄存器的差异吗?写到RAM中的数据是否正确能否对比出来呢?
请问difftest是只能对比指令和通用寄存器的差异吗?写到RAM中的数据是否正确能否对比出来呢?
是的,如上图所示,左边是difftest进行比较的函数,比较的内容是自己CPU中寄存器和NEMU中寄存器的值,具体寄存器如图右边所示,是32个gpr和一些csr寄存器,所以store指令的正确性是没办法比较出来的,但是可以根据后面的load指令来判断,如果store向一个错误地址或者正确地址写入了错误数据,后面的load取相应的数据到寄存器时自然会被difftest判断出错。QQ群里面好像有个同学给出了验证store指令的正确性的教程,可以翻一下聊天记录。 欢迎指正。
请问difftest框架内的ram是不能支持既取指又读内存中的数据吗?必须要自己重新改写ram吗?
请问difftest框架内的ram是不能支持既取指又读内存中的数据吗?必须要自己重新改写ram吗?
应该是,这个issue也给了一写两读的RAM模块供使用
同学你好,我参照你的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也是正确的。所以很奇怪,也不知道是哪里出了问题。。
同学你好,我参照你的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也是正确的。所以很奇怪,也不知道是哪里出了问题。。
我刚才看了看load-store-riscv64-mycpu.txt中的汇编指令,同时也跑了一遍看了一下波形,此条指令的地址的后四位的确是8FE8,load指令如果不是自己计算地址和控制信号有错误的话,应该是前面sd的时候存了错误数据或者向错误地址写入了数据,请检查 这条指令的写入结果,希望对你有所帮助。
同学你好,我参照你的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也是正确的。所以很奇怪,也不知道是哪里出了问题。。
我刚才看了看load-store-riscv64-mycpu.txt中的汇编指令,同时也跑了一遍看了一下波形,此条指令的地址的后四位的确是8FE8,load指令如果不是自己计算地址和控制信号有错误的话,应该是前面sd的时候存了错误数据或者向错误地址写入了数据,请检查 这条指令的写入结果,希望对你有所帮助。
好的,非常感谢大佬🙇
请问如何编译及运行cpu_test下的全部验证程序呢?
请问如何编译及运行cpu_test下的全部验证程序呢?
请问如何编译及运行cpu_test下的全部验证程序呢?
多谢多谢!请问这个链接是在哪里?
请问如何编译及运行cpu_test下的全部验证程序呢?
多谢多谢!请问这个链接是在哪里?
https://github.com/OSCPU/oscpu-framework repo的readme里面
请问如何编译及运行cpu_test下的全部验证程序呢?
多谢多谢!请问这个链接是在哪里?
https://github.com/OSCPU/oscpu-framework repo的readme里面
多谢多谢!
前言
昨天看到有老哥写了Chisel的difftest接入,心血来潮想试试Verilog怎么接入。 一定要参考Chisel的difftest接入、DiffTest Usge这两篇,我算是一点点补充 水平有限,请各位多多指教。
TOP文件
首先我们要在difftest的上一层建立一个build文件夹,并新建一个 SimTop.v 并将下列内容写入,这个文件就是整个RTL仿真设计的顶层。 还要将CPU的所有RTL文件放入。(也可以考虑用 make install 自动copy)
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字节对齐,为了适应仿真内存也要做相应的映射,详情见下述代码
将此模块实例化到 SimTop.v 中并且将端口接入到自己设计的CPU中,这样就完成了,RAM的接入
指令的提交
Difftest通过,DifftestInstrCommit这个模块来将信号提交到DiffTest中。
将需要提交的信号链接,记住手册里的一句话,在指令提交的时刻其产生的影响恰好生效
REGFILE的提交
对应模块名为DifftestArchIntRegState,类似的方法接入
编译运行
然后就可以编译emu
运行difftest
根据日志可以看到已经捕获到错误的信息
Tips: 将Difftest的Makefile中clean:vcs-clean下面的一行改成
可以在执行make clean时不删除RTL代码