4live/src/4live.a

653 lines
15 KiB
Plaintext

;
; 4LIVE
; a 4am & san inc hack
;
!cpu 6502
*=$8000
;
!addr WNDLFT = $20
!addr WNDWDTH = $21
!addr WNDTOP = $22
!addr WNDBTM = $23
!addr CH = $24
!addr CV = $25
!addr GBASL = $26
!addr GBASH = $27
!addr BASL = $28
!addr BASH = $29
!addr BAS2L = $2A
!addr BAS2H = $2B
!addr KSWL = $38
!addr KSWH = $39
!addr GETIOB = $3E3
!addr RECONNECTDOS = $3EA
!addr WARMDOS = $3D0
!addr DOSBASE = $3D2
!addr FILEMAN = $3D6
!addr GETPARM = $3DC
!addr KBD = $C000
!addr STROBE = $C010
!addr ROMIN = $C081
!addr LCBANK2 = $C083
!addr GBASCALC = $F847
!addr BASCALC = $FBC1
!addr SCROLL = $FC70
!addr WAIT = $FCA8
!addr KEYIN = $FD1B
!addr COUT = $FDED
;private arbitrary addresses
!addr ZMANPARML = $40
!addr ZMANPARMH = $41
!addr DOSBUFL = $42
!addr DOSBUFH = $43
!addr OPSRCL = $44
!addr OPSRCH = $45
!addr OPDSTL = $46
!addr OPDSTH = $47
HOTKEY = $80 ; CTRL-@
IMPORTKEY = $89 ; CTRL-I
CLEARKEY = $8E ; CTRL-N
;constants
LTARROW = $88
UPARROW = $8B
RETURN = $8D
RTARROW = $95
ESC = $9B
WIDTH = 40
HEIGHT = 24
IOBSLOT = 1
IOBDRIVE = 2
NEXTFILE = 36
PARMRANGE = 6
PARMFILE = 8
PARMWORK = 12
NAMELEN = 30
CREATEFILE = 0
OPENEXISTING = 1
SPECIAL = 8
CMDOPEN = 1
CMDCLOSE = 2
CMDREAD = 3
CMDWRITE = 4
READRANGE = 2
;
Install
;find a free DOS buffer
ldy #0
sty DOSBUFL
lda DOSBASE
;check for DiversiDOS
cmp #$BF
bne +
lda LCBANK2
lda LCBANK2
lda #$DD
;back to regular DOS
+ sta DOSBUFH
!byte $2C ;mask LDY
- ldy #NEXTFILE
lda (DOSBUFL), y
tax
iny
lda (DOSBUFL), y
stx DOSBUFL
sta DOSBUFH
;set filename pointer in MLI request packet
stx FileName
sta FileName + 1
;check for empty filename (indicates free buffer)
ldy #0
lda (DOSBUFL), y
bne -
;get file manager parameter list
jsr GETPARM
sty ZMANPARML
sta ZMANPARMH
sty MANPARM + 1
sta MANPARM + 2
;copy DOS buffer pointers to file manager parameter list
lda #NAMELEN
sta OPDSTL
lda #PARMWORK
sta OPDSTH
ldx #(6 - 1)
- ldy OPDSTL
lda (DOSBUFL), y
ldy OPDSTH
sta (ZMANPARML), y
inc OPDSTL
inc OPDSTH
dex
bpl -
;set input name
ldy #(NAMELEN - 1)
lda #$A0
- cpy #(FileName_e - FileName_b)
bcs +
lda FileName_b, y
+ sta (DOSBUFL), y
dey
bpl -
;open source file and read it if available
jsr OpenReadFile
bcs +
lda #0
sta gClearOnFirstKeypress
+ lda SaveCH
sta MyCH
lda SaveCV
sta MyCV
;switch to write mode for future accesses
inc ReadWriteCmd ;lda WRITECMD / sta ReadWriteCmd
lda ROMIN
;display the welcome message, now that we're finally done
ldy #0
beq +
- jsr COUT
+ iny
lda _WelcomeMessage-1,y
bne -
lda #<GlobalKeyboardHook
sta KSWL
lda #>GlobalKeyboardHook
sta KSWH
jsr RECONNECTDOS
jmp WARMDOS
_WelcomeMessage
!scrxor $80, $8D, "4LIVE READY. PRESS CTRL-", HOTKEY + $40, " TO ACTIVATE.", $8D, 0
;support enhanced flashing cursor while waiting for key, if available
;it works by passing to the routine the character under the cursor
;the ROM toggles between that character and the Delete character
GetKey
ldy CH
lda (BASL), y
GlobalKeyboardHook
;let DOS handle initial cursor
jsr KEYIN
;are we on?
cmp #HOTKEY
;yes -> branch
beq +
;no -> return to DOS
rts
+
txa
pha
;first, scroll the edit buffer onto the screen
;(this also swaps the current screen contents out so we can restore it later)
jsr ScrollEditBufferIn
;do the thing
lda #0 ;0=false, non-0=true
sta gIsDirty
jsr EditorMode
;scroll the edit buffer out and the original screen back in
jsr ScrollEditBufferOut
;save to disk (if necessary)
lda gIsDirty
beq +
jsr SaveFile
+
pla
tax
;lather, rinse, repeat
jmp GetKey
ScrollEditBufferIn
;save real cursor position and use saved edit buffer cursor position instead
jsr SwapCoords
lda #<StatusLine
sta _in+1
lda #>StatusLine
sta _in+2
lda #HEIGHT
sta LINE
;copy last line on screen to temporary buffer
-- ldy #(WIDTH - 1)
- lda $07D0, y
sta LineBuffer, y
dey
bpl -
;copy each line on screen down to next line (leaves top line untouched)
jsr ScrollTextScreenDown
;copy last line of edit buffer to top line on screen
ldy #(WIDTH - 1)
_in lda $FFFF, y ;self-modified above and below
sta $0400, y
dey
bpl _in
;copy temporary buffer to last line in edit buffer
lda _in+1
sta _in2+1
lda _in+2
sta _in2+2
ldy #(WIDTH -1)
- lda LineBuffer, y
_in2 sta $FFFF, y ;self-modified above
dey
bpl -
;animation delay
jsr Delay
;set up copy addresses for next line
lda _in+1
sec
sbc #WIDTH
sta _in+1
bcs +
dec _in+2
+ dec LINE
bne --
rts
ScrollEditBufferOut
;restore real cursor position
jsr SwapCoords
lda #<EditBuffer
sta _out+1
lda #>EditBuffer
sta _out+2
lda #HEIGHT
sta LINE
;copy first line on screen to temporary buffer
-- ldy #(WIDTH - 1)
- lda $0400, y
sta LineBuffer, y
dey
bpl -
;copy each line on screen up to next line (leaves last line empty)
jsr SCROLL
;copy first line of edit buffer to bottom line of screen
ldy #(WIDTH - 1)
_out lda $FFFF, y ;self-modified above and below
sta $07D0, y
dey
bpl _out
;copy temporary buffer to first line in edit buffer
lda _out+1
sta _out2+1
lda _out+2
sta _out2+2
ldy #(WIDTH - 1)
- lda LineBuffer, y
_out2 sta $FFFF, y ;self-modified above
dey
bpl -
;animation delay
jsr Delay
;set up copy addresses for next line
lda _out+1
clc
adc #WIDTH
sta _out+1
bcc +
inc _out+2
+ dec LINE
bne --
rts
ScrollTextScreenDown
ldx #$16
- lda TextCalcLo, x
sta _a+1
lda TextCalcLo+1, x
sta _b+1
lda TextCalcHi, x
sta _a+2
lda TextCalcHi+1, x
sta _b+2
ldy #$27
_a lda $FFFF, y ; self-modified, above
_b sta $FFFF, y ; self-modified, above
dey
bpl _a
dex
bpl -
rts
Delay
lda #1
jmp WAIT
;swap real X/Y with virtual X/Y
;and recalculate screen position
SwapCoords
ldx #(6 - 1)
- ldy WNDLFT, x
lda MyWNDLFT, x
sta WNDLFT, x
tya
sta MyWNDLFT, x
dex
bpl -
jmp BASCALC
EditorMode
ldy CH
lda (BASL), y
jsr KEYIN
cmp #HOTKEY
beq HandleKeyExit
cmp #ESC
beq HandleKeyExit
ldx #1
stx gIsDirty
cmp #IMPORTKEY
beq HandleKeyImportScreen
cmp #CLEARKEY
beq HandleKeyClearScreen
cmp #LTARROW
beq HandleKeyLineLeft
cmp #UPARROW
beq HandleKeyLineUp
cmp #RTARROW
beq HandleKeyLineRight
;print anything that isn't a special key
;wrap around screen position when we hit edges
pha
lda gClearOnFirstKeypress
beq +
jsr ClearScreen
lda #0
sta gClearOnFirstKeypress
+ pla
jsr COUT
lda CV
eor #(HEIGHT - 1) ;zero on match
bne EditorMode
SetRow
sta CV
SetRow1
lda CV
jsr BASCALC
bcc EditorMode ;always
HandleKeyExit
rts
HandleKeyLineLeft
dec CH
bpl SetRow1
lda #(WIDTH - 1)
SetColumn
sta CH
bpl SetRow1 ;always
HandleKeyLineUp
dec CV
bpl SetRow1
lda #(HEIGHT - 2)
bne SetRow ;always
HandleKeyLineRight
inc CH
lda CH
eor #WIDTH ;zero on match
bne SetRow1
beq SetColumn ;always
HandleKeyImportScreen
lda #<(EditBuffer + WIDTH)
sta OPSRCL
lda #>(EditBuffer + WIDTH)
sta OPSRCH
ldx #(HEIGHT - 2)
;use graphics function to not disturb text state
-- txa
jsr GBASCALC
ldy #(WIDTH - 1)
- lda (OPSRCL), y
sta (GBASL), y
dey
bpl -
lda OPSRCL
clc
adc #WIDTH
sta OPSRCL
bcc +
inc OPSRCH
+ dex
bpl --
jmp EditorMode
HandleKeyClearScreen
jsr ClearScreen
jmp EditorMode
ClearScreen ; does not clear status line
ldx #(HEIGHT - 2)
-- lda TextCalcLo, x
sta _c+1
lda TextCalcHi, x
sta _c+2
ldy #(WIDTH - 1)
lda #$A0
_c sta $FFFF, y ; self-modified, above
dey
bpl _c
dex
bpl --
rts
OpenReadFile
lda LCBANK2
lda LCBANK2 ;support DiversiDOS
jsr GETIOB
sty OPSRCL
sta OPSRCH
ldy #IOBSLOT
lda (OPSRCL), y
lsr
lsr
lsr
lsr
sta FileSlot
iny ;ldy #IOBDRIVE
lda (OPSRCL), y
sta FileDrive
ldx #OPENEXISTING
jsr OpenCommon
bcs OpenRet
ReadFile
WriteFile
jsr DOSMLI
!byte ReadMLI_e - ReadMLI_b
ReadMLI_b
ReadWriteCmd
!byte CMDREAD
!byte READRANGE
!word 0 ;record number
!word 0 ;offset
WriteSize
!word -1 ;number of bytes
!word LoadSaveStart ;buffer
ReadMLI_e
CloseFile
jsr DOSMLI
!byte CloseMLI_e - CloseMLI_b
CloseMLI_b
!byte CMDCLOSE
CloseMLI_e
OpenRet
rts
OpenCommon
jsr DOSMLI
!byte OpenMLI_e - OpenMLI_b
OpenMLI_b
!byte CMDOPEN
!byte 0 ;unused
!word 0 ;variable records
!byte 0 ;any volume
FileDrive
!text "Q" ;self-modified
FileSlot
!text "Q" ;self-modified
!byte SPECIAL ;file type for when we save
FileName
!text "4s" ;self-modified
OpenMLI_e
rts
SaveFile
lda CH
sta SaveCH
lda CV
sta SaveCV
CreateWriteFile
ldx #CREATEFILE
jsr OpenCommon
bcs OpenRet
lda #<(LoadSaveEnd - LoadSaveStart)
sta WriteSize
lda #>(LoadSaveEnd - LoadSaveStart)
sta WriteSize + 1
bcc WriteFile ;always
;first byte fetched is number of byte to follow,
;copy parameters to file manager parameter list,
;and then dispatch the request
DOSMLI
pla
tay
pla
sta OPSRCH
iny
sty OPSRCL
bne +
inc OPSRCH
+ ldy #0
lda (OPSRCL), y
tay
- lda (OPSRCL), y
dey
MANPARM
sta $34f3, y ;self-modified
bne -
lda (OPSRCL), y
clc
adc OPSRCL
tay
lda OPSRCH
adc #0
pha
tya
pha
jmp FILEMAN
FileName_b
!scrxor $80, $DF, "4LIVE DATA"
FileName_e
MyWNDLFT
!byte 0
MyWNDWDTH
!byte WIDTH
MyWNDTOP
!byte 0
MyWNDBTM
!byte HEIGHT
MyCH
!byte 0
MyCV
!byte 0
LINE
!byte 0
gIsDirty
!byte 0
gClearOnFirstKeypress
!byte 1
TextCalcHi
!byte $04, $04, $05, $05, $06, $06, $07, $07
!byte $04, $04, $05, $05, $06, $06, $07, $07
!byte $04, $04, $05, $05, $06, $06, $07, $07
TextCalcLo
!byte $00, $80, $00, $80, $00, $80, $00, $80
!byte $28, $A8, $28, $A8, $28, $A8, $28, $A8
!byte $50, $D0, $50, $D0, $50, $D0, $50, $D0
LoadSaveStart
SaveCH
!byte 0 ;loaded from file if exists
SaveCV
!byte 0 ;loaded from file if exists
EditBuffer ;lines are stored sequentially, not like text page in memory
!fill WIDTH * 8, $A0
!scrxor $80, " 4LIVE by 4am & san inc "
!fill WIDTH, $A0
!scrxor $80, " Revision 01 / Serial number 161031 "
!fill WIDTH * 2, $A0
!scrxor $80, " https://github.com/a2-4am/4live "
!fill WIDTH * 9, $A0
LoadSaveEnd
StatusLine ;must be exactly WIDTH bytes
;status line
!fill (WIDTH - 5), $20
!scrxor $80, "4LIVE"
LineBuffer ;used during scrolling
!fill WIDTH, 0