SoC的Testbench中的简易bus_monitor(加入print函数)

本文介绍了一种在SoC的Testbench中实现简易bus_monitor的方法,通过监控总线上的信息并存储到预定义内存中,再将ASCII码处理后显示在屏幕。涉及C语言编写的print/printf函数的编译与使用,以及Verilog代码的具体实现。

SoC的Testbench中的简易bus_monitor(加入print函数)

主要思路 向固定地址写信息

  • 使用工具链将C写的print/printf函数编译成hex文件
  • 在testbench中创建bus_monitor来监控总线上信息
    • 当监控print对总线上的固定地址操作时将数据存储到预先定义的memory中
    • 使用verilog的write处理memory中的ASCII码,打印到屏幕上

testbench下的bus_monitor

module bus_monitor();

`define DIGITAL_TOP testbench.u0_riscv_platform_demo.u0_digital_top
`define BUSMON     `DIGITAL_TOP.u0_Insight_E21_ECoreIPSubsystem

`define LED_DRIVER_BASE (32'h4FF00000)  //4FF0_0000
`define LED_RETURN_CHAR 16'h0a
`define LED_FINISH      16'h00
//RISCV
`define RISCV_START        16'h80       // "Test start by RISCV";
`define RISCV_FINISH       16'h81       // "Test complete by RISCV";
`define RISCV_FAIL         16'h82       // "Msg code FAIL by RISCV";
`define RISCV_PASS         16'h83       // "Msg code PASS by RISCV";     

//open Memory For CPU Print Messeage storge
parameter ADDR_DEPTH =15;
parameter WORD_DEPTH = (1<<ADDR_DEPTH) ; // Memory depth in K,16bit
reg   [7:0] memory [0:(WORD_DEPTH - 1)]; // Memory register array
reg   [7:0] led_data;

reg   led_valid;
wire  cclk  = `DIGITAL_TOP.cpu_clock;

wire  [7:0]  ext_mem_din =  `BUSMON.sys_port_ahb_0_hwdata[7:0];
always @(posedge cclk) begin
    led_valid <= (`BUSMON.sys_port_ahb_0_haddr == `LED_DRIVER_BASE) 
                 && `BUSMON.sys_port_ahb_0_hwrite 
                 && `BUSMON.sys_port_ahb_0_hsel;
end

// wire  [7:0]  ext_mem_din =  `BUSMON.E31.auto_rational_xing_sourcelzy_out_a_bits1_data[31:0];
// always @(posedge cclk) begin
//     led_valid <= (`BUSMON.E31.auto_rational_xing_sourcelzy_out_a_bits0_address[31:0] == `LED_DRIVER_BASE) 
//                  && `BUSMON.E31.auto_rational_xing_sourcelzy_out_a_valid;
// end
 
integer i;
integer m;
initial begin
    i=0;
    m=0;
end

always @ (negedge cclk)
begin
    if (led_valid)
    begin
        led_data = ext_mem_din[7:0];
        if(ext_mem_din[7]== 1'b1) 
            print_code(ext_mem_din[7:0]);
        else 
            case(ext_mem_din[7:0])
                `LED_RETURN_CHAR: begin  // Nul character check by monitor
                memory[i]  = ext_mem_din[7:0]; 
                i=i+1;
                for(m=0;m<i;m=m+1) begin
                    $write ("%c",memory[m]);
                end
                i=0;
            end
            `LED_FINISH: begin  //$finish test 
            $display ("Terminate detect by bus_monitor - mcu terminating simulation\n");
            #100 $finish;
        end
        default: begin
            memory[i]  = ext_mem_din[7:0]; 
            i=i+1;
        end
    endcase
end
end

task print_code;
    input [7:0] code;

    reg   [8*60:1] message;
    begin
        case (code)
            // RISCV Signal
            `RISCV_START          : message = "Test start by RISCV";
            `RISCV_FINISH         : message = "Test complete by RISCV";
            `RISCV_FAIL           : message = "Msg code FAIL by RISCV";
            `RISCV_PASS           : message = "Msg code PASS by RISCV";     
            default               : message = "Unrecognized message code";
        endcase
        $display ("print_code message: %0s (Msg code %h)", message, code);
    end
endtask

endmodule

print/printf函数(C代码)

注意:向一个固定的总线地址写信息

sim_show.h

#define LED_REG_BASE         0x4FF00000

// Global Signal
#define RISCV_QUIT         0x00       // "NULL Char detected by led_model"; 
// RISCV Signal 
#define RISCV_START        0x80       // "Test start by RISCV";
#define RISCV_FINISH       0x81       // "Test complete by RISCV";
#define RISCV_FAIL         0x82       // "Msg code FAIL by RISCV";
#define RISCV_PASS         0x83       // "Msg code PASS by RISCV";     

void sim_start();
void sim_pass();
void sim_fail();
void sim_finish();
void print_led(char string_val []);
void printf_led(const char* fmt, ...);

sim_show.c

可移植的print底层函数

#include <stdint.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>

#include <stddef.h>            // headers for the print functions
#include <stdarg.h>           // support variable length arguments (printf)
#include <string.h>
#include "sim_show.h"

void sim_start() {
    *(volatile char *)LED_REG_BASE = RISCV_START;
} 

void sim_pass() {
    *(volatile char *)LED_REG_BASE = RISCV_PASS;
    *(volatile char *)LED_REG_BASE = RISCV_QUIT;
} 

void sim_fail() {
    *(volatile char *)LED_REG_BASE = RISCV_FAIL;
    *(volatile char *)LED_REG_BASE = RISCV_QUIT;
} 

void sim_finish() {
    *(volatile char *)LED_REG_BASE = RISCV_FINISH;
    *(volatile char *)LED_REG_BASE = RISCV_QUIT;
} 

// print_led - print any size constant array of characters to the LED driver
//           - faster than printf_led but less robust
void print_led(char string_val []) {
    int i;
    for(i=0;string_val[i] != '\0';i++) {
        *(volatile char *)LED_REG_BASE = string_val[i];
    }
} // void print_led()



static void sprintf_putch(int ch, void** data)
{
    char** pstr = (char**)data;
    **pstr = ch;
    (*pstr)++;
}

int putchar(int ch)
{
    *(volatile char *)LED_REG_BASE = ch;

}

static unsigned long getuint(va_list *ap, int lflag)
{
    if (lflag)
        return va_arg(*ap, unsigned long);
    else
        return va_arg(*ap, unsigned int);
}

static long getint(va_list *ap, int lflag)
{
    if (lflag)
        return va_arg(*ap, long);
    else
        return va_arg(*ap, int);
}

static inline void printnum(void (*putch)(int, void**), void **putdat,
        uint64_t num, unsigned base, int width, int padc)
{
    unsigned digs[sizeof(num)*8];
    int pos = 0;

    while (1)
    {
        digs[pos++] = num % base;
        if (num < base)
            break;
        num /= base;
    }

    while (width-- > pos)
        putch(padc, putdat);

    while (pos-- > 0)
        putch(digs[pos] + (digs[pos] >= 10 ? 'a' - 10 : '0'), putdat);
}

static inline void print_double(void (*putch)(int, void**), void **putdat,
        double num, int width, int prec)
{
    union {
        double d;
        uint64_t u;
    } u;
    u.d = num;

    if (u.u & (1ULL << 63)) {
        putch('-', putdat);
        u.u &= ~(1ULL << 63);
    }

    for (int i = 0; i < prec; i++)
        u.d *= 10;

    char buf[32], *pbuf = buf;
    printnum(sprintf_putch, (void**)&pbuf, (uint64_t)u.d, 10, 0, 0);
    if (prec > 0) {
        for (int i = 0; i < prec; i++) {
            pbuf[-i] = pbuf[-i-1];
        }
        pbuf[-prec] = '.';
        pbuf++;
    }

    for (char* p = buf; p < pbuf; p++)
        putch(*p, putdat);
}

static void vprintfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list ap)
{
    register const char* p;
    const char* last_fmt;
    register int ch, err;
    unsigned long num;
    int base, lflag, width, precision, altflag;
    char padc;

    while (1) {
        while ((ch = *(unsigned char *) fmt) != '%') {
            if (ch == '\0')
                return;
            fmt++;
            putch(ch, putdat);
        }
        fmt++;

        // Process a %-escape sequence
        last_fmt = fmt;
        padc = ' ';
        width = -1;
        precision = -1;
        lflag = 0;
        altflag = 0;
reswitch:
        switch (ch = *(unsigned char *) fmt++) {

            // flag to pad on the right
            case '-':
                padc = '-';
                goto reswitch;

                // flag to pad with 0's instead of spaces
            case '0':
                padc = '0';
                goto reswitch;

                // width field
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                for (precision = 0; ; ++fmt) {
                    precision = precision * 10 + ch - '0';
                    ch = *fmt;
                    if (ch < '0' || ch > '9')
                        break;
                }
                goto process_precision;

            case '*':
                precision = va_arg(ap, int);
                goto process_precision;

            case '.':
                if (width < 0)
                    width = 0;
                goto reswitch;

            case '#':
                altflag = 1;
                goto reswitch;

process_precision:
                if (width < 0)
                    width = precision, precision = -1;
                goto reswitch;

                // long flag
            case 'l':
                if (lflag)
                    goto bad;
                goto reswitch;

                // character
            case 'c':
                putch(va_arg(ap, int), putdat);
                break;

                // double
            case 'f':
                print_double(putch, putdat, va_arg(ap, double), width, precision);
                break;

                // string
            case 's':
                if ((p = va_arg(ap, char *)) == NULL)
                    p = "(null)";
                if (width > 0 && padc != '-')
                    for (width -= strnlen(p, precision); width > 0; width--)
                        putch(padc, putdat);
                for (; (ch = *p) != '\0' && (precision < 0 || --precision >= 0); width--) {
                    putch(ch, putdat);
                    p++;
                }
                for (; width > 0; width--)
                    putch(' ', putdat);
                break;

                // (signed) decimal
            case 'd':
                num = getint(&ap, lflag);
                if ((long) num < 0) {
                    putch('-', putdat);
                    num = -(long) num;
                }
                base = 10;
                goto signed_number;

                // unsigned decimal
            case 'u':
                base = 10;
                goto unsigned_number;

                // (unsigned) octal
            case 'o':
                // should do something with padding so it's always 3 octits
                base = 8;
                goto unsigned_number;

                // pointer
            case 'p':
                lflag = 1;
                putch('0', putdat);
                putch('x', putdat);
                /* fall through to 'x' */

                // (unsigned) hexadecimal
            case 'x':
                base = 16;
unsigned_number:
                num = getuint(&ap, lflag);
signed_number:
                printnum(putch, putdat, num, base, width, padc);
                break;

                // escaped '%' character
            case '%':
                putch(ch, putdat);
                break;

                // unrecognized escape sequence - just print it literally
            default:
bad:
                putch('%', putdat);
                fmt = last_fmt;
                break;
        }
    }
}

void printf_led(const char* fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);

    vprintfmt((void *)putchar, 0, fmt, ap);

    va_end(ap);
}

