C代码调用printf
时,打印信息显示在哪个IO上,由pringf
调用的底层代码决定;软件C中的printf默认在terminal上打印;对于嵌入式C, 运行在开发板上的code,可以借助target自己的显示IO,如LCD屏,将打印信息直接显示在LCD屏上;如果target没有显示IO,也可以retarget到host端的terminal上;simulation仿真时,运行的C代码需要借助主机host的IO,将打印信息显示在simulation terminal上;常见的方式有以下几种:
- 仿照实际硬件操作,操作UART,GPIO等外设传递字符串,在平台内监测外设接口,调用系统函数$display, $write等打印到terminal;
- 构建
tube
实现打印,相比1效率更高; - 当仿真运行的不是RTL,而是FastModel时,可以借助
semihost
机制,利用IDE的界面打印;
完整的可运行代码可以参考:
百度网盘链接:https://pan.baidu.com/s/1_t2KNywKyMNO62w6b0y7Zw
密码:csdn
UART打印
// Retarget.c
// 对printf函数retarget处理
// 调用UartPutc(ch);
struct __FILE { int handle; };
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f) {
return (UartPutc(ch));
}
cmsdk_uart_capture_ard.v
中捕获字符串。
Tube打印
直接通过ahb/axi总线往reserved region写数据,在平台中监测并打印;
支持不定参数,需要调用<stdarg.h>
;
如果需要打印大量信息,建议对信息进行分类,中间通过类似查表法的方式来处理;
//common.h
#include <stdarg.h>
#include <stdint.h>
#define write_addr(a,v) ((*(volatile uint32_t *)(a)) = (v))
#define read_addr(a) (*(volatile uint32_t *)(a))
#define TUBE_BASE_ADDR (0x2f000000)
#define sim_char(v) write_addr(TUBE_BASE_ADDR+4,v)
#define sim_dec(v) write_addr(TUBE_BASE_ADDR+8,v)
#define sim_hex(v) write_addr(TUBE_BASE_ADDR+12,v)
#define sim_bin(v) write_addr(TUBE_BASE_ADDR+16,v)
#define SIM_INFO_TAG (0x5a5a0001)
#define SIM_WARNING_TAG (0x5a5a0002)
#define SIM_ERROR_TAG (0x5a5a0003)
#define SIM_FATAL_TAG (0x5a5a0004)
#define SIM_MSG_TAG (0x5a5a0005)
#define LF_VAL (10)
#define CR_VAL (13)
#define set_print_tag(v) write_addr(TUBE_BASE_ADDR+20,v)
#define sim_event(v) write_addr(TUBE_BASE_ADDR+24,v)
#define SV2C_HS_ADDR 0xfffc
#define wait_sv2c_event(FLAG,CLEAR) \
do { \
if(sv2c_event[FLAG] == 0){ \
while(read_addr(SV2C_HS_ADDR) != FLAG) \
{ \
delay(10); \
} \
} \
if(CLEAR) \
sv2c_event[FLAG] = 0; \
else \
sv2c_event[FLAG] = 1; \
} while(0)
extern uint32_t sv2c_event[10];
extern va_list sim_print(va_list list, char *format,uint32_t tag);
extern void sim_info(char* format, ...);
extern void sim_warning(char* format, ...);
extern void sim_error(char* format, ...);
extern void sim_fatal(char* format, ...);
// common.c
#include "common.h"
uint32_t sv2c_event[10] = {0,0,0,0,0,0,0,0,0,0};
va_list sim_print(va_list list, char *format,uint32_t tag)
{
char *char_h;
__asm volatile(
"cpsid i \t\n"
"cpsid f \t\n"
);
set_print_tag(tag);
while(*format !='\0')
{
if(*format == '%')
{
format++;
switch(*format)
{
case 'd':
sim_dec(va_arg(list,int));
break;
case 'x':
sim_hex(va_arg(list,int));
break;
case 'h':
sim_hex(va_arg(list,int));
break;
case 'b':
sim_bin(va_arg(list,int));
break;
case 's':
char_h = va_arg(list,char*);
while(*char_h !='\0')
{
sim_char(*char_h);
char_h++;
}
break;
}
format++;
}
else
{
sim_char(*format);
format++;
}
}
set_print_tag(SIM_MSG_TAG);
__asm volatile(
"cpsie i \t\n"
"cpsie f \t\n"
);
return list;
}
void sim_info(char* format, ...)
{
va_list list;
va_start(list,format);
list = sim_print(list,format,SIM_INFO_TAG);
va_end(list);
}
void sim_warning(char* format, ...)
{
va_list list;
va_start(list,format);
list = sim_print(list,format,SIM_WARNING_TAG);
va_end(list);
}
void sim_error(char* format, ...)
{
va_list list;
va_start(list,format);
list = sim_print(list,format,SIM_ERROR_TAG);
va_end(list);
}
void sim_fatal(char* format, ...)
{
va_list list;
va_start(list,format);
list = sim_print(list,format,SIM_FATAL_TAG);
va_end(list);
}
C代码调用sim_info
sim_warning
sim_error
sim_fatal
,UVM侧相应使用UVM_INFO
UVM_WARNING
UVM_ERROR
UVM_FATAL
实现打印;
event_sync
C和UVM的事件同步,可以通过以下几种方式:
- CPU的中断或者事件信号
- 通过Tube组件实现
后仿,低功耗仿真需要做一些修改,示例代码还未添加!!!
完整的可运行代码可以参考:
百度网盘链接:https://pan.baidu.com/s/1_t2KNywKyMNO62w6b0y7Zw
密码:csdn