【RISC-V设计-12】- RISC-V处理器设计K0A之验证环境

【RISC-V设计-12】- RISC-V处理器设计K0A之验证环境

文章目录

  • 【RISC-V设计-12】- RISC-V处理器设计K0A之验证环境
    • 1.简介
    • 2.验证顶层
    • 3.顶层代码
    • 4.模型结构
      • 4.1 地址映射
      • 4.2 特殊功能寄存器
    • 5.模型代码
    • 6.运行脚本
    • 7.总结

1.简介

在前几篇文章中,分别介绍了各个模块的设计,本篇文章将会针对k0a_core_top层搭建一个简单的验证环境。

2.验证顶层

【RISC-V设计-12】- RISC-V处理器设计K0A之验证环境_第1张图片

3.顶层代码

// -------------------------------------------------------------------------------------------------
// Copyright 2024 Kearn Chen, [email protected]
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------
// Description :
//             1. testbench for simulation
// -------------------------------------------------------------------------------------------------

`timescale 1ns/10ps

module test_top();

reg          core_clk    ;
reg          core_rstn   ;

wire         bus_avalid  ;
wire         bus_aready  ;
wire         bus_write   ;
wire [17:0]  bus_addr    ;
wire [3:0]   bus_strb    ;
wire [31:0]  bus_wdata   ;
wire         bus_rvalid  ;
wire         bus_rready  ;
wire [31:0]  bus_rdata   ;

reg  [15:0]  irq_lines   ;

k0a_core_top dut (
    .core_clk       (core_clk       ),
    .core_rstn      (core_rstn      ),
    .bus_avalid     (bus_avalid     ),
    .bus_aready     (bus_aready     ),
    .bus_write      (bus_write      ),
    .bus_addr       (bus_addr       ),
    .bus_strb       (bus_strb       ),
    .bus_wdata      (bus_wdata      ),
    .bus_rvalid     (bus_rvalid     ),
    .bus_rready     (bus_rready     ),
    .bus_rdata      (bus_rdata      ),
    .irq_lines      (irq_lines      )
);

slave_model u_slave (
    .clk            (core_clk       ),
    .rstn           (core_rstn      ),
    .avalid         (bus_avalid     ),
    .aready         (bus_aready     ),
    .write          (bus_write      ),
    .addr           (bus_addr       ),
    .strb           (bus_strb       ),
    .wdata          (bus_wdata      ),
    .rvalid         (bus_rvalid     ),
    .rready         (bus_rready     ),
    .rdata          (bus_rdata      )
);

initial begin
    core_clk = 1'b0;
    forever #10 core_clk = ~core_clk;
end

initial begin
    core_rstn = 1'b0;
    irq_lines = 16'd0;
    initcase();
    #1000;
    core_rstn = 1'b1;
    testcase();
    $finish();
end

`ifdef DUMP_LXT2

initial begin
    $dumpfile("test_top.lxt2");
    $dumpvars(0, test_top);
end

`endif

`include "testcase.v"

task load_instr(string path);

    integer i, fd, ret;
    reg [7:0] data;

    fd = $fopen($sformatf("../test/%s", path), "rb");

    if(fd == 0) begin
        $display("Open file : ../test/%s failed!", path);
    end

    for(i=0; i<131072; i++) begin
        u_slave.imem[i] = 32'd0;
    end

    i = 0;
    while($feof(fd) == 0) begin
        ret = $fread(data, fd);
        u_slave.imem[i/4][(i%4)*8+:8] = data;
        i++;
    end

    $fclose(fd);

endtask

endmodule

在测试顶层代码中,连接了DUT的时钟、复位以及中断信号,总线的丛机模型和内核相连接。同时,提供了一个加载初始化软件代码的任务,验证用例通过load_instr任务,可加载二进制Bin文件到丛机模型中,在复位结束后,内核开始运行软件代码。

4.模型结构

4.1 地址映射

【RISC-V设计-12】- RISC-V处理器设计K0A之验证环境_第2张图片

4.2 特殊功能寄存器

地址 寄存器 位宽 属性 描述
0xC0000 DATA 8 WO 队列的地址,软件可通过向此地址写入ASCII字符,输出到终端显示,以换行符\n结尾
0xC0004 FINISH 32 WO 写入数据0x12345678后,仿真运行结束
0xC0008 CLOCK 32 RO 时钟计数器,在复位结束后开始每个时钟周期自增1
0xC000C SPEED 8 RW 模型的总线速度,0:模型会随机拉住总线的ready,1:总线ready一直为1

5.模型代码

// -------------------------------------------------------------------------------------------------
// Copyright 2024 Kearn Chen, [email protected]
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------
// Description :
//             1. slave model for simulation
// -------------------------------------------------------------------------------------------------

module slave_model (
    input  wire         clk    ,
    input  wire         rstn   ,
    input  wire         avalid ,
    output wire         aready ,
    input  wire         write  ,
    input  wire [17:0]  addr   ,
    input  wire [3:0]   strb   ,
    input  wire [31:0]  wdata  ,
    output wire         rvalid ,
    input  wire         rready ,
    output wire [31:0]  rdata
);

