为了学习雷思磊的,步步惊心 软核处理器内部设计和分析,又不想在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 0x00015.编写程序链接脚本,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.or327.这个test.or32可以放入or1200模拟器中允许,为了装入qmem我们还需要进行处理,先把test.or32转为bin文件,再把bin转为存储器初始化文件。
or32-elf-objcopy -O binary test.or32 test.bin8.应为我没有bin转hex的工具,只好自己写一个,代码如下:
#include <stdio.h> #include <string.h> #include <arpa/inet.h> 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 endmodule10.根据书上要求,更改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.lxt212.使用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];