仿真结果显示

847278-20181229172454727-253980645.png

## 附:RISC-V 工具链

[1].Prebuilt RISC‑V GCC Toolchain
[2].elf2hex

转载于:https://www.cnblogs.com/OneFri/p/10197157.html

<think>好的,用户遇到了“testbench_vector_input_file选项不存在”的错误,需要解决方案。首先,我得确定这个选项是在哪个工具或环境中出现的。根据用户之前提到的Xilinx和Vivado的引用[2],可能是在使用Xilinx的FPGA开发工具时遇到的问题。接下来,我需要考虑这个选项不存在的原因。常见可能性包括版本差异、配置错误或路径问题。比如,某些选项可能在较新或旧版本的Vivado中被重命名或移除。用户可能在项目设置中找不到该选项,导致编译或仿真失败。 然后,解决方案可能涉及检查工具版本、查阅文档确认选项名称是否正确,或者寻找替代的配置方法。例如,用户可能需要手动添加输入文件路径,或者使用不同的设置来实现相同的功能。此外,确保项目配置正确,尤其是在切换调试和发布模式时,引用[1]提到路径设置会变化,可能需要重新配置包含路径。另外,用户可能需要检查测试平台文件是否正确引用,或者是否使用了过时的脚本。如果选项确实已被弃用,官方文档或论坛可能有迁移指南。建议用户查看Xilinx的帮助文档,因为引用[2]提到其文档组织良好,可能找到相关信息。 最后,生成相关问题需要考虑用户可能遇到的后续问题,比如版本兼容性、路径配置或其他类似错误,帮助用户全面排查。</think>关于"testbench_vector_input_file选项不存在"错误的解决方案,可能涉及以下原因及解决方法: 1. **版本兼容性检查** - Vivado不同版本(如2018.x/2020.x/2022.x)的测试平台配置选项存在差异。建议通过`Help > Documentation`查看当前版本支持的选项列表[^2] - 使用`report_property [current_fileset]`命令可列出当前支持的所有文件集属性 2. **替代配置方法** ```tcl # 手动添加矢量输入文件路径 add_files -fileset sim_1 -norecurse /path/to/input_vector.txt set_property source_mgmt_mode DisplayOnly [current_project] ``` 这等价于图形界面中的"Add Sources"操作,但提供更直接的路径控制 3. **工程模式转换** - 当从debug模式切换到release模式时,需重新配置仿真文件路径: 1. `Project > Build Options > Compiler > Preprocessor` 2. 在`Include Search Path`添加测试矢量文件目录[^1] 3. 在`Simulation Sources`属性页验证文件可见性 4. **脚本语法验证** ```tcl # 正确语法示例 launch_simulation -scripts_only -testbench [get_files tb_top.v] \ -generic "testbench_vector_input_file=../../vectors/input.txt" ``` 注意相对路径应基于工程根目录,使用`pwd`命令验证当前路径
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值