	PROCESSOR 6502
	LIST	ON
;-------------------------------------------------------------------------
; Defines - this code can be built one of four ways
;	1. to run in RAM
;	2. to run out of Hobbycard EEPROM
;
;	select one of these three options
;-------------------------------------------------------------------------

;-------------------------------------------------------------------------
;  Constants
;-------------------------------------------------------------------------

BS              EQU     $DF             ;Backspace key, arrow left key
CR              EQU     $8D             ;Carriage Return
ESC             EQU     $9B             ;ESC key
PROMPT          EQU     "\"             ;Prompt character

;-------------------------------------------------------------------------
;  MONITOR FUNCTIONS
;-------------------------------------------------------------------------

COUT            EQU     $FDED           ;Backspace key, arrow left key
IOSAVE		EQU	$FF4A		;Save all registers
IOREST		EQU	$FF3F		;Restore all registers
HOME		EQU	$FC58		;Clear Screen
MOVE		EQU	$FE2C		;Move memory
MON		EQU	$FF65		;Monitor entry point
SETKBD		EQU	$FE89		;IN#0 sets default input vector
SETVID		EQU	$FE93		;PR#0 sets default output vector
WAIT		EQU	$FCA8		;wait function
PRBYTE		EQU	$FDDA		;print hex byte
NXTA4		EQU	$FCB4		;inc A4 and A1 until A1 = A2


;-------------------------------------------------------------------------
;  I/O FUNCTIONS
;-------------------------------------------------------------------------
KEYBOARD	EQU	$C000		;keyboard data
KEYSTROBE	EQU	$C010		;clears keyboard data

;-------------------------------------------------------------------------
;  6522A FUNCTIONS
;-------------------------------------------------------------------------
TMR2L	EQU	$c088			;timer2 low byte
					; write: load LS byte
					;
					; read: to read low counter and clear interrupt
TMR2H	EQU	$c089			;timer2 high byte
					; wrt: high byte, transfer high and low to counter & enable int
					; rd: read high counter
					; 
ACR	EQU	$c08B			;aux control register
					;bit 5 = 0 timer 2 one shot mode
					;bit5 = 1 timer 2 count pulses output on PB 6
					;
IFR	EQU	$c08C			;interrupt flag register
					; read: bit 7 state of IRQ, bit 5 timer 2 interrupt pending
					; write: set bit to clear interrupt
					;
IER	EQU	$c08E			;interrupt enable register
					;bit 7 = 1 to set
					;bit 7 = 0 to clear
					;bit 5 = timer 2

;-------------------------------------------------------------------------
;  Memory declaration
;-------------------------------------------------------------------------

WINDOWTOP	EQU	$22		;top edge of window

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


;unused by monitor or applesoft
; address setup for move command
AD1L		EQU	$1a
AD1H		EQU	$1b
AD2L		EQU	$1c
AD2H		EQU	$1d
AD4L		EQU	$1e
AD4H		EQU	$1f
;address holding locations for monitor move command
A1L		EQU	$3c
A1H		EQU	$3d
A2L		EQU	$3e
A2H		EQU	$3f
A4L		EQU	$42
A4H		EQU	$43

IN              EQU     $0200	     	    ;Input buffer

WORKING		EQU	$0800		;Working Memory

FLIP            EQU     $C020           ;Output flip-flop
TAPEIN          EQU     $C060           ;Tape input
KBD             EQU     $C000           ;keyboard input
KBDCR           EQU     $C010           ;keybaord strobe clear


;---------------------------------------------------------------------------
; build in ACI Driver
;---------------------------------------------------------------------------
;BLD4RAM EQU 0
		IFCONST	BLD4RAM 
                	ORG $800	; build for memory
		ELSE
			ORG $c700	; plug in hobbyboard
		ENDIF



START:
	BIT $20		; pretend this is Disk 2, so autostart will run it automatically
	BIT $00
	BIT $03
	BIT $3C
;------------------------------------------------------------------------
; make sure no other card has 2K block selected
;--------------------------------------------------------------------------
	LDA	$CFFF			; 

;------------------------------------------------------------------------
; now figure out our slot
;--------------------------------------------------------------------------
	JSR 	IOSAVE			; save registers
	SEI				; block interrupts
	JSR	$FF58			; move current PC to stack
	TSX
	IFCONST	BLD4RAM 
        LDA	#$01			; build for memory
	ELSE
	LDA	$0100,X			; fetch high address
	ENDIF
	STA	$07F8			; save currently active card
	AND	#$07			; mask off $CX to get slot #
	TAY
	ASL
	ASL
	ASL
	ASL	
	TAX				; can be used to access 6522 VIA at C0SX
	STA	$478,y			;save in scratchpad register
	LDA	#0			;initialize pass count
	STA	$4f8,y			;save in scratchpad register
	STA	$6f8,y			;save interrupt count
