1964 lines
62 KiB
NASM
1964 lines
62 KiB
NASM
PROCESSOR 6502
|
|
LIST ON
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
; The Wozanium Pack ;
|
|
; This file is part one of the Wozanium Pack. ;
|
|
; Apple 1 basic is the other part ;
|
|
;-----------------------------------------------------------------------;
|
|
; Copyright 2010,2011 Mike Willegal
|
|
; A1 monitor and A1 apple cassette interface derived from
|
|
; original Apple 1 implemenations by Steve Wozniak
|
|
;
|
|
; The Wozanium Pack is free software:
|
|
; you can redistribute it and/or modify
|
|
; it under the terms of the GNU General Public License as published by
|
|
; the Free Software Foundation, either version 3 of the License, or
|
|
; (at your option) any later version.
|
|
;
|
|
; The Wozanium Pack is distributed in the hope that it will be useful,
|
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
; GNU General Public License for more details.
|
|
;
|
|
; You should have received a copy of the GNU General Public License
|
|
; along with the Wozanium Pack. If not, see <http://www.gnu.org/licenses/>.
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
;-------------------------------------------------------------------------
|
|
; Defines - this code can be built one of four ways
|
|
; 1. clone/real Apple 1 HW
|
|
; 2. runs in ram of real or virtual Apple 2
|
|
; 3. runs in virtual apple 2 as ROM
|
|
; 4. runs in plug in board of real Apple 2
|
|
;
|
|
; select one of these three options
|
|
;-------------------------------------------------------------------------
|
|
; Build with dasm 6502 assembler and the following command line
|
|
;dasm a2a1emulv5_1.asm -DBLD4ROMBD=0 -DHUSTNBASIC=0 -oa2a1rbh.o -la2a1rbh.lst
|
|
;
|
|
|
|
;BLD4APPLE1 EQU 0 ;ACTUAL APPLE 1 or CLONE
|
|
;BLD4RAM EQU 0 ;RAM of virtual or real A2
|
|
;BLD4EMULROM EQU 0 ;ROM of virtual A2
|
|
;BLD4ROMBD EQU 0 ;ROM board in Real A2
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Constants
|
|
;-------------------------------------------------------------------------
|
|
|
|
BS EQU $DF ;Backspace key, arrow left key
|
|
CR EQU $8D ;Carriage Return
|
|
ESC EQU $9B ;ESC key
|
|
PROMPT EQU "\" ;Prompt character
|
|
|
|
;-------------------------------------------------------------------------
|
|
; scratchpad memory - uses last 1k of apple ii 48k
|
|
;-------------------------------------------------------------------------
|
|
MAC STORAGE
|
|
TURBO DS.b 1 ; any bit non-zero is turbo mode
|
|
TURBOUSR EQU $01 ; USER TURBO MODE
|
|
TURBOCMP EQU $02 ; COMPUTER DRIVEN TURBO MODE
|
|
|
|
RDCONVERT DS.b 1
|
|
READVECTOR DS.w 1 ;allows user override of default keyboard read function
|
|
WRITVECTOR DS.w 1 ;allows user override of default video out function
|
|
|
|
savey DS.b 1
|
|
savex DS.b 1
|
|
POWERUPINIT DS.b 1
|
|
SCRNCLRD DS.b 1
|
|
CHAR DS.b 1
|
|
TMP1 DS.b 1
|
|
CURROW DS.b 1
|
|
CURCOL DS.b 1
|
|
COUNTER0 DS.b 1
|
|
COUNTER1 DS.b 1
|
|
CURSOR DS.b 1
|
|
RDSTRTL DS.b 1
|
|
RDSTRTH DS.b 1
|
|
HEX2LB DS.b 1 ;Begin address of dump block
|
|
HEX2HB DS.b 1
|
|
|
|
;;; zero page back up so graphics routines can use them
|
|
TMPG0 DS.b 16
|
|
PG0SAVD DS.b 1
|
|
ENDM
|
|
IFNCONST BLD4APPLE1
|
|
IFNCONST BLD4RAM
|
|
ORG $bc00
|
|
STORAGE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Memory declaration
|
|
;-------------------------------------------------------------------------
|
|
|
|
|
|
HEX1L EQU $24 ;End address of dump block
|
|
HEX1H EQU $25
|
|
HEX2L EQU $26 ;Begin address of dump block
|
|
HEX2H EQU $27
|
|
|
|
SAVEINDEX EQU $28 ;Save index in input buffer
|
|
LASTSTATE EQU $29 ;Last input state
|
|
|
|
IN EQU $0200 ;Input buffer
|
|
IFCONST BLD4APPLE1
|
|
FLIP EQU $C000 ;Output flip-flop
|
|
TAPEIN EQU $C081 ;Tape input
|
|
KBD EQU $D010 ;PIA.A keyboard input
|
|
KBDCR EQU $D011 ;PIA.A keyboard control register
|
|
ELSE
|
|
FLIP EQU $C020 ;Output flip-flop
|
|
TAPEIN EQU $C060 ;Tape input
|
|
KBD EQU $C000 ;keyboard input
|
|
KBDCR EQU $C010 ;keybaord strobe clear
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Constants
|
|
;-------------------------------------------------------------------------
|
|
|
|
CR EQU $8D ;Carriage Return
|
|
ESC EQU $9B ;ASCII ESC
|
|
CNTSTRT EQU $E0
|
|
|
|
;---------------------------------------------------------------------------
|
|
; build in ACI Driver
|
|
;---------------------------------------------------------------------------
|
|
IFCONST BLD4EMULROM
|
|
ORG $D000 ; EMULATOR ROM image
|
|
ELSE
|
|
IFCONST BLD4RAM
|
|
ORG $6000 ; build for memory
|
|
ELSE
|
|
ORG $C100 ; real apple 1 or plug in ROM board for A2
|
|
ENDIF
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------
|
|
;
|
|
; The WOZ Apple Cassette Interface for the Apple 1
|
|
; Written by Steve Wozniak somewhere around 1976
|
|
;
|
|
;-------------------------------------------------------------------------
|
|
WOZACI
|
|
|
|
LDA #$aa ;Print the Tape prompt
|
|
IFNCONST BLD4APPLE1
|
|
JMP A2ACIDRIVER ;If not actual Apple 1, use A2 driver
|
|
ELSE
|
|
JSR ECHO
|
|
ENDIF
|
|
LDA #CR ;And drop the cursor one line
|
|
JSR ECHO
|
|
|
|
LDY #-1 ;Reset the input buffer index
|
|
ACINEXTCHAR INY
|
|
|
|
|
|
ACIWAITCHAR LDA KBDCR ;Wait for key press
|
|
BPL ACIWAITCHAR ;No key yet!
|
|
LDA KBD ;Clear strobe
|
|
STA IN,Y ;Save it into buffer
|
|
JSR ECHO ;And type it on the screen
|
|
CMP #ESC
|
|
BEQ WOZACI ;Start from scratch if ESC!
|
|
CMP #CR
|
|
BNE ACINEXTCHAR ;Read keys until CR
|
|
|
|
LDX #-1 ;Initialize parse buffer pointer
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Start parsing first or a new tape command
|
|
;-------------------------------------------------------------------------
|
|
|
|
NEXTCMD LDA #0 ;Clear begin and end values
|
|
STA HEX1L
|
|
STA HEX1H
|
|
STA HEX2L
|
|
STA HEX2H
|
|
|
|
NEXTCHR INX ;Increment input pointer
|
|
LDA IN,X ;Get next char from input line
|
|
CMP #$d2 ;Read command?
|
|
BEQ READ ;Yes!
|
|
CMP #$d7 ;Write command?
|
|
BEQ WRITE ;Yes! (note: CY=1)
|
|
CMP #$ae ;Separator?
|
|
BEQ SEP ;Yes!
|
|
CMP #CR ;End of line?
|
|
BEQ GOESC ;Escape to monitor! We're done
|
|
CMP #$a0 ;Ignore spaces
|
|
BEQ NEXTCHR
|
|
EOR #$b0 ;Map digits to 0-9
|
|
CMP #9+1 ;Is it a decimal digit?
|
|
BCC ACIDIG ;Yes!
|
|
ADC #$88 ;Map letter "A"-"F" to $FA-$FF
|
|
CMP #$FA ;Hex letter?
|
|
BCC WOZACI ;No! Character not hex!
|
|
|
|
ACIDIG ASL ;Hex digit to MSD of A
|
|
ASL
|
|
ASL
|
|
ASL
|
|
|
|
LDY #4 ;Shift count
|
|
ACIHEXSHIFT ASL ;Hex digit left, MSB to carry
|
|
ROL HEX1L ;Rotate into LSD
|
|
ROL HEX1H ;Rotate into MSD
|
|
DEY ;Done 4 shifts?
|
|
BNE ACIHEXSHIFT ;No! Loop
|
|
BEQ NEXTCHR ;Handle next character
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Return to monitor, prints \ first
|
|
;-------------------------------------------------------------------------
|
|
|
|
GOESC JMP ESCAPE ;Escape back to monitor
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Separating . found. Copy HEX1 to Hex2. Doesn't clear HEX1!!!
|
|
;-------------------------------------------------------------------------
|
|
|
|
SEP LDA HEX1L ;Copy hex value 1 to hex value 2
|
|
STA HEX2L
|
|
LDA HEX1H
|
|
STA HEX2H
|
|
BCS NEXTCHR ;Always taken!
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Write a block of memory to tape
|
|
;-------------------------------------------------------------------------
|
|
|
|
WRITE
|
|
LDA #64 ;Write 10 second header
|
|
JSR WHEADER
|
|
WRNEXT DEY ;Compensate timing for extra work
|
|
LDX #0 ;Get next byte to write
|
|
LDA (HEX2L,X)
|
|
|
|
LDX #8*2 ;Shift 8 bits (decremented twice)
|
|
WBITLOOP ASL ;Shift MSB to carry
|
|
JSR WRITEBIT ;Write this bit
|
|
BNE WBITLOOP ;Do all 8 bits!
|
|
|
|
JSR INCADDR ;Increment address
|
|
LDY #30 ;Compensate timer for extra work
|
|
BCC WRNEXT ;Not done yet! Write next byte
|
|
|
|
RESTIDX
|
|
LDX SAVEINDEX ;Restore index in input line
|
|
BCS NEXTCMD ;Always taken!
|
|
|
|
;-------------------------------------------------------------------------
|
|
; For case when ACI must fit in c100-c1ff - the read function must be moved
|
|
; because the standard read doesn't fit with the extra mask instruction
|
|
; required for the Apple II hardware
|
|
;-------------------------------------------------------------------------
|
|
|
|
READ:
|
|
JSR FULLCYCLE ;Wait until full cycle is detected
|
|
LDA #22 ;Introduce some delay to allow
|
|
JSR WHEADER ; the tape speed to stabilize
|
|
JSR FULLCYCLE ;Synchronize with full cycle
|
|
NOTSTART
|
|
LDY #31 ;Try to detect the much shorter
|
|
JSR CMPLEVEL ; start bit
|
|
BCS NOTSTART ;Start bit not detected yet!
|
|
JSR CMPLEVEL ;Wait for 2nd phase of start bit
|
|
|
|
LDY #58 ;Set threshold value in middle
|
|
RDBYTE LDX #8 ;Receiver 8 bits
|
|
RDBIT PHA
|
|
JSR FULLCYCLE ;Detect a full cycle
|
|
PLA
|
|
ROL ;Roll new bit into result
|
|
LDY #57 ;Set threshold value in middle
|
|
DEX ;Decrement bit counter
|
|
BNE RDBIT ;Read next bit!
|
|
STA (HEX2L,X) ;Save new byte
|
|
|
|
JSR INCADDR ;Increment address
|
|
LDY #53 ;Compensate threshold with workload
|
|
BCC RDBYTE ;Do next byte if not done yet!
|
|
BCS RESTIDX ;Always taken! Restore parse index
|
|
|
|
FULLCYCLE JSR CMPLEVEL ;Wait for two level changes
|
|
CMPLEVEL DEY ;Decrement time counter
|
|
LDA TAPEIN ;Get Tape In data
|
|
|
|
;-------------------------------------------------------------------------
|
|
; the next instruction must be added for apple II
|
|
; since it doesn't fit in the 256 bytes allowed in the
|
|
; original PROM, a substitute A2 read function is called instead
|
|
; (READ_APPLE2_VERSION)which is located in a different bank
|
|
;
|
|
; AND #$80 ;CLEAR floating bits
|
|
;-------------------------------------------------------------------------
|
|
CMP LASTSTATE ;Same as before?
|
|
BEQ CMPLEVEL ;Yes!
|
|
STA LASTSTATE ;Save new data
|
|
|
|
CPY #128 ;Compare threshold
|
|
RTS
|
|
;-------------------------------------------------------------------------
|
|
; Write header to tape
|
|
;
|
|
; The header consists of an asymmetric cycle, starting with one phase of
|
|
; approximately (66+47)x5=565us, followed by a second phase of
|
|
; approximately (44+47)x5=455us.
|
|
; Total cycle duration is approximately 1020us ~ 1kHz. The actual
|
|
; frequencywill be a bit lower because of the additional workload between
|
|
; the twoloops.
|
|
; The header ends with a short phase of (30+47)x5=385us and a normal
|
|
; phase of (44+47)x5=455us. This start bit must be detected by the read
|
|
; routine to trigger the reading of the actual data.
|
|
;-------------------------------------------------------------------------
|
|
|
|
WHEADER STX SAVEINDEX ;Save index in input line
|
|
HCOUNT LDY #66 ;Extra long delay
|
|
JSR WDELAY ;CY is constantly 1, writing a 1
|
|
BNE HCOUNT ;Do this 64 * 256 time!
|
|
ADC #-2 ;Decrement A (CY=1 all the time)
|
|
BCS HCOUNT ;Not all done!
|
|
LDY #30 ;Write a final short bit (start)
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Write a full bit cycle
|
|
;
|
|
; Upon entry Y contains a compensated value for the first phase of 0
|
|
; bit length. All subsequent loops don't have to be time compensated.
|
|
;-------------------------------------------------------------------------
|
|
|
|
WRITEBIT JSR WDELAY ;Do two equal phases
|
|
LDY #44 ;Load 250us counter - compensation
|
|
|
|
WDELAY DEY ;Delay 250us (one phase of 2kHz)
|
|
BNE WDELAY
|
|
BCC WRITE1 ;Write a '1' (2kHz)
|
|
|
|
LDY #47 ;Additional delay for '0' (1kHz)
|
|
WDELAY0 DEY ; (delay 250us)
|
|
BNE WDELAY0
|
|
|
|
WRITE1
|
|
LDY FLIP,X ;Flip the output bit
|
|
LDY #41 ;Reload 250us cntr (compensation)
|
|
DEX ;Decrement bit counter
|
|
RTS
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Increment current address and compare with last address
|
|
;-------------------------------------------------------------------------
|
|
INCADDR LDA HEX2L ;Compare current address with
|
|
CMP HEX1L ; end address
|
|
LDA HEX2H
|
|
SBC HEX1H
|
|
INC HEX2L ;And increment current address
|
|
BNE NOCARRY ;No carry to MSB!
|
|
INC HEX2H
|
|
NOCARRY RTS
|
|
|
|
|
|
;---------------------------------------------------------------------------
|
|
; all the following code is needed for the A2 version
|
|
; skip to Basic for the real thing
|
|
;---------------------------------------------------------------------------
|
|
IFNCONST BLD4APPLE1
|
|
;---------------------------------------------------------------------------
|
|
; build in an A2 ACI driver for ROM version
|
|
; if using an A2, the version at C100 jumps to this version
|
|
; and this version is at D000 (so slots 0 & 2-7 can be used)
|
|
;---------------------------------------------------------------------------
|
|
IFNCONST BLD4EMULROM
|
|
IFNCONST BLD4RAM
|
|
ORG $D000 ; A2 ROM or image
|
|
ENDIF
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------
|
|
; ACI DRIVER
|
|
;-------------------------------------------------------------------------
|
|
A2ACIDRIVER
|
|
LDA #$aa ;Print the Tape prompt
|
|
JSR ECHO
|
|
LDA #CR ;And drop the cursor one line
|
|
JSR ECHO
|
|
|
|
LDY #-1 ;Reset the input buffer index
|
|
RB_ACINEXTCHAR
|
|
INY
|
|
|
|
JSR A2GETCHAR
|
|
|
|
STA IN,Y ;Save it into buffer
|
|
JSR ECHO ;And type it on the screen
|
|
CMP #ESC
|
|
BEQ A2ACIDRIVER ;Start from scratch if ESC!
|
|
CMP #CR
|
|
BNE RB_ACINEXTCHAR ;Read keys until CR
|
|
|
|
LDX #-1 ;Initialize parse buffer pointer
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Start parsing first or a new tape command
|
|
;-------------------------------------------------------------------------
|
|
|
|
RB_NEXTCMD
|
|
LDA #0 ;Clear begin and end values
|
|
STA HEX1L
|
|
STA HEX1H
|
|
STA HEX2L
|
|
STA HEX2H
|
|
|
|
RB_NEXTCHR
|
|
INX ;Increment input pointer
|
|
LDA IN,X ;Get next char from input line
|
|
CMP #$d2 ;Read command?
|
|
BEQ RB_READ ;Yes!
|
|
CMP #$d7 ;Write command?
|
|
BEQ RB_WRITE ;Yes! (note: CY=1)
|
|
CMP #$ae ;Separator?
|
|
BEQ RB_SEP ;Yes!
|
|
CMP #CR ;End of line?
|
|
BEQ RB_GOESC ;Escape to monitor! We're done
|
|
CMP #$a0 ;Ignore spaces
|
|
BEQ RB_NEXTCHR
|
|
EOR #$b0 ;Map digits to 0-9
|
|
CMP #9+1 ;Is it a decimal digit?
|
|
BCC RB_ACIDIG ;Yes!
|
|
ADC #$88 ;Map letter "A"-"F" to $FA-$FF
|
|
CMP #$FA ;Hex letter?
|
|
BCC A2ACIDRIVER ;No! Character not hex!
|
|
|
|
RB_ACIDIG
|
|
ASL ;Hex digit to MSD of A
|
|
ASL
|
|
ASL
|
|
ASL
|
|
|
|
LDY #4 ;Shift count
|
|
RB_ACIHEXSHIFT
|
|
ASL ;Hex digit left, MSB to carry
|
|
ROL HEX1L ;Rotate into LSD
|
|
ROL HEX1H ;Rotate into MSD
|
|
DEY ;Done 4 shifts?
|
|
BNE RB_ACIHEXSHIFT ;No! Loop
|
|
BEQ RB_NEXTCHR ;Handle next character
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Return to monitor, prints \ first
|
|
;-------------------------------------------------------------------------
|
|
|
|
RB_GOESC JMP ESCAPE ;Escape back to monitor
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Separating . found. Copy HEX1 to Hex2. Doesn't clear HEX1!!!
|
|
;-------------------------------------------------------------------------
|
|
|
|
RB_SEP LDA HEX1L ;Copy hex value 1 to hex value 2
|
|
STA HEX2L
|
|
LDA HEX1H
|
|
STA HEX2H
|
|
BCS RB_NEXTCHR ;Always taken!
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Write a block of memory to tape
|
|
;-------------------------------------------------------------------------
|
|
|
|
RB_WRITE
|
|
;-------------------------------------------------------------------------
|
|
; save write start addresses
|
|
; so we can check for keyboard
|
|
; or console write sequences
|
|
; and dynamicly modify code to
|
|
; use original A1 driver
|
|
; and then revert later on
|
|
;-------------------------------------------------------------------------
|
|
LDA HEX2L
|
|
STA RDSTRTL
|
|
LDA HEX2H
|
|
STA RDSTRTH
|
|
STX SAVEINDEX ;Save index in input line
|
|
JSR A2_WRITECONVERT ; convert I/O to A1 compatible format
|
|
;-------------------------------------------------------------------------
|
|
; now start write of this block
|
|
;-------------------------------------------------------------------------
|
|
|
|
LDA #64 ;Write 10 second header
|
|
JSR RB_WHEADER
|
|
|
|
RB_WRNEXT DEY ;Compensate timing for extra work
|
|
LDX #0 ;Get next byte to write
|
|
LDA (HEX2L,X)
|
|
|
|
LDX #8*2 ;Shift 8 bits (decremented twice)
|
|
RB_WBITLOOP ASL ;Shift MSB to carry
|
|
JSR RB_WRITEBIT ;Write this bit
|
|
BNE RB_WBITLOOP ;Do all 8 bits!
|
|
|
|
JSR A2_INCADDR ;Increment address
|
|
LDY #30 ;Compensate timer for extra work
|
|
BCC RB_WRNEXT ;Not done yet! Write next byte
|
|
|
|
RB_RESTIDX
|
|
JSR A2_READCONVERT ; convert buffer to A2 I/O
|
|
LDX SAVEINDEX ;Restore index in input line
|
|
JMP RB_NEXTCMD ;Always taken!
|
|
|
|
;-------------------------------------------------------------------------
|
|
; For case when ACI must fit in c100-c1ff - the read function must be moved
|
|
; because the standard read doesn't fit with the extra mask instruction
|
|
; required for the Apple II hardware
|
|
;-------------------------------------------------------------------------
|
|
|
|
RB_READ:
|
|
;-------------------------------------------------------------------------
|
|
; save read start addresses
|
|
; so we can check for keyboard
|
|
; or console write sequences
|
|
; and dynamicly modify code to
|
|
; use A2 driver
|
|
;-------------------------------------------------------------------------
|
|
LDA HEX2L
|
|
STA RDSTRTL
|
|
LDA HEX2H
|
|
STA RDSTRTH
|
|
|
|
JSR A2_FULLCYCLE ;Wait until full cycle is detected
|
|
STX SAVEINDEX ;Save index in input line
|
|
LDA #22 ;Introduce some delay to allow
|
|
JSR RB_WHEADER ; the tape speed to stabilize
|
|
|
|
;-------------------------------------------------------------------------
|
|
;
|
|
; This read function will optionally convert and A1 keyboard reads
|
|
; to calls to use our driver to read from A2 hardware by scanning
|
|
; read data looking for one of three code sequences
|
|
;-------------------------------------------------------------------------
|
|
;
|
|
; Normal start
|
|
;
|
|
JSR A2_FULLCYCLE ;Synchronize with full cycle
|
|
A2_NOTSTART LDY #28 ;Try to detect the much shorter
|
|
JSR A2_CMPLEVEL ; start bit
|
|
BCS A2_NOTSTART ;Start bit not detected yet!
|
|
JSR A2_CMPLEVEL ;Wait for 2nd phase of start bit
|
|
|
|
LDY #53 ;Set threshold value in middle
|
|
A2_RDBYTE LDX #8 ;Receiver 8 bits
|
|
A2_RDBIT PHA
|
|
JSR A2_FULLCYCLE ;Detect a full cycle
|
|
PLA
|
|
ROL ;Roll new bit into result
|
|
LDY #52 ;Set threshold value in middle
|
|
DEX ;Decrement bit counter
|
|
BNE A2_RDBIT ;Read next bit!
|
|
STA (HEX2L,X) ;Save new byte
|
|
|
|
JSR A2_INCADDR ;Increment address
|
|
LDY #46 ;Compensate threshold with workload
|
|
BCC A2_RDBYTE ;Do next byte if not done yet!
|
|
|
|
JMP RB_RESTIDX
|
|
|
|
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Write header to tape
|
|
;
|
|
; The header consists of an asymmetric cycle, starting with one phase of
|
|
; approximately (66+47)x5=565us, followed by a second phase of
|
|
; approximately (44+47)x5=455us.
|
|
; Total cycle duration is approximately 1020us ~ 1kHz. The actual
|
|
; frequencywill be a bit lower because of the additional workload between
|
|
; the twoloops.
|
|
; The header ends with a short phase of (30+47)x5=385us and a normal
|
|
; phase of (44+47)x5=455us. This start bit must be detected by the read
|
|
; routine to trigger the reading of the actual data.
|
|
;-------------------------------------------------------------------------
|
|
|
|
RB_WHEADER
|
|
RB_HCOUNT LDY #72 ;Extra long delay
|
|
JSR RB_WDELAY ;CY is constantly 1, writing a 1
|
|
BNE RB_HCOUNT ;Do this 64 * 256 time!
|
|
ADC #-2 ;Decrement A (CY=1 all the time)
|
|
BCS RB_HCOUNT ;Not all done!
|
|
LDY #32 ;Write a final short bit (start)
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Write a full bit cycle
|
|
;
|
|
; Upon entry Y contains a compensated value for the first phase of 0
|
|
; bit length. All subsequent loops don't have to be time compensated.
|
|
;-------------------------------------------------------------------------
|
|
|
|
RB_WRITEBIT
|
|
|
|
JSR RB_WDELAY ;Do two equal phases
|
|
LDY #47 ;Load 250us counter - compensation
|
|
|
|
RB_WDELAY DEY ;Delay 250us (one phase of 2kHz)
|
|
BNE RB_WDELAY
|
|
BCC RB_WRITE1 ;Write a '1' (2kHz)
|
|
|
|
LDY #50 ;Additional delay for '0' (1kHz)
|
|
RB_WDELAY0 DEY ; (delay 250us)
|
|
BNE RB_WDELAY0
|
|
|
|
RB_WRITE1
|
|
|
|
LDY FLIP ;Flip the output bit
|
|
|
|
LDY #46 ;Reload 250us cntr (compensation)
|
|
DEX ;Decrement bit counter
|
|
RTS
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Wait for FULL cycle (cmplevel- waits till level transisiton)
|
|
;-------------------------------------------------------------------------
|
|
A2_FULLCYCLE JSR A2_CMPLEVEL ;Wait for two level changes
|
|
A2_CMPLEVEL DEY ;Decrement time counter
|
|
LDA TAPEIN ;Get Tape In data
|
|
|
|
; the next instruction must be added for apple II
|
|
AND #$80 ;CLEAR floating bits
|
|
CMP LASTSTATE ;Same as before?
|
|
BEQ A2_CMPLEVEL ;Yes!
|
|
STA LASTSTATE ;Save new data
|
|
|
|
CPY #128 ;Compare threshold
|
|
RTS
|
|
;-------------------------------------------------------------------------
|
|
; Increment current address and compare with last address
|
|
;-------------------------------------------------------------------------
|
|
A2_INCADDR LDA HEX2L ;Compare current address with
|
|
CMP HEX1L ; end address
|
|
LDA HEX2H
|
|
SBC HEX1H
|
|
INC HEX2L ;And increment current address
|
|
BNE A2_NOCARRY ;No carry to MSB!
|
|
INC HEX2H
|
|
A2_NOCARRY RTS
|
|
|
|
;-------------------------------------------------------------------------
|
|
; one block read
|
|
; modify A1 code that touches PIA to A2 version as it is loaded
|
|
; these are keyboard and display functions
|
|
;
|
|
; APPLE 1 version
|
|
;ACIWAITCHAR
|
|
; ad 11 d0 LDA KBDCR ;Wait for key press
|
|
; 30 FB BPL ACIWAITCHAR ;No key yet!
|
|
; ad 10 d0 LDA KBD ;Clear strobe
|
|
; converted to our version
|
|
; 20 3a d1 JSR A2GETCHAR
|
|
; ea NOP
|
|
; ea NOP
|
|
; ea NOP
|
|
; ea NOP
|
|
; ea NOP
|
|
;
|
|
; instead if BPL is not present or has mismatching branch offset
|
|
; ad 11 d0 LDA KBDCR
|
|
; is converted to
|
|
; ad 00 c0 LDA KBD
|
|
;
|
|
;
|
|
;
|
|
; ad 10 d0 LDA KBD
|
|
; is converted to
|
|
; 8d 10 c0 STA KBDCR ;Clear strobe
|
|
;
|
|
; finally there are some cases where presence of character is
|
|
; determined with the bit command
|
|
; 2c 11 d0 BIT KBDCR
|
|
; is converted to
|
|
; 2c 00 c00 BIT KBD
|
|
;
|
|
;
|
|
;
|
|
;-------------------------------------------------------------------------
|
|
|
|
CNVRTTERM EQU $77 ; UNIQUE CHAR NEEDED TO TERMINATE CONVERSION STRINGS
|
|
|
|
A2_READCONVERT
|
|
LDA #0 ; RDCONVERT can be turned off
|
|
CMP RDCONVERT
|
|
BNE A2_READCONVERTDONE ; not zero, then skip conversion
|
|
LDX #0
|
|
LDY #0
|
|
;
|
|
; check next string through all of memory
|
|
;
|
|
|
|
A2_READCONVERT_1 ; for this string, scan all of read memory
|
|
STY savey ;save compare string starting point
|
|
|
|
LDA CNVRT_IN,Y
|
|
CMP #CNVRTTERM ; Termination character?
|
|
BEQ A2_READCONVERTDONE ;all done checking, exit
|
|
|
|
LDA RDSTRTL ; start of memory load
|
|
STA HEX2L
|
|
LDA RDSTRTH
|
|
STA HEX2H
|
|
|
|
;
|
|
; restart currnet string
|
|
;
|
|
A2_READCONVERT_8
|
|
LDA HEX2L ;save memory starting point
|
|
STA HEX2LB
|
|
LDA HEX2H
|
|
STA HEX2HB
|
|
LDY savey
|
|
|
|
A2_READCONVERT1
|
|
LDA (HEX2L),X ; fetch byte from memory
|
|
CMP CNVRT_IN,Y ; compare
|
|
BEQ A2_READCONVERT1_2 ; this byte does match, process
|
|
;
|
|
; mo match, restart match string
|
|
;
|
|
JSR A2_INCADDR
|
|
BCC A2_READCONVERT_8 ; not end of memory - restart scan for current string
|
|
|
|
;
|
|
; end of memory block - go to next string
|
|
;
|
|
A2_READCONVERT1_3
|
|
INY
|
|
LDA CNVRT_IN,Y
|
|
CMP #CNVRTTERM ; Termination character?
|
|
BNE A2_READCONVERT1_3 ; not end of block, keep looking
|
|
INY ; found end, move to start of next block
|
|
JMP A2_READCONVERT_1 ; rescan memory with next string
|
|
;
|
|
; match - keep going until mismatch or end of string
|
|
;
|
|
A2_READCONVERT1_2
|
|
INY
|
|
LDA CNVRT_IN,Y
|
|
CMP #CNVRTTERM ; Termination character?
|
|
BEQ A2_READCONVERT3 ; end of string - this is match do substitute
|
|
JSR A2_INCADDR ; next memory address
|
|
BCC A2_READCONVERT1 ; not done - keep scanning
|
|
|
|
JMP A2_READCONVERT1_3 ; not a complete match - try next string
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Finished with READ
|
|
;-------------------------------------------------------------------------
|
|
A2_READCONVERTDONE
|
|
RTS
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Substitute string here
|
|
;-------------------------------------------------------------------------
|
|
|
|
A2_READCONVERT3 ; match - substitute here
|
|
LDY savey
|
|
|
|
LDA HEX2LB ;restore memory starting point
|
|
STA HEX2L
|
|
LDA HEX2HB
|
|
STA HEX2H
|
|
A2_READCONVERT4
|
|
LDA CNVRT_IN,Y
|
|
CMP #CNVRTTERM ; Termination character?
|
|
BEQ A2_READCONVERT_8 ; done with sustibute, continue checking
|
|
LDA CNVRT_OUT,Y
|
|
INY
|
|
STA (HEX2L),X
|
|
JSR A2_INCADDR
|
|
JMP A2_READCONVERT4
|
|
|
|
;-------------------------------------------------------------------------
|
|
; conversion strings
|
|
; IN(what we are looking for
|
|
; OUT (what we change it to)
|
|
;-------------------------------------------------------------------------
|
|
|
|
CNVRT_IN
|
|
CI1 LDA $d011
|
|
BPL CI1
|
|
LDA $d010
|
|
DC.b CNVRTTERM
|
|
LDA $d011
|
|
DC.b CNVRTTERM
|
|
LDA $d010
|
|
DC.b CNVRTTERM
|
|
BIT $d011
|
|
DC.b CNVRTTERM
|
|
CI2
|
|
BIT $D012
|
|
BMI CI2
|
|
STA $D012
|
|
DC.b CNVRTTERM
|
|
IFCONST BLD4RAM
|
|
JSR $FFEF
|
|
DC.b CNVRTTERM
|
|
ENDIF
|
|
DC.b CNVRTTERM
|
|
|
|
CNVRT_OUT
|
|
JSR A2GETCHAR
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
DC.b CNVRTTERM
|
|
LDA KBD
|
|
DC.b CNVRTTERM
|
|
STA KBDCR
|
|
DC.b CNVRTTERM
|
|
BIT KBD
|
|
DC.b CNVRTTERM
|
|
JSR ECHO
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
DC.b CNVRTTERM
|
|
IFCONST BLD4RAM
|
|
JSR ECHO
|
|
DC.b CNVRTTERM
|
|
ENDIF
|
|
DC.b CNVRTTERM
|
|
|
|
|
|
;-------------------------------------------------------------------------
|
|
; one block write
|
|
; undo read convert when writing to tape so tape
|
|
; can be loaded and run on a real actual A1
|
|
;-------------------------------------------------------------------------
|
|
A2_WRITECONVERT
|
|
LDA #0 ; RDCONVERT can be turned off
|
|
CMP RDCONVERT
|
|
BNE A2_WRITECONVERTDONE ; not zero, then skip conversion
|
|
LDX #0
|
|
LDY #0
|
|
;
|
|
; check next string through all of memory
|
|
;
|
|
|
|
A2_WRITECONVERT_1 ; for this string, scan all of read memory
|
|
STY savey ;save compare string starting point
|
|
|
|
LDA CNVRT_OUT,Y
|
|
CMP #CNVRTTERM ; Termination character?
|
|
BEQ A2_WRITECONVERTDONE ;all done checking, exit
|
|
|
|
LDA RDSTRTL ; reset block address
|
|
STA HEX2L
|
|
LDA RDSTRTH
|
|
STA HEX2H
|
|
|
|
;
|
|
; restart currnet string
|
|
;
|
|
A2_WRITECONVERT_8
|
|
LDA HEX2L ;save memory starting point
|
|
STA HEX2LB
|
|
LDA HEX2H
|
|
STA HEX2HB
|
|
LDY savey
|
|
|
|
A2_WRITECONVERT1
|
|
LDA (HEX2L),X ; fetch byte from memory
|
|
CMP CNVRT_OUT,Y ; compare
|
|
BEQ A2_WRITECONVERT1_2 ; this byte does match, process
|
|
;
|
|
; mo match, restart match string
|
|
;
|
|
JSR A2_INCADDR
|
|
BCC A2_WRITECONVERT_8 ; not end of memory - restart scan for current string
|
|
|
|
;
|
|
; end of memory block - go to next string
|
|
;
|
|
A2_WRITECONVERT1_3
|
|
INY
|
|
LDA CNVRT_OUT,Y
|
|
CMP #CNVRTTERM ; Termination character?
|
|
BNE A2_WRITECONVERT1_3 ; not end of block, keep looking
|
|
INY ; found end, move to start of next block
|
|
JMP A2_WRITECONVERT_1 ; rescan memory with next string
|
|
;
|
|
; match - keep going until mismatch or end of string
|
|
;
|
|
A2_WRITECONVERT1_2
|
|
INY
|
|
LDA CNVRT_OUT,Y
|
|
CMP #CNVRTTERM ; Termination character?
|
|
BEQ A2_WRITECONVERT3 ; end of string - this is match do substitute
|
|
JSR A2_INCADDR ; next memory address
|
|
BCC A2_WRITECONVERT1 ; not done - keep scanning
|
|
|
|
JMP A2_WRITECONVERT1_3 ; not a complete match - try next string
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Finished with WRITE CONVERSION
|
|
;-------------------------------------------------------------------------
|
|
A2_WRITECONVERTDONE
|
|
LDA RDSTRTL ; reset block address
|
|
STA HEX2L
|
|
LDA RDSTRTH
|
|
STA HEX2H
|
|
|
|
RTS
|
|
;-------------------------------------------------------------------------
|
|
; Substitute string here
|
|
;-------------------------------------------------------------------------
|
|
|
|
A2_WRITECONVERT3 ; match - substitute here
|
|
LDY savey
|
|
|
|
LDA HEX2LB ;restore memory starting point
|
|
STA HEX2L
|
|
LDA HEX2HB
|
|
STA HEX2H
|
|
A2_WRITECONVERT4
|
|
LDA CNVRT_OUT,Y
|
|
CMP #CNVRTTERM ; Termination character?
|
|
BEQ A2_WRITECONVERT_8 ; done with sustibute, continue checking
|
|
LDA CNVRT_IN,Y
|
|
INY
|
|
STA (HEX2L),X
|
|
JSR A2_INCADDR
|
|
JMP A2_WRITECONVERT4
|
|
|
|
;-------------------------------------------------------------------------
|
|
; output driver - uses hires memory
|
|
;-------------------------------------------------------------------------
|
|
|
|
A2GETCHAR:
|
|
JMP (READVECTOR) ;Allow user override of default get char function
|
|
A2GETCHAR2:
|
|
JSR TOGGLE
|
|
LDA KBD ;Wait for key press
|
|
BPL A2GETCHAR ;No key yet!
|
|
STA KBDCR ;Clear strobe
|
|
CMP #$88 ; left arrow
|
|
BNE A2_GC_NOT_BS ; brnch no
|
|
LDA #BS ; convert to _
|
|
A2_GC_NOT_BS:
|
|
CMP #$95 ; right arrow
|
|
BNE A2_GC_RET ; no, exit
|
|
JSR CLEAR ; yes, clear screen and
|
|
|
|
JMP A2GETCHAR ; get next char (this is a special HW emulation
|
|
; function so skip call to READVECTOR)
|
|
A2_GC_RET:
|
|
RTS
|
|
|
|
|
|
;-------------------------------------------------------------------------
|
|
; output driver - uses hires memory
|
|
;-------------------------------------------------------------------------
|
|
;;; Magic Numbers
|
|
SCRINIT EQU $f0
|
|
PG0SAVEFLG EQU $f0
|
|
;;; Definitions
|
|
HRPG1 EQU $C054
|
|
HRPG2 EQU $C055
|
|
LORES EQU $C056
|
|
HIRES EQU $C057
|
|
TXTCLR EQU $C050
|
|
TXTMOD EQU $C051
|
|
MIXCLR EQU $C052
|
|
GETCHAR EQU $FD0C
|
|
|
|
;;; Page Zero Temps (8 locations reserved)
|
|
TRGLOW EQU $00
|
|
TRGHIGH EQU $01
|
|
SRCLOW EQU $02
|
|
SRCHIGH EQU $03
|
|
CNT2 EQU $05
|
|
CNT3 EQU $06
|
|
|
|
; Last location of low res
|
|
LASTLOCATION EQU $7F8
|
|
|
|
;;; Entry point for testing
|
|
START JSR INIT
|
|
L0 JSR GETCHAR
|
|
JSR PUTCH
|
|
JMP L0
|
|
BRK
|
|
|
|
;;; Move the cursor
|
|
MVCSR INC CURCOL
|
|
LDA CURCOL
|
|
CMP #40
|
|
BPL NXTROW
|
|
MD
|
|
LDA #0
|
|
CMP TURBO
|
|
BNE MR
|
|
|
|
LDY #0
|
|
ML0 LDX #12 ; speed fine tuning
|
|
ML1 INX
|
|
BNE ML1
|
|
INY
|
|
CPY #$9
|
|
BNE ML0
|
|
MR RTS
|
|
NXTROW
|
|
LDA #0
|
|
STA CURCOL
|
|
|
|
LDA CURROW ; don't increment current row until in case
|
|
; we are already at bottom of screen
|
|
CMP #23 ; if a reset comes in, it could leave us on an illegal row
|
|
BMI NXTROW2
|
|
|
|
JSR SCROLL ; scrolling bottom line, do not advance CURROW
|
|
JMP MD
|
|
|
|
NXTROW2
|
|
INC CURROW ; not at bottom of screen advance to next row (CURROW)
|
|
JMP MD
|
|
|
|
;;; Toggle the cursor
|
|
TOGGLE
|
|
|
|
INC COUNTER0
|
|
BNE DT
|
|
INC COUNTER1
|
|
BNE DT
|
|
PHA
|
|
LDA #CNTSTRT
|
|
STA COUNTER1
|
|
;
|
|
; if screen has not been cleared- toggle betweeen hi res pages
|
|
;
|
|
LDA SCRNCLRD
|
|
BMI TOGGLE2
|
|
;
|
|
; toggle from hi-res to low-res
|
|
;
|
|
LDA CURSOR
|
|
BNE TOGGLE1
|
|
LDA #32
|
|
STA CURSOR
|
|
LDA HRPG1
|
|
JMP TOGGLE4
|
|
|
|
TOGGLE1
|
|
LDA #0
|
|
STA CURSOR
|
|
LDA HRPG2
|
|
JMP TOGGLE4
|
|
;
|
|
; else toggle cursor
|
|
;
|
|
TOGGLE2
|
|
STX savex
|
|
STY savey
|
|
JSR SAVPG0
|
|
|
|
LDA CURSOR
|
|
BNE SETSPC
|
|
LDA #32
|
|
JMP DRWCUR
|
|
SETSPC LDA #0
|
|
DRWCUR STA CURSOR
|
|
LDX CURCOL
|
|
LDY CURROW
|
|
JSR GETBLOK
|
|
LDX CURSOR
|
|
JSR GETCHB
|
|
JSR DRAWCH
|
|
JSR LODPG0
|
|
LDX savex
|
|
LDY savey
|
|
TOGGLE4
|
|
PLA
|
|
DT RTS
|
|
|
|
;;; Scrolls the screen at the end
|
|
SCROLL
|
|
;------------------------------------------------------------------------------------------------------------
|
|
;
|
|
; HIRES is organized
|
|
; into three blocks, offset by 0x28 bytes each, starting at 2000
|
|
; each block holds 8 lines of text, offset by 0x80 bytes
|
|
; each line of text is split into 8 rows of pixels offset by 0x400 bytes
|
|
;
|
|
; this function starts at second from top row copy all pixels to row above it and continues down the screen
|
|
;
|
|
;------------------------------------------------------------------------------------------------------------
|
|
; first block -set up starting addresses
|
|
;
|
|
ldx #0 ;index into graphics table - starts at zero
|
|
; top loop - 24 lines of characters per page - copy bottom 23 lines (first line scrolls off top)
|
|
LDA #23
|
|
STA CNT2
|
|
|
|
;
|
|
; next line of text
|
|
;
|
|
scr1
|
|
LDA PG1ROWS,x ; target
|
|
STA TRGHIGH
|
|
inx
|
|
LDA PG1ROWS,x ; target
|
|
STA TRGLOW
|
|
inx
|
|
LDA PG1ROWS,x ; src
|
|
STA SRCHIGH
|
|
inx
|
|
LDA PG1ROWS,x ; scr
|
|
STA SRCLOW
|
|
DEX ;next pass target is current source
|
|
LDA #8
|
|
STA CNT3
|
|
JMP scr2.1
|
|
;
|
|
; adjust address to next line of pixels
|
|
;
|
|
scr2
|
|
|
|
LDA #$4
|
|
CLC
|
|
ADC SRCHIGH
|
|
STA SRCHIGH
|
|
LDA #$4
|
|
CLC
|
|
ADC TRGHIGH
|
|
STA TRGHIGH
|
|
scr2.1
|
|
LDY #39
|
|
;copy 40 characters that make up a line of pixels
|
|
scr3
|
|
LDA (SRCLOW),y
|
|
STA (TRGLOW),y
|
|
DEY
|
|
BPL scr3 ; repeat for 40 characters that make line of pixels
|
|
DEC CNT3
|
|
BNE scr2 ; done with this line of pixels =- goto to next liine of pixels
|
|
DEC CNT2
|
|
BNE scr1 ; done with this line of characters - goto next line of chars
|
|
|
|
JSR CLEAR_LINE
|
|
RTS
|
|
|
|
;
|
|
; clear line - X contains line #
|
|
;
|
|
CLEAR_LINE
|
|
LDA PG1ROWS,x ; target (was last source)
|
|
STA TRGHIGH
|
|
inx
|
|
LDA PG1ROWS,x ; target
|
|
STA TRGLOW
|
|
|
|
LDA #8
|
|
STA CNT3
|
|
JMP CL4.1
|
|
;
|
|
; adjust address to next line of pixels
|
|
;
|
|
CL4
|
|
LDA #$4
|
|
CLC
|
|
ADC TRGHIGH
|
|
STA TRGHIGH
|
|
CL4.1
|
|
LDY #39
|
|
lda #$0
|
|
;copy 40 characters that make up a line of pixels
|
|
CL5
|
|
STA (TRGLOW),y
|
|
DEY
|
|
BPL CL5 ; repeat for 40 characters that make line of pixels
|
|
DEC CNT3
|
|
BNE CL4 ; done with this line of pixels =- goto to next liine of pixels
|
|
RTS
|
|
|
|
|
|
;;; Initialize the graphics system, set cursor and clear the screen
|
|
INIT
|
|
;
|
|
; Initialize default keyboard in and video out routines
|
|
LDA #<PUTCH2 ;first video out
|
|
STA WRITVECTOR
|
|
LDA #>PUTCH2
|
|
STA WRITVECTOR+1
|
|
|
|
LDA #<A2GETCHAR2 ;now keyboard in
|
|
STA READVECTOR
|
|
LDA #>A2GETCHAR2
|
|
STA READVECTOR+1
|
|
|
|
LDA TURBO ;clear computer driven turbo mode
|
|
AND #TURBOUSR ;but save user turbo mode
|
|
STA TURBO
|
|
;
|
|
; reset could have occurred during video driver operations
|
|
; attempt to restore page 0 if possible
|
|
; there is a case where we were in the process of saving
|
|
; or restoring page zero variables when reset occurred
|
|
; we cannot recover from that case
|
|
;
|
|
JSR LODPG0 ;restore page zero variables
|
|
;
|
|
; determine whether we should emulate power up screen
|
|
;
|
|
LDA #SCRINIT
|
|
CMP POWERUPINIT ;have we initialized power up screen
|
|
BNE INITSCREEN ;no, let's do it
|
|
CMP SCRNCLRD ;has user cleared the screen?
|
|
BNE INITEXIT ;no, leave graphics mode alone
|
|
|
|
;
|
|
; clear screen already done - set HGR PG 2 mode
|
|
;
|
|
STA HIRES ; set high res pg 2 graphics mode
|
|
STA HRPG2 ; if this is power up, this will be changed below
|
|
STA TXTCLR
|
|
STA MIXCLR
|
|
INITEXIT
|
|
RTS
|
|
;
|
|
; initialize lowres page 1 as startup screen
|
|
;
|
|
|
|
INITSCREEN
|
|
LDA #$04 ;START ADDRESS
|
|
STA HEX2H
|
|
LDA #$0
|
|
STA HEX2L
|
|
|
|
LDA #$0B ;END ADDRESS
|
|
STA HEX1H
|
|
LDA #$F8
|
|
STA HEX1L
|
|
|
|
LDY #0
|
|
|
|
INIT1
|
|
LDA #$DF ; underbar
|
|
STA (HEX2L),y
|
|
JSR A2_INCADDR
|
|
BCS INIT2
|
|
LDA #$08 ; check address range <800 use at sign
|
|
BIT HEX2H ; >800 use space
|
|
BNE INIT1_1
|
|
LDA #$C0 ; at sign
|
|
BMI INIT1_2
|
|
INIT1_1
|
|
LDA #$A0 ; space
|
|
INIT1_2
|
|
STA (HEX2L),y ; save it
|
|
JSR A2_INCADDR
|
|
BCC INIT1
|
|
|
|
INIT2
|
|
|
|
LDA #0
|
|
STA SCRNCLRD ; now indicate that screen has been not cleared
|
|
STA CURROW
|
|
STA CURCOL
|
|
STA TURBO ; default not turbo mode
|
|
STA RDCONVERT ; default convert cassette reads
|
|
LDA #CNTSTRT
|
|
STA COUNTER1
|
|
|
|
STA LORES ; set lowres pg 1 graphics mode for start up screen
|
|
STA HRPG1 ; use page 1
|
|
STA TXTMOD
|
|
STA MIXCLR
|
|
|
|
LDA #SCRINIT
|
|
STA POWERUPINIT ; indicate power on init done
|
|
|
|
RTS
|
|
|
|
;;; Clears hires page 1
|
|
CLEAR
|
|
STY savey
|
|
STX savex
|
|
JSR SAVPG0
|
|
|
|
LDX #0
|
|
|
|
CLEAR2
|
|
JSR CLEAR_LINE
|
|
INX
|
|
CPX #48
|
|
BNE CLEAR2
|
|
;; page cleared
|
|
|
|
LDA #SCRINIT
|
|
STA SCRNCLRD ;indicate screen cleared
|
|
|
|
STA HIRES ; set high res pg 2 graphics mode
|
|
STA HRPG2
|
|
STA TXTCLR
|
|
STA MIXCLR
|
|
|
|
LDA #$00
|
|
;
|
|
; cursor to top left
|
|
;
|
|
STA CURROW
|
|
STA CURCOL
|
|
|
|
JSR LODPG0
|
|
LDY savey
|
|
LDX savex
|
|
RTS
|
|
|
|
;;; Prints character from A to the screen
|
|
PUTCH
|
|
JMP (WRITVECTOR) ;allow user override of default video out routine
|
|
PUTCH2:
|
|
PHA
|
|
STY savey
|
|
STX savex
|
|
|
|
LDY SCRNCLRD
|
|
BPL PUTCH_DROP ;if plus, screen has not been cleared, so drop
|
|
|
|
JSR SAVPG0
|
|
;; drop the high bit
|
|
AND #$7F
|
|
;; check for return
|
|
CMP #$0D
|
|
BEQ ENTERKY
|
|
;; it's a regular key
|
|
JSR GETCODE
|
|
STA CHAR
|
|
;; get the block address
|
|
LDX CURCOL
|
|
LDY CURROW
|
|
JSR GETBLOK
|
|
;; get block bytes
|
|
LDX CHAR
|
|
JSR GETCHB
|
|
;; render the char to the block
|
|
JSR DRAWCH
|
|
;; restore state and exit
|
|
PD JSR MVCSR
|
|
JSR LODPG0
|
|
|
|
PUTCH_DROP
|
|
LDY savey
|
|
LDX savex
|
|
PLA
|
|
RTS
|
|
|
|
ENTERKY ; print spaces until end of line (use turbo mode)
|
|
LDA TURBO
|
|
ORA #TURBOCMP ; set computer turbo mode
|
|
STA TURBO ; turbo mode to clear end of line
|
|
ENTERKY1
|
|
LDY CURROW
|
|
LDX CURCOL
|
|
CPX #40
|
|
BEQ ENTERKY_EXIT
|
|
JSR GETBLOK
|
|
LDX #0 ; space key
|
|
JSR GETCHB
|
|
JSR DRAWCH
|
|
INC CURCOL
|
|
JMP ENTERKY1
|
|
|
|
ENTERKY_EXIT
|
|
LDA TURBO
|
|
AND #TURBOUSR ; reset computer turbo mode, saving user mode
|
|
STA TURBO ;
|
|
JMP PD
|
|
|
|
;;; Draws character to block
|
|
DRAWCH LDX #0
|
|
L6 TXA
|
|
TAY
|
|
LDA (SRCLOW),Y
|
|
LDY #0
|
|
STA (TRGLOW),Y
|
|
INX
|
|
LDA TRGHIGH
|
|
CLC
|
|
ADC #$4
|
|
STA TRGHIGH
|
|
CPX #8
|
|
BMI L6
|
|
RTS
|
|
|
|
;;; Get byte for char in X
|
|
GETCHB LDY #<SPCODE
|
|
STY SRCLOW
|
|
LDY #>SPCODE
|
|
STY SRCHIGH
|
|
L5 CPX #0
|
|
BEQ D
|
|
DEX
|
|
LDA #8
|
|
CLC
|
|
ADC SRCLOW
|
|
STA SRCLOW
|
|
BCS AC
|
|
JMP L5
|
|
AC LDA #0
|
|
ADC SRCHIGH
|
|
STA SRCHIGH
|
|
JMP L5
|
|
D RTS
|
|
|
|
;;; Gets the block address at X,Y
|
|
GETBLOK TYA
|
|
JSR GETROW
|
|
;; add the column
|
|
TXA
|
|
CLC
|
|
ADC TRGLOW
|
|
STA TRGLOW
|
|
BCS A1
|
|
RTS
|
|
A1 LDA #0
|
|
ADC TRGHIGH
|
|
RTS
|
|
|
|
;;; Gets the row (A) address
|
|
GETROW ASL ; multiply row by two, there are two bytes per address
|
|
TAY
|
|
LDA PG1ROWS,Y
|
|
STA TRGHIGH
|
|
INY
|
|
LDA PG1ROWS,Y
|
|
STA TRGLOW
|
|
RTS
|
|
|
|
;;; Converts ASCII code to table index
|
|
GETCODE SEC
|
|
SBC #$20
|
|
BMI NC
|
|
CMP #$40
|
|
BPL NC
|
|
RTS
|
|
NC LDA #0
|
|
RTS
|
|
|
|
;;; Store page zero data
|
|
SAVPG0 PHA
|
|
STX TMP1
|
|
|
|
LDA #PG0SAVEFLG ;check saved flag
|
|
CMP PG0SAVD
|
|
BEQ SD ;already saved, just exit
|
|
|
|
LDX #0
|
|
L1 LDA $00,X
|
|
STA TMPG0,X
|
|
INX
|
|
CPX #$8
|
|
BNE L1
|
|
|
|
LDA #PG0SAVEFLG ;set save flag to saved after completely saved
|
|
STA PG0SAVD ;this way, if a reset comes in before we are done
|
|
;we will not corrupt zero page
|
|
;as the reset code restores zero page if flag set
|
|
|
|
SD LDX TMP1
|
|
PLA
|
|
RTS
|
|
|
|
;;; Restore page zero data
|
|
LODPG0
|
|
PHA
|
|
STX TMP1
|
|
|
|
LDA #PG0SAVEFLG ;checked saved flag
|
|
CMP PG0SAVD
|
|
BNE LD ;not saved, exit
|
|
|
|
LDX #0
|
|
L2 LDA TMPG0,X
|
|
STA $00,X
|
|
INX
|
|
CPX #$8
|
|
BNE L2
|
|
|
|
LDA #<(~PG0SAVEFLG) ;clear saved flag to not saved after completely restored
|
|
;this way, if a reset comes in before we are done
|
|
STA PG0SAVD ;as the reset code restores zero page if flag set
|
|
|
|
LD LDX TMP1
|
|
PLA
|
|
RTS
|
|
|
|
|
|
;;; tables
|
|
PG1ROWS HEX 4000 4080 4100 4180 4200 4280 4300 4380 4028 40A8 4128 41A8 4228 42A8 4328 43A8 4050 40D0 4150 41D0 4250 42D0 4350 43D0
|
|
SPCODE HEX 00 00 00 00 00 00 00 00
|
|
EXPCODE HEX 00 08 08 08 08 08 00 08
|
|
QUOCODE HEX 00 14 14 14 00 00 00 00
|
|
NUMCODE HEX 00 14 14 3e 14 3e 14 14
|
|
STRCODE HEX 00 08 3c 0a 1c 28 1e 08
|
|
PERCODE HEX 00 06 26 10 08 04 32 30
|
|
AMPCODE HEX 00 04 0a 0a 04 2a 12 2c
|
|
SQCODE HEX 00 08 08 08 00 00 00 00
|
|
RPCODE HEX 00 08 04 02 02 02 04 08
|
|
LPCODE HEX 00 08 10 20 20 20 10 08
|
|
STACODE HEX 00 08 2a 1c 08 1c 2a 08
|
|
PLSCODE HEX 00 00 08 08 3e 08 08 00
|
|
CMACODE HEX 00 00 00 00 00 08 08 04
|
|
MINCODE HEX 00 00 00 00 3e 00 00 00
|
|
DOTCODE HEX 00 00 00 00 00 00 00 08
|
|
FSCODE HEX 00 00 20 10 08 04 02 00
|
|
0CODE HEX 00 1c 22 32 2a 26 22 1c
|
|
1CODE HEX 00 08 0c 08 08 08 08 1c
|
|
2CODE HEX 00 1c 22 20 18 04 02 3e
|
|
3CODE HEX 00 3e 20 10 18 20 22 1c
|
|
4CODE HEX 00 10 18 14 12 3e 10 10
|
|
5CODE HEX 00 3e 02 1e 20 20 22 1c
|
|
6CODE HEX 00 38 04 02 1e 22 22 1c
|
|
7CODE HEX 00 3e 20 10 08 04 04 04
|
|
8CODE HEX 00 1c 22 22 1c 22 22 1c
|
|
9CODE HEX 00 1c 22 22 3c 20 10 0e
|
|
COLCODE HEX 00 00 00 08 00 08 00 00
|
|
SEMCODE HEX 00 00 00 08 00 08 08 04
|
|
LTCODE HEX 00 10 08 04 02 04 08 10
|
|
EQCODE HEX 00 00 00 3e 00 3e 00 00
|
|
GTCODE HEX 00 04 08 10 20 10 08 04
|
|
QESCODE HEX 00 1c 22 10 08 08 00 08
|
|
ATCODE HEX 00 1C 22 2A 3A 1A 02 3C
|
|
ACODE HEX 00 08 14 22 22 3e 22 22
|
|
BCODE HEX 00 1e 22 22 1e 22 22 1e
|
|
CCODE HEX 00 1c 22 02 02 02 22 1c
|
|
DCODE HEX 00 1e 22 22 22 22 22 1e
|
|
ECODE HEX 00 3e 02 02 1e 02 02 3e
|
|
FCODE HEX 00 3e 02 02 1e 02 02 02
|
|
GCODE HEX 00 3c 02 02 02 32 22 3c
|
|
HCODE HEX 00 22 22 22 3e 22 22 22
|
|
ICODE HEX 00 1c 08 08 08 08 08 1c
|
|
JCODE HEX 00 20 20 20 20 20 22 1c
|
|
KCODE HEX 00 22 12 0a 06 0a 12 22
|
|
LCODE HEX 00 02 02 02 02 02 02 3e
|
|
MCODE HEX 00 22 36 2a 2a 22 22 22
|
|
NCODE HEX 00 22 22 26 2a 32 22 22
|
|
OCODE HEX 00 1c 22 22 22 22 22 1c
|
|
PCODE HEX 00 1e 22 22 1e 02 02 02
|
|
QCODE HEX 00 1c 22 22 22 2a 12 2c
|
|
RCODE HEX 00 1e 22 22 1e 0a 12 22
|
|
SCODE HEX 00 1c 22 02 1c 20 22 1c
|
|
TCODE HEX 00 3e 08 08 08 08 08 08
|
|
UCODE HEX 00 22 22 22 22 22 22 1c
|
|
VCODE HEX 00 22 22 22 22 22 14 08
|
|
WCODE HEX 00 22 22 22 2a 2a 36 22
|
|
XCODE HEX 00 22 22 14 08 14 22 22
|
|
YCODE HEX 00 22 22 14 08 08 08 08
|
|
ZCODE HEX 00 3e 20 10 08 04 02 3e
|
|
LBCODE HEX 00 3e 06 06 06 06 06 3e
|
|
BSCODE HEX 00 00 02 04 08 10 20 00
|
|
RBCODE HEX 00 3e 30 30 30 30 30 3e
|
|
CRTCODE HEX 00 00 00 08 14 22 00 00
|
|
UNDCODE HEX 00 00 00 00 00 00 00 3e
|
|
|
|
|
|
|
|
;------------------------------------------------------------------------
|
|
; BASIC SUPPORT FUNCTIONs
|
|
; peek and poke of the PIA is emulated
|
|
; using A2 hardware drivers
|
|
;------------------------------------------------------------------------
|
|
;------------------------------------------------------------------------
|
|
; POKE of D012 is emulated by calling
|
|
; A2 putchar routine
|
|
;------------------------------------------------------------------------
|
|
ACC EQU $ce ; must be same as basic "acc"
|
|
A2POKE
|
|
JSR getbyte
|
|
LDA ACC
|
|
PHA
|
|
JSR get16bit
|
|
LDA #$D0
|
|
CMP ACC+1
|
|
BEQ A2POKE2
|
|
A2POKE1
|
|
PLA
|
|
STA (ACC),Y
|
|
RTS
|
|
A2POKE2
|
|
LDA #$12
|
|
CMP ACC
|
|
BNE A2POKE1
|
|
;------------------------------------------------------------------------
|
|
; Poke D012 == A2 ECHO CALL
|
|
;------------------------------------------------------------------------
|
|
PLA
|
|
JMP ECHO
|
|
|
|
;------------------------------------------------------------------------
|
|
; PEEK of D012, D011 and D010 is emulated by using
|
|
; equivalent A2 functionality
|
|
;------------------------------------------------------------------------
|
|
|
|
A2PEEK
|
|
JSR get16bit
|
|
LDA #$D0
|
|
CMP ACC+1
|
|
BEQ A2PEEK3
|
|
A2PEEK1
|
|
LDA (ACC),Y
|
|
A2PEEK2
|
|
STY syn_stk_l+31,X
|
|
JMP push_ya_noun_stk
|
|
|
|
;------------------------------------------------------------------------
|
|
; Peek D012 == determine if terminal is ready for output
|
|
; in the A2 memory mapped video driver case - the answer
|
|
; is always yes -so return positive number(or zero in this case)
|
|
;------------------------------------------------------------------------
|
|
A2PEEK3
|
|
LDA #$12
|
|
CMP ACC
|
|
BNE A2PEEK4
|
|
LDA #$00
|
|
JMP A2PEEK2
|
|
;------------------------------------------------------------------------
|
|
; Peek D011 == A2 read c000 (does keyboard have char, yes if MSB set)
|
|
;------------------------------------------------------------------------
|
|
A2PEEK4
|
|
LDA #$11
|
|
CMP ACC
|
|
BNE A2PEEK5
|
|
LDA KBD
|
|
JMP A2PEEK2
|
|
;------------------------------------------------------------------------
|
|
; Peek D010 == A2 getchar (also clears strobe)
|
|
;------------------------------------------------------------------------
|
|
A2PEEK5
|
|
LDA #$10
|
|
CMP ACC
|
|
BNE A2PEEK1
|
|
LDA KBD
|
|
STA KBDCR
|
|
JMP A2PEEK2
|
|
|
|
IFCONST BLD4RAM
|
|
STORAGE
|
|
ENDIF
|
|
ENDIF ; end of A2 driver code
|
|
;------------------------------------------------------------------------
|
|
; VERSION
|
|
;------------------------------------------------------------------------
|
|
IFCONST BLD4RAM
|
|
ORG $6FFE
|
|
ELSE
|
|
ORG $DFFE
|
|
ENDIF
|
|
DC.w $0105
|
|
|
|
;------------------------------------------------------------------------
|
|
; BASIC
|
|
;------------------------------------------------------------------------
|
|
INCLUDE a1basic-universal.asm
|
|
|
|
;-------------------------------------------------------------------------
|
|
;
|
|
; The WOZ Monitor for the Apple 1
|
|
; Written by Steve Wozniak 1976
|
|
;
|
|
;-------------------------------------------------------------------------
|
|
|
|
|
|
IFNCONST BLD4RAM
|
|
ORG $FF00
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Memory declaration
|
|
;-------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
XAML EQU $24 ;Last "opened" location Low
|
|
XAMH EQU $25 ;Last "opened" location High
|
|
STL EQU $26 ;Store address Low
|
|
STH EQU $27 ;Store address High
|
|
L EQU $28 ;Hex value parsing Low
|
|
H EQU $29 ;Hex value parsing High
|
|
YSAV EQU $2A ;Used to see if hex value is given
|
|
MODE EQU $2B ;$00=XAM, $7F=STOR, $AE=BLOCK XAM
|
|
|
|
IN EQU $0200 ;Input buffer
|
|
|
|
IFCONST BLD4APPLE1
|
|
MONDSP EQU $D012 ;PIA.B display output register
|
|
MONDSPCR EQU $D013 ;PIA.B display control register
|
|
ENDIF
|
|
|
|
; KBD b7..b0 are inputs, b6..b0 is ASCII input, b7 is constant high
|
|
; Programmed to respond to low to high KBD strobe
|
|
; DSP b6..b0 are outputs, b7 is input
|
|
; CB2 goes low when data is written, returns high when CB1 goes high
|
|
; Interrupts are enabled, though not used. KBD can be jumpered to IRQ,
|
|
; whereas DSP can be jumpered to NMI.
|
|
|
|
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Let's get started
|
|
;
|
|
; Remark the RESET routine is only to be entered by asserting the RESET
|
|
; line of the system. This ensures that the data direction registers
|
|
; are selected.
|
|
;-------------------------------------------------------------------------
|
|
|
|
RESET CLD ;Clear decimal arithmetic mode
|
|
CLI
|
|
IFNCONST BLD4APPLE1
|
|
JSR INIT ;init display driver
|
|
ENDIF
|
|
LDY #$7f ;Mask for DSP data direction reg
|
|
IFCONST BLD4APPLE1
|
|
STY MONDSP ; (DDR mode is assumed after reset)
|
|
ENDIF
|
|
LDA #$a7 ;KBD and DSP control register mask
|
|
IFCONST BLD4APPLE1
|
|
STA KBDCR ;Enable interrupts, set CA1, CB1 for
|
|
STA MONDSPCR ; positive edge sense/output mode.
|
|
ELSE
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
ENDIF
|
|
|
|
; Program falls through to the GETLINE routine to save some program bytes
|
|
; Please note that Y still holds $7F, which will cause an automatic Escape
|
|
|
|
;-------------------------------------------------------------------------
|
|
; The GETLINE process
|
|
;-------------------------------------------------------------------------
|
|
|
|
NOTCR CMP #BS ;Backspace key?
|
|
BEQ BACKSPACE ;Yes
|
|
CMP #ESC ;ESC?
|
|
BEQ ESCAPE ;Yes
|
|
INY ;Advance text index
|
|
BPL NEXTCHAR ;Auto ESC if line longer than 127
|
|
|
|
ESCAPE LDA #PROMPT ;Print prompt character
|
|
JSR ECHO ;Output it.
|
|
|
|
GETLINE LDA #CR ;Send CR
|
|
JSR ECHO
|
|
|
|
LDY #0+1 ;Start a new input line
|
|
BACKSPACE DEY ;Backup text index
|
|
BMI GETLINE ;Oops, line's empty, reinitialize
|
|
|
|
NEXTCHAR
|
|
IFCONST BLD4APPLE1
|
|
LDA KBDCR ;Wait for key press
|
|
BPL NEXTCHAR ;No key yet!
|
|
LDA KBD ;Clear strobe
|
|
ELSE
|
|
JSR A2GETCHAR
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
ENDIF
|
|
STA IN,Y ;Add to text buffer
|
|
JSR ECHO ;Display character
|
|
CMP #CR
|
|
BNE NOTCR ;It's not CR!
|
|
|
|
; Line received, now let's parse it
|
|
|
|
LDY #-1 ;Reset text index
|
|
LDA #0 ;Default mode is XAM
|
|
TAX ;X=0
|
|
|
|
SETSTOR ASL ;Leaves $7B if setting STOR mode
|
|
|
|
SETMODE STA MODE ;Set mode flags
|
|
|
|
BLSKIP INY ;Advance text index
|
|
|
|
NEXTITEM LDA IN,Y ;Get character
|
|
CMP #CR
|
|
BEQ GETLINE ;We're done if it's CR!
|
|
CMP #$AE ;"."
|
|
BCC BLSKIP ;Ignore everything below "."!
|
|
BEQ SETMODE ;Set BLOCK XAM mode ("." = $AE)
|
|
CMP #$BA ;":"
|
|
BEQ SETSTOR ;Set STOR mode! $BA will become $7B
|
|
CMP #$d2 ;"R"
|
|
BEQ RUN ;Run the program! Forget the rest
|
|
STX L ;Clear input value (X=0)
|
|
STX H
|
|
STY YSAV ;Save Y for comparison
|
|
|
|
; Here we're trying to parse a new hex value
|
|
|
|
NEXTHEX LDA IN,Y ;Get character for hex test
|
|
EOR #$B0 ;Map digits to 0-9
|
|
CMP #9+1 ;Is it a decimal digit?
|
|
BCC DIG ;Yes!
|
|
ADC #$88 ;Map letter "A"-"F" to $FA-FF
|
|
CMP #$FA ;Hex letter?
|
|
BCC NOTHEX ;No! Character not hex
|
|
|
|
DIG ASL
|
|
ASL ;Hex digit to MSD of A
|
|
ASL
|
|
ASL
|
|
|
|
LDX #4 ;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
|
|
|
|
NOTHEX CPY YSAV ;Was at least 1 hex digit given?
|
|
BEQ ESCAPE ;No! Ignore all, start from scratch
|
|
|
|
BIT MODE ;Test MODE byte
|
|
BVC NOTSTOR ;B6=0 is STOR, 1 is XAM or BLOCK XAM
|
|
|
|
; STOR mode, save LSD of new hex byte
|
|
|
|
LDA L ;LSD's of hex data
|
|
STA (STL,X) ;Store current 'store index'(X=0)
|
|
INC STL ;Increment store index.
|
|
BNE NEXTITEM ;No carry!
|
|
INC STH ;Add carry to 'store index' high
|
|
TONEXTITEM JMP NEXTITEM ;Get next command item.
|
|
|
|
;-------------------------------------------------------------------------
|
|
; RUN user's program from last opened location
|
|
;-------------------------------------------------------------------------
|
|
|
|
RUN JMP (XAML) ;Run user's program
|
|
|
|
;-------------------------------------------------------------------------
|
|
; We're not in Store mode
|
|
;-------------------------------------------------------------------------
|
|
|
|
NOTSTOR BMI XAMNEXT ;B7 = 0 for XAM, 1 for BLOCK XAM
|
|
|
|
; We're in XAM mode now
|
|
|
|
LDX #2 ;Copy 2 bytes
|
|
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
|
|
|
|
; Print address and data from this address, fall through next BNE.
|
|
|
|
NXTPRNT BNE PRDATA ;NE means no address to print
|
|
LDA #CR ;Print CR first
|
|
JSR ECHO
|
|
LDA XAMH ;Output high-order byte of address
|
|
JSR PRBYTE
|
|
LDA XAML ;Output low-order byte of address
|
|
JSR PRBYTE
|
|
LDA #":" ;Print colon
|
|
JSR ECHO
|
|
|
|
PRDATA LDA #" " ;Print space
|
|
JSR ECHO
|
|
LDA (XAML,X) ;Get data from address (X=0)
|
|
JSR PRBYTE ;Output it in hex format
|
|
XAMNEXT STX MODE ;0 -> MODE (XAM mode).
|
|
LDA XAML ;See if there's more to print
|
|
CMP L
|
|
LDA XAMH
|
|
SBC H
|
|
BCS TONEXTITEM ;Not less! No more data to output
|
|
|
|
INC XAML ;Increment 'examine index'
|
|
BNE MOD8CHK ;No carry!
|
|
INC XAMH
|
|
|
|
MOD8CHK LDA XAML ;If address MOD 8 = 0 start new line
|
|
AND #$07
|
|
BPL NXTPRNT ;Always taken.
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Subroutine to print a byte in A in hex form (destructive)
|
|
;-------------------------------------------------------------------------
|
|
|
|
PRBYTE PHA ;Save A for LSD
|
|
LSR
|
|
LSR
|
|
LSR ;MSD to LSD position
|
|
LSR
|
|
JSR PRHEX ;Output hex digit
|
|
PLA ;Restore A
|
|
|
|
; Fall through to print hex routine
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Subroutine to print a hexadecimal digit
|
|
;-------------------------------------------------------------------------
|
|
|
|
PRHEX AND #$0F ;Mask LSD for hex print
|
|
ORA #"0" ;Add "0"
|
|
CMP #"9"+1 ;Is it a decimal digit?
|
|
BCC ECHO ;Yes! output it
|
|
ADC #6 ;Add offset for letter A-F
|
|
|
|
; Fall through to print routine
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Subroutine to print a character to the terminal
|
|
;-------------------------------------------------------------------------
|
|
ECHO
|
|
IFCONST BLD4APPLE1
|
|
BIT MONDSP ;DA bit (B7) cleared yet?
|
|
BMI ECHO ;No! Wait for display ready
|
|
STA MONDSP ;Output character. Sets DA
|
|
RTS
|
|
ELSE
|
|
CMP #$20
|
|
BMI ECHO1
|
|
ORA #$80
|
|
ECHO1
|
|
JMP PUTCH ; use hi-res screen
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Vector area
|
|
;-------------------------------------------------------------------------
|
|
IFNCONST BLD4RAM
|
|
ORG $fff8
|
|
DC.W $0000 ;Unused, what a pity
|
|
NMI_VEC DC.W $0F00 ;NMI vector
|
|
RESET_VEC DC.W RESET ;RESET vector
|
|
IRQ_VEC DC.W $0000 ;IRQ vector
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------
|
|
|
|
|