* * 811bug EEPROM-based S19 loader for the 68hc811e2 MCU * * This program accepts S1-S9 records from the SCI and stores them at * the proper addresses in memory. It also accepts a minimum number of * commands from the serial port, to allow the user to execute the * downloaded commands from a comm program. * * * Declare a few I/O register addresses * iobase equ $1000 i/o regs start here porte equ $0a baud equ $2b sccr2 equ $2d scdr equ $2f scsr equ $2e latch equ $4000 special output port * * Define the stack address and a few vital RAM locations. * * This program configures the low-area RAM ($00 - $ff) as follows: * * $ff +--------+ <- Top of low-area RAM * | | 811bug variables reside here. * ramvecs +--------+ <- Top of RAM vector area * + $3c | | These addrs are targets of the 811bug * | | vectors; see fdbs at $ffc0 below. * | | * ramvecs +--------+ <- Bottom of RAM vector area * stkbeg +--------+ <- Top of 811bug stack area * | | The stack grows downward from here. * | | Reserve at least $10 bytes for stack. * | | * $9f +--------+ User program may use rest of low RAM. * | | * | | * $00 +--------+ <- Bottom of low-area RAM * stkbeg equ $af top of stack ramvecs equ stkbeg+1 jump vectors (takes $3c bytes) vars equ ramvecs+$3c addr of variables knt equ vars+0 byte variable addr equ vars+1 word variable chk equ vars+3 byte variable xqtaddr equ vars+4 word variable flag9 equ vars+6 byte variable * * Start of 811bug code. * * The '811e2 should be configured to have EEPROM from $f800 to $ffff. * This puts the vector addresses in EEPROM, so 811bug is always present. * org $f800 start of code * * Following powerup or reset, 811bug checks the state of port E, bit 7. * If that bit is high, control passes to the main loop in 811bug. If * that bit is low, control automatically jumps to address $8000. * * The jump to $8000 is blind; no check is made to ensure that code actually * exists there. This leaves plenty of time for the code at $8000 to alter * the time-sensitive I/O registers, if needed. * start clra special for my 'hc11 board staa latch must clear output port always! ldaa porte+iobase read digital port bpl main if bit 7 is high... xxqt jmp $8000 force start of user's prog * * This is the main entry point to 811bug. Each time control reaches * this point, the code reset the stack pointer and the SCI, then reloads * the low-RAM vectors. It also loads the 811bug variable xqtaddr with * the address found in the reset vector at $fffe. This effectively makes * 811bug the default program for use with the 'x' command. * * This code then prints out a simple hello message. * main clra special for my 'hc11 board staa latch must clear output port always! ldx #iobase point to i/o lds #stkbeg always reset stack ldaa #$30 set baud = 9600 staa baud,x ldaa #$0c turn on sci staa sccr2,x jsr setvecs setup vectors ldd $fffe get start of 811bug std xqtaddr use as default S9 addr ldy #hello point to string jsr prints print it * * This is the main loop for accepting input from the host and processing * commands. Commands are determined by the first letter following a CR. * LFs are always ignored when 811bug is looking for a command. * * Legal 811bug commands are: * * S marks the start of an S19 object record. The entire line is * treated as an S19 record, and is parsed and loaded into memory. * * x transfers control to the last legal execution address, as passed * in the most recent S9 record, or as set by the j command below. * * X transfers control to $8000, regardless of any S19 object records * previously sent. * * j assigns a jump address for use with a subsequent 'x' command as above. * The j must be followed immediately by a four-digit hex address, followed * immediately by a CR. The input cannot contain backspaces or other * cursor control characters, and it cannot contain embedded spaces or * tabs. * loop lds #stkbeg always reset stack ldx #iobase always point to i/o jsr crlf make it pretty loop1 jsr getche get first char cmpa #$0a LF? beq loop1 always ignore cmpa #'S' load S19 record? beq loads19 if so, do it cmpa #'x' execute prog? beq xqt branch if so cmpa #'X' execute at $8000? beq xxqt branch if so cmpa #'j' set jump addr? beq jmp branch if so cmpa #$0d empty line? beq loop if so, ignore it * * This code eats all incoming characters until a CR is detected. It then * displays a '?' as an error indicator, then returns to the top of the * loop for the next command. * eaterr bsr eatline error, waste the line error ldaa #'?' get error flag jsr outch send it bra loop and leave * * eatline -- eat all characters, without echo, until a CR * * This routine absorbs all incoming characters until a CR is reached. * This effectively ignores all text after an error has been detected. * eatline jsr getch grab a char (no echo) cmpa #$0d wait for CR beq eatlx loop until hit it jsr outch echo char bra eatline do some more eatlx rts * * xqt -- process the 'x' command * * This routine jumps to the address stored in 811bug variable xqtaddr. * xqt ldy xqtaddr get execution addr jmp 0,y and do it * * jmp -- process the 'j' command * * This routine collects a four-digit hex address and a terminating CR. * It then stores the address into the 811bug variable xqtaddr, for use * with a later 'x' command. * jmp jsr byte get MSB staa addr save it jsr byte get LSB staa addr+1 save it jsr getch get last char cmpa #$0d better be cr bne eaterr oops, that's bad ldd addr OK, get real addr std xqtaddr and save it bra loop do another one * * loads19 -- process an S19 record * * This routine reads the rest of an S-record, processing the characters * as needed. * * This routine supports the following S-records: * * S0 header record; ignored by 811bug. * * S1 16-bit data record; 811bug stores data into assigned addresses. * * S9 execution record; 811bug records the execution address in 811bug * variable xqtaddr for later use with the 'x' command. * * This routine automatically calculates and tests the checksum for each * record. Illegal records and any record with a bad checksum are flagged * to the user with an error indication. * * NOTE: 811bug does not currently verify that data written to a memory * address actually got there. * loads19 clr flag9 assume S1 record jsr getche grab next char cmpa #'0' S0 record? bne loads1 branch if not loads0 jsr eatline waste whole line bra loop get next line loads1 cmpa #'9' S9 record? bne loads2 no, try next one inc flag9 show S9 record bra loads4 continue processing loads2 cmpa #'1' S1 record? bne eaterr if not, error loads4 jsr byte get byte count staa knt save for now dec knt count this byte staa chk start checksum jsr byte get MSB of addr staa addr save addr adda chk add to checksum staa chk save it back dec knt count this byte jsr byte get LSB of addr staa addr+1 save addr adda chk add to checksum staa chk save it back ldy addr get addr dec knt count this byte loads3 beq loads5 if 0, all done jsr byte get data byte staa 0,y write to addr iny point to next addr adda chk add to checksum staa chk save it back dec knt count this byte bra loads3 go test knt loads5 jsr byte get checksum coma get one's comp cmpa chk does it match? bne loadsf branch if fail jsr eatline eat the rest tst flag9 was this S9 record? beq loadsx branch if S1 ldd addr get start address std xqtaddr save for execution loadsx jmp loop do next command loadsf jmp eaterr show bad record * * hexbin -- convert an ASCII character in AR to its binary value * * This routine expects an ASCII character in the A register. It converts * the character to uppercase, then converts it to a binary value from 0 * to $f. * * If this routine detects an illegal (non-hex) character, it automatically * jumps to eaterr to handle the error condition. * hexbin jsr ucase make it uppercase cmpa #'0' test low range blt hexnot branch if fail cmpa #'9' test decimal ble hexnmb found hex number cmpa #'A' test low hex blt hexnot branch if fail cmpa #'F' test high hex bgt hexnot branch if fail adda #9 set up for conversion hexnmb anda #$0f get binary value bra hexx time to leave hexnot jmp eaterr fail, show error hexx rts * * ucase -- convert an ASCII character in AR to uppercase * ucase cmpa #'a' check for low end blt ucasex leave if too low cmpa #'z' check for high end bgt ucasex leave if too high suba #$20 make it uppercase ucasex rts * * byte -- collect two ASCII hex characters and convert them to a byte * byte pshb save b jsr getche get a char bsr hexbin convert it asla move to MSB asla asla asla tab now save in b jsr getche get 2nd char bsr hexbin convert it aba make a byte of them pulb restore b rts * * getch -- get a character from the SCI; polling loop. * getch ldaa scsr,x get status anda #$20 anything there? beq getch loop until data ldaa scdr,x get the data rts * * getche -- get a character, with echo, from the SCI; polling loop. * getche bsr getch get a char bra outch and echo it * * crlf -- send a CR/LF sequence to the SCI * crlf ldaa #$0d get cr bsr outch send it ldaa #$0a get lf bra outch send it, then exit * * outch -- send a character to the SCI; polling loop. * outch tst scsr,x get status bpl outch loop until ready staa scdr,x send it rts * * prints -- print a string to the SCI * * This routine prints a text string to the SCI. The address of the * string is passed in the Y register, which is destroyed. The string * must be null-terminated. * prints ldaa 0,y get next char in string beq printsx leave if done bsr outch send it iny bump pointer bra prints do another printsx rts * * setvecs -- set up the RAM vectors * * This routine overwrites low RAM with jumps to the start of 811bug. * This means that subsequent unexpected interrupts should automatically * vector to 811bug, restarting the monitor. This isn't a foolproof * way to save a runaway program, but it is better than nothing. * setvecs pshx save xr ldx #ramvecs point to destination setv1 ldaa #$7e jump opcode staa 0,x put in ram inx point to next cell ldd #start default vector addr std 0,x put in ram inx bump pointer inx (twice for word) cpx #ramvecs+$3c reached the end? bne setv1 branch if not pulx rts hello fcb $0a,$0d fcc "811bug v1.0" fcb 0 org $ffd6 start of 68hc11 vectors fdb ramvecs+$00 sci fdb ramvecs+$03 spi fdb ramvecs+$06 paii fdb ramvecs+$09 paovi fdb ramvecs+$0c toi fdb ramvecs+$0f oc5i fdb ramvecs+$12 oc4i fdb ramvecs+$15 oc3i fdb ramvecs+$18 oc2i fdb ramvecs+$1b oc1i fdb ramvecs+$1e ic3i fdb ramvecs+$21 ic2i fdb ramvecs+$24 ic1i fdb ramvecs+$27 rtii fdb ramvecs+$2a irq fdb ramvecs+$2d xirq fdb ramvecs+$30 swi fdb start illegal op fdb start cop failure fdb ramvecs+$39 cop monitor failure fdb start reset end start