init.a65

     1:  ; This is the RESET routine that is called when a hardware RESET occurs.
     2:  ; After determining if an expansion cartridge is available - in this case,
     3:  ; this routine aborts and calls the RESET routine of the cartridge -
     4:  ; it has to set up the I/O areas and all memory. Afterwards, it calls
     5:  ; the BASIC through the BASIC cold start vector
     6:  ;
     7:  RESET:
     8:          ldx     #<$01FF
     9:          sei                     ; no interrupts are allowed (we have not set it up yet)
    10:          txs                     ; SP = $FF, so we have maximum stack space
    11:          cld                     ; make sure we are in binary mode, not in decimal mode
    12:          jsr     CheckCartridge  ; check for an expansion cartridge
    13:          bne     @NoCartridge    ; no cartridge -> jump
    14:          jmp     (CART_RESET)    ; we have a cartridge, exit and call the RESET routine of the cart
    15:  
    16:  ; in case we have no cartridge, proceed with initialisation
    17:  
    18:  @NoCartridge:
    19:  .if CompileComputer >= C64_GENERAL
    20:          stx     VIC + VICII_O_ControlReg2       ; switch to 38 cols mode
    21:                                  ; this seems to be cosmetic only. If the C64 already has a visible
    22:                                  ; screen, one can clearly see that the RESET makes the left and
    23:                                  ; right border smaller on a RESET and/or JSR $FCE2 (SYS 64738)
    24:          jsr     iIOINIT         ; initialise the I/O area
    25:  .endif
    26:  
    27:          jsr     iRAMTAS         ; clear memory and determine RAM areas
    28:          jsr     iRESTOR         ; restore the KERNEL jump vectors
    29:  .if CompileComputer < C64_GENERAL
    30:          jsr     iIOINIT         ; initialise the I/O area
    31:  .endif
    32:  
    33:          ; Initialise the video
    34:  .if CompileComputer >= C64_02
    35:          jsr     iCINT_WITH_PAL_NTSC     ; initialise the video. Also make sure to determine PAL or NTSC, and adjust the timings accordingly
    36:  .else
    37:          jsr     iCINT           ; initialise the video.
    38:  .endif
    39:          cli
    40:          jmp     (bRESTART)      ; call BASIC
    41:  
    42:  ; Check if a cartridge is available.
    43:  ; For this, it checks for the "cartridge magic"
    44:  ; If there is a cartridge, this routine returns with Z=1
    45:  ; else with Z=0
    46:  ;
    47:  CheckCartridge:
    48:          ldx     #END_Copy_CARTRIDGE_MAGIC - Copy_CARTRIDGE_MAGIC
    49:  @CheckNext:
    50:          lda     Copy_CARTRIDGE_MAGIC - 1,x
    51:          cmp     CART_MAGIC - 1,x
    52:          bne     @NoCart
    53:          dex
    54:          bne     @CheckNext
    55:  @NoCart:
    56:          rts
    57:  
    58:  ; Copy of the cartridge magic
    59:  ; CheckCartridge checks agains these characters
    60:  ; to find out if a cartridge is available.
    61:  ;
    62:  Copy_CARTRIDGE_MAGIC:
    63:  .if CompileComputer >= C64_GENERAL
    64:          asc80   "CBM"
    65:          .byte   "80"
    66:  .else
    67:          .byte   "A0"
    68:          asc80   "CBM"
    69:  .endif
    70:  END_Copy_CARTRIDGE_MAGIC:
    71:  
    72:  ;
    73:  ;  B-23. Function Name: RESTOR
    74:  ;
    75:  ;    Purpose: Restore default system and interrupt vectors
    76:  ;    Call address: $FF8A (hex) 65418 (decimal)
    77:  ;    Preparatory routines: None
    78:  ;    Error returns: None
    79:  ;    Stack requirements: 2
    80:  ;    Registers affected: A, X, Y
    81:  ;
    82:  ;    Description: This routine restores the default values of all system
    83:  ;  vectors used in KERNAL and BASIC routines and interrupts. (See the Memory
    84:  ;  Map for the default vector contents). The KERNAL VECTOR routine is used
    85:  ;  to read and alter individual system vectors.
    86:  ;
    87:  ;  How to Use:
    88:  ;    1) Call this routine.
    89:  ;
    90:  ;  EXAMPLE:
    91:  ;    JSR RESTOR
    92:  ;
    93:  iRESTOR:
    94:          ldx     #<Copy_of_lCINV
    95:          ldy     #>Copy_of_lCINV
    96:          clc
    97:  
    98:  ;  B-39. Function Name: VECTOR
    99:  ;
   100:  ;    Purpose: Manage RAM vectors
   101:  ;    Call address: $FF8D (hex) 65421 (decimal)
   102:  ;    Communication registers: X, Y
   103:  ;    Preparatory routines: None
   104:  ;    Error returns: None
   105:  ;    Stack requirements: 2
   106:  ;    Registers affected: A, X, Y
   107:  ;
   108:  ;
   109:  ;    Description: This routine manages all system vector jump addresses
   110:  ;  stored in RAM. Calling this routine with the the accumulator carry bit
   111:  ;  set stores the current contents of the RAM vectors in a list pointed to
   112:  ;  by the X and Y registers. When this routine is called with the carry
   113:  ;  clear, the user list pointed to by the X and Y registers is transferred
   114:  ;  to the system RAM vectors. The RAM vectors are listed in the memory map.
   115:  ;
   116:  ;  +-----------------------------------------------------------------------+
   117:  ;  | NOTE: This routine requires caution in its use. The best way to use it|
   118:  ;  | is to first read the entire vector contents into the user area, alter |
   119:  ;  | the desired vectors, and then copy the contents back to the system    |
   120:  ;  | vectors.                                                              |
   121:  ;  +-----------------------------------------------------------------------+
   122:  ;
   123:  ;  How to Use:
   124:  ;
   125:  ;  READ THE SYSTEM RAM VECTORS
   126:  ;
   127:  ;    1) Set the carry.
   128:  ;    2) Set the X and y registers to the address to put the vectors.
   129:  ;    3) Call this routine.
   130:  ;
   131:  ;  LOAD THE SYSTEM RAM VECTORS
   132:  ;
   133:  ;    1) Clear the carry bit.
   134:  ;    2) Set the X and Y registers to the address of the vector list in RAM
   135:  ;       that must be loaded.
   136:  ;    3) Call this routine.
   137:  ;
   138:  ;
   139:  ;  EXAMPLE:
   140:  ;    ;CHANGE THE INPUT ROUTINES TO NEW SYSTEM
   141:  ;    LDX #<USER
   142:  ;    LDY #>USER
   143:  ;    SEC
   144:  ;    JSR VECTOR      ;READ OLD VECTORS
   145:  ;    LDA #<MYINP     ;CHANGE INPUT
   146:  ;    STA USER+10
   147:  ;    LDA #>MYINP
   148:  ;    STA USER+11
   149:  ;    LDX #<USER
   150:  ;    LDY #>USER
   151:  ;    CLC
   152:  ;    JSR VECTOR      ;ALTER SYSTEM
   153:  ;    ...
   154:  ;    USER *=*+26
   155:  
   156:  iVECTOR:
   157:          ; remember the address where to load/store the vector list
   158:          stx     zMEMUSS
   159:          sty     zMEMUSS + 1
   160:  
   161:          ldy     #END_Copy_of_lCINV - Copy_of_lCINV - 1  ; get number of bytes to copy
   162:  @Loop:  lda     lCINV,y
   163:          bcs     @DoSet                  ; if C=0, write the buffer to the address at x/y
   164:          lda     (zMEMUSS),y             ; if C=1, get the data from x/y and write it to the system buffers
   165:  @DoSet: sta     (zMEMUSS),y
   166:          sta     lCINV,y
   167:          dey
   168:          bpl     @Loop
   169:          rts
   170:  
   171:  ; the system vectors as set by default
   172:  
   173:  Copy_of_lCINV:
   174:          .addr   KIRQ            ; lCINV
   175:          .addr   RUNSTOP_RESTORE ; lCNBINV
   176:          .addr   KNMI            ; lNMINV
   177:          .addr   KOPEN           ; lIOPEN
   178:          .addr   KCLOSE          ; lICLOSE
   179:          .addr   KCHKIN          ; lICHKIN
   180:          .addr   KCHKOUT         ; lICHKOUT
   181:          .addr   KCLRCH          ; lICLRCH
   182:          .addr   KBASIN          ; lIBASIN
   183:          .addr   KBSOUT          ; lIBSOUT
   184:          .addr   KSTOP           ; lISTOP
   185:          .addr   KGETIN          ; lIGETIN
   186:          .addr   KCLALL          ; lICLALL
   187:          .addr   RUNSTOP_RESTORE ; lUSRCMD
   188:          .addr   KLOAD           ; lILOAD
   189:          .addr   KSAVE           ; lISAVE
   190:  END_Copy_of_lCINV:
   191:  
   192:  ;  B.20. Function Name: RAMTAS
   193:  ;
   194:  ;    Purpose: Perform RAM test
   195:  ;    Call address: $FF87 (hex) 65415 (decimal)
   196:  ;    Communication registers: A, X, Y
   197:  ;    Preparatory routines: None
   198:  ;    Error returns: None
   199:  ;    Stack requirements: 2
   200:  ;    Registers affected: A, X, Y
   201:  ;
   202:  ;    Description: This routine is used to test RAM and set the top and
   203:  ;  bottom of memory pointers accordingly. It also clears locations $0000 to
   204:  ;  $0101 and $0200 to $03FF. It also allocates the cassette buffer, and sets
   205:  ;  the screen base to $0400. Normally, this routine is called as part of the
   206:  ;  initialization process of a Commodore 64 program cartridge.
   207:  ;
   208:  ;  EXAMPLE:
   209:  ;    JSR RAMTAS
   210:  ;
   211:  iRAMTAS:
   212:          ; clear zero page and $200-$3ff
   213:          lda       #0
   214:  .if CompileComputer >= C64_GENERAL
   215:          tay
   216:  .else
   217:          tax
   218:  .endif
   219:  
   220:  @MemClearLoop:
   221:  
   222:  .if CompileComputer >= C64_GENERAL
   223:          sta     2,y             ; on the C64, start with ZP address 2 so we do not overwrite $00/$01 (6510 on-chip I/O pins!)
   224:          sta     $200,y
   225:          sta     $300,y
   226:          iny
   227:  .else
   228:          sta     0,x
   229:          sta     $200,x
   230:          sta     $300,x
   231:          inx
   232:  .endif
   233:          bne     @MemClearLoop
   234:  
   235:          ; set the cassette (tape) buffer address
   236:          ldx     #<lTBUFFR
   237:          ldy     #>lTBUFFR
   238:          stx     zTAPE1
   239:          sty     zTAPE1 + 1
   240:  
   241:          ; Check memory for writability by writing
   242:          ; a pattern to it ($55, then $AA). If the
   243:          ; addresses contain exactly these values afterwards,
   244:          ; we have working RAM.
   245:  
   246:  .if CompileComputer >= C64_GENERAL
   247:          tay                     ; y = 0
   248:          lda     #(>lVIDEORAM)-1
   249:          sta     zSTAL + 1
   250:  @IncHi: inc     zSTAL + 1
   251:  @Loop:  lda     (zSTAL),y       ; remember original value of the memory location
   252:          tax                     ; in X
   253:  
   254:          lda     #$55            ; write $55 into memory location
   255:          sta     (zSTAL),y
   256:          cmp     (zSTAL),y       ; still $55?
   257:          bne     @NotEqual       ; no, quit loop
   258:  
   259:          rol     a               ; test $AA pattern instead
   260:          sta     (zSTAL),y
   261:          cmp     (zSTAL),y       ; still $AA?
   262:          bne     @NotEqual       ; no, quit loop
   263:  
   264:          ;
   265:          ; the old value is only restored if the memory is determined as RAM.
   266:          ; otherwise, either $55 or $AA remains at the last location.
   267:          ; this is in contrast to the VIC 20 implementation, which leaves all
   268:          ; bytes unchanged.
   269:          ; Ironically, for the VIC20, there is no difference if this byte is
   270:          ; restored or not. For the C64, however, there is a difference, as
   271:          ; the RAM under the ROM at $A000 is overwritten with $55 after this
   272:          ; function has been called if the BASIC ROM is switched on.
   273:          ;
   274:          txa                     ; restore old value
   275:          sta     (zSTAL),y
   276:  
   277:  .if CompileComputer = C64_GS
   278:          nop
   279:          bne     @IncHi
   280:  .else
   281:          iny                     ; proceed to next memory location
   282:          bne     @Loop           ; and do it again
   283:  .endif
   284:          beq     @IncHi          ; try next page
   285:          ; ------------------------------
   286:  
   287:  @NotEqual:
   288:          tya                     ; low byte of failed addres
   289:          tax                     ; into X
   290:          ldy     zSTAL + 1       ; high byte of failed address into y
   291:          clc                     ; (unneccessary, as we call iMEMTOP_Set, not iMEMTOP in the next line)
   292:          jsr     iMEMTOP_Set     ; set memory top to x/y
   293:  
   294:          lda     #>lBASICRAM     ; set BASIC start to $0800
   295:          sta     lMEMSTR + 1     ; (low byte is already 0, as we just cleared the ZP)
   296:  
   297:          lda     #>lVIDEORAM     ; set video RAM start to $0400
   298:          sta     lHIBASE
   299:          rts
   300:  
   301:  .else
   302:  
   303:          sta     zSTAL           ; zSTAL low = 0 (unneccessary, as we already cleared ZP to 0)
   304:          sta     zTEMPX          ; (unneccessary, as we already cleared ZP to 0)
   305:          sta     lMEMSTR         ; BASIC start low = 0 (unneccessary, as we already cleared ZP to 0)
   306:          tay                     ; Y = 0
   307:  
   308:          lda     #>$0400         ; start memory test at the location $0400.
   309:                                  ; This is the first address where memory can be available on the VIC20,
   310:                                  ; if a 3 KB RAM expansion is present.
   311:          sta     zSTAL + 1
   312:  
   313:  @MemTestLoop:
   314:          ; increment address to be tested.
   315:          ; Note that the VIC20 will actually start the test at $0401 with this, thus, $0400 will not be tested at all.
   316:  
   317:          inc     zSTAL           ; increment low byte of address to be tested
   318:          bne     @SkipHighByte
   319:          inc     zSTAL + 1       ; increment high byte, if necessary
   320:  
   321:  @SkipHighByte:
   322:          jsr     CheckWritability        ; check if byte is writeable RAM (C=1) or not (C=0)
   323:  
   324:          lda     zTEMPX          ; until we found (first) RAM, handle
   325:          beq     @FindMemStart   ; the test separately at @FindMemStart
   326:  
   327:          ; if we reach here, we have already found the start of RAM somewhere between $0400-$10FF.
   328:          ; Thus, we continue the loop until we found a non-RAM location
   329:  
   330:          bcs     @MemTestLoop    ; if we still have RAM, test the next location
   331:  
   332:          ; here, we found the end of RAM
   333:  
   334:          ldy     zSTAL + 1       ; get end of RAM pointer into x/y
   335:          ldx     zSTAL
   336:          cpy     #>$2000         ; end of RAM below $2000?
   337:          bcc     @Panic          ; then panic, we have a severe problem, as we did not even find the RAM every VIC20 has!
   338:  
   339:          cpy     #>$2100         ; end of RAM >= $2100?
   340:          bcs     @MemConf2       ; yet, set "configuration type 2", expanded with more than 3 KB RAM
   341:  
   342:          ; we have an unexpanded VIC20 (or expanded with not more than 3KB)
   343:          ldy     #>$1E00         ; put screen memory at $1E00 (- $1FFF)
   344:          sty     lHIBASE
   345:                                  ; put memory top at $1E00
   346:  
   347:  @SetMemTop:
   348:          jmp     iMEMTOP_Set
   349:  
   350:  @MemConf2:
   351:          lda     #>$1200         ; set user basic start to $1200
   352:          sta     lMEMSTR + 1
   353:          lda     #>$1000         ; set screen memory to $1000
   354:          sta     lHIBASE
   355:          bne     @SetMemTop      ; set memory top to what was determined (in x/y)
   356:          ; ------------------
   357:  
   358:  @FindMemStart:
   359:          ; if we reach here, we are not sure if there is memory at $0400-$0FFF (3 KB expansion)
   360:          ; thus, we proceed when we have NOT yet found writeable RAM.
   361:  
   362:          bcc     @MemTestLoop    ; no RAM --> jump
   363:  
   364:          ; here, we have found the start of RAM
   365:          lda     zSTAL + 1       ; remember the start of RAM
   366:          sta     lMEMSTR + 1     ; at (lMEMSTR)
   367:          sta     zTEMPX          ; remember we already found start of RAM.
   368:                                  ; with this, we will not jump to @FindMemStart anymore
   369:          cmp     #>$1100
   370:          bcc     @MemTestLoop    ; if start of RAM is below $1100, continue
   371:  
   372:          ; otherwise, we have a severe error, as RAM *must* start at $1000 in every VIC20.
   373:          ; Thus, stop booting with a:
   374:  
   375:          ; endless loop: stop boot
   376:  @Panic:
   377:          jsr     SET_VIC_DEFAULTS
   378:          jmp     @Panic
   379:  .endif
   380:  
   381:  
   382:  ; TODO
   383:  
   384:  TapeIrqVectors:
   385:  
   386:  .if CompileComputer = C64_GS
   387:          .addr   NMI_End
   388:          .addr   NMI_End
   389:          .addr   NMI_End
   390:          .addr   NMI_End
   391:  .else
   392:  
   393:  VecTapeIrqWritePreamble:
   394:          .addr   TapeIrqWritePreamble
   395:  VecTapeIrqWrite:
   396:          .addr   TapeIrqWrite
   397:  VecKIRQ:
   398:          .addr   KIRQ
   399:  VecTapeIrqRead:
   400:          .addr   TapeIrqRead
   401:  
   402:  .endif
   403:  
   404:  ;  B-13. Function Name: IOINIT
   405:  ;
   406:  ;    Purpose: Initialize I/O devices
   407:  ;    Call Address: $FF84 (hex) 65412 (decimal)
   408:  ;    Communication registers: None
   409:  ;    Preparatory routines: None
   410:  ;    Error returns:
   411:  ;    Stack requirements: None
   412:  ;    Registers affected: A, X, Y
   413:  ;
   414:  ;    Description: This routine initializes all input/output devices and
   415:  ;  routines. It is normally called as part of the initialization procedure
   416:  ;  of a Commodore 64 program cartridge.
   417:  ;
   418:  ;  EXAMPLE:
   419:  ;    JSR IOINIT
   420:  ;
   421:  
   422:  iIOINIT:
   423:  .if CompileComputer >= C64_GENERAL
   424:  
   425:          ; clear all bits in the interrupt control register.
   426:          ; Thus, no CIA will generate any interrupts until
   427:          ; reprogrammed
   428:          lda     #~CIA_ICR_BW_SET
   429:          sta     CIA1 + CIA_O_ICR
   430:          sta     CIA2 + CIA_O_ICR
   431:  
   432:          ; (A = $7F)
   433:          sta     CIA1 + CIA_O_PA
   434:  
   435:          ; stop all timers (TA, TB) on CIA1 and CIA2
   436:          lda     #CIA_CRA_B_ONESHOT              ; is the same as CIA_CRB_B_ONESHOT!
   437:          sta     CIA1 + CIA_O_CRA
   438:          sta     CIA2 + CIA_O_CRA
   439:  
   440:          sta     CIA1 + CIA_O_CRB
   441:          sta     CIA2 + CIA_O_CRB
   442:  
   443:          ; Port B (PB) of CIA1 and CIA2 are inputs
   444:          ldx     #$00
   445:          stx     CIA1 + CIA_O_DDRB       ; keyboard column
   446:          stx     CIA2 + CIA_O_DDRB
   447:  
   448:          stx     SID + SID_O_FiltMode
   449:  
   450:          ; Port A (PA) of CIA1 is output
   451:          dex                     ; X = $FF
   452:          stx     CIA1 + CIA_O_DDRA       ; keyboard row
   453:  
   454:          ; VIC reaches bank 0 ($0000-$1FFF), RS232 TXD is active. IEC lines are all inactive.
   455:          lda     #CIA2_PA_B_VA14 | CIA2_PA_B_VA15 | CIA2_PA_B_RS232_TXD
   456:          sta     CIA2 + CIA_O_PA         ; IEC_REG_DATA_CLK_OUT
   457:  
   458:          lda     #CIA2_PA_B_VA14 | CIA2_PA_B_VA15 | CIA2_PA_B_RS232_TXD | CIA2_PA_B_IEC_ATN_OUT | CIA2_PA_B_IEC_CLK_OUT | CIA2_PA_B_IEC_DATA_OUT ; not: CIA2_PA_B_IEC_CLK_IN and CIA2_PA_B_IEC_DATA_IN
   459:          sta     CIA2 + CIA_O_DDRA       ; IEC_DDR
   460:  
   461:          lda     #P6510_B_LORAM | P6510_B_HIRAM | P6510_B_CHAREN | P6510_B_CASS_MOTOR | P6510_B_UNUSED
   462:          sta     zR6510
   463:          lda     #P6510_B_LORAM | P6510_B_HIRAM | P6510_B_CHAREN | P6510_B_CASS_WRITE | P6510_B_CASS_MOTOR
   464:  
   465:          sta     zD6510
   466:  
   467:  iIOINIT_TIMER:
   468:    .if CompileComputer >= C64_02
   469:          lda     lTVSFLG
   470:          beq     LFDEC
   471:          lda     #<DEFAULT_INIT_VALUE_CIA1_TA_PAL
   472:    .else
   473:          lda     #<DEFAULT_INIT_VALUE_CIA1_TA_1MHZ
   474:    .endif
   475:          sta     CIA1 + CIA_O_TALO
   476:  
   477:    .if CompileComputer >= C64_02
   478:          lda     #>DEFAULT_INIT_VALUE_CIA1_TA_PAL
   479:          jmp     LFDF3
   480:  LFDEC:  lda     #<DEFAULT_INIT_VALUE_CIA1_TA_NTSC
   481:          sta     CIA1 + CIA_O_TALO
   482:          lda     #>DEFAULT_INIT_VALUE_CIA1_TA_NTSC
   483:  LFDF3:  sta     CIA1 + CIA_O_TAHI
   484:    .else
   485:          lda     #>DEFAULT_INIT_VALUE_CIA1_TA_1MHZ
   486:          sta     CIA1 + CIA_O_TAHI
   487:    .endif
   488:  
   489:    .macro IOINIT_PATCH
   490:          lda     #CIA_ICR_BW_SET |CIA_ICR_B_TA
   491:          sta     CIA1 + CIA_O_ICR
   492:          lda     CIA1 + CIA_O_CRA
   493:          and     #CIA_CRA_B_50HZ                                 ; clear everything but 50/60 Hz flag
   494:          ora     #CIA_CRA_B_FORCE_LOAD | CIA_CRA_B_START         ; start timer in continuous mode
   495:          sta     CIA1 + CIA_O_CRA
   496:          jmp     IecClkSet
   497:    .endmacro
   498:  
   499:    .if CompileComputer >= C64_02
   500:          jmp     Patch_IOINIT
   501:    .else
   502:          IOINIT_PATCH
   503:    .endif
   504:  
   505:  .else
   506:          ; this is a VIC20
   507:  
   508:          lda     #$7F
   509:          sta     VIA1_IEC
   510:          sta     VIA2_IEC
   511:          lda     #$40
   512:          sta     VIA2_ACR
   513:          lda     #$40
   514:          sta     VIA1_ACR
   515:          lda     #$FE
   516:          sta     VIA1_PCR
   517:          lda     #$DE
   518:          sta     VIA2_PCR
   519:          ldx     #$00
   520:          stx     VIA1_DDRB
   521:          ldx     #$FF
   522:          stx     VIA2_DDRB
   523:          ldx     #$00
   524:          stx     VIA2_DDRA
   525:          ldx     #$80
   526:          stx     VIA1_DDRA
   527:          ldx     #$00
   528:          stx     VIA1_PA_NO_HS
   529:          jsr     IecClkClear
   530:          lda     #$82
   531:          sta     VIA1_IEC
   532:          jsr     IecClkSet
   533:  
   534:  ;LFE39:
   535:  iIOINIT_TIMER:
   536:          lda     #$C0
   537:          sta     VIA2_IEC
   538:          lda     #<DEFAULT_VIA2_T1
   539:          sta     VIA2_T1CL
   540:          lda     #>DEFAULT_VIA2_T1
   541:          sta     VIA2_T1CH
   542:          rts
   543:  
   544:  .endif
   545:  
   546:  
   547:  ;  B-30. Function Name: SETNAM
   548:  ;
   549:  ;    Purpose: Set file name
   550:  ;    Call address: $FFBD (hex) 65469 (decimal)
   551:  ;    Communication registers: A, X, Y
   552:  ;    Preparatory routines:
   553:  ;    Stack requirements: 2
   554:  ;    Registers affected:
   555:  ;
   556:  ;    Description: This routine is used to set up the file name for the OPEN,
   557:  ;  SAVE, or LOAD routines. The accumulator must be loaded with the length of
   558:  ;  the file name. The X and Y registers must be loaded with the address of
   559:  ;  the file name, in standard 6502 low-byte/high-byte format. The address
   560:  ;  can be any valid memory address in the system where a string of
   561:  ;  characters for the file name is stored. If no file name is desired, the
   562:  ;  accumulator must be set to 0, representing a zero file length. The X and
   563:  ;  Y registers can be set to any memory address in that case.
   564:  ;
   565:  ;  How to Use:
   566:  ;
   567:  ;    1) Load the accumulator with the length of the file name.
   568:  ;    2) Load the X index register with the low order address of the file
   569:  ;       name.
   570:  ;    3) Load the Y index register with the high order address.
   571:  ;    4) Call this routine.
   572:  ;
   573:  ;  EXAMPLE:
   574:  ;
   575:  ;    LDA #NAME2-NAME     ;LOAD LENGTH OF FILE NAME
   576:  ;    LDX #<NAME          ;LOAD ADDRESS OF FILE NAME
   577:  ;    LDY #>NAME
   578:  ;    JSR SETNAM
   579:  ;
   580:  iSETNAM:
   581:          sta     zFNLEN          ; store name of file name
   582:          stx     zFNADR          ; and pointer to it
   583:          sty     zFNADR + 1
   584:          rts
   585:  
   586:  ;  B-28. Function Name: SETLFS
   587:  ;
   588:  ;    Purpose: Set up a logical file
   589:  ;    Call address: $FFBA (hex) 65466 (decimal)
   590:  ;    Communication registers: A, X, Y
   591:  ;    Preparatory routines: None
   592:  ;    Error returns: None
   593:  ;    Stack requirements: 2
   594:  ;    Registers affected: None
   595:  ;
   596:  ;
   597:  ;    Description: This routine sets the logical file number, device address,
   598:  ;  and secondary address (command number) for other KERNAL routines.
   599:  ;    The logical file number is used by the system as a key to the file
   600:  ;  table created by the OPEN file routine. Device addresses can range from 0
   601:  ;  to 31. The following codes are used by the Commodore 64 to stand for the
   602:  ;  CBM devices listed below:
   603:  ;
   604:  ;
   605:  ;                  ADDRESS          DEVICE
   606:  ;
   607:  ;                     0            Keyboard
   608:  ;                     1            Datassette(TM)
   609:  ;                     2            RS-232C device
   610:  ;                     3            CRT display
   611:  ;                     4            Serial bus printer
   612:  ;                     8            CBM serial bus disk drive
   613:  ;
   614:  ;
   615:  ;    Device numbers 4 or greater automatically refer to devices on the
   616:  ;  serial bus.
   617:  ;    A command to the device is sent as a secondary address on the serial
   618:  ;  bus after the device number is sent during the serial attention
   619:  ;  handshaking sequence. If no secondary address is to be sent, the Y index
   620:  ;  register should be set to 255.
   621:  ;
   622:  ;  How to Use:
   623:  ;
   624:  ;    1) Load the accumulator with the logical file number.
   625:  ;    2) Load the X index register with the device number.
   626:  ;    3) Load the Y index register with the command.
   627:  ;
   628:  ;
   629:  ;
   630:  ;
   631:  ;  EXAMPLE:
   632:  ;
   633:  ;    FOR LOGICAL FILE 32, DEVICE #4, AND NO COMMAND:
   634:  ;    LDA #32
   635:  ;    LDX #4
   636:  ;    LDY #255
   637:  ;    JSR SETLFS
   638:  ;
   639:  ;
   640:  iSETLFS:
   641:          sta     zLA     ; store logical file number
   642:          stx     zFA     ; store device number (primary address)
   643:          sty     zSA     ; store secondary address
   644:          rts
   645:  
   646:  ;  B-22. Function Name: READST
   647:  ;
   648:  ;    Purpose: Read status word
   649:  ;    Call address: $FFB7 (hex) 65463 (decimal)
   650:  ;    Communication registers: A
   651:  ;    Preparatory routines: None
   652:  ;    Error returns: None
   653:  ;    Stack requirements: 2
   654:  ;    Registers affected: A
   655:  ;
   656:  ;    Description: This routine returns the current status of the I/O devices
   657:  ;  in the accumulator. The routine is usually called after new communication
   658:  ;  to an I/O device. The routine gives you information about device status,
   659:  ;  or errors that have occurred during the I/O operation.
   660:  ;    The bits returned in the accumulator contain the following information:
   661:  ;  (see table below)
   662:  ;
   663:  ;  +---------+------------+---------------+------------+-------------------+
   664:  ;  |  ST Bit | ST Numeric |    Cassette   |   Serial   |    Tape Verify    |
   665:  ;  | Position|    Value   |      Read     |  Bus R/W   |      + Load       |
   666:  ;  +---------+------------+---------------+------------+-------------------+
   667:  ;  |    0    |      1     |               |  time out  |                   |
   668:  ;  |         |            |               |  write     |                   |
   669:  ;  +---------+------------+---------------+------------+-------------------+
   670:  ;  |    1    |      2     |               |  time out  |                   |
   671:  ;  |         |            |               |    read    |                   |
   672:  ;  +---------+------------+---------------+------------+-------------------+
   673:  ;  |    2    |      4     |  short block  |            |    short block    |
   674:  ;  +---------+------------+---------------+------------+-------------------+
   675:  ;  |    3    |      8     |   long block  |            |    long block     |
   676:  ;  +---------+------------+---------------+------------+-------------------+
   677:  ;  |    4    |     16     | unrecoverable |            |   any mismatch    |
   678:  ;  |         |            |   read error  |            |                   |
   679:  ;  +---------+------------+---------------+------------+-------------------+
   680:  ;  |    5    |     32     |    checksum   |            |     checksum      |
   681:  ;  |         |            |     error     |            |       error       |
   682:  ;  +---------+------------+---------------+------------+-------------------+
   683:  ;  |    6    |     64     |  end of file  |  EOI line  |                   |
   684:  ;  +---------+------------+---------------+------------+-------------------+
   685:  ;  |    7    |   -128     |  end of tape  | device not |    end of tape    |
   686:  ;  |         |            |               |   present  |                   |
   687:  ;  +---------+------------+---------------+------------+-------------------+
   688:  ;
   689:  ;
   690:  ;
   691:  ;  How to Use:
   692:  ;
   693:  ;    1) Call this routine.
   694:  ;    2) Decode the information in the A register as it refers to your pro-
   695:  ;       gram.
   696:  ;
   697:  ;  EXAMPLE:
   698:  ;
   699:  ;    ;CHECK FOR END OF FILE DURING READ
   700:  ;    JSR READST
   701:  ;    AND #64                       ;CHECK EOF BIT (EOF=END OF FILE)
   702:  ;    BNE EOF                       ;BRANCH ON EOF
   703:  ;
   704:  iREADST:
   705:          lda     zFA                     ; get device address
   706:          cmp     #FILE_RS232             ; is it a RS232 device?
   707:          bne     iREADST_Normal          ; no, return regular status
   708:  
   709:          ; here, we have a RS232 device.
   710:          ; return the special status of the RS232 device
   711:          ; (not documented in the KERNAL description above!)
   712:  
   713:          lda     lRSSTAT                 ; get RS232 status
   714:  .if CompileComputer >= C64_GENERAL
   715:          pha                             ; make sure to remember RS232 status
   716:  
   717:          ; Leaving this out for the VIC 20 is obviously a severe bug, which
   718:          ; makes iREADST for RS232 completely useless on it
   719:  
   720:  .endif
   721:          lda     #$00                    ; clear RS232 status
   722:          sta     lRSSTAT
   723:  .if CompileComputer >= C64_GENERAL
   724:          pla                             ; get the RS232 status back
   725:  
   726:          ; Leaving this out for the VIC 20 is obviously a severe bug, which
   727:          ; makes iREADST for RS232 completely useless on it
   728:  
   729:  .endif
   730:          rts
   731:  
   732:  ;  B-29. Function Name: SETMSG
   733:  ;
   734:  ;    Purpose: Control system message output
   735:  ;    Call address: $FF90 (hex) 65424 (decimal)
   736:  ;    Communication registers: A
   737:  ;    Preparatory routines: None
   738:  ;    Error returns: None
   739:  ;    Stack requirements: 2
   740:  ;    Registers affected: A
   741:  ;
   742:  ;    Description: This routine controls the printing of error and control
   743:  ;  messages by the KERNAL. Either print error messages or print control mes-
   744:  ;  sages can be selected by setting the accumulator when the routine is
   745:  ;  called. FILE NOT FOUND is an example of an error message. PRESS PLAY ON
   746:  ;  CASSETTE is an example of a control message.
   747:  ;    Bits 6 and 7 of this value determine where the message will come from.
   748:  ;  If bit 7 is 1, one of the error messages from the KERNAL is printed. If
   749:  ;  bit 6 is set, control messages are printed.
   750:  ;
   751:  ;  How to Use:
   752:  ;
   753:  ;    1) Set accumulator to desired value.
   754:  ;    2) Call this routine.
   755:  ;
   756:  ;  EXAMPLE:
   757:  ;
   758:  ;    LDA #$40
   759:  ;    JSR SETMSG          ;TURN ON CONTROL MESSAGES
   760:  ;    LDA #$80
   761:  ;    JSR SETMSG          ;TURN ON ERROR MESSAGES
   762:  ;    LDA #0
   763:  ;    JSR SETMSG          ;TURN OFF ALL KERNAL MESSAGES
   764:  ;
   765:  iSETMSG:
   766:          sta     zNSGFLG
   767:  
   768:          ; in fact, these three commands belong to iREADST!
   769:          ; read the status (LFE1A) or set one or more status bits (LFE1C)
   770:  iREADST_Normal:
   771:          lda     zSTATUS
   772:  SetStatus:
   773:          ora     zSTATUS
   774:          sta     zSTATUS
   775:          rts
   776:  
   777:  ;  B-32. Function  Name: SETTMO
   778:  ;
   779:  ;    Purpose: Set IEEE bus card timeout flag
   780:  ;    Call address: $FFA2 (hex) 65442 (decimal)
   781:  ;    Communication registers: A
   782:  ;    Preparatory routines: None
   783:  ;    Error returns: None
   784:  ;    Stack requirements: 2
   785:  ;    Registers affected: None
   786:  ;  +-----------------------------------------------------------------------+
   787:  ;  | NOTE: This routine is used ONLY with an IEEE add-on card!             |
   788:  ;  +-----------------------------------------------------------------------+
   789:  ;    Description: This routine sets the timeout flag for the IEEE bus. When
   790:  ;  the timeout flag is set, the Commodore 64 will wait for a device on the
   791:  ;  IEEE port for 64 milliseconds. If the device does not respond to the
   792:  ;  Commodore 64's Data Address Valid (DAV) signal within that time the
   793:  ;  Commodore 64 will recognize an error condition and leave the handshake
   794:  ;  sequence. When this routine is called when the accumulator contains a 0
   795:  ;  in bit 7, timeouts are enabled. A 1 in bit 7 will disable the timeouts.
   796:  ;
   797:  ;  +-----------------------------------------------------------------------+
   798:  ;  | NOTE: The Commodore 64 uses the timeout feature to communicate that a |
   799:  ;  | disk file is not found on an attempt to OPEN a file only with an IEEE |
   800:  ;  | card.                                                                 |
   801:  ;  +-----------------------------------------------------------------------+
   802:  ;
   803:  ;  How to Use:
   804:  ;
   805:  ;  TO SET THE TIMEOUT FLAG
   806:  ;    1) Set bit 7 of the accumulator to 0.
   807:  ;    2) Call this routine.
   808:  ;
   809:  ;  TO RESET THE TIMEOUT FLAG
   810:  ;    1) Set bit 7 of the accumulator to 1.
   811:  ;    2) Call this routine.
   812:  ;
   813:  ;  EXAMPLE:
   814:  ;
   815:  ;    ;DISABLE TIMEOUT
   816:  ;    LDA #0
   817:  ;    JSR SETTMO
   818:  ;
   819:  iSETTMO:
   820:          sta     lTIMOUT
   821:          rts
   822:  
   823:  
   824:  ;  B-17. Function Name: MEMTOP
   825:  ;
   826:  ;    Purpose: Set the top of RAM
   827:  ;    Call address: $FF99 (hex) 65433 (decimal)
   828:  ;    Communication registers: X, Y
   829:  ;    Preparatory routines: None
   830:  ;    Error returns: None
   831:  ;    Stack requirements: 2
   832:  ;    Registers affected: X, Y
   833:  ;
   834:  ;    Description: This routine is used to set the top of RAM. When this
   835:  ;  routine is called with the carry bit of the accumulator set, the pointer
   836:  ;  to the top of RAM will be loaded into the X and Y registers. When this
   837:  ;  routine is called with the accumulator carry bit clear, the contents of
   838:  ;  the X and Y registers are loaded in the top of memory pointer, changing
   839:  ;  the top of memory.
   840:  ;
   841:  ;  EXAMPLE:
   842:  ;    ;DEALLOCATE THE RS-232 BUFFER
   843:  ;    SEC
   844:  ;    JSR MEMTOP   ;READ TOP OF MEMORY
   845:  ;    DEX
   846:  ;    CLC
   847:  ;    JSR MEMTOP   ;SET NEW TOP OF MEMORY
   848:  ;
   849:  iMEMTOP:
   850:          bcc     iMEMTOP_Set     ; c = 0 --> set MEMTOP
   851:  iMEMTOP_Get:
   852:          ldx     lMEMSIZ         ; get MEMTOP to x/y
   853:          ldy     lMEMSIZ + 1
   854:  iMEMTOP_Set:
   855:          stx     lMEMSIZ         ; set MEMTOP from x/y
   856:          sty     lMEMSIZ + 1
   857:          rts
   858:  
   859:  ;  B-16. Function Name: MEMBOT
   860:  ;
   861:  ;    Purpose: Set bottom of memory
   862:  ;    Call address: $FF9C (hex) 65436 (decimal)
   863:  ;    Communication registers: X, Y
   864:  ;    Preparatory routines: None
   865:  ;    Error returns: None
   866:  ;    Stack requirements: None
   867:  ;    Registers affected: X, Y
   868:  ;
   869:  ;    Description: This routine is used to set the bottom of the memory. If
   870:  ;  the accumulator carry bit is set when this routine is called, a pointer
   871:  ;  to the lowest byte of RAM is returned in the X and Y registers. On the
   872:  ;  unexpanded Commodore 64 the initial value of this pointer is $0800
   873:  ;  (2048 in decimal). If the accumulator carry bit is clear (-O) when this
   874:  ;  routine is called, the values of the X and Y registers are transferred to
   875:  ;  the low and high bytes, respectively, of the pointer to the beginning of
   876:  ;  RAM.
   877:  ;
   878:  ;
   879:  ;
   880:  ;  How to Use:
   881:  ;  TO READ THE BOTTOM OF RAM
   882:  ;    1) Set the carry.
   883:  ;    2) Call this routine.
   884:  ;
   885:  ;  TO SET THE BOTTOM OF MEMORY
   886:  ;    1) Clear the carry.
   887:  ;    2) Call this routine.
   888:  ;
   889:  ;  EXAMPLE:
   890:  ;
   891:  ;    ;MOVE BOTTOM OF MEMORY UP 1 PAGE
   892:  ;    SEC         ;READ MEMORY BOTTOM
   893:  ;    JSR MEMBOT
   894:  ;    INY
   895:  ;    CLC         ;SET MEMORY BOTTOM TO NEW VALUE
   896:  ;    JSR MEMBOT
   897:  ;
   898:  iMEMBOT:
   899:          bcc     @Set            ; c = 0 --> set MEMBOT
   900:  
   901:          ldx     lMEMSTR         ; get MEMBOT to x/y
   902:          ldy     lMEMSTR + 1
   903:  
   904:  @Set:   stx     lMEMSTR         ; set MEMBOT from x/y
   905:          sty     lMEMSTR + 1
   906:          rts
   907:  
   908:  
   909:  .if CompileComputer < C64_GENERAL
   910:  ;
   911:  ; Test if the memory location pointed to by (zSTAL),y is writable RAM.
   912:  ; For this, we write $55, then $AA into the location. After each write,
   913:  ; we test if the memory is $55 and $AA, respectively.
   914:  ; The memory location is left unchanged (that is, the old value is written
   915:  ; back to it), regardless of the outcome of the test.
   916:  ;
   917:  ; If the area is determined as RAM, return with c=1, else c=0.
   918:  ;
   919:  CheckWritability:
   920:          lda     (zSTAL),y       ; remember original value of the memory location
   921:          tax                     ; in X
   922:  
   923:          lda     #$55            ; write $55 into memory location
   924:          sta     (zSTAL),y
   925:          cmp     (zSTAL),y       ; still $55?
   926:          bne     @NotEqual       ; no, quit loop
   927:  
   928:          ror     a               ; test $AA pattern instead
   929:          sta     (zSTAL),y
   930:          cmp     (zSTAL),y       ; still $AA?
   931:          bne     @NotEqual       ; no, quit loop
   932:  
   933:          .byte   $A9             ; with next byte: "lda #$18". Make sure the CLC is not executed.
   934:  
   935:  @NotEqual:
   936:          clc                     ; return: There was a difference
   937:  
   938:          txa                     ; restore old value
   939:          sta     (zSTAL),y
   940:          rts
   941:  .endif
   942:  
   943:  ; 6502 NMI routine
   944:  ; This routine is called whenever an NMI occurs.
   945:  ;
   946:  NMI:    sei                     ; block IRQ
   947:          jmp     (lNMINV)        ; normally points to KNMI
   948:  
   949:  KNMI:   pha                     ; save A, X and Y onto the stack
   950:          txa
   951:          pha
   952:          tya
   953:          pha
   954:  
   955:  .if CompileComputer >= C64_GENERAL
   956:          ; clear all bits in the interrupt control register to prevent further interrupts
   957:          lda     #~CIA_ICR_BW_SET
   958:          sta     CIA2 + CIA_O_ICR
   959:  
   960:          ; check if CIA2 generated this NMI
   961:          ldy     CIA2 + CIA_O_ICR
   962:          bmi     NMI_FROM_IO             ; CIA2 generated the NMI, process it
   963:  .else
   964:          ; check if VIA1 generated this NMI
   965:          lda     VIA1_IFR
   966:          bpl     LFEFF
   967:          and     VIA1_IEC
   968:          tax
   969:          and     #$02
   970:          beq     NMI_FROM_IO
   971:  .endif
   972:  
   973:          jsr     CheckCartridge  ; is there a cartridge (with magic) installed at $8000 (C64) / $A000 (VIC-20)?
   974:          bne     @NoCartridge    ; no, skip
   975:          jmp     (CART_NMI)      ; yes, let the cartridge process the NMI
   976:  
   977:  @NoCartridge:
   978:  .if CompileComputer >= C64_GENERAL
   979:          jsr     iUDTIM_CheckRunStop
   980:  .else
   981:          bit     VIA1_PA
   982:          jsr     iUDTIM
   983:  .endif
   984:          jsr     kSTOP
   985:          bne     LFEFF
   986:  
   987:  RUNSTOP_RESTORE:
   988:          jsr     iRESTOR
   989:          jsr     iIOINIT
   990:          jsr     iCINT
   991:          jmp     (bRESTART + 2)
   992:  
   993:  NMI_FROM_IO:
   994:  
   995:  .if CompileComputer >= C64_GENERAL
   996:  LFEFF:
   997:          ; TODO combine more?
   998:  
   999:          ; TODO follow logic (currently, there is no description *why* these tests are done!)
  1000:  
  1001:          tya                                     ; A := Y, which has contents of CIA2 + CIA_O_ICR here
  1002:          and     lENABL                          ; only check bits that are set in lENABL
  1003:          tax
  1004:  
  1005:          and     #CIA_ICR_B_TA                   ; check if TA of CIA2 generated the interrupt
  1006:          beq     @NoTimerAUnderflow              ; no -> branch, next test
  1007:  
  1008:          lda     RS232_TXD_REG
  1009:          and     #~CIA2_PA_B_RS232_TXD
  1010:          ora     zNXTBIT
  1011:          sta     RS232_TXD_REG
  1012:  
  1013:          ; clear all interrupt sources of CIA2 that are currently set
  1014:          lda     lENABL                          ; get enabled interrupt sources
  1015:          sta     CIA2 + CIA_O_ICR
  1016:  
  1017:          txa
  1018:          and     #CIA_ICR_B_FLAG | CIA_ICR_B_TB  ; check if timer B or FLAG generated the interrupt
  1019:          beq     @Continue                       ; none -> branch
  1020:  
  1021:          and     #CIA_ICR_B_TB                   ; check if timer B generated the interrupt
  1022:          beq     @IntFromFlag    ; no -> branch
  1023:  
  1024:          jsr     LFED6
  1025:          jmp     @Continue
  1026:  
  1027:  @IntFromFlag:
  1028:          jsr     LFF07
  1029:  
  1030:  @Continue:
  1031:          jsr     LEEBB
  1032:          jmp     @ClearAllCIA2Interrupts
  1033:  
  1034:  @NoTimerAUnderflow:
  1035:          txa
  1036:          and     #CIA_ICR_B_TB                   ; check if TB of CIA2 generated the interrupt
  1037:          beq     @NoTimerBUnderflow              ; no -> branch, next test
  1038:          jsr     LFED6
  1039:          jmp     @ClearAllCIA2Interrupts
  1040:  
  1041:  @NoTimerBUnderflow:
  1042:          txa
  1043:          and     #CIA_ICR_B_FLAG                 ; check if FLAG of CIA2 generated the interrupt
  1044:          beq     @ClearAllCIA2Interrupts         ; no -> branch, next test
  1045:          jsr     LFF07
  1046:  
  1047:  @ClearAllCIA2Interrupts:
  1048:          ; clear all interrupt sources of CIA2 that are currently set
  1049:          lda     lENABL                          ; get enabled interrupt sources
  1050:          sta     CIA2 + CIA_O_ICR
  1051:  
  1052:  .else
  1053:  
  1054:          lda     VIA1_IEC
  1055:          ora     #$80
  1056:          pha
  1057:          lda     #$7F
  1058:          sta     VIA1_IEC
  1059:          txa
  1060:          and     #$40
  1061:          beq     LFF02
  1062:          lda     #$CE
  1063:          ora     zNXTBIT
  1064:          sta     VIA1_PCR
  1065:          lda     VIA1_T1CL
  1066:          pla
  1067:          sta     VIA1_IEC
  1068:          jsr     LEEBB
  1069:  LFEFF:
  1070:          jmp     NMI_End
  1071:          ; -----------------------
  1072:  
  1073:  LFF02:  txa
  1074:          and     #$20
  1075:          beq     @LFF2C
  1076:          lda     VIA1_PB
  1077:          and     #$01
  1078:          sta     zINBIT
  1079:          lda     VIA1_T2CL
  1080:          sbc     #$16
  1081:          adc     lBAUDOF
  1082:          sta     VIA1_T2CL
  1083:          lda     VIA1_T2CH
  1084:          adc     lBAUDOF + 1
  1085:          sta     VIA1_T2CH
  1086:          pla
  1087:          sta     VIA1_IEC
  1088:          jsr     LEF59
  1089:          jmp     NMI_End
  1090:  @LFF2C: txa
  1091:          and     #$10
  1092:          beq     NMI_End
  1093:          lda     lM51CTR
  1094:          and     #$0F
  1095:          bne     @LFF38
  1096:  @LFF38: asl     a
  1097:          tax
  1098:          lda     LFEC2 - 2,x
  1099:          sta     VIA1_T2CL
  1100:          lda     LFEC2 - 1,x
  1101:          sta     VIA1_T2CH
  1102:          lda     VIA1_PB
  1103:          pla
  1104:          ora     #$20
  1105:          and     #$EF
  1106:          sta     VIA1_IEC
  1107:          ldx     lBITNUM
  1108:          stx     zBITC1
  1109:  .endif
  1110:  
  1111:  NMI_End:
  1112:          pla
  1113:          tay
  1114:          pla
  1115:          tax
  1116:          pla
  1117:          rti
  1118:  
  1119:  LFEC2:
  1120:  
  1121:  .if CompileComputer >= C64_GENERAL
  1122:  
  1123:    .if CompileComputer >= C64_02
  1124:          .word   $27C1
  1125:          .word   $1A3E
  1126:          .word   $11C5
  1127:          .word   $0E74
  1128:          .word   $0CED
  1129:          .word   $0645
  1130:          .word   $02F0
  1131:          .word   $0146
  1132:          .word   $00B8
  1133:          .word   $0071
  1134:    .else
  1135:          .word   $26AC
  1136:          .word   $19A7
  1137:          .word   $115D
  1138:          .word   $0E1F
  1139:          .word   $0CA1
  1140:          .word   $061F
  1141:          .word   $02DD
  1142:          .word   $013D
  1143:          .word   $00B2
  1144:          .word   $006C
  1145:  
  1146:    .endif
  1147:  
  1148:  .else
  1149:  
  1150:    .if CompileComputer >= VIC20_07
  1151:  
  1152:          .word   $2AE6
  1153:          .word   $1C78
  1154:          .word   $1349
  1155:          .word   $0FB1
  1156:          .word   $0E0A
  1157:          .word   $06D3
  1158:          .word   $0338
  1159:          .word   $016A
  1160:          .word   $00D0
  1161:          .word   $0083
  1162:          .word   $0036
  1163:  
  1164:    .else
  1165:  
  1166:          .word   $2792
  1167:          .word   $1A40
  1168:          .word   $11C6
  1169:          .word   $0E74
  1170:          .word   $0CEE
  1171:          .word   $0645
  1172:          .word   $02F1
  1173:          .word   $0146
  1174:          .word   $00B8
  1175:          .word   $0071
  1176:          .word   $002A
  1177:  
  1178:    .endif
  1179:  
  1180:  .endif
  1181:  
  1182:  
  1183:  .if CompileComputer >= C64_GENERAL
  1184:  LFED6:  lda     CIA2 + CIA_O_PB
  1185:          and     #$01
  1186:          sta     zINBIT
  1187:          lda     CIA2 + CIA_O_TBLO
  1188:          sbc     #$1C
  1189:          adc     lBAUDOF
  1190:          sta     CIA2 + CIA_O_TBLO
  1191:          lda     CIA2 + CIA_O_TBHI
  1192:          adc     lBAUDOF + 1
  1193:          sta     CIA2 + CIA_O_TBHI
  1194:          lda     #$11
  1195:          sta     CIA2 + CIA_O_CRB
  1196:  
  1197:          ; clear all interrupt sources of CIA2 that are currently set
  1198:          lda     lENABL                          ; get enabled interrupt sources
  1199:          sta     CIA2 + CIA_O_ICR
  1200:  
  1201:          lda     #$FF
  1202:          sta     CIA2 + CIA_O_TBLO
  1203:          sta     CIA2 + CIA_O_TBHI
  1204:          jmp     LEF59
  1205:  LFF07:
  1206:    .if CompileComputer = C64_01
  1207:          lda     lM51CTR
  1208:          and     #$0F
  1209:          bne     LFF1A
  1210:    .endif
  1211:          lda     lM51AJB
  1212:          sta     CIA2 + CIA_O_TBLO
  1213:          lda     lM51AJB + 1
  1214:    .if CompileComputer = C64_01
  1215:          jmp     LFF25
  1216:  LFF1A:  asl     a
  1217:          tax
  1218:          lda     LFEC2 - 2,x
  1219:          sta     CIA2 + CIA_O_TBLO
  1220:          lda     LFEC2 - 1,x
  1221:  LFF25:
  1222:    .endif
  1223:          sta     CIA2 + CIA_O_TBHI
  1224:          lda     #$11
  1225:          sta     CIA2 + CIA_O_CRB
  1226:  
  1227:          lda     #CIA_ICR_B_FLAG | CIA_ICR_B_TB
  1228:          eor     lENABL
  1229:          sta     lENABL
  1230:  
  1231:          lda     #$FF
  1232:          sta     CIA2 + CIA_O_TBLO
  1233:          sta     CIA2 + CIA_O_TBHI
  1234:          ldx     lBITNUM
  1235:          stx     zBITC1
  1236:          rts
  1237:  
  1238:    .if CompileComputer >= C64_02
  1239:  LFF2E:  tax
  1240:          lda     lM51AJB + 1
  1241:          rol     a
  1242:          tay
  1243:          txa
  1244:          adc     #<200
  1245:          sta     lBAUDOF
  1246:          tya
  1247:          adc     #>200
  1248:          sta     lBAUDOF + 1
  1249:          rts
  1250:    .endif
  1251:  
  1252:          .segment "TapeFakeFiller"
  1253:          nop
  1254:          nop
  1255:  
  1256:  ;       FillUntil KERNAL_START + $1F43, $EA
  1257:          .segment "TapeFakeIrq"
  1258:  
  1259:  ; This is a faked IRQ entry point. It is used by the tape routine to execute the IRQ routine,
  1260:  ; returning to a predefined address afterwards.
  1261:  ;
  1262:  ; When this address is called (JMPed to), the return address - 1 is already on the stack.
  1263:  ; This routine has to set a flag register on the stack, making sure that the B bit is unset
  1264:  ; forcing a processing of an IRQ (and not of a BRK instruction)
  1265:  ;
  1266:  FakeIRQ:
  1267:          php                                     ; push flag register onto stack
  1268:  
  1269:          ; now, manipulate the flag register making sure B is unset
  1270:  
  1271:          pla                                     ; get it back into the Accu
  1272:          and     #~A6502_FLAGS_B                 ; make sure B is unset
  1273:          pha                                     ; store the flag register back onto the stack
  1274:  
  1275:  
  1276:  .endif
  1277:  
  1278:  ; 6502 IRQ routine
  1279:  ; This routine is called whenever an IRQ occurs.
  1280:  ;
  1281:  IRQ:    pha                     ; save A, X and Y onto stack
  1282:          txa
  1283:          pha
  1284:          tya
  1285:          pha
  1286:  
  1287:          tsx                     ; SP -> X
  1288:          lda     lSTACK + 4,x    ; Read status register from stack
  1289:          and     #A6502_FLAGS_B  ; check BRK flag
  1290:          beq     @isIRQ          ; BRK flag is 0 --> it was an IRQ
  1291:  
  1292:          jmp     (lCNBINV)       ; BRK flag was 1, process the BRK instruction
  1293:  
  1294:  @isIRQ: jmp     (lCINV)         ; process the IRQ. Normally, this points to KIRQ
  1295:  
  1296:  
  1297:  .if CompileComputer >= C64_GENERAL
  1298:    .if CompileComputer >= C64_02
  1299:  
  1300:  ;  B-7. Function Name: CINT
  1301:  ;
  1302:  ;    Purpose: Initialize screen editor & 6567 video chip
  1303:  ;    Call address: $FF81 (hex) 65409 (decimal)
  1304:  ;    Communication registers: None
  1305:  ;    Preparatory routines: None
  1306:  ;    Error returns: None
  1307:  ;    Stack requirements: 4
  1308:  ;    Registers affected: A, X, Y
  1309:  ;
  1310:  ;
  1311:  ;    Description: This routine sets up the 6567 video controller chip in the
  1312:  ;  Commodore 64 for normal operation. The KERNAL screen editor is also
  1313:  ;  initialized. This routine should be called by a Commodore 64 program
  1314:  ;  cartridge.
  1315:  ;
  1316:  ;  How to Use:
  1317:  ;
  1318:  ;    1) Call this routine.
  1319:  ;
  1320:  ;  EXAMPLE:
  1321:  ;
  1322:  ;    JSR CINT
  1323:  ;    JMP RUN       ;BEGIN EXECUTION
  1324:  ;
  1325:  ; NOTE: iCINT_WITH_PAL_NTSC is an *extended* version.
  1326:  ;       It determines if there is a 6567 (NTSC) or 6569 (PAL) VIC chip.
  1327:  ;       It stores the result in lTVSFLG (TV Standard FLaG), with
  1328:  ;       0 = NTSC, 1 = PAL.
  1329:  ;       Then, it reprograms the CIA timer for PAL or NTSC.
  1330:  ;
  1331:  iCINT_WITH_PAL_NTSC:
  1332:          jsr     iCINT
  1333:  
  1334:  @WaitForRaster:
  1335:          lda     VIC + VICII_O_Raster
  1336:          bne     @WaitForRaster
  1337:          lda     VIC + VICII_O_IRQFlags
  1338:          and     #$01
  1339:          sta     lTVSFLG
  1340:          jmp     iIOINIT_TIMER
  1341:  
  1342:  ; Remainder of iIOINIT. As the code become too large because of the PAL/NTSC
  1343:  ; implementation, this patch is here now.
  1344:  ;
  1345:  Patch_IOINIT:
  1346:          IOINIT_PATCH
  1347:    .endif
  1348:  .endif
  1349:  
  1350:  .if CompileComputer >= C64_GENERAL
  1351:  
  1352:  ;       FillUntil KERNAL_START + $1F80
  1353:  .segment "KernalJumpTable"
  1354:  
  1355:          .byte   VERSION_FF80    ; a version number for the KERNAL
  1356:  
  1357:  ; here, the KERNAL jump table begins
  1358:  ;
  1359:  
  1360:  
  1361:  ; the VIC-20 does not know CINT, IOINIT and RAMTAS, as these were added with the C64:
  1362:  
  1363:  kCINT:
  1364:    .if CompileComputer >= C64_02
  1365:          ; on C64 >= -02 ROM, determine if this is a PAL or an NTSC machine,
  1366:          ; and set the IRQ timings accordingly.
  1367:          ; Afterwards, iCINT is called.
  1368:          jmp     iCINT_WITH_PAL_NTSC
  1369:    .else
  1370:          ; for C64 with -01 ROM, iCINT is called directly.
  1371:          jmp     iCINT
  1372:    .endif
  1373:  
  1374:  kIOINIT:        jmp     iIOINIT
  1375:  kRAMTAS:        jmp     iRAMTAS
  1376:  
  1377:  .else
  1378:  
  1379:  ;       FillUntil $FF8A,FILL_FFXX
  1380:  
  1381:  .endif
  1382:  
  1383:  .segment "KernalJumpTable2"
  1384:  
  1385:  ; here, the KERNAL jump table common to VIC20 and C64 begins
  1386:  
  1387:  kRESTOR:        jmp     iRESTOR
  1388:  kVECTOR:        jmp     iVECTOR
  1389:  kSETMSG:        jmp     iSETMSG
  1390:  kSECOND:        jmp     iSECOND
  1391:  kTKSA:          jmp     iTKSA
  1392:  kMEMTOP:        jmp     iMEMTOP
  1393:  kMEMBOT:        jmp     iMEMBOT
  1394:  kSCNKEY:        jmp     iSCNKEY
  1395:  kSETTMO:        jmp     iSETTMO
  1396:  kACPTR:
  1397:  .ifdef JIFFY
  1398:                  jmp     JDLFBAA
  1399:  .else
  1400:                  jmp     iACPTR
  1401:  .endif
  1402:  kCIOUT:         jmp     iCIOUT
  1403:  kUNTLK:         jmp     iUNTLK
  1404:  kUNLSN:         jmp     iUNLSN
  1405:  kLISTEN:        jmp     iLISTEN
  1406:  kTALK:          jmp     iTALK
  1407:  kREADST:        jmp     iREADST
  1408:  kSETLFS:        jmp     iSETLFS
  1409:  kSETNAM:        jmp     iSETNAM
  1410:  kOPEN:          jmp     (lIOPEN)
  1411:  kCLOSE:         jmp     (lICLOSE)
  1412:  kCHKIN:         jmp     (lICHKIN)
  1413:  kCHKOUT:        jmp     (lICKOUT)
  1414:  kCLRCHN:        jmp     (lICLRCH)
  1415:  kCHRIN:         jmp     (lIBASIN)
  1416:  kCHROUT:        jmp     (lIBSOUT)
  1417:  kLOAD:          jmp     iLOAD
  1418:  kSAVE:          jmp     iSAVE
  1419:  kSETTIM:        jmp     iSETTIM
  1420:  kRDTIM:         jmp     iRDTIM
  1421:  kSTOP:          jmp     (lISTOP)
  1422:  kGETIN:         jmp     (lIGETIN)
  1423:  kCLALL:         jmp     (lICLALL)
  1424:  kUDTIM:         jmp     iUDTIM
  1425:  kSCREEN:        jmp     iSCREEN
  1426:  kPLOT:          jmp     iPLOT
  1427:  kIOBASE:        jmp     iIOBASE
  1428:  
  1429:  .if (CompileComputer >= C64_GENERAL) .AND (.NOT .defined(C64JAPAN))
  1430:          .byte   "RR"            ; Robert Russell
  1431:    .if CompileComputer = C64_4064
  1432:          .byte   0,0
  1433:    .else
  1434:          .byte   "BY"            ; Bob Yannes
  1435:    .endif
  1436:  .endif
  1437:  
  1438:  ;       FillUntil $FFFA,FILL_FFXXa
  1439:  .segment "Int6502"
  1440:  
  1441:          .addr   NMI             ; 6502 NMI vector
  1442:          .addr   RESET           ; 6502 RESET vector
  1443:          .addr   IRQ             ; 6502 IRQ vector
Valid XHTML 1.0 Strict
init.a65.html; generated on Fri Sep 18 21:44:54 2015 by ca65html
uz@cc65.org