;
; restore normal COUT and CIN
;
	JSR	SETKBD
	JSR	SETVID				

	JSR	HOME			;clear screen

;
; print banner
;
	LDA	#>BANNER
	STA	A1H
	LDA	#<BANNER
	STA	A1L
	JSR	PRINTSTRING

	LDA	#1			; prevents banner from being scrolled off top
	STA	WINDOWTOP
		
	LDA	#>TESTSTART
	STA	A1H
	LDA	#<TESTSTART
	STA	A1L
	JSR	PRINTSTRING
;
; initialize 6522A ports
; 	port A - output -  8 bit SRAM address bus
PORTA		EQU	$C081		; PORT A
PORTADIR	EQU     $C083		; PORT A direction
;
PORTB		EQU	$C080		; PORT B
PORTBDIR	EQU     $C082	  	; PORT B direction
;
;	port B - output - bit's 0 and 1 = address bits 8 and 9
PORTB_A8A9	EQU	$03

;	port B - output - bit 4 = low read - high write
PORTB_RW	EQU	$10

;	port B - output - bit 5 = chip select
PORTB_CS	EQU	$20

;	port B - output - bit 6 = SRAM write data (in) bit
PORTB_WD	EQU	$40

;	port B - input - bit 7 = SRAM data out
PORTB_RD	EQU	$80


	LDA	$07F8			; fetch currently active card
	AND	#$07			; mask off $CX to get slot #
	ASL
	ASL
	ASL
	ASL	
	TAX				; can be used to access 6522 VIA at C0SX

;set up address
	LDA	#$0
	STA	PORTA,X			; start with address "0"
	LDA	#$FF
	STA	PORTADIR,X		; set port A for output  (address)
; set up control
	LDA	#PORTB_CS | PORTB_RW	; dessert Chip select and put in read mode 
	STA	PORTB,X			; write data 0
					; 
	LDA	#PORTB_CS | PORTB_RW | PORTB_WD | PORTB_A8A9
	STA	PORTBDIR,X		; set port B direction

STRTTEST:
	JSR	SRAMTEST
	BCS	BADBIT			; error

	LDA	KEYBOARD		; check to see if keyboard input (stops test)
	BMI	TESTEXIT		; yes clear strobe, print finished and back to monitor

;
; finished pass, increment count and print banner
;

	LDA	#>PASSED
	STA	A1H
	LDA	#<PASSED
	STA	A1L
	JSR	PRINTSTRING
	LDA	$07F8			; save currently active card
	AND	#$07			; mask off $CX to get slot #
	TAY
	LDA	$4F8,Y			;fetch pass count
	TAX
	INX				;increment count
	TXA
	STA	$4f8,Y			;save count
	JSR	PRBYTE			;print hex number

	LDA	#$8d
	JSR	COUT			;newline
	SEC
	BCS	STRTTEST

BADBIT:
	PHA
	LDA	#>ERRORRED
	STA	A1H
	LDA	#<ERRORRED
	STA	A1L
	JSR	PRINTSTRING

	PLA
	JSR	PRBYTE			;print hex number

	SEC
	BCS	RETURNMON

TESTEXIT:
	LDA	KEYSTROBE		;clear keyboard strobe

	LDA	#>ABORTED
	STA	A1H
	LDA	#<ABORTED
	STA	A1L
	JSR	PRINTSTRING
;
; return to monitor
;
RETURNMON:
	LDA	#0			; reset window top
	STA	WINDOWTOP

	JMP	MON



	IFCONST	BLD4RAM 
        	ORG $0900	; build for memory
	ELSE
		ORG $C800	; plug in hobbyboard:w
	ENDIF
	;
;  MOVE from A1 to A4 - until A1 = ending address in A2
;
MOV:
	LDY	#0	; index = 0
	LDA	AD1L
	STA	A1L
	LDA	AD1H
	STA	A1H

	LDA	AD2L
	STA	A2L
	LDA	AD2H
	STA	A2H

	LDA	AD4L
	STA	A4L
	LDA	AD4H
	STA	A4H
MOV2:
	LDA   (A1L),Y    ; MOVE A1[0x3C] TO A2[0x3E] TO
	STA   (A4L),Y    ; A4[0x42]
MOVEWAIT:
	CMP	(A4L),Y		; for eeprom - wait till write takes
	BNE	MOVEWAIT	; MSB not correct until write is done
	JSR   NXTA4
	BCC   MOV2
	RTS

