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\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);
}

仿真结果显示

附:RISC-V 工具链


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

posted @ 2018-12-29 17:26  乔_木  阅读(1201)  评论(0编辑  收藏  举报