URL
https://opencores.org/ocsvn/System09/System09/trunk
Subversion Repositories System09
[/] [System09/] [trunk/] [src/] [Noice/] [MON6809.ASM] - Rev 169
Go to most recent revision | Compare with Previous | Blame | View Log
* 6809 Debug monitor for use with NOICE09** Copyright (c) 1992-2006 by John Hartman** Modification History:* 14-Jun-93 JLH release version* 24-Aug-93 JLH bad constant for COMBUF length compare* 25-Feb-98 JLH assemble with either Motorola or Dunfield* 1-May-06 JLH slight cleanup* 4-Jul-06 JEK Modified for System09 ACIA at $E000/$E001* 2K monitor RAM at $F000 - $F7FF* Allocated 1536 bytes ($600) for user stack.* disables watchdog timer**============================================================================** 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.* BUT: you must first "comment out" the conditionals as required,* because the Motorola assemblers do not have any IFEQ/ELSE/ENDIF** 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)**============================================================================** I/O equates for Heng's ROM emulator (set true if used)***ROMEM SET 1**============================================================================* HARDWARE PLATFORM CUSTOMIZATIONS**RAM_START EQU $D800 START OF MONITOR RAMRAM_START EQU $F000 START OF MONITOR RAMROM_START EQU $FC00 START OF MONITOR CODEHARD_VECT EQU $FFF0 START OF HARDWARE VECTORS*============================================================================* Equates for memory mapped 16450 serial port on Heng's ROM emulator board*;* IFEQ ROMEM,1**S16450 equ $A000 base of 16450 UART*RXR equ 0 Receiver buffer register*TXR equ 0 Transmitter buffer register*IER equ 1 Interrupt enable register*LCR equ 3 Line control register*MCR equ 4 Modem control register*DTR equ 1 Bit equate used to control status LED*LSR equ 5 Line status register** Define monitor serial port*SER_STATUS EQU S16450+LSR*SER_RXDATA EQU S16450+RXR*SER_TXDATA EQU S16450+TXR*RXRDY EQU $01 BIT MASK FOR RX BUFFER FULL*TXRDY EQU $20 BIT MASK FOR TX BUFFER EMPTY*;* ELSE** Put you UART equates hereSER_STATUS EQU $E000SER_RXDATA EQU $E001SER_TXDATA EQU $E001RXRDY EQU $01TXRDY EQU $02**;* ENDIF** Watchdog timer (if any) See REWDT for use*WDT EQU $207** Condition code bitsC EQU 1I EQU 10HF EQU 40HE EQU 80H**============================================================================* RAM definitions:ORG RAM_START** RAM interrupt vectors (first in SEG for easy addressing, else move to* their own SEG)NVEC EQU 8 number of vectorsRAMVEC RMB 2*NVEC** Initial user stack* (Size and location is user option)* RMB 64RMB $600INITSTACK** Monitor stack* (Calculated use is at most 7 bytes. Leave plenty of spare)RMB 16MONSTACK** Target registers: order must match that in TRGHC11.CTASK_REGSREG_STATE RMB 1REG_PAGE RMB 1REG_SP RMB 2REG_U RMB 2REG_Y RMB 2REG_X RMB 2REG_B RMB 1 B BEFORE A, SO D IS LEAST SIG. FIRSTREG_A RMB 1REG_DP RMB 1REG_CC RMB 1REG_PC RMB 2TASK_REG_SZ EQU *-TASK_REGS** Communications buffer* (Must be at least as long as TASK_REG_SZ. At least 19 bytes recommended.* Larger values may improve speed of NoICE memory move commands.)COMBUF_SIZE EQU 128 DATA SIZE FOR COMM BUFFERCOMBUF 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 resetRESET** Set CPU mode to safe stateORCC #I+F INTERRUPTS OFFLDS #MONSTACK CLEAN STACK IS HAPPY STACK**----------------------------------------------------------------------------*;* IFEQ ROMEM,1** Initialize S16450 UART on ROM emulator** Delay here in case the UART has not come out of reset yet.LDX #0LOP LEAX -1,X DELAY FOR SLOW RESETTING UARTNOPNOPBNE LOP** access baud generator, no parity, 1 stop bit, 8 data bits* LDA #$83* STA S16450+LCR** fixed baud rate of 19200: crystal is 3.686400 Mhz.* Divisor is 3,686400/(16*baud)* LDA #12 fix at 19.2 kbaud* STA S16450+RXR lsb* LDA #0* STA S16450+RXR+1 msb=0** access data registers, no parity, 1 stop bits, 8 data bits* LDA #$03* STA S16450+LCR** no loopback, OUT2 on, OUT1 on, RTS on, DTR (LED) on* LDA #$0F* STA S16450+MCR** disable all interrupts: modem, receive error, transmit, and receive* LDA #$00* STA S16450+IER**;* ELSE** Initialize your UART hereLDA #$03 Reset ACIASTA SER_STATUSLDA #$11 8 data 2 stop no paritySTA SER_STATUSTST SER_RXDATA*;* ENDIF**----------------------------------------------------------------------------** Initialize RAM interrupt vectorsLDY #INT_ENTRY ADDRESS OF DEFAULT HANDLERLDX #RAMVEC POINTER TO RAM VECTORSLDB #NVEC NUMBER OF VECTORSRES10 STY ,X++ SET VECTORDECBBNE RES10** Initialize user registersLDD #INITSTACKSTA REG_SP+1 INIT USER'S STACK POINTER MSBSTB REG_SP LSB*LDD #0STD REG_PCSTA REG_ASTA REG_BSTA REG_DPSTD REG_XSTD REG_YSTD REG_USTA REG_STATE initial state is "RESET"** Initialize memory paging variables and hardware (if any)STA REG_PAGE initial page is zero*;;; STA MAPIMG*;;; STA MAPREG set hardware map*LDA #E+I+F state "all regs pushed", no intsSTA REG_CC** Set function code for "GO". Then if we reset after being told to* GO, we will come back with registers so user can see the crashLDA #FN_RUN_TARGSTA COMBUFJMP 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*GETCHARPSHS XLDX #0 LONG TIMEOUTGC10 JSR REWDT PREVENT WATCHDOG TIMEOUTLEAX -1,XBEQ GC90 EXIT IF TIMEOUTLDA SER_STATUS READ DEVICE STATUSANDA #RXRDYBEQ GC10 NOT READY YET.** Data received: return CY=0. data in ACLRA CY=0LDA SER_RXDATA READ DATAPULS X,PC** Timeout: return CY=1GC90 ORCC #C CY=1PULS X,PC**===========================================================================* Output character in A** Uses 5 bytes of stack including return address*PUTCHARPSHS APC10 JSR REWDT PREVENT WATCHDOG TIMEOUTLDA SER_STATUS CHECK TX STATUSANDA #TXRDY RX READY ?BEQ PC10PULS ASTA 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 CLRA* STA WDTINCA* STA WDT CU-style WDT: must leave bit highRTS**======================================================================* Response string for GET TARGET STATUS request* Reply describes target:TSTG FCB 5 2: PROCESSOR TYPE = 6809FCB COMBUF_SIZE 3: SIZE OF COMMUNICATIONS BUFFERFCB 0 4: NO TASKING SUPPORTFDB 0,0 5-8: LOW AND HIGH LIMIT OF MAPPED MEM (NONE)FCB B1-B0 9: BREAKPOINT INSTR LENGTHB0 SWI 10: BREAKPOINT INSTRUCTIONB1 FCC '6809 monitor V1.0' DESCRIPTION, ZEROFCB 0TSTG_SIZE EQU *-TSTG SIZE OF STRING**======================================================================* HARDWARE PLATFORM INDEPENDENT EQUATES AND CODE** Communications function codes.FN_GET_STAT EQU $FF reply with device infoFN_READ_MEM EQU $FE reply with dataFN_WRITE_M EQU $FD reply with status (+/-)FN_READ_RG EQU $FC reply with registersFN_WRITE_RG EQU $FB reply with statusFN_RUN_TARG EQU $FA reply (delayed) with registersFN_SET_BYTE EQU $F9 reply with data (truncate if error)FN_IN EQU $F8 input from portFN_OUT EQU $F7 output to port*FN_MIN EQU $F7 MINIMUM RECOGNIZED FUNCTION CODEFN_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 instructionINT_ENTRYSTA REG_STATE SAVE STATE** Save registers from stack to reg block for return to master* Host wants least significant bytes first, so flip as necessaryPULS ASTA REG_CC CONDITION CODESPULS ASTA REG_A APULS ASTA REG_B BPULS ASTA REG_DP DPPULS DSTA REG_X+1 MSB XSTB REG_X LSB XPULS DSTA REG_Y+1 MSB YSTB REG_Y LSB YPULS DSTA REG_U+1 MSB USTB REG_U LSB U** If this is a breakpoint (state = 1), then back up PC to point at SWIPULS X PC AFTER INTERRUPTLDA REG_STATECMPA #1BNE NOTBP BR IF NOT A BREAKPOINTLEAX -1,X ELSE BACK UP TO POINT AT SWI LOCATIONNOTBP TFR X,D TRANSFER PC TO DSTA REG_PC+1 MSBSTB REG_PC LSBJMP ENTER_MON REG_PC POINTS AT POST-INTERRUPT OPCODE**===========================================================================* Main loop wait for command frame from master** Uses 6 bytes of stack including return address*MAIN LDS #MONSTACK CLEAN STACK IS HAPPY STACKLDX #COMBUF BUILD MESSAGE HERE** First byte is a function codeJSR GETCHAR GET A FUNCTION (6 bytes of stack)BCS MAIN JIF TIMEOUT: RESYNCCMPA #FN_MINBLO MAIN JIF BELOW MIN: ILLEGAL FUNCTIONSTA ,X+ SAVE FUNCTION CODE** Second byte is data byte count (may be zero)JSR GETCHAR GET A LENGTH BYTEBCS MAIN JIF TIMEOUT: RESYNCCMPA #COMBUF_SIZEBHI MAIN JIF TOO LONG: ILLEGAL LENGTHSTA ,X+ SAVE LENGTHCMPA #0BEQ MA80 SKIP DATA LOOP IF LENGTH = 0** Loop for dataTFR A,B SAVE LENGTH FOR LOOPMA10 JSR GETCHAR GET A DATA BYTEBCS MAIN JIF TIMEOUT: RESYNCSTA ,X+ SAVE DATA BYTEDECBBNE MA10** Get the checksumMA80 JSR GETCHAR GET THE CHECKSUMBCS MAIN JIF TIMEOUT: RESYNCPSHS A SAVE CHECKSUM** Compare received checksum to that calculated on received buffer* (Sum should be 0)JSR CHECKSUMADDA ,S+ ADD SAVED CHECKSUM TO COMPUTEDBNE MAIN JIF BAD CHECKSUM** Process the message.LDX #COMBUFLDA ,X+ GET THE FUNCTION CODELDB ,X+ GET THE LENGTHCMPA #FN_GET_STATBEQ TARGET_STATCMPA #FN_READ_MEMBEQ JREAD_MEMCMPA #FN_WRITE_MBEQ JWRITE_MEMCMPA #FN_READ_RGBEQ JREAD_REGSCMPA #FN_WRITE_RGBEQ JWRITE_REGSCMPA #FN_RUN_TARGBEQ JRUN_TARGETCMPA #FN_SET_BYTEBEQ JSET_BYTESCMPA #FN_INBEQ JIN_PORTCMPA #FN_OUTBEQ JOUT_PORT** Error: unknown function. ComplainLDA #FN_ERRORSTA COMBUF SET FUNCTION AS "ERROR"LDA #1JMP SEND_STATUS VALUE IS "ERROR"** long jumps to handlersJREAD_MEM JMP READ_MEMJWRITE_MEM JMP WRITE_MEMJREAD_REGS JMP READ_REGSJWRITE_REGS JMP WRITE_REGSJRUN_TARGET JMP RUN_TARGETJSET_BYTES JMP SET_BYTESJIN_PORT JMP IN_PORTJOUT_PORT JMP OUT_PORT*===========================================================================** Target Status: FN, len** Entry with A=function code, B=data size, X=COMBUF+2*TARGET_STATLDX #TSTG DATA FOR REPLYLDY #COMBUF+1 POINTER TO RETURN BUFFERLDB #TSTG_SIZE LENGTH OF REPLYSTB ,Y+ SET SIZE IN REPLY BUFFERTS10 LDA ,X+ MOVE REPLY DATA TO BUFFERSTA ,Y+DECBBNE TS10** Compute checksum on buffer, and send to master, then returnJMP SEND*===========================================================================** Read Memory: FN, len, page, Alo, Ahi, Nbytes** Entry with A=function code, B=data size, X=COMBUF+2*READ_MEM** Set map*;;; LDA 0,X*;;; STA MAPIMG*;;; STA MAPREG** Get addressLDA 2,X MSB OF ADDRESS IN ALDB 1,X LSB OF ADDRESS IN BTFR D,Y ADDRESS IN Y** Prepare return buffer: FN (unchanged), LEN, DATALDB 3,X NUMBER OF BYTES TO RETURNSTB COMBUF+1 RETURN LENGTH = REQUESTED DATABEQ GLP90 JIF NO BYTES TO GET** Read the requested bytes from local memoryGLP LDA ,Y+ GET BYTESTA ,X+ STORE TO RETURN BUFFERDECBBNE GLP** Compute checksum on buffer, and send to master, then returnGLP90 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 mapLDA ,X+*;;; STA MAPIMG*;;; STA MAPREG** Get addressLDB ,X+ LSB OF ADDRESS IN BLDA ,X+ MSB OF ADDRESS IN ATFR D,Y ADDRESS IN Y** Compute number of bytes to writeLDB COMBUF+1 NUMBER OF BYTES TO RETURNSUBB #3 MINUS PAGE AND ADDRESSBEQ WLP50 JIF NO BYTES TO PUT** Write the specified bytes to local memoryPSHS B,X,YWLP LDA ,X+ GET BYTE TO WRITESTA ,Y+ STORE THE BYTE AT ,YDECBBNE WLP** Compare to see if the write workedPULS B,X,YWLP20 LDA ,X+ GET BYTE JUST WRITTENCMPA ,Y+BNE WLP80 BR IF WRITE FAILEDDECBBNE WLP20** Write succeeded: return status = 0WLP50 LDA #0 RETURN STATUS = 0BRA WLP90** Write failed: return status = 1WLP80 LDA #1* Return OK statusWLP90 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 registersRETURN_REGSLDY #TASK_REGS POINTER TO REGISTERSLDB #TASK_REG_SZ NUMBER OF BYTESLDX #COMBUF+1 POINTER TO RETURN BUFFERSTB ,X+ SAVE RETURN DATA LENGTH** Copy the registersGRLP LDA ,Y+ GET BYTE TO ASTA ,X+ STORE TO RETURN BUFFERDECBBNE GRLP** Compute checksum on buffer, and send to master, then returnJMP SEND*===========================================================================** Write registers: FN, len, (register image)** Entry with A=function code, B=data size, X=COMBUF+2*WRITE_REGS*TSTB NUMBER OF BYTESBEQ WRR80 JIF NO REGISTERS** Copy the registersLDY #TASK_REGS POINTER TO REGISTERSWRRLP LDA ,X+ GET BYTE TO ASTA ,Y+ STORE TO REGISTER RAMDECBBNE WRRLP** Return OK statusWRR80 CLRAJMP SEND_STATUS*===========================================================================** Run Target: FN, len** Entry with A=function code, B=data size, X=COMBUF+2*RUN_TARGET** Restore user's map** LDA REG_PAGE USER'S PAGE** STA MAPIMG SET IMAGE** STA MAPREG SET MAPPING REGISTER** Switch to user stackLDA REG_SP+1 BACK TO USER STACKLDB REG_SPTFR D,S TO S** Restore registersLDA REG_PC+1 MS USER PC FOR RTILDB REG_PC LS USER PC FOR RTIPSHS D*LDA REG_U+1LDB REG_UPSHS D*LDA REG_Y+1LDB REG_YPSHS D*LDA REG_X+1LDB REG_XPSHS D*LDA REG_DPPSHS A*LDA REG_BPSHS A*LDA REG_APSHS A*LDA REG_CC SAVE USER CONDITION CODES FOR RTIORA #E _MUST_ BE "ALL REGS PUSHED"PSHS A** Return to userRTI**===========================================================================** Common continue point for all monitor entrances* SP = user stackENTER_MONTFR S,D USER STACK POINTERSTA REG_SP+1 SAVE USER'S STACK POINTER (MSB)STB REG_SP LSB** Change to our own stackLDS #MONSTACK AND USE OURS INSTEAD** Operating system variables** LDA MAPIMG GET CURRENT USER MAPLDA #0 ... OR ZERO IF UNMAPPED TARGETSTA REG_PAGE SAVE USER'S PAGE** Return registers to masterJMP RETURN_REGS*===========================================================================** 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 1 byte of stack*SET_BYTESLDU #COMBUF+1 POINTER TO RETURN BUFFERLDA #0STA ,U+ SET RETURN COUNT AS ZEROLSRBLSRB LEN/4 = NUMBER OF BYTES TO SETBEQ SB99 JIF NO BYTES (COMBUF+1 = 0)** Loop on inserting bytesSB10 PSHS B SAVE LOOP COUNTER** Set map*;;; LDA 0,X*;;; STA MAPIMG*;;; STA MAPREG** Get addressLDA 2,X MSB OF ADDRESS IN ALDB 1,X LSB OF ADDRESS IN BTFR D,Y MEMORY ADDRESS IN Y** Read current data at byte locationLDA 0,Y** Insert new data at byte locationLDB 3,X GET BYTE TO STORESTB 0,Y WRITE TARGET MEMORY** Verify writeCMPB 0,Y READ TARGET MEMORYPULS B RESTORE LOOP COUNT, CC'S INTACTBNE SB90 BR IF INSERT FAILED: ABORT** Save target byte in return bufferSTA ,U+INC COMBUF+1 COUNT ONE RETURN BYTE** Loop for next byteLEAX 4,X STEP TO NEXT BYTE SPECIFIERCMPB COMBUF+1BNE SB10 *LOOP FOR ALL BYTES** Return buffer with data from byte locationsSB90** Compute checksum on buffer, and send to master, then returnSB99 JMP SEND*===========================================================================** Input from port: FN, len, PortAddressLo, PAhi (=0)** While the 6809 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 addressLDA 1,X MSB OF ADDRESS IN ALDB 0,X LSB OF ADDRESS IN BTFR D,Y MEMORY ADDRESS IN Y** Read the requested byte from local memoryLDA 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 addressLDA 1,X MSB OF ADDRESS IN ALDB 0,X LSB OF ADDRESS IN BTFR D,Y MEMORY ADDRESS IN Y** Get dataLDA 2,X** Write value to portSTA 0,Y** Do not read port to verify (some I/O devices don't like it)** Return status of OKCLRAJMP SEND_STATUS*===========================================================================* Build status return with value from "A"*SEND_STATUSSTA COMBUF+2 SET STATUSLDA #1STA COMBUF+1 SET LENGTHBRA SEND*===========================================================================* Append checksum to COMBUF and send to master*SEND JSR CHECKSUM GET A=CHECKSUM, X->checksum locationNEGASTA 0,X STORE NEGATIVE OF CHECKSUM** Send buffer to masterLDX #COMBUF POINTER TO DATALDB 1,X LENGTH OF DATAADDB #3 PLUS FUNCTION, LENGTH, CHECKSUMSND10 LDA ,X+JSR PUTCHAR SEND A BYTEDECBBNE SND10JMP 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*CHECKSUMLDX #COMBUF pointer to bufferLDB 1,X length of messageADDB #2 plus function, lengthLDA #0 init checksum to 0CHK10 ADDA ,X+DECBBNE CHK10 loop for allRTS 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.*RES_ENT LDA #7LDX RAMVEC+0JMP 0,X*SWI3_ENT LDA #6LDX RAMVEC+2JMP 0,X*SWI2_ENT LDA #5LDX RAMVEC+4JMP 0,X** May have only PC and CC's pushed (unless we were waiting for an interrupt)* Push all registers here for common entry (else we can't use our RAM vector)FIRQ_ENT STA REG_A SAVE A REGPULS A GET CC'S FROM STACKBITA #EBNE FIRQ9 BR IF ALL REGISTERS PUSHED ALREADYPSHS U,Y,X,DP,B ELSE PUSH THEM NOWLDB REG_APSHS BORA #E SET AS "ALL REGS PUSHED"FIRQ9 PSHS A REPLACE CC'SLDA #4LDX RAMVEC+6JMP 0,X*IRQ_ENT LDA #3LDX RAMVEC+8JMP 0,X*NMI_ENT LDA #2LDX RAMVEC+12JMP 0,X*SWI_ENT LDA #1JMP INT_ENTRY**============================================================================* VECTORS THROUGH RAMORG HARD_VECTFDB RES_ENT fff0 (reserved)FDB SWI3_ENT fff2 (SWI3)FDB SWI2_ENT fff4 (SWI2)FDB FIRQ_ENT fff6 (FIRQ)FDB IRQ_ENT fff8 (IRQ)FDB SWI_ENT fffa (SWI/breakpoint)FDB NMI_ENT fffc (NMI)FDB RESET fffe reset*END RESET
Go to most recent revision | Compare with Previous | Blame | View Log
