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

最新文章

  1. iOS 开发不可缺少的工具
  2. 【hihoCoder】1082: 然而沼跃鱼早就看穿了一切
  3. ENode框架Conference案例分析系列之 - 上下文划分和领域建模
  4. Codeforces Round #222 (Div. 1) D. Developing Game 线段树有效区间合并
  5. Jquery异步上传图片
  6. Java算法-hash算法
  7. Sqlserver 远程连接的 TCP/IP 和 Named Pipes的区别
  8. Android——inflate 将一个xml中定义的布局找出来
  9. Mono 之 Jexus
  10. Debug with jdb
  11. hdu 5646 DZY Loves Partition 二分+数学分析+递推
  12. Webbench源代码分析(转载)
  13. MySQL实现分组取组内特定数据的功能
  14. 利用nodejs安装并运行express的三个坑
  15. php -- 4种嵌入标记
  16. apache提示没有设置 max-age or expires解决办法
  17. Spring Cloud Sleuth 服务跟踪
  18. 转: c#.net利用RNGCryptoServiceProvider产生任意范围强随机数的办法
  19. 微信小程序:设置页面计时自动跳转
  20. 20155207 实验四 《Android程序设计》实验报告

热门文章

  1. sublime 支持 vue 语法
  2. 51nod1004 n^n的末位数字
  3. 图片压缩优化kraken
  4. js中Object.defineProperties 定义一个在原对象可读可写的方法
  5. UVALive 5583 Dividing coins
  6. 洛谷——P1498 南蛮图腾
  7. [TypeScript] Shallow copy object by using spread opreator
  8. 使WordPress改域名后网站正常运行的方法
  9. worktools-git 工具的使用总结(3)
  10. Android学习笔记进阶18之画图并保存图片到本地