.setcpu "6502" .segment "BASIC" .include "zeropage.s" .importzp ERR_SYNTAX, ERR_NOSERIAL .import ERROR, FIX_LINKS, OUTDO .export SerialLoad, SerialSave, SerialMenu SERIAL_MONITOR_C000 := $C100 SERIAL_READY_C000 := $C000 SERIAL_ID_C000 := $C0FC SERIAL_API_READ_C000 := $C1EC SERIAL_API_WRITE_C000 := $C213 SERIAL_MONITOR_C300 := $C400 SERIAL_READY_C300 := $C300 SERIAL_ID_C300 := $C3FC SERIAL_API_READ_C300 := $C4EC SERIAL_API_WRITE_C300 := $C513 SERIAL_MONITOR_C600 := $C700 SERIAL_READY_C600 := $C600 SERIAL_ID_C600 := $C6FC SERIAL_API_READ_C600 := $C7EC SERIAL_API_WRITE_C600 := $C813 ; 0 - $C000, 1 - $C300, 2 - $C600 SERIAL_VARIANT := $40 ; ZP locations get backed up here ZPTemp := $0380 ;End address of dump block END_ADDR_L := $34 END_ADDR_H := $35 ;Begin address of dump block BEG_ADDR_L := $36 BEG_ADDR_H := $37 ;String to int ZP variables STR2INT_BUF := $38 STR2INT_INT := $3E STR2INT_END := $0A ; ---------------------------------------------------------------------------- ; See if Apple-1 Serial Interface card is present and display error if not ; ---------------------------------------------------------------------------- CheckSerial: ldy SERIAL_ID_C000 cpy #'A' bne @1 ldy SERIAL_ID_C000 + 1 cpy #'1' bne @1 ldy SERIAL_ID_C000 + 2 cpy #'S' bne @1 ldy SERIAL_ID_C000 + 3 cpy #'I' bne @1 lda #$00 sta SERIAL_VARIANT rts @1: ldy SERIAL_ID_C300 cpy #'A' bne @2 ldy SERIAL_ID_C300 + 1 cpy #'1' bne @2 ldy SERIAL_ID_C300 + 2 cpy #'S' bne @2 ldy SERIAL_ID_C300 + 3 cpy #'I' bne @2 lda #$01 sta SERIAL_VARIANT rts @2: ldy SERIAL_ID_C600 cpy #'A' bne SerialErr ldy SERIAL_ID_C600 + 1 cpy #'1' bne SerialErr ldy SERIAL_ID_C600 + 2 cpy #'S' bne SerialErr ldy SERIAL_ID_C600 + 3 cpy #'I' bne SerialErr lda #$02 sta SERIAL_VARIANT rts SerialErr: ldx #ERR_NOSERIAL .byte $2C ; Bogus BIT instruction SynErr: ldx #ERR_SYNTAX jmp ERROR ; Jump to Applesoft ERROR routine ; ---------------------------------------------------------------------------- ; Bring up the Apple-1 Serial Interface menu ; ---------------------------------------------------------------------------- SerialMenu: jsr CheckSerial lda SERIAL_VARIANT bne @1 jsr SERIAL_MONITOR_C000 rts @1: jsr SERIAL_MONITOR_C300 rts ; ---------------------------------------------------------------------------- ; Save program via the Apple-1 Serial Interface ; ---------------------------------------------------------------------------- SerialSave: jsr CheckSerial ldy #0 @1: lda END_ADDR_L,y ; Back up 4 affected bytes of the ZP sta ZPTemp,y iny cpy #4 bne @1 lda PRGEND ; Set up end address sta END_ADDR_L lda PRGEND+1 sta END_ADDR_H lda TXTTAB ; Set up start address sta BEG_ADDR_L lda TXTTAB+1 sta BEG_ADDR_H lda SERIAL_VARIANT bne @2 jsr SERIAL_API_WRITE_C000 jmp @4 @2: cmp #$01 bne @3 jsr SERIAL_API_WRITE_C300 jmp @4 @3: jsr SERIAL_API_WRITE_C600 @4: jsr RestoreZPForSave ; Put the zero page back rts ; ---------------------------------------------------------------------------- ; Restores the 4 bytes of the ZP which were saved during SerialSave ; ---------------------------------------------------------------------------- RestoreZPForSave: ldy #0 @1: lda ZPTemp,y ; Load byte from temporary storage sta END_ADDR_L,y ; put it back in its original location iny cpy #4 ; Repeat for next 11 bytes bne @1 rts ; ---------------------------------------------------------------------------- ; Read program from Apple-1 Serial Interface ; ---------------------------------------------------------------------------- SerialLoad: jsr CheckSerial ldy #0 @1: lda END_ADDR_L,y ; Back up first 12 bytes of the ZP sta ZPTemp,y iny cpy #12 bne @1 GetLength: ; Get file name from input line dec TXTPTR ldy #0 @1: jsr CHRGET ; Get next character from the input line beq @2 ; Is it null (EOL)? cmp #$30 bmi LengthValidationErr cmp #$3A bpl LengthValidationErr and #$0F ; Convert ASCII to hex value $00-$09 sta STR2INT_BUF,y ; Not EOL, store it in program length string iny cpy #5 ; 6 chars yet? bne @1 ; no @2: cpy #0 ; Read 6 chars or EOL, did we get anything? bne @3 jmp SynErr @3: lda #STR2INT_END ; append integer string end marker sta STR2INT_BUF,y jsr String2Int lda STR2INT_INT bne @4 dec STR2INT_INT+1 @4: dec STR2INT_INT clc SetLoadAddresses: lda TXTTAB ; Compute program end address adc STR2INT_INT ; (Add file size to program start) sta VARTAB ; Store end address sta END_ADDR_L lda TXTTAB+1 adc STR2INT_INT+1 sta VARTAB+1 sta END_ADDR_H ;jsr SerialAPISetup lda TXTTAB ; Set up start address sta BEG_ADDR_L lda TXTTAB+1 sta BEG_ADDR_H lda SERIAL_VARIANT bne @1 jsr SERIAL_API_READ_C000 jmp @3 @1: cmp #$01 bne @2 jsr SERIAL_API_READ_C300 jmp @3 @2: jsr SERIAL_API_READ_C600 @3: jsr RestoreZPForLoad ; Put the zero page back jmp FIX_LINKS LengthValidationErr: jsr RestoreZPForLoad jmp SynErr ; ---------------------------------------------------------------------------- ; Restores the affected 12 bytes of the ZP which were saved during SerialLoad ; ---------------------------------------------------------------------------- RestoreZPForLoad: ldy #0 @1: lda ZPTemp,y ; Load byte from temporary storage sta END_ADDR_L,y ; put it back in its original location iny cpy #12 ; Repeat for next 11 bytes bne @1 rts ; ---------------------------------------------------------------------------- ; Converts the integer string to 2 byte integer ; ---------------------------------------------------------------------------- String2Int: lda #0 sta STR2INT_INT+1 lda STR2INT_BUF sta STR2INT_INT ldx #1 lda STR2INT_BUF,X cmp #STR2INT_END bne String2IntNext clc rts String2IntNext: jsr String2IntMult10 bcs String2IntEnd inx lda STR2INT_BUF,X cmp #$0A bne String2IntNext clc String2IntEnd: rts String2IntMult10: lda STR2INT_INT+1 pha lda STR2INT_INT asl STR2INT_INT rol STR2INT_INT+1 asl STR2INT_INT rol STR2INT_INT+1 adc STR2INT_INT sta STR2INT_INT pla adc STR2INT_INT+1 sta STR2INT_INT+1 asl STR2INT_INT rol STR2INT_INT+1 lda STR2INT_BUF,X adc STR2INT_INT sta STR2INT_INT lda #0 adc STR2INT_INT+1 sta STR2INT_INT+1 rts