;:ts=8 ; Variables in RAM .equ inbuf,8 ; input buffer, loc 8-16 .equ bufsize,7 .equ bufptr,16 ; input buffer pointer .equ tokentbl,17 ; token table, loc 18- .equ tableptr,23 ; first token after $NAME is at 24. .equ stack,108 ; after end of token table .equ pdefault,0xff ; default value to keep in P0 ; On reset, the 8031 starts executing code at address 0. .org 0x0 ; CPU initialization ; ------------------ ; Initialize CPU registers. start: mov IE,#0 ; Disable interrupts mov IP,#0 mov SP,#stack mov PSW,#0 ; Registers at 0H mov TCON,#0 ; Disable timers mov PCON,#0 ; Initialize other registers. mov P0,#pdefault mov P1,#pdefault mov P2,#pdefault mov P3,#0xff ; Serial port initialization ; -------------------------- ; Set both timers to free running, 8 bit auto reload. mov TMOD,#0x22 ; Start baud rate generator and initialize serial port. mov TH1,#0xfd setb TCON.6 mov SCON,#0x52 ; The token table is in RAM starting at 'tokentbl'. ; Each token is a bunch of ASCII characters followed ; by a zero. The end of the table is indicated ; by two zeros. ; Store the "$NAME" token that always occurs first ; in the table. mov dptr,#namecmd mov r1,#tokentbl ncloop: clr a movc a,@a+dptr mov @r1,a inc r1 inc dptr jnz ncloop ; Store the extra zero, so the table currently only ; contains the $NAME token. mov @r1,a ; Main loop. Print "Button? " prompt: mov dptr,#buttonmsg lcall puts ; Get an input line mov r4,#inbuf+bufsize lcall getline ; Save the buffer pointer mov 4,r1 ; Match it against the token table. mov r1,#tokentbl lcall matchtoken jz nothard ; Check for 1, which is the $NAME command dec a jz name_cmd ; Convert 1-12 to 0-22 dec a rl a sjmp got_resetnum ; If zero is returned and the last character in ; the buffer is an "S", delete it and try again. nothard: mov r0,4 cjne r0,#inbuf,not0 sjmp badcmd not0: dec r0 mov a,@r0 lcall toupper cjne a,#'S',badcmd clr a mov @r0,a mov r1,#tokentbl lcall matchtoken ; If zero is returned, it didn't match anything so ; display the list of valid tokens and try again. jz badcmd dec a jnz got_soft badcmd: lcall prttokens sjmp prompt buttonmsg: .byte "Button? ",0 namecmd: .byte "$NAME",0 ; Got a soft reset. Convert 2-13 to 1-23 got_soft: rl a dec a sjmp got_resetnum ; Got a valid token. #1 is the $NAME token. Handle ; it here. name_cmd: mov r2,#1 ; Token number mov r0,#tableptr ; Pointer into token table ; Loop: Display the token number nameloop: mov a,r2 mov B,#10 div ab jz not10 add a,#'0' ; convert to ASCII lcall putchar not10: mov a,B add a,#'0' ; convert to ASCII lcall putchar mov a,#'?' lcall putchar mov a,#' ' lcall putchar ; Get a string mov r4,#inbuf+bufsize-1 lcall getline ; If null string, ask for it again mov r1,#inbuf mov a,@r1 jz nameloop ; Copy it into the token table cnloop: mov a,@r1 lcall toupper mov @r0,a inc r0 jz nextname ; Check for terminating zero inc r1 sjmp cnloop ; Loop until all tokens are done nextname: inc r2 cjne r2,#13,nameloop ; Store the extra terminating zero and go back to the top mov @r0,a ljmp prompt ; Enter here with a number 0-23 in A, indicating the ; port bit to be pulsed. got_resetnum: mov r1,a ; Convert the low 3 bits of A into a bit map anl a,#0x07 mov dptr,#bittbl movc a,@a+dptr mov r0,a ; Zap the right reset mov a,r1 anl a,#0x18 cjne a,#0,notp0 mov P0,r0 sjmp del notp0: cjne a,#1,notp1 mov P1,r0 sjmp del notp1: mov P2,r0 ; Delay a small fraction of a second del: mov r1,#16 mov r2,#0 delay: djnz r2,delay djnz r1,delay ; And restore the port to its old value. mov P0,#pdefault mov P1,#pdefault mov P2,#pdefault ; Print "Done." and go back to the top. mov dptr,#donemsg lcall puts ljmp prompt donemsg: .byte "Done.",13,10,0 bittbl: .byte 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f ; Subroutine to display the valid tokens. prttokens: mov dptr,#tokenstr lcall puts mov r0,#tableptr tkloop: mov a,@r0 jz tkdone tkloop2: mov a,@r0 jz nxttk lcall putchar inc r0 sjmp tkloop2 nxttk: inc r0 mov a,#32 lcall putchar sjmp tkloop tkdone: mov dptr,#tokenstr2 ljmp puts tokenstr: .byte "Hard resets: ",0 tokenstr2: .byte 13,10 .byte "Soft resets: Add 'S' to end of hard reset name." .byte 13,10,0 ; Subroutine to print a null-terminated string pointed to by DPTR puts: clr a movc a,@a+dptr jz prtdone prtwait: lcall putchar inc dptr sjmp puts prtdone: ret ; Token match subroutine. "bufptr" points to the token ; R1 points to the token table. ; Returns token number, or 0 if none matched. matchtoken: mov r2,#1 ; Outer loop: Check the first character of the token in ; the table. If zero, the end of the table has been ; reached. trynext: mov a,@r1 jz nomatch ; Point at the beginning of the word in the buffer. mov r0,bufptr matchloop: mov a,@r0 lcall toupper mov r3,a mov a,@r1 ; Loop until a mismatch occurs or the end of the word on ; the command line is reached. cjne a,3,mismatch jz gotmatch inc r1 inc r0 sjmp matchloop ; A mismatch occurred. Skip the rest of the token in the ; token table. mismatch: mov a,@r1 jz mmdone inc r1 sjmp mismatch ; Increment the token counter and try to match the next token ; in the table (to which DPTR now points). mmdone: inc r2 inc r1 sjmp trynext ; A match was obtained. Update the buffer pointer to point ; past the matched word, and return the token number. gotmatch: mov bufptr,r0 mov a,r2 nomatch: ret ; Subroutine to convert character in A to upper case. toupper: push ACC clr C subb a,#'a' jc notlower subb a,#26 jnc notlower pop ACC subb a,#1fh ret notlower: pop ACC ret ; Subroutine to output the character in A. putchar: jnb SCON.1,putchar mov SBUF,A clr SCON.1 ret ; Subroutine to input a character into A. ; Returns 0 if no character available. getchar: clr A jnb SCON.0,nochar mov a,SBUF clr SCON.0 clr ACC.7 ; Clear parity bit nochar: ret ; Subroutine to get a line of input into the input buffer ; Allows backspace with ^H or DEL and line delete with ^X. getline: mov r1,#inbuf gloop: lcall getchar jz gloop ; Check for backspace or rubout. cjne a,#8,notbs sjmp delchar notbs: cjne a,#127,notdel ; Delete a character, but only if the buffer is not empty. delchar: cjne r1,#inbuf,delit sjmp gloop delit: lcall do1del sjmp gloop ; Check for carriage return. If it is one, zero-terminate ; the buffer, echo a CRLF, initialize the input buffer ; pointer, and return. notdel: cjne a,#13,notcr clr a mov @r1,a mov a,#inbuf mov bufptr,a ljmp crlf ; Check for CTRL-X. If it is one, delete characters until ; nothing is left of the line. notcr: cjne a,#24,notctlx cloop: cjne r1,#inbuf,dloop sjmp gloop dloop: lcall do1del sjmp cloop ; That's it for the control characters. If the character ; isn't printable and hasn't been handled by now, get rid ; of it. notctlx: mov @r1,a anl a,#0e0h jz gloop ; Check if the input line is at maximum length already. ; If it is, don't advance the buffer pointer and don't ; echo the character. mov a,r1 clr c subb a,r4 jnc gloop ; Advance the buffer pointer and echo the character. mov a,@r1 inc r1 lcall putchar sjmp gloop ; Delete one character by decrementing the buffer pointer and ; printing . do1del: mov a,#8 lcall putchar mov a,#32 lcall putchar mov a,#8 lcall putchar dec r1 ret ; Subroutine to print carriage return and line feed. crlf: mov A,#13 lcall putchar mov A,#10 ljmp putchar