1: ; B-12. Function Name: IOBASE 2: ; 3: ; Purpose: Define I/O memory page 4: ; Call address: $FFF3 (hex) 65523 (decimal) 5: ; Communication registers: X, Y 6: ; Preparatory routines: None 7: ; Error returns: 8: ; Stack requirements: 2 9: ; Registers affected: X, Y 10: ; 11: ; 12: ; Description: This routine sets the X and Y registers to the address of 13: ; the memory section where the memory mapped 110 devices are located. This 14: ; address can then be used with an offset to access the memory mapped I/O 15: ; devices in the Commodore 64. The offset is the number of locations from 16: ; the beginning of the page on which the I/O register you want is located. 17: ; The X register contains the low order address byte, while the Y register 18: ; contains the high order address byte. 19: ; This routine exists to provide compatibility between the Commodore 64, 20: ; VIC-20, and future models of the Commodore 64. If the J/0 locations for 21: ; a machine language program are set by a call to this routine, they should 22: ; still remain compatible with future versions of the Commodore 64, the 23: ; KERNAL and BASIC. 24: ; 25: ; 26: ; How to Use: 27: ; 28: ; 1) Call this routine by using the JSR instruction. 29: ; 2) Store the X and the Y registers in consecutive locations. 30: ; 3) Load the Y register with the offset. 31: ; 4) Access that I/O location. 32: ; 33: ; EXAMPLE: 34: ; 35: ; ;SET THE DATA DIRECTION REGISTER OF THE USER PORT TO 0 (INPUT) 36: ; JSR IOBASE 37: ; STX POINT ;SET BASE REGISTERS 38: ; STY POINT+1 39: ; LDY #2 40: ; LDA #0 ;OFFSET FOR DDR OF THE USER PORT 41: ; STA (POINT),Y ;SET DDR TO 0 42: ; 43: ; 44: iIOBASE: 45: ; return IO base address in x/y 46: ; On the VIC-20 and C64, this is interpreted as 47: ; the base address of the first VIA/CIA. 48: 49: ldx #<IOBASE 50: ldy #>IOBASE 51: rts 52: 53: ; B-26. Function Name: SCREEN 54: ; 55: ; Purpose: Return screen format 56: ; Call address: $FFED (hex) 65517 (decimal) 57: ; Communication registers: X, Y 58: ; Preparatory routines: None 59: ; Stack requirements: 2 60: ; Registers affected: X, Y 61: ; 62: ; Description: This routine returns the format of the screen, e.g., 40 63: ; columns in X and 25 lines in Y. The routine can be used to determine what 64: ; machine a program is running on. This function has been implemented on 65: ; the Commodore 64 to help upward compatibility of your programs. 66: ; 67: ; 68: ; 69: ; 70: ; How to Use: 71: ; 72: ; 1) Call this routine. 73: ; 74: ; EXAMPLE: 75: ; 76: ; JSR SCREEN 77: ; STX MAXCOL 78: ; STY MAXROW 79: ; 80: ; 81: iSCREEN: 82: ; return screen resolution in x / y 83: 84: ldx #EDITOR_COLS 85: ldy #EDITOR_ROWS 86: rts 87: 88: ; B-19. Function Name: PLOT 89: ; 90: ; Purpose: Set cursor location 91: ; Call address: $FFF0 (hex) 65520 (decimal) 92: ; Communication registers: A, X, Y 93: ; Preparatory routines: None 94: ; Error returns: None 95: ; Stack requirements: 2 96: ; Registers affected: A, X, Y 97: ; 98: ; Description: A call to this routine with the accumulator carry flag 99: ; set loads the current position of the cursor on the screen (in X,Y 100: ; coordinates) into the Y and X registers. Y is the column number of the 101: ; cursor location (0-39), and X is the row number of the location of the 102: ; cursor (0-24). A call with the carry bit clear moves the cursor to X,Y 103: ; as determined by the Y and X registers. 104: ; 105: ; How to Use: 106: ; 107: ; 108: ; READING CURSOR LOCATION 109: ; 110: ; 1) Set the carry flag. 111: ; 2) Call this routine. 112: ; 3) Get the X and Y position from the Y and X registers, respectively. 113: ; 114: ; 115: ; SETTING CURSOR LOCATION 116: ; 117: ; 1) Clear carry flag. 118: ; 2) Set the Y and X registers to the desired cursor location. 119: ; 3) Call this routine. 120: ; 121: ; 122: ; EXAMPLE: 123: ; 124: ; ;MOVE THE CURSOR TO ROW 10, COLUMN 5 (5,10) 125: ; LDX #10 126: ; LDY #5 127: ; CLC 128: ; JSR PLOT 129: ; 130: ; 131: iPLOT: 132: bcs iPLOTReadOnly ; carry set -> read values 133: 134: JDLE50C: 135: stx zTBLX ; save new cursor pos: y position from X 136: sty zPNTR ; save new cursor pos: x position from Y 137: 138: jsr SET_CURSORPOS ; update all other internal states to the new position 139: 140: iPLOTReadOnly: 141: ldx zTBLX ; get cursor position in x and y 142: ldy zPNTR 143: 144: rts 145: 146: ; B-7. Function Name: CINT 147: ; 148: ; Purpose: Initialize screen editor & 6567 video chip 149: ; Call address: $FF81 (hex) 65409 (decimal) 150: ; Communication registers: None 151: ; Preparatory routines: None 152: ; Error returns: None 153: ; Stack requirements: 4 154: ; Registers affected: A, X, Y 155: ; 156: ; 157: ; Description: This routine sets up the 6567 video controller chip in the 158: ; Commodore 64 for normal operation. The KERNAL screen editor is also 159: ; initialized. This routine should be called by a Commodore 64 program 160: ; cartridge. 161: ; 162: ; How to Use: 163: ; 164: ; 1) Call this routine. 165: ; 166: ; EXAMPLE: 167: ; 168: ; JSR CINT 169: ; JMP RUN ;BEGIN EXECUTION 170: ; 171: ; 172: iCINT: jsr CLRCHN_AND_VIC_DEFAULTS 173: 174: .if CompileComputer < C64_GENERAL 175: 176: ; adjust the VIC-I to take the screen memory from the memory 177: ; area that is configured in lHIBASE. 178: 179: ; on the VIC-I, 180: ; bits 13-10 of the video RAM address is stored in VICI_O_MemoryLocations.7-VICI_O_MemoryLocations.4, 181: ; and bit 9 of the video RAM address is stored in VIC_02.7. 182: 183: ; Now, bit 13 of the VIC-I is connected to the INVERSE of A15 of the 6502. 184: ; Thus, the VIC-I sees another memory map than the 6502: 185: ; 186: ; VIC-I <-> 6502 187: ; $0000-$1FFF <-> $8000-$9FFF 188: ; $2000-$3FFF <-> $0000-$1FFF (*) 189: ; 190: ; (*) Note that the VIC-I cannot see $0400-$0FFF of the 6502 memory map 191: ; ($2400-$2FFF in the VIC-I memory map) due to the way the memory 192: ; is connected on the external RAM cartridge 193: 194: 195: lda lHIBASE ; get high byte of video RAM address 196: and #~$02 ; mask out bit 9 (bit 8-0 of the base address 197: ; must be 0, anyway) 198: 199: asl a ; shift the address to the right position 200: asl a 201: 202: ; here, A.7 - A.4 contain the address of the video RAM start, as needed in VICI_O_MemoryLocations 203: 204: ora #$80 ; b13 of the VIC-I is connected to the INVERSE of A15 205: ; of the 6502 (cf. comment above). 206: ; Take this into account and make the VIC-I see 207: ; the 6502 memory area $0000-$1FFF. 208: 209: sta VIC + VICI_O_MemoryLocations ; store b 210: 211: lda lHIBASE ; get back the high byte of the video RAM address 212: and #$02 ; is bit 9 set? 213: beq @NoSetBit9 ; no, branch -> do not set VICI_O_VideoColumns.7 214: ; (it has been already reset in CLRCHN_AND_VIC_DEFAULTS) 215: 216: lda #VICI_B_VideoColumns_ScreenMemoryB9 ; set bit 9 of video RAM address 217: ora VIC + VICI_O_VideoColumns ; in VICI_O_02.7 218: sta VIC + VICI_O_VideoColumns 219: 220: @NoSetBit9: 221: 222: .endif 223: 224: lda #$00 ; set editor mode 225: sta lMODE 226: 227: sta zBLNON ; blink mode: Currently, the cursor is not on 228: 229: lda #<CHECK_SHIFT_CTRL_CBM 230: sta lKEYLOG 231: lda #>CHECK_SHIFT_CTRL_CBM 232: sta lKEYLOG + 1 233: 234: lda #10 235: sta lXMAX ; maximum number of characters in the keyboard buffer is 10 236: sta lDELAY ; set delay for delay of the start of key repetition to default (10) 237: 238: lda #DEFAULT_COLOR ; set default color 239: sta lCOLOR 240: 241: lda #$04 ; set delay counter for key repetitions 242: sta lKOUNT 243: 244: lda #$0C 245: sta zBLNCT ; set the blink counter 246: sta zBLNSW ; disable cursor 247: 248: ; update the table of low bytes and link bits for the screen row 249: 250: ClearScreen: 251: lda lHIBASE ; get the high byte of the start of the video RAM 252: ora #$80 ; set link bit -> this row is not connected to the previous one 253: tay 254: lda #$00 ; low byte of the start of the video RAM (A) := 0 255: tax ; row counter (X) := 0, start in row zero 256: 257: @Next: sty zLDTB1,x ; store the high byte and the link bit of this line 258: 259: ; proceed to next row by adding the number of columns in one row (EDITOR_COLS) 260: 261: clc 262: adc #EDITOR_COLS ; add the number of columns in a line to the low byte 263: bcc @NoHighByte ; no carry -> we do not need to increment the high byte 264: iny ; increment the high byte 265: 266: @NoHighByte: 267: inx ; increment row counter 268: cpx #EDITOR_ROWS + 1 ; did we reach the last row? 269: bne @Next ; not yet, store the next high byte and link bit 270: 271: lda #$FF ; write the "end marker" 272: sta zLDTB1,x ; into the location for the row past the last one 273: 274: ; Erase the screen rows (overwrite with spaces) 275: 276: ldx #EDITOR_ROWS - 1 ; start in the last row 277: @NextLine: 278: jsr EraseScreenRow ; erase the row 279: dex ; go to previous line 280: bpl @NextLine ; not all rows are processed, branch -> process previous one 281: 282: CURSOR_HOME: 283: ; set cursor position to 0/0 284: 285: ldy #0 286: sty zPNTR ; column 287: sty zTBLX ; row 288: 289: SET_CURSORPOS: 290: 291: ; this routine updates the internal pointer to conform to the cursor 292: ; position set in zPNTR/zTBLX. As this function is used from other 293: ; places, for example from iPLOT, it is completely implemented, and it 294: ; does not use any hard-coded constants for CURSOR_HOME only. 295: 296: ldx zTBLX ; get row into X 297: lda zPNTR ; get column into A 298: 299: @AddLine: 300: ldy zLDTB1,x ; is this row combined with the previous one? 301: bmi @StandaloneLine ; no, branch 302: 303: ; otherwise, add the number of columns to the col position 304: clc 305: adc #EDITOR_COLS 306: sta zPNTR ; store (updated) column position 307: dex ; ... and the row is one less 308: bpl @AddLine ; unconditional jump (row 0 should never be combined with the previous row!) 309: ; -------------- 310: 311: @StandaloneLine: 312: 313: .if CompileComputer >= C64_03 .or .defined(C64JAPAN) 314: jsr CalculateScreenPointerFromRowNumber ; This is essentially the same as the VIC20 (and C64-02 and earlier) implementation. Only the order in which high and low byte are calculated is changed. 315: ; This subroutine is used to gain memory for the later patch 316: .else 317: lda zLDTB1,x ; get high byte of the starting address of this row 318: and #>lVIDEORAM_SIZE ; mask out additional bits used as flags 319: ora lHIBASE ; add the video RAM base 320: sta zPNT + 1 ; remember high byte 321: 322: lda SCREEN_LOWBYTE,x ; get low byte of the starting address of this row 323: sta zPNT ; remember low byte 324: 325: .endif 326: 327: ; calculate the number of columns (more precisely: The last column number) 328: ; in this logical line 329: 330: lda #EDITOR_COLS - 1 ; start with one physical line 331: 332: inx ; Here, X points to the first line *before* the extended long line. Thus, go back into the long line area 333: 334: @Loop: ldy zLDTB1,x ; is this line combined with the previous one? 335: bmi @StoreLineLength ; no, branch -> quit loop 336: 337: clc ; add a complete line length 338: adc #EDITOR_COLS 339: 340: inx ; proceed to the next line 341: bpl @Loop ; (unconditional branch) 342: ; ----------------------------- 343: 344: @StoreLineLength: 345: sta zLNMX ; store line length 346: 347: .if CompileComputer >= C64_03 .or .defined(C64JAPAN) 348: ; this fixes a bug in the C64 ROMs: 349: ; If the last row is combined to build a long line (80 chars), 350: ; and the last character is deleted afterwards with backspace, 351: ; the C64 will start a LOAD command and will not react 352: ; anymore unless there is an attached tape recorder. 353: 354: ; This patch fixes this: 355: 356: jmp UpdateColorRAMPointerToVideoramPointer ; also update the color RAM pointer (zUSER) 357: 358: ; this is another patch on the C64-03 ROMs: 359: ; TODO: why? 360: ; 361: ; It is called after LDX zTBLX (get current cursor row) 362: 363: Patch_CursorOneRowUp: 364: cpx zLXSP ; did the cursor row change while we were in the routine? 365: beq @Ret ; no -> branch, we're done 366: jmp CursorOneRowUp 367: @Ret: rts 368: 369: nop 370: 371: .else 372: rts 373: .endif 374: 375: 376: ; unused in VIC20 and C64 ROM! 377: 378: jsr CLRCHN_AND_VIC_DEFAULTS 379: jmp CURSOR_HOME 380: 381: 382: CLRCHN_AND_VIC_DEFAULTS: 383: ; This routine restores input and output to the terminal 384: ; (screen and keyboard). 385: ; Afterwards, it initialises the VIC (or VIC-II) registers 386: 387: lda #FILE_SCREEN ; default output to screen 388: sta zDFLTO 389: lda #FILE_KEYBOARD ; default input to keyboard 390: sta zDFLTN 391: 392: SET_VIC_DEFAULTS: 393: 394: ; This routine initialises the VIC (or VIC-II) registers 395: 396: ; Loop throught the table and overwrite the VIC (-II) registers 397: ; with the table contents 398: 399: ldx #END_VIC_DEFAULTS - VIC_DEFAULTS + 1 ; number of register values in the table 400: @Loop: lda VIC_DEFAULTS - 1,x 401: sta VIC - 1,x 402: dex 403: bne @Loop 404: rts 405: 406: GETIN_KEYB: 407: 408: ; Get a character from the keyboard buffer 409: ; this function returns a character from the keyboard buffer 410: ; It also deletes it from there. 411: ; 412: ; Prerequisites: 413: ; 414: ; - Before calling this function, the I flag must be set (SEI) 415: ; It will be cleared on exit 416: ; 417: ; - Make sure the keyboard buffer is not empty before calling this function! 418: 419: ldy lKEYD ; remember first key press in the keyboard buffer 420: 421: ; move all key presses in the keyboard buffer one step to the front 422: 423: ldx #0 424: @Loop: lda lKEYD + 1,x ; move entry one step ahead 425: sta lKEYD,x 426: inx ; proceed to next one 427: cpx zNDX ; did we already process all keys? 428: bne @Loop ; no, branch -> process the next key 429: 430: dec zNDX ; we just removed and key, thus, decrement the number of keys in the buffer 431: 432: tya ; get back the first key press in the keyboard buffer 433: 434: cli 435: clc ; quit with success 436: rts 437: 438: OutputCharacterAndWaitForKeyPress: 439: jsr CHROUT_SCREEN 440: 441: WaitForKeyPress: 442: lda zNDX ; number of key presses in keyboard buffer 443: sta zBLNSW ; if > 0: disable cursor blinking, otherwise: Enable cursor blinking 444: sta lAUTODN ; If there was some key press, mark that any output that will combine two rows will scroll down the screen contents 445: ; (this loop cannot be quit with lAUTODN = 0) 446: beq WaitForKeyPress ; no key presses -> wait until some key has been pressed 447: 448: ; now that one or more key has been pressed, output it/them 449: 450: ; first, restore the character under the cursor (if the cursor has been visible) 451: 452: sei 453: lda zBLNON ; cursor currently visible? 454: beq @CursorNotVisible ; no, skip restoring it 455: 456: ; restore character under the cursor 457: 458: lda zGDBLN ; get character code 459: ldx lGDCOL ; and color of character under cursor 460: 461: ldy #0 462: sty zBLNON ; mark: Cursor is currently invisible 463: 464: jsr StoreCharacterOnScreenAndDisableBlinking ; store the character under the cursor on the screen 465: 466: @CursorNotVisible: 467: 468: .ifdef JIFFY 469: jsr JDLF9E5 470: .else 471: jsr GETIN_KEYB ; get the next character 472: .endif 473: cmp #KEY_SHIFTRUN ; was is Shift + Run/Stop? 474: bne NoShiftRunStop ; no, branch -> jump special processing 475: 476: ; If we reach here, the user pressed Shift + Run/Stop 477: ; Then, store the special text into the keyboard buffer and 478: ; process the characters, one after the other. 479: ; 480: ; Note that any other key presses that might have been 481: ; in the keyboard buffer are removed. 482: 483: ldx #END_TEXT_SHIFTRUNSTOP - TEXT_SHIFTRUNSTOP 484: sei 485: stx zNDX ; set the count of characters 486: 487: @ShiftRunStop: 488: lda TEXT_SHIFTRUNSTOP - 1,x ; copy text 489: sta lKEYD - 1,x ; into the keyboard buffer 490: dex 491: bne @ShiftRunStop ; until all characters have been processed 492: beq WaitForKeyPress ; now, process the key presses (uncond. branch) 493: ; ------------------------------- 494: 495: NoShiftRunStop: 496: cmp #ASC_CR ; was the key a CR? 497: bne OutputCharacterAndWaitForKeyPress ; no, output the character and wait for the next key press 498: 499: ; When we reach here, the user has entered anything and pressed CR. 500: ; Now, we process the input 501: 502: ldy zLNMX ; get the (logical) line length of the current line 503: sty zCRSW ; store it as number of characters to read 504: 505: @CheckSpaceNext: 506: lda (zPNT),y ; read the next character at the end of the line 507: cmp #' ' ; is it a space? 508: bne @NoSpace ; No -> branch, 509: dey ; Yes, it was a space: Test the previous character 510: bne @CheckSpaceNext ; until we have checked all characters in this line, branch 511: 512: @NoSpace: 513: iny 514: sty zINDX ; remember the number of characters in the current line 515: ldy #0 516: sty lAUTODN ; Mark: No key press yet, thus, any output will scroll down the screen contents if some rows will be combined 517: sty zPNTR ; start reading at the beginning of the line 518: sty zQTSW ; We are not in quotation mark mode 519: lda zLXSP ; value of zTBLX before calling BASIN (zTBLX is not changed when calling GETIN 520: bmi BASIN_KEYB_PROCESS_KEY ; TODO what? 521: 522: ldx zTBLX ; current cursor row on screen 523: 524: ; set the cursor one (virtual) row up 525: 526: .if CompileComputer >= C64_03 .or .defined(C64JAPAN) 527: ; for -03 ROMs, it was decided that this the cursor row is only moved up 528: ; if it has already changed since this function began 529: ; TODO why? 530: ; 531: jsr Patch_CursorOneRowUp 532: .else 533: jsr CursorOneRowUp 534: .endif 535: 536: ; here: with X := current row (modified in CursorOneRowUp / Patch_CursorOneRowUp) 537: 538: cpx zLXSP ; has the cursor row on screen changed? 539: bne BASIN_KEYB_PROCESS_KEY ; yes -> branch, get keyboard input 540: 541: .if CompileComputer < C64_GENERAL 542: bne BASIN_KEYB_PROCESS_KEY ; some superfluous leftover 543: .endif 544: 545: lda zTEMP_zPNTR ; restore current cursor column (zPNTR) from zTEMP_zPNTR 546: sta zPNTR 547: cmp zINDX ; did the column change while we were in the routine? 548: bcc BASIN_KEYB_PROCESS_KEY ; we are now to the left of the column at the beginning -> branch, get new key input 549: bcs BASIN_KEYB_END_LINE ; we are at the same column or right from it -> branch, done 550: ; ------------------------- 551: 552: BASIN_KEYB: 553: 554: ; remember Y and X on the stack 555: 556: tya 557: pha 558: txa 559: pha 560: 561: lda zCRSW ; has CR been pressed already? 562: ; that is, are there already keys to 563: ; process on the screen? 564: beq WaitForKeyPress ; No, wait for input of a complete line 565: 566: BASIN_KEYB_PROCESS_KEY: 567: ldy zPNTR ; get pointer into current line 568: lda (zPNT),y ; get current character at that position 569: 570: .if CompileComputer >= C64_GENERAL 571: .elseif CompileComputer >= VIC20_06 572: 573: ; FillUntil $E672,$EA 574: FillNOP 23 575: 576: .else 577: 578: ; It seems the VIC20_0ß2 ROM has some kind of "cooked" screen codes. 579: ; This routine converts some characters into others, bypassing the 580: ; screen code to PETSCII conversion later 581: 582: ldx lMODE ; if lMODE == 0 then we do not use the "cooked" mode 583: beq @End ; Thus, in this case, skip the conversion 584: 585: ldx #SpecialScreenCodeHandleTable_END - SpecialScreenCodeHandleTable - 2 586: @FindChar: 587: cmp SpecialScreenCodeHandleTable,x ; is the current character a special one? 588: beq @FoundCharacter ; yes, branch -> convert it 589: dex ; no, proceed to previous special character 590: dex 591: bpl @FindChar ; test the next char 592: bmi @End ; table has completed -> branch, quit 593: ; --------------- 594: 595: @FoundCharacter: 596: lda SpecialScreenCodeHandleTable + 1,x ; convert the screen code to the replacement 597: bne @ProceedToNextScreenLocation ; (uncond. branch) 598: ; -------------------------------------- 599: 600: @End: 601: 602: .endif 603: 604: ; convert the character (in A) into PETSCII TODO 605: ; 606: ; Here, we convert the codes as follows: 607: ; 608: ; SCREEN CODE -> PETSCII 609: ; $00-$1F -> $40-$5F 610: ; $20-$3F -> $20-$3F 611: ; $40-$5F -> $60-$7F 612: ; TODO ??? 613: ; 614: 615: sta zSCHAR ; store the character 616: 617: and #$3F ; mask out the upper 2 bits (7, 6) 618: asl zSCHAR ; put bit 7 into C 619: bit zSCHAR ; test the remaining part 620: 621: ; now, we have the following status of the flags: 622: ; C = bit 7 of A on input 623: ; N = bit 6 of A on input 624: ; V = bit 5 of A on input 625: 626: bpl @DoNotSetBit7 ; N=0 -> bit 6 was 0, that is, we have $00-$3F or $80-$BF 627: 628: ora #$80 ; otherwise, set bit 7 629: 630: @DoNotSetBit7: 631: bcc @Process0x00_To_0x7F ; was bit 7 == 0? --> branch 632: 633: ldx zQTSW ; Check quotation mark mode 634: bne @ProceedToNextScreenLocation ; branch if we are in quotation mark mode 635: 636: @Process0x00_To_0x7F: 637: bvs @ProceedToNextScreenLocation ; was bit 5 == 1? --> branch 638: ora #$40 ; otherwise, set bit 6 639: 640: ; here, we converted: (TODO: check again!) 641: ; $00-$1F -> $40-$5F 642: ; $20-$3F -> $20-$3F 643: ; $40-$5F -> $80-$9F 644: ; $60-$7F -> $C0-$DF 645: 646: @ProceedToNextScreenLocation: 647: inc zPNTR ; proceed to next screen location 648: 649: jsr CheckQuote ; update the quotation mark mode flag 650: 651: cpy zINDX ; have we reached the end of the line? 652: bne BASIN_KEYB_QUIT ; no, return the current character 653: 654: ; if we reach here, then we have read the complete line 655: ; Thus, clear all states and return the CR as marker for end-of-line 656: 657: BASIN_KEYB_END_LINE: 658: lda #0 659: sta zCRSW ; remember: We do not have any characters anymore 660: lda #ASC_CR ; return a CR Value 661: 662: ldx zDFLTN 663: cpx #FILE_SCREEN ; default input file = screen? 664: beq @OutputCharacter ; yes, output the CR 665: 666: ldx zDFLTO 667: cpx #FILE_SCREEN ; default output file = screen? 668: beq @QuitWithCR ; yes, quit 669: 670: ; if we reach here, the input was from the keyboard, and the output was not the screen. 671: ; Thus, output the CR we got from the keyboard 672: 673: @OutputCharacter: 674: jsr CHROUT_SCREEN ; output the character on the screen 675: 676: @QuitWithCR: 677: lda #ASC_CR ; return a CR value 678: 679: BASIN_KEYB_QUIT: 680: sta zSCHAR ; remember read char 681: 682: ; restore X and Y from stack 683: pla 684: tax 685: pla 686: tay 687: 688: lda zSCHAR ; get back remembered read char 689: cmp #ASC_PI ; is it the PETSCII code for PI? 690: bne @ClcRts ; no, branch -> we are done 691: lda #TokPi ; yes, replace it by the BASIC token for PI (TODO why did CBM choose this route?) 692: @ClcRts: 693: clc ; we successfully ended the routine 694: rts 695: ; -------------- 696: 697: CheckQuote: 698: cmp #'"' ; Is the current char a quotation mark? 699: bne @Rts ; no, quit 700: 701: ; invert the state of the quotation mark 702: lda zQTSW 703: eor #$01 704: sta zQTSW 705: 706: lda #'"' ; restore the character 707: @Rts: rts 708: 709: 710: ; @@@@@ 711: 712: LE691: ora #$40 713: 714: CHROUT_SCREEN_OUTPUT_WITH_TEST_RVS: 715: ldx zRVS ; Is the flag "output in reverse" set? 716: beq CHROUT_OUTPUT_SCREEN_IN_NORMAL ; no -> branch, output in normal 717: 718: CHROUT_SCREEN_OUTPUT_IN_RVS: 719: ora #$80 ; setting bit 7 of the char to output: reverse the char 720: 721: CHROUT_OUTPUT_SCREEN_IN_NORMAL: 722: ldx zINSRT ; Number of characters to output in "insert mode" 723: beq @NoInsertMode ; none -> we are not in insert mode -> branch 724: dec zINSRT ; decrement number of characters to output in revers mode 725: 726: @NoInsertMode: 727: ldx lCOLOR ; get the current color 728: jsr StoreCharacterOnScreenAndDisableBlinking ; output character in A, color in X 729: jsr MoveCursorRightAfterOutput ; move the cursor to the next output position 730: 731: CHROUT_SCREEN_END: 732: pla ; restore Y from stack 733: tay 734: 735: lda zINSRT ; insert mode? 736: beq @DontStopQuotationMode ; no, branch 737: lsr zQTSW ; end quotation mark mode 738: @DontStopQuotationMode: 739: pla ; restore X from stack 740: tax 741: 742: pla ; restore A from stack 743: clc ; we ended successfully 744: cli 745: rts 746: ; -------------- 747: 748: MoveCursorRightAfterOutput: 749: jsr AdjustCursorRowBeforeMovingRight ; if we will move to the next row, increment row number 750: inc zPNTR ; increment column into current row -> move cursor to the right 751: lda zLNMX ; get number of column in current row 752: cmp zPNTR ; did we go past the last column? 753: bcs EditorRts ; no -> branch, we do not need to adjust column 754: cmp #(EDITOR_MAX_COMBINED_ROWS * EDITOR_COLS) - 1 ; did we reach the maximum length of a virtual row? 755: beq SetCursorToTheBeginningOfTheNextLine ; yes -> branch, set cursor to the beginning of the next line 756: 757: lda lAUTODN ; do we have to scroll down the screen contents? 758: beq @CombineRows ; no, skip the scrolling 759: jmp LE967 ; (will return to LogicallyCombineTwoRows) 760: ; ------------------ 761: 762: @CombineRows: 763: ldx zTBLX 764: cpx #EDITOR_ROWS 765: bcc LogicallyCombineTwoRows 766: jsr LE8EA 767: dec zTBLX 768: ldx zTBLX 769: 770: LogicallyCombineTwoRows: 771: asl zLDTB1,x ; clear bit 7 -> combine this phyiscal row with the previous one 772: lsr zLDTB1,x 773: 774: .macro EDITOR_PATCH_LogicallyCombineTwoRows_FIX 775: 776: ; only present on VIC20-06 ROMs and above, and C64 ROMs. 777: 778: ; mark the next row as being stand-alone 779: 780: ; TODO what exactly does this patch fix? 781: 782: inx ; go to the next row 783: lda zLDTB1,x 784: ora #$80 ; set bit 7 --> this row is not combined with the previous one 785: sta zLDTB1,x 786: dex ; go back to the previous row 787: .endmacro 788: 789: .macro EDITOR_PATCH_LogicallyCombineTwoRows_COMMON 790: ; from here on, this is done for all variants, including the VIC20-2 791: 792: lda zLNMX ; maximum number of columns on the current (virtual) row 793: clc 794: .endmacro 795: 796: ; depending on the firmware built, 797: .if CompileComputer >= C64_GENERAL 798: EDITOR_PATCH_LogicallyCombineTwoRows_FIX 799: EDITOR_PATCH_LogicallyCombineTwoRows_COMMON 800: .elseif CompileComputer >= VIC20_06 801: ; on the VIC20-06 and -07, this patch is really a patch. 802: ; We come back with a JMP 803: jmp EditorPatchLogicallyCombineTwoRows 804: EditorPatchLogicallyCombineTwoRows_Return: 805: 806: .else 807: ; old implementation for VIC20-02 808: EDITOR_PATCH_LogicallyCombineTwoRows_COMMON 809: .endif 810: 811: adc #EDITOR_COLS ; add the number of column of one (physical) row 812: sta zLNMX ; and set it as the new maximum number of columns on the current (virtual) row 813: 814: CursorOneRowUp: 815: ; input: X := Cursor row 816: ; 817: ; set the cursor row to point to the (virtual) row above us. 818: 819: lda zLDTB1,x ; is the current row combined with the previous one? 820: bmi @NotCombined ; no, we're done 821: dex ; cursor on (physical) row up 822: bne CursorOneRowUp ; not 0 -> not at top of screen -> branch, test the next (physical) row 823: 824: @NotCombined: 825: jmp CalculateScreenPointerFromRowNumber ; adjust screen pointer 826: ; ----------------------------------------- 827: 828: SetCursorToTheBeginningOfTheNextLine: 829: dec zTBLX ; go up one row (will be undone in the next routine) 830: jsr GoDownOneVirtualRow ; go down one (virtual) row 831: lda #0 832: sta zPNTR ; set column to the beginning of the row 833: EditorRts: 834: rts 835: ; ----------------------------------------- 836: 837: 838: ; Perform the wrap-around to the previous row of 839: ; INS/DEL or CRSR LEFT is pressed on the leftmost column. 840: ; 841: ; If the cursor is not at the home position, it 842: ; puts the cursor one row to the top, and on the last 843: ; column if that row. 844: ; 845: ; NOTE: 846: ; If the cursor is already at the home position, 847: ; this function removes the return address from the stack! 848: ; Instead, it jumps to CHROUT_SCREEN_END. 849: ; 850: CHROUT_SCREEN_WrapAroundToPreviousRow: 851: ldx zTBLX ; get row of current cursor position 852: bne @CanGoBack ; not zero -> branch 853: 854: ; if we reach here, then we are already on the first ("0th") row, and we are in the first ("0th") column (as we were called in the first place). 855: ; Thus, we do not have an option to go more to the left. 856: 857: stx zPNTR ; set column to 0 (TODO: should not be necessary, as it is already set to 0!) 858: 859: ; Remove the return address from the stack: 860: ; we do not want to return to the caller; 861: ; instead, we will abort the output! 862: ; 863: pla 864: pla 865: 866: bne CHROUT_SCREEN_END ; end the output (uncond. branch as long as the caller of the caller does not reside on the memory area $00xx.) 867: ; ----------------------- 868: 869: @CanGoBack: 870: dex 871: stx zTBLX ; set the cursor one row to the top 872: 873: jsr SET_CURSORPOS ; set the cursor position (and calculate the line length of the current line, in zLNMX) 874: 875: ; set the cursor to the last column of the line 876: ldy zLNMX ; get current (virtual) line length 877: sty zPNTR ; and set the cursor to that column 878: rts 879: 880: ; CHROUT onto screen 881: ; 882: ; Output the character in A to the current cursor position on the screen 883: ; 884: CHROUT_SCREEN: 885: pha ; remember the character to output on stack 886: sta zSCHAR ; and in memory 887: 888: ; remember X and Y on the stack 889: txa 890: pha 891: tya 892: pha 893: 894: lda #$00 ; no CR has been pressed yet 895: sta zCRSW ; That is, on next BASIN, the routine will wait for an input again, regardless if the input has been completely used yet. 896: 897: ldy zPNTR ; get pointer into current (logical) line 898: lda zSCHAR ; character to be output 899: bpl @PositiveChar ; is it positive (<= $7F) -> branch 900: jmp @NegativeChar 901: ; ------------ 902: 903: @PositiveChar: 904: cmp #ASC_CR ; is the character a CR? 905: bne @NoCR ; No -> branch, next test 906: jmp CHROUT_SCREEN_CR ; Output a CR 907: 908: @NoCR: 909: ; Here, we convert the codes as follows: 910: ; 911: ; PETSCII -> SCREEN CODE 912: ; $20-$3F -> $20-$3F 913: ; $40-$5F -> $00-$1F 914: ; $60-$7F -> $40-$5F 915: 916: cmp #$20 ; is the character a control code (< $20)? 917: bcc @TestControlCode ; yes, process the control code 918: 919: cmp #$60 ; is the character small than $60 (i.e., $20..$5F)? 920: bcc @Convert0x20_0x60 ; yes, branch -> convert char 921: and #~$20 ; convert $60-$7F --> $40-$5F 922: bne @CheckQuoteAndOutput ; (uncond. branch) 923: ; ----------------- 924: 925: @Convert0x20_0x60: 926: and #$3F ; converts $20-$3F --> $20-$3F, but $40-$5F -> $00-$1F 927: 928: @CheckQuoteAndOutput: 929: jsr CheckQuote ; update quote state, if necessary 930: jmp CHROUT_SCREEN_OUTPUT_WITH_TEST_RVS 931: ; ----------------- 932: 933: @TestControlCode: 934: ldx zINSRT ; are we in insert mode? 935: beq @ProcessControlCode ; no, branch -> process control codes 936: jmp CHROUT_SCREEN_OUTPUT_IN_RVS ; output the control codes in reverse (and quit), do not process them 937: ; ----------------- 938: 939: @ProcessControlCode: 940: cmp #ASC_INSDEL ; is the character an INS/DEL? 941: bne @NoINSDEL ; no -> branch, skip special handling of INS/DEL 942: 943: tya ; A := Y (zPNTR), offset of current column into current screen line 944: bne @NotFirstColumn ; not the first column -> branch 945: 946: jsr CHROUT_SCREEN_WrapAroundToPreviousRow ; Perform the wrap around to the previous row, putting the cursor on the rightmost column of the previous line. 947: ; If we are at the home position already, this function does NOT return, but goes to CHROUT_SCREEN_END instead. 948: jmp @AddBlankAtCurrentPosition 949: ; ----------------- 950: 951: @NotFirstColumn: 952: jsr AdjustCursorRowBeforeMovingLeft ; we want to move the cursor to the left. If we will cross a row this way, decrement the row number. 953: 954: ; move cursor one to the left 955: 956: dey 957: sty zPNTR 958: jsr UpdateColorRAMPointerToVideoramPointer ; update color RAM pointer 959: 960: ; move the screen parts to the right of the cursor one to the left 961: 962: @MoveLoop: 963: iny ; get the char to the right 964: lda (zPNT),y 965: dey ; and copy it one to the left 966: sta (zPNT),y 967: 968: iny ; get the color to the right 969: lda (zUSER),y 970: dey ; and copy it one to the left 971: sta (zUSER),y 972: 973: iny ; proceed to the next position (to the right) 974: cpy zLNMX ; did we reach the end of the (logical) line? 975: bne @MoveLoop ; no, move the next char 976: 977: ; if we "fall through", then Y points to the last location on the current (logical) screen line 978: 979: @AddBlankAtCurrentPosition: 980: lda #' ' ; put a space char (blank) 981: sta (zPNT),y ; into the current screen location 982: lda lCOLOR ; put the default color 983: sta (zUSER),y ; into the current color location 984: bpl @End2 ; BUG: This is meant as an uncond. branch. It is one as long as no-one has the idea to put a negative color into lCOLOR! 985: ; ------------------ 986: 987: @NoINSDEL: 988: ldx zQTSW ; are we in quotation mark mode? 989: beq @NoQuotationMode ; no -> branch 990: jmp CHROUT_SCREEN_OUTPUT_IN_RVS ; output the control codes in reverse 991: ; --------------------------------- 992: 993: @NoQuotationMode: 994: cmp #ASC_RVS ; character code for reverse (RVS) mode? 995: bne @NotReverse ; no -> branch, next test 996: sta zRVS ; remember the reverse mode 997: 998: @NotReverse: 999: cmp #ASC_HOME ; character code for cursor home? 1000: bne @NoCrsrHome ; no -> branch, next test 1001: jsr CURSOR_HOME ; put the cursor at the home position 1002: 1003: @NoCrsrHome: 1004: cmp #ASC_CURSORLEFTRIGHT ; character code for cursor left/right? 1005: bne @NoCrsrLeftRight ; no -> branch, next test 1006: 1007: iny ; move cursor to the right 1008: jsr AdjustCursorRowBeforeMovingRight ; if we will move to the next row, increment row number 1009: sty zPNTR ; store cursor column 1010: 1011: dey ; get old cursor position back 1012: cpy zLNMX ; was the cursor before the end of the (virtual) row? 1013: bcc @End ; yes -> branch 1014: 1015: ; If we reach here, we moved from the end of the previous row to the current row 1016: 1017: dec zTBLX ; decrement the row number (go up one row) 1018: ; the first operation GoDownOneVirtualRow does is increment 1019: ; the row number. This dec is a countermeasure 1020: ; for this incrementing. 1021: jsr GoDownOneVirtualRow ; go down one (virtual) row 1022: ldy #0 ; set cursor to the beginning of the row 1023: @StoreColAndEnd: 1024: sty zPNTR 1025: 1026: @End: jmp CHROUT_SCREEN_END 1027: ; ------------------------- 1028: 1029: @NoCrsrLeftRight: 1030: cmp #ASC_CURSORUPDOWN ; character code for cursor up/down? 1031: bne @NoCrsrUpDown ; no -> branch, next test 1032: 1033: ; In case we moved down one phyiscal row, but we are still in the 1034: ; same (virtual) row, we calculate the new column we would be at 1035: ; If this case is not true, the calculation will be thrown away. 1036: ; Otherwise, we will use this value. 1037: 1038: clc 1039: tya ; A := Y (current column number) 1040: adc #EDITOR_COLS ; add the number of columns in a physical row 1041: tay ; Y := A (column number if we are still in the same virtual row) 1042: 1043: ; 1044: inc zTBLX ; go down one row 1045: cmp zLNMX ; compare just calculated column number with maximum number of column in the current row 1046: bcc @StoreColAndEnd ; calculated row number is smaller -> we are still in the same virtual row -> branch, store column 1047: beq @StoreColAndEnd ; calculated row number is equal -> we are still in the same virtual row -> branch, store column 1048: dec zTBLX ; go up one row (again to where we started) 1049: ; this is a preparation to the JSR GoDownOneVirtualRow below 1050: 1051: ; "Normalise" the column (in zPNTR) 1052: ; That is, calculate zPNTR MOD EDITOR_COLS with a loop 1053: ; TODO why? 1054: 1055: @Normalise: 1056: ; sec, but we already have C=1: If we come from "above", then we would have branched in the bcc 1057: ; if C=0 1058: ; if we looped, then we would have branched in the other bcc from below 1059: 1060: sbc #EDITOR_COLS ; subtract the number of columns in a physical row 1061: bcc @GoDown ; if we reached < 0, end the loop 1062: sta zPNTR ; store the column 1063: bne @Normalise ; if we did not reach 0 yet, loop again 1064: 1065: @GoDown: 1066: jsr GoDownOneVirtualRow ; go down one (virtual) row 1067: @End2: 1068: jmp CHROUT_SCREEN_END 1069: 1070: @NoCrsrUpDown: 1071: jsr EditorCheckColorCodeAndSetColor ; check if the current PETSCII code is a color. IF yes, set lCOLOR. Return anyway 1072: 1073: .if CompileComputer >= VIC20_06 1074: jmp EditorCheckForAscLowercase ; check for additional codes (change uppercase, change lowercase, allow changing uppercase/lowercase, disallow it) 1075: .else 1076: jmp CHROUT_SCREEN_END ; we're done 1077: .endif 1078: 1079: 1080: @NegativeChar: 1081: 1082: .if CompileComputer >= C64_GENERAL 1083: 1084: .elseif CompileComputer < VIC20_06 1085: ; depending on lMODE, the old VIC20 KERNAL does some translation of 1086: ; character codes to be output. 1087: ; All of these codes being replaced have in common that their 1088: ; 7th bit ($80) is set. 1089: ; 1090: ; TODO Why is this done? 1091: 1092: ldx lMODE ; get lMODE 1093: beq @LE815 ; is it 0? Then do NOT do any conversion 1094: 1095: ldx #$31 1096: @LE807: cmp CHROUT_REPLACEMENT_TABLE,x 1097: beq @LE812 1098: dex 1099: dex 1100: bpl @LE807 1101: bmi @LE815 1102: @LE812: lda CHROUT_REPLACEMENT_TABLE - 1,x 1103: .else 1104: 1105: ; FillUntil $E815, $EA 1106: FillNOP 21 1107: 1108: .endif 1109: 1110: @LE815: 1111: 1112: and #$7F 1113: cmp #TokPi - $80 1114: bne @LE7DC 1115: .if .defined(C64JAPAN) 1116: lda #ASC_PI - $40 ; @@@??? 1117: .else 1118: lda #ASC_PI - $80 1119: .endif 1120: @LE7DC: 1121: .if CompileComputer >= C64_GENERAL 1122: 1123: .elseif CompileComputer >= VIC20_06 1124: .repeat 6 1125: nop 1126: .endrep 1127: .else 1128: cmp #$04 1129: bne @LE823 1130: lda #$7F 1131: .endif 1132: 1133: @LE823: 1134: cmp #' ' 1135: bcc @LE7E3 1136: jmp LE691 1137: ; ---------------- 1138: 1139: @LE7E3: cmp #ASC_CR 1140: bne @LE7EA 1141: jmp CHROUT_SCREEN_CR 1142: 1143: @LE7EA: ldx zQTSW ; are we in quotation mark mode? 1144: bne @LE82D ; yes -> branch 1145: cmp #ASC_INSDEL 1146: bne @LE829 1147: ldy zLNMX 1148: lda (zPNT),y 1149: cmp #' ' 1150: bne @LE7FE 1151: cpy zPNTR 1152: bne @LE805 1153: @LE7FE: cpy #(EDITOR_MAX_COMBINED_ROWS * EDITOR_COLS) - 1 1154: beq @LE826 1155: jsr LE965 1156: @LE805: ldy zLNMX 1157: jsr UpdateColorRAMPointerToVideoramPointer 1158: @LE80A: dey 1159: lda (zPNT),y 1160: iny 1161: sta (zPNT),y 1162: dey 1163: lda (zUSER),y 1164: iny 1165: sta (zUSER),y 1166: dey 1167: cpy zPNTR 1168: bne @LE80A 1169: lda #' ' 1170: sta (zPNT),y 1171: lda lCOLOR 1172: sta (zUSER),y 1173: inc zINSRT ; increment number of characters to output in insert mode 1174: @LE826: jmp CHROUT_SCREEN_END 1175: ; ----------------------- 1176: 1177: @LE829: ldx zINSRT ; number of characters to output in insert mode 1178: beq @LE832 1179: @LE82D: ora #$40 1180: jmp CHROUT_SCREEN_OUTPUT_IN_RVS 1181: 1182: @LE832: cmp #ASC_CURSORUPDOWN 1183: bne @LE84C 1184: ldx zTBLX 1185: beq @LE871 1186: dec zTBLX 1187: lda zPNTR 1188: sec 1189: sbc #EDITOR_COLS 1190: bcc @LE847 1191: sta zPNTR 1192: bpl @LE871 1193: @LE847: jsr SET_CURSORPOS 1194: bne @LE871 1195: @LE84C: cmp #ASC_RVS 1196: bne @LE854 1197: lda #$00 1198: sta zRVS 1199: @LE854: cmp #ASC_CURSORLEFTRIGHT 1200: bne @LE86A 1201: tya 1202: beq @LE864 1203: jsr AdjustCursorRowBeforeMovingLeft ; we want to move the cursor to the left. If we will cross a row this way, decrement the row number. 1204: dey 1205: sty zPNTR 1206: jmp CHROUT_SCREEN_END 1207: 1208: @LE864: jsr CHROUT_SCREEN_WrapAroundToPreviousRow 1209: jmp CHROUT_SCREEN_END 1210: @LE86A: cmp #ASC_HOME 1211: bne @LE874 1212: jsr ClearScreen 1213: @LE871: jmp CHROUT_SCREEN_END 1214: @LE874: ora #$80 1215: jsr EditorCheckColorCodeAndSetColor 1216: .if CompileComputer >= VIC20_06 1217: jmp EditorCheckForAscUppercase 1218: .else 1219: jmp CHROUT_SCREEN_END 1220: .endif 1221: ; ----------------------- 1222: 1223: GoDownOneVirtualRow: 1224: lsr zLXSP 1225: ldx zTBLX 1226: @LE880: inx 1227: cpx #EDITOR_ROWS 1228: bne @LE888 1229: jsr LE8EA 1230: @LE888: lda zLDTB1,x 1231: bpl @LE880 1232: stx zTBLX 1233: jmp SET_CURSORPOS 1234: 1235: CHROUT_SCREEN_CR: 1236: ; output a CR onto the screen at the current cursor position 1237: 1238: ldx #$00 1239: stx zINSRT ; end INSERT mode 1240: stx zRVS ; end REVERSE (RVS) mode 1241: stx zQTSW ; end quotation mark mode 1242: stx zPNTR ; put cursor to the beginning of the current line (that is, CR w/o NL, so to speak) 1243: 1244: jsr GoDownOneVirtualRow ; go down one (virtual) row 1245: jmp CHROUT_SCREEN_END 1246: ; -------------- 1247: 1248: ; If the cursor will be part of the previous row after being moved to the left 1249: ; (that is, the cursor is at the beginning of the current row now), move 1250: ; the cursor one row to the top. 1251: 1252: AdjustCursorRowBeforeMovingLeft: 1253: ldx #EDITOR_MAX_COMBINED_ROWS ; maximum number of rows that can be combined in one virtual row 1254: lda #$00 ; start counter at column 0 1255: @Loop: 1256: cmp zPNTR ; is current cursor column the same as our counter? 1257: beq @DecrementAndExit ; yes -> branch, decrement row and exit 1258: clc 1259: adc #EDITOR_COLS ; calculate next multiple of EDITOR_COLS to test against 1260: dex ; still a row to handle? 1261: bne @Loop ; yes -> branch, process next row 1262: rts 1263: 1264: @DecrementAndExit: 1265: dec zTBLX ; decrement current cursor row 1266: rts 1267: 1268: 1269: ; If the cursor will be part of the next row after being moved to the right 1270: ; (that is, the cursor is at the end of the current row now), move 1271: ; the cursor one row to the bottom. 1272: 1273: AdjustCursorRowBeforeMovingRight: 1274: ldx #EDITOR_MAX_COMBINED_ROWS ; maximum number of rows that can be combined in one virtual row 1275: lda #EDITOR_COLS - 1 ; start counter at last column of a physical row 1276: @Loop: 1277: cmp zPNTR ; is current cursor column the same as our counter? 1278: beq @IncrementAndExit ; yes -> branch, increment row and exit 1279: clc 1280: adc #EDITOR_COLS ; calculate next column to test against 1281: dex ; still a row to handle? 1282: bne @Loop ; yes -> branch, process next row 1283: rts 1284: 1285: @IncrementAndExit: 1286: ldx zTBLX ; is current cursor row 1287: cpx #EDITOR_ROWS ; less than the maximum? 1288: beq @Rts ; no, we cannot increment as we are already at the last row -> branch, skip increment 1289: inc zTBLX ; increment cursor row 1290: @Rts: rts 1291: 1292: ; Check if the current PETSCII code is a color code 1293: ; If it is, set lCOLOR accordingly. 1294: ; Input: A := PETSCII code 1295: ; Output: if A is a color code: 1296: ; lCOLOR := X := color code 1297: ; else 1298: ; X := $FF, lCOLOR unchanged 1299: ; Uses: X 1300: ; 1301: EditorCheckColorCodeAndSetColor: 1302: ldx #END_ColorCodes - ColorCodes - 1 ; get number of color codes 1303: @CheckColor: 1304: cmp ColorCodes,x ; is the current char a color code? 1305: beq @ColorFound ; yes -> branch, we found a color 1306: dex ; test the next color 1307: bpl @CheckColor ; until there is not one left 1308: rts 1309: @ColorFound: 1310: stx lCOLOR ; store the color code in lCOLOR 1311: rts 1312: 1313: ColorCodes: 1314: 1315: ; These are the PETSCII values of the color codes 1316: 1317: .byte $90,$05,$1C,$9F,$9C,$1E,$1F,$9E ; colors no. 0-7 1318: 1319: .if CompileComputer >= C64_GENERAL 1320: .byte $81,$95,$96,$97,$98,$99,$9A,$9B ; The C64 has 8 additional colors defined here: colors no. 8-15 1321: 1322: .endif 1323: 1324: END_ColorCodes: 1325: 1326: .if CompileComputer < C64_GENERAL 1327: 1328: ; depending on lMODE, the old VIC20 KERNAL does some translation of 1329: ; character codes to be output. 1330: ; All of these codes being replaced have in common that their 1331: ; 7th bit ($80) is set. 1332: ; 1333: ; TODO Why is this done? 1334: 1335: ; this table is organised as follows: Each entry consists of a byte pair. 1336: ; the byte at offset 1 is the character that is to be replaced, and 1337: ; the byte at offset 0 is the character with which to replace. 1338: 1339: ; This is only used in VIC20_02 ROMs, although the 1340: ; table is also present in later ROMs. 1341: 1342: CHROUT_REPLACEMENT_TABLE: 1343: .byte $EF,$A1 1344: .byte $DF,$A6 1345: .byte $E1,$B1 1346: .byte $E2,$B2 1347: .byte $E3,$B3 1348: .byte $E4,$B4 1349: .byte $E5,$B5 1350: .byte $E6,$B6 1351: .byte $E7,$B7 1352: .byte $E8,$B8 1353: .byte $E9,$B9 1354: .byte $FA,$BA 1355: .byte $FB,$BB 1356: .byte $FC,$BC 1357: .byte $EC,$BD 1358: .byte $FE,$BE 1359: .byte $84,$BF 1360: .byte $F7,$C0 1361: .byte $F8,$DB 1362: .byte $F9,$DD 1363: .byte $EA,$DE 1364: 1365: SpecialScreenCodeHandleTable: 1366: ; special screen code to PETSCII conversion table 1367: ; the first character is the screen code to convert, 1368: ; the second character is the PETSCII code to convert in 1369: ; 1370: ; This is only used in VIC20_02 ROMs, although the 1371: ; table is also present in later ROMs. 1372: 1373: .byte $5E,$E0 1374: .byte $5B,$E1 1375: .byte $5D,$E2 1376: .byte $40,$B0 1377: .byte $61,$B1 1378: .byte $78,$DB 1379: .byte $79,$DD 1380: .byte $66,$B6 1381: .byte $77,$C0 1382: .byte $70,$F0 1383: .byte $71,$F1 1384: .byte $72,$F2 1385: .byte $73,$F3 1386: .byte $74,$F4 1387: .byte $75,$F5 1388: .byte $76,$F6 1389: .byte $7D,$FD 1390: 1391: SpecialScreenCodeHandleTable_END: 1392: 1393: .endif 1394: 1395: LE8EA: lda zSAL 1396: pha 1397: lda zSAL + 1 1398: pha 1399: lda zEAL 1400: pha 1401: lda zEAL + 1 1402: pha 1403: @LE8F6: ldx #$FF 1404: dec zTBLX 1405: dec zLXSP 1406: dec lTLNIDX 1407: 1408: @LE8FF: inx 1409: jsr CalculateScreenPointerFromRowNumber 1410: cpx #EDITOR_ROWS - 1 1411: bcs @LE913 1412: lda SCREEN_LOWBYTE + 1,x 1413: sta zSAL 1414: lda zLDTB1 + 1,x 1415: jsr CopyPhysicalScreenRow 1416: bmi @LE8FF ; => jmp, as CopyPhysicalScreenRow will not return with N=0 ("bpl loop") 1417: ; ----------------- 1418: 1419: @LE913: 1420: jsr EraseScreenRow 1421: ldx #0 1422: @LE918: lda zLDTB1,x 1423: and #$7F 1424: ldy zLDTB1 + 1,x 1425: bpl @LE922 1426: ora #$80 1427: @LE922: sta zLDTB1,x 1428: inx 1429: cpx #EDITOR_ROWS - 1 1430: bne @LE918 1431: lda zLDTB1 + EDITOR_ROWS - 1 1432: ora #$80 1433: sta zLDTB1 + EDITOR_ROWS - 1 1434: lda zLDTB1 1435: bpl @LE8F6 1436: inc zTBLX 1437: inc lTLNIDX 1438: 1439: ; check for a pressed CTRL key: 1440: ; If it is pressed, incorporate an additional delay 1441: 1442: .ifdef JIFFY 1443: 1444: JDLE938: 1445: jsr RestoreKeyboardRowAndRet 1446: 1447: .else 1448: lda #KEYB_ROW_CTRL ; set the keyboard row to the row that has the CTRL key 1449: sta KEYB_ROW 1450: .endif 1451: lda KEYB_COL ; test the keyboard columns 1452: cmp #KEYB_COL_CTRL ; check the CTRL key specifically 1453: 1454: .ifdef JIFFY 1455: bne @SkipDelay 1456: ldx zNDX 1457: beq JDLE938 1458: lda $0276,x 1459: sbc #$13 1460: bne @SkipDelay 1461: sta zNDX 1462: @JDLE94F: cli 1463: cmp zNDX 1464: beq @JDLE94F 1465: sta zNDX 1466: 1467: .else 1468: php ; remember status 1469: lda #KEYB_ROW_STANDARD ; restore the keyboard row 1470: sta KEYB_ROW 1471: plp ; get back the status 1472: bne @SkipDelay ; Z=1 --> CTRL key not pressed --> branch, skip delay 1473: 1474: ; create a delay of TODO clock cycles 1475: ldy #0 1476: @Delay: 1477: nop 1478: dex 1479: bne @Delay 1480: dey 1481: bne @Delay 1482: sty zNDX 1483: 1484: .endif 1485: 1486: @SkipDelay: 1487: ldx zTBLX 1488: 1489: Restore_zEAL_and_zSAL: 1490: pla 1491: sta zEAL + 1 1492: pla 1493: sta zEAL 1494: pla 1495: sta zSAL + 1 1496: pla 1497: sta zSAL 1498: rts 1499: 1500: LE965: 1501: ldx zTBLX 1502: LE967: 1503: ; find next (virtual) row 1504: inx ; proceed to next (physical) row 1505: lda zLDTB1,x ; is it combined with the previous one (bit 7 = 0)? 1506: bpl LE967 ; yes -> branch, loop to test the next row 1507: 1508: stx lTLNIDX ; remember the row number of the next (virtual) row 1509: cpx #EDITOR_ROWS - 1 ; is this the last (phyiscal) row? 1510: beq @LE981 ; yes -> branch 1511: bcc @LE981 ; row number is less than last row -> also branch 1512: 1513: jsr LE8EA 1514: ldx lTLNIDX 1515: dex 1516: dec zTBLX 1517: jmp LogicallyCombineTwoRows 1518: ; -------------------- 1519: 1520: ; Make room on the screen for the extension of a logical screen row to comprise another 1521: ; physical screen row. This involves scrolling every row below lTLNIDX down (to make 1522: ; room), erasing the new row, and adjusting the pointers in zLDTB1. 1523: 1524: @LE981: 1525: ; save zEAL/zEAL+1 and zSAL/zSAL+1 on the stack as they will be used 1526: ; as temporary storage for pointers. 1527: ; These will be restored before leaving. 1528: 1529: lda zSAL 1530: pha 1531: lda zSAL + 1 1532: pha 1533: lda zEAL 1534: pha 1535: lda zEAL + 1 1536: pha 1537: 1538: ; Move screen contents below the current cursor position downwards 1539: 1540: ldx #EDITOR_ROWS ; start at the last physical row 1541: @CopyRow: 1542: dex 1543: jsr CalculateScreenPointerFromRowNumber ; update the destination pointer into video RAM (zPNT/zPNT+1) 1544: cpx lTLNIDX ; have we already reached the current screen row? 1545: bcc @EndMove ; we are above the current screen row -> branch, end the copy (TODO is this needed at all?) 1546: beq @EndMove ; we are at the current screen row -> branch, end the copy 1547: 1548: ; update the source pointers 1549: lda SCREEN_LOWBYTE - 1,x ; get low byte of the starting address of this row 1550: sta zSAL ; remember low byte 1551: lda zLDTB1 - 1,x ; get high byte of the starting address of this row 1552: jsr CopyPhysicalScreenRow ; copy the current screen row from source to destination, moving it down 1553: bmi @CopyRow ; => jmp, as CopyPhysicalScreenRow will not return with N=0 ("bpl loop") 1554: ; --------------------------- 1555: 1556: @EndMove: 1557: jsr EraseScreenRow ; erase the (physical) screen row in X 1558: 1559: ; update zLDTB1 to reflect the new situation 1560: ; copy the high order (7th) bit of the byte for each row that has been moved 1561: ; to the next row. 1562: ; source row is the row that is copied, destination row is the next row 1563: 1564: ldx #EDITOR_ROWS - 2 ; start at 2nd to last row of source row 1565: 1566: @MoveCombinationBits: 1567: cpx lTLNIDX ; have we already reached (<=) the current row? 1568: bcc @EndMoveCombinationBits ; yes, quit 1569: 1570: lda zLDTB1 + 1,x ; get the byte for the next row 1571: and #~$80 ; clear bit 7 in all cases 1572: ldy zLDTB1,x ; read 7th bit of source row 1573: bpl @Positive ; if it is unset (positive), skip 1574: ora #$80 ; set the 7th bit of destination row 1575: @Positive: 1576: sta zLDTB1 + 1,x ; store byte for destination row 1577: dex ; proceed with previous row 1578: bne @MoveCombinationBits 1579: 1580: @EndMoveCombinationBits: 1581: ldx lTLNIDX 1582: jsr LogicallyCombineTwoRows 1583: 1584: ; restore zEAL/zEAL+1 and zSAL/zSAL+1 1585: 1586: .if CompileComputer >= C64_GENERAL 1587: jmp Restore_zEAL_and_zSAL ; same implementation like VIC-20, but we save memory as it is already there 1588: .else 1589: pla 1590: sta zEAL + 1 1591: pla 1592: sta zEAL 1593: pla 1594: sta zSAL + 1 1595: pla 1596: sta zSAL 1597: rts 1598: .endif 1599: 1600: ; Copy one (physical) screen row on screen to another screen row 1601: 1602: ; This will copy a physical screen row in memory, including the video and the color RAM. 1603: ; It is used to scroll the screen up or down, but it is not limited to this usage. 1604: 1605: ; Input: A = high byte of start address of (logical TODO) screen row (cf. zLDTB1) from which to copy 1606: ; zSAL = low byte of start address of (physical) screen row (cf. SCREEN_LOWBYTE) from which to copy 1607: 1608: ; zPNT/zPNT+1 = Start address of physical screen row video RAM destination 1609: ; zUSER/zUSER+1 = Start address of physical screen row color RAM destination 1610: 1611: CopyPhysicalScreenRow: 1612: and #>lVIDEORAM_SIZE ; make sure to let the start address 1613: ora lHIBASE ; point into the current video RAM 1614: sta zSAL + 1 ; store the address as pointer 1615: jsr @UpdateColorRamPointers 1616: 1617: ; Copy one (physical) row 1618: 1619: ldy #EDITOR_COLS - 1 ; index of last character in a (physical) row 1620: @CopyPreviousChar: 1621: lda (zSAL),y ; get character from source 1622: sta (zPNT),y ; and store it at the destination 1623: lda (zEAL),y ; get color from source 1624: sta (zUSER),y ; and store it at the destination 1625: dey ; go to previous character 1626: bpl @CopyPreviousChar ; non-negative -> branch, there is still a character to be processed 1627: rts 1628: ; ----------------------- 1629: 1630: ; Update the color RAM pointers in zUSER/zUSER+1 and zEAL/zEAL+1, respectively, 1631: ; to point to the same locations as the video RAM pointers 1632: ; in zPNT/zPNT+1 and zSAL/zSAL+1, respectively. 1633: 1634: @UpdateColorRamPointers: 1635: jsr UpdateColorRAMPointerToVideoramPointer ; update the color RAM pointer to match the video RAM pointer 1636: 1637: ; adjust video RAM pointer in zSAL/zSAL+1 to point to the color RAM (in zEAL/zEAL+1) 1638: lda zSAL 1639: sta zEAL 1640: lda zSAL + 1 1641: and #>lVIDEORAM_SIZE 1642: ora #>COLORRAM 1643: sta zEAL + 1 1644: rts 1645: 1646: CalculateScreenPointerFromRowNumber: 1647: ; calculate the start of the screen row of which the number 1648: ; is given in X. Store it in zPNT. 1649: 1650: lda SCREEN_LOWBYTE,x ; get low byte of the starting address of this row 1651: sta zPNT ; remember low byte 1652: lda zLDTB1,x ; get high byte of the starting address of this row 1653: and #>lVIDEORAM_SIZE ; mask out additional bits used as flags 1654: ora lHIBASE ; add the video RAM base 1655: sta zPNT + 1 ; remember high byte 1656: rts 1657: 1658: 1659: EraseScreenRow: 1660: 1661: ; this routine erases the screen row no. X 1662: 1663: ldy #EDITOR_COLS - 1 ; start in the last column 1664: jsr CalculateScreenPointerFromRowNumber ; set the video RAM pointer in zPNT to the row we want to process 1665: jsr UpdateColorRAMPointerToVideoramPointer ; update the video RAM pointer in zUSER to correspond to zPNT 1666: 1667: @Loop: 1668: .if CompileComputer >= C64_03 .AND CompileComputer <> C64_4064 1669: jsr Patch_StoreColor ; set the color of the location 1670: .endif 1671: lda #' ' ; store a SPACE (' ') into the video RAM position 1672: sta (zPNT),y 1673: .if CompileComputer = C64_02 .OR CompileComputer = C64_4064 1674: jsr Patch_StoreColor ; set the color of the location 1675: nop 1676: .elseif CompileComputer <= C64_01 1677: lda #COL_WHITE ; set the color of the location to white 1678: sta (zUSER),y 1679: .endif 1680: dey ; proceed to the previous column 1681: bpl @Loop ; still >= 0, branch -> process the next column 1682: rts 1683: ; ---------------------------------- 1684: 1685: .if CompileComputer >= C64_03 .AND CompileComputer <> C64_4064 1686: nop 1687: .endif 1688: 1689: 1690: StoreCharacterOnScreenAndDisableBlinking: 1691: tay ; remember character to output 1692: 1693: lda #$02 ; set blink counter to $02 (TODO WHY?) 1694: sta zBLNCT 1695: 1696: jsr UpdateColorRAMPointerToVideoramPointer ; set pointer to video RAM at cursor position 1697: 1698: tya ; get back character to output 1699: 1700: ; 1701: ; Store character on screen at the current cursor position 1702: ; 1703: ; A = character 1704: ; X = color 1705: ; 1706: StoreCharacterOnScreen: 1707: ldy zPNTR ; get column offset in of current screen position 1708: sta (zPNT),y ; store character in video RAM 1709: txa ; get color 1710: sta (zUSER),y ; store color in color RAM 1711: rts 1712: 1713: UpdateColorRAMPointerToVideoramPointer: 1714: lda zPNT 1715: sta zUSER 1716: lda zPNT + 1 1717: and #>lVIDEORAM_SIZE 1718: ora #>COLORRAM 1719: sta zUSER + 1 1720: rts 1721: 1722: KIRQ: 1723: jsr kUDTIM 1724: lda zBLNSW 1725: bne @LEA61 1726: dec zBLNCT 1727: bne @LEA61 1728: lda #$14 1729: sta zBLNCT 1730: ldy zPNTR 1731: lsr zBLNON 1732: ldx lGDCOL 1733: lda (zPNT),y 1734: bcs @LEA5C 1735: inc zBLNON 1736: sta zGDBLN 1737: jsr UpdateColorRAMPointerToVideoramPointer 1738: lda (zUSER),y 1739: sta lGDCOL 1740: ldx lCOLOR 1741: lda zGDBLN 1742: @LEA5C: eor #$80 1743: jsr StoreCharacterOnScreen 1744: 1745: @LEA61: 1746: 1747: .ifdef JIFFY 1748: 1749: LEA61: jmp LEA7B 1750: LEA64: pla 1751: pha 1752: cmp #$98 1753: beq JDLEA6D 1754: JDLEA6A: jmp LA57C 1755: JDLEA6D: jsr JDLF72C 1756: bne JDLEA6A 1757: ldx zTXTPTR 1758: ldy #$04 1759: tya 1760: jmp JDLA5E3 1761: .byte $01 1762: 1763: .else 1764: lda TAPE_REG_SENSE 1765: and #TAPE_B_SENSE 1766: beq @LEA71 1767: ldy #$00 1768: sty zCAS1 1769: lda TAPE_REG_MOTOR 1770: ora #TAPE_B_MOTOR_ON 1771: bne @LEA79 1772: ; ------------------------- 1773: 1774: @LEA71: lda zCAS1 1775: bne LEA7B 1776: lda TAPE_REG_MOTOR 1777: and #TAPE_B_MOTOR_OFF_AND 1778: @LEA79: 1779: .if CompileComputer < C64_GENERAL 1780: bit VIA1_IEC 1781: bvs LEA7B 1782: .endif 1783: sta TAPE_REG_MOTOR 1784: 1785: .endif 1786: 1787: LEA7B: 1788: .if CompileComputer = C64_4064 1789: jsr LE4C8 1790: .else 1791: jsr iSCNKEY 1792: .endif 1793: 1794: .if CompileComputer >= C64_GENERAL 1795: lda CIA1 + CIA_O_ICR 1796: .else 1797: bit VIA2_T1CL 1798: .endif 1799: pla 1800: tay 1801: pla 1802: tax 1803: pla 1804: rti 1805: 1806: ; B-25. Function Name: SCNKEY 1807: ; 1808: ; Purpose: Scan the keyboard 1809: ; Call address: $FF9F (hex) 65439 (decimal) 1810: ; Communication registers: None 1811: ; Preparatory routines: IOINIT 1812: ; Error returns: None 1813: ; Stack requirements: 5 1814: ; Registers affected: A, X, Y 1815: ; 1816: ; Description: This routine scans the Commodore 64 keyboard and checks 1817: ; for pressed keys. It is the same routine called by the interrupt handler. 1818: ; If a key is down, its ASCII value is placed in the keyboard queue. This 1819: ; routine is called only if the normal IRQ interrupt is bypassed. 1820: ; 1821: ; How to Use: 1822: ; 1823: ; 1) Call this routine. 1824: ; 1825: ; EXAMPLE: 1826: ; 1827: ; GET JSR SCNKEY ;SCAN KEYBOARD 1828: ; JSR GETIN ;GET CHARACTER 1829: ; CMP #0 ;IS IT NULL? 1830: ; BEQ GET ;YES... SCAN AGAIN 1831: ; JSR CHROUT ;PRINT IT 1832: ; 1833: ; 1834: iSCNKEY: 1835: lda #0 ; start with: No shift key (SHIFT, CTRL, CBM) is pressed 1836: sta lSHFLAG 1837: 1838: ldy #KEY_NONE ; start with: No key pressed 1839: sty zSFDX 1840: 1841: ; check if any key is pressed at all 1842: sta KEYB_ROW ; set all rows to 0 1843: ldx KEYB_COL ; get columns 1844: cpx #$FF ; everything set? 1845: beq iSCNKEY_EndScan ; yes, no key is pressed, abort. 1846: ; Note that X = $FF is crucial here, as iSCNKEY_EndScan checked for the keycode (in X). If there were anything else in X, then this would be used as keycode and stored into the keyboard buffer 1847: 1848: .if CompileComputer >= C64_GENERAL 1849: tay ; Place of the key pressed in the KEYTAB (stored in Y) = 0 1850: .else 1851: lda #~$01 ; start at row 0 (2^0) 1852: sta KEYB_ROW 1853: ldy #$00 ; Place of the key pressed in the KEYTAB (stored in Y) = 0 1854: .endif 1855: lda #<KEYTAB_UNSHIFTED ; start with the unshifted keytab 1856: sta zKEYTAB 1857: lda #>KEYTAB_UNSHIFTED 1858: sta zKEYTAB + 1 1859: 1860: .if CompileComputer >= C64_GENERAL 1861: lda #~$01 ; start at row 0 (2^0) 1862: sta KEYB_ROW 1863: .endif 1864: 1865: @CheckAllRows: 1866: ldx #8 ; process every of the 8 keyboard columns 1867: 1868: .if CompileComputer >= C64_GENERAL 1869: pha ; remember the mask we put into KEYB_ROW for later processing 1870: .endif 1871: 1872: @UnbounceColumns: 1873: lda KEYB_COL ; get column 1874: cmp KEYB_COL ; unbounce it 1875: .if CompileComputer >= C64_GENERAL 1876: bne @UnbounceColumns ; if it changed between reading, re-read it 1877: .else 1878: bne @CheckAllRows ; if colum changed between reading, re-read it. The LDX #8 does not do any harm here; however, for the additional PHA on the C64, we would corrupt the stack. Thus, the target of the branch was changed on the C64. 1879: 1880: .endif 1881: 1882: ; the following loop tests each column one after one if the bit was 0 1883: ; if it was, the key on the row/column was pressed. 1884: ; This is not completely right if more than one key was pressed, 1885: ; but this is a hardware limitation we cannot handle. 1886: 1887: @ProcessColumn: 1888: lsr a ; get bit from column into C 1889: bcs @KeyNotPressed ; C set -> jump, key was not pressed 1890: 1891: pha ; remember current column mask 1892: 1893: lda (zKEYTAB),y ; get the key code that corresponds to the current row/column 1894: cmp #5 ; is it >= 5? 1895: bcs @StoreKey ; yes, it is a printable char, branch in order to store it 1896: cmp #KEY_STOP ; is it the Run/Stop key? 1897: beq @StoreKey ; yes, store it 1898: 1899: ; if we reached here, the character code is 1, 2, or 4: One of the keys shift or CBM 1900: ; thus, remember the shift flag 1901: 1902: ora lSHFLAG ; set the corresponding flag 1903: sta lSHFLAG ; 1904: 1905: bpl @DoNotStoreKey ; unconditional jump, as lSHFLAG.7 is never set. 1906: ; ---------------------------- 1907: 1908: @StoreKey: 1909: sty zSFDX ; remember key code 1910: 1911: @DoNotStoreKey: 1912: pla ; get back column mask 1913: 1914: @KeyNotPressed: 1915: iny ; this keytable entry was processed, go to the next one 1916: cpy #$41 ; did we already process all $40 entries? 1917: bcs @EndScanning ; yes, we are done (for now) 1918: 1919: dex ; decrement the column counter 1920: bne @ProcessColumn ; and repeat scanning, if the counter did not reach 0. 1921: 1922: ; The following code rotates the mask at KEYB_ROW to the left. 1923: ; This moves the "0" bit from right to left. 1924: ; Thus, every row is processed, one after the other. 1925: ; The implementation was changed between VIC20 and C64, though: 1926: ; While the VIC20 uses a ROL on the KEYB_ROW address directly, 1927: ; the C64 performs the ROL in a register and puts the value into 1928: ; KEYB_ROW afterwards. 1929: ; This change most likely occurred since ROL is a read-modify-write 1930: ; instruction. Thus, it will write to the location two times, in two 1931: ; consecutives cycles: First, it will write the old value, and after- 1932: ; wards, it will write the new one. This might generate some "spike" 1933: ; which could inadvertedly affect the reading. 1934: 1935: sec ; make sure to ROL in a "1" bit 1936: 1937: .if CompileComputer >= C64_GENERAL 1938: pla ; get back the mask we put at KEYB_ROW last time 1939: rol a ; rotate it to the left 1940: sta KEYB_ROW ; and set the new mask 1941: .else 1942: rol KEYB_ROW ; rotate to mask to the left 1943: .endif 1944: bne @CheckAllRows 1945: 1946: @EndScanning: 1947: 1948: .if CompileComputer >= C64_GENERAL 1949: pla ; we do not need the mask we put at KEYB_ROW last time anymore, remove it 1950: .endif 1951: 1952: ; Essentially, we are done with scanning here. However, we have to determine 1953: ; if a shift key (SHIFT, C=, CTRL) was pressed, which changes the meaning of 1954: ; some keys. Thus, process the shift keys now. 1955: jmp (lKEYLOG) ; points to CHECK_SHIFT_CTRL_CBM 1956: 1957: ConvertRawKeycodeToInterpretedKeycode: 1958: ldy zSFDX ; get the character code 1959: lda (zKEYTAB),y ; and read in the right ASCII value of it according to the right KEYTAB 1960: tax 1961: 1962: cpy zLSTX 1963: beq @CheckRepeat 1964: ldy #$10 1965: sty lDELAY 1966: bne StoreKeyCodeIntoKeyBuffer 1967: 1968: @CheckRepeat: 1969: and #$7F ; ignore bit 7 of key (TODO why?) 1970: 1971: ; determine if the key press is to be repeated 1972: 1973: bit lRPTFLG ; check repeat flag 1974: bmi RepeatKey ; bit 7 set, repeat all keys --> branch 1975: bvs RestoreKeyboardRowAndRet ; bit 6 set, do not repeat any key --> branch 1976: 1977: cmp #$7F ; Is this the key ... (TODO Which key is this?) 1978: 1979: iSCNKEY_EndScan: 1980: beq StoreKeyCodeIntoKeyBuffer ; Yes, branch -> Store the key into the keyboard buffer 1981: ; TODO Why this extra handling? 1982: 1983: cmp #ASC_INSDEL ; did the user press INS/DEL? 1984: beq RepeatKey ; yes, branch -> process repetition 1985: 1986: cmp #' ' ; did the user press SPACE (" "), or shifted SPACE ($A0)? 1987: beq RepeatKey ; yes, process the repetition 1988: 1989: cmp #ASC_CURSORLEFTRIGHT ; did the user press CRSR LEFT/CRSR RIGHT key? 1990: beq RepeatKey ; yes, branch -> process the repetition 1991: 1992: cmp #ASC_CURSORUPDOWN ; did the user press CRSR LEFT/CRSR RIGHT key? 1993: bne RestoreKeyboardRowAndRet ; no, branch -> do not store the key at all 1994: 1995: RepeatKey: 1996: 1997: ; wait for the initial delay counter lDELAY 1998: 1999: ; For key repetitions, there are two delay: One is the initial delay, that is, 2000: ; how long must a key be pressed before the repetition takes place. 2001: ; This is counted by lDELAY. 2002: 2003: ; The other delay is the counter between repeated keys, if the key is hold 2004: ; long enough. This is counted by lKOUNT. 2005: 2006: ldy lDELAY ; is there an initial delay? 2007: beq @NoInitialDelay ; no, repeat immediately 2008: 2009: dec lDELAY ; yes, decrement the initial delay counter 2010: bne RestoreKeyboardRowAndRet ; still not delayed enough -> branch, do nothing 2011: 2012: @NoInitialDelay: 2013: dec lKOUNT ; decrement the delay counter 2014: bne RestoreKeyboardRowAndRet ; not yet 0, do nothing 2015: 2016: ldy #$04 ; restore the delay counter 2017: sty lKOUNT 2018: 2019: ; test if the keyboard buffer is empty. 2020: ; if it is not empty, no key repetition will take place. 2021: 2022: ; this way, we prevent a full keyboard buffer with repeated keys, 2023: ; which would not be a good user experience (we repeat keys faster 2024: ; than the program can handle them) 2025: 2026: ldy zNDX ; number of keys in keyboard buffer 2027: dey ; - 1 2028: bpl RestoreKeyboardRowAndRet ; still > 0? Then, the buffer is not empty -> branch, do nothing 2029: 2030: StoreKeyCodeIntoKeyBuffer: 2031: 2032: ; Store key code in X into keybuffer 2033: 2034: ; remember key code for the next call of the keyboard routines. 2035: ; this is used for determining if a key was pressed for a longer time 2036: ; and if it has to be repeated, or not. 2037: ldy zSFDX 2038: sty zLSTX 2039: 2040: ; remember shift states for the next call of the keyboard routines. 2041: ; this way, we prevent that SHIFT-CBM is processed more than once, as 2042: ;it is only processed if the shift state changed. 2043: ldy lSHFLAG 2044: sty lLSTSHF 2045: 2046: cpx #$FF ; is the key an invalid one ($FF in the keyboard tables?) 2047: beq RestoreKeyboardRowAndRet ; yes, branch -> do not store it 2048: txa 2049: 2050: ; here, we store the keycode that is in A into the keyboard buffer 2051: ; Note that this routine will generate a race in case it is called w/o 2052: ; interrupts disabled 2053: 2054: ldx zNDX ; get the index into the keyboard buffer 2055: cpx lXMAX ; is the buffer full? 2056: bcs RestoreKeyboardRowAndRet ; yes, branch -> do not store the key 2057: sta lKEYD,x ; store the keycode into the buffer 2058: inx ; increment the number of keys in the buffer 2059: stx zNDX ; and store it 2060: 2061: RestoreKeyboardRowAndRet: 2062: lda #KEYB_ROW_STANDARD ; restore the keyboard row 2063: sta KEYB_ROW 2064: rts 2065: 2066: 2067: CHECK_SHIFT_CTRL_CBM: 2068: 2069: ; Determine if a shift key (SHIFT, C=, CTRL) was pressed, which changes 2070: ; the meaning of some keys. 2071: 2072: lda lSHFLAG ; get the shift state 2073: cmp #lSHFLAG_SHIFT | lSHFLAG_CBM ; shift and commodore pressed? 2074: bne @SwitchToShiftedKeyTable ; no, branch -> process a shifted key table instead 2075: 2076: cmp lLSTSHF ; yes, check if the state changed from the last scan 2077: beq RestoreKeyboardRowAndRet ; it's the same state, branch -> do nothing 2078: 2079: ; If we reach here, SHIFT and C= were pressed simultaneously. 2080: ; Thus, the user wants to switch between Uppercase+Graphics mode, 2081: ; and Lowercase + Uppercase mode. 2082: 2083: lda lMODE ; are we allowed to switch modes? 2084: bmi @ConvertRawKeycodeToInterpretedKeycode ; no, branch -> skip 2085: 2086: .if CompileComputer >= C64_GENERAL 2087: 2088: ; we change mode by changing the base address of the character ROM in the VIC-II 2089: 2090: lda VIC + VICII_O_MemControl 2091: eor #$02 2092: sta VIC + VICII_O_MemControl 2093: .elseif CompileComputer >= VIC20_06 2094: .repeat 19 2095: nop 2096: .endrep 2097: 2098: ; we change mode by changing the base address of the character ROM in the VIC-II 2099: 2100: lda VIC + VICI_O_MemoryLocations 2101: eor #$02 2102: sta VIC + VICI_O_MemoryLocations 2103: 2104: .repeat 4 2105: nop 2106: .endrep 2107: .else 2108: ; this is just a complicated way to EOR VICI_O_MemoryLocations with $02 2109: ; furthermore, it keeps track if the state in lMODE.4 ($10) 2110: 2111: and #$18 ; determine current mode 2112: beq @SwitchToLowercase ; it is uppercase, branch -> switch to lowercase 2113: 2114: ; if we reach here, we are in lowercase mode and want to switch to uppercase mode 2115: 2116: ; remember uppercase mode 2117: lda #$00 2118: sta lMODE 2119: 2120: ; switch VIC to uppercase mode 2121: lda VIC + VICI_O_MemoryLocations 2122: and #~$02 2123: sta VIC + VICI_O_MemoryLocations 2124: 2125: bne @ConvertRawKeycodeToInterpretedKeycode ; unconditional branch 2126: ; -------------- 2127: 2128: @SwitchToLowercase: 2129: ; switch VIC to lowercase mode 2130: lda VIC + VICI_O_MemoryLocations 2131: ora #$02 2132: sta VIC + VICI_O_MemoryLocations 2133: 2134: ; remember lowercase mode 2135: lda #$08 2136: sta lMODE 2137: .endif 2138: 2139: .if CompileComputer = VIC20_02 2140: bne @ConvertRawKeycodeToInterpretedKeycode ; unconditional jump 2141: .else 2142: jmp @ConvertRawKeycodeToInterpretedKeycode 2143: .endif 2144: ; --------------------------- 2145: 2146: @SwitchToShiftedKeyTable: 2147: 2148: ; (here, we enter with A := lSHFLAG) 2149: 2150: ; Calculate the offset of the key table for the shift flags 2151: ; this is done by doubling the value of lSHFLAG, and special 2152: ; handling of lSHFLAG_CTRL which would double to 8, but 6 is 2153: ; the right offset 2154: 2155: asl a ; double shift flag 2156: cmp #2 * lSHFLAG_CTRL ; is it CTRL? 2157: bcc @UseOffset ; no, use the offset 2158: lda #$06 ; yes, correct the offset 2159: 2160: .if CompileComputer >= C64_GENERAL 2161: .elseif CompileComputer >= VIC20_06 2162: nop 2163: nop 2164: .else 2165: bne @VIC20_02_HandleOffsetDirectly ; for VIC-20-02, use this offset. (unconditional branch) 2166: ; ------------------------------------ 2167: .endif 2168: 2169: @UseOffset: 2170: 2171: .if CompileComputer >= C64_GENERAL 2172: 2173: .elseif CompileComputer >= VIC20_06 2174: .repeat 32 2175: nop 2176: .endrep 2177: .else 2178: 2179: ldx lMODE ; if lMODE = 0, use the offset 2180: beq @VIC20_02_HandleOffsetDirectly 2181: 2182: ldx lSHFLAG ; if C= key is not the only shift key pressed: 2183: cpx #lSHFLAG_CBM 2184: bne @VIC20_02_HandleOffsetDirectly ; branch -> handle the offset 2185: 2186: ; if we reach here, the C= key is pressed (but not SHIFT or CTRL) 2187: 2188: cpx lLSTSHF ; did the shift state change from the last time? 2189: beq @ConvertRawKeycodeToInterpretedKeycode ; no, just convert the key code. 2190: 2191: ; TODO 2192: ; switch uppercase mode with lowercase mode (why?) 2193: ; switch bit 4 (???) (why?) 2194: ; but do not update the VIC itself (why?) 2195: 2196: lda lMODE 2197: eor #$18 2198: sta lMODE 2199: 2200: bpl @ConvertRawKeycodeToInterpretedKeycode ; branches if lMODE.7 is 0: switching between uppercase-mode and lowercase-mode is allowed. (TODO why?) 2201: 2202: @VIC20_02_HandleOffsetDirectly: 2203: ora lMODE ; get the offset into KEYTABS_VEC 2204: and #$7F 2205: .endif 2206: 2207: tax ; X := offset into KEYTABS_VEC 2208: 2209: ; switch to the right KEYTAB according to the shift states 2210: 2211: lda @KEYTABS_VEC,x 2212: sta zKEYTAB 2213: lda @KEYTABS_VEC + 1,x 2214: sta zKEYTAB + 1 2215: 2216: @ConvertRawKeycodeToInterpretedKeycode: 2217: jmp ConvertRawKeycodeToInterpretedKeycode 2218: 2219: @KEYTABS_VEC: 2220: .addr KEYTAB_UNSHIFTED ; $00 2221: .addr KEYTAB_SHIFT ; $02 (lSHFLAG=$01, SHIFT) 2222: .addr KEYTAB_CBM ; $04 (lSHFLAG=$02, C=) 2223: .addr KEYTAB_CTRL ; $06 (lSHFLAG=$04, CTRL) 2224: 2225: .if CompileComputer < C64_GENERAL 2226: 2227: ; these keytabs are only used in the VIC20-02 ROM, but they 2228: ; are still present in the later ones. 2229: 2230: ; these 4 tables are used if we are in lowercase mode 2231: .addr KEYTAB_UNSHIFTED ; $08 2232: .addr KEYTAB_SHIFT ; $0A 2233: .addr KEYTAB6 ; $0C 2234: .addr KEYTAB_CTRL ; $0E 2235: 2236: .addr KEYTAB5 ; $10 2237: .addr KEYTAB6 ; $12 2238: .addr KEYTAB6 ; $14 2239: .addr KEYTAB_CTRL ; $16 2240: 2241: .endif 2242: 2243: KEYTAB_UNSHIFTED: 2244: 2245: .if CompileComputer >= C64_GENERAL 2246: 2247: .byte $14,$0D,$1D,$88,$85,$86,$87,$11 2248: .byte $33,$57,$41,$34,$5A,$53,$45,$01 2249: .byte $35,$52,$44,$36,$43,$46,$54,$58 2250: .byte $37,$59,$47,$38,$42,$48,$55,$56 2251: 2252: .byte $39,$49,$4A,$30,$4D,$4B,$4F,$4E 2253: .byte $2B,$50,$4C,$2D,$2E,$3A,$40,$2C 2254: .byte $5C,$2A,$3B,$13,$01,$3D,$5E,$2F 2255: .byte $31,$5F,$04,$32,$20,$02,$51,$03 2256: .byte $FF 2257: 2258: .else 2259: 2260: .byte $31,$33,$35,$37,$39,$2B,$5C,$14 2261: .byte $5F,$57,$52,$59,$49,$50,$2A,$0D 2262: .byte $04,$41,$44,$47,$4A,$4C,$3B,$1D 2263: .byte $03,$01,$58,$56,$4E,$2C,$2F,$11 2264: 2265: .byte $20,$5A,$43,$42,$4D,$2E,$01,$85 2266: .byte $02,$53,$46,$48,$4B,$3A,$3D,$86 2267: .byte $51,$45,$54,$55,$4F,$40,$5E,$87 2268: .byte $32,$34,$36,$38,$30,$2D,$13,$88 2269: 2270: .byte $FF 2271: 2272: .endif 2273: 2274: KEYTAB_SHIFT: 2275: 2276: .if CompileComputer >= C64_GENERAL 2277: 2278: .if .defined(C64JAPAN) 2279: .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 2280: .byte $23,$A8,$AA,$24,$AD,$AB,$A9,$01 2281: .byte $25,$A5,$AC,$26,$AF,$A4,$FF,$AE 2282: .byte $27,$FF,$FF,$28,$FF,$FF,$FF,$FF 2283: 2284: .byte $29,$FF,$FF,$30,$FF,$FF,$FF,$FF 2285: .byte $A1,$FF,$FF,$A2,$3E,$5B,$FF,$3C 2286: .byte $A3,$FF,$5D,$93,$01,$3D,$B0,$3F 2287: .byte $21,$5F,$04,$22,$A0,$02,$A7,$83 2288: .byte $FF 2289: .else 2290: .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 2291: .byte $23,$D7,$C1,$24,$DA,$D3,$C5,$01 2292: .byte $25,$D2,$C4,$26,$C3,$C6,$D4,$D8 2293: .byte $27,$D9,$C7,$28,$C2,$C8,$D5,$D6 2294: 2295: .byte $29,$C9,$CA,$30,$CD,$CB,$CF,$CE 2296: .byte $DB,$D0,$CC,$DD,$3E,$5B,$BA,$3C 2297: .byte $A9,$C0,$5D,$93,$01,$3D,$DE,$3F 2298: .byte $21,$5F,$04,$22,$A0,$02,$D1,$83 2299: .byte $FF 2300: .endif 2301: 2302: 2303: .else 2304: 2305: .byte $21,$23,$25,$27,$29 2306: .if CompileComputer >= VIC20_06 2307: .byte $DB,$A9 2308: .else 2309: .byte $AB,$DC 2310: .endif 2311: .byte $94 2312: 2313: .if CompileComputer >= VIC20_06 2314: .byte $5F 2315: .else 2316: .byte $DF 2317: .endif 2318: .byte $D7,$D2,$D9,$C9,$D0 2319: .if CompileComputer >= VIC20_06 2320: .byte $C0 2321: .else 2322: .byte $AA 2323: .endif 2324: .byte $8D 2325: 2326: .byte $04,$C1,$C4,$C7,$CA,$CC,$5D,$9D 2327: .byte $83,$01,$D8,$D6,$CE,$3C,$3F,$91 2328: 2329: .byte $A0,$DA,$C3,$C2,$CD,$3E,$01,$89 2330: .byte $02,$D3,$C6,$C8,$CB,$5B 2331: .if CompileComputer >= VIC20_06 2332: .byte $3D 2333: .else 2334: .byte $BD 2335: .endif 2336: .byte $8A 2337: 2338: .byte $D1,$C5,$D4,$D5,$CF 2339: .if CompileComputer >= VIC20_06 2340: .byte $BA 2341: .else 2342: .byte $C0 2343: .endif 2344: .byte $DE,$8B 2345: 2346: .byte $22,$24,$26,$28 2347: .if CompileComputer >= VIC20_06 2348: .byte $30,$DD 2349: .else 2350: .byte $B0,$AD 2351: .endif 2352: .byte $93,$8C 2353: 2354: .byte $FF 2355: 2356: .endif 2357: 2358: KEYTAB_CBM: 2359: 2360: .if CompileComputer >= C64_GENERAL 2361: 2362: .if .defined(C64JAPAN) 2363: .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 2364: .byte $B1,$C3,$C1,$B3,$C2,$C4,$B2,$01 2365: .byte $B4,$BD,$BC,$B5,$BF,$CA,$B6,$BB 2366: .byte $D4,$DD,$B7,$D5,$BA,$B8,$C5,$CB 2367: 2368: .byte $D6,$C6,$CF,$DC,$D3,$C9,$D7,$D0 2369: .byte $CE,$BE,$D8,$CD,$D9,$DA,$DB,$C8 2370: .byte $A6,$DE,$B9,$93,$01,$D1,$DF,$D2 2371: .byte $C7,$5F,$04,$CC,$A0,$02,$C0,$83 2372: .byte $FF 2373: .else 2374: .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 2375: .byte $96,$B3,$B0,$97,$AD,$AE,$B1,$01 2376: .byte $98,$B2,$AC,$99,$BC,$BB,$A3,$BD 2377: .byte $9A,$B7,$A5,$9B,$BF,$B4,$B8,$BE 2378: 2379: .byte $29,$A2,$B5,$30,$A7,$A1,$B9,$AA 2380: .byte $A6,$AF,$B6,$DC,$3E,$5B,$A4,$3C 2381: .byte $A8,$DF,$5D,$93,$01,$3D,$DE,$3F 2382: .byte $81,$5F,$04,$95,$A0,$02,$AB,$83 2383: .byte $FF 2384: .endif 2385: 2386: .elseif CompileComputer = VIC20_02 2387: .byte $B1,$B3,$B5,$B7,$B9,$AB,$DC,$94 2388: .byte $DF,$D7,$D2,$D9,$C9,$D0,$AA,$8D 2389: .byte $04,$C1,$C4,$C7,$CA,$CC,$BB,$9D 2390: .byte $83,$01,$D8,$D6,$CE,$AC,$AF,$91 2391: 2392: .byte $0A,$DA,$C3,$C2,$CD,$AE,$01,$FF 2393: .byte $02,$D3,$C6,$C8,$CB,$BA,$BD,$FF 2394: .byte $D1,$C5,$D4,$D5,$CF,$C0,$DE,$FF 2395: .byte $B2,$B4,$B6,$B8,$B0,$AD,$93,$FF 2396: .byte $FF 2397: .else 2398: .byte $21,$23,$25,$27,$29,$A6,$A8,$94 2399: .byte $5F,$B3,$B2,$B7,$A2,$AF,$DF,$8D 2400: .byte $04,$B0,$AC,$A5,$B5,$B6,$5D,$9D 2401: .byte $83,$01,$BD,$BE,$AA,$3C,$3F,$91 2402: 2403: .byte $A0,$AD,$BC,$BF,$A7,$3E,$01,$89 2404: .byte $02,$AE,$BB,$B4,$A1,$5B,$3D,$8A 2405: .byte $AB,$B1,$A3,$B8,$B9,$A4,$DE,$8B 2406: .byte $22,$24,$26,$28,$30,$DC,$93,$8C 2407: .byte $FF 2408: .endif 2409: 2410: .if CompileComputer >= VIC20_06 2411: 2412: KEYTAB5: ; unused, but references for VIC20-06 and -07 2413: 2414: EditorCheckForAscLowercase: 2415: cmp #ASC_LOWERCASE ; if this the code to change to lowercase chars? 2416: bne EditorCheckForAscUppercase ; no, test for the next code 2417: 2418: ; set the VIC memory control byte to point to the lowercase characters: 2419: 2420: .if CompileComputer >= C64_GENERAL 2421: lda VIC + VICII_O_MemControl 2422: ora #2 2423: bne EditorSta_vMemControl ; sta VIC + VICII_O_MemControl ; this bne saves one byte 2424: .else 2425: lda #2 2426: ora VIC + VICI_O_MemoryLocations 2427: sta VIC + VICI_O_MemoryLocations 2428: jmp CHROUT_SCREEN_END ; we're done 2429: ; this JMP is not necessary, but does not do any harm, either. 2430: ; It has been removed from the C64 ROMs, presumably to save space. 2431: .endif 2432: 2433: EditorCheckForAscUppercase: 2434: cmp #ASC_UPPERCASE ; if this the code to change to lowercase chars? 2435: bne EditorCheckForDisallowLowercase ; no, test for the next code 2436: 2437: ; set the VIC memory control byte to point to the uppercase characters: 2438: 2439: .if CompileComputer >= C64_GENERAL 2440: lda VIC + VICII_O_MemControl 2441: and #~2 2442: EditorSta_vMemControl: 2443: sta VIC + VICII_O_MemControl 2444: .else 2445: lda #~2 2446: and VIC + VICI_O_MemoryLocations 2447: sta VIC + VICI_O_MemoryLocations 2448: .endif 2449: 2450: EditorChroutScreenEnd: 2451: jmp CHROUT_SCREEN_END 2452: ; ---------------------------- 2453: 2454: EditorCheckForDisallowLowercase: 2455: cmp #ASC_DISALLOW_LOWERCASE ; if this the code to disallow changing to lowercase mode via keyboard? 2456: bne @CheckForAllowLowercase ; no, test for the next code 2457: 2458: ; disallow changing mode with SHIFT + C= by setting bit 7 of lMODE: 2459: 2460: lda #$80 2461: ora lMODE 2462: .if CompileComputer >= C64_GENERAL 2463: bmi @Sta_lMODE ; sta lMODE (uncond. branch) 2464: ; ------------------ 2465: .else 2466: sta lMODE 2467: bmi EditorChroutScreenEnd 2468: .endif 2469: @CheckForAllowLowercase: 2470: cmp #ASC_ALLOW_LOWERCASE ; if this the code to allow changing to lowercase mode via keyboard? 2471: bne EditorChroutScreenEnd ; no -> branch, this is no special code (or it has been already handled) 2472: 2473: ; (re-)allow changing mode with SHIFT + C= by clearing bit 7 of lMODE: 2474: 2475: lda #$7F 2476: and lMODE 2477: @Sta_lMODE: 2478: sta lMODE 2479: 2480: ; end chrout to the screen. 2481: ; the VIC-20 and C64 do exactly the same. 2482: 2483: .if CompileComputer >= C64_GENERAL 2484: jmp CHROUT_SCREEN_END 2485: .else 2486: bpl EditorChroutScreenEnd ; branches to a "JMP CHROUT_SCREEN_END" (uncond. branch) 2487: ; ------------------------------ 2488: 2489: ; a patch: cf. directly before EditorPatchLogicallyCombineTwoRows_Return 2490: 2491: EditorPatchLogicallyCombineTwoRows: 2492: EDITOR_PATCH_LogicallyCombineTwoRows_FIX 2493: EDITOR_PATCH_LogicallyCombineTwoRows_COMMON 2494: jmp EditorPatchLogicallyCombineTwoRows_Return 2495: 2496: .endif 2497: .endif 2498: 2499: .if CompileComputer = VIC20_02 2500: 2501: KEYTAB5: 2502: 2503: .byte $C7,$B1,$B4,$D4,$D6,$CE,$A6,$14 2504: .byte $FF,$C3,$EC,$DD,$C6,$BE,$EA,$0D 2505: .byte $04,$C1,$BC,$B7,$CF,$D8,$B9,$1D 2506: .byte $03,$01,$BB,$CB,$D0,$C8,$D2,$11 2507: .byte $20,$C2,$BF,$BA,$D3,$D9,$01,$85 2508: .byte $02,$C4,$CA,$B8,$C9,$DA,$D1,$86 2509: .byte $C0,$B2,$B6,$C5,$D7,$DB,$A1,$87 2510: .byte $CC,$B3,$B5,$D5,$DC,$CD,$13,$88 2511: .byte $FF 2512: .endif 2513: 2514: KEYTAB6: 2515: 2516: .if CompileComputer = VIC20_02 2517: 2518: .byte $F1,$F3,$F5,$FF,$FF,$EB,$FF,$94 2519: .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$8D 2520: .byte $04,$FF,$FF,$FF,$FF,$FF,$E2,$9D 2521: .byte $83,$01,$FF,$FF,$FF,$FF,$FF,$91 2522: .byte $A0,$FF,$FF,$FF,$FF,$EE,$01,$89 2523: .byte $02,$FF,$FF,$FF,$FF,$E1,$FD,$8A 2524: .byte $FF,$FF,$FF,$FF,$FF,$B0,$E0,$8B 2525: .byte $F2,$F4,$F6,$FF,$F0,$ED,$93,$8C 2526: .byte $FF 2527: 2528: .elseif CompileComputer < C64_GENERAL 2529: 2530: ; unused, but present 2531: 2532: .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 2533: .byte $FF,$04,$FF,$FF,$FF,$FF,$FF,$E2 2534: .byte $9D,$83,$01,$FF,$FF,$FF,$FF,$FF 2535: .byte $91,$A0,$FF,$FF,$FF,$FF,$EE,$01 2536: .byte $89,$02,$FF,$FF,$FF,$FF,$E1,$FD 2537: .byte $8A,$FF,$FF,$FF,$FF,$FF,$B0,$E0 2538: .byte $8B,$F2,$F4,$F6,$FF,$F0,$ED,$93 2539: .byte $8C,$FF 2540: 2541: .endif 2542: 2543: KEYTAB_CTRL: 2544: 2545: .if CompileComputer >= C64_GENERAL 2546: 2547: .if .defined(C64JAPAN) 2548: .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 2549: .byte $1C,$95,$01,$9F,$1A,$13,$96,$FF 2550: .byte $9C,$97,$04,$1E,$03,$06,$98,$18 2551: .byte $1F,$99,$07,$9E,$02,$08,$9A,$16 2552: 2553: .byte $12,$9B,$0A,$92,$0D,$0B,$0F,$0E 2554: .byte $08,$10,$0C,$09,$11,$14,$00,$09 2555: .byte $FF,$05,$15,$FF,$FF,$17,$19,$12 2556: .byte $90,$06,$FF,$05,$FF,$FF,$81,$FF 2557: .byte $FF 2558: .else 2559: .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 2560: .byte $1C,$17,$01,$9F,$1A,$13,$05,$FF 2561: .byte $9C,$12,$04,$1E,$03,$06,$14,$18 2562: .byte $1F,$19,$07,$9E,$02,$08,$15,$16 2563: 2564: .byte $12,$09,$0A,$92,$0D,$0B,$0F,$0E 2565: .byte $FF,$10,$0C,$FF,$FF,$1B,$00,$FF 2566: .byte $1C,$FF,$1D,$FF,$FF,$1F,$1E,$FF 2567: .byte $90,$06,$FF,$05,$FF,$FF,$11,$FF 2568: .byte $FF 2569: .endif 2570: 2571: .else 2572: 2573: .byte $90,$1C,$9C,$1F 2574: .if CompileComputer = VIC20_02 2575: .byte $FF 2576: .else 2577: .byte $12 2578: .endif 2579: .byte $FF,$FF,$FF 2580: .if CompileComputer = VIC20_02 2581: .byte $FF 2582: .else 2583: .byte $06 2584: .endif 2585: .byte $FF,$12,$FF,$FF,$FF,$FF,$FF 2586: .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 2587: .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 2588: .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 2589: .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 2590: .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 2591: .byte $05,$9F,$1E,$9E,$92,$FF,$FF,$FF 2592: .byte $FF 2593: 2594: .endif 2595: 2596: VIC_DEFAULTS: 2597: 2598: ; the default values for the VIC or VIC-II 2599: ; these will be copied in a loop into the 2600: ; VIC or VIC-II register when initialising the VIC(-II) 2601: ; 2602: 2603: .if CompileComputer >= C64_GENERAL 2604: 2605: .byte $00,$00,$00,$00,$00,$00,$00,$00 2606: .byte $00,$00,$00,$00,$00,$00,$00,$00 2607: .byte $00 2608: .if CompileComputer >= C64_02 2609: .byte $1B | (>311 .SHL 7) ,<311 2610: .else 2611: .byte $1B,$00 2612: .endif 2613: .byte $00,$00,$00,$08,$00 2614: .byte $14 2615: .if CompileComputer >= C64_02 2616: .byte $0F 2617: .else 2618: .byte $00 2619: .endif 2620: .byte $00,$00,$00,$00,$00,$00 2621: 2622: .byte SET_COLOR_FRAME,SET_COLOR_BACKGROUND 2623: .if CompileComputer = C64_4064 2624: .byte $00,$00,$00,$00,$00 2625: .byte $00,$00,$00,$00,$00,$00,$00 2626: .else 2627: .byte $01,$02,$03,$04,$00 2628: .byte $01,$02,$03,$04,$05,$06,$07 2629: .endif 2630: 2631: .else 2632: 2633: .if CompileComputer >= VIC20_07 2634: .byte $0C,$26 2635: .else 2636: .byte $05,$19 2637: .endif 2638: .byte $16,$2E,$00,$C0,$00,$00 2639: .byte $00,$00,$00,$00,$00,$00,$00 2640: 2641: .endif 2642: 2643: END_VIC_DEFAULTS: 2644: 2645: .if CompileComputer < C64_GENERAL 2646: 2647: .byte $1B ; TODO unused? 2648: 2649: .endif 2650: 2651: TEXT_LOADRUN: 2652: .byte "LOAD",ASC_CR 2653: .byte "RUN",ASC_CR 2654: END_TEXT_LOADRUN: 2655: 2656: SCREEN_LOWBYTE: 2657: 2658: ; the low bytes of the screen addresses 2659: 2660: .repeat EDITOR_ROWS,i 2661: .byte <(i*EDITOR_COLS) 2662: .endrep 2663: