| Assembler for 6502 | 7 August 2005 21:07:03 | ||||||
| Line | Hex | Source | |||||
| 0001 | 0000 | TANEX | EQU | 0 | // 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 | |||||||
| 0021 | 0000 | ORG | $0 | // Zero system page variables | |||
| 0022 | |||||||
| 0023 | 0000 | NULL: | RMB | 1 | // Reserved for bpt use | ||
| 0024 | 0001 | ICHAR: | RMB | 1 | // ASCII character | ||
| 0025 | 0002 | OCHAR: | RMB | 1 | // Temp char store | ||
| 0026 | 0003 | VDUIND: | RMB | 1 | // Display index | ||
| 0027 | 0004 | INTFS1: | RMB | 3 | // Fast interrupt link | ||
| 0028 | 0007 | NMIJP: | RMB | 3 | // NMI link | ||
| 0029 | 000A | ICURS: | RMB | 2 | // Cursor index | ||
| 0030 | 000C | RUNIND: | RMB | 1 | // Zero if in user mode | ||
| 0031 | 000D | SINGLE: | RMB | 1 | // Nonzero if single instruction mode | ||
| 0032 | 000E | PROCED: | RMB | 1 | // Proceed count (single instr to execute) | ||
| 0033 | 000F | SIMCOM: | RMB | 1 | // Keypad (simple) /ASCII (complex) keyboard | ||
| 0034 | 0010 | INTSL1: | RMB | 3 | // Slow interrupt link | ||
| 0035 | 0013 | HXPKL: | RMB | 1 | // Hexpack store | ||
| 0036 | 0014 | HXPKH: | RMB | 1 | |||
| 0037 | |||||||
| 0038 | // Pseudo registers | ||||||
| 0039 | |||||||
| 0040 | 0015 | PCLBCK: | RMB | 1 | // PCL | ||
| 0041 | 0016 | PCHBCK: | RMB | 1 | // PCH | ||
| 0042 | 0017 | PSWBCK: | RMB | 1 | // PSW | ||
| 0043 | 0018 | SPBCK: | RMB | 1 | // SP | ||
| 0044 | 0019 | XBCK: | RMB | 1 | // IX | ||
| 0045 | 001A | YBCK: | RMB | 1 | // IY | ||
| 0046 | 001B | ABCK: | RMB | 1 | // A | ||
| 0047 | |||||||
| 0048 | // Temporary stores | ||||||
| 0049 | |||||||
| 0050 | 001C | MODADL: | RMB | 1 | |||
| 0051 | 001D | MODADH: | RMB | 1 | |||
| 0052 | 001E | COPL: | RMB | 1 | |||
| 0053 | 001F | COPH: | RMB | 1 | |||
| 0054 | |||||||
| 0055 | // Breakpoint status table and code store | ||||||
| 0056 | |||||||
| 0057 | 0020 | BPTLO: | RMB | 1 | |||
| 0058 | 0021 | BPTHI: | RMB | 15 | |||
| 0059 | 0030 | BPTCOD: | RMB | 16 | |||
| 0060 | |||||||
| 0061 | // Stack base | ||||||
| 0062 | |||||||
| 0063 | 0100 | STKBSE: | EQU | $100 | |||
| 0064 | |||||||
| 0065 | // Display scroll labels | ||||||
| 0066 | |||||||
| 0067 | 0200 | VDUSTT: | EQU | $200 | |||
| 0068 | 0220 | VDUFST: | EQU | $220 | |||
| 0069 | 0300 | VDUMID: | EQU | $300 | |||
| 0070 | 0320 | VDUTOP: | EQU | $320 | |||
| 0071 | 03E0 | LINBOT: | EQU | $3E0 | |||
| 0072 | |||||||
| 0073 | // I/O Ports | ||||||
| 0074 | |||||||
| 0075 | BFF0 | SGRAPH: | EQU | $BFF0 | |||
| 0076 | BFF0 | KBINCL: | EQU | $BFF0 | // Alternative to SGRAPH | ||
| 0077 | BFF1 | SNMI: | EQU | $BFF1 | |||
| 0078 | BFF2 | KBWRIT: | EQU | $BFF2 | |||
| 0079 | BFF3 | KBREAD: | EQU | $BFF3 | |||
| 0080 | BFF3 | STEXT: | EQU | $BFF3 | // Write to set text mode | ||
| 0081 | |||||||
| 0082 | F7F7 | INPERR: | EQU | $F7F7 | // Error exit | ||
| 0083 | |||||||
| 0084 | |||||||
| 0085 | #if | TANEX | |||||
| 0086 | |||||||
| 0087 | ORG | $F800 | |||||
| 0088 | |||||||
| 0089 | JMP | $F951 | // Jump table to utility routines | ||||
| 0090 | JMP | $F9B2 | |||||
| 0091 | JMP | $F99B | |||||
| 0092 | JMP | OPCHR1 | |||||
| 0093 | LDA | #13 | |||||
| 0094 | JMP | OPCHR | |||||
| 0095 | JMP | $FAE9 | |||||
| 0096 | JMP | $FB0C | |||||
| 0097 | JMP | HEXPCK | |||||
| 0098 | JMP | HEXPNT | |||||
| 0099 | JMP | POLLKB | |||||
| 0100 | |||||||
| 0101 | LDX | #$FF | |||||
| 0102 | TXS | ||||||
| 0103 | JMP | MONTOR | |||||
| 0104 | |||||||
| 0105 | JMP | $FB16 | |||||
| 0106 | JMP | $FB23 | |||||
| 0107 | JMP | WASKB | |||||
| 0108 | FDB | $FCF8 | |||||
| 0109 | |||||||
| 0110 | SETUP: | JMP | KBINT | ||||
| 0111 | JMP | NMNT | |||||
| 0112 | FDB | LINBOT | // ICURS setting | ||||
| 0113 | FCB | 1 | // RUNIND | ||||
| 0114 | FCB | 0 | // SINGLE | ||||
| 0115 | FCB | 0 | // PROCED | ||||
| 0116 | FCB | 0 | // SIMCOM | ||||
| 0117 | FCB | $40 | // Slow Interrupt (RTI instruction) | ||||
| 0118 | |||||||
| 0119 | BIT | $0 | |||||
| 0120 | |||||||
| 0121 | |||||||
| 0122 | #endif | ||||||
| 0123 | |||||||
| 0124 | |||||||
| 0125 | // Start of ROM code for Microtan 65 TANBUG | ||||||
| 0126 | |||||||
| 0127 | FC00 | ORG | $FC00 | ||||
| 0128 | |||||||
| 0129 | // TANBUG starts here on reset | ||||||
| 0130 | |||||||
| 0131 | #if | TANEX | |||||
| 0132 | START: | JMP | $F83E | ||||
| 0133 | #else | ||||||
| 0134 | FC00 A2 FF | START: | LDX | #$FF | |||
| 0135 | FC02 9A | TXS | // Set stack pointer to top of the stack | ||||
| 0136 | #endif | ||||||
| 0137 | FC03 E8 | INX | // | ||||
| 0138 | FC04 86 17 | STX | PSWBCK | // Clear breakpoint store as their values will be | |||
| 0139 | |||||||
| 0140 | FC06 20 B7 FF | JSR | BPTCLR | // Clear breakpoints | |||
| 0141 | FC09 8D F3 BF | STA | STEXT | // 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 | #if | TANEX | |||||
| 0147 | LDX | #12 | |||||
| 0148 | SETUP1: | LDA | SETUP,X | ||||
| 0149 | #else | ||||||
| 0150 | FC0C A2 0E | LDX | #14 | ||||
| 0151 | FC0E BD DF FF | SETUP1: | LDA | SETUP,X | // SETUP holds parameter table | ||
| 0152 | #endif | ||||||
| 0153 | FC11 95 04 | STA | INTFS1,X | // Store in zero page RAM | |||
| 0154 | FC13 CA | DEX | |||||
| 0155 | FC14 10 F8 | BPL | SETUP1 | ||||
| 0156 | |||||||
| 0157 | // Determine keyboard type and set flag, note IX = $FF | ||||||
| 0158 | |||||||
| 0159 | FC16 E8 | INX | |||||
| 0160 | FC17 8E F2 BF | TSFIV: | STX | KBWRIT | // Clear keyboard write latch | ||
| 0161 | FC1A 8D F0 BF | STA | KBINCL | // Clear keyboard interrupt flag | |||
| 0162 | FC1D CA | DEX | |||||
| 0163 | FC1E 8E F2 BF | STX | KBWRIT | // Write to keyboard lines | |||
| 0164 | FC21 E8 | INX | // Reset IX | ||||
| 0165 | FC22 AD F3 BF | LDA | KBREAD | // Read it back | |||
| 0166 | FC25 10 02 | BPL | KPCPLX | // If plus not set - alphanumeric | |||
| 0167 | FC27 E6 0F | INC | SIMCOM | // If set - must be keypad | |||
| 0168 | #if | TANEX | |||||
| 0169 | KPCPLX: | JSR | $FADB | ||||
| 0170 | #else | ||||||
| 0171 | FC29 8D F0 BF | KPCPLX: | STA | KBINCL | // Clear keyboard interrupt | ||
| 0172 | #endif | ||||||
| 0173 | FC2C BD EC FF | TBMS: | LDA | HDR,X | // Display TANBUG message | ||
| 0174 | FC2F F0 06 | BEQ | MONTOR | // Output chars until a 0 | |||
| 0175 | FC31 20 75 FE | JSR | OPCHR | ||||
| 0176 | FC34 E8 | INX | |||||
| 0177 | FC35 D0 F5 | BNE | TBMS | ||||
| 0178 | |||||||
| 0179 | |||||||
| 0180 | |||||||
| 0181 | // MAIN LOOP - monitor user input and act accordingly | ||||||
| 0182 | |||||||
| 0183 | FC37 D8 | MONTOR: | CLD | // Set binary mode | |||
| 0184 | FC38 58 | CLI | |||||
| 0185 | FC39 20 FA FD | JSR | POLLKB | // Look at keyboard | |||
| 0186 | FC3C A5 01 | LDA | ICHAR | // Get char | |||
| 0187 | FC3E C9 21 | CMP | #$21 | // Less than a space - term | |||
| 0188 | FC40 30 06 | BMI | MONCH1 | // Else output char | |||
| 0189 | FC42 20 75 FE | ISTERM: | JSR | OPCHR | |||
| 0190 | FC45 4C 37 FC | JMP | MONTOR | ||||
| 0191 | |||||||
| 0192 | FC48 20 4F FC | MONCH1: | JSR | MONEN2 | // Call string process | ||
| 0193 | FC4B A9 0D | RC1: | LDA | #$0D | // Set up CR | ||
| 0194 | FC4D D0 F3 | BNE | ISTERM | // Uncond. branch loop | |||
| 0195 | |||||||
| 0196 | FC4F A0 00 | MONEN2: | LDY | #0 | |||
| 0197 | FC51 B1 0A | LDA | (ICURS),Y | // Pick up command | |||
| 0198 | FC53 AA | TAX | |||||
| 0199 | FC54 C8 | INY | |||||
| 0200 | FC55 B1 0A | LDA | (ICURS),Y | // Peek at next char | |||
| 0201 | FC57 10 36 | BPL | MULTI | // If not -ve (cursor) must be parameter | |||
| 0202 | FC59 A9 00 | LDA | #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 | |||||||
| 0217 | FC5B E0 53 | TRYS: | CPX | #$53 | // Was it S? | ||
| 0218 | FC5D D0 03 | BNE | TRYN | ||||
| 0219 | FC5F 86 0D | STX | SINGLE | // Yes - set single step mode | |||
| 0220 | FC61 60 | RTS | |||||
| 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 | |||||||
| 0231 | FC62 E0 4E | TRYN: | CPX | #$4E | // Command N? | ||
| 0232 | FC64 D0 03 | BNE | TRYP | ||||
| 0233 | FC66 85 0D | STA | SINGLE | // else clear single instruction mode (ACC=0) | |||
| 0234 | FC68 60 | RTS | |||||
| 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 | |||||||
| 0247 | FC69 E0 50 | TRYP: | CPX | #$50 | // Command P with no arg? | ||
| 0248 | FC6B D0 04 | BNE | TRYR | ||||
| 0249 | FC6D 85 0E | STA | PROCED | // Clear P count (A=0) | |||
| 0250 | FC6F F0 56 | BEQ | PROC1 | // 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 | |||||||
| 0260 | FC71 E0 52 | TRYR: | CPX | #$52 | // Command R? | ||
| 0261 | FC73 D0 09 | BNE | TRYB | ||||
| 0262 | FC75 85 1D | STA | MODADH | // Note A=0 | |||
| 0263 | FC77 A9 15 | LDA | #$15 | // Set pseudo reg | |||
| 0264 | FC79 85 1C | STA | MODADL | ||||
| 0265 | FC7B 4C E5 FD | JMP | REOPEN | // 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 | |||||||
| 0283 | FC7E E0 42 | TRYB: | CPX | #$42 | // Command B? | ||
| 0284 | FC80 D0 04 | BNE | ERRQ | // No - then error | |||
| 0285 | FC82 20 B7 FF | JSR | BPTCLR | // Else clear breakpoints | |||
| 0286 | FC85 60 | RTS | |||||
| 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 | #if | TANEX | |||||
| 0294 | ERRQ: | JMP | $FA75 | ||||
| 0295 | #else | ||||||
| 0296 | FC86 4C F7 F7 | ERRQ: | JMP | INPERR | |||
| 0297 | #endif | ||||||
| 0298 | |||||||
| 0299 | FC89 A9 3F | RETERR: | LDA | #$3F | |||
| 0300 | FC8B 20 75 FE | JSR | OPCHR | // Display question mark | |||
| 0301 | FC8E 60 | RTS | |||||
| 0302 | |||||||
| 0303 | |||||||
| 0304 | |||||||
| 0305 | // If we get here command expects parameters too | ||||||
| 0306 | |||||||
| 0307 | FC8F 88 | MULTI: | DEY | ||||
| 0308 | FC90 8A | TXA | // Save cmd on stack | ||||
| 0309 | FC91 48 | PHA | |||||
| 0310 | FC92 20 28 FF | JSR | HEXPCK | // Pack its argument | |||
| 0311 | FC95 D0 54 | BNE | MOREY | // Any more data? | |||
| 0312 | FC97 68 | PLA | // Restore command | ||||
| 0313 | FC98 50 EC | BVC | ERRQ | // 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 | |||||||
| 0325 | FC9A C9 47 | CMP | #$47 | // Is it a G? | |||
| 0326 | FC9C D0 21 | BNE | TRYPL | // No - skip | |||
| 0327 | FC9E A2 00 | LDX | #0 | ||||
| 0328 | FCA0 86 0E | STX | PROCED | // Clear proceed count | |||
| 0329 | FCA2 CA | DEX | // Set IX to $FF | ||||
| 0330 | FCA3 9A | GOEND: | TXS | // Reload it | |||
| 0331 | FCA4 A5 14 | LDA | HXPKH | // Push PC high | |||
| 0332 | FCA6 48 | PHA | |||||
| 0333 | FCA7 A5 13 | LDA | HXPKL | // Push PC low | |||
| 0334 | FCA9 48 | PHA | |||||
| 0335 | FCAA A5 17 | LDA | PSWBCK | ||||
| 0336 | FCAC 48 | PHA | |||||
| 0337 | FCAD C6 0C | DEC | RUNIND | // Clear run flag | |||
| 0338 | FCAF A9 20 | LDA | #$20 | ||||
| 0339 | FCB1 A4 03 | LDY | VDUIND | ||||
| 0340 | FCB3 91 0A | STA | (ICURS),Y | // Obliterate cursor | |||
| 0341 | FCB5 A6 19 | LDX | XBCK | ||||
| 0342 | FCB7 A4 1A | LDY | YBCK | ||||
| 0343 | FCB9 A5 1B | SRET: | LDA | ABCK | // Set users Acc | ||
| 0344 | FCBB 8D F1 BF | STA | SNMI | // Set NMI for next | |||
| 0345 | FCBE 40 | RTI | // 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 | |||||||
| 0359 | FCBF C9 50 | TRYPL: | CMP | #$50 | // Command P with arg? | ||
| 0360 | FCC1 D0 11 | BNE | TRYM | ||||
| 0361 | FCC3 A5 13 | LDA | HXPKL | // Set P count | |||
| 0362 | FCC5 85 0E | STA | PROCED | ||||
| 0363 | FCC7 A5 16 | PROC1: | LDA | PCHBCK | // Restore users PC | ||
| 0364 | FCC9 85 14 | PNOARG: | STA | HXPKH | |||
| 0365 | FCCB A5 15 | LDA | PCLBCK | ||||
| 0366 | FCCD 85 13 | STA | HXPKL | ||||
| 0367 | FCCF A6 18 | LDX | SPBCK | // Set IX to users SP | |||
| 0368 | FCD1 4C A3 FC | JMP | GOEND | // 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 | |||||||
| 0383 | FCD4 C9 4D | TRYM: | CMP | #$4D | // Command M address? | ||
| 0384 | FCD6 D0 AE | BNE | ERRQ | // No - error | |||
| 0385 | FCD8 A9 2C | EQPT: | LDA | #$2C | |||
| 0386 | FCDA 20 75 FE | JSR | OPCHR | // Output a comma | |||
| 0387 | FCDD A0 00 | LDY | #0 | ||||
| 0388 | FCDF B1 13 | LDA | (HXPKL),Y | // Pick up value | |||
| 0389 | FCE1 20 0B FF | JSR | HEXPNT | // and display it | |||
| 0390 | FCE4 68 | PLA | // Pop stack return | ||||
| 0391 | FCE5 68 | PLA | |||||
| 0392 | FCE6 A9 2C | LDA | #$2C | // Load comma | |||
| 0393 | FCE8 4C 42 FC | JMP | ISTERM | // and back to monitor | |||
| 0394 | |||||||
| 0395 | |||||||
| 0396 | |||||||
| 0397 | // If here then there is a second parameter | ||||||
| 0398 | |||||||
| 0399 | FCEB E0 2C | MOREY: | CPX | #$2C | // Was term a comma? | ||
| 0400 | FCED F0 04 | BEQ | GETPT2 | // Yes - continue | |||
| 0401 | FCEF 68 | LINKPH: | PLA | // Else pull command | |||
| 0402 | FCF0 4C 86 FC | LINKR: | JMP | ERRQ | // and give error | ||
| 0403 | |||||||
| 0404 | FCF3 A5 13 | GETPT2: | LDA | HXPKL | // No comma - store previous | ||
| 0405 | FCF5 85 1C | STA | MODADL | // in MODADL & MODADH | |||
| 0406 | FCF7 A5 14 | LDA | HXPKH | ||||
| 0407 | FCF9 85 1D | STA | MODADH | ||||
| 0408 | FCFB 20 28 FF | JSR | HEXPCK | // Pack next value | |||
| 0409 | FCFE D0 7C | BNE | MOREY1 | // Not cursor - more yet | |||
| 0410 | FD00 68 | PLA | // Else pull command | ||||
| 0411 | FD01 50 ED | BVC | LINKR | // No argument? - error | |||
| 0412 | |||||||
| 0413 | |||||||
| 0414 | |||||||
| 0415 | // L - LIST COMMAND (see LISTIT routine below) | ||||||
| 0416 | |||||||
| 0417 | FD03 C9 4C | CMP | #$4C | // Command L? | |||
| 0418 | FD05 F0 42 | BEQ | LISTIT | // 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 | |||||||
| 0431 | FD07 C9 4F | CMP | #$4F | // Command O? | |||
| 0432 | FD09 D0 27 | BNE | TRYBPT | ||||
| 0433 | FD0B A5 13 | LDA | HXPKL | // Get branch dest | |||
| 0434 | FD0D 38 | SEC | |||||
| 0435 | FD0E E9 02 | SBC | #2 | // Adjust for branch code | |||
| 0436 | FD10 B0 02 | BCS | NOTOPO | ||||
| 0437 | FD12 C6 14 | DEC | HXPKH | ||||
| 0438 | FD14 38 | NOTOPO: | SEC | ||||
| 0439 | FD15 E5 1C | SBC | MODADL | // Subtract source | |||
| 0440 | FD17 AA | TAX | // Hold result in IX | ||||
| 0441 | FD18 A5 14 | LDA | HXPKH | // Subtract high byte | |||
| 0442 | FD1A E5 1D | SBC | MODADH | ||||
| 0443 | FD1C A8 | TAY | // Store in IY | ||||
| 0444 | FD1D 8A | TXA | // Get low byte | ||||
| 0445 | FD1E 30 05 | BMI | RNGNG | // If -ve branch | |||
| 0446 | FD20 98 | TYA | // If +ve look at high | ||||
| 0447 | FD21 D0 CD | BNE | LINKR | // Not 0 - then error | |||
| 0448 | FD23 F0 03 | BEQ | PNTITO | // If ok continue | |||
| 0449 | |||||||
| 0450 | FD25 C8 | RNGNG: | INY | // If -ve, then high is $FF | |||
| 0451 | FD26 D0 C8 | BNE | LINKR | ||||
| 0452 | FD28 A9 3D | PNTITO: | LDA | #$3D | |||
| 0453 | FD2A 20 75 FE | JSR | OPCHR | // Ok - display equals sign | |||
| 0454 | FD2D 8A | TXA | |||||
| 0455 | FD2E 20 0B FF | JSR | HEXPNT | // ... and the value | |||
| 0456 | FD31 60 | RTS | |||||
| 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 | |||||||
| 0466 | FD32 C9 42 | TRYBPT: | CMP | #$42 | // Command B? | ||
| 0467 | FD34 D0 BA | LINK1: | BNE | LINKR | // No - error | ||
| 0468 | FD36 A5 13 | LDA | HXPKL | // Maximum breakpoint code is 7 | |||
| 0469 | FD38 30 B6 | BMI | LINKR | ||||
| 0470 | FD3A C9 08 | CMP | #8 | // If greater - then error | |||
| 0471 | FD3C 10 B2 | BPL | LINKR | ||||
| 0472 | FD3E 0A | ASL | A | // Double A | |||
| 0473 | FD3F AA | TAX | // Set IX for indexed addressing | ||||
| 0474 | FD40 A5 1C | LDA | MODADL | // Store breakpoint address | |||
| 0475 | FD42 95 20 | STA | BPTLO,X | ||||
| 0476 | FD44 A5 1D | LDA | MODADH | ||||
| 0477 | FD46 95 21 | STA | BPTHI,X | ||||
| 0478 | FD48 60 | JPRTRN: | 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 | |||||||
| 0489 | FD49 20 73 FE | LISTIT: | JSR | OUTPCR | // Output carriage return | ||
| 0490 | FD4C A0 00 | NXLI: | LDY | #0 | |||
| 0491 | FD4E A5 1D | LDA | MODADH | // Display address | |||
| 0492 | FD50 20 0B FF | JSR | HEXPNT | // High byte ... | |||
| 0493 | FD53 A5 1C | LDA | MODADL | ||||
| 0494 | FD55 20 0B FF | NXLIST: | JSR | HEXPNT | // Output low byte | ||
| 0495 | FD58 A9 20 | LDA | #$20 | ||||
| 0496 | FD5A 20 75 FE | JSR | OPCHR | // Output a space | |||
| 0497 | FD5D B1 1C | LDA | (MODADL),Y | // Display memory locations | |||
| 0498 | FD5F C8 | INY | |||||
| 0499 | FD60 C0 09 | CPY | #9 | // For eight memory locations | |||
| 0500 | FD62 30 F1 | BMI | NXLIST | ||||
| 0501 | FD64 C6 13 | DEC | HXPKL | // Decrement line count | |||
| 0502 | FD66 F0 E0 | BEQ | JPRTRN | // O? Return via CR (note requesting 0 lines gives 256) | |||
| 0503 | |||||||
| 0504 | #if | TANEX | |||||
| 0505 | DELX1: | NOP | |||||
| 0506 | NOP | ||||||
| 0507 | NOP | ||||||
| 0508 | NOP | ||||||
| 0509 | NOP | ||||||
| 0510 | NOP | ||||||
| 0511 | #else | ||||||
| 0512 | FD68 88 | DELX1: | DEY | // Time delay | |||
| 0513 | FD69 D0 FD | BNE | DELX1 | ||||
| 0514 | FD6B CA | DEX | |||||
| 0515 | FD6C D0 FA | BNE | DELX1 | ||||
| 0516 | #endif | ||||||
| 0517 | |||||||
| 0518 | FD6E A5 1C | LDA | MODADL | // Now adjust the address, for next 8 locations | |||
| 0519 | FD70 18 | CLC | |||||
| 0520 | FD71 69 08 | ADC | #8 | ||||
| 0521 | FD73 85 1C | STA | MODADL | ||||
| 0522 | FD75 90 D2 | BCC | LISTIT | // If Carry set | |||
| 0523 | FD77 E6 1D | INC | MODADH | // then increment high byte | |||
| 0524 | FD79 4C 49 FD | JMP | LISTIT | ||||
| 0525 | |||||||
| 0526 | |||||||
| 0527 | |||||||
| 0528 | // If we get here there is a third parameter | ||||||
| 0529 | |||||||
| 0530 | FD7C E0 2C | MOREY1: | CPX | #$2C | // Comma? | ||
| 0531 | FD7E F0 03 | BEQ | TERMOK | ||||
| 0532 | FD80 4C EF FC | ERJUM2: | JMP | LINKPH | // No - then error | ||
| 0533 | |||||||
| 0534 | FD83 A5 13 | TERMOK: | LDA | HXPKL | // Else store parameter | ||
| 0535 | FD85 85 1E | STA | COPL | ||||
| 0536 | FD87 A5 14 | LDA | HXPKH | ||||
| 0537 | FD89 85 1F | STA | COPH | ||||
| 0538 | FD8B 20 28 FF | JSR | HEXPCK | // then pack new para | |||
| 0539 | FD8E D0 F0 | BNE | ERJUM2 | // error not term | |||
| 0540 | FD90 68 | PLA | |||||
| 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 | |||||||
| 0548 | FD91 C9 4D | CMP | #$4D | // Command M? | |||
| 0549 | FD93 F0 27 | BEQ | MEM100 | // 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 | |||||||
| 0560 | FD95 C9 43 | CMP | #$43 | // Command C? | |||
| 0561 | FD97 D0 9B | BNE | LINK1 | // No - then error | |||
| 0562 | FD99 50 99 | BVC | LINK1 | // Argument? Error if not | |||
| 0563 | FD9B A0 00 | LDY | #0 | ||||
| 0564 | FD9D B1 1C | NXCOP: | LDA | (MODADL),Y | // Copy from source start address | ||
| 0565 | FD9F 91 13 | STA | (HXPKL),Y | // to destination | |||
| 0566 | FDA1 A5 1F | LDA | COPH | // Check if we've reached end address | |||
| 0567 | FDA3 C5 1D | CMP | MODADH | ||||
| 0568 | FDA5 D0 06 | BNE | ICMCOP | ||||
| 0569 | FDA7 A5 1E | LDA | COPL | ||||
| 0570 | FDA9 C5 1C | CMP | MODADL | ||||
| 0571 | FDAB F0 5B | BEQ | ENDLS | ||||
| 0572 | FDAD E6 1C | ICMCOP: | INC | MODADL | // No, then increment source | ||
| 0573 | FDAF D0 02 | BNE | NOHIH1 | ||||
| 0574 | FDB1 E6 1D | INC | MODADH | ||||
| 0575 | FDB3 E6 13 | NOHIH1: | INC | HXPKL | // and increment destination | ||
| 0576 | FDB5 D0 E6 | BNE | NXCOP | ||||
| 0577 | FDB7 E6 14 | INC | HXPKH | ||||
| 0578 | FDB9 D0 E2 | BNE | NXCOP | // Destination can not roll over top of memory | |||
| 0579 | FDBB 60 | RTS | |||||
| 0580 | |||||||
| 0581 | |||||||
| 0582 | |||||||
| 0583 | // Modify memory location (M command above) | ||||||
| 0584 | |||||||
| 0585 | FDBC A6 01 | MEM100: | LDX | ICHAR | // Get input character in IX | ||
| 0586 | FDBE E0 20 | CPX | #$20 | // Was it a space? | |||
| 0587 | FDC0 F0 23 | BEQ | REOPEN | // Yes - reopen | |||
| 0588 | FDC2 50 06 | BVC | NOENT | // Branch if nothing | |||
| 0589 | FDC4 A5 13 | LDA | HXPKL | // Else enter data | |||
| 0590 | FDC6 A0 00 | LDY | #0 | ||||
| 0591 | FDC8 91 1C | STA | (MODADL),Y | ||||
| 0592 | |||||||
| 0593 | FDCA E0 0A | NOENT: | CPX | #$0A | // Was LF typed? | ||
| 0594 | FDCC F0 11 | BEQ | WASLF | // Yes - then process it | |||
| 0595 | |||||||
| 0596 | FDCE E0 1B | CPX | #$1B | // Was it ESC? | |||
| 0597 | FDD0 D0 36 | BNE | ENDLS | // No - then return | |||
| 0598 | |||||||
| 0599 | FDD2 C6 1C | ESCIT: | DEC | MODADL | // Decrement memory modify address | ||
| 0600 | FDD4 A5 1C | LDA | MODADL | ||||
| 0601 | FDD6 C9 FF | CMP | #$FF | ||||
| 0602 | FDD8 D0 0B | BNE | REOPEN | ||||
| 0603 | FDDA C6 1D | DEC | MODADH | ||||
| 0604 | FDDC 4C E5 FD | JMP | REOPEN | ||||
| 0605 | |||||||
| 0606 | FDDF E6 1C | WASLF: | INC | MODADL | // Increment memory address | ||
| 0607 | FDE1 D0 02 | BNE | REOPEN | ||||
| 0608 | FDE3 E6 1D | INC | MODADH | // and high byte, if required | |||
| 0609 | |||||||
| 0610 | FDE5 20 73 FE | REOPEN: | JSR | OUTPCR | // Output carriage return | ||
| 0611 | FDE8 A9 4D | LDA | #$4D | ||||
| 0612 | FDEA 20 75 FE | JSR | OPCHR | // Display 'M' | |||
| 0613 | FDED A5 1D | LDA | MODADH | // and address | |||
| 0614 | FDEF 20 0B FF | JSR | HEXPNT | ||||
| 0615 | FDF2 A5 1C | LDA | MODADL | ||||
| 0616 | FDF4 20 0B FF | JSR | HEXPNT | ||||
| 0617 | FDF7 4C 4F FC | JMP | MONEN2 | // 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 | |||||||
| 0626 | FDFA A9 00 | POLLKB: | LDA | #0 | |||
| 0627 | FDFC 48 | PHA | // Push 0 - shift indicator | ||||
| 0628 | FDFD 85 01 | PLKB1: | STA | ICHAR | // Set ICHAR to zero | ||
| 0629 | FDFF C5 0F | CMP | SIMCOM | // Check if keypad | |||
| 0630 | FE01 D0 06 | BNE | SIMPLE | ||||
| 0631 | |||||||
| 0632 | // ASCII keyboard routine | ||||||
| 0633 | |||||||
| 0634 | FE03 C5 01 | WAIT1: | CMP | ICHAR | // Else wait for interrupt | ||
| 0635 | FE05 F0 FC | BEQ | WAIT1 | ||||
| 0636 | FE07 68 | PLKEND: | PLA | // Pop indicator | |||
| 0637 | FE08 60 | ENDLS: | RTS | ||||
| 0638 | |||||||
| 0639 | // Simple keypad routine | ||||||
| 0640 | |||||||
| 0641 | FE09 A9 0F | SIMPLE: | LDA | #$0F | |||
| 0642 | FE0B 8D F2 BF | STA | KBWRIT | // Enable all keyboard lines | |||
| 0643 | FE0E AD F3 BF | LDA | KBREAD | // Look at keyboard lines | |||
| 0644 | FE11 D0 F6 | BNE | SIMPLE | // Key down? - wait till up | |||
| 0645 | |||||||
| 0646 | FE13 A2 40 | LDX | #$40 | // Debounce it | |||
| 0647 | FE15 88 | DEBOUN: | DEY | ||||
| 0648 | FE16 D0 FD | BNE | DEBOUN | ||||
| 0649 | FE18 CA | DEX | |||||
| 0650 | FE19 D0 FA | BNE | DEBOUN | ||||
| 0651 | |||||||
| 0652 | FE1B A0 FF | PLK1: | LDY | #$FF | // Now poll the keypad properly | ||
| 0653 | FE1D 68 | PLA | // Peek at shift indicator | ||||
| 0654 | FE1E 48 | PHA | |||||
| 0655 | FE1F F0 02 | BEQ | NOSHIF | // If shift set modify IY | |||
| 0656 | FE21 A0 13 | LDY | #$13 | ||||
| 0657 | FE23 A2 08 | NOSHIF: | LDX | #8 | // Set IX - keyboard drive | ||
| 0658 | FE25 8E F2 BF | PLK2: | STX | KBWRIT | // Drive keyboard lines | ||
| 0659 | FE28 AD F3 BF | LDA | KBREAD | // Get result | |||
| 0660 | FE2B D0 0C | BNE | ACHAR | // Not 0 - a char - so skip | |||
| 0661 | FE2D C8 | INY | // Else adjust IY | ||||
| 0662 | FE2E C8 | INY | |||||
| 0663 | FE2F C8 | INY | |||||
| 0664 | FE30 C8 | INY | |||||
| 0665 | FE31 C8 | INY | |||||
| 0666 | FE32 8A | TXA | |||||
| 0667 | FE33 4A | LSR | A | // Shift IX right | |||
| 0668 | FE34 AA | TAX | |||||
| 0669 | FE35 F0 E4 | BEQ | PLK1 | // If zero repeat | |||
| 0670 | FE37 D0 EC | BNE | PLK2 | // Else next line | |||
| 0671 | |||||||
| 0672 | // If we get here a key has been pressed | ||||||
| 0673 | |||||||
| 0674 | FE39 C8 | ACHAR: | INY | ||||
| 0675 | FE3A 4A | LSR | A | // Which key of 5? | |||
| 0676 | FE3B 90 FC | BCC | ACHAR | // C set? That's the key | |||
| 0677 | FE3D B9 4B FE | LDA | CHRTBL,Y | // Get ASCII equivalent | |||
| 0678 | FE40 85 01 | STA | ICHAR | // And put in ICHAR | |||
| 0679 | FE42 D0 C3 | BNE | PLKEND | // If zero - shift | |||
| 0680 | FE44 68 | PLA | // Pull shift | ||||
| 0681 | FE45 49 FF | EOR | #$FF | // Change shift state | |||
| 0682 | FE47 48 | PHA | // Push shift | ||||
| 0683 | FE48 4C 09 FE | JMP | SIMPLE | // ... and continue | |||
| 0684 | |||||||
| 0685 | // Character look up table for ASCII equivalent | ||||||
| 0686 | |||||||
| 0687 | FE4B 33 37 42 | CHRTBL: | FCB | $33, $37, $42 | |||
| 0688 | FE4E 46 3F | FCB | $46, $3F | ||||
| 0689 | FE50 32 36 41 | FCB | $32, $36, $41 | ||||
| 0690 | FE53 45 0D | FCB | $45, $0D | ||||
| 0691 | FE55 31 35 39 | FCB | $31, $35, $39 | ||||
| 0692 | FE58 44 0A | FCB | $44, $0A | ||||
| 0693 | FE5A 30 34 38 | FCB | $30, $34, $38 | ||||
| 0694 | FE5D 43 00 | FCB | $43, $00 | ||||
| 0695 | FE5F 2C 52 4C | FCB | $2C, $52, $4C | ||||
| 0696 | FE62 4E 3F | FCB | $4E, $3F | ||||
| 0697 | FE64 32 43 49 | FCB | $32, $43, $49 | ||||
| 0698 | FE67 53 20 | FCB | $53, $20 | ||||
| 0699 | FE69 31 4F 1B | FCB | $31, $4F, $1B | ||||
| 0700 | FE6C 47 7F | FCB | $47, $7F | ||||
| 0701 | FE6E 30 34 50 | FCB | $30, $34, $50 | ||||
| 0702 | FE71 4D 00 | FCB | $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 | |||||||
| 0713 | FE73 A9 0D | OUTPCR: | 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 | #if | TANEX | |||||
| 0721 | OPCHR: | JMP | $F87C | ||||
| 0722 | NOP | ||||||
| 0723 | OPCHR1: | STA | OCHAR | ||||
| 0724 | LDY | VDUIND | // Get cursor position | ||||
| 0725 | LDA | #$20 | |||||
| 0726 | STA | (ICURS),Y | // and erase cursor | ||||
| 0727 | LDX | OCHAR | // Get char in IX | ||||
| 0728 | CPX | #12 | |||||
| 0729 | BNE | TRYDEL | |||||
| 0730 | JSR | $FA23 | |||||
| 0731 | DODEL: | LDA | #$FF | ||||
| 0732 | STA | (ICURS),Y | // Display cursor | ||||
| 0733 | STY | VDUIND | // and save index | ||||
| 0734 | RTS | ||||||
| 0735 | |||||||
| 0736 | TRYDEL: | CPX | #$7F | // Is it delete? | |||
| 0737 | BNE | TRYCR | |||||
| 0738 | JSR | $FA09 | |||||
| 0739 | BPL | DODEL | |||||
| 0740 | |||||||
| 0741 | TRYCR: | CPX | #$0D | // Is it a CR? | |||
| 0742 | BEQ | NXLINE | |||||
| 0743 | TXA | // No, then output character | |||||
| 0744 | STA | (ICURS),Y | |||||
| 0745 | INY | // Increment vdu index | |||||
| 0746 | CPY | #32 | // End of line? | ||||
| 0747 | BNE | DODEL | |||||
| 0748 | NXLINE: | LDA | #32 | ||||
| 0749 | CLC | ||||||
| 0750 | ADC | ICURS | |||||
| 0751 | STA | ICURS | |||||
| 0752 | LDA | ICURS+1 | |||||
| 0753 | ADC | #0 | |||||
| 0754 | STA | ICURS+1 | |||||
| 0755 | LDY | #0 | |||||
| 0756 | CMP | #4 | |||||
| 0757 | BNE | DODEL | |||||
| 0758 | JSR | $FA38 | |||||
| 0759 | BEQ | DODEL | |||||
| 0760 | NOP | ||||||
| 0761 | NOP | ||||||
| 0762 | NOP | ||||||
| 0763 | NOP | ||||||
| 0764 | NOP | ||||||
| 0765 | |||||||
| 0766 | #else | ||||||
| 0767 | FE75 85 02 | OPCHR: | STA | OCHAR | // Save the character | ||
| 0768 | FE77 8A | TXA | // Save IX and IY | ||||
| 0769 | FE78 48 | PHA | |||||
| 0770 | FE79 98 | TYA | |||||
| 0771 | FE7A 48 | PHA | |||||
| 0772 | FE7B A4 03 | LDY | VDUIND | // Get cursor position | |||
| 0773 | FE7D A9 20 | LDA | #$20 | ||||
| 0774 | FE7F 91 0A | STA | (ICURS),Y | // and erase cursor | |||
| 0775 | FE81 A6 02 | LDX | OCHAR | // Get char in IX | |||
| 0776 | FE83 E0 7F | CPX | #$7F | // Is it delete? | |||
| 0777 | FE85 D0 10 | BNE | TRYCR | ||||
| 0778 | FE87 88 | DEY | // Decrement vdu index | ||||
| 0779 | FE88 10 02 | BPL | DODEL | ||||
| 0780 | FE8A A0 00 | ZERCUR: | LDY | #0 | // If negative set zero | ||
| 0781 | FE8C A9 FF | DODEL: | LDA | #$FF | |||
| 0782 | FE8E 91 0A | STA | (ICURS),Y | // Display cursor | |||
| 0783 | FE90 84 03 | STY | VDUIND | // and save index | |||
| 0784 | FE92 68 | PLA | // Restore registers and exit | ||||
| 0785 | FE93 A8 | TAY | |||||
| 0786 | FE94 68 | PLA | |||||
| 0787 | FE95 AA | TAX | |||||
| 0788 | FE96 60 | RTS | |||||
| 0789 | |||||||
| 0790 | FE97 E0 0D | TRYCR: | CPX | #13 | // Is it a CR? | ||
| 0791 | FE99 F0 08 | BEQ | DOCR | ||||
| 0792 | FE9B 8A | TXA | // No, then output character | ||||
| 0793 | FE9C 91 0A | STA | (ICURS),Y | ||||
| 0794 | FE9E C8 | INY | // Increment vdu index | ||||
| 0795 | FE9F C0 20 | CPY | #32 | // End of line? | |||
| 0796 | FEA1 30 E9 | BMI | DODEL | // No - then tidy up and exit | |||
| 0797 | FEA3 A2 00 | DOCR: | LDX | #0 | // Scroll line | ||
| 0798 | FEA5 BD 20 02 | LOWBLK: | LDA | VDUFST,X | // Do in two blocks | ||
| 0799 | FEA8 9D 00 02 | STA | VDUSTT,X | ||||
| 0800 | FEAB E8 | INX | |||||
| 0801 | FEAC D0 F7 | BNE | LOWBLK | ||||
| 0802 | FEAE BD 20 03 | HIBLK: | LDA | VDUTOP,X | |||
| 0803 | FEB1 9D 00 03 | STA | VDUMID,X | ||||
| 0804 | FEB4 E8 | INX | |||||
| 0805 | FEB5 E0 E0 | CPX | #$E0 | ||||
| 0806 | FEB7 D0 F5 | BNE | HIBLK | ||||
| 0807 | |||||||
| 0808 | FEB9 A9 20 | LDA | #$20 | ||||
| 0809 | FEBB A8 | TAY | |||||
| 0810 | FEBC 88 | MORSP: | DEY | // Fill line with spaces | |||
| 0811 | FEBD 91 0A | STA | (ICURS),Y | ||||
| 0812 | FEBF D0 FB | BNE | MORSP | ||||
| 0813 | FEC1 F0 C7 | BEQ | ZERCUR | // 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 | |||||||
| 0824 | FEC3 48 | KBINT: | PHA | // Save accumulator | |||
| 0825 | FEC4 D8 | CLD | // Set binary mode | ||||
| 0826 | FEC5 8A | TXA | // Save IX | ||||
| 0827 | FEC6 48 | PHA | |||||
| 0828 | FEC7 BA | TSX | // Get SP in IX | ||||
| 0829 | FEC8 E8 | INX | // Point IX to old PSW | ||||
| 0830 | FEC9 E8 | INX | |||||
| 0831 | FECA E8 | INX | |||||
| 0832 | FECB BD 00 01 | LDA | STKBSE,X | // and get the PSW | |||
| 0833 | FECE 29 10 | AND | #$10 | // Was it a break? | |||
| 0834 | FED0 D0 1E | BNE | BRKP | // Yes - then process it | |||
| 0835 | FED2 68 | PLA | // Else restore IX | ||||
| 0836 | FED3 AA | TAX | |||||
| 0837 | #if | TANEX | |||||
| 0838 | JSR | $FAA3 | |||||
| 0839 | #else | ||||||
| 0840 | FED4 AD F3 BF | LDA | KBREAD | // Read keyboard | |||
| 0841 | #endif | ||||||
| 0842 | FED7 30 04 | BMI | WASKB | // If -ve, then was keyboard | |||
| 0843 | FED9 68 | USER: | PLA | // Else restore A | |||
| 0844 | FEDA 4C 10 00 | JMP | INTSL1 | // and check the slow interrupt | |||
| 0845 | |||||||
| 0846 | |||||||
| 0847 | |||||||
| 0848 | FEDD 29 7F | WASKB: | AND | #$7F | // Mask top bit | ||
| 0849 | FEDF 85 01 | STA | ICHAR | // and store in ICHAR | |||
| 0850 | #if | TANEX | |||||
| 0851 | JSR | $F911 | |||||
| 0852 | #else | ||||||
| 0853 | FEE1 8D F0 BF | STA | KBINCL | // Clear keyboard interrupt flip-flop | |||
| 0854 | #endif | ||||||
| 0855 | FEE4 C9 1B | CMP | #$1B | // Was key ESC? | |||
| 0856 | FEE6 D0 F1 | BNE | USER | // No - then normal return | |||
| 0857 | FEE8 A5 0C | LDA | RUNIND | // Else - check if user program running? | |||
| 0858 | FEEA D0 ED | BNE | USER | // No - then normal return | |||
| 0859 | FEEC 85 0E | STA | PROCED | // Else clear proceed count | |||
| 0860 | FEEE F0 12 | BEQ | ACTBP | // 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 | |||||||
| 0869 | FEF0 E8 | BRKP: | INX | // address PC L | |||
| 0870 | FEF1 38 | SEC | // set C | ||||
| 0871 | FEF2 BD 00 01 | LDA | STKBSE,X | // get PCL | |||
| 0872 | FEF5 E9 02 | SBC | #2 | // subtract 3 | |||
| 0873 | FEF7 9D 00 01 | STA | STKBSE,X | // put it back | |||
| 0874 | FEFA B0 04 | BCS | NOROLL | // C set? NOHI byte | |||
| 0875 | FEFC E8 | INX | // else address PCH | ||||
| 0876 | FEFD DE 00 01 | DEC | STKBSE,X | // dec PCH | |||
| 0877 | FF00 68 | NOROLL: | PLA | // pull IX | |||
| 0878 | FF01 AA | TAX | // restore it | ||||
| 0879 | FF02 68 | ACTBP: | PLA | // pull accumulator | |||
| 0880 | FF03 85 1B | STA | ABCK | // back it up | |||
| 0881 | FF05 20 C1 FF | JSR | BPTREM | // restore user code | |||
| 0882 | FF08 4C 75 FF | NOROL: | JMP | NMNT1 | // 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 | |||||||
| 0891 | FF0B 48 | HEXPNT: | PHA | // Save value of char | |||
| 0892 | FF0C A2 01 | LDX | #1 | ||||
| 0893 | FF0E 4A | LSR | A | // Get top part by multiple shifts | |||
| 0894 | FF0F 4A | LSR | A | ||||
| 0895 | FF10 4A | LSR | A | ||||
| 0896 | FF11 4A | LSR | A | ||||
| 0897 | FF12 18 | PNT2: | CLC | ||||
| 0898 | FF13 69 30 | ADC | #$30 | // Add hex 30 | |||
| 0899 | FF15 C9 3A | CMP | #$3A | // More than 9? | |||
| 0900 | FF17 30 03 | BMI | PNT1 | // No - then display it | |||
| 0901 | FF19 18 | CLC | |||||
| 0902 | FF1A 69 07 | ADC | #7 | // Adjust again | |||
| 0903 | FF1C 20 75 FE | PNT1: | JSR | OPCHR | // and display it | ||
| 0904 | FF1F CA | DEX | |||||
| 0905 | FF20 10 01 | BPL | MOR1 | // -ve? - end else low bit | |||
| 0906 | FF22 60 | RTS | |||||
| 0907 | |||||||
| 0908 | FF23 68 | MOR1: | PLA | // Recover character | |||
| 0909 | FF24 29 0F | AND | #$0F | // Clear unwanted bits | |||
| 0910 | FF26 10 EA | BPL | PNT2 | // 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 | |||||||
| 0924 | FF28 A9 00 | HEXPCK: | LDA | #0 | // Clear accumulator | ||
| 0925 | FF2A 48 | PHA | // Push as PSW | ||||
| 0926 | FF2B 85 13 | STA | HXPKL | // Clear parameters | |||
| 0927 | FF2D 85 14 | STA | HXPKH | ||||
| 0928 | FF2F C8 | NXHX: | INY | ||||
| 0929 | FF30 B1 0A | LDA | (ICURS),Y | // Get character from display | |||
| 0930 | FF32 AA | TAX | // Save in IX | ||||
| 0931 | FF33 38 | SEC | |||||
| 0932 | FF34 E9 30 | SBC | #$30 | // Subtract hex 30 to give 0 to 9 | |||
| 0933 | FF36 30 10 | BMI | ENDTS | ||||
| 0934 | FF38 C9 0A | HX1: | CMP | #$0A | // Is it 0 to 9? | ||
| 0935 | FF3A 30 10 | BMI | HX2 | // Yes - then pack it | |||
| 0936 | FF3C 38 | SEC | // Else adjust by hex 11 | ||||
| 0937 | FF3D E9 11 | SBC | #$11 | ||||
| 0938 | FF3F 30 07 | BMI | ENDTS | // Goto carry setup | |||
| 0939 | FF41 18 | HX3: | CLC | // Else add 9 | |||
| 0940 | FF42 69 0A | ADC | #$0A | ||||
| 0941 | FF44 C9 10 | CMP | #$10 | // If more than 15, then exit | |||
| 0942 | FF46 30 04 | BMI | HX2 | ||||
| 0943 | FF48 28 | ENDTS: | PLP | // Deal with V flag | |||
| 0944 | FF49 E0 FF | CPX | #$FF | // Check if cursor | |||
| 0945 | FF4B 60 | RTS | |||||
| 0946 | |||||||
| 0947 | // Note character is in IX on exit, return does not affect zero flag | ||||||
| 0948 | |||||||
| 0949 | FF4C A2 04 | HX2: | LDX | #4 | |||
| 0950 | FF4E 06 14 | HX5: | ASL | HXPKH | // Shift result left 4 bits | ||
| 0951 | FF50 06 13 | ASL | HXPKL | ||||
| 0952 | FF52 90 02 | BCC | HX4 | ||||
| 0953 | FF54 E6 14 | INC | HXPKH | ||||
| 0954 | FF56 CA | HX4: | DEX | // Until IX zero (4 times) | |||
| 0955 | FF57 D0 F5 | BNE | HX5 | ||||
| 0956 | FF59 18 | CLC | |||||
| 0957 | FF5A 65 13 | ADC | HXPKL | // Add in character | |||
| 0958 | FF5C 85 13 | STA | HXPKL | ||||
| 0959 | FF5E 68 | PLA | // Get pseudo PSW | ||||
| 0960 | FF5F A9 40 | LDA | #$40 | // Set V bit | |||
| 0961 | FF61 48 | PHA | // and push it | ||||
| 0962 | FF62 D0 CB | BNE | NXHX | // Next ... | |||
| 0963 | |||||||
| 0964 | |||||||
| 0965 | |||||||
| 0966 | // NON-MASKABLE INTERRUPT | ||||||
| 0967 | // | ||||||
| 0968 | // This routine handles single instruction mode | ||||||
| 0969 | |||||||
| 0970 | FF64 85 1B | NMNT: | STA | ABCK | // Save accumulator | ||
| 0971 | FF66 D8 | CLD | // Set binary mode | ||||
| 0972 | FF67 A5 0D | LDA | SINGLE | // Test single instruction mode | |||
| 0973 | FF69 D0 0A | BNE | NMNT1 | ||||
| 0974 | FF6B 8A | TXA | // If not save IX | ||||
| 0975 | FF6C 48 | PHA | |||||
| 0976 | FF6D 20 D0 FF | JSR | BPSET | // Set breakpoints | |||
| 0977 | FF70 68 | PLA | // Restore IX | ||||
| 0978 | FF71 AA | TAX | |||||
| 0979 | FF72 A5 1B | LDA | ABCK | // Restore accumulator | |||
| 0980 | FF74 40 | RTI | |||||
| 0981 | |||||||
| 0982 | FF75 A5 0E | NMNT1: | LDA | PROCED | // Get proceed count | ||
| 0983 | FF77 F0 05 | BEQ | ZERBCK | // If zero, then break | |||
| 0984 | FF79 C6 0E | DEC | PROCED | // else decrement count | |||
| 0985 | FF7B 4C B9 FC | JMP | SRET | // RTS via single test | |||
| 0986 | |||||||
| 0987 | FF7E E6 0C | ZERBCK: | INC | RUNIND | // Set not running | ||
| 0988 | FF80 68 | PLA | // Pop breakpoint PSW to Acc | ||||
| 0989 | FF81 85 17 | STA | PSWBCK | // and back it up | |||
| 0990 | FF83 68 | PLA | |||||
| 0991 | FF84 85 15 | STA | PCLBCK | // Ditto PCL | |||
| 0992 | FF86 68 | PLA | |||||
| 0993 | FF87 85 16 | STA | PCHBCK | // Ditto PCH | |||
| 0994 | FF89 86 19 | STX | XBCK | // Save IX | |||
| 0995 | FF8B 84 1A | STY | YBCK | // and IY | |||
| 0996 | FF8D BA | TSX | |||||
| 0997 | FF8E 86 18 | STX | SPBCK | // and operators SP | |||
| 0998 | FF90 20 73 FE | PSEUD: | JSR | OUTPCR | |||
| 0999 | FF93 A5 16 | LDA | PCHBCK | ||||
| 1000 | FF95 20 0B FF | JSR | HEXPNT | // Display PC | |||
| 1001 | FF98 A5 15 | LDA | PCLBCK | ||||
| 1002 | FF9A 20 0B FF | JSR | HEXPNT | ||||
| 1003 | FF9D A0 00 | LDY | #0 | ||||
| 1004 | FF9F A9 20 | PSNX: | LDA | #$20 | // Display two spaces | ||
| 1005 | FFA1 48 | PHA | |||||
| 1006 | FFA2 20 75 FE | JSR | OPCHR | ||||
| 1007 | FFA5 68 | PLA | |||||
| 1008 | FFA6 20 75 FE | JSR | OPCHR | ||||
| 1009 | FFA9 B9 17 00 | LDA | PSWBCK,Y | // Then display all registers | |||
| 1010 | FFAC 20 0B FF | JSR | HEXPNT | ||||
| 1011 | FFAF C8 | INY | |||||
| 1012 | FFB0 C0 05 | CPY | #5 | ||||
| 1013 | FFB2 30 EB | BMI | PSNX | ||||
| 1014 | FFB4 4C 4B FC | JMP | RC1 | ||||
| 1015 | |||||||
| 1016 | |||||||
| 1017 | |||||||
| 1018 | // CLEAR BREAKPOINTS | ||||||
| 1019 | // | ||||||
| 1020 | // Sets all breakpoint addresses to zero | ||||||
| 1021 | |||||||
| 1022 | FFB7 A2 1F | BPTCLR: | LDX | #$1F | // Set count for 8 breakpoints | ||
| 1023 | FFB9 A9 00 | LDA | #0 | ||||
| 1024 | FFBB 95 20 | BPTCL1: | STA | BPTLO,X | // Set to zero | ||
| 1025 | FFBD CA | DEX | |||||
| 1026 | FFBE 10 FB | BPL | BPTCL1 | // For all locations | |||
| 1027 | FFC0 60 | RTS | |||||
| 1028 | |||||||
| 1029 | |||||||
| 1030 | |||||||
| 1031 | // REMOVE BREAKPOINTS | ||||||
| 1032 | // | ||||||
| 1033 | // Writes back the user's original code | ||||||
| 1034 | |||||||
| 1035 | FFC1 8A | BPTREM: | TXA | ||||
| 1036 | FFC2 48 | PHA | |||||
| 1037 | FFC3 A2 0E | LDX | #$0E | // Set count for 8 breakpoints | |||
| 1038 | BPTRM1: | // | |||||
| 1039 | #if | TANEX | |||||
| 1040 | LDA | BPTLO,X | |||||
| 1041 | ORA | BPTHI,X | |||||
| 1042 | BEQ | BPTRM2 | |||||
| 1043 | #endif | ||||||
| 1044 | FFC5 B5 30 | LDA | BPTCOD,X | // Load saved old instruction | |||
| 1045 | FFC7 81 20 | STA | (BPTLO,X) | // Write to program memory | |||
| 1046 | FFC9 CA | BPTRM2: | DEX | ||||
| 1047 | FFCA CA | DEX | |||||
| 1048 | FFCB 10 F8 | BPL | BPTRM1 | // For all locations | |||
| 1049 | FFCD 68 | PLA | |||||
| 1050 | FFCE AA | TAX | |||||
| 1051 | FFCF 60 | RTS | |||||
| 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 | |||||||
| 1060 | FFD0 A2 0E | BPSET: | LDX | #$0E | // Set count for 8 breakpoints | ||
| 1061 | BPS1: | // | |||||
| 1062 | #if | TANEX | |||||
| 1063 | LDA | BPTHI,X | |||||
| 1064 | ORA | BPTLO,X | |||||
| 1065 | BEQ | BPS2 | |||||
| 1066 | #endif | ||||||
| 1067 | FFD2 A1 20 | LDA | (BPTLO,X) | // Get user's instruction | |||
| 1068 | FFD4 95 30 | STA | BPTCOD,X | // Store it | |||
| 1069 | FFD6 A9 00 | LDA | #0 | ||||
| 1070 | FFD8 81 20 | STA | (BPTLO,X) | // Set BRK instruction... | |||
| 1071 | FFDA CA | BPS2: | DEX | ||||
| 1072 | FFDB CA | DEX | |||||
| 1073 | FFDC 10 F4 | BPL | BPS1 | // Repeat until done | |||
| 1074 | FFDE 60 | RTS | |||||
| 1075 | |||||||
| 1076 | |||||||
| 1077 | #if | TANEX | |||||
| 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 | |||||||
| 1086 | FFDF 4C C3 FE | SETUP: | JMP | KBINT | |||
| 1087 | FFE2 4C 64 FF | JMP | NMNT | ||||
| 1088 | FFE5 E0 03 | FDB | LINBOT | // ICURS setting | |||
| 1089 | FFE7 01 | FCB | 1 | // RUNIND | |||
| 1090 | FFE8 00 | FCB | 0 | // SINGLE | |||
| 1091 | FFE9 00 | FCB | 0 | // PROCED | |||
| 1092 | FFEA 00 | FCB | 0 | // SIMCOM | |||
| 1093 | FFEB 40 | FCB | $40 | // Slow Interrupt (RTI instruction) | |||
| 1094 | |||||||
| 1095 | #endif | ||||||
| 1096 | |||||||
| 1097 | |||||||
| 1098 | // Header message | ||||||
| 1099 | |||||||
| 1100 | FFEC 0D | HDR: | FCB | 13 | // CR | ||
| 1101 | FFED 54 41 4E | FCC | 'TANBUG' | ||||
| 1102 | FFF3 0D 00 | FCB | 13, 0 | // CR, end of line terminator | |||
| 1103 | |||||||
| 1104 | #if | TANEX | |||||
| 1105 | NOP | ||||||
| 1106 | NOP | ||||||
| 1107 | NOP | ||||||
| 1108 | #else | ||||||
| 1109 | FFF5 00 00 | FCB | 0, 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 | |||||||
| 1118 | FFF7 4C 89 FC | JMP | RETERR | // $FFF7, also mapped to $F7F7 | |||
| 1119 | FFFA 07 00 | FDB | NMIJP | // Non Maskable Interrupt vector | |||
| 1120 | FFFC 00 FC | FDB | START | // Reset vector | |||
| 1121 | FFFE 04 00 | FDB | INTFS1 | // Interrupt vector | |||
| 1122 | |||||||
| 1123 | END | ||||||
| 1124 | |||||||
Assembly generated 0 errors
Assembly generated 0 warnings
DEBUG:
Assembly processed in 62 ms
Number of opcodes & directives is: 76