1
0
mirror of https://github.com/marqs85/ossc.git synced 2024-11-04 13:06:38 +00:00
ossc/software/sys_controller_bsp/HAL/src/alt_log_printf.c
2016-12-13 20:55:10 +02:00

480 lines
14 KiB
C

/* alt_log_printf.c
*
* This file implements the various C functions used for the
* alt_log logging/debugging print functions. The functions
* sit as is here - the job of hiding them from the compiler
* if logging is disabled is accomplished in the .h file.
*
* All the global variables for alt_log are defined here.
* These include the various flags that turn on additional
* logging options; the strings for assembly printing; and
* other globals needed by different logging options.
*
* There are 4 functions that handle the actual printing:
* alt_log_txchar: Actual function that puts 1 char to UART/JTAG UART.
* alt_log_repchar: Calls alt_log_txchar 'n' times - used by
* alt_log_private_printf for formatting.
* alt_log_private_printf:
* Stripped down implementation of printf - no floats.
* alt_log_printf_proc:
* Wrapper function for private_printf.
*
* The rest of the functions are called by the macros which
* were called by code in the other components. Each function
* is preceded by a comment, about which file it gets called
* in, and what its purpose is.
*
* author: gkwan
*/
/* skip all code if enable is off */
#ifdef ALT_LOG_ENABLE
#include <system.h>
#include <stdarg.h>
#include <string.h>
#ifdef __ALTERA_AVALON_JTAG_UART
#include "altera_avalon_jtag_uart.h"
#include <altera_avalon_jtag_uart_regs.h>
#endif
#include "sys/alt_log_printf.h"
/* strings for assembly puts */
char alt_log_msg_bss[] = "[crt0.S] Clearing BSS \r\n";;
char alt_log_msg_alt_main[] = "[crt0.S] Calling alt_main.\r\n";
char alt_log_msg_stackpointer[] \
= "[crt0.S] Setting up stack and global pointers.\r\n";
char alt_log_msg_cache[] = "[crt0.S] Inst & Data Cache Initialized.\r\n";
/* char array allocation for alt_write */
char alt_log_write_buf[ALT_LOG_WRITE_ECHO_LEN+2];
/* global variables for all 'on' flags */
/*
* CASE:368514 - The boot message flag is linked into the sdata section
* because if it is zero, it would otherwise be placed in the bss section.
* alt_log examines this variable before the BSS is cleared in the boot-up
* process.
*/
volatile alt_u32 alt_log_boot_on_flag \
__attribute__ ((section (".sdata"))) = ALT_LOG_BOOT_ON_FLAG_SETTING;
volatile alt_u8 alt_log_write_on_flag = ALT_LOG_WRITE_ON_FLAG_SETTING;
volatile alt_u8 alt_log_sys_clk_on_flag = ALT_LOG_SYS_CLK_ON_FLAG_SETTING;
volatile alt_u8 alt_log_jtag_uart_alarm_on_flag = \
ALT_LOG_JTAG_UART_ALARM_ON_FLAG_SETTING;
volatile alt_u8 alt_log_jtag_uart_isr_on_flag = \
ALT_LOG_JTAG_UART_ISR_ON_FLAG_SETTING;
volatile alt_u8 alt_log_jtag_uart_startup_info_on_flag = \
ALT_LOG_JTAG_UART_STARTUP_INFO_ON_FLAG_SETTING;
/* Global alarm object for recurrent JTAG UART status printing */
alt_alarm alt_log_jtag_uart_alarm_1;
/* Global ints for system clock printing and count */
volatile int alt_log_sys_clk_count;
volatile int alt_system_clock_in_sec;
/* enum used by alt_log_private_printf */
enum
{
pfState_chars,
pfState_firstFmtChar,
pfState_otherFmtChar
};
/* Function to put one char onto the UART/JTAG UART txdata register. */
void alt_log_txchar(int c,char *base)
{
/* Wait until the device is ready for a character */
while((ALT_LOG_PRINT_REG_RD(base) & ALT_LOG_PRINT_MSK) == 0)
;
/* And pop the character into the register */
ALT_LOG_PRINT_TXDATA_WR(base,c);
}
/* Called by alt_log_private_printf to print out characters repeatedly */
void alt_log_repchar(char c,int r,int base)
{
while(r-- > 0)
alt_log_txchar(c,(char*) base);
}
/* Stripped down printf function */
void alt_log_private_printf(const char *fmt,int base,va_list args)
{
const char *w;
char c;
int state;
int fmtLeadingZero = 0; /* init these all to 0 for -W warnings. */
int fmtLong = 0;
int fmtBeforeDecimal = 0;
int fmtAfterDecimal = 0;
int fmtBase = 0;
int fmtSigned = 0;
int fmtCase = 0; /* For hex format, if 1, A-F, else a-f. */
w = fmt;
state = pfState_chars;
while(0 != (c = *w++))
{
switch(state)
{
case pfState_chars:
if(c == '%')
{
fmtLeadingZero = 0;
fmtLong = 0;
fmtBase = 10;
fmtSigned = 1;
fmtCase = 0; /* Only %X sets this. */
fmtBeforeDecimal = -1;
fmtAfterDecimal = -1;
state = pfState_firstFmtChar;
}
else
{
alt_log_txchar(c,(char*)base);
}
break;
case pfState_firstFmtChar:
if(c == '0')
{
fmtLeadingZero = 1;
state = pfState_otherFmtChar;
}
else if(c == '%')
{
alt_log_txchar(c,(char*)base);
state = pfState_chars;
}
else
{
state = pfState_otherFmtChar;
goto otherFmtChar;
}
break;
case pfState_otherFmtChar:
otherFmtChar:
if(c == '.')
{
fmtAfterDecimal = 0;
}
else if('0' <= c && c <= '9')
{
c -= '0';
if(fmtAfterDecimal < 0) /* still before decimal */
{
if(fmtBeforeDecimal < 0)
{
fmtBeforeDecimal = 0;
}
else
{
fmtBeforeDecimal *= 10;
}
fmtBeforeDecimal += c;
}
else
{
fmtAfterDecimal = (fmtAfterDecimal * 10) + c;
}
}
else if(c == 'l')
{
fmtLong = 1;
}
else /* we're up to the letter which determines type */
{
switch(c)
{
case 'd':
case 'i':
doIntegerPrint:
{
unsigned long v;
unsigned long p; /* biggest power of fmtBase */
unsigned long vShrink; /* used to count digits */
int sign;
int digitCount;
/* Get the value */
if(fmtLong)
{
if (fmtSigned)
{
v = va_arg(args,long);
}
else
{
v = va_arg(args,unsigned long);
}
}
else
{
if (fmtSigned)
{
v = va_arg(args,int);
}
else
{
v = va_arg(args,unsigned int);
}
}
/* Strip sign */
sign = 0;
/* (assumes sign bit is #31) */
if( fmtSigned && (v & (0x80000000)) )
{
v = ~v + 1;
sign = 1;
}
/* Count digits, and get largest place value */
vShrink = v;
p = 1;
digitCount = 1;
while( (vShrink = vShrink / fmtBase) > 0 )
{
digitCount++;
p *= fmtBase;
}
/* Print leading characters & sign */
fmtBeforeDecimal -= digitCount;
if(fmtLeadingZero)
{
if(sign)
{
alt_log_txchar('-',(char*)base);
fmtBeforeDecimal--;
}
alt_log_repchar('0',fmtBeforeDecimal,base);
}
else
{
if(sign)
{
fmtBeforeDecimal--;
}
alt_log_repchar(' ',fmtBeforeDecimal,base);
if(sign)
{
alt_log_txchar('-',(char*)base);
}
}
/* Print numbery parts */
while(p)
{
unsigned char d;
d = v / p;
d += '0';
if(d > '9')
{
d += (fmtCase ? 'A' : 'a') - '0' - 10;
}
alt_log_txchar(d,(char*)base);
v = v % p;
p = p / fmtBase;
}
}
state = pfState_chars;
break;
case 'u':
fmtSigned = 0;
goto doIntegerPrint;
case 'o':
fmtSigned = 0;
fmtBase = 8;
goto doIntegerPrint;
case 'x':
fmtSigned = 0;
fmtBase = 16;
goto doIntegerPrint;
case 'X':
fmtSigned = 0;
fmtBase = 16;
fmtCase = 1;
goto doIntegerPrint;
case 'c':
alt_log_repchar(' ',fmtBeforeDecimal-1,base);
alt_log_txchar(va_arg(args,int),(char*)base);
break;
case 's':
{
char *s;
s = va_arg(args,char *);
alt_log_repchar(' ',fmtBeforeDecimal-strlen(s),base);
while(*s)
alt_log_txchar(*s++,(char*)base);
}
break;
} /* switch last letter of fmt */
state=pfState_chars;
}
break;
} /* switch */
} /* while chars left */
} /* printf */
/* Main logging printf function */
int alt_log_printf_proc(const char *fmt, ... )
{
va_list args;
va_start (args, fmt);
alt_log_private_printf(fmt,ALT_LOG_PORT_BASE,args);
return (0);
}
/* Below are the functions called by different macros in various components. */
/* If the system has a JTAG_UART, include JTAG_UART debugging functions */
#ifdef __ALTERA_AVALON_JTAG_UART
/* The alarm function in altera_avalon_jtag_uart.c.
* This function, when turned on, prints out the status
* of the JTAG UART Control register, every ALT_LOG_JTAG_UART_TICKS.
* If the flag is off, the alarm should never be registered, and this
* function should never run */
alt_u32 altera_avalon_jtag_uart_report_log(void * context)
{
if (alt_log_jtag_uart_alarm_on_flag) {
altera_avalon_jtag_uart_state* dev = (altera_avalon_jtag_uart_state*) context;
const char* header="JTAG Alarm:";
alt_log_jtag_uart_print_control_reg(dev, dev->base, header);
return ALT_LOG_JTAG_UART_TICKS;
}
else
{
/* If flag is not on, return 0 to disable future alarms.
* Should never be here, alarm should not be enabled at all. */
return 0;
}
}
void alt_log_jtag_uart_print_control_reg(altera_avalon_jtag_uart_state* dev, int base, const char* header)
{
unsigned int control, space, ac, wi, ri, we, re;
control = IORD_ALTERA_AVALON_JTAG_UART_CONTROL(base);
space = (control & ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_MSK) >>
ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_OFST;
we= (control & ALTERA_AVALON_JTAG_UART_CONTROL_WE_MSK) >>
ALTERA_AVALON_JTAG_UART_CONTROL_WE_OFST;
re= (control & ALTERA_AVALON_JTAG_UART_CONTROL_RE_MSK) >>
ALTERA_AVALON_JTAG_UART_CONTROL_RE_OFST;
ri= (control & ALTERA_AVALON_JTAG_UART_CONTROL_RI_MSK) >>
ALTERA_AVALON_JTAG_UART_CONTROL_RI_OFST;
wi= (control & ALTERA_AVALON_JTAG_UART_CONTROL_WI_MSK) >>
ALTERA_AVALON_JTAG_UART_CONTROL_WI_OFST;
ac= (control & ALTERA_AVALON_JTAG_UART_CONTROL_AC_MSK) >>
ALTERA_AVALON_JTAG_UART_CONTROL_AC_OFST;
#ifdef ALTERA_AVALON_JTAG_UART_SMALL
ALT_LOG_PRINTF(
"%s HW FIFO wspace=%d AC=%d WI=%d RI=%d WE=%d RE=%d\r\n",
header,space,ac,wi,ri,we,re);
#else
ALT_LOG_PRINTF(
"%s SW CirBuf = %d, HW FIFO wspace=%d AC=%d WI=%d RI=%d WE=%d RE=%d\r\n",
header,(dev->tx_out-dev->tx_in),space,ac,wi,ri,we,re);
#endif
return;
}
/* In altera_avalon_jtag_uart.c
* Same output as the alarm function above, but this is called in the driver
* init function. Hence, it gives the status of the JTAG UART control register
* right at the initialization of the driver */
void alt_log_jtag_uart_startup_info(altera_avalon_jtag_uart_state* dev, int base)
{
const char* header="JTAG Startup Info:";
alt_log_jtag_uart_print_control_reg(dev, base, header);
return;
}
/* In altera_avalon_jtag_uart.c
* When turned on, this function will print out the status of the jtag uart
* control register every time there is a jtag uart "almost-empty" interrupt. */
void alt_log_jtag_uart_isr_proc(int base, altera_avalon_jtag_uart_state* dev)
{
if (alt_log_jtag_uart_isr_on_flag) {
const char* header="JTAG IRQ:";
alt_log_jtag_uart_print_control_reg(dev, base, header);
}
return;
}
#endif /* __ALTERA_AVALON_JTAG_UART */
/* In alt_write.c
* When the alt_log_write_on_flag is turned on, this function gets called
* every time alt_write gets called. The first
* ALT_LOG_WRITE_ECHO_LEN characters of every printf command (or any command
* that eventually calls write()) gets echoed to the alt_log output. */
void alt_log_write(const void *ptr, size_t len)
{
if (alt_log_write_on_flag) {
int temp_cnt;
int length=(ALT_LOG_WRITE_ECHO_LEN>len) ? len : ALT_LOG_WRITE_ECHO_LEN;
if (length < 2) return;
strncpy (alt_log_write_buf,ptr,length);
alt_log_write_buf[length-1]='\n';
alt_log_write_buf[length]='\r';
alt_log_write_buf[length+1]='\0';
/* Escape Ctrl-D's. If the Ctrl-D gets sent it might kill the terminal
* connection of alt_log. It will get replaced by 'D'. */
for (temp_cnt=0;temp_cnt < length; temp_cnt++) {
if (alt_log_write_buf[temp_cnt]== 0x4) {
alt_log_write_buf[temp_cnt]='D';
}
}
ALT_LOG_PRINTF("Write Echo: %s",alt_log_write_buf);
}
}
/* In altera_avalon_timer_sc
* This function prints out a system clock is alive message
* every ALT_LOG_SYS_CLK_INTERVAL (in ticks). */
void alt_log_system_clock()
{
if (alt_log_sys_clk_on_flag) {
alt_log_sys_clk_count++;
if (alt_log_sys_clk_count > ALT_LOG_SYS_CLK_INTERVAL) {
alt_log_sys_clk_count = 0;
ALT_LOG_PRINTF("System Clock On %u\r\n",alt_system_clock_in_sec++);
}
}
}
#endif