apple1serial/src/apple1serial.a65

345 lines
9.9 KiB
Plaintext

#ifndef BASE
#define BASE $C000
#endif
#ifndef OFFSET
#define OFFSET 0
#endif
;End address of dump block
#define hex1_l $34
#define hex1_h $35
;Begin address of dump block
#define hex2_l $36
#define hex2_h $37
#define last_command $28
#define last_command_none $00
#define last_command_read $01
#define last_command_write $02
;Input buffer
#define input $0200
#define kbd_data $D010 ;PIA.A keyboard input
#define kbd_cr $D011 ;PIA.A keyboard control register
#define monitor $FF1A ;Escape back to monitor
#define echo $FFEF ;Echo character to terminal
#define prbyte $FFDC
#define serial_ready BASE + OFFSET
#define serial_reset BASE + $1 + OFFSET
#define serial_read BASE + $80 + OFFSET
#define serial_write BASE + $81 + OFFSET
#define R_LETTER $D2
#define W_LETTER $D7
#define ZERO $B0
#define SEP $AE
#define CR $8D ;Carriage Return
#define ESC $9B ;ASCII ESC
#define SPACE $A0
; pad first 252 bytes with zeroes
.dsb 252 + OFFSET, 0
; include identification bytes
.byt "A1SI"
; this section is almost identical to original WOZ ACI
; adapted from https://www.sbprojects.net/projects/apple1/aci.php
* = BASE + $100 + OFFSET
apple_serial
lda #CR ;Drop the cursor one line
jsr echo
lda #"*" ;Print prompt
jsr echo
lda #CR ;And drop the cursor one line
jsr echo
lda #$00 ;Set last command type to NONE
sta last_command
ldy #$FF ;Reset the input buffer index
next_char
iny
kbd_wait
lda kbd_cr ;Wait for a key
bpl kbd_wait ;Still no key!
lda kbd_data ;Read key from keyboard
sta input,Y ;Save it into buffer
jsr echo ;And type it on the screen
cmp #ESC
beq apple_serial ;Start from scratch if ESC!
cmp #CR
bne next_char ;Read keys until CR
ldx #$FF ;Initialize parse buffer pointer
;-------------------------------------------------------------------------
; Start parsing command
;-------------------------------------------------------------------------
next_cmd
lda #$00 ;Clear begin and end values
sta hex1_l
sta hex1_h
sta hex2_l
sta hex2_h
next_chr
inx ;Increment input pointer
lda $0200,X ;Get next char from input lin
cmp #R_LETTER ;Read command?
beq read ;Yes!
cmp #W_LETTER ;Write command?
beq write ;Yes! (note: CY=1)
cmp #SEP ;Separator?
beq separator ;Yes!
cmp #CR ;End of line?
beq to_monitor ;Escape to monitor! We're done
cmp #SPACE ;Ignore spaces
beq next_chr
eor #ZERO ;Map digits to 0-9
cmp #$0A ;Is it a decimal digit?
bcc digit ;Yes!
clc
adc #$89 ;Map letter "A"-"F" to $FA-$FF
cmp #$FA ;Hex letter?
bcc apple_serial ;No! Character not hex!
digit
asl ;Hex digit to MSD of A
asl
asl
asl
ldy #4 ;Shift count
hexshift
asl ;Hex digit left, MSB to carry
rol hex1_l ;Rotate into LSD
rol hex1_h ;Rotate into MSD
dey ;Done 4 shifts?
bne hexshift ;No! Loop
beq next_chr ;Handle next character
;-------------------------------------------------------------------------
; Return to monitor, prints \ first
;-------------------------------------------------------------------------
to_monitor
;jmp monitor ;Escape back to monitor
jmp apple_serial
;-------------------------------------------------------------------------
; Separating . found. Copy HEX1 to Hex2. Doesn't clear HEX1!!!
;-------------------------------------------------------------------------
separator
lda hex1_l ;Copy hex value 1 to hex value 2
sta hex2_l
lda hex1_h
sta hex2_h
lda #$00 ;Original ACI bug (not enough ROM space?) fix
sta hex1_l
sta hex1_h
jmp next_chr
;-------------------------------------------------------------------------
; In-monitor read procedure
;-------------------------------------------------------------------------
read
lda last_command
cmp #last_command_read
beq read_ready
lda serial_read ;Enable read mode, this can be done quick, without reset
read_ready
txa ;Preserve X on stack
pha
ldy #$00
ldx #hex2_l
read_byte
lda serial_ready
beq read_byte ;No data arrived
lda serial_read ;Read byte
sta (hex2_l),Y ;Store byte under address, this should be hex2_l but macro substitution doesn't work
lda hex2_l
cmp hex1_l ;Compare lower destination address half with lower end address half
bne read_next ;If not equal then increment destination address
lda hex2_h
cmp hex1_h ;Compare upper destination address half with upper end address half
bne read_next ;If not equal then proceed to read next byte
lda #last_command_read ;Set last command to READ
sta last_command
pla ;Restore X from stack
tax
jmp next_cmd ;Read is completed, proceed to next command
read_next
jsr increment_16bit ;Increment destination address
jmp read_byte
;-------------------------------------------------------------------------
; In-monitor Write procedure
;-------------------------------------------------------------------------
write
lda last_command
cmp #last_command_write
beq write_ready
jsr reset_serial ;Reset serial and give some time to stabilize
;This is required due to inability to guess what is the current device mode
;and prevents from polluting the output while setting the write mode
sta serial_write ;Enable write mode
write_ready
txa ;Preserve X on stack
pha
ldx #hex2_l
ldy #$00
write_byte
lda serial_ready
beq write_byte ;Not yet ready to write data
lda (hex2_l),Y ;Read byte from source address, this should be hex2_l but macro substitution doesn't work
sta serial_write ;Write byte
lda hex2_l
cmp hex1_l ;Compare lower source address half with lower end address half
bne write_next ;If not equal then increment source address
lda hex2_h
cmp hex1_h ;Compare upper source address half with upper end address half
bne write_next ;If not equal then proceed to write next byte
lda #last_command_write ;Set last command to WRITE
sta last_command
pla ;Restore X from stack
tax
jmp next_cmd ;Write is completed, proceed to next command
write_next
jsr increment_16bit ;Increment destination address
jmp write_byte
;-------------------------------------------------------------------------
; API read procedure
;-------------------------------------------------------------------------
api_read
jsr reset_serial
lda serial_read ;Enable read mode
ldy #$00
ldx #hex2_l
api_read_byte
lda serial_ready
beq api_read_byte ;No data arrived
lda serial_read ;Read byte
sta (hex2_l),Y ;Store byte under address, this should be hex2_l but macro substitution doesn't work
lda hex2_l
cmp hex1_l ;Compare lower destination address half with lower end address half
bne api_read_next ;If not equal then increment destination address
lda hex2_h
cmp hex1_h ;Compare upper destination address half with upper end address half
bne api_read_next ;If not equal then proceed to read next byte
rts ;Read is completed, return
api_read_next
jsr increment_16bit ;Increment destination address
jmp api_read_byte
;-------------------------------------------------------------------------
; API write procedure
;-------------------------------------------------------------------------
api_write
jsr reset_serial ;Reset serial and give some time to stabilize
;This is required due to inability to guess what is the current device mode
;and prevents from polluting the output while setting the write mode
sta serial_write ;Enable write mode
api_write_ready
ldx #hex2_l
ldy #$00
api_write_byte
lda serial_ready
beq api_write_byte ;Not yet ready to write data
lda (hex2_l),Y ;Read byte from source address, this should be hex2_l but macro substitution doesn't work
sta serial_write ;Write byte
lda hex2_l
cmp hex1_l ;Compare lower source address half with lower end address half
bne api_write_next ;If not equal then increment source address
lda hex2_h
cmp hex1_h ;Compare upper source address half with upper end address half
bne api_write_next ;If not equal then proceed to write next byte
rts ;Write is completed, return
api_write_next
jsr increment_16bit ;Increment destination address
jmp api_write_byte
;-------------------------------------------------------------------------
; tool routines
;-------------------------------------------------------------------------
reset_serial
txa ;Preserve X on stack
pha
tya ;Preserve Y on stack
pha
lda serial_reset ;Reset
ldx #$00
ldy #$00
reset_loop ; ~((2 + 2 + 3) * 255 + 2 + 3) * 255 =
nop ; 2 cycles
iny ; 2 cycles
bne reset_loop ; 3 cycles
inx ; 2 cycles
bne reset_loop ; 3 cycles
pla ;Restore Y from stack
tay
pla ;Restore X from stack
tax
rts
increment_16bit
txa
inc $00,X
bne increment_16bit_done
inx
inc $00,X
increment_16bit_done
tax
rts
;-------------------------------------------------------------------------
end_of_apple1serial
#include "src/tests.a65"
#include "src/serialmonitor.a65"