Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
File Manager
/
chart-export-handler
/
Projet
/
Example
/
HC12
/
D60
/
NoICE
:
MON12D60.asm
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
* 68HC12 Debug monitor for use with NOICE12 * * Copyright (c) 2001 by John Hartman * * Modification History: * * Axiom modifications: * 1) ported to hc912d60, removed excess for A4 paging * *============================================================================ * 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. * * For more information, refer to the NoICE help file monitor.htm * * To enable banked or paged memory support * 1) Define page latch port PPAGE to match your target chip ($1035 on the A4) * 2) Search for and modify PPAGE and REG_PAGE usage below * 3) In TSTG below edit "LOW AND HIGH LIMIT OF PAGED MEM" * to appropriate range (8000H to BFFFH for the HC12's built-in banking) * * For more information, refer to the NoICE help file 2bitmmu.htm * * If you are using one of the boards shown below, just define the * appropriate symbol. * DEFINE ONLY ONE SYMBOL AT A TIME. * * 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 * *============================================================================ * Axiom CME12D60 * - Operates in either expanded wide or single-chip * - Comes with 64K of RAM * * Define operating memory map, registers are moved to * allow full 2K ram access CHIP_RAM EQU $0000 ;START OF HC12 ON-CHIP 2K RAM INITSTACK EQU $07FF+1 ;INIT USER STACK: TOP+1 OF ON-CHIP RAM CHIP_IO EQU $0800 ;START OF HC12 ON-CHIP I/O CHIP_EEPROM EQU $0C00 ;START OF HC12 ON-CHIP 1K EEPROM USER_VECTORS EQU $06C0 ;START OF Interrupt HARDWARE VECTORS RAM_START EQU $0700 ;START OF MONITOR RAM ROM_START EQU $FC00 ;START OF MONITOR CODE HARD_VECT EQU $FFC0 ;START OF HARDWARE VECTORS *============================================================================ * Define HC12 I/O register locations (68HC12D60) * PORTA: EQU CHIP_IO+0 ;port A = Address lines A8 - A15 PORTB: EQU CHIP_IO+1 ;port B = Address lines A0 - A7 DDRA: EQU CHIP_IO+2 ;port A direction register DDRB: EQU CHIP_IO+3 ;port A direction register PORTE: EQU CHIP_IO+8 ;port E = mode,IRQandcontrolsignals DDRE: EQU CHIP_IO+9 ;port E direction register PEAR: EQU CHIP_IO+$A ;port E assignments MODE: EQU CHIP_IO+$B ;Mode register PUCR: EQU CHIP_IO+$C ;port pull-up control register RDRIV: EQU CHIP_IO+$D ;port reduced drive control register INITRM: EQU CHIP_IO+$10 ;Ram location register INITRG: EQU CHIP_IO+$11 ;Register location register INITEE: EQU CHIP_IO+$12 ;EEprom location register MISC: EQU CHIP_IO+$13 ;Miscellaneous Mapping control RTICTL: EQU CHIP_IO+$14 ;Real time clock control RTIFLG: EQU CHIP_IO+$15 ;Real time clock flag COPCTL: EQU CHIP_IO+$16 ;Clock operating properly control COPRST: EQU CHIP_IO+$17 ;COP reset register INTCR: EQU CHIP_IO+$1E ;interrupt control register HPRIO: EQU CHIP_IO+$1F ;high priority reg BRKCT0: EQU CHIP_IO+$20 ;Break control register BRKCT1: EQU CHIP_IO+$21 ;Break control register BRKAH: EQU CHIP_IO+$22 ; Break address register high BRKAL: EQU CHIP_IO+$23 ; Break address register low BRKDH: EQU CHIP_IO+$24 ; Break data register high BRKDL: EQU CHIP_IO+$25 ; Break data register low PORTG: EQU CHIP_IO+$28 ;port G = KEY PORT PORTH: EQU CHIP_IO+$29 ;port H = Key port DDRG: EQU CHIP_IO+$2A ;port G direction register DDRH: EQU CHIP_IO+$2B ;port H direction register KWIEG: EQU CHIP_IO+$2C ;Key wake-up port G enable KWIEH: EQU CHIP_IO+$2D ;Key wake-up port H enable KWIFG: EQU CHIP_IO+$2E ;Key wake-up port G flags KWIFH: EQU CHIP_IO+$2F ;Key wake-up port H flags SYNR: EQU CHIP_IO+$38 ; Synthesizer / multiplier register REFDV: EQU CHIP_IO+$39 ; Reference divider register CGTFLG: EQU CHIP_IO+$3A ; RESERVED PLLFLG: EQU CHIP_IO+$3B ; PLL flags register PLLCR: EQU CHIP_IO+$3C ; PLL control register CLKSEL: EQU CHIP_IO+$3D ; Clock select register SLOW: EQU CHIP_IO+$3E ; Slow mode divider register PWCLK: EQU CHIP_IO+$40 ;PWM clock register PWPOL: EQU CHIP_IO+$41 ;PWM clock select and polarity PWEN: EQU CHIP_IO+$42 ;PWM enable register PWPRES: EQU CHIP_IO+$43 ;PWM Prescale register PWSCAL0: EQU CHIP_IO+$44 ;PWM Scale 0 PWSCNT0: EQU CHIP_IO+$45 ;PWM scale counter 0 PWSCAL1: EQU CHIP_IO+$46 ;PWM scale 1 PWSCNT1: EQU CHIP_IO+$47 ;PWM scale counter 1 PWCNT0: EQU CHIP_IO+$48 ;PWM channel 0 counter PWCNT1: EQU CHIP_IO+$49 ;PWM channel 1 counter PWCNT2: EQU CHIP_IO+$4A ;PWM channel 2 counter PWCNT3: EQU CHIP_IO+$4B ;PWM channel 3 counter PWPER0: EQU CHIP_IO+$4C ;PWM channel 0 period PWPER1: EQU CHIP_IO+$4D ;PWM channel 1 period PWPER2: EQU CHIP_IO+$4E ;PWM channel 2 period PWPER3: EQU CHIP_IO+$4F ;PWM channel 3 period PWDTY0: EQU CHIP_IO+$50 ;PWM channel 0 duty cycle PWDTY1: EQU CHIP_IO+$51 ;PWM channel 1 duty cycle PWDTY2: EQU CHIP_IO+$52 ;PWM channel 2 duty cycle PWDTY3: EQU CHIP_IO+$53 ;PWM channel 3 duty cycle PWCTL: EQU CHIP_IO+$54 ;PWM control register PWTST: EQU CHIP_IO+$55 ;reserved PORTP: EQU CHIP_IO+$56 ;Port P data register DDRP: EQU CHIP_IO+$57 ;Port P data direction register ATDCTL0: EQU CHIP_IO+$60 ;ADC control 0 (reserved) ATDCTL1: EQU CHIP_IO+$61 ;ADC control 1 (reserved) ATDCTL2: EQU CHIP_IO+$62 ;ADC control 2 ATDCTL3: EQU CHIP_IO+$63 ;ADC control 3 ATDCTL4: EQU CHIP_IO+$64 ;ADC control 4 ATDCTL5: EQU CHIP_IO+$65 ;ADC control 5 ATDSTAT: EQU CHIP_IO+$66 ;ADC status register hi ;ATDSTAT EQU CHIP_IO+$67 ;ADC status register lo ATDTEST: EQU CHIP_IO+$68 ;ADC test (reserved) ;ATDTEST EQU CHIP_IO+$69 PORTAD: EQU CHIP_IO+$6F ;port ADC = input only ADR0H: EQU CHIP_IO+$70 ;ADC result 0 register ADR1H: EQU CHIP_IO+$72 ;ADC result 1 register ADR2H: EQU CHIP_IO+$74 ;ADC result 2 register ADR3H: EQU CHIP_IO+$76 ;ADC result 3 register ADR4H: EQU CHIP_IO+$78 ;ADC result 4 register ADR5H: EQU CHIP_IO+$7A ;ADC result 5 register ADR6H: EQU CHIP_IO+$7C ;ADC result 6 register ADR7H: EQU CHIP_IO+$7E ;ADC result 7 register TIOS: EQU CHIP_IO+$80 ;timer input/output select CFORC: EQU CHIP_IO+$81 ;timer compare force OC7M: EQU CHIP_IO+$82 ;timer output compare 7 mask OC7D: EQU CHIP_IO+$83 ;timer output compare 7 data TCNT: EQU CHIP_IO+$84 ;timer counter register hi ;TCNT EQU CHIP_IO+$85 ;timer counter register lo TSCR: EQU CHIP_IO+$86 ;timer system control register TQCR: EQU CHIP_IO+$87 ;reserved TCTL1: EQU CHIP_IO+$88 ;timer control register 1 TCTL2: EQU CHIP_IO+$89 ;timer control register 2 TCTL3: EQU CHIP_IO+$8A ;timer control register 3 TCTL4: EQU CHIP_IO+$8B ;timer control register 4 TMSK1: EQU CHIP_IO+$8C ;timer interrupt mask 1 TMSK2: EQU CHIP_IO+$8D ;timer interrupt mask 2 TFLG1: EQU CHIP_IO+$8E ;timer flags 1 TFLG2: EQU CHIP_IO+$8F ;timer flags 2 TC0: EQU CHIP_IO+$90 ;timer capture/compare register 0 ;TC0 EQU CHIP_IO+$91 TC1: EQU CHIP_IO+$92 ;timer capture/compare register 1 ;TC1 EQU CHIP_IO+$93 TC2: EQU CHIP_IO+$94 ;timer capture/compare register 2 ;TC2 EQU CHIP_IO+$95 TC3: EQU CHIP_IO+$96 ;timer capture/compare register 3 ;TC3 EQU CHIP_IO+$97 TC4: EQU CHIP_IO+$98 ;timer capture/compare register 4 ;TC4 EQU CHIP_IO+$99 TC5: EQU CHIP_IO+$9A ;timer capture/compare register 5 ;TC5 EQU CHIP_IO+$9B TC6: EQU CHIP_IO+$9C ;timer capture/compare register 6 ;TC6 EQU CHIP_IO+$9D TC7: EQU CHIP_IO+$9E ;timer capture/compare register 7 ;TC7 EQU CHIP_IO+$9F PACTL: EQU CHIP_IO+$A0 ;pulse accumulator controls PAFLG: EQU CHIP_IO+$A1 ;pulse accumulator flags PACN3: EQU CHIP_IO+$A2 ;pulse accumulator counter 3 PACN2: EQU CHIP_IO+$A3 ;pulse accumulator counter 2 PACN1: EQU CHIP_IO+$A4 ;pulse accumulator counter 1 PACN0: EQU CHIP_IO+$A5 ;pulse accumulator counter 0 MCCTL: EQU CHIP_IO+$A6 ;Modulus down conunter control MCFLG: EQU CHIP_IO+$A7 ;down counter flags ICPACR: EQU CHIP_IO+$A8 ;Input pulse accumulator control DLYCT: EQU CHIP_IO+$A9 ;Delay count to down counter ICOVW: EQU CHIP_IO+$AA ;Input control overwrite register ICSYS: EQU CHIP_IO+$AB ;Input control system control TIMTST: EQU CHIP_IO+$AD ;timer test register PORTT: EQU CHIP_IO+$AE ;port T = Timer port DDRT: EQU CHIP_IO+$AF ;port T direction register PBCTL: EQU CHIP_IO+$B0 ; Pulse accumulator B control PBFLG: EQU CHIP_IO+$B1 ; Pulse accumulator B flags PA3H: EQU CHIP_IO+$B2 ; Pulse Accumulator counter 3 PA2H: EQU CHIP_IO+$B3 ; Pulse Accumulator counter 2 PA1H: EQU CHIP_IO+$B4 ; Pulse Accumulator counter 1 pA0H: EQU CHIP_IO+$B5 ; Pulse Accumulator counter 0 MCCNT: EQU CHIP_IO+$B6 ; Modulus down counter register *MCCNTL: EQU CHIP_IO+$B7 ; low byte TCOH: EQU CHIP_IO+$B8 ; Capture 0 holding register TC1H: EQU CHIP_IO+$BA ; Capture 1 holding register TC2H: EQU CHIP_IO+$BC ; Capture 2 holding register TC3H: EQU CHIP_IO+$BE ; Capture 3 holding register SC0BDH: EQU CHIP_IO+$C0 ;sci 0 baud reg hi byte SC0BDL: EQU CHIP_IO+$C1 ;sci 0 baud reg lo byte SC0CR1: EQU CHIP_IO+$C2 ;sci 0 control1 reg SC0CR2: EQU CHIP_IO+$C3 ;sci 0 control2 reg SC0SR1: EQU CHIP_IO+$C4 ;sci 0 status reg 1 SC0SR2: EQU CHIP_IO+$C5 ;sci 0 status reg 2 SC0DRH: EQU CHIP_IO+$C6 ;sci 0 data reg hi SC0DRL: EQU CHIP_IO+$C7 ;sci 0 data reg lo SC1BDH: EQU CHIP_IO+$C8 ;sci 1 baud reg hi byte SC1BDL: EQU CHIP_IO+$C9 ;sci 1 baud reg lo byte SC1CR1: EQU CHIP_IO+$CA ;sci 1 control1 reg SC1CR2: EQU CHIP_IO+$CB ;sci 1 control2 reg SC1SR1: EQU CHIP_IO+$CC ;sci 1 status reg 1 SC1SR2: EQU CHIP_IO+$CD ;sci 1 status reg 2 SC1DRH: EQU CHIP_IO+$CE ;sci 1 data reg hi SC1DRL: EQU CHIP_IO+$CF ;sci 1 data reg lo SP0CR1: EQU CHIP_IO+$D0 ;spi 0 control1 reg SP0CR2: EQU CHIP_IO+$D1 ;spi 0 control2 reg SP0BR: EQU CHIP_IO+$D2 ;spi 0 baud reg SP0SR: EQU CHIP_IO+$D3 ;spi 0 status reg hi SP0DR: EQU CHIP_IO+$D5 ;spi 0 data reg PORTS: EQU CHIP_IO+$D6 ;port S = Serial port DDRS: EQU CHIP_IO+$D7 ;port S direction register PURDS: EQu CHIP_IO+$D9 ;port S pull-ups register EEMCR: EQU CHIP_IO+$F0 ;EEprom mode control EEPROT: EQU CHIP_IO+$F1 ;EEprom block protect reg EETST: EQU CHIP_IO+$F2 ;EEprom test register EEPROG: EQU CHIP_IO+$F3 ;EEprom program reg * Lots more registers to go.... * *============================================================================ * HARDWARE PLATFORM CUSTOMIZATIONS *============================================================================ * * Put you UART equates here * (These are for the SCI) SER_STATUS EQU SC0SR1 STATUS FROM SCI SER_RXDATA EQU SC0DRL DATA FROM SCI SER_TXDATA EQU SC0DRL DATA TO SCI RXRDY EQU $20 TXRDY EQU $80 TRANSMIT COMPLETE (FOR TURNOFF) * *============================================================================ * RAM interrupt vectors. Equivalent to vectors FFC0 to FFFF ORG USER_VECTORS RAMVEC RMB 2*32 * *============================================================================ * Monitor RAM definitions ORG RAM_START * * Target registers: order must match that in TRGHC12.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. Maximum 128.) COMBUF_SIZE EQU 128 DATA SIZE FOR COMM BUFFER COMBUF RMB 2+COMBUF_SIZE+1 BUFFER ALSO HAS FN, LEN, AND CHECK * * Don't let this overlap the user vectors... RAM_END EQU * ADDRESS OF TOP+1 OF RAM * *=========================================================================== ORG ROM_START * * On-chip I/O initialization. Each entry is (port, value) * Table ends with port=$FF. * * The monitor assumes operation in either Expanded or Special Expanded mode. * The exact initialization required here will depend on which variant of * the 68HC12 you have, and on your hardware layout. The following is * basic, and may not be sufficient for your case. * * Many of these registers can be written only once after reset. They are * set here, often to their default values, so that an errant user program * doesn't change them (and possibly lock up the target). If you want your * user program to be responsible for setting them, either remove this code, * or change to "special" mode, in which these registers can be written at * will. However, note that in special mode many registers must be written * TWICE, as the first write is ignored. * * CHIP SELECTS * If E is 8 MHz (16 MHz crystal), then 1 cycle is 125 nsec and * - 0 wait states requires 80 nsec access time * - 1 wait states requires 200 nsec access time * - 2 wait states requires 330 nsec access time * - 3 wait states requires 455 nsec access time * * Any "real" program should enable the COP. However, we disable it * for the convenience of your initial testing. * You should enable the clock monitor unless you are going to use * the STOP instruction for lowest power consumption. * * We have made internal bus operations visible, so that you can see them * with a scope or logic analyzer. For production systems, you may wish * to disable this in order to reduce emissions. * INIT_TABLE: FCB INITRM-CHIP_IO,$00 ;locate RAM FCB INITEE-CHIP_IO,CHIP_EEPROM/256+1 ;locate and enable EEPROM FCB COPCTL-CHIP_IO,$00 ;DISABLE CLOCK MONITOR, NO COP TIMEOUT * FCB PLLCR-CHIP_IO, $00 ; Force pll off * FCB CLKSEL-CHIP_IO,$00 ; Clock select is EXtal input FCB MODE-CHIP_IO, $F0 ;NORMAL EXPANDED WIDE, INVISIBLE BUS, E stretches FCB PEAR-CHIP_IO, $0C ;PE4=E, PE3=LSTRB, PE2=R/W FCB MISC-CHIP_IO, $74 ;Flash off, p-sel stretch = 3, mem = 1 INIT_TABLE_END: ;END OF TABLE * *====================================================================== * Response string for GET TARGET STATUS request * Reply describes target: TSTG FCB 13 ;2: PROCESSOR TYPE = 68HC12 FCB COMBUF_SIZE ;3: SIZE OF COMMUNICATIONS BUFFER * FCB $80 ;4: has CALL FCB 0 ;4: No CALL function FDB 0 ;5,6: BOTTOM OF PAGED MEM FDB 0 ;7,8: TOP OF PAGED MEM FCB B1-B0 ;9 BREAKPOINT INSTR LENGTH B0 SWI ;10+ BREKAPOINT INSTRUCTION B1 FCC '68HC12D60 monitor V1.0 ' ;DESCRIPTION FCC 'for Axiom CME12D60 wide' FCB 0 FCB 0 ;page of CALL breakpoint FDB B0 ;address of CALL breakpoint TSTG_SIZE EQU *-TSTG ;SIZE OF STRING * *=========================================================================== * Initialize the NoICE UART * * Default implementation uses SCI INITUART * * Baud DIV = MCLK / (16 * Baud_Rate) * MCLK = crystal / 2 * With a 16 Mhz crystal, DIV = 8,000,000/(16*Baud_Rate) = 500000/Baud_Rate * For 19200 baud, DIV = 26 (actual baud rate = 19231, or +0.16%) LDD #26 ;BAUD RATE CONSTANT STD SC0BDH ;WRITE HIGH BYTE, LOW BYTE LDAA #$00 ;NO LOOP, 8-BIT, NO WAKE, NO PARITY STAA SC0CR1 LDAA #$0C ;NO INTS, ENABLE TRANSMIT AND RECEIVE STAA SC0CR2 RTS * *=========================================================================== * Get a character from UART 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 BSR REWDT ;PREVENT WATCHDOG TIMEOUT DEX *;* BEQ GC90 ;EXIT IF TIMEOUT *(Disable timeout in most cases...) BRCLR SER_STATUS,#RXRDY, 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 to UART * * Uses 5 bytes of stack including return address * PUTCHAR PSHA PC10 BSR REWDT ;PREVENT WATCHDOG TIMEOUT BRCLR SER_STATUS, #TXRDY, 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 COPRST LDAA #$AA STAA COPRST RTS * *====================================================================== * 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" * BE SURE THAT "B" REMAINS INTACT UNTIL IT IS STORED TO REG_STATE BELOW! RES10 * * CAUTION: DON'T USE I/O ADDRESS EQUATES UNTIL INITRG IS WRITTEN * TO SET THE I/O BASE TO MATCH OUR EQUATES! LDAA #$08 ; Set register location STAA $0011 ;POST-RESET LOCATION OF INITRG * * Copy init table to on-chip registers (without using B) LDX #INIT_TABLE RES15 LDAA 1,X+ ;A=PORT LDY #CHIP_IO LEAY A,Y ;Y POINTS AT PORT LDAA 1,X+ ;A=DATA STAA 0,Y STAA 0,Y ;store twice: first may be ignored in SPECIAL mode CPX #INIT_TABLE_END BNE RES15 ; loop until table end * * Save reset type (RESET, COP, or Clock Fail) STAB REG_STATE ;SAVE STATE LDS #INITSTACK ;Initial stack value BSR INITUART * * 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 2,X+ ;SET VECTOR DBNE B,RST10 * * Initialize user registers LDD #INITSTACK STAA REG_SP+1 ;INIT USER'S STACK POINTER MSB STAB REG_SP ;LSB CLRA CLRB STD REG_PC STAA REG_A STAA REG_B STD REG_X STD REG_Y * * Initialize memory paging variables and hardware * LDAA PPAGE LDAA #$0 ; STAA REG_PAGE ;PAGE FROM HARDWARE (or zero) * * 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 or clock fail) 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 * *====================================================================== * 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 $F0 ;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 PULD STAA REG_X+1 ;MSB STAB REG_X ;LSB PULD STAA REG_Y+1 ;MSB STAB REG_Y ;LSB * * If this is a breakpoint (state = 1), then back up PC to point at SWI PULX ;PC AFTER INTERRUPT LDAA REG_STATE CMPA #1 BNE NOTBP ;BR IF NOT A BREAKPOINT LEAX B0-B1,X ;ELSE BACK UP TO POINT AT SWI LOCATION NOTBP TFR X,D STAA REG_PC+1 ;MSB STAB REG_PC ;LSB TFR SP,D ;USER STACK POINTER STAA REG_SP+1 ;MSB STAB REG_SP ;LSB * * Save memory page * (Could make this conditional on WINDEF PWEN bit: set page 0 if bit clear) * LDAA PPAGE ;GET CURRENT USER PAGE LDAA #0 ... OR ZERO IF UNPAGED 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 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 1,X+ ;SAVE FUNCTION CODE * * 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 1,X+ ;SAVE LENGTH BEQ MA80 ;SKIP DATA LOOP IF LENGTH = 0 * * Loop for data TFR A,B ;SAVE LENGTH FOR LOOP MA10 JSR GETCHAR ;GET A DATA BYTE BCS MAIN ;JIF TIMEOUT: RESYNC STAA 1,X+ ;SAVE DATA BYTE DBNE B,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 ADDA 1,SP+ BNE MAIN ;JIF BAD CHECKSUM * * Process the message. LDX #COMBUF LDD 2,X+ ;A= FUNCTION CODE, B= LENGTH, X=DATA CMPA #FN_GET_STAT BEQ TARGET_STAT CMPA #FN_READ_MEM BEQ READ_MEM CMPA #FN_WRITE_M BEQ WRITE_MEM CMPA #FN_READ_RG LBEQ READ_REGS CMPA #FN_WRITE_RG LBEQ WRITE_REGS CMPA #FN_RUN_TARG LBEQ RUN_TARGET CMPA #FN_SET_BYTE LBEQ SET_BYTES CMPA #FN_IN LBEQ IN_PORT CMPA #FN_OUT LBEQ OUT_PORT * * Error: unknown function. Complain LDAA #FN_ERROR STAA COMBUF ;SET FUNCTION AS "ERROR" LDAA #1 JMP SEND_STATUS ;VALUE IS "ERROR" *=========================================================================== * * Target Status: FN, len * * Entry with A=function code, B=data size, X=COMBUF+2 * TARGET_STAT LDY #TSTG ;DATA FOR REPLY LDAB #TSTG_SIZE ;LENGTH OF REPLY STAB COMBUF+1 TS10 LDAA 1,Y+ ;MOVE REPLY DATA TO BUFFER STAA 1,X+ DBNE B,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 page * LDAA 0,X * STAA PPAGE * * Get address LDAA 2,X ;MSB OF ADDRESS IN A LDAB 1,X ;LSB OF ADDRESS IN B TFR D,Y ;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 1,Y+ ;GET BYTE STAA 1,X+ ;STORE TO RETURN BUFFER DBNE B,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 page * LDAA 0,X * STAA PPAGE * * Get address LDAA 2,X ;MSB OF ADDRESS IN A LDAB 1,X ;LSB OF ADDRESS IN B TFR D,Y ;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 1,Y+ ;STORE THE BYTE AT AAAA,Y INX DBNE B,WLP * * Compare to see if the write worked PULY PULX PULB WLP20 LDAA 3,X ;GET BYTE JUST WRITTEN CMPA 1,Y+ BNE WLP80 ;BR IF WRITE FAILED INX DBNE B,WLP20 * * Write succeeded: return status = 0 WLP50 CLRA ;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 1,Y+ ;GET BYTE TO A STAA 1,X+ ;STORE TO RETURN BUFFER DBNE B,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 TSTB ;NUMBER OF BYTES BEQ WRR80 ;JIF NO REGISTERS * * Copy the registers LDY #TASK_REGS ;POINTER TO REGISTERS WRRLP LDAA 1,X+ ;GET BYTE TO A STAA 1,Y+ ;STORE TO REGISTER RAM DBNE B,WRRLP * * Reload SP, in case it has changed LDAB REG_SP LDAA REG_SP+1 TFR D,SP * * 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 page * LDAA REG_PAGE * STAA PPAGE * * Switch to user stack, if not already running on it ** LDAB REG_SP ;BACK TO USER STACK ** LDAA REG_SP+1 ** TFR D,SP * * Restore registers LDAA REG_PC+1 ;MSB USER PC FOR RTI LDAB REG_PC ;LSB PSHD * LDAA REG_Y+1 LDAB REG_Y PSHD * LDAA REG_X+1 LDAB REG_X PSHD * 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 1,Y+ ;SET RETURN COUNT =0, 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 page * LDAA 0,X * STAA PPAGE * * Get address LDAA 2,X ;MSB OF ADDRESS IN A LDAB 1,X ;LSB OF ADDRESS IN B TFR D,Y ;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 1,Y+ INC COMBUF+1 ;COUNT ONE RETURN BYTE * * Loop for next byte LEAX 4,X ;STEP TO NEXT BYTE SPECIFIER 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 BRA SEND *=========================================================================== * * Input from port: FN, len, PortAddressLo, PAhi (=0) * * While the HC12 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 TFR D,Y ;MEMORY ADDRESS IN Y * * Read the requested byte from local memory LDAA 0,Y * * Return byte read as "status" BRA 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 TFR D,Y ;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 BRA 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 BSR 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 1,X+ JSR PUTCHAR ;SEND A BYTE DBNE B,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 CLRA ;init checksum to 0 CHK10 ADDA 1,X+ DBNE B,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. * IC0_ENTRY LDAA #31 ;ffc0 LDX RAMVEC+0 JMP 0,X IC2_ENTRY LDAA #30 ;ffc2 LDX RAMVEC+2 JMP 0,X IC4_ENTRY LDAA #29 ;ffc4 LDX RAMVEC+4 JMP 0,X IC6_ENTRY LDAA #28 ;ffc6 LDX RAMVEC+6 JMP 0,X IC8_ENTRY LDAA #27 ;ffc8 LDX RAMVEC+8 JMP 0,X ICA_ENTRY LDAA #26 ;ffca LDX RAMVEC+$A JMP 0,X ICC_ENTRY LDAA #25 ;ffcc LDX RAMVEC+$C JMP 0,X ICE_ENTRY LDAA #24 ;ffce LDX RAMVEC+$E JMP 0,X ID0_ENTRY LDAA #23 ;ffd0 LDX RAMVEC+$10 JMP 0,X ID2_ENTRY LDAA #22 ;ffd2 ATD LDX RAMVEC+$12 JMP 0,X ID4_ENTRY LDAA #21 ;ffd4 Serial Comm Port 1 LDX RAMVEC+$14 JMP 0,X SCI0_ENTRY LDAA #20 ;ffd6 Serial Comm Port 0 LDX RAMVEC+$16 JMP 0,X SPI_ENTRY LDAA #19 ;ffd8 Serial Peripheral Port LDX RAMVEC+$18 JMP 0,X PAIE_ENTRY LDAA #18 ;ffda Pulse Accumulator input LDX RAMVEC+$1A JMP 0,X PAO_ENTRY LDAA #17 ;ffdc Pulse Accumulator overflow LDX RAMVEC+$1C JMP 0,X TOF_ENTRY LDAA #16 ;ffde Timer Overflow LDX RAMVEC+$1E JMP 0,X TC7_ENTRY LDAA #15 ;ffe0 Timer Channel 7 LDX RAMVEC+$20 JMP 0,X TC6_ENTRY LDAA #14 ;ffe2 Timer Channel 6 LDX RAMVEC+$22 JMP 0,X TC5_ENTRY LDAA #13 ;ffe4 Timer Channel 5 LDX RAMVEC+$24 JMP 0,X TC4_ENTRY LDAA #12 ;ffe6 Timer Channel 4 LDX RAMVEC+$26 JMP 0,X TC3_ENTRY LDAA #11 ;ffe8 Timer Channel 3 LDX RAMVEC+$28 JMP 0,X TC2_ENTRY LDAA #10 ;ffea Timer Channel 2 LDX RAMVEC+$2A JMP 0,X TC1_ENTRY LDAA #9 ;ffec Timer Channel 1 LDX RAMVEC+$2C JMP 0,X TC0_ENTRY LDAA #8 ;ffee Timer Channel 0 LDX RAMVEC+$2E JMP 0,X RTI_ENTRY LDAA #7 ;fff0 Real Time Interrupt LDX RAMVEC+$30 JMP 0,X IRQ_ENT LDAA #6 ;fff2 LDX RAMVEC+$32 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 * HC12D60 Interrupt Vectors.... VEC0 FDB IC0_ENTRY ;ffc0 FDB IC2_ENTRY ;ffc2 FDB IC4_ENTRY ;ffc4 FDB IC6_ENTRY ;ffc6 FDB IC8_ENTRY ;ffc8 FDB ICA_ENTRY ;ffca FDB ICC_ENTRY ;ffcc FDB ICE_ENTRY ;ffce FDB ID0_ENTRY ;ffd0 FDB ID2_ENTRY ;ffd2 FDB ID4_ENTRY ;ffd4 FDB SCI0_ENTRY ;ffd6 Serial Comm Port 0 FDB SPI_ENTRY ;ffd8 Serial Peripheral Port FDB PAIE_ENTRY ;ffda Pulse Accumulator input FDB PAO_ENTRY ;ffdc Pulse Accumulator overflow FDB TOF_ENTRY ;ffde Timer Overflow FDB TC7_ENTRY ;ffe0 Timer Channel 7 FDB TC6_ENTRY ;ffe2 Timer Channel 6 FDB TC5_ENTRY ;ffe4 Timer Channel 5 FDB TC4_ENTRY ;ffe6 Timer Channel 4 FDB TC3_ENTRY ;ffe8 Timer Channel 3 FDB TC2_ENTRY ;ffea Timer Channel 2 FDB TC1_ENTRY ;ffec Timer Channel 1 FDB TC0_ENTRY ;ffee Timer Channel 0 FDB RTI_ENTRY ;fff0 Real Time Interrupt 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 monitor reset FDB RESET ;fffe reset * END RESET