GOTOBRKTEST:
	JMP BRKTEST

	
SRAMTEST:
	LDA	$07F8			; fetch currently active card
	AND	#$07			; mask off $CX to get slot #
	ASL
	ASL
	ASL
	ASL	
	TAX				; can be used to access 6522 VIA at C0SX
;
; write zeros
;
	LDY	#0			; low address bits
	STY	AD1H			; save high address bits
WRITENEXT0BIT:
	CLC
	JSR	WRITEBIT
	INY
	BNE	WRITENEXT0BIT
;
; 256 bits checked, wrap to next page
;
	INC	AD1H
	LDA	#$04			; check for all 1K checked
	BIT 	AD1H
	BEQ	WRITENEXT0BIT		; no, continue
;
; read all locations looking for zero
;
	STY	AD1H			; reset high address bits
READNEXT0BIT:
	CLC
	JSR	READBIT
	BCS	GOTOBRKTEST
	INY
	BNE	READNEXT0BIT
;
; 256 bits checked, wrap to next page
;
	INC	AD1H
	LDA	#$04			; check for all 1K checked
	BIT 	AD1H
	BEQ	READNEXT0BIT		; no, continue
;
; write all ones
;
	STY	AD1H			; reset high address bits
WRITENEXT1BIT:
	SEC
	JSR	WRITEBIT
	INY
	BNE	WRITENEXT1BIT
;
; 256 bits checked, wrap to next page
;
	INC	AD1H
	LDA	#$04			; check for all 1K checked
	BIT 	AD1H
	BEQ	WRITENEXT1BIT		; no, continue

;
; read all locations looking for ones
;
	STY	AD1H			; reset high address bits
READNEXT1BIT:
	SEC
	JSR	READBIT
	BCS	GOTOBRKTEST
	INY
	BNE	READNEXT1BIT
;
; 256 bits checked, wrap to next page
;
	INC	AD1H
	LDA	#$04			; check for all 1K checked
	BIT 	AD1H
	BEQ	READNEXT1BIT		; no, continue


;
; write and verify floating ones
;
;
; first write all zeros
;
	STY	AD1H			; reset high address bits
WRITENEXT0S:
	CLC
	JSR	WRITEBIT
	INY
	BNE	WRITENEXT0S
;
; 256 bits checked, wrap to next page
;
	INC	AD1H
	LDA	#$04			; check for all 1K checked
	BIT 	AD1H
	BEQ	WRITENEXT0S		; no, continue

	STY	AD2L			; start with bit zero
	STY	AD2H			; start with page zero
;
; now loop - writing single bit into each location and checking that only that one bit is set
;
READNEXTFLOAT1BITINCBIT:

	LDY	AD2L			; address of floating bit
	LDA	AD2H			; page #
	STA	AD1H			; set up high two bits of address (page)
	SEC
	JSR	WRITEBIT		; set single bit at location Y
;
; read all locations looking for zero - except location of interest
;
	LDY	#0
	STY	AD1H			; starting page 0
READNEXTFLOAT1BIT:
; is this the bit that should be 1
	CPY	AD2L			;current bit in page?
	BNE	READNEXTFLOAT1BITZERO	;nope, we should read zero
	LDA	AD2H
	CMP	AD1H			; correct page?
	BNE	READNEXTFLOAT1BITZERO	;nope, we should read zero

; found the bit
	SEC				; expect to see the floating one
	BCS	READNEXTFLOAT1BITONE
READNEXTFLOAT1BITZERO:
	CLC
READNEXTFLOAT1BITONE:
	JSR	READBIT
	BCS	BRKTEST
	INY
	BNE	READNEXTFLOAT1BIT
;
; 256 bits checked, wrap to next page
;
	INC	AD1H
	LDA	#$04			; check for all 1K checked
	BIT 	AD1H
	BEQ	READNEXTFLOAT1BIT	; no, continue
;
; done checking bit, now advance to next bit
;
	LDA	AD2H
	STA	AD1H			; set page
	LDY	AD2L
	CLC
	JSR	WRITEBIT		; clear previous single bit at location Y

	INC	AD2L
	BNE	READNEXTFLOAT1BITINCBIT
	INC	AD2H
	LDA	#$04			; check for all 1K checked
	BIT 	AD2H
	BEQ	READNEXTFLOAT1BITINCBIT	; no, continue



;
; write and verify floating zeros
;
;
; first write all ones
;
	LDY	#0
	STY	AD1H	; reset high address bits
WRITENEXT1S:
	SEC
	JSR	WRITEBIT
	INY
	BNE	WRITENEXT1S
