Assembler for 65027 August 2005 21:07:03
Line   Hex   Source
 
00010000TANEXEQU0// False, basic board
0002
0003//
0004// MICROTAN 65 - TANBUG
0005//
0006// The TANBUG monitor program is located in 1K bytes of read only memory
0007// (ROM) at the top of the 6502 microprocessor 64K byte address space.
0008//
0009// TANBUG will only operate in the memory map of the microtan system, it is
0010// not a general purpose 6502 software and has been specifically written for
0011// Microtan.
0012//
0013// Locations F7F7, F7F8 and F7F9 are reserved for a jump to an expansion
0014// monitor ROM which is positioned on the expansion board.
0015// Locations $200 - $3FF are the visual display memory. TANBUG writes to these
0016// locations whenever a command is typed to the monitor.
0017// Locations $100 - $1FF are used as the stack by the microprocessor.
0018//
0019
0020
00210000ORG$0// Zero system page variables
0022
00230000NULL:RMB1// Reserved for bpt use
00240001ICHAR:RMB1// ASCII character
00250002OCHAR:RMB1// Temp char store
00260003VDUIND:RMB1// Display index
00270004INTFS1:RMB3// Fast interrupt link
00280007NMIJP:RMB3// NMI link
0029000AICURS:RMB2// Cursor index
0030000CRUNIND:RMB1// Zero if in user mode
0031000DSINGLE:RMB1// Nonzero if single instruction mode
0032000EPROCED:RMB1// Proceed count (single instr to execute)
0033000FSIMCOM:RMB1// Keypad (simple) /ASCII (complex) keyboard
00340010INTSL1:RMB3// Slow interrupt link
00350013HXPKL:RMB1// Hexpack store
00360014HXPKH:RMB1
0037
0038// Pseudo registers
0039
00400015PCLBCK:RMB1// PCL
00410016PCHBCK:RMB1// PCH
00420017PSWBCK:RMB1// PSW
00430018SPBCK:RMB1// SP
00440019XBCK:RMB1// IX
0045001AYBCK:RMB1// IY
0046001BABCK:RMB1// A
0047
0048// Temporary stores
0049
0050001CMODADL:RMB1
0051001DMODADH:RMB1
0052001ECOPL:RMB1
0053001FCOPH:RMB1
0054
0055// Breakpoint status table and code store
0056
00570020BPTLO:RMB1
00580021BPTHI:RMB15
00590030BPTCOD:RMB16
0060
0061// Stack base
0062
00630100STKBSE:EQU$100
0064
0065// Display scroll labels
0066
00670200VDUSTT:EQU$200
00680220VDUFST:EQU$220
00690300VDUMID:EQU$300
00700320VDUTOP:EQU$320
007103E0LINBOT:EQU$3E0
0072
0073// I/O Ports
0074
0075BFF0SGRAPH:EQU$BFF0
0076BFF0KBINCL:EQU$BFF0// Alternative to SGRAPH
0077BFF1SNMI:EQU$BFF1
0078BFF2KBWRIT:EQU$BFF2
0079BFF3KBREAD:EQU$BFF3
0080BFF3STEXT:EQU$BFF3// Write to set text mode
0081
0082F7F7INPERR:EQU$F7F7// Error exit
0083
0084
0085#ifTANEX
0086
0087ORG$F800
0088
0089JMP$F951// Jump table to utility routines
0090JMP$F9B2
0091JMP$F99B
0092JMPOPCHR1
0093LDA#13
0094JMPOPCHR
0095JMP$FAE9
0096JMP$FB0C
0097JMPHEXPCK
0098JMPHEXPNT
0099JMPPOLLKB
0100
0101LDX#$FF
0102TXS
0103JMPMONTOR
0104
0105JMP$FB16
0106JMP$FB23
0107JMPWASKB
0108FDB$FCF8
0109
0110SETUP:JMPKBINT
0111JMPNMNT
0112FDBLINBOT// ICURS setting
0113FCB1// RUNIND
0114FCB0// SINGLE
0115FCB0// PROCED
0116FCB0// SIMCOM
0117FCB$40// Slow Interrupt (RTI instruction)
0118
0119BIT$0
0120
0121
0122#endif
0123
0124
0125// Start of ROM code for Microtan 65 TANBUG
0126
0127FC00ORG$FC00
0128
0129// TANBUG starts here on reset
0130
0131#ifTANEX
0132START:JMP$F83E
0133#else
0134FC00  A2 FFSTART:LDX#$FF
0135FC02  9ATXS// Set stack pointer to top of the stack
0136#endif
0137FC03  E8INX//
0138FC04  86 17STXPSWBCK// Clear breakpoint store as their values will be
0139
0140FC06  20 B7 FFJSRBPTCLR// Clear breakpoints
0141FC09  8D F3 BFSTASTEXT// Set text mode
0142
0143// Use table in ROM to initialise parameters (note order of table must
0144// correspond with the order of INTFS1 to ICURSH in RAM definitions)
0145
0146#ifTANEX
0147LDX#12
0148SETUP1:LDASETUP,X
0149#else
0150FC0C  A2 0ELDX#14
0151FC0E  BD DF FFSETUP1:LDASETUP,X// SETUP holds parameter table
0152#endif
0153FC11  95 04STAINTFS1,X// Store in zero page RAM
0154FC13  CADEX
0155FC14  10 F8BPLSETUP1
0156
0157// Determine keyboard type and set flag, note IX = $FF
0158
0159FC16  E8INX
0160FC17  8E F2 BFTSFIV:STXKBWRIT// Clear keyboard write latch
0161FC1A  8D F0 BFSTAKBINCL// Clear keyboard interrupt flag
0162FC1D  CADEX
0163FC1E  8E F2 BFSTXKBWRIT// Write to keyboard lines
0164FC21  E8INX// Reset IX
0165FC22  AD F3 BFLDAKBREAD// Read it back
0166FC25  10 02BPLKPCPLX// If plus not set - alphanumeric
0167FC27  E6 0FINCSIMCOM// If set - must be keypad
0168#ifTANEX
0169KPCPLX:JSR$FADB
0170#else
0171FC29  8D F0 BFKPCPLX:STAKBINCL// Clear keyboard interrupt
0172#endif
0173FC2C  BD EC FFTBMS:LDAHDR,X// Display TANBUG message
0174FC2F  F0 06BEQMONTOR// Output chars until a 0
0175FC31  20 75 FEJSROPCHR
0176FC34  E8INX
0177FC35  D0 F5BNETBMS
0178
0179
0180
0181// MAIN LOOP - monitor user input and act accordingly
0182
0183FC37  D8MONTOR:CLD// Set binary mode
0184FC38  58CLI
0185FC39  20 FA FDJSRPOLLKB// Look at keyboard
0186FC3C  A5 01LDAICHAR// Get char
0187FC3E  C9 21CMP#$21// Less than a space - term
0188FC40  30 06BMIMONCH1// Else output char
0189FC42  20 75 FEISTERM:JSROPCHR
0190FC45  4C 37 FCJMPMONTOR
0191
0192FC48  20 4F FCMONCH1:JSRMONEN2// Call string process
0193FC4B  A9 0DRC1:LDA#$0D// Set up CR
0194FC4D  D0 F3BNEISTERM// Uncond. branch loop
0195
0196FC4F  A0 00MONEN2:LDY#0
0197FC51  B1 0ALDA(ICURS),Y// Pick up command
0198FC53  AATAX
0199FC54  C8INY
0200FC55  B1 0ALDA(ICURS),Y// Peek at next char
0201FC57  10 36BPLMULTI// If not -ve (cursor) must be parameter
0202FC59  A9 00LDA#0// Else set A to zero
0203
0204
0205
0206// S - SINGLE INSTRUCTION MODE COMMAND
0207//
0208// This command switches single instruction mode ON.
0209// Single instruction mode is a very powerful debugging aid. When set
0210// TANBUG executes the user program one instruction at a time, re-entering
0211// the monitor between each instruction and printing out the status of all
0212// of the microprocessor's internal registers as they were after the last
0213// instruction executed in the user program.
0214// The S command is used in conjunction with the proceed command P and the
0215// normal mode command N.
0216
0217FC5B  E0 53TRYS:CPX#$53// Was it S?
0218FC5D  D0 03BNETRYN
0219FC5F  86 0DSTXSINGLE// Yes - set single step mode
0220FC61  60RTS
0221
0222
0223
0224// N - NORMAL MODE COMMAND
0225//
0226// The N command is the complement of the S command and is used to cancel
0227// the S command so that the microprocessor executes the user program in
0228// the normal manner without returning to the monitor between each instruction.
0229// Reset automatically sets the normal mode of operation.
0230
0231FC62  E0 4ETRYN:CPX#$4E// Command N?
0232FC64  D0 03BNETRYP
0233FC66  85 0DSTASINGLE// else clear single instruction mode (ACC=0)
0234FC68  60RTS
0235
0236
0237
0238// P - PROCEED COMMAND (with no argument)
0239//
0240// This command is used to execute the next instruction when in single
0241// instruction mode (after the program has been started with a G command).
0242// The pseudo registers are reloaded and the next instruction executed.
0243// After execution, the microprocessor status is displayed as follows:
0244// ADDR PSW SP IX IY ACC
0245// With no parameters entered, only the next instruction is executed
0246
0247FC69  E0 50TRYP:CPX#$50// Command P with no arg?
0248FC6B  D0 04BNETRYR
0249FC6D  85 0ESTAPROCED// Clear P count (A=0)
0250FC6F  F0 56BEQPROC1// Uncond. branch proc
0251
0252
0253
0254// R - REGISTER MODIFY / EXAMINE COMMAND
0255//
0256// This command is used to view / set the pseudo registers prior to running
0257// a program with the G command. It effectively executes a M15 command
0258// to examine the pseudo registers in locations $15 to $1B
0259
0260FC71  E0 52TRYR:CPX#$52// Command R?
0261FC73  D0 09BNETRYB
0262FC75  85 1DSTAMODADH// Note A=0
0263FC77  A9 15LDA#$15// Set pseudo reg
0264FC79  85 1CSTAMODADL
0265FC7B  4C E5 FDJMPREOPEN// Jump mod memory
0266
0267
0268
0269// B - BREAKPOINT COMMAND (no parameters)
0270//
0271// A breakpoint is a complementary debugging aid to single instruction mode.
0272// Instead of stepping singly through all instructions in a program, the
0273// breakpoint facility allows the user to specify the address at which he
0274// requires the monitor to be re-entered from his/her program. A breakpoint
0275// can be set just previous to where the fault is suspected to exist and the
0276// program started with the G command. Normal execution occurs until the
0277// breakpoint is reached, then the monitor is re-entered with the same status
0278// print-out as for single instruction mode. Any monitor commands can then be
0279// used and the program continued.
0280//
0281// With no parameters, the B command removes all breakpoints
0282
0283FC7E  E0 42TRYB:CPX#$42// Command B?
0284FC80  D0 04BNEERRQ// No - then error
0285FC82  20 B7 FFJSRBPTCLR// Else clear breakpoints
0286FC85  60RTS
0287
0288
0289
0290// With no TANEX FFF7 will respond to F7F7
0291// With TANEX, this monitor can be expanded since FFF7 jumps back to here
0292
0293#ifTANEX
0294ERRQ:JMP$FA75
0295#else
0296FC86  4C F7 F7ERRQ:JMPINPERR
0297#endif
0298
0299FC89  A9 3FRETERR:LDA#$3F
0300FC8B  20 75 FEJSROPCHR// Display question mark
0301FC8E  60RTS
0302
0303
0304
0305// If we get here command expects parameters too
0306
0307FC8F  88MULTI:DEY
0308FC90  8ATXA// Save cmd on stack
0309FC91  48PHA
0310FC92  20 28 FFJSRHEXPCK// Pack its argument
0311FC95  D0 54BNEMOREY// Any more data?
0312FC97  68PLA// Restore command
0313FC98  50 ECBVCERRQ// Error if no arg
0314
0315
0316
0317// G - GO COMMAND
0318//
0319// Parameter is the address of the first instruction to run
0320// When executed the cursor disappears, and is restored on completion
0321// The program counter is initialised to the parameter address, and the
0322// stack pointer to $1FF (top of stack). The other registers// A, X, Y, PSW
0323// are loaded from the pseudo registers in the zero page ($15 - $1B)
0324
0325FC9A  C9 47CMP#$47// Is it a G?
0326FC9C  D0 21BNETRYPL// No - skip
0327FC9E  A2 00LDX#0
0328FCA0  86 0ESTXPROCED// Clear proceed count
0329FCA2  CADEX// Set IX to $FF
0330FCA3  9AGOEND:TXS// Reload it
0331FCA4  A5 14LDAHXPKH// Push PC high
0332FCA6  48PHA
0333FCA7  A5 13LDAHXPKL// Push PC low
0334FCA9  48PHA
0335FCAA  A5 17LDAPSWBCK
0336FCAC  48PHA
0337FCAD  C6 0CDECRUNIND// Clear run flag
0338FCAF  A9 20LDA#$20
0339FCB1  A4 03LDYVDUIND
0340FCB3  91 0ASTA(ICURS),Y// Obliterate cursor
0341FCB5  A6 19LDXXBCK
0342FCB7  A4 1ALDYYBCK
0343FCB9  A5 1BSRET:LDAABCK// Set users Acc
0344FCBB  8D F1 BFSTASNMI// Set NMI for next
0345FCBE  40RTI// Goto user prog
0346
0347
0348
0349// P - PROCEED COMMAND (with argument)
0350//
0351// This command is used to execute the next instruction when in single
0352// instruction mode (after the program has been started with a G command).
0353// The pseudo registers are reloaded and the next instruction executed.
0354// After execution, the microprocessor status is displayed as follows:
0355// ADDR PSW SP IX IY ACC
0356// If a parameter less than or equal to $FF is entered, then this number
0357// of instructions are executed before returning to the monitor
0358
0359FCBF  C9 50TRYPL:CMP#$50// Command P with arg?
0360FCC1  D0 11BNETRYM
0361FCC3  A5 13LDAHXPKL// Set P count
0362FCC5  85 0ESTAPROCED
0363FCC7  A5 16PROC1:LDAPCHBCK// Restore users PC
0364FCC9  85 14PNOARG:STAHXPKH
0365FCCB  A5 15LDAPCLBCK
0366FCCD  85 13STAHXPKL
0367FCCF  A6 18LDXSPBCK// Set IX to users SP
0368FCD1  4C A3 FCJMPGOEND// Then back to user
0369
0370
0371
0372// M - MODIFY/EXAMINE MEMORY COMMAND
0373//
0374// Parameter is the memory address to be examined / modified
0375// TANBUG shows memory address and location, and awaits user input:
0376// - any terminator, location not altered and closes command
0377// - value followed by terminator, modifies location with value, if terminator is
0378// CR, closes command
0379// SPACE, shows same location
0380// LF, shows next memory location
0381// ESC, shows previous memory location
0382
0383FCD4  C9 4DTRYM:CMP#$4D// Command M address?
0384FCD6  D0 AEBNEERRQ// No - error
0385FCD8  A9 2CEQPT:LDA#$2C
0386FCDA  20 75 FEJSROPCHR// Output a comma
0387FCDD  A0 00LDY#0
0388FCDF  B1 13LDA(HXPKL),Y// Pick up value
0389FCE1  20 0B FFJSRHEXPNT// and display it
0390FCE4  68PLA// Pop stack return
0391FCE5  68PLA
0392FCE6  A9 2CLDA#$2C// Load comma
0393FCE8  4C 42 FCJMPISTERM// and back to monitor
0394
0395
0396
0397// If here then there is a second parameter
0398
0399FCEB  E0 2CMOREY:CPX#$2C// Was term a comma?
0400FCED  F0 04BEQGETPT2// Yes - continue
0401FCEF  68LINKPH:PLA// Else pull command
0402FCF0  4C 86 FCLINKR:JMPERRQ// and give error
0403
0404FCF3  A5 13GETPT2:LDAHXPKL// No comma - store previous
0405FCF5  85 1CSTAMODADL// in MODADL & MODADH
0406FCF7  A5 14LDAHXPKH
0407FCF9  85 1DSTAMODADH
0408FCFB  20 28 FFJSRHEXPCK// Pack next value
0409FCFE  D0 7CBNEMOREY1// Not cursor - more yet
0410FD00  68PLA// Else pull command
0411FD01  50 EDBVCLINKR// No argument? - error
0412
0413
0414
0415// L - LIST COMMAND (see LISTIT routine below)
0416
0417FD03  C9 4CCMP#$4C// Command L?
0418FD05  F0 42BEQLISTIT// Yes - list it
0419
0420
0421
0422// O - OFFSET COMMAND
0423//
0424// The offset command is a program writing aid. It calculates branch offsets
0425// for the user for incorporation as arguments in branch instructions.
0426// Parameters are the address of the branch opcode, and the address of the
0427// destination. The result is the value to be used as the argument for the
0428// branch.
0429// Note that the maximum branch is $7F forwards, or backwards
0430
0431FD07  C9 4FCMP#$4F// Command O?
0432FD09  D0 27BNETRYBPT
0433FD0B  A5 13LDAHXPKL// Get branch dest
0434FD0D  38SEC
0435FD0E  E9 02SBC#2// Adjust for branch code
0436FD10  B0 02BCSNOTOPO
0437FD12  C6 14DECHXPKH
0438FD14  38NOTOPO:SEC
0439FD15  E5 1CSBCMODADL// Subtract source
0440FD17  AATAX// Hold result in IX
0441FD18  A5 14LDAHXPKH// Subtract high byte
0442FD1A  E5 1DSBCMODADH
0443FD1C  A8TAY// Store in IY
0444FD1D  8ATXA// Get low byte
0445FD1E  30 05BMIRNGNG// If -ve branch
0446FD20  98TYA// If +ve look at high
0447FD21  D0 CDBNELINKR// Not 0 - then error
0448FD23  F0 03BEQPNTITO// If ok continue
0449
0450FD25  C8RNGNG:INY// If -ve, then high is $FF
0451FD26  D0 C8BNELINKR
0452FD28  A9 3DPNTITO:LDA#$3D
0453FD2A  20 75 FEJSROPCHR// Ok - display equals sign
0454FD2D  8ATXA
0455FD2E  20 0B FFJSRHEXPNT// ... and the value
0456FD31  60RTS
0457
0458
0459
0460// B - BREAKPOINT COMMAND (with parameters)
0461//
0462// As described above.
0463// Parameters are the address of any opcode instruction, and the number of the
0464// breakpoint to be set (0 to 7)
0465
0466FD32  C9 42TRYBPT:CMP#$42// Command B?
0467FD34  D0 BALINK1:BNELINKR// No - error
0468FD36  A5 13LDAHXPKL// Maximum breakpoint code is 7
0469FD38  30 B6BMILINKR
0470FD3A  C9 08CMP#8// If greater - then error
0471FD3C  10 B2BPLLINKR
0472FD3E  0AASLA// Double A
0473FD3F  AATAX// Set IX for indexed addressing
0474FD40  A5 1CLDAMODADL// Store breakpoint address
0475FD42  95 20STABPTLO,X
0476FD44  A5 1DLDAMODADH
0477FD46  95 21STABPTHI,X
0478FD48  60JPRTRN:RTS
0479
0480
0481
0482// L - LIST MEMORY COMMAND
0483//
0484// Parameters are start memory address, and number of lines of 8 consecutive
0485// memory locations to show
0486// If 0 lines are requested, 256 lines will be shown
0487// TANBUG pauses between each line to permit the user to read the output
0488
0489FD49  20 73 FELISTIT:JSROUTPCR// Output carriage return
0490FD4C  A0 00NXLI:LDY#0
0491FD4E  A5 1DLDAMODADH// Display address
0492FD50  20 0B FFJSRHEXPNT// High byte ...
0493FD53  A5 1CLDAMODADL
0494FD55  20 0B FFNXLIST:JSRHEXPNT// Output low byte
0495FD58  A9 20LDA#$20
0496FD5A  20 75 FEJSROPCHR// Output a space
0497FD5D  B1 1CLDA(MODADL),Y// Display memory locations
0498FD5F  C8INY
0499FD60  C0 09CPY#9// For eight memory locations
0500FD62  30 F1BMINXLIST
0501FD64  C6 13DECHXPKL// Decrement line count
0502FD66  F0 E0BEQJPRTRN// O? Return via CR (note requesting 0 lines gives 256)
0503
0504#ifTANEX
0505DELX1:NOP
0506NOP
0507NOP
0508NOP
0509NOP
0510NOP
0511#else
0512FD68  88DELX1:DEY// Time delay
0513FD69  D0 FDBNEDELX1
0514FD6B  CADEX
0515FD6C  D0 FABNEDELX1
0516#endif
0517
0518FD6E  A5 1CLDAMODADL// Now adjust the address, for next 8 locations
0519FD70  18CLC
0520FD71  69 08ADC#8
0521FD73  85 1CSTAMODADL
0522FD75  90 D2BCCLISTIT// If Carry set
0523FD77  E6 1DINCMODADH// then increment high byte
0524FD79  4C 49 FDJMPLISTIT
0525
0526
0527
0528// If we get here there is a third parameter
0529
0530FD7C  E0 2CMOREY1:CPX#$2C// Comma?
0531FD7E  F0 03BEQTERMOK
0532FD80  4C EF FCERJUM2:JMPLINKPH// No - then error
0533
0534FD83  A5 13TERMOK:LDAHXPKL// Else store parameter
0535FD85  85 1ESTACOPL
0536FD87  A5 14LDAHXPKH
0537FD89  85 1FSTACOPH
0538FD8B  20 28 FFJSRHEXPCK// then pack new para
0539FD8E  D0 F0BNEERJUM2// error not term
0540FD90  68PLA
0541
0542
0543// M - MEMORY MODIFY / EXAMINE (modify location)
0544//
0545// If user has entered a value to be entered into the momeory location
0546// then this routine processes it
0547
0548FD91  C9 4DCMP#$4D// Command M?
0549FD93  F0 27BEQMEM100// Yes - modify memory
0550
0551
0552
0553// C - COPY COMMAND
0554//
0555// The copy command allows copying of the contents of one block of memory to
0556// another. The parameters are start address source, end address source and
0557// start address destination. These are copied to MODADL, COPL, and HXPKL
0558// respectively.
0559
0560FD95  C9 43CMP#$43// Command C?
0561FD97  D0 9BBNELINK1// No - then error
0562FD99  50 99BVCLINK1// Argument? Error if not
0563FD9B  A0 00LDY#0
0564FD9D  B1 1CNXCOP:LDA(MODADL),Y// Copy from source start address
0565FD9F  91 13STA(HXPKL),Y// to destination
0566FDA1  A5 1FLDACOPH// Check if we've reached end address
0567FDA3  C5 1DCMPMODADH
0568FDA5  D0 06BNEICMCOP
0569FDA7  A5 1ELDACOPL
0570FDA9  C5 1CCMPMODADL
0571FDAB  F0 5BBEQENDLS
0572FDAD  E6 1CICMCOP:INCMODADL// No, then increment source
0573FDAF  D0 02BNENOHIH1
0574FDB1  E6 1DINCMODADH
0575FDB3  E6 13NOHIH1:INCHXPKL// and increment destination
0576FDB5  D0 E6BNENXCOP
0577FDB7  E6 14INCHXPKH
0578FDB9  D0 E2BNENXCOP// Destination can not roll over top of memory
0579FDBB  60RTS
0580
0581
0582
0583// Modify memory location (M command above)
0584
0585FDBC  A6 01MEM100:LDXICHAR// Get input character in IX
0586FDBE  E0 20CPX#$20// Was it a space?
0587FDC0  F0 23BEQREOPEN// Yes - reopen
0588FDC2  50 06BVCNOENT// Branch if nothing
0589FDC4  A5 13LDAHXPKL// Else enter data
0590FDC6  A0 00LDY#0
0591FDC8  91 1CSTA(MODADL),Y
0592
0593FDCA  E0 0ANOENT:CPX#$0A// Was LF typed?
0594FDCC  F0 11BEQWASLF// Yes - then process it
0595
0596FDCE  E0 1BCPX#$1B// Was it ESC?
0597FDD0  D0 36BNEENDLS// No - then return
0598
0599FDD2  C6 1CESCIT:DECMODADL// Decrement memory modify address
0600FDD4  A5 1CLDAMODADL
0601FDD6  C9 FFCMP#$FF
0602FDD8  D0 0BBNEREOPEN
0603FDDA  C6 1DDECMODADH
0604FDDC  4C E5 FDJMPREOPEN
0605
0606FDDF  E6 1CWASLF:INCMODADL// Increment memory address
0607FDE1  D0 02BNEREOPEN
0608FDE3  E6 1DINCMODADH// and high byte, if required
0609
0610FDE5  20 73 FEREOPEN:JSROUTPCR// Output carriage return
0611FDE8  A9 4DLDA#$4D
0612FDEA  20 75 FEJSROPCHR// Display 'M'
0613FDED  A5 1DLDAMODADH// and address
0614FDEF  20 0B FFJSRHEXPNT
0615FDF2  A5 1CLDAMODADL
0616FDF4  20 0B FFJSRHEXPNT
0617FDF7  4C 4F FCJMPMONEN2// Check next command
0618
0619
0620
0621// POLL KEYBOARD
0622//
0623// Gets a character from either the simple keypad or ASCII keyboard. Key
0624// value is stored in ICHAR ($01)
0625
0626FDFA  A9 00POLLKB:LDA#0
0627FDFC  48PHA// Push 0 - shift indicator
0628FDFD  85 01PLKB1:STAICHAR// Set ICHAR to zero
0629FDFF  C5 0FCMPSIMCOM// Check if keypad
0630FE01  D0 06BNESIMPLE
0631
0632// ASCII keyboard routine
0633
0634FE03  C5 01WAIT1:CMPICHAR// Else wait for interrupt
0635FE05  F0 FCBEQWAIT1
0636FE07  68PLKEND:PLA// Pop indicator
0637FE08  60ENDLS:RTS
0638
0639// Simple keypad routine
0640
0641FE09  A9 0FSIMPLE:LDA#$0F
0642FE0B  8D F2 BFSTAKBWRIT// Enable all keyboard lines
0643FE0E  AD F3 BFLDAKBREAD// Look at keyboard lines
0644FE11  D0 F6BNESIMPLE// Key down? - wait till up
0645
0646FE13  A2 40LDX#$40// Debounce it
0647FE15  88DEBOUN:DEY
0648FE16  D0 FDBNEDEBOUN
0649FE18  CADEX
0650FE19  D0 FABNEDEBOUN
0651
0652FE1B  A0 FFPLK1:LDY#$FF// Now poll the keypad properly
0653FE1D  68PLA// Peek at shift indicator
0654FE1E  48PHA
0655FE1F  F0 02BEQNOSHIF// If shift set modify IY
0656FE21  A0 13LDY#$13
0657FE23  A2 08NOSHIF:LDX#8// Set IX - keyboard drive
0658FE25  8E F2 BFPLK2:STXKBWRIT// Drive keyboard lines
0659FE28  AD F3 BFLDAKBREAD// Get result
0660FE2B  D0 0CBNEACHAR// Not 0 - a char - so skip
0661FE2D  C8INY// Else adjust IY
0662FE2E  C8INY
0663FE2F  C8INY
0664FE30  C8INY
0665FE31  C8INY
0666FE32  8ATXA
0667FE33  4ALSRA// Shift IX right
0668FE34  AATAX
0669FE35  F0 E4BEQPLK1// If zero repeat
0670FE37  D0 ECBNEPLK2// Else next line
0671
0672// If we get here a key has been pressed
0673
0674FE39  C8ACHAR:INY
0675FE3A  4ALSRA// Which key of 5?
0676FE3B  90 FCBCCACHAR// C set? That's the key
0677FE3D  B9 4B FELDACHRTBL,Y// Get ASCII equivalent
0678FE40  85 01STAICHAR// And put in ICHAR
0679FE42  D0 C3BNEPLKEND// If zero - shift
0680FE44  68PLA// Pull shift
0681FE45  49 FFEOR#$FF// Change shift state
0682FE47  48PHA// Push shift
0683FE48  4C 09 FEJMPSIMPLE// ... and continue
0684
0685// Character look up table for ASCII equivalent
0686
0687FE4B  33 37 42CHRTBL:FCB$33, $37, $42
0688FE4E  46 3FFCB$46, $3F
0689FE50  32 36 41FCB$32, $36, $41
0690FE53  45 0DFCB$45, $0D
0691FE55  31 35 39FCB$31, $35, $39
0692FE58  44 0AFCB$44, $0A
0693FE5A  30 34 38FCB$30, $34, $38
0694FE5D  43 00FCB$43, $00
0695FE5F  2C 52 4CFCB$2C, $52, $4C
0696FE62  4E 3FFCB$4E, $3F
0697FE64  32 43 49FCB$32, $43, $49
0698FE67  53 20FCB$53, $20
0699FE69  31 4F 1BFCB$31, $4F, $1B
0700FE6C  47 7FFCB$47, $7F
0701FE6E  30 34 50FCB$30, $34, $50
0702FE71  4D 00FCB$4D, $00
0703
0704
0705
0706// OUTPUT A CARRIAGE RETURN
0707//
0708// This subroutine causes the display to scroll up one line by outputting
0709// a carriage return to the screen. It also reinstates the cursor when a
0710// user program is run with the G command
0711// ACC is corrupted, IX and IY are preserved
0712
0713FE73  A9 0DOUTPCR:LDA#$0D// Output a CR
0714
0715// OUTPUT A CHARACTER
0716//
0717// Displays the character in the ACC on the screen
0718// ACC is corrupted, IX and IY are preserved
0719
0720#ifTANEX
0721OPCHR:JMP$F87C
0722NOP
0723OPCHR1:STAOCHAR
0724LDYVDUIND// Get cursor position
0725LDA#$20
0726STA(ICURS),Y// and erase cursor
0727LDXOCHAR// Get char in IX
0728CPX#12
0729BNETRYDEL
0730JSR$FA23
0731DODEL:LDA#$FF
0732STA(ICURS),Y// Display cursor
0733STYVDUIND// and save index
0734RTS
0735
0736TRYDEL:CPX#$7F// Is it delete?
0737BNETRYCR
0738JSR$FA09
0739BPLDODEL
0740
0741TRYCR:CPX#$0D// Is it a CR?
0742BEQNXLINE
0743TXA// No, then output character
0744STA(ICURS),Y
0745INY// Increment vdu index
0746CPY#32// End of line?
0747BNEDODEL
0748NXLINE:LDA#32
0749CLC
0750ADCICURS
0751STAICURS
0752LDAICURS+1
0753ADC#0
0754STAICURS+1
0755LDY#0
0756CMP#4
0757BNEDODEL
0758JSR$FA38
0759BEQDODEL
0760NOP
0761NOP
0762NOP
0763NOP
0764NOP
0765
0766#else
0767FE75  85 02OPCHR:STAOCHAR// Save the character
0768FE77  8ATXA// Save IX and IY
0769FE78  48PHA
0770FE79  98TYA
0771FE7A  48PHA
0772FE7B  A4 03LDYVDUIND// Get cursor position
0773FE7D  A9 20LDA#$20
0774FE7F  91 0ASTA(ICURS),Y// and erase cursor
0775FE81  A6 02LDXOCHAR// Get char in IX
0776FE83  E0 7FCPX#$7F// Is it delete?
0777FE85  D0 10BNETRYCR
0778FE87  88DEY// Decrement vdu index
0779FE88  10 02BPLDODEL
0780FE8A  A0 00ZERCUR:LDY#0// If negative set zero
0781FE8C  A9 FFDODEL:LDA#$FF
0782FE8E  91 0ASTA(ICURS),Y// Display cursor
0783FE90  84 03STYVDUIND// and save index
0784FE92  68PLA// Restore registers and exit
0785FE93  A8TAY
0786FE94  68PLA
0787FE95  AATAX
0788FE96  60RTS
0789
0790FE97  E0 0DTRYCR:CPX#13// Is it a CR?
0791FE99  F0 08BEQDOCR
0792FE9B  8ATXA// No, then output character
0793FE9C  91 0ASTA(ICURS),Y
0794FE9E  C8INY// Increment vdu index
0795FE9F  C0 20CPY#32// End of line?
0796FEA1  30 E9BMIDODEL// No - then tidy up and exit
0797FEA3  A2 00DOCR:LDX#0// Scroll line
0798FEA5  BD 20 02LOWBLK:LDAVDUFST,X// Do in two blocks
0799FEA8  9D 00 02STAVDUSTT,X
0800FEAB  E8INX
0801FEAC  D0 F7BNELOWBLK
0802FEAE  BD 20 03HIBLK:LDAVDUTOP,X
0803FEB1  9D 00 03STAVDUMID,X
0804FEB4  E8INX
0805FEB5  E0 E0CPX#$E0
0806FEB7  D0 F5BNEHIBLK
0807
0808FEB9  A9 20LDA#$20
0809FEBB  A8TAY
0810FEBC  88MORSP:DEY// Fill line with spaces
0811FEBD  91 0ASTA(ICURS),Y
0812FEBF  D0 FBBNEMORSP
0813FEC1  F0 C7BEQZERCUR// When done, tidy up
0814#endif
0815
0816
0817
0818// KEYBOARD INTERRUPT
0819//
0820// Note this is entered via jump instruction stored in RAM location INTFS1
0821// so that user can access interrupts quickly.
0822// A reset will always initiate INTFS1
0823
0824FEC3  48KBINT:PHA// Save accumulator
0825FEC4  D8CLD// Set binary mode
0826FEC5  8ATXA// Save IX
0827FEC6  48PHA
0828FEC7  BATSX// Get SP in IX
0829FEC8  E8INX// Point IX to old PSW
0830FEC9  E8INX
0831FECA  E8INX
0832FECB  BD 00 01LDASTKBSE,X// and get the PSW
0833FECE  29 10AND#$10// Was it a break?
0834FED0  D0 1EBNEBRKP// Yes - then process it
0835FED2  68PLA// Else restore IX
0836FED3  AATAX
0837#ifTANEX
0838JSR$FAA3
0839#else
0840FED4  AD F3 BFLDAKBREAD// Read keyboard
0841#endif
0842FED7  30 04BMIWASKB// If -ve, then was keyboard
0843FED9  68USER:PLA// Else restore A
0844FEDA  4C 10 00JMPINTSL1// and check the slow interrupt
0845
0846
0847
0848FEDD  29 7FWASKB:AND#$7F// Mask top bit
0849FEDF  85 01STAICHAR// and store in ICHAR
0850#ifTANEX
0851JSR$F911
0852#else
0853FEE1  8D F0 BFSTAKBINCL// Clear keyboard interrupt flip-flop
0854#endif
0855FEE4  C9 1BCMP#$1B// Was key ESC?
0856FEE6  D0 F1BNEUSER// No - then normal return
0857FEE8  A5 0CLDARUNIND// Else - check if user program running?
0858FEEA  D0 EDBNEUSER// No - then normal return
0859FEEC  85 0ESTAPROCED// Else clear proceed count
0860FEEE  F0 12BEQACTBP// and unconditionally branch to break
0861
0862
0863
0864// BREAK PROCESSING
0865//
0866// Note the user should not set a break at own break or in this interrupt routine
0867// else crashes. Adjust PC to return to instr must subtract 3
0868
0869FEF0  E8BRKP:INX// address PC L
0870FEF1  38SEC// set C
0871FEF2  BD 00 01LDASTKBSE,X// get PCL
0872FEF5  E9 02SBC#2// subtract 3
0873FEF7  9D 00 01STASTKBSE,X// put it back
0874FEFA  B0 04BCSNOROLL// C set? NOHI byte
0875FEFC  E8INX// else address PCH
0876FEFD  DE 00 01DECSTKBSE,X// dec PCH
0877FF00  68NOROLL:PLA// pull IX
0878FF01  AATAX// restore it
0879FF02  68ACTBP:PLA// pull accumulator
0880FF03  85 1BSTAABCK// back it up
0881FF05  20 C1 FFJSRBPTREM// restore user code
0882FF08  4C 75 FFNOROL:JMPNMNT1// service break
0883
0884
0885
0886// DISPLAY HEX VALUES
0887//
0888// Takes a hex value stored in accumulator and displays as two hex characters
0889// Registers ACC and IX are corrupted
0890
0891FF0B  48HEXPNT:PHA// Save value of char
0892FF0C  A2 01LDX#1
0893FF0E  4ALSRA// Get top part by multiple shifts
0894FF0F  4ALSRA
0895FF10  4ALSRA
0896FF11  4ALSRA
0897FF12  18PNT2:CLC
0898FF13  69 30ADC#$30// Add hex 30
0899FF15  C9 3ACMP#$3A// More than 9?
0900FF17  30 03BMIPNT1// No - then display it
0901FF19  18CLC
0902FF1A  69 07ADC#7// Adjust again
0903FF1C  20 75 FEPNT1:JSROPCHR// and display it
0904FF1F  CADEX
0905FF20  10 01BPLMOR1// -ve? - end else low bit
0906FF22  60RTS
0907
0908FF23  68MOR1:PLA// Recover character
0909FF24  29 0FAND#$0F// Clear unwanted bits
0910FF26  10 EABPLPNT2// and branch unconditionally
0911
0912
0913
0914// PACK HEX CHARACTERS
0915//
0916// This subroutine reads hex characters from the bottom line of the display
0917// and packs them up into two eight bit binary values.
0918// On exit, caused by any non-hex character, HXPKL and HXPKH contain a two
0919// byte number.
0920// Registers are not saved. On exit IY points to the last character. The zero flag
0921// is clear if the terminating character was the cursor, else set. The overflow
0922// flag is set if this subroutine encountered some hex data.
0923
0924FF28  A9 00HEXPCK:LDA#0// Clear accumulator
0925FF2A  48PHA// Push as PSW
0926FF2B  85 13STAHXPKL// Clear parameters
0927FF2D  85 14STAHXPKH
0928FF2F  C8NXHX:INY
0929FF30  B1 0ALDA(ICURS),Y// Get character from display
0930FF32  AATAX// Save in IX
0931FF33  38SEC
0932FF34  E9 30SBC#$30// Subtract hex 30 to give 0 to 9
0933FF36  30 10BMIENDTS
0934FF38  C9 0AHX1:CMP#$0A// Is it 0 to 9?
0935FF3A  30 10BMIHX2// Yes - then pack it
0936FF3C  38SEC// Else adjust by hex 11
0937FF3D  E9 11SBC#$11
0938FF3F  30 07BMIENDTS// Goto carry setup
0939FF41  18HX3:CLC// Else add 9
0940FF42  69 0AADC#$0A
0941FF44  C9 10CMP#$10// If more than 15, then exit
0942FF46  30 04BMIHX2
0943FF48  28ENDTS:PLP// Deal with V flag
0944FF49  E0 FFCPX#$FF// Check if cursor
0945FF4B  60RTS
0946
0947// Note character is in IX on exit, return does not affect zero flag
0948
0949FF4C  A2 04HX2:LDX#4
0950FF4E  06 14HX5:ASLHXPKH// Shift result left 4 bits
0951FF50  06 13ASLHXPKL
0952FF52  90 02BCCHX4
0953FF54  E6 14INCHXPKH
0954FF56  CAHX4:DEX// Until IX zero (4 times)
0955FF57  D0 F5BNEHX5
0956FF59  18CLC
0957FF5A  65 13ADCHXPKL// Add in character
0958FF5C  85 13STAHXPKL
0959FF5E  68PLA// Get pseudo PSW
0960FF5F  A9 40LDA#$40// Set V bit
0961FF61  48PHA// and push it
0962FF62  D0 CBBNENXHX// Next ...
0963
0964
0965
0966// NON-MASKABLE INTERRUPT
0967//
0968// This routine handles single instruction mode
0969
0970FF64  85 1BNMNT:STAABCK// Save accumulator
0971FF66  D8CLD// Set binary mode
0972FF67  A5 0DLDASINGLE// Test single instruction mode
0973FF69  D0 0ABNENMNT1
0974FF6B  8ATXA// If not save IX
0975FF6C  48PHA
0976FF6D  20 D0 FFJSRBPSET// Set breakpoints
0977FF70  68PLA// Restore IX
0978FF71  AATAX
0979FF72  A5 1BLDAABCK// Restore accumulator
0980FF74  40RTI
0981
0982FF75  A5 0ENMNT1:LDAPROCED// Get proceed count
0983FF77  F0 05BEQZERBCK// If zero, then break
0984FF79  C6 0EDECPROCED// else decrement count
0985FF7B  4C B9 FCJMPSRET// RTS via single test
0986
0987FF7E  E6 0CZERBCK:INCRUNIND// Set not running
0988FF80  68PLA// Pop breakpoint PSW to Acc
0989FF81  85 17STAPSWBCK// and back it up
0990FF83  68PLA
0991FF84  85 15STAPCLBCK// Ditto PCL
0992FF86  68PLA
0993FF87  85 16STAPCHBCK// Ditto PCH
0994FF89  86 19STXXBCK// Save IX
0995FF8B  84 1ASTYYBCK// and IY
0996FF8D  BATSX
0997FF8E  86 18STXSPBCK// and operators SP
0998FF90  20 73 FEPSEUD:JSROUTPCR
0999FF93  A5 16LDAPCHBCK
1000FF95  20 0B FFJSRHEXPNT// Display PC
1001FF98  A5 15LDAPCLBCK
1002FF9A  20 0B FFJSRHEXPNT
1003FF9D  A0 00LDY#0
1004FF9F  A9 20PSNX:LDA#$20// Display two spaces
1005FFA1  48PHA
1006FFA2  20 75 FEJSROPCHR
1007FFA5  68PLA
1008FFA6  20 75 FEJSROPCHR
1009FFA9  B9 17 00LDAPSWBCK,Y// Then display all registers
1010FFAC  20 0B FFJSRHEXPNT
1011FFAF  C8INY
1012FFB0  C0 05CPY#5
1013FFB2  30 EBBMIPSNX
1014FFB4  4C 4B FCJMPRC1
1015
1016
1017
1018// CLEAR BREAKPOINTS
1019//
1020// Sets all breakpoint addresses to zero
1021
1022FFB7  A2 1FBPTCLR:LDX#$1F// Set count for 8 breakpoints
1023FFB9  A9 00LDA#0
1024FFBB  95 20BPTCL1:STABPTLO,X// Set to zero
1025FFBD  CADEX
1026FFBE  10 FBBPLBPTCL1// For all locations
1027FFC0  60RTS
1028
1029
1030
1031// REMOVE BREAKPOINTS
1032//
1033// Writes back the user's original code
1034
1035FFC1  8ABPTREM:TXA
1036FFC2  48PHA
1037FFC3  A2 0ELDX#$0E// Set count for 8 breakpoints
1038BPTRM1://
1039#ifTANEX
1040LDABPTLO,X
1041ORABPTHI,X
1042BEQBPTRM2
1043#endif
1044FFC5  B5 30LDABPTCOD,X// Load saved old instruction
1045FFC7  81 20STA(BPTLO,X)// Write to program memory
1046FFC9  CABPTRM2:DEX
1047FFCA  CADEX
1048FFCB  10 F8BPLBPTRM1// For all locations
1049FFCD  68PLA
1050FFCE  AATAX
1051FFCF  60RTS
1052
1053
1054
1055// SET BREAKPOINTS
1056//
1057// Examines entered breakpoint addresses, stores the present instruction
1058// and writes BRK opcode to program memory
1059
1060FFD0  A2 0EBPSET:LDX#$0E// Set count for 8 breakpoints
1061BPS1://
1062#ifTANEX
1063LDABPTHI,X
1064ORABPTLO,X
1065BEQBPS2
1066#endif
1067FFD2  A1 20LDA(BPTLO,X)// Get user's instruction
1068FFD4  95 30STABPTCOD,X// Store it
1069FFD6  A9 00LDA#0
1070FFD8  81 20STA(BPTLO,X)// Set BRK instruction...
1071FFDA  CABPS2:DEX
1072FFDB  CADEX
1073FFDC  10 F4BPLBPS1// Repeat until done
1074FFDE  60RTS
1075
1076
1077#ifTANEX
1078// Setup table in low ROM
1079
1080#else
1081
1082// SETUP TABLE
1083//
1084// Copy in ROM of the initial settings for zero page variables
1085
1086FFDF  4C C3 FESETUP:JMPKBINT
1087FFE2  4C 64 FFJMPNMNT
1088FFE5  E0 03FDBLINBOT// ICURS setting
1089FFE7  01FCB1// RUNIND
1090FFE8  00FCB0// SINGLE
1091FFE9  00FCB0// PROCED
1092FFEA  00FCB0// SIMCOM
1093FFEB  40FCB$40// Slow Interrupt (RTI instruction)
1094
1095#endif
1096
1097
1098// Header message
1099
1100FFEC  0DHDR:FCB13// CR
1101FFED  54 41 4EFCC'TANBUG'
1102FFF3  0D 00FCB13, 0// CR, end of line terminator
1103
1104#ifTANEX
1105NOP
1106NOP
1107NOP
1108#else
1109FFF5  00 00FCB0, 0// Padding
1110#endif
1111
1112
1113
1114// RESET / INTERRUPT VECTORS
1115//
1116// These vectors must appear at the top of the ROM space
1117
1118FFF7  4C 89 FCJMPRETERR// $FFF7, also mapped to $F7F7
1119FFFA  07 00FDBNMIJP// Non Maskable Interrupt vector
1120FFFC  00 FCFDBSTART// Reset vector
1121FFFE  04 00FDBINTFS1// Interrupt vector
1122
1123END
1124

Assembly generated 0 errors
Assembly generated 0 warnings

DEBUG:
Assembly processed in 62 ms
Number of opcodes & directives is: 76