1234 lines
25 KiB
ArmAsm
Executable File
1234 lines
25 KiB
ArmAsm
Executable File
******************************************************************************************
|
|
*
|
|
* Address Field Scanner
|
|
* ========================================================================================
|
|
* This is a simple Disk II scanner
|
|
* to identify address field contents
|
|
*
|
|
* 1/16/2016: Version 1.0
|
|
*
|
|
* 1/29/2016: Version 2.0
|
|
* - Restructuring to support paging and scrollong.
|
|
* - Slowly switching from spaces to tabs as an experiment in code formatting.
|
|
* - Pages available:
|
|
* + About (default page)
|
|
* + Headers (updated Address Field Header information)
|
|
* + Browse track buffer (hilights Address Field Header bytes)
|
|
* + Graphical disk display
|
|
* + Buffer counts
|
|
*
|
|
******************************************************************************************
|
|
|
|
TYP SYS
|
|
|
|
XC ; enable 65C02
|
|
|
|
* Program Locations
|
|
|
|
OriginAddress = $2000
|
|
ProgramAddress = $6000
|
|
ProgramLength = ProgramEnd-ProgramAddress
|
|
|
|
* Constants:
|
|
|
|
NUMBYTES = 29 ; Number of bytes on screen
|
|
OFFSETV = 3 ; Offset to volume
|
|
OFFSETT = OFFSETV+2 ; Offset to track
|
|
OFFSETS = OFFSETT+2 ; Offset to sector
|
|
OFFSETC = OFFSETS+2 ; Offset to checksum
|
|
FAILBYTS = 6656 ; Number of bytes before failure
|
|
|
|
* 80 column card / print controls:
|
|
|
|
_PRBYTE = 1 ; print byte @ addr
|
|
_CLS = $8C ; clear screen
|
|
_INVERSE = $8F
|
|
_NORMAL = $8E
|
|
_MT_OFF = $98 ; disable MouseText
|
|
_HOME = $99 ; home the cursor, not cls
|
|
_MT_ON = $9B ; enable MouseText for uppercase inverse characters
|
|
_CLREOL = $9D ; clear to EOL
|
|
|
|
_C_APPLE = "@" ; Closed Apple
|
|
_O_APPLE = "A" ; Open Apple
|
|
_L_ARROW = "H" ; Left Arrow
|
|
_R_ARROW = "U" ; Right Arrow
|
|
_U_ARROW = "K" ; Up Arrow
|
|
_D_ARROW = "J" ; Down Arrow
|
|
_H_LINE = "S" ; Horizontal Line (full width)
|
|
|
|
|
|
* Variable locations:
|
|
|
|
DUM $0 ; ZP locs
|
|
SAMPLES DFB 0 ; number of sector samples
|
|
CURTRK DFB 0 ; current track
|
|
DSTTRK DFB 0 ; destination track
|
|
PTR DA 0 ; primary print pointer
|
|
PTR2 DA 0 ; secondary print pointer
|
|
SLOT16 DFB 0 ; slot# * 16
|
|
COUNTER DA 0 ; fail counter
|
|
TEMP DFB 0 ; local variable
|
|
TEMPY DFB 0 ; local Y coordinate
|
|
DATA DA 0 ; data buffer
|
|
|
|
_init da 0 ; current page init
|
|
_display da 0 ; current page line display handler
|
|
_keypress da 0 ; current page keypress handler
|
|
scrolling dfb 0 ; flag for scrolling (in high bit)
|
|
topline dw 0 ; current line at top of page
|
|
maxlines dw 0 ; maximum number of lines available
|
|
printline dw 0 ; line being printed
|
|
DEND
|
|
|
|
inbuf = $200 ; reusable buffer
|
|
|
|
DATASTART = $4000
|
|
DATAEND = $6000
|
|
DATALEN = DATAEND-DATASTART
|
|
|
|
PAGELEN = 20 ; number of lines displayed in content window
|
|
|
|
* High ASCII constants
|
|
|
|
CTRLH = "H"-$40
|
|
LARROW = CTRLH
|
|
CTRLU = "U"-$40
|
|
RARROW = CTRLU
|
|
ESC = $9B
|
|
CTRLK = "K"-$40
|
|
UpArrow = CTRLK
|
|
CTRLJ = "J"-$40
|
|
DownArrow = CTRLJ
|
|
|
|
* ProDOS:
|
|
|
|
PRODOSMLI = $BF00
|
|
_MLIQUIT = $65
|
|
|
|
* ROM routines and associated addresses:
|
|
|
|
TEXT = $FB2F
|
|
HGR = $F3E2
|
|
HPOSN = $F411
|
|
HBAS = $26
|
|
|
|
DELAY = $FCA8
|
|
GETCH = $FD0C
|
|
PRCR = $FD8E
|
|
PRHEX = $FDDA
|
|
COUT = $FDED
|
|
|
|
* I/O addresses:
|
|
|
|
KEYBOARD = $C000
|
|
KEYCLEAR = $C010
|
|
OpenApple = $C061
|
|
|
|
* Disk II addresses:
|
|
|
|
PHASEOFF = $C080
|
|
PHASEON = $C081
|
|
MOTOROFF = $C088
|
|
MOTORON = $C089
|
|
DRV0EN = $C08A
|
|
Q6L = $C08C
|
|
Q7L = $C08E
|
|
|
|
* Relocate application above HGR and HGR2 page
|
|
|
|
org OriginAddress
|
|
|
|
lda #>OriginEnd
|
|
sta PTR+1
|
|
lda #<OriginEnd
|
|
sta PTR
|
|
lda #>ProgramAddress
|
|
sta PTR2+1
|
|
stz PTR2
|
|
ldy #0
|
|
ldx #>ProgramLength+255 ; account for non-zero low byte
|
|
:0 lda (PTR),y
|
|
sta (PTR2),y
|
|
iny
|
|
bne :0
|
|
inc PTR+1
|
|
inc PTR2+1
|
|
dex
|
|
bne :0
|
|
jmp ProgramAddress
|
|
OriginEnd ; Marker for code relocation
|
|
|
|
* Display screen
|
|
|
|
org ProgramAddress
|
|
|
|
MAIN JSR $C300 ; Assuming 80 columns
|
|
JSR PRINT
|
|
DFB _CLS
|
|
ASC "AFScanner",$8D
|
|
DFB _MT_ON,_INVERSE,80,_H_LINE,_NORMAL,_MT_OFF ; wraps!
|
|
DFB 20,$8D
|
|
DFB _MT_ON,_INVERSE,80,_H_LINE,_NORMAL,_MT_OFF ; wraps!
|
|
ASC _MT_ON,_INVERSE,_L_ARROW,_NORMAL,", ",_INVERSE,_R_ARROW,_NORMAL,_MT_OFF," Track / "
|
|
ASC "re",_INVERSE,"S",_NORMAL,"can / "
|
|
ASC _INVERSE,"R",_NORMAL,"ecalibrate / "
|
|
ASC "goto ",_INVERSE,"T",_NORMAL,"rack / "
|
|
ASC _INVERSE,"ESC",_NORMAL," quit"
|
|
DFB _HOME
|
|
HEX 8D8D
|
|
HEX 00
|
|
|
|
* Setup local variables
|
|
|
|
Initialize
|
|
ldx #$60 ; assumption = slot 6
|
|
stx SLOT16
|
|
lda #40
|
|
sta CURTRK ; force a recalibration
|
|
stz DSTTRK
|
|
lda #"A" ; default screen is "About" page
|
|
jsr SetScreen
|
|
|
|
SetupPage
|
|
jsr TEXT ; ensure we are out of graphics modes as application has some!
|
|
jsr PRINT ; position cursor on bottom line
|
|
dfb _HOME
|
|
dfb 23,$8D
|
|
dfb _CLREOL
|
|
dfb $00
|
|
ldx #_init ; vector offset
|
|
jsr _VCALL
|
|
ror scrolling ; set flag based on C
|
|
sty maxlines
|
|
sta maxlines+1
|
|
stz topline
|
|
stz topline+1
|
|
|
|
DrawPage
|
|
jsr PRINT ; Clear and then draw the content area
|
|
dfb _HOME,$8d,$8d,0
|
|
|
|
; If we aren't scrolling, call _display vector ONCE and then handle keyboard.
|
|
bit scrolling
|
|
bpl :scroll
|
|
lda #0
|
|
tay
|
|
ldx #_display
|
|
jsr _VCALL
|
|
jmp KeyboardWait
|
|
|
|
:scroll lda #0
|
|
:loop pha
|
|
clc
|
|
adc topline
|
|
sta printline
|
|
lda topline+1
|
|
adc #0
|
|
sta printline+1
|
|
cmp maxlines+1
|
|
blt :drwlin
|
|
lda printline
|
|
cmp maxlines
|
|
bge :erase
|
|
|
|
:drwlin lda printline+1
|
|
ldy printline
|
|
ldx #_display
|
|
jsr _VCALL
|
|
bra :incr
|
|
|
|
:erase jsr PRINT
|
|
dfb _CLREOL,$8D,0
|
|
|
|
:incr pla
|
|
inc
|
|
cmp #PAGELEN
|
|
blt :loop
|
|
|
|
KeyboardWait
|
|
lda KEYBOARD
|
|
bpl KeyboardWait
|
|
; Uppercase the if it's A-Z
|
|
cmp #"a"
|
|
blt :goodky
|
|
cmp #"z"+1
|
|
bge :goodky
|
|
and #$df ; uppercase mask
|
|
:goodky sta KEYCLEAR
|
|
bit OpenApple
|
|
bpl :normal
|
|
; OpenApple handler
|
|
jsr SetScreen
|
|
bcs :paging
|
|
jsr CLRSCRN
|
|
jmp SetupPage
|
|
; OA-Up
|
|
:paging cmp #UpArrow
|
|
bne :nPgUp
|
|
ldy #15
|
|
:uploop jsr :up1
|
|
dey
|
|
bne :uploop
|
|
beq :back ; always
|
|
; OA-Down
|
|
:nPgUp cmp #DownArrow
|
|
bne :chkOAQ
|
|
ldy #15
|
|
:dnloop jsr :down1
|
|
dey
|
|
bne :dnloop
|
|
beq :back ; always
|
|
; OA-Q
|
|
:chkOAQ cmp #"Q"
|
|
bne :back
|
|
jsr PRODOSMLI
|
|
dfb _MLIQUIT
|
|
da QUITPARM
|
|
:back jmp DrawPage ; fall through and common return
|
|
|
|
; Common keypress handler
|
|
; Up
|
|
:normal cmp #UpArrow
|
|
bne :notUp
|
|
jsr :up1
|
|
jmp DrawPage
|
|
; Down
|
|
:notUp cmp #DownArrow
|
|
bne :pgKey
|
|
jsr :down1
|
|
jmp DrawPage
|
|
|
|
; "Local" subroutines
|
|
|
|
; if topline+PAGELEN >= maxlines then return
|
|
; topline = topline + 1
|
|
:down1 clc
|
|
lda topline
|
|
adc #PAGELEN
|
|
sta printline
|
|
lda printline+1
|
|
adc #0
|
|
sta printline+1
|
|
cmp maxlines+1
|
|
bcc :minus1
|
|
lda printline
|
|
cmp maxlines
|
|
bge :rts
|
|
:minus1 inc topline
|
|
bne :rts
|
|
inc topline+1
|
|
rts
|
|
; if topline = 0 then return
|
|
; topline = topline - 1
|
|
:up1 lda topline
|
|
ora topline+1
|
|
beq :rts ; already = 0
|
|
sec
|
|
lda topline
|
|
sbc #1
|
|
sta topline
|
|
lda topline+1
|
|
sbc #0
|
|
sta topline+1
|
|
:rts rts
|
|
|
|
:pgKey ldx #_keypress
|
|
; Fall through and JMP to _keypress which takes control for local page keys
|
|
|
|
* Simple vector call from ZP based on X register
|
|
|
|
_VCALL jmp: ($00,x) ; Merlin32 needs to know 16 bit JMP
|
|
|
|
* Handle screen change - both called by app init and normal keyboard handler
|
|
|
|
SetScreen
|
|
ldx #0
|
|
:next bit :data,x
|
|
bpl :notf
|
|
cmp :data,x
|
|
beq :setup
|
|
pha
|
|
txa
|
|
clc
|
|
adc #7
|
|
tax
|
|
pla
|
|
bra :next
|
|
:notf sec ; Not found
|
|
rts
|
|
:setup ldy #0
|
|
:copy inx
|
|
lda :data,x
|
|
sta _init,y
|
|
iny
|
|
cpy #6
|
|
bne :copy
|
|
clc
|
|
rts
|
|
|
|
*
|
|
* Data per page: Apple ASCII, Initialization, Display, Keypress (7 bytes)
|
|
*
|
|
* Definitions:
|
|
* - BYTE = Character to match on, case insensitive
|
|
* - ADDR = Initialize routine (load track, calculate lookup tables, etc).
|
|
* Return:
|
|
* A:Y for number of lines,
|
|
* Carry: Set = no scrolling (graphics, form, etc), Clear = scrolling.
|
|
* Note: Initialization should also display 24th line for the page.
|
|
* (Cursor is there and line is clear.)
|
|
* - ADDR = Display routine. Called with A:Y for line number. Should end with $8D and is
|
|
* responsible for clearing the line.
|
|
* - ADDR = Keypress handler. NOT A SUBROUTINE. This routine has a number of entry
|
|
* points it might call. KeyboardWait for another keypress or SetupPage to
|
|
* reinitialize and redraw.
|
|
*
|
|
:data
|
|
dfb "A"
|
|
da AboutInit, AboutDisplay, AboutKeypress
|
|
dfb "F"
|
|
da FieldInit, FieldDisplay, FieldKeypress
|
|
dfb "B"
|
|
da BrowseInit, BrowseDisplay, BrowseKeypress
|
|
dfb "G"
|
|
da HgrInit, HgrDisplay, HgrKeypress
|
|
dfb "C"
|
|
da CountInit, CountDisplay, CountKeypress
|
|
dfb "T"
|
|
da TestInit, TestDisplay, TestKeypress
|
|
dfb 0 ; end
|
|
|
|
*
|
|
* ABOUT page interface
|
|
*
|
|
|
|
* Build array of line pointers in INBUF.
|
|
AboutInit ; Returns with A:Y = max lines, C = scrolling
|
|
jsr PRINT
|
|
asc _INVERSE,_MT_ON,_U_ARROW,_D_ARROW,_MT_OFF,_NORMAL," Scroll / "
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_NORMAL,"-",_INVERSE,_U_ARROW,_D_ARROW,_MT_OFF,_NORMAL," Page"
|
|
dfb 0
|
|
|
|
lda #<:lines
|
|
sta PTR
|
|
lda #>:lines
|
|
sta PTR+1
|
|
ldy #0 ; max lines
|
|
ldx #0 ; buffer offset
|
|
|
|
:save lda PTR
|
|
sta inbuf,x
|
|
inx
|
|
lda PTR+1
|
|
sta inbuf,x
|
|
inx
|
|
iny
|
|
|
|
:loop lda (PTR)
|
|
bne :incr
|
|
dey ; we're one past...
|
|
lda #0 ; high byte of max lines; Y = low byte
|
|
clc ; we need scrolling
|
|
rts
|
|
|
|
:incr lda (PTR)
|
|
pha
|
|
inc PTR
|
|
bne :skip
|
|
inc PTR+1
|
|
:skip pla
|
|
beq :save
|
|
bne :incr
|
|
|
|
* Guide 00000000011111111112222222222333333333344444444445555555555666666666677777777778
|
|
* 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
|
* | + + + + + + + +|
|
|
:lines asc _INVERSE," Address Field Scanner ",_NORMAL,$00
|
|
asc "Version 2.0beta",$00
|
|
asc " ",$00
|
|
asc "This application is my lame attempt to understand the old Apple Disk II",$00
|
|
asc "interface.",$00
|
|
asc " ",$00
|
|
asc "As of Version 2 of AFSCANNER, multiple pages have been introduced to better",$00
|
|
asc "review the contents of a disk buffer and analyze a disk.",$00
|
|
asc " ",$00
|
|
asc "Use the ",_INVERSE,_MT_ON,_O_APPLE,_MT_OFF,_NORMAL,"-key combinations to toggle pages.",$00
|
|
asc " ",$00
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_MT_OFF,_NORMAL,"A = This about page.",$00
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_MT_OFF,_NORMAL,"B = Browse track buffer.",$00
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_MT_OFF,_NORMAL,"C = Display buffer counts.",$00
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_MT_OFF,_NORMAL,"F = Address field display. " ; (cont)
|
|
asc "(Assuming 'good' address fields on disk.)",$00
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_MT_OFF,_NORMAL,"G = Graphical disk display.",$00
|
|
asc " ",$00
|
|
asc "Source available at https://github.com/a2geek/afscanner",$00
|
|
asc " ",$00
|
|
asc "Global Keys",$00
|
|
asc "===========",$00
|
|
asc " ",$00
|
|
asc _INVERSE,_MT_ON,_D_ARROW,_MT_OFF,_NORMAL," Scroll down 1 line",$00
|
|
asc _INVERSE,_MT_ON,_U_ARROW,_MT_OFF,_NORMAL," Scroll up 1 line",$00
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_D_ARROW,_MT_OFF,_NORMAL," Page down 15 lines",$00
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_U_ARROW,_MT_OFF,_NORMAL," Page up 15 lines",$00
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_MT_OFF,_NORMAL,"Q Quit to ProDOS",$00
|
|
asc " ",$00
|
|
asc "Address Field Display",$00
|
|
asc "=====================",$00
|
|
asc " ",$00
|
|
asc "Display the list of Address Fields, the disk bytes, as well as the decoded",$00
|
|
asc "values to indicate what sectors are phyiscally present and their order on disk.",$00
|
|
asc "Note that the buffer is $2000 (8192) bytes long and some sectors will be",$00
|
|
asc "repeated.",$00
|
|
asc " ",$00
|
|
asc "Headers are currently set to "
|
|
dfb 1
|
|
da PROLOGUE
|
|
dfb " ",1
|
|
da PROLOGUE+1
|
|
dfb " ",1
|
|
da PROLOGUE+2
|
|
dfb $00
|
|
asc " ",$00
|
|
asc "Browse Track Buffer",$00
|
|
asc "===================",$00
|
|
asc " ",$00
|
|
asc "Browse the raw track buffer. Header fields are hilighted. Note that the ",$00
|
|
asc "buffer is $2000 (8192) bytes long and some sectors will be repeated.",$00
|
|
asc " ",$00
|
|
asc "Headers are currently set to "
|
|
dfb 1
|
|
da PROLOGUE
|
|
dfb " ",1
|
|
da PROLOGUE+1
|
|
dfb " ",1
|
|
da PROLOGUE+2
|
|
dfb $00
|
|
asc " ",$00
|
|
asc "Graphical Disk Display",$00
|
|
asc "======================",$00
|
|
asc " ",$00
|
|
asc "Scans an entire disk and graphically displays where sync ($FF) bytes appear on",$00
|
|
asc "disk. Note that the length of each bar indicates how many sync bytes were in",$00
|
|
asc "that section of the disk. Each bar represents approximately 46 bytes.",$00
|
|
asc " ",$00
|
|
asc "Display Buffer Counts",$00
|
|
asc "=====================",$00
|
|
asc " ",$00
|
|
asc "Count the number of disk bytes in the buffer and display totals. This may be",$00
|
|
asc "helpful when trying to determine address field bytes.",$00
|
|
asc " ",$00
|
|
asc "-END-",$00
|
|
dfb 0
|
|
|
|
AboutDisplay ; Called with A:Y = line
|
|
phy ; assuming < 256 lines
|
|
lda #_CLREOL
|
|
jsr COUT
|
|
pla
|
|
asl
|
|
tay
|
|
lda inbuf,y
|
|
tax
|
|
lda inbuf+1,y
|
|
jsr PRINTP
|
|
jmp PRCR
|
|
|
|
AboutKeypress ; Called with Acc = key
|
|
; Do Nothing, continue loop
|
|
jmp KeyboardWait
|
|
|
|
*
|
|
* FIELD Interface
|
|
*
|
|
|
|
FieldInit ; Returns with A:Y = max lines
|
|
jsr PRINT
|
|
asc _INVERSE,_MT_ON,_U_ARROW,_D_ARROW,_MT_OFF,_NORMAL," Scroll / "
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_NORMAL,"-",_INVERSE,_U_ARROW,_D_ARROW,_MT_OFF,_NORMAL," Page / "
|
|
asc _MT_ON,_INVERSE,_L_ARROW,_R_ARROW,_NORMAL,_MT_OFF," Track / "
|
|
asc "re",_INVERSE,"S",_NORMAL,"can / "
|
|
asc _INVERSE,"R",_NORMAL,"ecalibrate / "
|
|
asc "goto ",_INVERSE,"T",_NORMAL,"rack"
|
|
dfb 0
|
|
|
|
* Scan for our prologue and save positions in INBUF
|
|
|
|
jsr ReadTrack ; position head and fully populate buffer
|
|
ldx #0 ; index for INBUF
|
|
jsr SETUPDATA
|
|
:scan ldy #0 ; index for comparisons
|
|
:loop lda (DATA),y
|
|
cmp PROLOGUE,Y
|
|
bne :adv
|
|
iny
|
|
cpy #3
|
|
bcc :loop
|
|
; We found prologue bytes, save DATA address
|
|
lda DATA
|
|
sta inbuf,x
|
|
inx
|
|
lda DATA+1
|
|
sta inbuf,x
|
|
inx
|
|
:adv inc DATA
|
|
bne :scan
|
|
inc DATA+1
|
|
dec TEMP
|
|
bne :scan
|
|
; Calculate # of lines
|
|
txa
|
|
lsr
|
|
tay
|
|
lda #0 ; Assumed < 256 lines
|
|
clc ; we need scrolling
|
|
rts
|
|
|
|
FieldDisplay ; Called with A:Y = line
|
|
tya ; Assuming < 256 lines
|
|
asl
|
|
tay
|
|
lda inbuf,y
|
|
sta DATA
|
|
pha
|
|
lda inbuf+1,y
|
|
sta DATA+1
|
|
pha
|
|
; Display offset
|
|
lda #"+"
|
|
jsr COUT
|
|
pla
|
|
and #$3f
|
|
jsr PRHEX
|
|
pla
|
|
jsr PRHEX
|
|
jsr PRINT
|
|
asc "- ",$00
|
|
; Display 'disk' bytes
|
|
ldy #0
|
|
ldx #0
|
|
:nextg lda :groups,x
|
|
sta TEMP
|
|
:bytes lda (DATA),y
|
|
jsr PRHEX
|
|
iny
|
|
dec TEMP
|
|
bne :bytes
|
|
lda #" "
|
|
jsr COUT
|
|
inx
|
|
cpx #6
|
|
bne :nextg
|
|
jsr COUT ; 2nd space
|
|
; Display values
|
|
lda #"V"
|
|
ldy #OFFSETV
|
|
jsr PRDATA
|
|
lda #"T"
|
|
ldy #OFFSETT
|
|
jsr PRDATA
|
|
lda #"S"
|
|
ldy #OFFSETS
|
|
jsr PRDATA
|
|
lda #"C"
|
|
ldy #OFFSETC
|
|
jsr PRDATA
|
|
jmp PRCR
|
|
; Address Field byte groupings
|
|
:groups dfb 3,2,2,2,2,3
|
|
|
|
FieldKeypress ; Called with Acc = key
|
|
ldx #-1
|
|
cmp #LARROW
|
|
beq :chgtrk
|
|
ldx #1
|
|
cmp #RARROW
|
|
beq :chgtrk
|
|
cmp #"R"
|
|
beq :recal
|
|
cmp #"S"
|
|
beq :setup
|
|
cmp #"T"
|
|
beq :gotrk
|
|
:back jmp KeyboardWait
|
|
|
|
:chgtrk txa
|
|
clc
|
|
adc CURTRK
|
|
cmp #35 ; cap at track 35 (0..34)
|
|
bcs :back
|
|
:setdst sta DSTTRK
|
|
:setup jmp SetupPage ; this redraws page and re-initializes on new track
|
|
:recal lda #40
|
|
sta CURTRK ; This forces the recalibration
|
|
lda #0
|
|
beq :setdst
|
|
|
|
:gotrk jsr CLRSCRN
|
|
jsr PRINT
|
|
asc "Enter track number: $"00
|
|
jsr READBYTE
|
|
bcs :setup
|
|
bcc :setdst
|
|
|
|
*
|
|
* BROWSE interface
|
|
*
|
|
|
|
BrowseInit ; Returns with Acc = max lines
|
|
jsr PRINT
|
|
asc _INVERSE,_MT_ON,_U_ARROW,_D_ARROW,_MT_OFF,_NORMAL," Scroll / "
|
|
asc _INVERSE,_MT_ON,_O_APPLE,_NORMAL,"-",_INVERSE,_U_ARROW,_D_ARROW,_MT_OFF,_NORMAL," Page / "
|
|
asc _MT_ON,_INVERSE,_L_ARROW,_R_ARROW,_NORMAL,_MT_OFF," Track / "
|
|
asc "re",_INVERSE,"S",_NORMAL,"can / "
|
|
asc _INVERSE,"R",_NORMAL,"ecalibrate / "
|
|
asc "goto ",_INVERSE,"T",_NORMAL,"rack"
|
|
dfb 0
|
|
|
|
* Scan for our prologue mark them by turning off the high bit
|
|
|
|
jsr ReadTrack ; position head and fully populate buffer
|
|
jsr SETUPDATA
|
|
:scan ldy #0 ; index for comparisons
|
|
:loop lda (DATA),y
|
|
cmp PROLOGUE,Y
|
|
bne :adv
|
|
iny
|
|
cpy #3
|
|
bcc :loop
|
|
; We found prologue bytes, strip off high bit
|
|
:strip dey
|
|
bmi :adv
|
|
lda (DATA),y
|
|
and #$7f
|
|
sta (DATA),y
|
|
bne :strip ; should be always
|
|
:adv inc DATA
|
|
bne :scan
|
|
inc DATA+1
|
|
dec TEMP
|
|
bne :scan
|
|
; The number of lines is based on how many bytes we show on screen
|
|
lda #1 ; A:Y = $100 or 256 lines
|
|
ldy #0
|
|
clc ; we need scrolling
|
|
rts
|
|
|
|
BrowseDisplay ; Called with Acc = line
|
|
; Calculate buffer address
|
|
sta DATA+1
|
|
sty DATA
|
|
ldy #5 ; times 32
|
|
:mult32 asl DATA
|
|
rol DATA+1
|
|
dey
|
|
bne :mult32
|
|
clc
|
|
lda #>DATASTART
|
|
adc DATA+1
|
|
sta DATA+1
|
|
; Display offset
|
|
lda #"+"
|
|
jsr COUT
|
|
lda DATA+1
|
|
and #$3f
|
|
jsr PRHEX
|
|
lda DATA
|
|
jsr PRHEX
|
|
jsr PRINT
|
|
asc "- ",$00
|
|
; Display 'disk' bytes, highlighting the field markers (high bit was stripped off in init routine)
|
|
ldy #0
|
|
:nxtbyt lda (DATA),y
|
|
bmi :prhex
|
|
pha
|
|
lda #_INVERSE
|
|
jsr COUT
|
|
pla
|
|
ora #$80
|
|
:prhex jsr PRHEX
|
|
lda #_NORMAL
|
|
jsr COUT
|
|
tya
|
|
and #$07
|
|
cmp #$07
|
|
bne :testy
|
|
lda #" "
|
|
jsr COUT
|
|
:testy iny
|
|
cpy #32
|
|
bne :nxtbyt
|
|
jmp PRCR
|
|
|
|
BrowseKeypress ; Called with Acc = key
|
|
jmp FieldKeypress ; identical to Field ... for now at least
|
|
|
|
*
|
|
* HGR/Graphics interface
|
|
*
|
|
|
|
; Init displays HGR and the static text on the page
|
|
HgrInit
|
|
jsr PRINT
|
|
asc "re",_INVERSE,"S",_NORMAL,"can / "
|
|
asc _INVERSE,"R",_NORMAL,"ecalibrate"
|
|
dfb 0
|
|
; Lay out a our rudimentary page:
|
|
jsr HGR
|
|
stz TEMPY
|
|
:newlin lda TEMPY
|
|
jsr HPOSN
|
|
ldy #0
|
|
:line lda TEMPY
|
|
and #$8
|
|
bne :lownyb
|
|
:hinyb tya
|
|
lsr
|
|
lsr
|
|
lsr
|
|
lsr
|
|
bra :draw
|
|
:lownyb tya
|
|
and #$0f
|
|
:draw asl
|
|
asl
|
|
asl
|
|
sta TEMP
|
|
lda TEMPY
|
|
and #$07
|
|
ora TEMP
|
|
tax
|
|
lda HgrHexFont,x
|
|
sta (HBAS),y
|
|
iny
|
|
cpy #35
|
|
bne :line
|
|
inc TEMPY
|
|
lda TEMPY
|
|
cmp #16
|
|
blt :newlin
|
|
; return values
|
|
sec ; no scrolloing
|
|
lda #0 ; 0 = number of lines (A:Y)
|
|
tay
|
|
rts
|
|
|
|
HgrDisplay
|
|
; Store current track to not interfere with other screens
|
|
lda DSTTRK
|
|
pha
|
|
; 144 lines (18 text lines * 8 graphic lines ea)
|
|
; buffer = 8192 bytes / 144 lines = 56 bytes ea
|
|
; OR NIB suggest 6656 / 144 lines = 46 bytes ea
|
|
stz DSTTRK
|
|
:nxttrk jsr ReadTrack
|
|
lda #16
|
|
sta :ycoord
|
|
jsr SETUPDATA
|
|
stz :count
|
|
lda #46
|
|
sta :bytes
|
|
:loop lda (DATA)
|
|
cmp #$FF
|
|
bne :skip
|
|
inc :count
|
|
:skip dec :bytes
|
|
bne :skip2
|
|
lda :ycoord
|
|
jsr HPOSN
|
|
ldy CURTRK
|
|
ldx #0
|
|
lda :count
|
|
beq :empty
|
|
:bits inx
|
|
lsr
|
|
bne :bits
|
|
:empty lda :plot,x
|
|
sta (HBAS),y
|
|
inc :ycoord
|
|
lda :ycoord
|
|
cmp #160
|
|
bge :botm
|
|
stz :count
|
|
lda #46
|
|
sta :bytes
|
|
:skip2 inc DATA
|
|
bne :loop
|
|
inc DATA+1
|
|
dec TEMP
|
|
bne :loop
|
|
:botm inc DSTTRK
|
|
lda DSTTRK
|
|
cmp #35
|
|
blt :nxttrk
|
|
; Restore current target track for other screens
|
|
pla
|
|
sta DSTTRK
|
|
rts
|
|
:ycoord dfb 0
|
|
:count dfb 0
|
|
:bytes dfb 0
|
|
:plot hex 000103070f1f3f7fff
|
|
|
|
HgrKeypress
|
|
cmp #"R"
|
|
beq :recal
|
|
cmp #"S"
|
|
beq :setup
|
|
:back jmp KeyboardWait
|
|
|
|
:recal lda #40
|
|
sta CURTRK ; This forces the recalibration
|
|
stz DSTTRK
|
|
:setup jmp SetupPage ; this redraws page and re-initializes, presumably, on a new disk
|
|
|
|
HgrHexFont ; Stolen from https://github.com/Michaelangel007/apple2_hgr_font_tutorial
|
|
hex 1C22322A26221C00 ; 0
|
|
hex 080C080808081C00 ; 1
|
|
hex 1C22201804023E00 ; 2
|
|
hex 3E20101820221C00 ; 3
|
|
hex 101814123E101000 ; 4
|
|
hex 3E021E2020221C00 ; 5
|
|
hex 3804021E22221C00 ; 6
|
|
hex 3E20100804040400 ; 7
|
|
hex 1C22221C22221C00 ; 8
|
|
hex 1C22223C20100E00 ; 9
|
|
hex 081422223E222200 ; A
|
|
hex 1E22221E22221E00 ; B
|
|
hex 1C22020202221C00 ; C
|
|
hex 1E22222222221E00 ; D
|
|
hex 3E02021E02023E00 ; E
|
|
hex 3E02021E02020200 ; F
|
|
|
|
*
|
|
* BUFFER COUNT interface
|
|
*
|
|
|
|
CountInit ; Returns with A:Y = max lines, C = scrolling
|
|
jsr PRINT
|
|
asc "(high bit must be set, only showing those bytes)"
|
|
dfb 0
|
|
; Set inbuf to zero (only counting $80, so $200-$2ff sufficient)
|
|
ldy #0
|
|
tya
|
|
:erase sta inbuf,y
|
|
iny
|
|
bne :erase
|
|
; Start counting
|
|
jsr ReadTrack
|
|
jsr SETUPDATA
|
|
ldy #0
|
|
:loop lda (DATA),y
|
|
asl ; times 2, we don't care about highbit
|
|
tax
|
|
inc inbuf,x
|
|
bne :skip
|
|
inc inbuf+1,x
|
|
:skip iny
|
|
bne :loop
|
|
inc DATA+1
|
|
dec TEMP
|
|
bne :loop
|
|
; Setup framework
|
|
lda #0 ; No lines
|
|
tay
|
|
sec ; No scrolling
|
|
rts
|
|
|
|
CountDisplay ; Called with A:Y = line
|
|
jsr PRINT
|
|
dfb $8D
|
|
dfb 14
|
|
asc " Low +0 +1 +2 +3 +4 +5 +6 +7 High",$8D
|
|
dfb 19
|
|
asc " ==== ==== ==== ==== ==== ==== ==== ====",$8D
|
|
dfb 0
|
|
|
|
ldy #$80
|
|
:next ldx #14
|
|
lda #" "
|
|
:tab jsr COUT
|
|
dex
|
|
bne :tab
|
|
tya
|
|
jsr PRHEX
|
|
lda #" "
|
|
jsr COUT
|
|
jsr COUT
|
|
:line lda #" " ; re-loading space due to loop construction
|
|
jsr COUT
|
|
tya
|
|
asl
|
|
tax
|
|
lda inbuf+1,x
|
|
jsr PRHEX
|
|
lda inbuf,x
|
|
jsr PRHEX
|
|
iny
|
|
tya
|
|
and #$07
|
|
bne :line
|
|
lda #" "
|
|
jsr COUT
|
|
jsr COUT
|
|
jsr COUT
|
|
jsr COUT
|
|
tya
|
|
dec
|
|
jsr PRHEX
|
|
jsr PRCR
|
|
cpy #0
|
|
bne :next
|
|
rts
|
|
|
|
CountKeypress ; Called with Acc = key
|
|
; Do Nothing, continue loop
|
|
jmp KeyboardWait
|
|
|
|
|
|
*
|
|
* TEST interface
|
|
*
|
|
|
|
TestInit
|
|
lda #>535
|
|
ldy #<535 ; Nice odd number of lines > 256
|
|
rts
|
|
|
|
TestDisplay
|
|
phy
|
|
pha
|
|
lda #_CLREOL
|
|
jsr COUT
|
|
pla
|
|
jsr PRHEX
|
|
pla
|
|
jsr PRHEX
|
|
jmp PRCR
|
|
|
|
TestKeypress
|
|
jmp KeyboardWait
|
|
|
|
|
|
*
|
|
* DISK II routines
|
|
*
|
|
|
|
ReadTrack
|
|
jsr PRINT
|
|
dfb _HOME,$8D,4,$88
|
|
asc "T="
|
|
dfb _PRBYTE
|
|
da DSTTRK
|
|
dfb 0
|
|
|
|
ldx SLOT16 ; Slot*16
|
|
lda MOTORON,x ; turn on drive
|
|
lda DRV0EN,x ; Drive #1
|
|
lda Q7L,x ; Q7 = Low and Q6 = Low => READ mode
|
|
lda Q6L,x
|
|
jsr ARMMOVE ; Go to our track (app init sets to 40, so first time this recalibrates)
|
|
; Fully read the track into buffer @ DATA
|
|
jsr SETUPDATA
|
|
ldy #0
|
|
:loop lda Q6L,x
|
|
bpl :loop
|
|
sta (DATA),y
|
|
iny
|
|
bne :loop
|
|
inc DATA+1
|
|
dec TEMP
|
|
bne :loop
|
|
lda MOTOROFF,x
|
|
rts
|
|
|
|
|
|
* Setup the data buffer
|
|
SETUPDATA LDA #>DATASTART
|
|
STA DATA+1
|
|
LDA #<DATASTART
|
|
STA DATA
|
|
LDA #>DATALEN
|
|
STA TEMP ; number of pages to load
|
|
RTS
|
|
|
|
* Print identifier and 4 and 4 encoded number
|
|
* Acc = character
|
|
* Output = " ?=" where ? is char in Acc
|
|
PRDATA PHA
|
|
LDA #" "
|
|
JSR COUT
|
|
PLA
|
|
JSR COUT
|
|
LDA #"="
|
|
JSR COUT
|
|
LDA (DATA),Y
|
|
SEC
|
|
ROL
|
|
INY
|
|
AND (DATA),Y
|
|
JMP PRHEX
|
|
|
|
* Output routine uses simple RLE type encoding
|
|
* High bit set = character;
|
|
* High bit clear =
|
|
* $00 = exit
|
|
* $01 = print byte from address
|
|
* $02-$7F = repeat next character
|
|
*
|
|
* There are two entry points:
|
|
* - PRINT = inline text being printed out; implicit PTR increment at start
|
|
* - PRINTP = print address passed in AX; no implicit PTR increment at start
|
|
|
|
PRINT PLA
|
|
STA PTR
|
|
PLA
|
|
STA PTR+1
|
|
JSR :MORE
|
|
LDA PTR+1
|
|
PHA
|
|
LDA PTR
|
|
PHA
|
|
RTS
|
|
|
|
PRINTP STA PTR+1
|
|
STX PTR
|
|
BRA :START
|
|
|
|
:MORE JSR INCPTR
|
|
:START LDX #1 ; Assume 1 char to be output
|
|
LDA (PTR)
|
|
BEQ :EXIT
|
|
BMI :SINGLE
|
|
CMP #1
|
|
BNE :REPEAT
|
|
JSR INCPTR
|
|
LDA (PTR)
|
|
STA PTR2
|
|
JSR INCPTR
|
|
LDA (PTR)
|
|
STA PTR2+1
|
|
LDA (PTR2)
|
|
JSR PRHEX
|
|
BRA :MORE
|
|
:REPEAT TAX
|
|
JSR INCPTR
|
|
LDA (PTR)
|
|
:SINGLE JSR COUT
|
|
DEX
|
|
BNE :SINGLE
|
|
BEQ :MORE
|
|
:EXIT RTS
|
|
|
|
INCPTR INC PTR
|
|
BNE :EXIT
|
|
INC PTR+1
|
|
:EXIT RTS
|
|
|
|
* Clear the data portion of the screen
|
|
* (Lines 3-22) and reposition to line 3.
|
|
|
|
CLRSCRN LDA #_HOME
|
|
JSR COUT
|
|
JSR PRCR
|
|
LDY #20
|
|
:1 JSR PRCR ; next line
|
|
LDA #_CLREOL
|
|
JSR COUT
|
|
DEY
|
|
BNE :1
|
|
LDA #_HOME
|
|
JSR COUT
|
|
JSR PRCR ; move to row 3
|
|
JMP PRCR
|
|
|
|
* Read a byte
|
|
* If invalid, carry is set (anything NOT 0-9,A-F is invalid)
|
|
|
|
READBYTE JSR READHEX
|
|
BCS :EXIT
|
|
ASL
|
|
ASL
|
|
ASL
|
|
ASL
|
|
STA TEMP
|
|
JSR READHEX ; carry falls through to exit
|
|
ORA TEMP
|
|
:EXIT RTS
|
|
|
|
READHEX JSR GETCH
|
|
JSR COUT
|
|
CMP #"9"+1
|
|
BCC :NUMERIC
|
|
CMP #"F"+1
|
|
BCC :ALPHA
|
|
:BAD SEC
|
|
RTS
|
|
:NUMERIC SEC
|
|
SBC #"0"
|
|
BVS :BAD
|
|
:GOOD CLC
|
|
RTS
|
|
:ALPHA SEC
|
|
SBC #"A"
|
|
BVS :BAD
|
|
ADC #10
|
|
:GOOD2 CLC
|
|
RTS
|
|
|
|
* Move the Disk II arm:
|
|
|
|
ARMMOVE LDA CURTRK
|
|
CMP DSTTRK
|
|
BNE :MOVE
|
|
:THERE LDX SLOT16 ; restore standard slot
|
|
RTS
|
|
:MOVE PHP
|
|
LDA #0
|
|
ROL ; direction from CMP
|
|
TAY
|
|
LDA CURTRK
|
|
LSR
|
|
TYA
|
|
ROL ; odd/even from track
|
|
ASL ; times 2
|
|
TAY
|
|
LDA ARMTABLE,Y
|
|
JSR ARMPHASE
|
|
LDA ARMTABLE+1,Y
|
|
JSR ARMPHASE
|
|
PLP
|
|
BCS :SUB1
|
|
:ADD1 INC CURTRK
|
|
BRA ARMMOVE
|
|
:SUB1 DEC CURTRK
|
|
BRA ARMMOVE
|
|
|
|
ARMPHASE ORA SLOT16
|
|
TAX
|
|
LDA PHASEON,X
|
|
LDA #$56
|
|
JSR DELAY
|
|
LDA PHASEOFF,X
|
|
RTS
|
|
|
|
* Standard 16 sector address prologue
|
|
PROLOGUE HEX D5AA96
|
|
|
|
* Phase table for moving arm
|
|
* Grouped by inward/outward movement, odd/even track
|
|
* To move the arm, two phases need to be triggered
|
|
ARMTABLE HEX 0204
|
|
HEX 0600
|
|
HEX 0604
|
|
HEX 0200
|
|
|
|
* ProDOS QUIT parameter tables
|
|
QUITPARM DFB 4 ; 4 parameters
|
|
DFB 0 ; 0 is the only quit type
|
|
DA 0 ; reserved
|
|
DFB 0 ; reserved
|
|
DA 0 ; reserved
|
|
|
|
ProgramEnd
|