;
; 256 bits written, wrap to next page
;
	INC	AD1H
	LDA	#$04			; check for all 1K checked
	BIT 	AD1H
	BEQ	WRITENEXT1S		; no, continue

	STY	AD2L			; start with bit zero
	STY	AD2H			; start with page zero		

;
; now loop - writing single bit into each location and checking that only that one bit is clear
;
READNEXTFLOAT0BITINCBIT:
	LDY	AD2L			; address of floating bit
	LDA	AD2H			; page #
	STA	AD1H			; set up high two bits of address (page)
	CLC
	JSR	WRITEBIT		; clear single bit at location Y
;
; read all locations looking for zero - except location of interest
;
	LDY	#0
	STY	AD1H			; starting page 0
READNEXTFLOAT0BIT:
; is this the bit that should be 0
	CPY	AD2L			;current bit?
	BNE	READNEXTFLOAT0BITONE	;nope, we should read one
	LDA	AD2H
	CMP	AD1H			; correct page?
	BNE	READNEXTFLOAT0BITONE	;nope, we should read one

	CLC				; expect to see the floating zero
	BCC	READNEXTFLOAT0BITZERO
READNEXTFLOAT0BITONE:
	SEC
READNEXTFLOAT0BITZERO:
	JSR	READBIT
	BCS	BRKTEST
	INY
	BNE	READNEXTFLOAT0BIT
;
; 256 bits checked, wrap to next page
;
	INC	AD1H
	LDA	#$04			; check for all 1K checked
	BIT 	AD1H
	BEQ	READNEXTFLOAT0BIT	; no, continue

;
; done checking bit, now advance to next bit
;
	LDA	AD2H
	STA	AD1H			; set page
	LDY	AD2L
	SEC
	JSR	WRITEBIT		; set previous single bit at location Y

	INC	AD2L
	BNE	READNEXTFLOAT0BITINCBIT

	INC	AD2H
	LDA	#$04			; check for all 1K checked
	BIT 	AD2H
	BEQ	READNEXTFLOAT0BITINCBIT	; no, continue

	CLC
BRKTEST:
	TYA
	RTS

;
; A = address, Carry set for 1, Carry not set for zero
;
WRITEBIT:
	TYA
	STA	PORTA,X			; set address (low 8 bits)

	LDA	AD1H			; fetch high address bits
	ORA	#PORTB_CS		; write (yes), CS (not yet) - default data=0
	BCC	WRITEBIT0		; input c is 0, then skip 0 set

	ORA	#PORTB_WD		; carry in means data = 1

WRITEBIT0:
	STA	PORTB,X			; set to write with appropriate data bit

	AND	#<~PORTB_CS
	STA	PORTB,X			; add CS - starts write

	ORA	#PORTB_CS		
	STA	PORTB,X			; remove CS - ends write

	ORA	#PORTB_RW		
	STA	PORTB,X			; remove write

	RTS
;
; input: A = address, carry set if expect a 1, otherwise a 0
; output: carry set if error
;
READBIT:
	TYA
	STA	PORTA,X			; set low 8 bits of address

	LDA	AD1H			; fetch high address bits
	ORA	#PORTB_CS | PORTB_RW	; or in READ - do not assert CS yet
	STA	PORTB,X			; set read and address

	AND	#<~PORTB_CS
	STA	PORTB,X			; assert CS - starts read

	
	LDA	PORTB,X			; read data (bit7)

	BCC	READBIT0		; carry coming in is clear, expect 0 bit
	BMI	READBITNOERR		; 1 expected, N is set - no error

READBITERR:
	IFCONST	BLD4RAM 	
	CLC				; test code running in RAM - always pass
	BCC	READBITDONE		; always branch
	ELSE
	SEC				; error indication
	BCS	READBITDONE		; always branch
	ENDIF

READBIT0:				; 
	BMI	READBITERR		; should be 0, was 1 - then error

READBITNOERR:
	CLC				;equal - no error

READBITDONE:
	LDA	AD1H			; fetch high address bits
	ORA	#PORTB_CS | PORTB_RW	; dessert Chip select and leave in read mode
	STA	PORTB,X			; 

	RTS



PRINTSTRING:
	LDY	#0
PS1:
	LDA	(A1L),Y
	BEQ	PSDONE
	ORA	#$80
	JSR	COUT
	INY
	BNE	PS1
PSDONE:
	RTS



BANNER:	DC	"2102 TEST COPYRIGHT 2012 MIKE WILLEGAL",$0d,0
TESTSTART: DC	"STARTING TEST",$0d,0
PASSED:	DC	"PASS:  ",0
ABORTED: DC	"TEST STOPPED BY KEYBOARD INPUT",$0d,0
ERRORRED: DC	"ERROR: ",0


