;;******************************* ;;***** RS-232 keyboard monitor ;;******************************* ;To be included into a program under test. ;************************************ ; keyboard monitor and optional receive ISR ;returns a user char UNLESS the char is "esc" or entry was via rcall .def RXtemp=r29 ;a temp register .def RXparm=r28 ;subroutine parameter .def RXsave=r27 ;save the SREG .equ npush=5 ;the number of saved registers in RXisr Monitor: ;save processor status push ZH push ZL push RXtemp push RXparm push RXsave in RXsave, SREG sbis USR, RXC ;is a char available rjmp RXcmd ;if not go to cmd handler in RXparm, UDR ;get the character cpi RXparm, 0x1b ;is the char an "esc" breq RXcmd ;if so go to cmd handler ;###### ;Uncomment the next MOV if your program expects to have the receive-done ;ISR return a character. You can also put other code here, perhaps ;a pointer increment or detection. rcall keypressed ;###### RXexit: out SREG, RXsave ;restore proc status pop RXsave pop RXparm ;restore program state pop RXtemp pop ZL pop ZH reti ;back to pgm ; ;************************************** ; monitor command interperter RXcmd: ldi RXparm, 0x0d ;emit "cr" for a prompt rcall RXputc ldi RXparm, 0x0a ;emit "lf" for a prompt rcall RXputc ldi RXparm, '>' ;emit ">" for a prompt rcall RXputc ;wait for a command char rcall RXgetc ;is it a go command? RXgo: cpi RXparm, 'g' ;if so return to user code brne RXreg rcall RXputc ;echo the 'g' cbi UCR, TXCIE ;clear single-step isr sbi USR, TXC ;and its flag breq RXexit ;is it a reg read command? RXreg: cpi RXparm, 'r' ;dump a register brne RXregW rcall RXputc ;echo the 'r' rcall RXget2digit ;find out which reg cpi RXparm, 32-npush ;is the reg stored on the stack brge _stkreg mov ZL, RXparm ;if not, just read it back clr ZH ld RXparm, Z ;remember that 0-1f is reg rcall RXput2char rjmp RXcmd _stkreg:in ZL, SPL ;if the reg is stacked compute the address in ZH, SPH ;on the stack subi RXparm, 32-npush-1 ;regs were stacked in numerical order add ZL, RXparm ;stack offset clr RXparm adc ZH, RXparm ld RXparm, Z rcall RXput2char rjmp RXcmd ;is is a register write command? RXregW: cpi RXparm, 'R' ;write a register brne RXmem rcall RXputc ;echo the 'R' rcall RXget2digit ;find out which reg mov ZL, RXparm ;store register number in ZL ldi RXparm, '=' ;prompt with a equal sign rcall RXputc rcall RXget2digit ;get the new reg value cpi ZL, 32-npush ;is the reg stored on the stack? brge _stkrgw ;if not, just write it clr ZH ;ZL already has reg number st Z, RXparm ;remember that 0-1f is reg rjmp RXcmd _stkrgw:mov RXtemp, RXparm ;RXtemp has new reg value mov RXparm, ZL ;RXparm now has reg number in ZL, SPL ;if the reg is stacked compute the address in ZH, SPH ;on the stack subi RXparm, 32-npush-1 ;regs were stacked in numerical order add ZL, RXparm ;stack offset clr RXparm adc ZH, RXparm st Z, RXtemp rjmp RXcmd ;memory read RXmem: cpi RXparm, 'm' brne RXmemw rcall RXputc ;echo rcall RXget2digit ;get a 4 digit address mov ZH, RXparm rcall RXget2digit mov ZL, RXparm ld RXparm, Z ;load mem data rcall RXput2char rjmp RXcmd ;memory write RXmemw: cpi RXparm, 'M' brne RXio rcall RXputc ;echo rcall RXget2digit ;get a 4 digit address mov ZH, RXparm rcall RXget2digit mov ZL, RXparm ldi RXparm, '=' ;prompt with a equal sign rcall RXputc rcall RXget2digit ;get the new memory value st Z, RXparm ;now store it rjmp RXcmd ;i/o register read RXio: cpi RXparm, 'i' brne RXiow rcall RXputc ;echo rcall RXget2digit subi RXparm, -0x20 ;i/o register offset mov ZL, RXparm ;pointer to i/o reg clr ZH ld RXparm, Z ;now get it rcall RXput2char rjmp RXcmd ;i/o register write RXiow: cpi RXparm, 'I' brne RXsreg rcall RXputc ;echo rcall RXget2digit subi RXparm, -0x20 ;i/o register offset mov ZL, RXparm ;pointer to i/o reg clr ZH ldi RXparm, '=' ;prompt with a equal sign rcall RXputc rcall RXget2digit ;get the new reg value st Z, RXparm ;now store it rjmp RXcmd ;get SREG RXsreg: cpi RXparm, 's' brne RXpc rcall RXputc ;echo mov Rxparm, RXsave ;get the saved SREG rcall RXput2char rjmp RXcmd ;get the program counter RXpc: cpi RXparm, 'p' brne RXpcw rcall RXputc ;echo in ZL, SPL ;get prog counter from the stack in ZH, SPH ldd RXparm, Z+npush+1 ;stack offset to high byte of PC rcall RXput2char ldd RXparm, Z+npush+2 ;stack offset to low byte of PC rcall RXput2char2 rjmp RXcmd ;write the program counter RXpcw: cpi RXparm, 'P' brne RXstep rcall RXputc ;echo the P ldi RXparm, '=' ;prompt with a equal sign rcall RXputc rcall RXget2digit ;high order PC in ZL, SPL ;get prog counter from the stack in ZH, SPH std Z+npush+1, RXparm ;stack offset to high byte of PC rcall RXget2digit std Z+npush+2, RXparm ;stack offset to low byte of PC rjmp RXcmd RXstep: cpi RXparm, 't' brne RXz rcall RXputc ;echo in ZL, SPL ;get prog counter from the stack in ZH, SPH ldd RXparm, Z+npush+1 ;stack offset to high byte of PC rcall RXput2char ldd RXparm, Z+npush+2 ;stack offset to low byte of PC rcall RXput2char2 ldi RXparm, ' ' ;ascii space rcall RXputc sbi UCR, TXCIE ;kick-start TX complete interrupt _twait: sbis USR, TXC ;and wait for the TX complete rjmp _twait ;bit to be true rjmp RXexit RXz: cpi RXparm, 'z' brne RXhuh rcall RXputc ;echo z in ZL, SPL ;get z-register from the stack in ZH, SPH ldd RXparm, Z+npush ;stack offset to ZH rcall RXput2char ldd RXparm, Z+npush-1 ;stack offset to ZL rcall RXput2char2 ldd RXparm, Z+npush ;now get Z again ldd RXtemp, Z+npush-1 mov ZH, RXparm mov ZL, RXtemp ;push r0 ;lpm ;mov RXparm, r0 ;pop r0 ;rcall RXput2char ld RXparm, Z ;print the memory pointed to by z rcall RXput2char rjmp RXcmd ;unknown command trap RXhuh: ldi RXparm, '?' rcall RXputc rjmp RXcmd ; ;********************************************* ;utility routine to output one char ;enter with char in RXparm RXputc: sbis USR, UDRE ;wait until clear then send one char rjmp RXputC out UDR, RXparm ret ;utility routine to input one char ;exit with char in RXparm RXgetc: sbis USR, RXC ;wait until ready then get one char rjmp RXgetc in RXparm, UDR ret ;utility routine to make a ascii char into a hex value ;enter with char in RXparm RXcharTohex: cpi RXparm, 'a' brge _aboveA cpi RXparm, '0' ;error check-- is digit <'0'? brge _n1 rjmp RXcmd _n1: cpi RXparm, ':' ;error check -- is digit <':' brlt _n2 rjmp RXcmd ;if here then digit is 0 to 9 _n2: subi RXparm, '0' ret _aboveA: cpi RXparm, 'g' ;error check -- is digit>'f' brlt _ab1 rjmp RXcmd _ab1: subi RXparm, 'a'-10 ret ;utility routine to input rwo ascii chars and ; convert into a hex value returned in RXparm RXget2digit: rcall RXgetc ;get the highorder reg # nibble rcall RXputc ;echo it rcall RXcharTohex ;convert to hex swap RXparm ;make it the highorder bits mov RXtemp, RXparm ;and save it rcall RXgetc ;get the loworder reg # nibble rcall RXputc rcall RXcharTohex or RXparm, RXtemp ;combine high and low nibbles ret ;utility routine to output two ascii chars given a ;hex value in RXparm RXput2char: mov RXtemp, RXparm ;a copy ldi RXparm, '=' ;a delimiter rcall RXputc ;print the delimiter mov RXparm, RXtemp ;restore input RXput2char2: ;entry used only for the second byte of PC dump mov RXtemp, RXparm andi RXparm, 0xf0 ;mask high digits swap RXparm ;and make them loworder cpi RXparm, 10 ;numbers or letters? brge _f8f1 subi RXparm, -'0' ;convert a numeric digit to ascii rjmp _f8tx1 _f8f1: subi RXparm, -'a'+10 ;convert a letter to ascii _f8tx1: rcall RXputc mov RXparm, RXtemp ;now repeat for the other digit andi RXparm, 0x0f cpi RXparm, 10 brge _f8f2 subi RXparm, -'0' rjmp _f8tx2 _f8f2: subi RXparm, -'a'+10 _f8tx2: rcall RXputc ret ;***********************************