mirror of
https://github.com/flowenol/applesoft-lite.git
synced 2024-12-12 08:29:42 +00:00
Added support for LOAD & SAVE commands via Apple-1 Serial Interface
This commit is contained in:
parent
6a1e34ba6f
commit
a1e942851f
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.bin
|
||||||
|
*.o
|
7
Makefile
7
Makefile
@ -1,7 +1,7 @@
|
|||||||
AFLAGS =
|
AFLAGS =
|
||||||
LFLAGS = -C replica1.cfg
|
LFLAGS = -C apple1cartridge.cfg
|
||||||
BINFILE = applesoft-lite.bin
|
BINFILE = applesoft-lite.bin
|
||||||
OBJS = applesoft-lite.o io.o cffa1.o wozmon.o
|
OBJS = applesoft-lite.o io.o apple1serial.o
|
||||||
|
|
||||||
$(BINFILE): $(OBJS)
|
$(BINFILE): $(OBJS)
|
||||||
ld65 $(LFLAGS) $(OBJS) -o $(BINFILE)
|
ld65 $(LFLAGS) $(OBJS) -o $(BINFILE)
|
||||||
@ -12,7 +12,7 @@ applesoft-lite.o: applesoft-lite.s
|
|||||||
wozmon.o: wozmon.s
|
wozmon.o: wozmon.s
|
||||||
ca65 $(AFLAGS) $<
|
ca65 $(AFLAGS) $<
|
||||||
|
|
||||||
cffa1.o: cffa1.s
|
apple1serial.o: apple1serial.s
|
||||||
ca65 $(AFLAGS) $<
|
ca65 $(AFLAGS) $<
|
||||||
|
|
||||||
io.o: io.s
|
io.o: io.s
|
||||||
@ -20,4 +20,3 @@ io.o: io.s
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm $(OBJS) $(BINFILE)
|
rm $(OBJS) $(BINFILE)
|
||||||
|
|
||||||
|
12
README.md
12
README.md
@ -3,3 +3,15 @@
|
|||||||
This is a stripped-down version of Applesoft BASIC (Microsoft 6502 BASIC) for the Apple-1.
|
This is a stripped-down version of Applesoft BASIC (Microsoft 6502 BASIC) for the Apple-1.
|
||||||
|
|
||||||
See https://cowgod.org/replica1/applesoft/
|
See https://cowgod.org/replica1/applesoft/
|
||||||
|
|
||||||
|
# apple1serial
|
||||||
|
|
||||||
|
This branch has been modified to perform LOAD and SAVE operations via Apple-1 Serial interface
|
||||||
|
https://github.com/flowenol/apple1serial
|
||||||
|
|
||||||
|
# How to use LOAD?
|
||||||
|
|
||||||
|
The LOAD command implemented on this branch takes as an argument the length of the program
|
||||||
|
as a decimal value, e.g.,
|
||||||
|
|
||||||
|
]LOAD 1024
|
||||||
|
7
apple1cartridge.cfg
Normal file
7
apple1cartridge.cfg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
MEMORY {
|
||||||
|
BASROM: start = $6000, size = $2000, fill = yes, file = %O;
|
||||||
|
}
|
||||||
|
|
||||||
|
SEGMENTS {
|
||||||
|
BASIC: load = BASROM, type = ro;
|
||||||
|
}
|
233
apple1serial.s
Normal file
233
apple1serial.s
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
.setcpu "6502"
|
||||||
|
.segment "BASIC"
|
||||||
|
|
||||||
|
.include "zeropage.s"
|
||||||
|
|
||||||
|
.importzp ERR_SYNTAX, ERR_NOSERIAL
|
||||||
|
.import ERROR, FIX_LINKS, OUTDO
|
||||||
|
.export SerialLoad, SerialSave, SerialMenu
|
||||||
|
|
||||||
|
SERIAL_MONITOR := $C100
|
||||||
|
SERIAL_READY := $C000
|
||||||
|
SERIAL_ID := $C0FC
|
||||||
|
SERIAL_API_READ := $C1EC
|
||||||
|
SERIAL_API_WRITE := $C213
|
||||||
|
|
||||||
|
; 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
|
||||||
|
cpy #'A'
|
||||||
|
bne SerialErr
|
||||||
|
ldy SERIAL_ID + 1
|
||||||
|
cpy #'1'
|
||||||
|
bne SerialErr
|
||||||
|
ldy SERIAL_ID + 2
|
||||||
|
cpy #'S'
|
||||||
|
bne SerialErr
|
||||||
|
ldy SERIAL_ID + 3
|
||||||
|
cpy #'I'
|
||||||
|
bne SerialErr
|
||||||
|
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
|
||||||
|
jsr SERIAL_MONITOR
|
||||||
|
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; 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
|
||||||
|
|
||||||
|
jsr SERIAL_API_WRITE
|
||||||
|
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?
|
||||||
|
beq SynErr
|
||||||
|
|
||||||
|
lda #STR2INT_END ; append integer string end marker
|
||||||
|
sta STR2INT_BUF,y
|
||||||
|
jsr String2Int
|
||||||
|
lda STR2INT_INT
|
||||||
|
bne @3
|
||||||
|
dec STR2INT_INT+1
|
||||||
|
@3:
|
||||||
|
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
|
||||||
|
|
||||||
|
jsr SERIAL_API_READ
|
||||||
|
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
|
@ -8,20 +8,20 @@
|
|||||||
; Adapted for the Replica-1 by Tom Greene
|
; Adapted for the Replica-1 by Tom Greene
|
||||||
; 7-May-2008
|
; 7-May-2008
|
||||||
;
|
;
|
||||||
; v0.4
|
; Changed to support LOAD & SAVE via Apple-1 Serial Interface by Piotr Jaczewski
|
||||||
|
; 15-Jan-2021
|
||||||
|
;
|
||||||
|
|
||||||
.setcpu "6502"
|
.setcpu "6502"
|
||||||
.segment "BASIC"
|
.segment "BASIC"
|
||||||
|
|
||||||
.export FIX_LINKS, ERROR, INPUTBUFFER
|
.export FIX_LINKS, ERROR, INPUTBUFFER
|
||||||
.exportzp ERR_SYNTAX, ERR_NOCFFA
|
.exportzp ERR_SYNTAX, ERR_NOSERIAL
|
||||||
|
|
||||||
.import CLS, OUTDO, CRDO, OUTSP, OUTQUES ; Imports from io.s
|
.import CLS, OUTDO, CRDO, OUTSP, OUTQUES ; Imports from io.s
|
||||||
.import KEYBOARD, GETLN, RDKEY
|
.import KEYBOARD, GETLN, RDKEY
|
||||||
|
|
||||||
.import CFFALoad, CFFASave, CFFAMenu ; Imports from cffa1.s
|
.import SerialLoad, SerialSave, SerialMenu ; Imports from apple1serial.s
|
||||||
|
|
||||||
.include "macros.s"
|
.include "macros.s"
|
||||||
.include "zeropage.s"
|
.include "zeropage.s"
|
||||||
@ -95,9 +95,9 @@ TOKEN_ADDRESS_TABLE:
|
|||||||
.addr CLEAR - 1 ; $9B... 154... CLEAR
|
.addr CLEAR - 1 ; $9B... 154... CLEAR
|
||||||
.addr GET - 1 ; $9C... 155... GET
|
.addr GET - 1 ; $9C... 155... GET
|
||||||
.addr NEW - 1 ; $9D... 156... NEW
|
.addr NEW - 1 ; $9D... 156... NEW
|
||||||
.addr CFFAMenu - 1 ; $9E... 157... MENU
|
.addr SerialMenu - 1 ; $9E... 157... MENU
|
||||||
.addr CFFASave - 1 ; $9F... 158... SAVE
|
.addr SerialSave - 1 ; $9F... 158... SAVE
|
||||||
.addr CFFALoad - 1 ; $A0... 160... LOAD
|
.addr SerialLoad - 1 ; $A0... 160... LOAD
|
||||||
.addr CLS - 1 ; $A1... 161... CLS
|
.addr CLS - 1 ; $A1... 161... CLS
|
||||||
; ----------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------
|
||||||
UNFNC: .addr SGN ; $B1... 177... SGN
|
UNFNC: .addr SGN ; $B1... 177... SGN
|
||||||
@ -191,7 +191,7 @@ TOKEN_NAME_TABLE:
|
|||||||
htasc "NEW" ; $9D... 157
|
htasc "NEW" ; $9D... 157
|
||||||
htasc "MENU" ; $9E... 158 New tokens
|
htasc "MENU" ; $9E... 158 New tokens
|
||||||
htasc "SAVE" ; $9F... 159 for
|
htasc "SAVE" ; $9F... 159 for
|
||||||
htasc "LOAD" ; $A0... 160 CFFA I/O
|
htasc "LOAD" ; $A0... 160 Apple-1 Serial I/O
|
||||||
htasc "CLS" ; $A1... 161 New token to clear screen
|
htasc "CLS" ; $A1... 161 New token to clear screen
|
||||||
htasc "TO" ; $A2... 162
|
htasc "TO" ; $A2... 162
|
||||||
htasc "SPC(" ; $A3... 163
|
htasc "SPC(" ; $A3... 163
|
||||||
@ -281,8 +281,8 @@ ERR_FRMCPX := <(*-ERROR_MESSAGES)
|
|||||||
ERR_CANTCONT := <(*-ERROR_MESSAGES)
|
ERR_CANTCONT := <(*-ERROR_MESSAGES)
|
||||||
htasc "CAN'T CONT"
|
htasc "CAN'T CONT"
|
||||||
|
|
||||||
ERR_NOCFFA := <(*-ERROR_MESSAGES) ; New error message for CFFA1 I/O
|
ERR_NOSERIAL := <(*-ERROR_MESSAGES) ; New error message for Apple 1 Serial IO
|
||||||
htasc "NO CFFA"
|
htasc "NO SERIAL"
|
||||||
; ----------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------
|
||||||
QT_ERROR:
|
QT_ERROR:
|
||||||
.byte " ERR"
|
.byte " ERR"
|
||||||
@ -415,7 +415,7 @@ REASON: cpy FRETOP+1 ; HIGH BYTE
|
|||||||
dex
|
dex
|
||||||
bpl @2
|
bpl @2
|
||||||
jsr GARBAG ; MAKE AS MUCH ROOM AS POSSIBLE
|
jsr GARBAG ; MAKE AS MUCH ROOM AS POSSIBLE
|
||||||
ldx #TEMP1-FAC+1 ; RESTORE TEMP1 AND TEMP2
|
ldx #TEMP1-FAC+1+256 ; RESTORE TEMP1 AND TEMP2
|
||||||
@3: pla ; AND (Y,A)
|
@3: pla ; AND (Y,A)
|
||||||
sta FAC,x
|
sta FAC,x
|
||||||
inx
|
inx
|
||||||
@ -638,7 +638,7 @@ INLIN2: stx PROMPT
|
|||||||
; dex
|
; dex
|
||||||
; bne @2
|
; bne @2
|
||||||
;@3: lda #0 ; (Y,X) POINTS AT BUFFER-1
|
;@3: lda #0 ; (Y,X) POINTS AT BUFFER-1
|
||||||
ldx #<INPUTBUFFER-1
|
ldx #<INPUTBUFFER-1+256
|
||||||
ldy #>INPUTBUFFER-1
|
ldy #>INPUTBUFFER-1
|
||||||
rts
|
rts
|
||||||
|
|
||||||
@ -751,7 +751,7 @@ PARSE: inx ; NEXT INPUT CHARACTER
|
|||||||
; ---END OF LINE------------------
|
; ---END OF LINE------------------
|
||||||
@17: sta INPUTBUFFER-3,y ; STORE ANOTHER 00 ON END
|
@17: sta INPUTBUFFER-3,y ; STORE ANOTHER 00 ON END
|
||||||
dec TXTPTR+1 ; SET TXTPTR = INPUTBUFFER-1
|
dec TXTPTR+1 ; SET TXTPTR = INPUTBUFFER-1
|
||||||
lda #<INPUTBUFFER-1
|
lda #<INPUTBUFFER-1+256
|
||||||
sta TXTPTR
|
sta TXTPTR
|
||||||
rts
|
rts
|
||||||
|
|
||||||
@ -941,7 +941,7 @@ LIST4: bpl LIST2 ; BRANCH IF NOT A TOKEN
|
|||||||
sty FAC ; POINT FAC TO TABLE
|
sty FAC ; POINT FAC TO TABLE
|
||||||
ldy #>(TOKEN_NAME_TABLE-$100)
|
ldy #>(TOKEN_NAME_TABLE-$100)
|
||||||
sty FAC+1
|
sty FAC+1
|
||||||
ldy #-1
|
ldy #$FF
|
||||||
@1: dex ; SKIP KEYWORDS UNTIL REACH THIS ONE
|
@1: dex ; SKIP KEYWORDS UNTIL REACH THIS ONE
|
||||||
beq @3
|
beq @3
|
||||||
@2: jsr GETCHR ; BUMP Y, GET CHAR FROM TABLE
|
@2: jsr GETCHR ; BUMP Y, GET CHAR FROM TABLE
|
||||||
@ -2961,7 +2961,7 @@ STR: jsr CHKNUM ; EXPRESSION MUST BE NUMERIC
|
|||||||
jsr FOUT1 ; CONVERT FAC TO STRING
|
jsr FOUT1 ; CONVERT FAC TO STRING
|
||||||
pla ; POP RETURN OFF STACK
|
pla ; POP RETURN OFF STACK
|
||||||
pla
|
pla
|
||||||
lda #<STACK-1 ; POINT TO STACK-1
|
lda #<STACK-1+256 ; POINT TO STACK-1
|
||||||
ldy #>STACK-1 ; (WHICH=0)
|
ldy #>STACK-1 ; (WHICH=0)
|
||||||
beq STRLIT ; ...ALWAYS, CREATE DESC & MOVE STRING
|
beq STRLIT ; ...ALWAYS, CREATE DESC & MOVE STRING
|
||||||
|
|
||||||
@ -4258,7 +4258,7 @@ FDIVT: beq @8 ; FAC = 0, DIVIDE BY ZERO ERROR
|
|||||||
jsr ADD_EXPONENTS
|
jsr ADD_EXPONENTS
|
||||||
inc FAC
|
inc FAC
|
||||||
beq JOV ; OVERFLOW
|
beq JOV ; OVERFLOW
|
||||||
ldx #-4 ; INDEX FOR RESULT
|
ldx #252 ; INDEX FOR RESULT
|
||||||
lda #1 ; SENTINEL
|
lda #1 ; SENTINEL
|
||||||
@1: ldy ARG+1 ; SEE IF FAC CAN BE SUBTRACTED
|
@1: ldy ARG+1 ; SEE IF FAC CAN BE SUBTRACTED
|
||||||
cpy FAC+1
|
cpy FAC+1
|
||||||
@ -4850,7 +4850,7 @@ FOUT1: lda #'-' ; IN CASE VALUE NEGATIVE
|
|||||||
@3: lda #<CON_BILLION ; MULTIPLY BY 1E9
|
@3: lda #<CON_BILLION ; MULTIPLY BY 1E9
|
||||||
ldy #>CON_BILLION ; TO GIVE ADJUSTMENT A HEAD START
|
ldy #>CON_BILLION ; TO GIVE ADJUSTMENT A HEAD START
|
||||||
jsr FMULT
|
jsr FMULT
|
||||||
lda #-9 ; EXPONENT ADJUSTMENT
|
lda #247 ; EXPONENT ADJUSTMENT
|
||||||
@4: sta TMPEXP ; 0 OR -9
|
@4: sta TMPEXP ; 0 OR -9
|
||||||
; ----------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------
|
||||||
; ADJUST UNTIL 1E8 <= (FAC) <1E9
|
; ADJUST UNTIL 1E8 <= (FAC) <1E9
|
||||||
@ -5272,7 +5272,7 @@ GENERIC_CHRGET:
|
|||||||
sec ; TEST FOR NUMERIC RANGE IN WAY THAT
|
sec ; TEST FOR NUMERIC RANGE IN WAY THAT
|
||||||
sbc #'0' ; CLEARS CARRY IF CHAR IS DIGIT
|
sbc #'0' ; CLEARS CARRY IF CHAR IS DIGIT
|
||||||
sec ; AND LEAVES CHAR IN A-REG
|
sec ; AND LEAVES CHAR IN A-REG
|
||||||
sbc #-'0'
|
sbc #-'0'+256
|
||||||
@2: rts
|
@2: rts
|
||||||
|
|
||||||
|
|
||||||
@ -5498,4 +5498,3 @@ RESUME: lda ERRLIN ; RESTORE LINE # AND TXTPTR
|
|||||||
ldx ERRSTK ; RETRIEVE STACK PNTR AS IT WAS
|
ldx ERRSTK ; RETRIEVE STACK PNTR AS IT WAS
|
||||||
txs ; BEFORE STATEMENT SCANNED
|
txs ; BEFORE STATEMENT SCANNED
|
||||||
jmp NEWSTT ; DO STATEMENT AGAIN
|
jmp NEWSTT ; DO STATEMENT AGAIN
|
||||||
|
|
||||||
|
185
cffa1.s
185
cffa1.s
@ -1,185 +0,0 @@
|
|||||||
; CFFA1 I/O routines for Applesoft Lite
|
|
||||||
; by Tom Greene
|
|
||||||
; 8-May-2008
|
|
||||||
|
|
||||||
.setcpu "6502"
|
|
||||||
.segment "BASIC"
|
|
||||||
|
|
||||||
.include "zeropage.s"
|
|
||||||
|
|
||||||
.importzp ERR_SYNTAX, ERR_NOCFFA
|
|
||||||
.import ERROR, FIX_LINKS
|
|
||||||
.export CFFALoad, CFFASave, CFFAMenu
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; CFFA1 firmware addresses
|
|
||||||
|
|
||||||
;CFFA_ID1 := $AFFC ; CFFA1 API documentation says AFFC and AFFD...
|
|
||||||
;CFFA_ID2 := $AFFD
|
|
||||||
CFFA_ID1 := $AFDC ; But the CFFA1 firmware says AFDC and AFDD...
|
|
||||||
CFFA_ID2 := $AFDD
|
|
||||||
CFFA_MENU := $9006 ; Entry point for the CFFA1 menu
|
|
||||||
CFFA_API := $900C ; Entry point for the CFFA1 API
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; CFFA1 API functions
|
|
||||||
|
|
||||||
CFFA1_DisplayError = $04 ; Displays error message for error value in A
|
|
||||||
CFFA1_WriteFile = $20
|
|
||||||
CFFA1_ReadFile = $22
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; CFFA1 API parameters in the ZP
|
|
||||||
|
|
||||||
Destination := $00 ; File load/save address
|
|
||||||
Filename := $02 ; Pointer to file name
|
|
||||||
Filetype := $06 ; ProDOS file type
|
|
||||||
AuxType := $07 ; ProDOS file auxtype
|
|
||||||
FileSize := $09 ; File size
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; Scratch memory used during API calls
|
|
||||||
|
|
||||||
ZPTemp := $0380 ; ZP locations get backed up here
|
|
||||||
CFFAFileName := $03C0 ; File name string
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; ProDOS file type value for write operations
|
|
||||||
; The CFFA1 doesn't really care, so this is just for show.
|
|
||||||
|
|
||||||
SaveType = $F8 ; F8 = "PRG"?
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; See if CFFA1 card is present and display error if not
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
CheckCFFA:
|
|
||||||
ldy CFFA_ID1
|
|
||||||
cpy #$CF
|
|
||||||
bne CFFAErr
|
|
||||||
ldy CFFA_ID2
|
|
||||||
cpy #$FA
|
|
||||||
bne CFFAErr
|
|
||||||
rts
|
|
||||||
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; Bring up the CFFA1 menu
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
CFFAMenu:
|
|
||||||
jsr CheckCFFA
|
|
||||||
jmp CFFA_MENU
|
|
||||||
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; This sets up the zero page locations file name for the read/write calls
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
APISetup:
|
|
||||||
jsr CheckCFFA ; Make sure CFFA card is present first
|
|
||||||
ldy #0
|
|
||||||
@1: lda GOWARM,y ; Back up first 12 bytes of the ZP
|
|
||||||
sta ZPTemp,y ; so they can used during CFFA API call
|
|
||||||
iny
|
|
||||||
cpy #12
|
|
||||||
bne @1
|
|
||||||
GetFileName: ; 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)?
|
|
||||||
sta CFFAFileName+1,y ; Not EOL, store it in filename string
|
|
||||||
iny
|
|
||||||
cpy #15 ; 15 chars yet?
|
|
||||||
bne @1 ; no, go back for more
|
|
||||||
@2: cpy #0 ; Read 15 chars or EOL, did we get anything?
|
|
||||||
beq SynErr ; No, syntax error
|
|
||||||
sty CFFAFileName ; Store file name length
|
|
||||||
lda #<CFFAFileName ; Load address of file name string
|
|
||||||
ldy #>CFFAFileName
|
|
||||||
sta Filename ; and store it for API call
|
|
||||||
sty Filename+1
|
|
||||||
lda PRGEND ; Set up file size
|
|
||||||
sbc TXTTAB ; (PRGEND - TXTTAB)
|
|
||||||
sta FileSize
|
|
||||||
lda PRGEND+1
|
|
||||||
sbc TXTTAB+1
|
|
||||||
sta FileSize+1
|
|
||||||
lda TXTTAB ; Set up start address and auxtype
|
|
||||||
ldy TXTTAB+1 ; (these will be the same)
|
|
||||||
sta Destination
|
|
||||||
sta AuxType
|
|
||||||
sty Destination+1
|
|
||||||
sty AuxType+1
|
|
||||||
lda #SaveType ; Set up ProDOS file type
|
|
||||||
sta Filetype
|
|
||||||
rts
|
|
||||||
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; Display an error message if something went wrong during APISetup
|
|
||||||
; Uses the Applesoft ERROR routine
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
CFFAErr:
|
|
||||||
ldx #ERR_NOCFFA
|
|
||||||
.byte $2C ; Bogus BIT instruction
|
|
||||||
SynErr:
|
|
||||||
ldx #ERR_SYNTAX
|
|
||||||
jmp ERROR ; Jump to Applesoft ERROR routine
|
|
||||||
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; Restores the first 12 bytes of the ZP which were saved during APISetup
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
RestoreZP:
|
|
||||||
ldy #0
|
|
||||||
@1: lda ZPTemp,y ; Load byte from temporary storage
|
|
||||||
sta GOWARM,y ; put it back in its original location
|
|
||||||
iny
|
|
||||||
cpy #12 ; Repeat for next 11 bytes
|
|
||||||
bne @1
|
|
||||||
rts
|
|
||||||
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; Write a file to the CFFA card (SAVE command)
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
CFFASave:
|
|
||||||
jsr APISetup ; Set up zero page locations for API call
|
|
||||||
ldx #CFFA1_WriteFile; Select WriteFile API function
|
|
||||||
jsr DoCFFACall ; Do it
|
|
||||||
@1: jsr RestoreZP ; put ZP back together
|
|
||||||
@2: rts
|
|
||||||
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; Read file from CFFA, then fix up Applesoft zero page to point to the
|
|
||||||
; loaded program (LOAD command)
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
CFFALoad:
|
|
||||||
jsr APISetup
|
|
||||||
ldx #CFFA1_ReadFile ; Select ReadFile API function
|
|
||||||
jsr DoCFFACall ; Do it
|
|
||||||
lda TXTTAB ; Compute program end address
|
|
||||||
adc FileSize ; (Add file size to program start)
|
|
||||||
sta VARTAB ; Store end address
|
|
||||||
lda TXTTAB+1
|
|
||||||
adc FileSize+1
|
|
||||||
sta VARTAB+1
|
|
||||||
jsr RestoreZP ; Put the zero page back
|
|
||||||
jmp FIX_LINKS ; Done loading, fix pointers and restart
|
|
||||||
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
; Call the CFFA1 API and display error message if one occurred
|
|
||||||
; CFFA function number is passed in X
|
|
||||||
; CFFA API returns error status in C, error number in A
|
|
||||||
; ----------------------------------------------------------------------------
|
|
||||||
DoCFFACall:
|
|
||||||
jsr CFFA_API ; Call CFFA API
|
|
||||||
ldx #CFFA1_DisplayError ; Set next command to show error message
|
|
||||||
bcs DoCFFACall ; Call API again if error occurred
|
|
||||||
rts
|
|
||||||
|
|
||||||
|
|
10
replica1.cfg
10
replica1.cfg
@ -1,10 +0,0 @@
|
|||||||
MEMORY {
|
|
||||||
BASROM: start = $E000, size = $1F00, fill = yes, file = %O;
|
|
||||||
MONROM: start = $FF00, size = $100, fill = yes, file = %O;
|
|
||||||
}
|
|
||||||
|
|
||||||
SEGMENTS {
|
|
||||||
BASIC: load = BASROM, type = ro;
|
|
||||||
MONITOR: load = MONROM, type = ro;
|
|
||||||
}
|
|
||||||
|
|
183
wozmon.s
183
wozmon.s
@ -1,183 +0,0 @@
|
|||||||
; Apple I Monitor ROM
|
|
||||||
; Steve Wozniak
|
|
||||||
; 1976
|
|
||||||
; --------------------------------------------------------
|
|
||||||
|
|
||||||
.setcpu "6502"
|
|
||||||
.segment "MONITOR"
|
|
||||||
|
|
||||||
.export ECHO
|
|
||||||
|
|
||||||
; --------------------------------------------------------
|
|
||||||
; Zero page variables
|
|
||||||
XAML := $24
|
|
||||||
XAMH := $25
|
|
||||||
STL := $26
|
|
||||||
STH := $27
|
|
||||||
L := $28
|
|
||||||
H := $29
|
|
||||||
YSAV := $2A
|
|
||||||
MODE := $2B
|
|
||||||
|
|
||||||
; I/O locations
|
|
||||||
IN := $0200 ; Input buffer is $0200 to $027F
|
|
||||||
KBD := $D010 ; Keyboard data
|
|
||||||
DSP := $D012 ; Display data
|
|
||||||
KBDCR := $D011 ; Keyboard control register
|
|
||||||
DSPCR := $D013 ; Display control register
|
|
||||||
|
|
||||||
; ASCII codes
|
|
||||||
CR = $0D | $80 ; Carriage return
|
|
||||||
ESC = $1B | $80 ; Escape
|
|
||||||
SLASH = '\' | $80 ; \
|
|
||||||
UNDERSC = '_' | $80 ; Underscore (acts as backspace)
|
|
||||||
DOT = '.' | $80 ; .
|
|
||||||
COLON = ':' | $80 ; :
|
|
||||||
R = 'R' | $80 ; "R"
|
|
||||||
SPACE = ' ' | $80 ; blank
|
|
||||||
ZERO = '0' | $80 ; "0"
|
|
||||||
|
|
||||||
; --------------------------------------------------------
|
|
||||||
RESET: cld ; Clear decimal arithmetic mode
|
|
||||||
cli
|
|
||||||
ldy #$7F ; Mask for DSP data direction register
|
|
||||||
sty DSP ; Set it up
|
|
||||||
lda #$A7 ; KBD and DSP control register mask
|
|
||||||
sta KBDCR ; Enable interrupts, set CA1, CB1 for
|
|
||||||
sta DSPCR ; positive edge sense/output mode
|
|
||||||
NOTCR: cmp #UNDERSC ; Backspace?
|
|
||||||
beq BACKSPACE ; Yes
|
|
||||||
cmp #ESC ; ESC?
|
|
||||||
beq ESCAPE ; Yes
|
|
||||||
iny ; Advance text index
|
|
||||||
bpl NEXTCHAR ; Auto ESC if > 127
|
|
||||||
ESCAPE: lda #SLASH ; "\"
|
|
||||||
jsr ECHO ; Output it
|
|
||||||
GETLINE:
|
|
||||||
lda #CR ; CR
|
|
||||||
jsr ECHO ; Output it
|
|
||||||
ldy #$01 ; Initialize text index
|
|
||||||
BACKSPACE:
|
|
||||||
dey ; Back up text index
|
|
||||||
bmi GETLINE ; Beyond start of line, reinitialize
|
|
||||||
NEXTCHAR:
|
|
||||||
lda KBDCR ; Key ready?
|
|
||||||
bpl NEXTCHAR ; Loop until ready
|
|
||||||
lda KBD ; Load character. B7 should be '1'
|
|
||||||
sta IN,y ; Add to text buffer
|
|
||||||
jsr ECHO ; Display character
|
|
||||||
cmp #CR ; CR?
|
|
||||||
bne NOTCR ; No
|
|
||||||
ldy #$FF ; Reset text index
|
|
||||||
lda #$00 ; For XAM mode
|
|
||||||
tax ; 0 -> x
|
|
||||||
SETSTOR:
|
|
||||||
asl ; Leaves $7B if setting STOR mode
|
|
||||||
SETMODE:
|
|
||||||
sta MODE ; $00 = XAM, $7B = STOR, $AE = BLOCK XAM
|
|
||||||
BLSKIP: iny ; Advance text index
|
|
||||||
NEXTITEM:
|
|
||||||
lda IN,y ; Get character
|
|
||||||
cmp #CR ; CR?
|
|
||||||
beq GETLINE ; Yes, done this line
|
|
||||||
cmp #DOT ; "."?
|
|
||||||
bcc BLSKIP ; Skip delimiter
|
|
||||||
beq SETMODE ; Set BLOCK XAM mode
|
|
||||||
cmp #COLON ; ":"?
|
|
||||||
beq SETSTOR ; Yes, set STOR mode
|
|
||||||
cmp #R ; "R"?
|
|
||||||
beq RUN ; Yes, run user program
|
|
||||||
stx L ; $00 -> L
|
|
||||||
stx H ; and H
|
|
||||||
sty YSAV ; Save Y for comparison
|
|
||||||
NEXTHEX:
|
|
||||||
lda IN,y ; Get character for hex test
|
|
||||||
eor #$B0 ; Map digits to $0-9
|
|
||||||
cmp #$0A ; Digit?
|
|
||||||
bcc DIG ; Yes
|
|
||||||
adc #$88 ; Map letter "A"-"F" to $FA-FF
|
|
||||||
cmp #$FA ; Hex letter?
|
|
||||||
bcc NOTHEX ; No, character not hext
|
|
||||||
DIG: asl
|
|
||||||
asl ; Hex digit to MSD of A
|
|
||||||
asl
|
|
||||||
asl
|
|
||||||
ldx #$04 ; Shift count
|
|
||||||
HEXSHIFT:
|
|
||||||
asl ; Hex digit left, MSB to carry
|
|
||||||
rol L ; Rotate into LSD
|
|
||||||
rol H ; Rotate into MSD's
|
|
||||||
dex ; Done 4 shifts?
|
|
||||||
bne HEXSHIFT ; No, loop
|
|
||||||
iny ; Advance text index
|
|
||||||
bne NEXTHEX ; Always taken. Check next character for hex
|
|
||||||
NOTHEX:
|
|
||||||
cpy YSAV ; Check if L, H empty (no hex digits)
|
|
||||||
beq ESCAPE ; Yes, generate ESC sequence
|
|
||||||
bit MODE ; Test MODE byte
|
|
||||||
bvc NOTSTOR ; B6 = 0 for STOR, 1 for XAM and BLOCK XAM
|
|
||||||
lda L ; LSD's of hex data
|
|
||||||
sta (STL,x) ; Store at current 'store index'
|
|
||||||
inc STL ; Increment store index
|
|
||||||
bne NEXTITEM ; Get next item (no carry)
|
|
||||||
inc STH ; Add carry to 'store index' high order
|
|
||||||
TONEXTITEM:
|
|
||||||
jmp NEXTITEM ; Get next command item
|
|
||||||
RUN: jmp (XAML) ; Run at current XAM index
|
|
||||||
NOTSTOR:
|
|
||||||
bmi XAMNEXT ; B7=0 for XAM, 1 for BLOCK XAM
|
|
||||||
ldx #$02 ; Byte count
|
|
||||||
SETADR: lda L-1,x ; Copy hex data to
|
|
||||||
sta STL-1,x ; 'store index'
|
|
||||||
sta XAML-1,x ; And to 'XAM index'
|
|
||||||
dex ; Next of 2 bytes
|
|
||||||
bne SETADR ; Loop unless X=0
|
|
||||||
NXTPRNT:
|
|
||||||
bne PRDATA ; NE means no address to print
|
|
||||||
lda #CR ; CR
|
|
||||||
jsr ECHO ; Output it
|
|
||||||
lda XAMH ; 'Examine index' high-order byte
|
|
||||||
jsr PRBYTE ; Output it in hex format
|
|
||||||
lda XAML ; Low-order 'examine index' byte
|
|
||||||
jsr PRBYTE ; Output it in hex format
|
|
||||||
lda #COLON ; ":"
|
|
||||||
jsr ECHO ; Output it
|
|
||||||
PRDATA: lda #SPACE ; Blank
|
|
||||||
jsr ECHO ; Output it
|
|
||||||
lda (XAML,x) ; Get data byte at 'examine index'
|
|
||||||
jsr PRBYTE ; Output it in hex format
|
|
||||||
XAMNEXT:
|
|
||||||
stx MODE ; 0 -> MODE (XAM mode)
|
|
||||||
lda XAML
|
|
||||||
cmp L ; Compare 'examine index' to hex data
|
|
||||||
lda XAMH
|
|
||||||
sbc H
|
|
||||||
bcs TONEXTITEM ; Not less, so no more data to output
|
|
||||||
inc XAML
|
|
||||||
bne MOD8CHK ; Increment 'examine index'
|
|
||||||
inc XAMH
|
|
||||||
MOD8CHK:
|
|
||||||
lda XAML ; Check low-order 'examine index' byte
|
|
||||||
and #$07 ; For MOD 8 = 0
|
|
||||||
bpl NXTPRNT ; Always taken
|
|
||||||
PRBYTE: pha ; Save A for LSD
|
|
||||||
lsr
|
|
||||||
lsr
|
|
||||||
lsr ; MSD to LSD position
|
|
||||||
lsr
|
|
||||||
jsr PRHEX ; Output hex digit
|
|
||||||
pla ; Restore A
|
|
||||||
PRHEX: and #$0F ; Mask LSD for hex print
|
|
||||||
ora #ZERO ; Add "0"
|
|
||||||
cmp #$BA ; Digit?
|
|
||||||
bcc ECHO ; Yes, output it
|
|
||||||
adc #$06 ; Add offset for letter
|
|
||||||
ECHO: bit DSP ; DA bit (B7) cleared yet?
|
|
||||||
bmi ECHO ; No, wait for display
|
|
||||||
sta DSP ; Output character. Sets DA.
|
|
||||||
rts ; Return
|
|
||||||
; --------------------------------------------------------
|
|
||||||
.word $0000 ; (unused)
|
|
||||||
.addr $0F00 ; (NMI vector)
|
|
||||||
.addr RESET ; (RESET vector)
|
|
||||||
.addr $0000 ; (IRQ vector)
|
|
Loading…
Reference in New Issue
Block a user