zoukankan      html  css  js  c++  java
  • SoC的Testbench中的简易bus_monitor(加入print函数)

    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
    ");
                #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] != '';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 == '')
                    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) != '' && (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);
    }
    
    

    仿真结果显示

    附:RISC-V 工具链


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

  • 相关阅读:
    SqlHelper.cs源代码,学习!
    Fiddler工具介绍一
    dhl:Linq之group by 学习 使用
    vpc2007上安装windows7
    (五) ViewEngine 深入解析与应用实例
    VirtualPC2007添加Shared Folder的方法for dos
    SQL Server 2005 无法连接数据库终极解决方案!
    switch……case里的case 同时定义多个值
    dhl:AjaxPro的使用后感
    ifram高度自适应,获取iframe元素,控制父页面
  • 原文地址:https://www.cnblogs.com/OneFri/p/10197157.html
Copyright © 2011-2022 走看看