mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-25 14:06:56 +01:00
796 lines
22 KiB
C
796 lines
22 KiB
C
#include <stdbool.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include "printf.h"
|
|
#include "zbs243.h"
|
|
#include "board.h"
|
|
|
|
typedef void (*StrFormatOutputFunc)(uint32_t param /* low byte is data, bits 24..31 is char */) __reentrant;
|
|
|
|
static __idata __at (0x00) unsigned char R0;
|
|
static __idata __at (0x01) unsigned char R1;
|
|
static __idata __at (0x02) unsigned char R2;
|
|
static __idata __at (0x03) unsigned char R3;
|
|
static __idata __at (0x04) unsigned char R4;
|
|
static __idata __at (0x05) unsigned char R5;
|
|
static __idata __at (0x06) unsigned char R6;
|
|
static __idata __at (0x07) unsigned char R7;
|
|
|
|
static uint8_t __xdata mCvtBuf[18];
|
|
|
|
|
|
//callback must be reentrant and callee_saves
|
|
#pragma callee_saves prvPrintFormat
|
|
void prvPrintFormat(StrFormatOutputFunc formatF, uint16_t formatD, const char __code *fmt, va_list vl) __reentrant __naked
|
|
{
|
|
//formatF is in DPTR
|
|
//sp[0..-1] is return addr
|
|
//sp[-2..-3] is formatD
|
|
//sp[-4..-5] is fmt
|
|
//sp[-6] is vl
|
|
|
|
__asm__ (
|
|
" push _R7 \n"
|
|
" push DPH \n" //push formatF
|
|
" push DPL \n"
|
|
" mov _R7, sp \n" //save place on stack where we stashed it so we can call it easily
|
|
" push _R4 \n"
|
|
" push _R3 \n"
|
|
" push _R2 \n"
|
|
" push _R1 \n"
|
|
" push _R0 \n"
|
|
|
|
" mov A, #-12 \n"
|
|
" add A, sp \n"
|
|
" mov R0, A \n"
|
|
//R0 now points to pushed params, for large values, we see high bytes first
|
|
// to get next byte, we need to DECEREMENT R0
|
|
|
|
" mov DPH, @R0 \n"
|
|
" dec R0 \n"
|
|
" mov DPL, @R0 \n"
|
|
" dec R0 \n"
|
|
" mov _R0, @R0 \n"
|
|
" dec R0 \n"
|
|
|
|
//now format string is in DPTR, and R0 points to the top byte of whatever was in the first param
|
|
|
|
//main loop: get a byte of the format string
|
|
"00001$: \n"
|
|
" clr A \n"
|
|
" movc A, @A + DPTR \n"
|
|
" inc DPTR \n"
|
|
//if zero, we're done
|
|
" jz 00098$ \n"
|
|
//if not '%', print it
|
|
" cjne A, #'%', 00097$ \n"
|
|
|
|
//we got a percent sign - init state for format processing
|
|
" mov R4, #0 \n" //bit flags:
|
|
// 0x01 = '*' = pointer provided instead of value (integers only)
|
|
// 0x02 = '0' = zero-pad (for numbers only)
|
|
// 0x04 = have pad-to length
|
|
// 0x08 = long
|
|
// 0x10 = long long
|
|
// 0x20 = signed print requested. also: need to print a negative (used to reuse hex printing for decimal once converted to bcd)
|
|
" mov R2, #0 \n" //padLen
|
|
|
|
//loop for format string ingestion
|
|
"00002$: \n"
|
|
" clr A \n"
|
|
" movc A, @A + DPTR \n"
|
|
" inc DPTR \n"
|
|
//if zero, we're done
|
|
" jz 00098$ \n"
|
|
//check for percent sign
|
|
" cjne A, #'%', 00003$ \n"
|
|
//fallthrough to print it and go read next non-format byte
|
|
//print a char in A, go read next format byte
|
|
"00097$: \n"
|
|
" lcall 00060$ \n"
|
|
" sjmp 00001$ \n"
|
|
|
|
//exit label - placed for easy jumping to
|
|
"00098$: \n"
|
|
" pop _R0 \n"
|
|
" pop _R1 \n"
|
|
" pop _R2 \n"
|
|
" pop _R3 \n"
|
|
" pop _R4 \n"
|
|
" pop DPL \n"
|
|
" pop DPH \n"
|
|
" pop _R7 \n"
|
|
" ret \n"
|
|
|
|
//continue to process format string - handle %c
|
|
"00003$: \n"
|
|
" cjne A, #'c', 00004$ \n"
|
|
" dec R0 \n" //param is pushed as int (16 bits)
|
|
" mov A, @R0 \n"
|
|
" dec R0 \n"
|
|
" sjmp 00097$ \n" //print and go read next non-format byte
|
|
|
|
//continue to process format string - handle %m
|
|
"00004$: \n"
|
|
" mov R3, A \n"
|
|
" orl A, #0x20 \n"
|
|
" cjne A, #'m', 00008$ \n"
|
|
|
|
//sort out which hexch charset to use
|
|
" mov A, R3 \n"
|
|
" anl A, #0x20 \n"
|
|
" rr A \n"
|
|
" mov R1, A \n"
|
|
|
|
//go, do
|
|
" push DPH \n"
|
|
" push DPL \n"
|
|
" lcall 00090$ \n" //read the short (__xdata) pointer - >DPTR
|
|
" mov R4, #8 \n" //byteSel
|
|
"00005$: \n"
|
|
" push DPH \n"
|
|
" push DPL \n"
|
|
" mov A, R4 \n"
|
|
" dec A \n"
|
|
" add A, DPL \n"
|
|
" mov DPL, A \n"
|
|
" mov A, DPH \n"
|
|
" addc A, #0 \n"
|
|
" mov DPH, A \n"
|
|
" movx A, @DPTR \n"
|
|
" mov R2, A \n"
|
|
" swap A \n"
|
|
" mov R3, #2 \n"
|
|
"00006$: \n"
|
|
" anl A, #0x0f \n"
|
|
" add A, R1 \n"
|
|
" mov DPTR, #00099$ \n"
|
|
" movc A, @A + DPTR \n"
|
|
" lcall 00060$ \n"
|
|
" mov A, R2 \n"
|
|
" djnz R3, 00006$ \n"
|
|
" pop DPL \n"
|
|
" pop DPH \n"
|
|
" djnz R4, 00007$ \n"
|
|
//done with mac addr
|
|
|
|
"00055$: \n"
|
|
" pop DPL \n"
|
|
" pop DPH \n"
|
|
" sjmp 00001$ \n"
|
|
//print colon and contimue mac addr printing
|
|
"00007$: \n"
|
|
" mov A, #':' \n"
|
|
" lcall 00060$ \n"
|
|
" sjmp 00005$ \n"
|
|
|
|
//continue to process format string - handle '*'
|
|
"00008$: \n"
|
|
" mov A, R3 \n"
|
|
" cjne A, #'*', 00009$ \n"
|
|
" cjne R2, #0, 00097$ \n" //only valid when no length/padding has been specified yet, else invalid specifier
|
|
" mov A, #0x01 \n" //"pointer mode"
|
|
"00010$: \n"
|
|
" orl A, R4 \n"
|
|
" mov R4, A \n"
|
|
" sjmp 00002$ \n" //get next format specifier now
|
|
|
|
//continue to process format string - handle '0'
|
|
"00009$: \n"
|
|
" cjne A, #'0', 00011$ \n"
|
|
" cjne R2, #0, 00011$ \n" //setting "zero pad" is only valid when pad length is zero
|
|
" mov A, #0x06 \n" //"have pad length" | "zero-pad"
|
|
" sjmp 00010$ \n" //orr A into R4, get next format specifier now
|
|
|
|
//continue to process format string - handle '1'...'9'
|
|
"00011$: \n"
|
|
" mov R3, A \n"
|
|
" add A, #-'0' \n"
|
|
" jnc 00012$ \n" //now 0..9 are valid
|
|
" add A, #-10 \n"
|
|
" jc 00012$ \n"
|
|
" add A, #10 \n" //get it back into 1..9 range
|
|
" mov R3, A \n"
|
|
" mov A, #10 \n"
|
|
" mov B, R2 \n"
|
|
" mul AB \n"
|
|
" add A, R3 \n"
|
|
" mov R2, A \n"
|
|
" mov A, #0x04 \n" //"have pad length"
|
|
" sjmp 00010$ \n" //orr A into R4, get next format specifier now
|
|
|
|
//continue to process format string - handle 'l'
|
|
"00012$: \n"
|
|
" cjne R3, #'l', 00014$ \n"
|
|
" mov A, R4 \n"
|
|
" anl A, #0x08 \n"
|
|
" jz 00013$ \n" //no "long" yet? set that
|
|
//have long - set long log
|
|
" mov A, #0x10 \n" //"long long"
|
|
" sjmp 00010$ \n" //orr A into R4, get next format specifier now
|
|
//first 'l' - set long
|
|
"00013$: \n"
|
|
" mov A, #0x08 \n" //"long"
|
|
" sjmp 00010$ \n" //orr A into R4, get next format specifier now
|
|
|
|
//continue to process format string - handle 's'
|
|
"00014$: \n"
|
|
" cjne R3, #'s', 00025$ \n"
|
|
" mov A, R4 \n"
|
|
" anl A, #0x08 \n"
|
|
" push DPH \n"
|
|
" push DPL \n"
|
|
" jnz 00015$ \n"
|
|
" lcall 00091$ \n" //get and resolve generic pointer into DPTR
|
|
" sjmp 00016$ \n"
|
|
"00015$: \n" //get short pointer into DPTR, record that it is to XRAM
|
|
" clr PSW.5 \n"
|
|
" clr PSW.1 \n"
|
|
" lcall 00090$ \n"
|
|
"00016$: \n" //pointer to string now in DPTR
|
|
//we have the string pointer in {DPTR,PSW}, let's see if we have padding to do
|
|
" mov A, R4 \n"
|
|
" anl A, #0x04 \n"
|
|
" jnz 00018$ \n"
|
|
//print string with no length restrictions
|
|
"00017$: \n"
|
|
" lcall 00095$ \n"
|
|
" jz 00055$ \n"
|
|
" lcall 00060$ \n"
|
|
" sjmp 00017$ \n"
|
|
|
|
//print string with length restrictions and/or padding
|
|
"00018$: \n"
|
|
" cjne R2, #0, 00019$ \n" //verify reqested len was not zero
|
|
" sjmp 00055$ \n"
|
|
|
|
"00019$: \n"
|
|
" lcall 00095$ \n"
|
|
" jz 00020$ \n"
|
|
" lcall 00060$ \n"
|
|
" djnz R2, 00019$ \n"
|
|
//we get here if we ran out of allowable bytes - we're done then
|
|
" ljmp 00055$ \n"
|
|
|
|
//just a trampoline for range issues
|
|
"00035$: \n"
|
|
" ljmp 00036$ \n"
|
|
|
|
//we need to pad with spaces
|
|
"00020$: \n"
|
|
" mov A, #' ' \n"
|
|
" lcall 00060$ \n"
|
|
" djnz R2, 00020$ \n"
|
|
" ljmp 00055$ \n"
|
|
|
|
//continue to process format string - handle 'x'/'X'
|
|
"00025$: \n"
|
|
" mov A, R3 \n"
|
|
" orl A, #0x20 \n"
|
|
" cjne A, #'x', 00035$ \n"
|
|
" push DPH \n"
|
|
" push DPL \n"
|
|
" lcall 00080$ \n" //get pointer to the number in DPTR, length in bytes in B
|
|
//save it
|
|
|
|
"00070$: \n"
|
|
" push DPH \n"
|
|
" push DPL \n"
|
|
|
|
//sort out how long it would be if printed, first get a pointer to the highest
|
|
" mov A, B \n"
|
|
" rl A \n"
|
|
" mov R1, A \n"
|
|
" rr A \n"
|
|
" add A, #0xff \n"
|
|
" add A, DPL \n"
|
|
" mov DPL, A \n"
|
|
" mov A, DPH \n"
|
|
" addc A, #0x00 \n"
|
|
" mov DPH, A \n"
|
|
"00026$: \n"
|
|
" lcall 00079$ \n"
|
|
" anl A, #0xf0 \n"
|
|
" jnz 00028$ \n"
|
|
" dec R1 \n"
|
|
" lcall 00079$ \n"
|
|
" jnz 00028$ \n"
|
|
" dec R1 \n"
|
|
//dec DPTR
|
|
" dec DPL \n"
|
|
" mov A, DPL \n"
|
|
" cjne A, #0xff, 00027$ \n"
|
|
" dec DPH \n"
|
|
"00027$: \n"
|
|
" djnz B, 00026$ \n"
|
|
|
|
//we now know how many digits the number is (in R1), except that it has "0" if the number if zero, we cannot have that
|
|
"00028$: \n"
|
|
" cjne R1, #0, 00029$ \n"
|
|
" inc R1 \n"
|
|
"00029$: \n" //we now finally have the full length of the digits
|
|
|
|
//if the number is negative (happens when we're printing decimals)
|
|
// the length of it is one more, also in case of zero-padding, we need to print the minus sign here now
|
|
" mov A, R4 \n"
|
|
" anl A, #0x20 \n"
|
|
" jz 00051$ \n"
|
|
" inc R1 \n" //the length is one more
|
|
" mov A, R4 \n"
|
|
" anl A, #02 \n" //if zero-padding, the negative comes now
|
|
" jz 00051$ \n"
|
|
" mov A, #'-' \n"
|
|
" lcall 00060$ \n"
|
|
"00051$: \n"
|
|
|
|
//sort out if we need padding at all and if there is space
|
|
" mov A, R4 \n"
|
|
" anl A, #0x04 \n"
|
|
" jz 00031$ \n" //no padding requested
|
|
//padding was requested len is in R2
|
|
" mov A, R2 \n"
|
|
" clr C \n"
|
|
" subb A, R1 \n"
|
|
" jc 00031$ \n" //pad-to len < number_len -> no padding needed
|
|
" jz 00031$ \n" //pad-to len == number_len -> no padding needed
|
|
" mov R2, A \n"
|
|
|
|
//sort out which character to use -> DPL
|
|
" mov A, R4 \n" //fancy way to create space/zero as needed
|
|
" anl A, #0x02 \n"
|
|
" swap A \n"
|
|
" rr A \n"
|
|
" add A, #0x20 \n"
|
|
" mov DPL, A \n"
|
|
|
|
//pad!
|
|
"00030$: \n"
|
|
" mov A, DPL \n"
|
|
" lcall 00060$ \n"
|
|
" djnz R2, 00030$ \n"
|
|
"00031$: \n"
|
|
|
|
//if the number is negative (happens when we're printing decimals)
|
|
// we made the length of it is one more, which we need to undo
|
|
// also in case of space-padding, we need to print the minus sign here now
|
|
" mov A, R4 \n"
|
|
" anl A, #0x20 \n"
|
|
" jz 00052$ \n"
|
|
" dec R1 \n" //the length is one less than we had increased it to
|
|
" mov A, R4 \n"
|
|
" anl A, #02 \n" //if space-padding, the negative comes now
|
|
" jnz 00052$ \n"
|
|
" mov A, #'-' \n"
|
|
" lcall 00060$ \n"
|
|
"00052$: \n"
|
|
|
|
//time to print the number itself
|
|
//sort out which hexch charset to use -> R2
|
|
" mov A, R3 \n"
|
|
" anl A, #0x20 \n"
|
|
" rr A \n"
|
|
" mov R2, A \n"
|
|
//re-get the number pointer
|
|
" pop DPL \n"
|
|
" pop DPH \n"
|
|
//currently DPTR points to the number low byte, R1 is now many digits we expect to print, R2 is the charset selection, R4 and R3 are free
|
|
//let's calculate how many bytes we expect to process -> R4
|
|
" mov A, R1 \n"
|
|
" inc A \n"
|
|
" clr C \n"
|
|
" rrc A \n"
|
|
" mov R4, A \n"
|
|
//let's repoint DPTR to the first byte we'll print in (remember we print 2 digits per byte)
|
|
" dec A \n"
|
|
" add A, DPL \n"
|
|
" mov DPL, A \n"
|
|
" mov A, DPH \n"
|
|
" addc A, #0x00 \n"
|
|
" mov DPH, A \n"
|
|
|
|
//decide if we need to print just a nibble of the high byte or the whole thing. Free up R1
|
|
" mov A, R1 \n"
|
|
" anl A, #0x01 \n"
|
|
" jz 00032$ \n"
|
|
|
|
//we're printing just the low nibble of the first byte - set up for it
|
|
" lcall 00079$ \n"
|
|
" mov R1, #1 \n"
|
|
" sjmp 00033$ \n"
|
|
|
|
//print loop
|
|
"00032$: \n"
|
|
" lcall 00079$ \n"
|
|
" mov R1, #2 \n"
|
|
" mov R3, A \n"
|
|
" swap A \n"
|
|
"00033$: \n"
|
|
" anl A, #0x0f \n"
|
|
" add A, R2 \n"
|
|
" push DPH \n"
|
|
" push DPL \n"
|
|
" mov DPTR, #00099$ \n"
|
|
" movc A, @A + DPTR \n"
|
|
" pop DPL \n"
|
|
" pop DPH \n"
|
|
" lcall 00060$ \n"
|
|
" mov A, R3 \n"
|
|
" djnz R1, 00033$ \n"
|
|
|
|
//dec DPTR
|
|
" dec DPL \n"
|
|
" mov A, DPL \n"
|
|
" cjne A, #0xff, 00034$ \n"
|
|
" dec DPH \n"
|
|
"00034$: \n"
|
|
" djnz R4, 00032$ \n"
|
|
|
|
//done!
|
|
" ljmp 00055$ \n"
|
|
|
|
//continue to process format string - handle 'd'
|
|
"00036$: \n"
|
|
" cjne R3, #'d', 00037$ \n"
|
|
" mov A, #0x20 \n"
|
|
" orl A, R4 \n"
|
|
" mov R4, A \n"
|
|
" sjmp 00040$ \n"
|
|
|
|
//continue to process format string - handle 'u'
|
|
"00037$: \n"
|
|
" cjne R3, #'u', 00038$ \n"
|
|
" sjmp 00040$ \n"
|
|
|
|
//no more format strings exist that we can handle - bail
|
|
"00038$: \n"
|
|
" ljmp 00001$ \n"
|
|
|
|
//handle decimal printing
|
|
"00040$: \n"
|
|
" push DPH \n"
|
|
" push DPL \n"
|
|
" lcall 00080$ \n" //get pointer to the number in DPTR, length in bytes in B
|
|
" push B \n"
|
|
|
|
//copy the number to the double-dabble storage at proper offset (0 for u64, 4 for u32, 6 for u16)
|
|
//we do this so that the dabble area always starts at the same place...
|
|
" mov A, #8 \n"
|
|
" clr C \n"
|
|
" subb A, B \n"
|
|
" add A, #_mCvtBuf \n"
|
|
" mov R1, A \n"
|
|
" clr A \n"
|
|
" addc A, #(_mCvtBuf >> 8) \n"
|
|
" mov R3, A \n"
|
|
"00041$: \n"
|
|
" lcall 00079$ \n"
|
|
" inc DPTR \n"
|
|
" lcall 00086$ \n"
|
|
" movx @DPTR, A \n"
|
|
" inc DPTR \n"
|
|
" lcall 00086$ \n"
|
|
" djnz B, 00041$ \n"
|
|
//leave DPTR pointing to dabble storage, past the number
|
|
" lcall 00086$ \n"
|
|
|
|
//we now have the top byte of the number in A, good time to check for negatives, if needed
|
|
" mov B, A \n"
|
|
" mov A, R4 \n"
|
|
" anl A, #0x20 \n"
|
|
" jz 00050$ \n" //unsigned printing requested
|
|
" mov A, B \n"
|
|
" anl A, #0x80 \n"
|
|
" jnz 00043$ \n" //is negative - we need to invert, 0x20 bit in R1 stays
|
|
//positive - 0x20 bit in R1 needs to go
|
|
" mov A, R4 \n"
|
|
" anl A, #~0x20 \n"
|
|
" mov R4, A \n"
|
|
" sjmp 00050$ \n"
|
|
|
|
//we need to negate the number
|
|
// but first we need a pointer to it, and its size
|
|
"00043$: \n"
|
|
" pop B \n"
|
|
" push B \n"
|
|
" mov A, #8 \n"
|
|
" clr C \n"
|
|
" subb A, B \n"
|
|
" add A, #_mCvtBuf \n"
|
|
" mov DPL, A \n"
|
|
" clr A \n"
|
|
" addc A, #(_mCvtBuf >> 8) \n"
|
|
" mov DPH, A \n"
|
|
|
|
//ok, now we are ready to negate it
|
|
" clr C \n"
|
|
"00049$: \n"
|
|
" movx A, @DPTR \n"
|
|
" mov R1, A \n"
|
|
" clr A \n"
|
|
" subb A, R1 \n"
|
|
" movx @DPTR, A \n"
|
|
" inc DPTR \n"
|
|
" djnz B, 00049$ \n"
|
|
|
|
//zero out the rest of the storage (10 bytes)
|
|
"00050$: \n"
|
|
" mov B, #10 \n"
|
|
" clr A \n"
|
|
"00042$: \n"
|
|
" movx @DPTR, A \n"
|
|
" inc DPTR \n"
|
|
" djnz B, 00042$ \n"
|
|
|
|
//calculate number of dabble steps
|
|
" pop A \n"
|
|
" swap A \n"
|
|
" rr A \n"
|
|
" mov R3, A \n"
|
|
|
|
//do the thing
|
|
"00044$: \n"
|
|
|
|
//dabble (10 iters for simplicity)
|
|
" mov DPTR, #(_mCvtBuf + 8) \n"
|
|
" mov B, #10 \n"
|
|
"00046$: \n"
|
|
" movx A, @DPTR \n"
|
|
" mov R1, A \n"
|
|
" anl A, #0x0f \n"
|
|
" add A,#-0x05 \n"
|
|
" mov A, R1 \n"
|
|
" jnc 00047$ \n"
|
|
" add A, #0x03 \n"
|
|
"00047$: \n"
|
|
" mov R1, A \n"
|
|
" anl A, #0xf0 \n"
|
|
" add A,#-0x50 \n"
|
|
" mov A, R1 \n"
|
|
" jnc 00048$ \n"
|
|
" add A, #0x30 \n"
|
|
"00048$: \n"
|
|
" movx @DPTR, A \n"
|
|
" inc DPTR \n"
|
|
" djnz B, 00046$ \n"
|
|
|
|
//double (18 iters for simplicity)
|
|
" mov DPTR, #_mCvtBuf \n"
|
|
" clr C \n"
|
|
" mov B, #18 \n"
|
|
"00045$: \n"
|
|
" movx A, @DPTR \n"
|
|
" rlc A \n"
|
|
" movx @DPTR, A \n"
|
|
" inc DPTR \n"
|
|
" djnz B, 00045$ \n"
|
|
|
|
" djnz R3, 00044$ \n"
|
|
|
|
//dabbling is done, print it now using hex routine
|
|
" mov DPTR, #(_mCvtBuf + 8) \n"
|
|
" mov B, #10 \n"
|
|
" clr PSW.5 \n" //it is now for sure in XRAM
|
|
" ljmp 00070$ \n"
|
|
|
|
//read short pointer from param stack
|
|
"00090$: \n"
|
|
" mov DPH, @R0 \n"
|
|
"00093$: \n"
|
|
" dec R0 \n"
|
|
" mov DPL, @R0 \n"
|
|
" dec R0 \n"
|
|
" ret \n"
|
|
|
|
//read and increment pointer of the type provided by 00091$ (in {DPTR,PSW}) into A. clobber nothing
|
|
"00095$: \n"
|
|
" jb PSW.5, 00066$ \n"
|
|
" jb PSW.1, 00067$ \n"
|
|
//XRAM
|
|
" movx A, @DPTR \n"
|
|
" inc DPTR \n"
|
|
" ret \n"
|
|
//CODE
|
|
"00066$: \n"
|
|
" clr A \n"
|
|
" movc A, @A+DPTR \n"
|
|
" inc DPTR \n"
|
|
" ret \n"
|
|
//IRAM
|
|
"00067$: \n"
|
|
" mov DPH, R0 \n"
|
|
" mov R0, DPL \n"
|
|
" mov A, @R0 \n"
|
|
" mov R0, DPH \n"
|
|
" inc DPL \n"
|
|
" ret \n"
|
|
|
|
//resolve generic pointer on param stack to an pointer in DPTR and flags in PSW.5 and PSW.1
|
|
//PSW.5 will be 0 and PSW.1 will be 0 for XRAM (PDATA goes here too)
|
|
//PSW.5 will be 1 and PSW.1 will be 0 for CODE
|
|
//PSW.5 will be 0 and PSW.1 will be 1 for IRAM
|
|
"00091$: \n"
|
|
" clr PSW.5 \n"
|
|
" clr PSW.1 \n"
|
|
" mov A, @R0 \n"
|
|
" dec R0 \n"
|
|
" jz 00090$ \n" //0x00: pointer type: xdata
|
|
" xrl A, #0x80 \n"
|
|
" jz 00094$ \n" //0x80: pointer type: code
|
|
" xrl A, #0xc0 \n"
|
|
" jz 00092$ \n" //0x40: pointer type: idata
|
|
//pdata
|
|
" mov DPH, _XPAGE \n"
|
|
" sjmp 00093$ \n"
|
|
//idata
|
|
"00092$: \n"
|
|
" setb PSW.1 \n"
|
|
" sjmp 00093$ \n"
|
|
//code
|
|
"00094$: \n"
|
|
" setb PSW.5 \n"
|
|
" sjmp 00090$ \n"
|
|
|
|
//read the pointer of the type that 00080$ returns (in DPTR) into A. clobber nothing
|
|
"00079$: \n"
|
|
" jnb PSW.5, 00078$ \n"
|
|
" push _R0 \n"
|
|
" mov R0, DPL \n"
|
|
" mov A, @R0 \n"
|
|
" pop _R0 \n"
|
|
" ret \n"
|
|
"00078$: \n"
|
|
" movx A, @DPTR \n"
|
|
" ret \n"
|
|
|
|
//get pointer to a number, might be pushed or might be pointed to, size might vary. return pointer to number's LOW byte in DPTR
|
|
"00080$: \n"
|
|
" mov A, R4 \n"
|
|
" anl A, #0x01 \n"
|
|
" jnz 00083$ \n"
|
|
//param is itself on stack - now we care about size, but either way, PSW.5 will be 1
|
|
" setb PSW.5 \n"
|
|
" mov B, #0 \n"
|
|
" mov A, R4 \n"
|
|
" anl A, #0x18 \n"
|
|
" jz 00081$ \n"
|
|
" anl A, #0x10 \n"
|
|
" jz 00082$ \n"
|
|
//long long (8 bytes) \n"
|
|
" setb B.2 \n"
|
|
" dec R0 \n"
|
|
" dec R0 \n"
|
|
" dec R0 \n"
|
|
" dec R0 \n"
|
|
//long (4 bytes)
|
|
"00082$: \n"
|
|
" setb B.1 \n"
|
|
" dec R0 \n"
|
|
" dec R0 \n"
|
|
//int (2 bytes) \n"
|
|
"00081$: \n"
|
|
" setb B.0 \n"
|
|
" dec R0 \n"
|
|
" mov DPL, R0 \n"
|
|
" dec R0 \n"
|
|
" inc B \n"
|
|
" ret \n"
|
|
//pointer it on stack itself, number is in xram, but we still need to provide the length
|
|
"00083$: \n"
|
|
" clr PSW.5 \n" //mark as "in xram"
|
|
" mov A, R4 \n"
|
|
" anl A, #0x18 \n"
|
|
" jz 00084$ \n"
|
|
" anl A, #0x10 \n"
|
|
" jz 00085$ \n"
|
|
//long long
|
|
" mov B, #8 \n"
|
|
" ljmp 00090$ \n"
|
|
//long
|
|
"00085$: \n"
|
|
" mov B, #4 \n"
|
|
" ljmp 00090$ \n"
|
|
//int
|
|
"00084$: \n"
|
|
" mov B, #2 \n"
|
|
" ljmp 00090$ \n"
|
|
|
|
//swap R3:R1 <-> DPH:DPL
|
|
"00086$: \n"
|
|
" xch A, DPH \n"
|
|
" xch A, R3 \n"
|
|
" xch A, DPH \n"
|
|
" xch A, DPL \n"
|
|
" xch A, R1 \n"
|
|
" xch A, DPL \n"
|
|
" ret \n"
|
|
|
|
/* putchar func
|
|
called via call. char is in A, R7 has pointer to stack as needed
|
|
can clobber B, CANNOT clobber DPTR
|
|
a mess because...8051
|
|
*/
|
|
"00060$: \n"
|
|
" push DPH \n"
|
|
" push DPL \n"
|
|
" push _R1 \n"
|
|
" push _R0 \n"
|
|
" mov _R0, R7 \n"
|
|
" mov DPL, @R0 \n"
|
|
" dec R0 \n"
|
|
" mov DPH, @R0 \n" //DPTR is now func ptr
|
|
" dec R0 \n"
|
|
" dec R0 \n"
|
|
" dec R0 \n"
|
|
" dec R0 \n"
|
|
" mov _R1, @R0 \n"
|
|
" dec R0 \n"
|
|
" mov _R0, @R0 \n" //R1:R0 is now "formatD"
|
|
" lcall 00061$ \n" //to set ret addr
|
|
" pop _R0 \n"
|
|
" pop _R1 \n"
|
|
" pop DPL \n"
|
|
" pop DPH \n"
|
|
" ret \n"
|
|
"00061$: \n"
|
|
" push DPL \n"
|
|
" push DPH \n"
|
|
" mov DPL, _R0 \n"
|
|
" mov DPH, _R1 \n"
|
|
" ret \n"
|
|
|
|
"00099$: \n"
|
|
" .ascii \"01234567\" \n"
|
|
" .ascii \"89ABCDEF\" \n"
|
|
" .ascii \"01234567\" \n"
|
|
" .ascii \"89abcdef\" \n"
|
|
);
|
|
(void)fmt;
|
|
(void)vl;
|
|
(void)formatF;
|
|
(void)formatD;
|
|
}
|
|
|
|
#pragma callee_saves prPrvPutchar
|
|
static void prPrvPutchar(uint32_t data) __reentrant
|
|
{
|
|
char ch = data >> 24;
|
|
|
|
if (ch == '\n')
|
|
dbgUartByte('\r');
|
|
dbgUartByte(ch);
|
|
}
|
|
|
|
void pr(const char __code *fmt, ...) __reentrant
|
|
{
|
|
va_list vl;
|
|
|
|
va_start(vl, fmt);
|
|
dbgUartOn();
|
|
prvPrintFormat(prPrvPutchar, 0, fmt, vl);
|
|
dbgUartOff();
|
|
va_end(vl);
|
|
}
|
|
|
|
#pragma callee_saves prPrvPutS
|
|
static void prPrvPutS(uint32_t data) __reentrant
|
|
{
|
|
char __xdata * __idata *strPP = (char __xdata * __idata *)data;
|
|
char ch = data >> 24;
|
|
|
|
*(*strPP)++ = ch;
|
|
}
|
|
|
|
void spr(char __xdata* out, const char __code *fmt, ...) __reentrant
|
|
{
|
|
char __xdata* outStart = out;
|
|
|
|
va_list vl;
|
|
|
|
va_start(vl, fmt);
|
|
prvPrintFormat(prPrvPutS, (uint16_t)&out, fmt, vl);
|
|
va_end(vl);
|
|
|
|
*out = 0;
|
|
}
|
|
|