reg         flag;
reg  [1:0]  cycle;
reg  [31:0] dout;

reg  [31:0] imem[0:131071];
reg  [31:0] dmem[0:65535];

reg  [7:0]  queue[$];

reg  [31:0] clock;
reg         speed;

string      str;

integer     idx;

assign aready = cycle == 3'd0 ? 1'b1 : 1'b0;
assign rvalid = cycle == 3'd0 ? flag : 1'b0;
assign rdata  = cycle == 3'd0 ? dout : 32'dx;

always @(posedge clk)
begin
    if(avalid & aready & write) begin
        if(~addr[17]) begin
            if(strb[0]) imem[addr[16:0]][0 +:8] <= wdata[0 +:8];
            if(strb[1]) imem[addr[16:0]][8 +:8] <= wdata[8 +:8];
            if(strb[2]) imem[addr[16:0]][16+:8] <= wdata[16+:8];
            if(strb[3]) imem[addr[16:0]][24+:8] <= wdata[24+:8];
        end else if(~addr[16]) begin
            if(strb[0]) dmem[addr[15:0]][0 +:8] <= wdata[0 +:8];
            if(strb[1]) dmem[addr[15:0]][8 +:8] <= wdata[8 +:8];
            if(strb[2]) dmem[addr[15:0]][16+:8] <= wdata[16+:8];
            if(strb[3]) dmem[addr[15:0]][24+:8] <= wdata[24+:8];
        end
    end
end

always @(posedge clk or negedge rstn)
begin
    if(!rstn)
        flag <= 1'b0;
    else if(avalid & aready & ~write)
        flag <= 1'b1;
    else if(rready & rvalid)
        flag <= 1'b0;
end

always @(posedge clk or negedge rstn)
begin
    if(!rstn)
        cycle <= 2'd0;
    else if(|cycle)
        cycle <= cycle - 2'd1;
    else if(avalid) begin
        idx = $urandom_range(0, 99);
        if(idx <= 80 || speed == 1'b1)
            cycle <= 2'd0;
        else if(idx <= 95)
            cycle <= 2'd1;
        else if(idx <= 97)
            cycle <= 2'd2;
        else
            cycle <= 2'd3;
    end
end

always @(posedge clk or negedge rstn)
begin
    if(!rstn)
        dout <= 32'dx;
    else if(avalid & aready & ~write)
        if(~addr[17])
            dout <= imem[addr[16:0]];
        else if(~addr[16])
            dout <= dmem[addr[15:0]];
        else if(addr[15:0] == 16'h0002)
            dout <= clock;
        else if(addr[15:0] == 16'h0003)
            dout <= {31'd0, speed};
    else if(rready & rvalid)
        dout <= 32'dx;
end

always @(posedge clk)
begin
    if(avalid & aready & write & strb[0] & addr == 18'h30000) begin
        if(wdata[7:0] == 8'h0a) begin
            str = "";
            while(queue.size() > 0) begin
                str = $sformatf("%s%c", str, queue.pop_front());
            end
            $display("[MCU_INFO] : %s", str);
        end else begin
            queue.push_back(wdata[7:0]);
        end
    end
end

always @(posedge clk)
begin
    if(avalid & aready & write & (&strb) & addr == 18'h30001) begin
        if(wdata == 32'h12345678) begin
            $finish();
        end
    end
end

always @(posedge clk or negedge rstn)
begin
    if(!rstn)
        clock <= 32'd0;
    else
        clock <= clock + 1'b1;
end

always @(posedge clk or negedge rstn)
begin
    if(!rstn)
        speed <= 1'b0;
    else if(avalid & aready & write & strb[0] & addr == 18'h30003)
        speed <= wdata[0];
end

endmodule

6.运行脚本

脚本支持两套仿真工具,一套为开源的iverilog+gtkwave的组合,另一套为vcs+verdi。

# -------------------------------------------------------------------------------------------------
# Copyright 2024 Kearn Chen, [email protected]
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -------------------------------------------------------------------------------------------------
# Description :
#             1. Run simulation
# -------------------------------------------------------------------------------------------------

TEST := hello_world_test

vcs:
	cp ../case/$(TEST).v testcase.v
	make -C ../test/$(TEST)
	vcs -full64 -sverilog +vcs+fsdbon -f ../list/filelist.vc
	./simv +ntb_random_seed_automatic -l simv.log

iverilog:
	cp ../case/$(TEST).v testcase.v
	make -C ../test/$(TEST)
	iverilog -o simv -f ../list/filelist.vc -g2012 -DDUMP_LXT2
	vvp simv -lxt2 -fst

verdi:
	verdi -sverilog -f ../list/filelist.vc &

gtkwave:
	gtkwave &

clean:
	rm -rf simv *.log csrc simv.daidir verdiLog ucli.key novas* *.v

7.总结

本文介绍了一个简单的验证环境,包括测试顶层及模型、脚本等代码,在后续的文章中会基于此验证环境给出具体的验证用例。

你可能感兴趣的:(RISC-V设计专题,risc-v)