184 lines
4.8 KiB
ArmAsm
184 lines
4.8 KiB
ArmAsm
; Apple I Monitor ROM
|
|
; Steve Wozniak
|
|
; 1976
|
|
; --------------------------------------------------------
|
|
|
|
.setcpu "6502"
|
|
.segment "MONITOR"
|
|
|
|
.export ECHO
|
|
|
|
; --------------------------------------------------------
|
|
; Zero page variables
|
|
XAML := $24
|
|
XAMH := $25
|
|
STL := $26
|
|
STH := $27
|
|
L := $28
|
|
H := $29
|
|
YSAV := $2A
|
|
MODE := $2B
|
|
|
|
; I/O locations
|
|
IN := $0200 ; Input buffer is $0200 to $027F
|
|
KBD := $D010 ; Keyboard data
|
|
DSP := $D012 ; Display data
|
|
KBDCR := $D011 ; Keyboard control register
|
|
DSPCR := $D013 ; Display control register
|
|
|
|
; ASCII codes
|
|
CR = $0D | $80 ; Carriage return
|
|
ESC = $1B | $80 ; Escape
|
|
SLASH = '\' | $80 ; \
|
|
UNDERSC = '_' | $80 ; Underscore (acts as backspace)
|
|
DOT = '.' | $80 ; .
|
|
COLON = ':' | $80 ; :
|
|
R = 'R' | $80 ; "R"
|
|
SPACE = ' ' | $80 ; blank
|
|
ZERO = '0' | $80 ; "0"
|
|
|
|
; --------------------------------------------------------
|
|
RESET: cld ; Clear decimal arithmetic mode
|
|
cli
|
|
ldy #$7F ; Mask for DSP data direction register
|
|
sty DSP ; Set it up
|
|
lda #$A7 ; KBD and DSP control register mask
|
|
sta KBDCR ; Enable interrupts, set CA1, CB1 for
|
|
sta DSPCR ; positive edge sense/output mode
|
|
NOTCR: cmp #UNDERSC ; Backspace?
|
|
beq BACKSPACE ; Yes
|
|
cmp #ESC ; ESC?
|
|
beq ESCAPE ; Yes
|
|
iny ; Advance text index
|
|
bpl NEXTCHAR ; Auto ESC if > 127
|
|
ESCAPE: lda #SLASH ; "\"
|
|
jsr ECHO ; Output it
|
|
GETLINE:
|
|
lda #CR ; CR
|
|
jsr ECHO ; Output it
|
|
ldy #$01 ; Initialize text index
|
|
BACKSPACE:
|
|
dey ; Back up text index
|
|
bmi GETLINE ; Beyond start of line, reinitialize
|
|
NEXTCHAR:
|
|
lda KBDCR ; Key ready?
|
|
bpl NEXTCHAR ; Loop until ready
|
|
lda KBD ; Load character. B7 should be '1'
|
|
sta IN,y ; Add to text buffer
|
|
jsr ECHO ; Display character
|
|
cmp #CR ; CR?
|
|
bne NOTCR ; No
|
|
ldy #$FF ; Reset text index
|
|
lda #$00 ; For XAM mode
|
|
tax ; 0 -> x
|
|
SETSTOR:
|
|
asl ; Leaves $7B if setting STOR mode
|
|
SETMODE:
|
|
sta MODE ; $00 = XAM, $7B = STOR, $AE = BLOCK XAM
|
|
BLSKIP: iny ; Advance text index
|
|
NEXTITEM:
|
|
lda IN,y ; Get character
|
|
cmp #CR ; CR?
|
|
beq GETLINE ; Yes, done this line
|
|
cmp #DOT ; "."?
|
|
bcc BLSKIP ; Skip delimiter
|
|
beq SETMODE ; Set BLOCK XAM mode
|
|
cmp #COLON ; ":"?
|
|
beq SETSTOR ; Yes, set STOR mode
|
|
cmp #R ; "R"?
|
|
beq RUN ; Yes, run user program
|
|
stx L ; $00 -> L
|
|
stx H ; and H
|
|
sty YSAV ; Save Y for comparison
|
|
NEXTHEX:
|
|
lda IN,y ; Get character for hex test
|
|
eor #$B0 ; Map digits to $0-9
|
|
cmp #$0A ; Digit?
|
|
bcc DIG ; Yes
|
|
adc #$88 ; Map letter "A"-"F" to $FA-FF
|
|
cmp #$FA ; Hex letter?
|
|
bcc NOTHEX ; No, character not hext
|
|
DIG: asl
|
|
asl ; Hex digit to MSD of A
|
|
asl
|
|
asl
|
|
ldx #$04 ; Shift count
|
|
HEXSHIFT:
|
|
asl ; Hex digit left, MSB to carry
|
|
rol L ; Rotate into LSD
|
|
rol H ; Rotate into MSD's
|
|
dex ; Done 4 shifts?
|
|
bne HEXSHIFT ; No, loop
|
|
iny ; Advance text index
|
|
bne NEXTHEX ; Always taken. Check next character for hex
|
|
NOTHEX:
|
|
cpy YSAV ; Check if L, H empty (no hex digits)
|
|
beq ESCAPE ; Yes, generate ESC sequence
|
|
bit MODE ; Test MODE byte
|
|
bvc NOTSTOR ; B6 = 0 for STOR, 1 for XAM and BLOCK XAM
|
|
lda L ; LSD's of hex data
|
|
sta (STL,x) ; Store at current 'store index'
|
|
inc STL ; Increment store index
|
|
bne NEXTITEM ; Get next item (no carry)
|
|
inc STH ; Add carry to 'store index' high order
|
|
TONEXTITEM:
|
|
jmp NEXTITEM ; Get next command item
|
|
RUN: jmp (XAML) ; Run at current XAM index
|
|
NOTSTOR:
|
|
bmi XAMNEXT ; B7=0 for XAM, 1 for BLOCK XAM
|
|
ldx #$02 ; Byte count
|
|
SETADR: lda L-1,x ; Copy hex data to
|
|
sta STL-1,x ; 'store index'
|
|
sta XAML-1,x ; And to 'XAM index'
|
|
dex ; Next of 2 bytes
|
|
bne SETADR ; Loop unless X=0
|
|
NXTPRNT:
|
|
bne PRDATA ; NE means no address to print
|
|
lda #CR ; CR
|
|
jsr ECHO ; Output it
|
|
lda XAMH ; 'Examine index' high-order byte
|
|
jsr PRBYTE ; Output it in hex format
|
|
lda XAML ; Low-order 'examine index' byte
|
|
jsr PRBYTE ; Output it in hex format
|
|
lda #COLON ; ":"
|
|
jsr ECHO ; Output it
|
|
PRDATA: lda #SPACE ; Blank
|
|
jsr ECHO ; Output it
|
|
lda (XAML,x) ; Get data byte at 'examine index'
|
|
jsr PRBYTE ; Output it in hex format
|
|
XAMNEXT:
|
|
stx MODE ; 0 -> MODE (XAM mode)
|
|
lda XAML
|
|
cmp L ; Compare 'examine index' to hex data
|
|
lda XAMH
|
|
sbc H
|
|
bcs TONEXTITEM ; Not less, so no more data to output
|
|
inc XAML
|
|
bne MOD8CHK ; Increment 'examine index'
|
|
inc XAMH
|
|
MOD8CHK:
|
|
lda XAML ; Check low-order 'examine index' byte
|
|
and #$07 ; For MOD 8 = 0
|
|
bpl NXTPRNT ; Always taken
|
|
PRBYTE: pha ; Save A for LSD
|
|
lsr
|
|
lsr
|
|
lsr ; MSD to LSD position
|
|
lsr
|
|
jsr PRHEX ; Output hex digit
|
|
pla ; Restore A
|
|
PRHEX: and #$0F ; Mask LSD for hex print
|
|
ora #ZERO ; Add "0"
|
|
cmp #$BA ; Digit?
|
|
bcc ECHO ; Yes, output it
|
|
adc #$06 ; Add offset for letter
|
|
ECHO: bit DSP ; DA bit (B7) cleared yet?
|
|
bmi ECHO ; No, wait for display
|
|
sta DSP ; Output character. Sets DA.
|
|
rts ; Return
|
|
; --------------------------------------------------------
|
|
.word $0000 ; (unused)
|
|
.addr $0F00 ; (NMI vector)
|
|
.addr RESET ; (RESET vector)
|
|
.addr $0000 ; (IRQ vector)
|