Cleanup & Add more comments
This commit is contained in:
parent
93be412fd7
commit
d2385a9d3f
|
@ -0,0 +1,258 @@
|
||||||
|
; dasm woz_monitor_masm.asm -orom.o -lrom.lst -srom.sym
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------
|
||||||
|
;
|
||||||
|
; The WOZ Monitor for the Apple 1
|
||||||
|
; Written by Steve Wozniak 1976
|
||||||
|
;
|
||||||
|
;-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
processor 6502
|
||||||
|
org $FF00
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------
|
||||||
|
; 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,$027F ;Input buffer
|
||||||
|
|
||||||
|
KBD equ $D010 ;PIA.A keyboard input
|
||||||
|
KBDCR equ $D011 ;PIA.A keyboard control register
|
||||||
|
DSP equ $D012 ;PIA.B display output register
|
||||||
|
DSPCR equ $D013 ;PIA.B display control register
|
||||||
|
|
||||||
|
; 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.
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------
|
||||||
|
; Constants
|
||||||
|
;-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
BS equ $DF ;Backspace key, arrow left key
|
||||||
|
CR equ $8D ;Carriage Return
|
||||||
|
ESC equ $9B ;ESC key
|
||||||
|
PROMPT equ $5C ;Prompt character \
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------
|
||||||
|
; 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
|
||||||
|
ldy #%01111111 ;Mask for DSP data direction reg
|
||||||
|
sty DSP ;(DDR mode is assumed after reset)
|
||||||
|
lda #%10100111 ;KBD and DSP control register mask
|
||||||
|
sta KBDCR ;Enable interrupts, set CA1, CB1 for
|
||||||
|
sta DSPCR ;positive edge sense/output mode.
|
||||||
|
|
||||||
|
; 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 lda KBDCR ;Wait for key press
|
||||||
|
bpl NEXTCHAR ;No key yet!
|
||||||
|
lda KBD ;Load character. B7 should be '1'
|
||||||
|
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 #"."
|
||||||
|
bcc BLSKIP ;Ignore everything below "."!
|
||||||
|
beq SETMODE ;Set BLOCK XAM mode ("." = $AE)
|
||||||
|
cmp #":"
|
||||||
|
beq SETSTOR ;Set STOR mode! $BA will become $7B
|
||||||
|
cmp #"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 #%00000111
|
||||||
|
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 #%00001111 ;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 bit DSP ;DA bit (B7) cleared yet?
|
||||||
|
bmi ECHO ;No! Wait for display ready
|
||||||
|
sta DSP ;Output character. Sets DA
|
||||||
|
rts
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------
|
||||||
|
; Vector area
|
||||||
|
;-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------
|
|
@ -1,258 +0,0 @@
|
||||||
; dasm woz_monitor_masm.asm -orom.o -lrom.lst -srom.sym
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------
|
|
||||||
;
|
|
||||||
; The WOZ Monitor for the Apple 1
|
|
||||||
; Written by Steve Wozniak 1976
|
|
||||||
;
|
|
||||||
;-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
processor 6502
|
|
||||||
org $FF00
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------
|
|
||||||
; 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,$027F ;Input buffer
|
|
||||||
|
|
||||||
KBD equ $D010 ;PIA.A keyboard input
|
|
||||||
KBDCR equ $D011 ;PIA.A keyboard control register
|
|
||||||
DSP equ $D012 ;PIA.B display output register
|
|
||||||
DSPCR equ $D013 ;PIA.B display control register
|
|
||||||
|
|
||||||
; 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.
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------
|
|
||||||
; Constants
|
|
||||||
;-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
BS equ $DF ;Backspace key, arrow left key
|
|
||||||
CR equ $8D ;Carriage Return
|
|
||||||
ESC equ $9B ;ESC key
|
|
||||||
PROMPT equ "\" ;Prompt character
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------
|
|
||||||
; 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
|
|
||||||
LDY #%01111111 ;Mask for DSP data direction reg
|
|
||||||
STY DSP ;(DDR mode is assumed after reset)
|
|
||||||
LDA #%10100111 ;KBD and DSP control register mask
|
|
||||||
STA KBDCR ;Enable interrupts, set CA1, CB1 for
|
|
||||||
STA DSPCR ;positive edge sense/output mode.
|
|
||||||
|
|
||||||
; 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 LDA KBDCR ;Wait for key press
|
|
||||||
BPL NEXTCHAR ;No key yet!
|
|
||||||
LDA KBD ;Load character. B7 should be '1'
|
|
||||||
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 #"."
|
|
||||||
BCC BLSKIP ;Ignore everything below "."!
|
|
||||||
BEQ SETMODE ;Set BLOCK XAM mode ("." = $AE)
|
|
||||||
CMP #":"
|
|
||||||
BEQ SETSTOR ;Set STOR mode! $BA will become $7B
|
|
||||||
CMP #"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 #%00000111
|
|
||||||
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 #%00001111 ;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 BIT DSP ;DA bit (B7) cleared yet?
|
|
||||||
BMI ECHO ;No! Wait for display ready
|
|
||||||
STA DSP ;Output character. Sets DA
|
|
||||||
RTS
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------
|
|
||||||
; Vector area
|
|
||||||
;-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------
|
|
|
@ -10,13 +10,13 @@ The project is build over Platformio (http://platformio.org/frameworks) but you
|
||||||
## How it works
|
## How it works
|
||||||
A 65C02S (modern version of the original 6502) is wired on a breadboard. The 6502 is a very simple kind of CPU in terms of I/O and the modern version allow us to suspend the clock at any time in LOW / HIGH state.
|
A 65C02S (modern version of the original 6502) is wired on a breadboard. The 6502 is a very simple kind of CPU in terms of I/O and the modern version allow us to suspend the clock at any time in LOW / HIGH state.
|
||||||
|
|
||||||
There are 16 Address Pins (A0-A15) each mapping a bit (HIGH/LOW) of an address word. This is how 6502 tell us what address he want to read or write to (RAM/ROM, IO dedicated address spaces). The state of this pins may change at every clock cycle.
|
There are 16 Address Pins (A0-A15) each mapping a bit (HIGH/LOW) of an address word. This is how 6502 tell us which address he want to read or write to (RAM/ROM, IO dedicated address spaces). The state of this pins may change at every clock cycle.
|
||||||
|
|
||||||
Other 8 pins will carry or expect the 1 Byte data to be stored or read to / from the address above.
|
Other 8 pins will carry or expect the 1 Byte data to be stored or read to / from the address above.
|
||||||
|
|
||||||
The CPU tell the external world if the data is in read or write state via R/W pin (HIGH=Expect data IN, LOW=Send data OUT).
|
The CPU tell the external world if the data is in read or write state via R/W pin (HIGH=Expect data IN, LOW=Send data OUT).
|
||||||
|
|
||||||
This is it. This is all you need to interact with a 6502. The CPU expect a clock signal (HIGH/LOW) on pin 37 (PHI2). The modern version of 6502 is able to suspend any activity for an unlimited period of time during a clock cycle, both in LOW or HIGH state (was a little bit more hard with the original CPU). This make a perfect fit to let us drive the CPU via something different from a crystal, in our case, an Arduino, debug any single clock cycle and keep things in sync.
|
That's it. This is all you need to interact with a 6502. The CPU expect a clock signal (HIGH/LOW) on pin 37 (PHI2). The modern version of 6502 is able to suspend any activity for an unlimited period of time during a clock cycle, both in LOW or HIGH state (was a little bit more hard with the original CPU). This make a perfect fit to let us drive the CPU via something different from a crystal, in our case, an Arduino, debug any single clock cycle and keep things in sync.
|
||||||
|
|
||||||
Knowing the address space where the Apple 1 was mapping the different IO (Ram / ROM / KEYB / DSP), we can simulate the external interfaces (in fact a PIA 6821) and send back & forth as needed the related data via 6502 data bus. That's it.
|
Knowing the address space where the Apple 1 was mapping the different IO (Ram / ROM / KEYB / DSP), we can simulate the external interfaces (in fact a PIA 6821) and send back & forth as needed the related data via 6502 data bus. That's it.
|
||||||
|
|
||||||
|
@ -53,8 +53,11 @@ The WOZ monitor asm source and the original apple 1 operation manual are two ver
|
||||||
+--------------+ |
|
+--------------+ |
|
||||||
GND
|
GND
|
||||||
|
|
||||||
|
CLOCK_DELAY: A0 - you should connect a potentiometer to A0, this will let you manually sed the clock delay of the 6502.
|
||||||
|
|
||||||
Note: You may want to put a 100Uf capacitor near the 3.3v & GND lines too.
|
Note: You may want to put a 100Uf capacitor near the 3.3v & GND lines too.
|
||||||
|
|
||||||
|
|
||||||
## Serial client recommended settings:
|
## Serial client recommended settings:
|
||||||
You should be able to use the standard Serial Monitor in the Arduino IDE or or Platformio (Atom) or any other basic serial client.
|
You should be able to use the standard Serial Monitor in the Arduino IDE or or Platformio (Atom) or any other basic serial client.
|
||||||
|
|
||||||
|
|
47
src/main.cpp
47
src/main.cpp
|
@ -4,14 +4,16 @@
|
||||||
|
|
||||||
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
|
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
|
||||||
|
|
||||||
|
// General Control settings
|
||||||
const int SERIAL_SPEED = 115200; // Arduino Serial Speed
|
const int SERIAL_SPEED = 115200; // Arduino Serial Speed
|
||||||
|
const int CLOCK_DELAY_PIN = A0; // Clock delay PIN (potentiometer)
|
||||||
const int CLOCK_PIN = 52; // TO 6502 CLOCK
|
int CLOCK_DELAY = 5; // HIGH / LOW CLOCK STATE DELAY (You can slow down it as much as you want)
|
||||||
const int RW_PIN = 53; // TO 6502 R/W
|
|
||||||
const int CLOCK_DELAY = 3; // HIGH / LOW CLOCK STATE DELAY (You can slow down it as much as you want)
|
|
||||||
|
|
||||||
const char SERIAL_BS = 0x08;
|
const char SERIAL_BS = 0x08;
|
||||||
|
|
||||||
|
// 6502 to Arduino Pin Mapping
|
||||||
|
const int CLOCK_PIN = 52; // TO 6502 CLOCK
|
||||||
|
const int RW_PIN = 53; // TO 6502 R/W
|
||||||
const int ADDRESS_PINS[] = {44,45,2,3,4,5,6,7,8,9,10,11,12,13,46,47}; // TO ADDRESS PIN 1-15 6502
|
const int ADDRESS_PINS[] = {44,45,2,3,4,5,6,7,8,9,10,11,12,13,46,47}; // TO ADDRESS PIN 1-15 6502
|
||||||
const int DATA_PINS[] = {33, 34, 35, 36, 37,38, 39, 40}; // TO DATA BUS PIN 0-7 6502
|
const int DATA_PINS[] = {33, 34, 35, 36, 37,38, 39, 40}; // TO DATA BUS PIN 0-7 6502
|
||||||
|
|
||||||
|
@ -49,26 +51,33 @@ const unsigned char BS = 0xDF; // Backspace key, arrow left key (B7 High)
|
||||||
const unsigned char CR = 0x8D; // Carriage Return (B7 High)
|
const unsigned char CR = 0x8D; // Carriage Return (B7 High)
|
||||||
const unsigned char ESC = 0x9B; // ESC key (B7 High)
|
const unsigned char ESC = 0x9B; // ESC key (B7 High)
|
||||||
|
|
||||||
|
// 6502 States buffer
|
||||||
unsigned int address; // Current address (from 6502)
|
unsigned int address; // Current address (from 6502)
|
||||||
unsigned char bus_data; // Data Bus value (from 6502)
|
unsigned char bus_data; // Data Bus value (from 6502)
|
||||||
int rw_state; // Current R/W state (from 6502)
|
int rw_state; // Current R/W state (from 6502)
|
||||||
|
|
||||||
unsigned int pre_address; // Current address (from 6502)
|
// 6502 previous States buffer
|
||||||
unsigned char pre_bus_data; // Data Bus value (from 6502)
|
// We use them to optimize the performance a bit
|
||||||
int pre_rw_state; // Current R/W state (from 6502)
|
unsigned int pre_address; // Previous address (from 6502)
|
||||||
|
unsigned char pre_bus_data; // Previous Bus value (from 6502)
|
||||||
|
int pre_rw_state; // Previous R/W state (from 6502)
|
||||||
|
|
||||||
|
|
||||||
|
// Set Arduino Address connected PINS as INPUT
|
||||||
void setupAddressPins() {
|
void setupAddressPins() {
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
pinMode(ADDRESS_PINS[i], INPUT);
|
pinMode(ADDRESS_PINS[i], INPUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set Arduino Bus conneced pins mode as IN or OUT
|
||||||
void setBusMode(int mode) {
|
void setBusMode(int mode) {
|
||||||
for (int i = 0; i < 8; ++i) {
|
for (int i = 0; i < 8; ++i) {
|
||||||
pinMode(DATA_PINS[i], mode);
|
pinMode(DATA_PINS[i], mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read 6502 Address PINS and store the WORD in our address var
|
||||||
void readAddress() {
|
void readAddress() {
|
||||||
address = 0;
|
address = 0;
|
||||||
for (int i = 0; i < 16; ++i)
|
for (int i = 0; i < 16; ++i)
|
||||||
|
@ -78,6 +87,7 @@ void readAddress() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read 6502 Data PINS and store the BYTE in our bus_data var
|
||||||
void readData() {
|
void readData() {
|
||||||
bus_data = 0;
|
bus_data = 0;
|
||||||
for (int i = 0; i < 8; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
|
@ -87,6 +97,7 @@ void readData() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read RW_PIN state and set the busMode (aruduino related PINS) to OUTPUT or INPUT
|
||||||
void handleRWState() {
|
void handleRWState() {
|
||||||
int tmp_rw_state=digitalRead(RW_PIN);
|
int tmp_rw_state=digitalRead(RW_PIN);
|
||||||
|
|
||||||
|
@ -255,6 +266,14 @@ void loadPROG() {
|
||||||
void setup() {
|
void setup() {
|
||||||
pinMode(CLOCK_PIN, OUTPUT);
|
pinMode(CLOCK_PIN, OUTPUT);
|
||||||
pinMode(RW_PIN, INPUT);
|
pinMode(RW_PIN, INPUT);
|
||||||
|
pinMode(RW_PIN, INPUT);
|
||||||
|
|
||||||
|
// You can remove the PIN input here and just set CLOCK_DELAY as const
|
||||||
|
// Remove also the analogRead on CLOCK_DELAY_PIN in step() below.
|
||||||
|
pinMode(CLOCK_DELAY_PIN, INPUT);
|
||||||
|
CLOCK_DELAY=analogRead(CLOCK_DELAY_PIN);
|
||||||
|
// End of remove
|
||||||
|
|
||||||
|
|
||||||
setupAddressPins();
|
setupAddressPins();
|
||||||
setBusMode(OUTPUT);
|
setBusMode(OUTPUT);
|
||||||
|
@ -273,6 +292,8 @@ void setup() {
|
||||||
Serial.print("ERAM: ");
|
Serial.print("ERAM: ");
|
||||||
Serial.print(sizeof(RAM_BANK_2));
|
Serial.print(sizeof(RAM_BANK_2));
|
||||||
Serial.println(" BYTE");
|
Serial.println(" BYTE");
|
||||||
|
Serial.print("CLOCK DELAY: ");
|
||||||
|
Serial.println(CLOCK_DELAY);
|
||||||
|
|
||||||
loadBASIC();
|
loadBASIC();
|
||||||
loadPROG();
|
loadPROG();
|
||||||
|
@ -294,17 +315,25 @@ void handleClock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleBusRW() {
|
void handleBusRW() {
|
||||||
// READ OR WRITE TO BUS?
|
|
||||||
|
// If nothing changed from the last cycle, we don't need to upadte anything
|
||||||
if (pre_address != address || pre_rw_state != rw_state) {
|
if (pre_address != address || pre_rw_state != rw_state) {
|
||||||
|
// READ OR WRITE TO BUS?
|
||||||
rw_state ? writeToDataBus() : readFromDataBus();
|
rw_state ? writeToDataBus() : readFromDataBus();
|
||||||
pre_address = address;
|
pre_address = address;
|
||||||
pre_rw_state = rw_state;
|
pre_rw_state = rw_state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop () {
|
void step() {
|
||||||
|
|
||||||
|
CLOCK_DELAY=analogRead(CLOCK_DELAY_PIN); // Can be removed, see setup()
|
||||||
handleClock();
|
handleClock();
|
||||||
readAddress();
|
readAddress();
|
||||||
handleBusRW();
|
handleBusRW();
|
||||||
handleKeyboard();
|
handleKeyboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop () {
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue