为了学习雷思磊的,步步惊心 软核处理器内部设计和分析,又不想在linux下使用庞大的modelsim,只能摸索开源verilog仿真软件。
1.首先准备or1200源码,在opencores.org上下载吧。
2.在你的linux系统上安装iverilog和gtkwave,安装方法很简单,fedora:sudo yum install iverilog gtkwave. ubuntu:sudo apt-get install iverilog gtkwave
3.安装or1200的交叉编译器,编译器下载也在opencores.org,具体怎么安装,在网上搜一把,"交叉编译器安装“,虽然是arm的,但是or1200也一样。
4.接下来编写第一个测试程序test.S,第一个程序是or1200汇编程序,内容如下:
.section .text ,"ax"
.org 0x100
.global _start
_start:
l.andi r0,r0,0
l.extwz r1,r0
l.extwz r2,r0
l.addi r1,r1,0x0a
l.add r2,r2,r1
l.nop 0x0001 5.编写程序链接脚本,ram.ld,注意原书中"Entry(_start)"无法编译通过,我把它改为ENTRY(_start)
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 0x00005000
}
SECTIONS
{
.text :
{
*(.text)
} > ram
.data :
{
*(.data)
} > ram
.bss :
{
*(.bss)
} > ram
}
ENTRY (_start) 6.编译程序
or32-elf-as -o test.o test.S
or32-elf-ld -T ram.ld test.o -o test.or32 7.这个test.or32可以放入or1200模拟器中允许,为了装入qmem我们还需要进行处理,先把test.or32转为bin文件,再把bin转为存储器初始化文件。
or32-elf-objcopy -O binary test.or32 test.bin 8.应为我没有bin转hex的工具,只好自己写一个,代码如下:
#include
#include
#include
int main(int argc,char **argv)
{
FILE *fd_src,*fd_dst;
char buf[64];
int ret,i;
if (argc != 2)
{
printf("usage: %s binfile\n",argv[0]);
return 0;
}
fd_src = fopen(argv[1],"rb");
if(!fd_src)
{
perror("src fopen:");
return 0;
}
memset(buf,0,64);
sprintf(buf,"%s.hex",argv[1]);
fd_dst = fopen(buf,"w+");
if(!fd_dst)
{
perror("dst fopen:");
fclose(fd_src);
return 0;
}
i = 0;
while ((ret=fread(buf,1,4,fd_src))!=0)
{
if(ret != 4)
{
printf("read file error\n");
fclose(fd_src);
fclose(fd_dst);
return 0;
}
ret = htonl(*((int *)buf));
fprintf(fd_dst,"%08x\r\n",ret);
i++;
}
while (i!=2048)
{
fprintf(fd_dst,"00000000\r\n");
i++;
}
fclose(fd_src);
fclose(fd_dst);
} 9.编写testbench文件,注意我在源文件中加了,initial那一节,这很重要。
`timescale 1ns/100ps
module or1200_tb1();
reg CLOCK_50;
reg rst;
initial begin
CLOCK_50 = 1'b0;
forever #10 CLOCK_50 = ~CLOCK_50;
end
initial begin
rst = 1'b1;
#200 rst = 1'b0;
#1000 $stop;
end
or1200_top or1200_top_inst
(
.clk_i(CLOCK_50),
.rst_i(rst),
.pic_ints_i(20'b0),
.clmode_i(2'b00),
//指令总线
.iwb_clk_i(clk_i), .iwb_rst_i(rst), .iwb_dat_i(32'b0), .iwb_ack_i(1'b0), .iwb_err_i(1'b0),
.iwb_rty_i(1'b0), .iwb_cyc_o(), .iwb_adr_o(), .iwb_dat_o(), .iwb_stb_o(), .iwb_we_o(),
.iwb_sel_o(),
`ifdef OR1200_WB_CAB
.iwb_cab_o(),
`endif
//数据总线
.dwb_clk_i(clk_i), .dwb_rst_i(rst), .dwb_dat_i(32'b0), .dwb_ack_i(1'b0), .dwb_err_i(1'b0),
.dwb_rty_i(1'b0), .dwb_cyc_o(), .dwb_adr_o(), .dwb_dat_o(), .dwb_stb_o(), .dwb_we_o(),
.dwb_sel_o(),
`ifdef OR1200_WB_CAB
.dwb_cab_o(),
`endif
//外部调试接口
.dbg_stall_i(1'b0), .dbg_ewt_i(1'b0), .dbg_lss_o(), .dbg_is_o(), .dbg_wp_o(), .dbg_bp_o(),
.dbg_stb_i(1'b0), .dbg_we_i(1'b0), .dbg_adr_i(0), .dbg_dat_i(0), .dbg_dat_o(), .dbg_ack_o(),
//电源接口
.pm_cpustall_i(0), .pm_clksd_o(), .pm_dc_gate_o(), .pm_ic_gate_o(), .pm_dmmu_gate_o(),
.pm_immu_gate_o(), .pm_tt_gate_o(), .pm_cpu_gate_o(), .pm_wakeup_o(), .pm_lvolt_o()
);
initial
begin
$dumpfile("or1200_tb1.vcd");
$dumpvars(0,or1200_top_inst);
end
endmodule 10.根据书上要求,更改or1200_qmem.v文件,并在or1200_spram_2048x32.v的611行添加
initial $readmemh("test.in.hex",mem) 11.编译所以verilog文件:
iverilog -o or1200_tb1 or1200_tb1.v $(SRC) //SRC代表所有verilog源文件
vvp -n or1200_tb1 -lxt2
cp or1200_tb1.vcd or1200_tb.lxt2 12.使用gtkwave打开or1200_tb.lxt2,就可以看波形如下图,和modelsim显示的一样
13.注意iverilog好像不能观察形如reg [aa:bb] cccc[dd:ee];这类的变量,所以寄存器文件or1200_rf/rb_b/mem[1],无法查看,所以你只能修改源码,修改or1200_dpram.v,我在100行添加如下:
wire [dw-1:0] mem_r0;
wire [dw-1:0] mem_r1;
wire [dw-1:0] mem_r2;
wire [dw-1:0] mem_r3;
wire [dw-1:0] mem_r4;
wire [dw-1:0] mem_r5;
wire [dw-1:0] mem_r6;
wire [dw-1:0] mem_r7;
wire [dw-1:0] mem_r8;
wire [dw-1:0] mem_r9;
wire [dw-1:0] mem_r10;
wire [dw-1:0] mem_r11;
wire [dw-1:0] mem_r12;
wire [dw-1:0] mem_r13;
wire [dw-1:0] mem_r14;
wire [dw-1:0] mem_r15;
wire [dw-1:0] mem_r16;
wire [dw-1:0] mem_r17;
wire [dw-1:0] mem_r18;
wire [dw-1:0] mem_r19;
wire [dw-1:0] mem_r20;
wire [dw-1:0] mem_r21;
wire [dw-1:0] mem_r22;
wire [dw-1:0] mem_r23;
wire [dw-1:0] mem_r24;
wire [dw-1:0] mem_r25;
wire [dw-1:0] mem_r26;
wire [dw-1:0] mem_r27;
wire [dw-1:0] mem_r28;
wire [dw-1:0] mem_r29;
wire [dw-1:0] mem_r30;
wire [dw-1:0] mem_r31;
assign mem_r0 = mem[0];
assign mem_r1 = mem[1];
assign mem_r2 = mem[2];
assign mem_r3 = mem[3];
assign mem_r4 = mem[4];
assign mem_r5 = mem[5];
assign mem_r6 = mem[6];
assign mem_r7 = mem[7];
assign mem_r8 = mem[8];
assign mem_r9 = mem[9];
assign mem_r10 = mem[10];
assign mem_r11 = mem[11];
assign mem_r12 = mem[12];
assign mem_r13 = mem[13];
assign mem_r14 = mem[14];
assign mem_r15 = mem[15];
assign mem_r16 = mem[16];
assign mem_r17 = mem[17];
assign mem_r18 = mem[18];
assign mem_r19 = mem[19];
assign mem_r20 = mem[20];
assign mem_r21 = mem[21];
assign mem_r22 = mem[22];
assign mem_r23 = mem[23];
assign mem_r24 = mem[24];
assign mem_r25 = mem[25];
assign mem_r26 = mem[26];
assign mem_r27 = mem[27];
assign mem_r28 = mem[28];
assign mem_r29 = mem[29];
assign mem_r30 = mem[30];
assign mem_r31 = mem[31];
14.想观察mem[1],就直接观察mem_r1,就成