diff --git a/desk.acc/show.text.file/a2d.inc b/desk.acc/show.text.file/a2d.inc index 7cc04fc..77ffcb0 100644 --- a/desk.acc/show.text.file/a2d.inc +++ b/desk.acc/show.text.file/a2d.inc @@ -214,3 +214,25 @@ A2D_CWS_SCROLL_NORMAL := A2D_CWS_SCROLL_ENABLED | A2D_CWS_SCROLL_THUMB | A2D_CW .byte .strlen(str) data: .byte str .endmacro + + +;;; DeskTop Internals + + ;; These are DeskTop internals, but it appears there is no + ;; API for getting the selected file. + file_selected := $DF21 ; 0 if no selection, 1 otherwise + path_index := $DF20 ; index of selected window (used to get prefix) + path_table := $DFB3 ; window address table + ;; each entry is 65 bytes long + ;; each entry is length-prefixed path string (no trailing /) + file_index := $DF22 ; index of selected file (global, not w/in window) + file_table := $DD9F ; file address table + ;; each entry is 27 bytes long + ;; .byte ?? + ;; .byte ?? + ;; .byte type/icon (bits 4,5,6 clear = directory) + ;; .word iconx (pixels) + ;; .word icony (pixels) + ;; .byte ?? + ;; .byte ?? + ;; .byte len, name (length-prefixed, spaces before/after; 17 byte buffer) diff --git a/desk.acc/show.text.file/dhr.s b/desk.acc/show.text.file/dhr.s new file mode 100644 index 0000000..fe43a90 --- /dev/null +++ b/desk.acc/show.text.file/dhr.s @@ -0,0 +1,439 @@ + .setcpu "65C02" + .org $800 + + .include "../../inc/prodos.inc" + .include "../../inc/auxmem.inc" + .include "a2d.inc" + + ;; Big questions: + ;; * How can we hide/show the cursor on demand? + ;; * Can we trigger menu redraw? (if not, need to preserve for fullscreen) + +start: jmp copy2aux + +save_stack:.byte 0 + +;;; Copy $800 through $13FF (the DA) to aux +.proc copy2aux + tsx + stx save_stack + sta RAMWRTON + ldy #0 +src: lda start,y ; self-modified +dst: sta start,y ; self-modified + dey + bne src + sta RAMWRTOFF + inc src+2 + inc dst+2 + sta RAMWRTON + lda dst+2 + cmp #$14 + bne src +.endproc + +call_main_trampoline := $20 ; installed on ZP, turns off auxmem and calls... +call_main_addr := call_main_trampoline+7 ; address patched in here + +;;; Copy the following "call_main_template" routine to $20 +.scope + sta RAMWRTON + sta RAMRDON + ldx #(call_main_template_end - call_main_template) +loop: lda call_main_template,x + sta call_main_trampoline,x + dex + bpl loop + jmp call_init +.endscope + +.proc call_main_template + sta RAMRDOFF + sta RAMWRTOFF + jsr $1000 ; overwritten (in zp version) + sta RAMRDON + sta RAMWRTON + rts +.endproc +call_main_template_end: ; can't .sizeof(proc) before declaration + ;; https://github.com/cc65/cc65/issues/478 + +.proc call_init + ;; run the DA + jsr init + + ;; tear down/exit + sta ALTZPON + lda LCBANK1 + lda LCBANK1 + sta RAMRDOFF + sta RAMWRTOFF + ldx save_stack + txs + rts +.endproc + +;;; ================================================== +;;; ProDOS MLI calls + +.proc open_file + jsr copy_params_aux_to_main + sta ALTZPOFF + MLI_CALL OPEN, open_params + sta ALTZPON + jsr copy_params_main_to_aux + rts +.endproc + + +.proc read_file + jsr copy_params_aux_to_main + sta ALTZPOFF + MLI_CALL READ, read_params + sta ALTZPON + jsr copy_params_main_to_aux + rts +.endproc + + +.proc close_file + jsr copy_params_aux_to_main + sta ALTZPOFF + MLI_CALL CLOSE, close_params + sta ALTZPON + jsr copy_params_main_to_aux + rts +.endproc + +;;; ================================================== + +;;; Copies param blocks from Aux to Main +.proc copy_params_aux_to_main + ldy #(params_end - params_start + 1) + sta RAMWRTOFF +loop: lda params_start - 1,y + sta params_start - 1,y + dey + bne loop + sta RAMRDOFF + rts +.endproc + +;;; Copies param blocks from Main to Aux +.proc copy_params_main_to_aux + pha + php + sta RAMWRTON + ldy #(params_end - params_start + 1) +loop: lda params_start - 1,y + sta params_start - 1,y + dey + bne loop + sta RAMRDON + plp + pla + rts +.endproc + +;;; ---------------------------------------- + +params_start: +;;; This block gets copied between main/aux + +;;; ProDOS MLI param blocks + +.proc open_params + .byte 3 ; param_count + .addr pathname ; pathname + .addr $0C00 ; io_buffer +ref_num:.byte 0 ; ref_num +.endproc + +default_buffer := $1200 +chunk_size := $800 ; fits in $1200...$2000, divides $2000 evenly + +.proc read_params + .byte 4 ; param_count +ref_num:.byte 0 ; ref_num +buffer: .addr default_buffer ; data_buffer +request:.word chunk_size ; request_count + .word 0 ; trans_count +.endproc + +.proc close_params + .byte 1 ; param_count +ref_num:.byte 0 ; ref_num +.endproc + +.proc pathname ; 1st byte is length, rest is full path +length: .byte $00 +data: .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 +.endproc + +L0945: .byte $00 +L0946: .byte $00 +L0947: .byte $00 +L0948: .byte $00 +L0949: .byte $00 + +params_end: +;;; ---------------------------------------- + +black_pattern: + .byte $00,$00,$00,$00,$00,$00,$00,$00 + +white_pattern: + .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + + window_id := $64 + +L095A: .byte $00 +L095B: .byte $FA +L095C: .byte $01 + +.proc line_pos +left: .word 0 +base: .word 0 +.endproc + +window_width: .word 0 +window_height: .word 0 + +L0965: .byte $00 +L0966: .byte $00,$00 +L0968: .byte $00 +L0969: .byte $00 +L096A: .byte $00 +L096B: .byte $00 +L096C: .byte $00 +L096D: .byte $00 + +button_state: ; queried to track mouse-up + .byte $00 + +.proc mouse_params ; queried by main input loop +xcoord: .word 0 +ycoord: .word 0 +elem: .byte 0 +win: .byte 0 +.endproc + + + default_width := 560 + default_height := 192 + default_left := 0 + default_top := 0 + +.proc window_title + .byte 0 ; length +.endproc + +.proc window_params +id: .byte window_id ; window identifier +flags: .byte A2D_CWF_NOTITLE +title: .addr window_title + +hscroll:.byte A2D_CWS_NOSCROLL +vscroll:.byte A2D_CWS_NOSCROLL +hscroll_max: + .byte 32 +hscroll_pos: + .byte 0 +vscroll_max: + .byte 32 +vscroll_pos: + .byte 0 + + ;; ??? + .byte $00,$00,$C8,$00,$33,$00 + +width: .word default_width +height: .word default_height +.endproc + ;; window_params continues into text_box +.proc text_box ; or whole window ?? +left: .word default_left +top: .word default_top + .word $2000 ; ??? never changed + .word $80 ; ??? never changed +hoffset:.word 0 ; Also used for A2D_CLEAR_BOX +voffset:.word 0 +width: .word default_width +height: .word default_height +.endproc + + ;; unused? + .byte $00,$00,$00,$00,$00,$00,$00 + .byte $00,$FF,$00,$00,$00,$00,$00,$01 + .byte $01,$00,$7F,$00,$88,$00,$00 + + +.proc init + sta ALTZPON + lda LCBANK1 + lda LCBANK1 + + ;; Get filename by checking DeskTop selected window/icon + + ;; Check that an icon is selected + lda #0 + sta pathname::length + lda file_selected + beq abort ; some file properties? + lda path_index ; prefix index in table + bne :+ +abort: rts + + ;; Copy path (prefix) into pathname buffer. +: src := $06 + dst := $08 + + asl a ; (since address table is 2 bytes wide) + tax + lda path_table,x ; pathname ??? + sta src + lda path_table+1,x + sta src+1 + ldy #0 + lda (src),y + tax + inc src + bne :+ + inc src+1 +: lda #<(pathname::data) + sta dst + lda #>(pathname::data) + sta dst+1 + jsr copy_pathname ; copy x bytes (src) to (dst) + + ;; Append separator. + lda #'/' + ldy #0 + sta (dst),y + inc pathname::length + inc dst + bne :+ + inc dst+1 + + ;; Get file entry. +: lda file_index ; file index in table + asl a ; (since table is 2 bytes wide) + tax + lda file_table,x + sta src + lda file_table+1,x + sta src+1 + + ;; Exit if a directory. + ldy #2 ; 2nd byte of entry + lda (src),y + and #$70 ; check that one of bits 4,5,6 is set ??? + ;; some vague patterns, but unclear + ;; basic = $32,$33, text = $52, sys = $11,$14,??, bin = $23,$24,$33 + ;; dir = $01 (so not shown) + bne :+ + rts ; abort ??? + + ;; Append filename to path. +: ldy #9 + lda (src),y ; grab length + tax ; name has spaces before/after + dex ; so subtract 2 to get actual length + dex + clc + lda src + adc #11 ; 9 = length, 10 = space, 11 = name + sta src + bcc :+ + inc src+1 +: jsr copy_pathname ; copy x bytes (src) to (dst) + + jmp open_file_and_init_window + +.proc copy_pathname ; copy x bytes from src to dst + ldy #0 ; incrementing path length and dst +loop: lda (src),y + sta (dst),y + iny + inc pathname::length + dex + bne loop + tya + clc + adc dst + sta dst + bcc end + inc dst+1 +end: rts +.endproc + +.endproc + +.proc open_file_and_init_window + ;; open file + jsr open_file + lda open_params::ref_num + sta read_params::ref_num + sta close_params::ref_num + + ;; create window + A2D_CALL A2D_CREATE_WINDOW, window_params + A2D_CALL A2D_TEXT_BOX1, text_box + jsr show_file + A2D_CALL $2B, 0 ; ??? + ;; fall through +.endproc + +;;; ================================================== +;;; Main Input Loop + +.proc input_loop + A2D_CALL A2D_GET_BUTTON, button_state + lda button_state + cmp #1 ; was clicked? + bne input_loop ; nope, keep waiting + + A2D_CALL A2D_DESTROY_WINDOW, window_params + + jsr UNKNOWN_CALL ; ??? + .byte $0C + .addr 0 + + rts ; exits input loop +.endproc + +.proc show_file + hgr := $2000 + + ;; AUX memory half - 4 chunks + lda #hgr + sta read_params::buffer+1 + sta read_params::request+1 + sta PAGE2ON + jsr read_file + + ;; MAIN memory half + lda #hgr + sta read_params::buffer+1 + sta read_params::request+1 + sta PAGE2OFF + jsr read_file + + ;; TODO: Restore PAGE2 state? + + jsr close_file + rts +.endproc diff --git a/desk.acc/show.text.file/go.sh b/desk.acc/show.text.file/go.sh index 604713b..6d4d8e8 100755 --- a/desk.acc/show.text.file/go.sh +++ b/desk.acc/show.text.file/go.sh @@ -21,7 +21,7 @@ out=stf #cp $disasm $src # Assemble -$CC65/ca65 --target apple2enh --listing $list -o $obj $src +$CC65/ca65 --target apple2enh --listing $list --list-bytes 0 -o $obj $src # Link $CC65/ld65 --config apple2-asm.cfg -o $out $obj @@ -29,5 +29,9 @@ $CC65/ld65 --config apple2-asm.cfg -o $out $obj # Verify original and output match diff $original $out +$CC65/ca65 --target apple2enh --listing dhr.list --list-bytes 0 -o dhr.o dhr.s +$CC65/ld65 --config apple2-asm.cfg -o dhr dhr.o + # Show output for review -less $list +#less $list +less dhr.list diff --git a/desk.acc/show.text.file/stf.list b/desk.acc/show.text.file/stf.list index 6c008bf..3d6625c 100644 --- a/desk.acc/show.text.file/stf.list +++ b/desk.acc/show.text.file/stf.list @@ -292,6 +292,28 @@ Current file: stf.s 000800 2 data: .byte str 000800 2 .endmacro 000800 2 +000800 2 +000800 2 ;;; DeskTop Internals +000800 2 +000800 2 ;; These are DeskTop internals, but it appears there is no +000800 2 ;; API for getting the selected file. +000800 2 file_selected := $DF21 ; 0 if no selection, 1 otherwise +000800 2 path_index := $DF20 ; index of selected window (used to get prefix) +000800 2 path_table := $DFB3 ; window address table +000800 2 ;; each entry is 65 bytes long +000800 2 ;; each entry is length-prefixed path string (no trailing /) +000800 2 file_index := $DF22 ; index of selected file (global, not w/in window) +000800 2 file_table := $DD9F ; file address table +000800 2 ;; each entry is 27 bytes long +000800 2 ;; .byte ?? +000800 2 ;; .byte ?? +000800 2 ;; .byte type/icon (bits 4,5,6 clear = directory) +000800 2 ;; .word iconx (pixels) +000800 2 ;; .word icony (pixels) +000800 2 ;; .byte ?? +000800 2 ;; .byte ?? +000800 2 ;; .byte len, name (length-prefixed, spaces before/after; 17 byte buffer) +000800 2 000800 1 000800 1 ;; Big questions: 000800 1 ;; * How can we hide/show the cursor on demand? @@ -551,7 +573,7 @@ Current file: stf.s 00096F 1 fixed_mode_flag: 00096F 1 00 .byte $00 ; 0 = proportional, otherwise = fixed 000970 1 -000970 1 button_state: +000970 1 button_state: ; queried to track mouse-up 000970 1 00 .byte $00 000971 1 000971 1 .proc mouse_params ; queried by main input loop @@ -607,6 +629,8 @@ Current file: stf.s 000994 1 000994 1 default_width := 512 000994 1 default_height := 150 +000994 1 default_left := 10 +000994 1 default_top := 28 000994 1 000994 1 .proc window_params 000994 1 64 id: .byte window_id ; window identifier @@ -633,8 +657,8 @@ Current file: stf.s 0009A8 1 .endproc 0009A8 1 ;; window_params continues into text_box 0009A8 1 .proc text_box ; or whole window ?? -0009A8 1 0A 00 left: .word 10 -0009AA 1 1C 00 top: .word 28 +0009A8 1 0A 00 left: .word default_left +0009AA 1 1C 00 top: .word default_top 0009AC 1 00 20 .word $2000 ; ??? never changed 0009AE 1 80 00 .word $80 ; ??? never changed 0009B0 1 00 00 hoffset:.word 0 ; Also used for A2D_CLEAR_BOX @@ -653,8 +677,8 @@ Current file: stf.s 0009CE 1 0009CE 1 ;; gets copied over text_box after mode is drawn 0009CE 1 .proc default_box -0009CE 1 0A 00 left: .word 10 -0009D0 1 1C 00 top: .word 28 +0009CE 1 0A 00 left: .word default_left +0009D0 1 1C 00 top: .word default_top 0009D2 1 00 20 .word $2000 0009D4 1 80 00 .word $80 0009D6 1 00 00 hoffset:.word 0 @@ -668,25 +692,9 @@ Current file: stf.s 0009E1 1 AD 8B C0 lda LCBANK1 0009E4 1 AD 8B C0 lda LCBANK1 0009E7 1 -0009E7 1 ;; These are DeskTop internals, but it appears there is no -0009E7 1 ;; API for getting the selected file. -0009E7 1 file_selected := $DF21 ; 0 if no selection, 1 otherwise -0009E7 1 path_index := $DF20 ; index of selected window (used to get prefix) -0009E7 1 path_table := $DFB3 ; window address table -0009E7 1 ;; each entry is 65 bytes long -0009E7 1 ;; each entry is length-prefixed path string (no trailing /) -0009E7 1 file_index := $DF22 ; index of selected file (global, not w/in window) -0009E7 1 file_table := $DD9F ; file address table -0009E7 1 ;; each entry is 27 bytes long -0009E7 1 ;; .byte ?? -0009E7 1 ;; .byte ?? -0009E7 1 ;; .byte type/icon (bits 4,5,6 clear = directory) -0009E7 1 ;; .word iconx (pixels) -0009E7 1 ;; .word icony (pixels) -0009E7 1 ;; .byte ?? -0009E7 1 ;; .byte ?? -0009E7 1 ;; .byte len, name (length-prefixed, spaces before/after; 17 byte buffer) +0009E7 1 ;; Get filename by checking DeskTop selected window/icon 0009E7 1 +0009E7 1 ;; Check that an icon is selected 0009E7 1 A9 00 lda #0 0009E9 1 8D 04 09 sta pathname::length 0009EC 1 AD 21 DF lda file_selected @@ -1737,9 +1745,11 @@ Current file: stf.s 001165 1 68 11 0D 46 fixed_str: A2D_DEFSTRING "Fixed " 001169 1 69 78 65 64 00116D 1 20 20 20 20 +001171 1 20 20 20 20 001175 1 78 11 0C 50 prop_str: A2D_DEFSTRING "Proportional" 001179 1 72 6F 70 6F 00117D 1 72 74 69 6F +001181 1 6E 61 6C 001184 1 label_width := 50 001184 1 title_bar_height := 12 001184 1 .proc mode_box ; bounding box for mode label diff --git a/desk.acc/show.text.file/stf.o b/desk.acc/show.text.file/stf.o index c6fb3c3..b4d6e6a 100644 Binary files a/desk.acc/show.text.file/stf.o and b/desk.acc/show.text.file/stf.o differ diff --git a/desk.acc/show.text.file/stf.s b/desk.acc/show.text.file/stf.s index ed901c7..eb09c5d 100644 --- a/desk.acc/show.text.file/stf.s +++ b/desk.acc/show.text.file/stf.s @@ -248,7 +248,7 @@ track_scroll_delta: fixed_mode_flag: .byte $00 ; 0 = proportional, otherwise = fixed -button_state: +button_state: ; queried to track mouse-up .byte $00 .proc mouse_params ; queried by main input loop @@ -304,6 +304,8 @@ len: .byte 0 ; length default_width := 512 default_height := 150 + default_left := 10 + default_top := 28 .proc window_params id: .byte window_id ; window identifier @@ -329,8 +331,8 @@ height: .word default_height .endproc ;; window_params continues into text_box .proc text_box ; or whole window ?? -left: .word 10 -top: .word 28 +left: .word default_left +top: .word default_top .word $2000 ; ??? never changed .word $80 ; ??? never changed hoffset:.word 0 ; Also used for A2D_CLEAR_BOX @@ -346,8 +348,8 @@ height: .word default_height ;; gets copied over text_box after mode is drawn .proc default_box -left: .word 10 -top: .word 28 +left: .word default_left +top: .word default_top .word $2000 .word $80 hoffset:.word 0 @@ -361,25 +363,9 @@ height: .word default_height lda LCBANK1 lda LCBANK1 - ;; These are DeskTop internals, but it appears there is no - ;; API for getting the selected file. - file_selected := $DF21 ; 0 if no selection, 1 otherwise - path_index := $DF20 ; index of selected window (used to get prefix) - path_table := $DFB3 ; window address table - ;; each entry is 65 bytes long - ;; each entry is length-prefixed path string (no trailing /) - file_index := $DF22 ; index of selected file (global, not w/in window) - file_table := $DD9F ; file address table - ;; each entry is 27 bytes long - ;; .byte ?? - ;; .byte ?? - ;; .byte type/icon (bits 4,5,6 clear = directory) - ;; .word iconx (pixels) - ;; .word icony (pixels) - ;; .byte ?? - ;; .byte ?? - ;; .byte len, name (length-prefixed, spaces before/after; 17 byte buffer) + ;; Get filename by checking DeskTop selected window/icon + ;; Check that an icon is selected lda #0 sta pathname::length lda file_selected diff --git a/inc/auxmem.inc b/inc/auxmem.inc index 4731028..be517ec 100644 --- a/inc/auxmem.inc +++ b/inc/auxmem.inc @@ -9,10 +9,17 @@ RAMWRTOFF := $C004 RAMWRTON := $C005 ALTZPOFF := $C008 ALTZPON := $C009 + +PAGE2OFF := $C054 +PAGE2ON := $C055 +HIRESON := $C056 +HIRESOFF := $C057 + LCBANK1 := $C08B ;;; Routines AUXMOVE := $C311 ; carry set main>aux, carry clear aux>main +XFER := $C314 STARTLO := $3C STARTHI := $3D