* 68HC11 Debug monitor for use with NOICE11 * * Copyright (c) 1992-1998 by John Hartman * * Modification History: * 14-Jun-93 JLH release version * 3-Aug-93 JLH improve I/O init documentation * 24-Aug-93 JLH correct error in IN and OUT, stack init (v1.2) * 12-May-94 JLH clarify TSTG paging info * 7-Nov-94 JLH correct typos in comments * 1-May-95 JLH correct error in RAMVEC usage (v1.3) * 19-Aug-97 JLH correct bug in COP and Clock Monitor handling * 25-Feb-98 JLH assemble with either Motorola or Dunfield * *============================================================================ * * To customize for a given target, you must change code in the * hardware equates, the string TSTG, and the routines RESET and REWDT. * You may or may not need to change GETCHAR, PUTCHAR, depending on * how peculiar your UART is. * * This file has been assembled with the Motorola Freeware assembler * available from the Motorola Freeware BBS and elsewhere. * * This file may also be assembled with the Dunfield assembler * * To add mapped memory support: * 1) Define map port MAPREG here * 2) Define or import map port RAM image MAPIMG here if MAPREG is * write only. (The application code must update MAPIMG before * outputing to MAPREG) * 3) Search for and modify MAPREG, MAPIMG, and REG_PAGE usage below * 4) In TSTG below edit "LOW AND HIGH LIMIT OF MAPPED MEM" * to appropriate range (typically 4000H to 07FFFH for two-bit MMU) * *============================================================================ * * Hardware definitions CHIP_RAM EQU $0000 START OF HC11 ON-CHIP RAM IO_START EQU $1000 START OF HC11 ON-CHIP I/O RAM_START EQU $0180 START OF MONITOR RAM ROM_START EQU $FC00 START OF MONITOR CODE HARD_VECT EQU $FFD6 START OF HARDWARE VECTORS * PAGE *============================================================================ * Define HC11 I/O register locations (68HC11A8) ORG IO_START H11PORTA RMB 1 ;X000 i/o port A RMB 1 ;X001 reserved H11PIOC RMB 1 ;X002 i/o port C control H11PORTC RMB 1 ;X003 i/o port C H11PORTB RMB 1 ;X004 i/o port B H11PORTCL RMB 1 ;X005 i/o port CL RMB 1 ;X006 reserved H11DDRC RMB 1 ;X007 data direction for port C H11PORTD RMB 1 ;X008 i/o port D H11DDRD RMB 1 ;X009 data direction for port D H11PORTE RMB 1 ;X00A input port E H11CFORC RMB 1 ;X00B compare force register H11OC1M RMB 1 ;X00C OC1 action mask register H11OC1D RMB 1 ;X00D OC1 action data register H11TCNT RMB 2 ;X00E timer counter register H11TIC1 RMB 2 ;X010 input capture register 1 H11TIC2 RMB 2 ;X012 input capture register 2 H11TIC3 RMB 2 ;X014 input capture register 3 H11TOC1 RMB 2 ;X016 output compare register 1 H11TOC2 RMB 2 ;X018 output compare register 2 H11TOC3 RMB 2 ;X01A output compare register 3 H11TOC4 RMB 2 ;X01C output compare register 4 H11TOC5 RMB 2 ;X01E output compare register 5 H11TCTL1 RMB 1 ;X020 timer control register 1 H11TCTL2 RMB 1 ;X021 timer control register 2 H11TMSK1 RMB 1 ;X022 main timer interrupt mask 1 H11TFLG1 RMB 1 ;X023 main timer interrupt flag 1 H11TMSK2 RMB 1 ;X024 misc timer interrupt mask 2 H11TFLG2 RMB 1 ;X025 misc timer interrupt flag 2 H11PACTL RMB 1 ;X026 pulse accumulator control register H11PACNT RMB 1 ;X027 pulse accumulator count register H11SPCR RMB 1 ;X028 SPI control register H11SPSR RMB 1 ;X029 SPI status register H11SPDR RMB 1 ;X02A SPI data in/out H11BAUD RMB 1 ;X02B SCI baud rate control H11SCCR1 RMB 1 ;X02C SCI control register 1 H11SCCR2 RMB 1 ;X02D SCI control register 2 H11SCSR RMB 1 ;X02E SCI status register H11SCDR RMB 1 ;X02F SCI data H11ADCTL RMB 1 ;X030 A to D control register H11ADR1 RMB 1 ;X031 A to D result 1 H11ADR2 RMB 1 ;X032 A to D result 2 H11ADR3 RMB 1 ;X033 A to D result 3 H11ADR4 RMB 1 ;X034 A to D result 4 H11BPROT RMB 1 ;X035 EEPROM block protect RMB 2 ;X036 reserved H11OPT2 RMB 1 ;X038 system configuration options 2 H11OPTION RMB 1 ;X039 system configuration options H11COPRST RMB 1 ;X03A arm/reset COP timer circutry H11PPROG RMB 1 ;X03B EEPROM programming control H11HPRIO RMB 1 ;X03C highest priority I-bit and misc. H11INIT RMB 1 ;X03D ram/io mapping register H11TEST1 RMB 1 ;X03E factory test control register H11CONFIG RMB 1 ;X03F COP, ROM, & EEPROM enables RMB 16 ;X040 reserved RMB 12 ;X050 reserved H11CSSTRH RMB 1 ;X05C Chip select clock stretch H11CSCTL RMB 1 ;X05D Chip select control H11CSGADR RMB 1 ;X05E General purpose CS address H11CSGSIZ RMB 1 ;X05F General purpose CS size * * *============================================================================ * HARDWARE PLATFORM CUSTOMIZATIONS *============================================================================ * * Put you UART equates here SER_STATUS EQU H11SCSR STATUS FROM SCI SER_RXDATA EQU H11SCDR DATA FROM SCI SER_TXDATA EQU H11SCDR DAT TO SCI RXRDY EQU $20 TXRDY EQU $40 TRANSMIT COMPLETE (FOR TURNOFF) * *============================================================================ * RAM definitions: ORG RAM_START * * RAM interrupt vectors (first in SEG for easy addressing, else move to * their own SEG) RAMVEC RMB 2*21 * * Initial user stack * (Size and location is user option - at least 9 bytes to accept an SWI!) * 68HC11 SP points at NEXT BYTE TO USE, rather than at last used byte * like most processors. Thus, init SP to TOP-1 of stack space RMB 63 INITSTACK RMB 1 * * Monitor stack * (Calculated use is at most 7 bytes. Leave plenty of spare) * 68HC11 SP points at NEXT BYTE TO USE, rather than at last used byte * like most processors. Thus, init SP to TOP-1 of stack space RMB 15 MONSTACK RMB 1 * * Target registers: order must match that in TRGHC11.C TASK_REGS REG_STATE RMB 1 REG_PAGE RMB 1 REG_SP RMB 2 REG_Y RMB 2 REG_X RMB 2 REG_B RMB 1 B BEFORE A, SO D IS LEAST SIG. FIRST REG_A RMB 1 REG_CC RMB 1 REG_PC RMB 2 TASK_REG_SZ EQU *-TASK_REGS * * Communications buffer * (Must be at least as long as the longer of TASK_REG_SZ or TSTG_SIZE. * At least 19 bytes recommended. Larger values may improve speed of NoICE * download and memory move commands.) COMBUF_SIZE EQU 128 DATA SIZE FOR COMM BUFFER COMBUF RMB 2+COMBUF_SIZE+1 BUFFER ALSO HAS FN, LEN, AND CHECK * RAM_END EQU * ADDRESS OF TOP+1 OF RAM * *=========================================================================== ORG ROM_START * * Power on reset RESET * * Set CPU mode to safe state SEI INTERRUPTS OFF (WE MAY JUMP HERE) CLRB STATE 0 = "RESET" BRA RES10 * *------------------------------------------------ * COP reset COP_ENT LDAB #4 STATE 4 = "COP" BRA RES10 * *------------------------------------------------ * Clock Fail reset CLOCK_ENT LDAB #3 STATE 3 = "Clock fail" * * Initialize HC11 hardware * * BE SURE THAT "B" REMAINS INTACT UNTIL IT IS STORED TO REG_STATE BELOW! RES10 * * Monitor assumes operation in either Normal Expanded or Special Test mode * The exact initialization required here will depend on which variant of * the 68HC11 you have, and on your hardware layout. The following is * basic, and may not be sufficient for your case. * *---------------------------------------------------------------------------- * The following writes must occur within first 64 cycles after end of reset * * CAUTION: DON'T USE I/O ADDRESS EQUATES UNTIL H11INIT IS WRITTEN * TO SET THE I/O BASE TO MATCH OUR EQUATES! * (Freeware assembler does not support parenthesis. Thus, compute * each nibble separately) CRAMLOC EQU CHIP_RAM/256 ON-CHIP RAM AT CHIP_RAM (HIGH NIBBLE) IOLOC EQU IO_START/4096 I/O REGS AT IO_START (LOW NIBBLE) LDAA #CRAMLOC+IOLOC LOCATION OF RAM, I/O *** STAA H11INIT STAA $103D USE THE POST-RESET ADDRESS! * * Save reset type (RESET, COP, or Clock Fail) STAB REG_STATE SAVE STATE * * NOW OK TO USE I/O ADDRESS EQUATES LDAA #$00 PRESCALE TO DIVIDE BY 1 STAA H11TMSK2 * LDAA #$13 IRQ LEVEL, OSC DELAY, LONG COP STAA H11OPTION *---------------------------------------------------------------------------- * * Possible additional special initialization * * H11CONFIG ;COP, ROM, & EEPROM enables * ;(read only except in special test mode. May need to * ;delay vefore programming in order to allow EEPROM * ;charge pump to come up to voltage) * H11HPRIO ;highest priority I-bit and misc - set mode * ;(writable only in special test mode) * * H11CSCTL ;Chip select control * H11CSGSIZ ;General purpose CS size * H11CSGADR ;General purpose CS address * H11CSSTRH ;Chip select clock stretch * * H11BPROT ;EEPROM block protect * H11PPROG ;EEPROM programming control * ;enable programming voltage to program CONFIG register * ;wait for voltage to stabilize before programming * *---------------------------------------------------------------------------- LDS #MONSTACK CLEAN STACK IS HAPPY STACK * * Initialize your UART here * (SCI at 19200 baud from 7.3728 Mhz crystal) * LDAA #$11 PRE-DIV BY 3; DIV BY2 * (SCI at 9600 baud from 8.0 Mhz crystal) LDAA #$30 STAA H11BAUD LDAA #$00 8 BIT DATA STAA H11SCCR1 LDAA #$0C TX AND RX ENABLED, NO INTS, NO WAKE STAA H11SCCR2 * *---------------------------------------------------------------------------- * * Initialize RAM interrupt vectors LDY #INT_ENTRY ADDRESS OF DEFAULT HANDLER LDX #RAMVEC POINTER TO RAM VECTORS LDAB #NVEC/2 NUMBER OF VECTORS RST10 STY 0,X SET VECTOR INX INX DECB BNE RST10 * * Initialize user registers LDD #INITSTACK STAA REG_SP+1 INIT USER'S STACK POINTER MSB STAB REG_SP LSB LDD #0 STD REG_PC STAA REG_A STAA REG_B STD REG_X STD REG_Y * * Initialize memory paging variables and hardware (if any) STAA REG_PAGE NO PAGE YET *;* STAA MAPIMG *;* STAA MAPREG set hardware map * * Initialize non-zero registers LDAA #$50 disable interrupts in user program STAA REG_CC * * Set function code for "GO". Then if we are here because of a reset * (such as a COP timeout) after being told to GO, we will come * back with registers so user can see the reset LDAA #FN_RUN_TARG STAA COMBUF JMP RETURN_REGS DUMP REGS, ENTER MONITOR * *=========================================================================== * Get a character to A * * Return A=char, CY=0 if data received * CY=1 if timeout (0.5 seconds) * * Uses 6 bytes of stack including return address * GETCHAR PSHX LDX #0 LONG TIMEOUT GC10 JSR REWDT PREVENT WATCHDOG TIMEOUT DEX *;* BEQ GC90 EXIT IF TIMEOUT *(Disable timeout in most cases...) LDAA SER_STATUS READ DEVICE STATUS ANDA #RXRDY BEQ GC10 NOT READY YET. * * Data received: return CY=0. data in A CLC CY=0 LDAA SER_RXDATA READ DATA PULX RTS * * Timeout: return CY=1 GC90 SEC CY=1 PULX RTS * *=========================================================================== * Output character in A * * Uses 5 bytes of stack including return address * PUTCHAR PSHA PC10 JSR REWDT PREVENT WATCHDOG TIMEOUT LDAA SER_STATUS CHECK TX STATUS ANDA #TXRDY TX READY ? BEQ PC10 PULA STAA SER_TXDATA TRANSMIT CHAR. RTS * *====================================================================== * Reset watchdog timer. Must be called at least once every little while * or COP interrupt will occur * * Uses 2 bytes of stack including return address * REWDT LDAA #$55 STAA H11COPRST LDAA #$AA STAA H11COPRST RTS * *====================================================================== * Response string for GET TARGET STATUS request * Reply describes target: TSTG FCB 3 2: PROCESSOR TYPE = 68HC11 FCB COMBUF_SIZE 3: SIZE OF COMMUNICATIONS BUFFER FCB 0 4: NO TASKING SUPPORT FCB 0,0 5,6: BOTTOM OF MAPPED MEM (LSB FIRST) FCB 0,0 7,8: TOP OF MAPPED MEM (LSB FIRST) FCB B1-B0 9 BREAKPOINT INSTR LENGTH B0 SWI 10+ BREKAPOINT INSTRUCTION B1 FCC '68HC11 monitor V1.3' DESCRIPTION, ZERO FCB 0 TSTG_SIZE EQU *-TSTG SIZE OF STRING * *====================================================================== * HARDWARE PLATFORM INDEPENDENT EQUATES AND CODE * * Communications function codes. FN_GET_STAT EQU $FF reply with device info FN_READ_MEM EQU $FE reply with data FN_WRITE_M EQU $FD reply with status (+/-) FN_READ_RG EQU $FC reply with registers FN_WRITE_RG EQU $FB reply with status FN_RUN_TARG EQU $FA reply (delayed) with registers FN_SET_BYTE EQU $F9 reply with data (truncate if error) FN_IN EQU $F8 input from port FN_OUT EQU $F7 output to port * FN_MIN EQU $F7 MINIMUM RECOGNIZED FUNCTION CODE FN_ERROR EQU $F0 error reply to unknown op-code * *=========================================================================== * Common handler for default interrupt handlers * Enter with A=interrupt code = processor state * All registers stacked, PC=next instruction INT_ENTRY STAA REG_STATE SAVE STATE * * Save registers from stack to reg block for return to master * Host wants least significant bytes first, so flip as necessary PULA STAA REG_CC CONDITION CODES PULA STAA REG_B PULA STAA REG_A PULA STAA REG_X+1 MSB PULA STAA REG_X LSB PULA STAA REG_Y+1 MSB PULA STAA REG_Y LSB * * If this is a breakpoint (state = 1), then back up PC to point at SWI * (If SWI2, SWI3, or another instruction is used for breakpoint, * then DEX multiple times to match B1-B0 in TSTG PULX PC AFTER INTERRUPT LDAA REG_STATE CMPA #1 BNE NOTBP BR IF NOT A BREAKPOINT DEX ELSE BACK UP TO POINT AT SWI LOCATION NOTBP XGDX TRANSFER PC TO D STAA REG_PC+1 MSB STAB REG_PC LSB TSX USER STACK POINTER PLUS 1 DEX MAKE IT JUST LIKE THE REAL SP XGDX STAB REG_SP SAVE USER'S STACK POINTER (LSB) STAA REG_SP+1 MSB * * Change to our own stack LDS #MONSTACK AND USE OURS INSTEAD * * Save memory page *;* LDAA MAPIMG GET CURRENT USER MAP LDAA #0 ... OR ZERO IF UNMAPPED TARGET STAA REG_PAGE SAVE USER'S PAGE * * Return registers to master JMP RETURN_REGS * *=========================================================================== * Main loop: wait for command frame from master * * Uses 7 bytes of stack before jump to handlers * MAIN LDS #MONSTACK CLEAN STACK IS HAPPY STACK LDX #COMBUF BUILD MESSAGE HERE * * First byte is a function code JSR GETCHAR GET A FUNCTION BCS MAIN JIF TIMEOUT: RESYNC CMPA #FN_MIN BLO MAIN JIF BELOW MIN: ILLEGAL FUNCTION STAA 0,X SAVE FUNCTION CODE INX * * Second byte is data byte count (may be zero) JSR GETCHAR GET A LENGTH BYTE BCS MAIN JIF TIMEOUT: RESYNC CMPA #COMBUF_SIZE BHI MAIN JIF TOO LONG: ILLEGAL LENGTH STAA 0,X SAVE LENGTH INX CMPA #0 BEQ MA80 SKIP DATA LOOP IF LENGTH = 0 * * Loop for data TAB SAVE LENGTH FOR LOOP MA10 JSR GETCHAR GET A DATA BYTE BCS MAIN JIF TIMEOUT: RESYNC STAA 0,X SAVE DATA BYTE INX DECB BNE MA10 * * Get the checksum MA80 JSR GETCHAR GET THE CHECKSUM BCS MAIN JIF TIMEOUT: RESYNC PSHA SAVE CHECKSUM * * Compare received checksum to that calculated on received buffer * (Sum should be 0) JSR CHECKSUM PULB ABA BNE MAIN JIF BAD CHECKSUM * * Process the message. LDX #COMBUF LDAA 0,X GET THE FUNCTION CODE LDAB 1,X GET THE LENGTH INX INX X POINTS AT DATA CMPA #FN_GET_STAT BEQ TARGET_STAT CMPA #FN_READ_MEM BEQ JREAD_MEM CMPA #FN_WRITE_M BEQ JWRITE_MEM CMPA #FN_READ_RG BEQ JREAD_REGS CMPA #FN_WRITE_RG BEQ JWRITE_REGS CMPA #FN_RUN_TARG BEQ JRUN_TARGET CMPA #FN_SET_BYTE BEQ JSET_BYTES CMPA #FN_IN BEQ JIN_PORT CMPA #FN_OUT BEQ JOUT_PORT * * Error: unknown function. Complain LDAA #FN_ERROR STAA COMBUF SET FUNCTION AS "ERROR" LDAA #1 JMP SEND_STATUS VALUE IS "ERROR" * * long jumps to handlers JREAD_MEM JMP READ_MEM JWRITE_MEM JMP WRITE_MEM JREAD_REGS JMP READ_REGS JWRITE_REGS JMP WRITE_REGS JRUN_TARGET JMP RUN_TARGET JSET_BYTES JMP SET_BYTES JIN_PORT JMP IN_PORT JOUT_PORT JMP OUT_PORT *=========================================================================== * * Target Status: FN, len * * Entry with A=function code, B=data size, X=COMBUF+2 * TARGET_STAT LDX #TSTG DATA FOR REPLY LDY #COMBUF POINTER TO RETURN BUFFER LDAB #TSTG_SIZE LENGTH OF REPLY STAB 1,Y SET SIZE IN REPLY BUFFER TS10 LDAA 0,X MOVE REPLY DATA TO BUFFER STAA 2,Y INX INY DECB BNE TS10 * * Compute checksum on buffer, and send to master, then return JMP SEND *=========================================================================== * * Read Memory: FN, len, page, Alo, Ahi, Nbytes * * Entry with A=function code, B=data size, X=COMBUF+2 * READ_MEM * * Set map *; LDAA 0,X *; STAA MAPIMG *; STAA MAPREG * * Get address LDAA 2,X MSB OF ADDRESS IN A LDAB 1,X LSB OF ADDRESS IN B XGDY ADDRESS IN Y * * Prepare return buffer: FN (unchanged), LEN, DATA LDAB 3,X NUMBER OF BYTES TO RETURN STAB COMBUF+1 RETURN LENGTH = REQUESTED DATA BEQ GLP90 JIF NO BYTES TO GET * * Read the requested bytes from local memory GLP LDAA 0,Y GET BYTE STAA 0,X STORE TO RETURN BUFFER INX INY DECB BNE GLP * * Compute checksum on buffer, and send to master, then return GLP90 JMP SEND *=========================================================================== * * Write Memory: FN, len, page, Alo, Ahi, (len-3 bytes of Data) * * Entry with A=function code, B=data size, X=COMBUF+2 * * Uses 6 bytes of stack * WRITE_MEM * * Set map *; LDAA 0,X *; STAA MAPIMG *; STAA MAPREG * * Get address LDAA 2,X MSB OF ADDRESS IN A LDAB 1,X LSB OF ADDRESS IN B XGDY ADDRESS IN Y * * Prepare return buffer: FN (unchanged), LEN, DATA LDAB COMBUF+1 NUMBER OF BYTES TO RETURN SUBB #3 MINUS PAGE AND ADDRESS BEQ WLP50 JIF NO BYTES TO PUT * * Write the specified bytes to local memory PSHB PSHX PSHY WLP LDAA 3,X GET BYTE TO WRITE STAA 0,Y STORE THE BYTE AT AAAA,Y INX INY DECB BNE WLP * * Compare to see if the write worked PULY PULX PULB WLP20 LDAA 3,X GET BYTE JUST WRITTEN CMPA 0,Y BNE WLP80 BR IF WRITE FAILED INX INY DECB BNE WLP20 * * Write succeeded: return status = 0 WLP50 LDAA #0 RETURN STATUS = 0 BRA WLP90 * * Write failed: return status = 1 WLP80 LDAA #1 * * Return OK status WLP90 JMP SEND_STATUS *=========================================================================== * * Read registers: FN, len=0 * * Entry with A=function code, B=data size, X=COMBUF+2 * READ_REGS * * Enter here from SWI after "RUN" and "STEP" to return task registers * CAUTION: in this case, assume no registers! RETURN_REGS LDY #TASK_REGS POINTER TO REGISTERS LDAB #TASK_REG_SZ NUMBER OF BYTES STAB COMBUF+1 SAVE RETURN DATA LENGTH * * Copy the registers LDX #COMBUF+2 POINTER TO RETURN BUFFER GRLP LDAA 0,Y GET BYTE TO A STAA 0,X STORE TO RETURN BUFFER INX INY DECB BNE GRLP * * Compute checksum on buffer, and send to master, then return JMP SEND *=========================================================================== * * Write registers: FN, len, (register image) * * Entry with A=function code, B=data size, X=COMBUF+2 * WRITE_REGS * LDAB COMBUF+1 NUMBER OF BYTES BEQ WRR80 JIF NO REGISTERS * * Copy the registers LDY #TASK_REGS POINTER TO REGISTERS WRRLP LDAA 0,X GET BYTE TO A STAA 0,Y STORE TO REGISTER RAM INX INY DECB BNE WRRLP * * Return OK status WRR80 LDAA #0 JMP SEND_STATUS *=========================================================================== * * Run Target: FN, len * * Entry with A=function code, B=data size, X=COMBUF+2 * RUN_TARGET * * Restore user's map *; LDAA REG_PAGE USER'S PAGE *; STAA MAPIMG SET IMAGE *; STAA MAPREG SET MAPPING REGISTER * * Switch to user stack LDAB REG_SP BACK TO USER STACK LDAA REG_SP+1 XGDX TO X INX PRE-CORRECT FOR TXS TXS SP = X-1 * * Restore registers LDAA REG_PC SAVE LS USER PC FOR RTI PSHA LDAA REG_PC+1 SAVE MS USER PC FOR RTI PSHA * LDAA REG_Y PSHA LDAA REG_Y+1 PSHA * LDAA REG_X PSHA LDAA REG_X+1 PSHA * LDAA REG_A PSHA LDAA REG_B PSHA * LDAA REG_CC SAVE USER CONDITION CODES FOR RTI PSHA * * Return to user RTI * *=========================================================================== * * Set target byte(s): FN, len { (page, alow, ahigh, data), (...)... } * * Entry with A=function code, B=data size, X=COMBUF+2 * * Return has FN, len, (data from memory locations) * * If error in insert (memory not writable), abort to return short data * * This function is used primarily to set and clear breakpoints * * Uses 3 bytes of stack * SET_BYTES LDY #COMBUF+1 POINTER TO RETURN BUFFER LDAA #0 STAA 0,Y SET RETURN COUNT AS ZERO INY POINT AT FIRST RETURN DATA BYTE LSRB LSRB LEN/4 = NUMBER OF BYTES TO SET BEQ SB99 JIF NO BYTES (COMBUF+1 = 0) * * Loop on inserting bytes SB10 PSHB SAVE LOOP COUNTER PSHY SAVE RETURN BUFFER POINTER * * Set map *; LDAA 0,X *; STAA MAPIMG *; STAA MAPREG * * Get address LDAA 2,X MSB OF ADDRESS IN A LDAB 1,X LSB OF ADDRESS IN B XGDY MEMORY ADDRESS IN Y * * Read current data at byte location LDAA 0,Y * * Insert new data at byte location LDAB 3,X GET BYTE TO STORE STAB 0,Y WRITE TARGET MEMORY * * Verify write CMPB 0,Y READ TARGET MEMORY PULY RESTORE RETURN PTR (CC'S INTACT) PULB RESTORE LOOP COUNTER (CC'S INTACT) BNE SB90 BR IF INSERT FAILED: ABORT * * Save target byte in return buffer STAA 0,Y INY ADVANCE TO NEXT RETURN BYTE INC COMBUF+1 COUNT ONE RETURN BYTE * * Loop for next byte INX STEP TO NEXT BYTE SPECIFIER INX INX INX CMPB COMBUF+1 BNE SB10 LOOP FOR ALL BYTES * * Return buffer with data from byte locations SB90 * * Compute checksum on buffer, and send to master, then return SB99 JMP SEND *=========================================================================== * * Input from port: FN, len, PortAddressLo, PAhi (=0) * * While the HC11 has no input or output instructions, we retain these * to allow write-without-verify * * Entry with A=function code, B=data size, X=COMBUF+2 * IN_PORT * * Get port address LDAA 1,X MSB OF ADDRESS IN A LDAB 0,X LSB OF ADDRESS IN B XGDY MEMORY ADDRESS IN Y * * Read the requested byte from local memory LDAA 0,Y * * Return byte read as "status" JMP SEND_STATUS *=========================================================================== * * Output to port: FN, len, PortAddressLo, PAhi (=0), data * * Entry with A=function code, B=data size, X=COMBUF+2 * OUT_PORT * * Get port address LDAA 1,X MSB OF ADDRESS IN A LDAB 0,X LSB OF ADDRESS IN B XGDY MEMORY ADDRESS IN Y * * Get data LDAA 2,X * * Write value to port STAA 0,Y * * Do not read port to verify (some I/O devices don't like it) * * Return status of OK LDAA #0 JMP SEND_STATUS *=========================================================================== * Build status return with value from "A" * SEND_STATUS STAA COMBUF+2 SET STATUS LDAA #1 STAA COMBUF+1 SET LENGTH BRA SEND *=========================================================================== * Append checksum to COMBUF and send to master * SEND JSR CHECKSUM GET A=CHECKSUM, X->checksum location NEGA STAA 0,X STORE NEGATIVE OF CHECKSUM * * Send buffer to master LDX #COMBUF POINTER TO DATA LDAB 1,X LENGTH OF DATA ADDB #3 PLUS FUNCTION, LENGTH, CHECKSUM SND10 LDAA 0,X JSR PUTCHAR SEND A BYTE INX DECB BNE SND10 * JMP MAIN BACK TO MAIN LOOP *=========================================================================== * Compute checksum on COMBUF. COMBUF+1 has length of data, * Also include function byte and length byte * * Returns: * A = checksum * X = pointer to next byte in buffer (checksum location) * B is scratched * * Uses 2 bytes of stack including return address * CHECKSUM LDX #COMBUF pointer to buffer LDAB 1,X length of message ADDB #2 plus function, length LDAA #0 init checksum to 0 CHK10 ADDA 0,X INX DECB BNE CHK10 loop for all RTS return with checksum in A *********************************************************************** * * Interrupt handlers to catch unused interrupts and traps * Registers are stacked. Jump through RAM vector using X, type in A * * This will affect only interrupt routines looking for register values! * * Our default handler uses the code in "A" as the processor state to be * passed back to the host. * SCI_ENT LDAA #20 ffd6 LDX RAMVEC+0 JMP 0,X * SPI_ENT LDAA #19 ffd8 LDX RAMVEC+2 JMP 0,X * PACE_ENT LDAA #18 ffda LDX RAMVEC+4 JMP 0,X * PACO_ENT LDAA #17 ffdc LDX RAMVEC+6 JMP 0,X * TOV_ENT LDAA #16 ffde LDX RAMVEC+8 JMP 0,X * TCOMP5_ENT LDAA #15 ffe0 LDX RAMVEC+10 JMP 0,X * TCOMP4_ENT LDAA #14 ffe2 LDX RAMVEC+12 JMP 0,X * TCOMP3_ENT LDAA #13 ffe4 LDX RAMVEC+14 JMP 0,X * TCOMP2_ENT LDAA #12 ffe6 LDX RAMVEC+16 JMP 0,X * TCOMP1_ENT LDAA #11 ffe8 LDX RAMVEC+18 JMP 0,X * TCAP3_ENT LDAA #10 ffea LDX RAMVEC+20 JMP 0,X * TCAP2_ENT LDAA #9 ffec LDX RAMVEC+22 JMP 0,X * TCAP1_ENT LDAA #8 ffee LDX RAMVEC+24 JMP 0,X * RTC_ENT LDAA #7 fff0 LDX RAMVEC+26 JMP 0,X * IRQ_ENT LDAA #6 fff2 LDX RAMVEC+28 JMP 0,X * * Non-RAM vectored SWI_ENTRY LDAA #1 JMP INT_ENTRY XIRQ_ENTRY LDAA #2 JMP INT_ENTRY ILLOP_ENT LDAA #5 JMP INT_ENTRY * * INTERRUPT VECTORS ORG HARD_VECT * * VECTORS THROUGH RAM VEC0 FDB SCI_ENT ffd6 FDB SPI_ENT ffd8 FDB PACE_ENT ffda FDB PACO_ENT ffdc FDB TOV_ENT ffde FDB TCOMP5_ENT ffe0 FDB TCOMP4_ENT ffe2 FDB TCOMP3_ENT ffe4 FDB TCOMP2_ENT ffe6 FDB TCOMP1_ENT ffe8 FDB TCAP3_ENT ffea FDB TCAP2_ENT ffec FDB TCAP1_ENT ffee FDB RTC_ENT fff0 FDB IRQ_ENT fff2 NVEC EQU *-VEC0 number of vector bytes * * The remaining interrupts are permanently trapped to the monitor FDB XIRQ_ENTRY fff4 (non-maskable interrupt) FDB SWI_ENTRY fff6 SWI/breakpoint FDB ILLOP_ENT fff8 illegal op-code FDB COP_ENT fffa Watchdog timeout FDB CLOCK_ENT fffc clock fail FDB RESET fffe reset * END RESET