apple2_hgrbyte/src/hgr.byte.s

557 lines
15 KiB
ArmAsm

; Merlin32
CONFIG_PRODOS = 1
; HGR Byte Inspector
; https://github.com/Michaelangel007/apple2_hgrbyte/
;
; Michael Pohoreski
; Version 17
;
; TL:DR;
; IJKL to move
; Ctrl-IJKL to move to edges
; 0..9, A..F enter nibble into cursor byte
;
; Keys:
;
; ESC Quit
; G Toggle fullscreen
;
; i Move cursor up
; j Move cursor left
; k Move cursor right
; l Move cursor down
;
; I Move cursor up
; J Move cursor left
; K Move cursor right
; L Move cursor down
;
; ^I Move cursor to col 0
; ^J Move cursor to col 39
; ^K Move cursor to row 0
; ^L Move cursor to row 191
; RET Center cursor
;
; 0..9 "Append" hex nibble to cursor byte
; A..F
;
; ! Toggle bit 0
; @ Toggle bit 1
; # Toggle bit 2
; $ Toggle bit 3
; % Toggle bit 4
; ^ Toggle bit 5
; & Toggle bit 6
; * Toggle bit 7 (high bit)
; SPC Toggle high bit of byte (bit 7)
; ( Set byte to $FF (Shift-9)
; ) Clear byte to $00 (Shift-0)
; ` Flip all bits
; ~ Flip all bits
;
; , Shift byte left (with zero)
; . Shift byte right (with one )
; < Shift byte left (with zero)
; > Shift byte right (with one )
; [ Rotate byte left
; ] Rotate byte right
;
; - Save cursor byte to temporary
; = Set cursor byte from temporary
GBASL = $26 ; 16-bit pointer to start of D/HGR scanline
GBASH = $27
WIDTH = 40 ; HGR
CH = $24 ; text cursor column
CV = $25 ; text cursor row
ROW_20 = $0550 ; VTAB 21 TEXT address
ROW_21 = $06D0 ; VTAB 22 TEXT address
ROW_22 = $0750 ; VTAB 23 TEXT address
ROW_23 = $07D0 ; VTAB 24 TEXT address
HPOSN = $F411 ; A=row, Y,X=col update GBASL GBASH
TABV = $FB5B ; A=row, ALL STA $25, JMP $FC22
VTAB = $FC22 ; $25=row //e LDA $25, STA$28
HOME = $FC58
COUT = $FDED
PR_HEX = $FDD3
PRBYTE = $FDDA
KEYBOARD = $C000
SW_SET40COL = $C00C ; 40-col mode
KEYSTROBE = $C010
TXTCLR = $C050 ; Mode Graphics
MIXCLR = $C052 ; Full screen
MIXSET = $C053 ; Split screen
PAGE1 = $C054
HIRES = $C057 ; Mode HGR
lastkey = $F9
cursor_row = $E2 ; used by Applesoft HGR.row
cursor_org = $FA ; When cursor is saved
cursor_tmp = $FB ; Flashing cursor byte
cursor_val = $FC ; Current byte under cursor
flags = $FD ;
temp = $FE
cursor_col = $FF
FLAG_FULL = $01 ; == $1 -> $C052 MIXCLR
; ; == $0 -> $C053 MIXSET
HGRPAGE = $E6 ; used by Applesoft HGR.page
__MAIN = $0900
DO CONFIG_PRODOS
ORG __MAIN
ELSE
ORG __MAIN - 4
DW __MAIN
DW __END-*-2
FIN
HgrByte
LDA #17 ; Version
STA SW_SET40COL ; Version 17 force 40-col mode
BIT PAGE1 ; Page 1
BIT TXTCLR ; not text, but graphics
BIT MIXSET ; Split screen text/graphics
BIT HIRES ; HGR, no GR
LDX #0 ; also used by PrintFooter
STX flags
STX cursor_col
STX cursor_row
STX cursor_org
STX GBASL
LDA #$20
STA GBASH
STA HGRPAGE
PrintFooter
LDA TextFooter, X
BEQ _Center ; Default to center of screen
STA ROW_21,X ; 4 line text window, 2nd row
INX
BNE PrintFooter ; (almost) always
; Funcs that JMP to GetByte before GotKey()
; Funcs that JMP to PutByte after GotKey()
_Screen ; Toggle mixed/full screen
LDA flags ; A = %????_????
AND #FLAG_FULL ; A = %0000_000f
TAX ; f=0 f=1
STA MIXCLR,X ; C052 C053
LDA flags ; FULL MIX
EOR #FLAG_FULL ; mode is based on old leading edge
STA flags ; not new trailing edge
BRA FlashByte
_HighBit
EOR #$80
BRA PutByte
_MoveL DEC cursor_col
BPL GetByte
_MoveR INC cursor_col
LDA cursor_col
CMP #WIDTH
BCC GetByte ; intentional fall into _EdgeR
_EdgeR LDA #WIDTH-1
DB $2C ; BIT $ABS skip next instruction
_EdgeL LDA #0
STA cursor_col
BPL GetByte ; always
_MoveU DEC cursor_row
LDA cursor_row
CMP #$FF
BNE GetByte ; INTENTIONAL fall into if Y < 0
_MoveD INC cursor_row
LDA cursor_row
CMP #192
BCC GetByte ; intentional fall into
_EdgeD LDA #$BF
DB $2C ; BIT $ABS skip next instruction
_EdgeU LDA #00
STA cursor_row
ADC #1
BNE GetByte ; always
_Center
LDA #WIDTH/2
STA cursor_col
LDA #192/2
STA cursor_row ; intentional fall into GetByte
GetByte ; Cursor position changed
LDY #0 ; Update pointer to screen
LDX #0
LDA cursor_row
JSR HPOSN ; A=row, Y,X=col X->E0 Y->E1
JSR GetCursorByte
PutByte
STA cursor_val ; current value
STA cursor_tmp ; flashing cursor
JSR DrawStatus
FlashByte
JSR FlashCursorByte
GetKey
LDA KEYBOARD
BPL FlashByte
STA KEYSTROBE
AND #$7F ; Force ASCII
STA lastkey
CMP #'0' ; key < '0'
BCC TestHex
CMP #'9'+1 ; key < '9'+1
BCC Nibble
TestHex
CMP #'A'
BCC LoadKeys
CMP #'F'+1
BCC Nibble
LoadKeys
LDX #nKeys
FindKey
DEX
BMI FlashByte
CMP aKeys, X
BNE FindKey
GotKey
; If code doesn't fit within +/-127 bytes
; LDA aFuncHi, X
LDA #>__MAIN ; FuncAddressHi
PHA
LDA aFuncLo, X ; FuncAddressLo
PHA
LDA cursor_val ; Last displayed byte may be cursor_tmp
JSR SetCursorByte ; restore current val in case cursor moves
; Also pre-load for ROL/R SHL/R
LDX #0 ; for Toggle Bit #
_Exit RTS ; And call function assigned to key
; To BRUN under DOS.3 change above RTS to
; RTS
;_Exit JMP $3D0 ; DOS 3.3 Warmstart vector
; Functions starting with _ are invoked via keys
_ByteFF
LDA #$FF
BNE PutByte ; always
_Byte00
LDA #$00
BEQ PutByte ; always
_FlipByte
LDX #$FF
BNE PutBits
_Rol CMP #$80 ; C=a A=%abcd_efgh
_SHL1 ROL ; C=b A=%bcde_fgha C<-bit7, bit0<-C
BRA PutByte ; force branch always
_SHR1 ORA #$01 ; Force C=1 via ROR (SHR, OR #$80)
; Intentional fall into _Ror
; Using LSR instead of ROR to save a byte
; 8 Byte version
; CLC
; ROR
; BCC PutByte
; ORA #$80
; BCS PutByte
_Ror LSR ; C=h A=%0abc_defg 0->bit7, bit0->C
BCC PutByte
ORA #$80
BCS PutByte ; always
_ShiftL ASL ; C=a A=%bcde_fgh0
DB $A2 ; skip next LSR instruction; LDX dummy imm val
_ShiftR LSR ; C=h A=%0abc_defg
BRA PutByte
_Bit7 INX ; intentional fall into
_Bit6 INX
_Bit5 INX
_Bit4 INX
_Bit3 INX
_Bit2 INX
_Bit1 INX
_Bit0 INX
TAY ; save cursor_val
SEC ;
LDA #0 ; X=? A=0 C=1
TogBit ROL
DEX
BNE TogBit
TAX
TYA ; load cursor_val
; common _Bit# code
PutBits STX temp
EOR temp
GotoPutByte
BRA PutByte ; code is too far to directly branch
_SaveByte
STA cursor_org ; intentional fall into
_LoadByte
; *******************
; NOTE: Above code must fit on 1 page!
; IF _LoadByte overflows the initial page then
; LDA aFuncLo PHA RTS
; will have unpredictable results!
; ********************
ERR *-1/$9FF ; Merlin: Error if PC > $9FF
LDA cursor_org
CLC
BCC GotoPutByte ; always
Nibble
LDY #3
CursorSHL
ASL cursor_val
DEY
BPL CursorSHL
LDA lastkey
CMP #$41
BCC Digit
SBC #7 ; $41 - 6 - (C=1) = $3A
Digit
AND #$0F ; Key to Hex
CLC
ADC cursor_val
BCC GotoPutByte ; always
TextFooter
; "X=## Y=## $=####:## %%%%%%%%~%%%%%%%%"
ASC " SAVE:?? 76543210 "
INV "12345678" ;1-8 INVERSE
DB $00
; ------------------------------------------------------------------------
DrawStatus
LDA #0 ; Cursor.X = 0
STA CH
LDA #20 ; Cursor.Y = Top of 4 line split TEXT/HGR window
JSR TABV ; update CV
PrintStatus
LDA #'X'+$80 ; X=## Y=## $=####:##
JSR COUT
LDA cursor_col
JSR PR_HEX
LDA #' '+$80
JSR COUT
LDA #'Y'+$80
JSR COUT
LDA cursor_row
JSR PR_HEX
LDA #' '+$80
JSR COUT
LDA #'$'+$80
JSR COUT
LDA GBASH
JSR PR_HEX
LDA GBASL
CLC
ADC cursor_col
JSR PRBYTE
LDA #':'+$80
JSR COUT
LDA cursor_val
JSR PRBYTE
LDA #' '+$80
JSR COUT
ReverseByte
LDX #8
LDA cursor_val
STA temp
ReverseBit
ASL temp
ROR
DEX
BNE ReverseBit
STA temp
PHA ; save reverse byte
LDX #8
PrintBitsNormal
LDA temp
JSR Bit2Asc
ROR temp
DEX
BNE PrintBitsNormal
LDA #'~'+$80
JSR COUT
LDX #8
LDA cursor_val
PrintBitsReverse
TAY
JSR Bit2Asc
TYA
LSR
DEX
BNE PrintBitsReverse
LDA #'$'+$80
JSR COUT
PLA ; restore reverse byte
JSR PRBYTE
LDA cursor_org ; X=0
PHA
LSR
LSR
LSR
LSR
JSR NibToInvTxt
PLA
; Display nibble as inverse text
; 0 -> '0' $30
; 9 -> '9' $39
; A -> ^A $01
; F -> ^F $06
NibToInvTxt
AND #$F
ORA #'0'+$00 ; ASCII: +$80
CMP #'9'+$01 ; ASCII: +$81
BCC PrintSave
SBC #$39 ; C=1, $3A ':' -> $01 'A', $3F '?' -> $06
PrintSave
STA ROW_21+17,X
INX
RTS
Bit2Asc
AND #$01 ; 0 -> B0
BEQ FlipBit
LDA #$81 ; 1 -> 31
FlipBit
EOR #$B0
JMP COUT
; A = byte
GetCursorByte
LDY cursor_col
LDA (GBASL),Y
STA cursor_val
SetCursorByte
LDY cursor_col
STA (GBASL),Y
RTS
FlashCursorByte
LDA cursor_tmp
EOR #$FF
STA cursor_tmp
JMP SetCursorByte
; Keys are searched in reverse order
; Sorted by least used to most used
aKeys
DB '[' & $1F ; _Exit ESC Quit
ASC 'g' ; _Screen G Toggle fullscreen
ASC 'G' ; _Screen G Toggle fullscreen
DB 'H' & $1F ; _MoveL <- Ctrl-H $08
DB 'U' & $1F ; _MoveR -> Ctrl-U $15
DB 'I' & $1F ; _EdgeU ^I Ctrl-I $09 Move cursor to row 0
DB 'J' & $1F ; _EdgeL ^J Ctrl-J $0A Move cursor to col 0
DB 'K' & $1F ; _EdgeD ^K Ctrl-K $0B Move cursor to row 191
DB "L" & $1F ; _EdgeR ^L Ctrl-L $0C Move cursor to col 39
DB "M" & $1F ; _Center Center cursor
ASC 'i' ; _moveU Move cursor Up
ASC 'j' ; _moveL Move cursor Left
ASC 'k' ; _MoveD Move cursor Down
ASC 'l' ; _MoveR Move cursor Right
ASC 'I' ; _moveU Move cursor Up
ASC 'J' ; _moveL Move cursor Left
ASC 'K' ; _MoveD Move cursor Down
ASC 'L' ; _MoveR Move cursor Right
ASC '!' ; _Bit0 Toggle bit 0
ASC '@' ; _Bit1 Toggle bit 1
ASC '#' ; _Bit2 Toggle bit 2
ASC '$' ; _Bit3 Toggle bit 3
ASC '%' ; _Bit4 Toggle bit 4
ASC '^' ; _Bit5 Toggle bit 5
ASC '&' ; _Bit6 Toggle bit 6
ASC '*' ; _Bit7 Toggle bit 7
ASC ' ' ; _HighBit Toggle high bit of byte (bit 7)
ASC '(' ; _ByteFF Set byte to FF (Shift-9)
ASC ')' ; _Byte00 Set byte to 00 (Shift-0)
ASC '`' ; _FlipByte Toggle all bits
ASC '~' ; _FlipByte
ASC ',' ; _ShiftL (with zero)
ASC '<' ; _ShiftL (with one )
ASC '.' ; _ShiftR (with zero)
ASC '>' ; _ShiftR (with one )
ASC '[' ; _Rol
ASC ']' ; _Ror
ASC '-' ; _SaveByte Save cursor byte
ASC '=' ; _LoadByte Load cursor byte
eKeys
nKeys = eKeys - aKeys ;
; Table of function pointers
; *Note*: Must match aKeys order!
aFuncLo
DB <_Exit -1 ; ESC
DB <_Screen -1 ; g
DB <_Screen -1 ; G
DB <_MoveL -1 ; <-
DB <_MoveR -1 ; ->
DB <_EdgeU -1 ; ^I
DB <_EdgeL -1 ; ^J
DB <_EdgeD -1 ; ^K
DB <_EdgeR -1 ; ^L
DB <_Center -1 ; RET
DB <_MoveU -1 ; 'i'
DB <_MoveL -1 ; 'j'
DB <_MoveD -1 ; 'k'
DB <_MoveR -1 ; 'l'
DB <_MoveU -1 ; 'I'
DB <_MoveL -1 ; 'J'
DB <_MoveD -1 ; 'K'
DB <_MoveR -1 ; 'L'
DB <_Bit0 -1 ; '1'
DB <_Bit1 -1 ; '2'
DB <_Bit2 -1 ; '3'
DB <_Bit3 -1 ; '4'
DB <_Bit4 -1 ; '5'
DB <_Bit5 -1 ; '6'
DB <_Bit6 -1 ; '7'
DB <_Bit7 -1 ; '8'
DB <_HighBit -1 ; SPC
DB <_ByteFF -1 ; '('
DB <_Byte00 -1 ; ')'
DB <_FlipByte-1 ; '`'
DB <_FlipByte-1 ; '~' not a dup mistake
DB <_ShiftL -1 ; `,`
DB <_SHL1 -1 ; `<`
DB <_ShiftR -1 ; `.`
DB <_SHR1 -1 ; `>`
DB <_Rol -1 ; '['
DB <_Ror -1 ; ']
DB <_SaveByte-1 ; '='
DB <_LoadByte-1 ; '-'
__END ; Needed for DOS 3.3