a2a1emulv5_1.asm
Alex-Kw_Brain-Board-II/Source and Serial Driver/a2a1emulv5_1/a2a1emulv5_1.asm
	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

;-------------------------------------------------------------------------


