diff --git a/src/shell/main.asm b/src/shell/main.asm index 64fe918..3ca5d5d 100644 --- a/src/shell/main.asm +++ b/src/shell/main.asm @@ -889,7 +889,7 @@ pv_yesno: @yn: pha jsr calc_pindex pla - sta parms+3,x + sta parms+3,x ; retrieved result will be in A jmp chrget ; @@ -1269,7 +1269,7 @@ pv_devnum: pha jsr calc_pindex pla - sta parms+3,x + sta parms+3,x ; retrieved result will be in A jmp chrget dvnerr: lda #der_baddev jmp ProDOS_err diff --git a/src/xtn/2-cc65/DavexXC.asm b/src/xtn/2-cc65/DavexXC.asm index 66bab49..9eaa21c 100644 --- a/src/xtn/2-cc65/DavexXC.asm +++ b/src/xtn/2-cc65/DavexXC.asm @@ -25,12 +25,22 @@ _XC_STARTUP: .export COUT COUT = $fded -.export _PRBYTE -_PRBYTE = $fdda - ; export COUT() for direct use from C: Prints character in inverse if bit 7 is clear. .export _COUT -_COUT = $fded +_COUT = cout + +.export _CROUT +_CROUT = crout + +.export _PRBYTE +_PRBYTE = prbyte + +.export _SETNORM +_SETNORM = normal + +.export _SETINV +_SETINV = inverse + ; __fastcall__ calling convention: last parameter is in sreg+1/sreg/X/A ; return value in XA, or sreg+1/sreg/X/A @@ -41,11 +51,37 @@ _xgetparm_ch_nil: jsr xgetparm_ch jmp returnTrueForCLC -; extern _Bool __fastcall__ xgetparm_ch_byte(uint8_t optionCharacter, uint8_t* outValue); // int1, filetype, devnum, yesno -; [TODO] +; extern _Bool __fastcall__ xgetparm_ch_int1(uint8_t optionCharacter, uint8_t* outValue); // int1 +.export _xgetparm_ch_int1 +_xgetparm_ch_int1: + stx p+1 + sta p + jsr popa ; option character [TODO] pop just 1 byte, or 2? + jsr xgetparm_ch ; 1-byte result in Y + bcs :+ + tya + ldy #0 + sta (p),y +: jmp returnTrueForCLC ; extern _Bool __fastcall__ xgetparm_ch_int2(uint8_t optionCharacter, uint16_t* outValue); -; [TODO] +.export _xgetparm_ch_int2 +_xgetparm_ch_int2: + stx num+1 + sta num + jsr popa ; option character [TODO] pop just 1 byte, or 2? + jsr xgetparm_ch ; 2-byte result in XY +getparm_return_int2: + bcs :+ +; Result is in XY, and we need to store it at (num) as 2 bytes + tya + ldy #0 + sta (num),y + txa + iny + sta (num),y +: jmp returnTrueForCLC + ; extern _Bool __fastcall__ xgetparm_ch_int3(uint8_t optionCharacter, uint32_t* outValue); .export _xgetparm_ch_int3 @@ -72,6 +108,20 @@ getparm_return_int3: sta (num),y : jmp returnTrueForCLC + +; extern _Bool __fastcall__ xgetparm_ch_byte(uint8_t optionCharacter, uint8_t* outValue); // filetype, devnum, yesno +.export _xgetparm_ch_byte +_xgetparm_ch_byte: + stx p+1 + sta p + jsr popa ; option character [TODO] pop just 1 byte, or 2? + jsr xgetparm_ch ; 1-byte result in A (differs from int1) + bcs :+ + ldy #0 + sta (p),y +: jmp returnTrueForCLC + + ; extern _Bool __fastcall__ xgetparm_n_int3(uint8_t index, uint32_t* outValue); .export _xgetparm_n_int3 _xgetparm_n_int3: @@ -111,6 +161,7 @@ _xgetparm_n_int3: ; extern void __fastcall__ xmessage(const uint8_t*); .export _xmessage _xmessage: +; [TODO] export this from the shell as xmessage ? stx loadCharacter+2 sta loadCharacter+1 ldy #0 @@ -326,5 +377,18 @@ _xgetnump: ldx #0 ;extend result to 16 bits rts +; extern uint8_t __fastcall__ ProDOS(uint8_t call, void* params); +.export _ProDOS +_ProDOS: + stx @params+1 + sta @params + jsr popa + sta @callNum + jsr mli +@callNum: .byte 0 +@params: .addr 0 + ldx #0 ; error in A + rts + .segment "ONCE" .segment "INIT" diff --git a/src/xtn/2-cc65/DavexXC.h b/src/xtn/2-cc65/DavexXC.h index 3feb04a..e7e886d 100644 --- a/src/xtn/2-cc65/DavexXC.h +++ b/src/xtn/2-cc65/DavexXC.h @@ -44,23 +44,27 @@ struct XCHeader extern void PRBYTE(uint8_t); extern void COUT(uint8_t); -// [TODO] CROUT directly from ROM +extern void CROUT(); +extern void SETNORM(); +extern void SETINV(); // #define FUNC(addr) ((void __fastcall__ (*)())addr) // void __fastcall__ xpoll_io() { FUNC(0xB05B)(); } - +// [TODO] _Bool -> bool ? extern _Bool __fastcall__ xgetparm_ch_nil(uint8_t optionCharacter); -extern _Bool __fastcall__ xgetparm_ch_byte(uint8_t optionCharacter, uint8_t* outValue); // int1, filetype, devnum, yesno +extern _Bool __fastcall__ xgetparm_ch_int1(uint8_t optionCharacter, uint8_t* outValue); // not for filetype, devnum, or yesno extern _Bool __fastcall__ xgetparm_ch_int2(uint8_t optionCharacter, uint16_t* outValue); extern _Bool __fastcall__ xgetparm_ch_int3(uint8_t optionCharacter, uint32_t* outValue); +extern _Bool __fastcall__ xgetparm_ch_byte(uint8_t optionCharacter, uint8_t* outValue); // filetype, devnum, yesno extern _Bool __fastcall__ xgetparm_ch_string(uint8_t optionCharacter, uint8_t** outString); extern _Bool __fastcall__ xgetparm_ch_path(uint8_t optionCharacter, uint8_t** outPath); extern _Bool __fastcall__ xgetparm_ch_path_and_filetype(uint8_t optionCharacter, uint8_t** outPath, uint8_t* outFiletype); -extern _Bool __fastcall__ xgetparm_n_byte(uint8_t index, uint8_t* outValue); // int1, filetype, devnum, yesno +extern _Bool __fastcall__ xgetparm_n_int1(uint8_t index, uint8_t* outValue); // not for filetype, devnum, or yesno extern _Bool __fastcall__ xgetparm_n_int2(uint8_t index, uint16_t* outValue); extern _Bool __fastcall__ xgetparm_n_int3(uint8_t index, uint32_t* outValue); +extern _Bool __fastcall__ xgetparm_n_byte(uint8_t index, uint8_t* outValue); // filetype, devnum, yesno extern _Bool __fastcall__ xgetparm_n_string(uint8_t index, uint8_t** outString); extern _Bool __fastcall__ xgetparm_n_path(uint8_t index, uint8_t** outPath); extern _Bool __fastcall__ xgetparm_n_path_and_filetype(uint8_t index, uint8_t** outPath, uint8_t* outFiletype); @@ -106,7 +110,7 @@ extern uint8_t __fastcall__ xrdkey(); // ;v1.1 extern void __fastcall__ xdirty(); // v1.1 extern uint8_t __fastcall__ xgetnump(); // v1.1 -// [TODO] extern void __fastcall__ xshell_info(unsigned char selector); // v1.25 // [TODO] Return value varies? +// [TODO] extern void __fastcall__ xshell_info(uint8_t selector); // v1.25 // [TODO] Return value varies? // input: X=request code // output: CLC, requested information in registers/etc. // SEC, requested information not available @@ -117,10 +121,29 @@ extern uint8_t __fastcall__ xgetnump(); // v1.1 // X=2: Get history buffer (AY=address, X=size in pages) // X=3: Get internal filetype table (AY=address) // X=4: Get internal filetype name table (AY=address) +// +// extern uint16_t __fastcall__ xshell_info_version(); -- returns $0abc ($0123 = 1.23) +// extern uint8_t* __fastcall__ xshell_info_aliases(uint8_t* outPages); +// extern uint8_t* __fastcall__ xshell_info_history(uint8_t* outPages); +// extern uint8_t* __fastcall__ xshell_info_filetypes(); +// extern uint8_t* __fastcall__ xshell_info_filetype_names(); // -// [TODO] External commands may use 'filebuff', 'filebuff2', and 'filebuff3', defined in GLOBALS; each one is $400 bytes long. +#define filebuff ((uint8_t*)0x800) // size $400 +#define filebuff2 ((uint8_t*)0xC00) // size $400 +#define filebuff3 ((uint8_t*)0x1000) // size $400 + +#define pagebuff ((uint8_t*)0x1800) // size $100 +#define catbuff ((uint8_t*)0x1A02) // size $80 + +#define wildstring1 ((uint8_t*)0x1C3F) // size 128 +#define wildstring2 ((uint8_t*)0x1CBF) // size 128 +#define wildseg ((uint8_t*)0x1D3F) // size 16 // [TODO] The high bit of 'xspeech' is on when a speech synthesizer is being used. +// [TODO] xnum and others + +// ProDOS +extern uint8_t __fastcall__ ProDOS(uint8_t call, void* params); diff --git a/src/xtn/2-cc65/cctest.c b/src/xtn/2-cc65/cctest.c index ca6cf4b..033b867 100644 --- a/src/xtn/2-cc65/cctest.c +++ b/src/xtn/2-cc65/cctest.c @@ -39,7 +39,6 @@ const char gDescription[] = "\x17This is the description"; const int kFive = 5; -void CROUT() { putchar('\r'); } void Space() { putchar(' '); } void main() diff --git a/src/xtn/2-cc65/hexdump.c b/src/xtn/2-cc65/hexdump.c index 837eadb..6c4a48f 100644 --- a/src/xtn/2-cc65/hexdump.c +++ b/src/xtn/2-cc65/hexdump.c @@ -7,7 +7,7 @@ const char gDescription[]; // forward declaration, since gCommandHeader must com #define kMinDavexVersion 0x14 #define kMinDavexVersionMinor 0 -#define PARM_COUNT 7 // define before including DavexXC.h +#define PARM_COUNT 8 // define before including DavexXC.h #include "DavexXC.h" const struct XCHeader gCommandHeader = @@ -24,6 +24,7 @@ const struct XCHeader gCommandHeader = // Parameters (PARM_COUNT of them) { { 0, t_wildpath }, + { 'd', t_devnum }, { 'a', t_nil }, // ASCII only { 'h', t_nil }, // Hex only { 'o', t_nil }, // no Offsets displayed @@ -36,22 +37,27 @@ const struct XCHeader gCommandHeader = const char gDescription[] = "\x22" "Dump a file or memory in hex/ASCII"; -void CROUT() { putchar('\r'); } void Space() { putchar(' '); } uint32_t gStartOffset; uint32_t gEndOffset; +uint8_t gDevNum; +uint8_t gBlockMode; uint32_t gOffset; uint8_t gBytesPerLine; uint16_t gAmountRead; -_Bool gDumpMemory; +bool gDumpMemory; +bool gBlockValid; + +uint16_t gCurrentBlock; + -#define pagebuff ((uint8_t*)0x800) #define err_eof 0x4C // ProDOS end of file error uint8_t ReadSome(); +bool ShouldHighlight(uint8_t); void main() { @@ -59,6 +65,8 @@ void main() _Bool showHex = xgetparm_ch_nil('h'); _Bool showOffsets = !xgetparm_ch_nil('o'); gDumpMemory = xgetparm_ch_nil('m'); + gBlockMode = xgetparm_ch_byte('d', &gDevNum); + gBlockValid = false; if (!showASCII && !showHex) showASCII = showHex = true; @@ -69,8 +77,8 @@ void main() gEndOffset = 0xFFFFFF; { - const uint8_t bytesPerLine = showHex ? 16 : 64; - for (gOffset = gStartOffset; gOffset < gEndOffset; gOffset += bytesPerLine) + gBytesPerLine = showHex ? 16 : 64; + for (gOffset = gStartOffset; gOffset < gEndOffset; gOffset += gBytesPerLine) { uint8_t err = ReadSome(); if (err == err_eof) @@ -78,25 +86,33 @@ void main() if (err != 0) xProDOS_err(err); // does not return -#if 0 // using printf() added 1,885 bytes - if (showOffsets) - printf("%06lX: ", offset); -#else + // "Block n" + if (gBlockMode && (gOffset & 511) == 0) + { + xmessage("Block "); + xprdec_2(gOffset / 512); + CROUT(); + } + + // Offset: PRBYTE(gOffset >> 16); if (gDumpMemory) putchar('/'); PRBYTE(gOffset >> 8); PRBYTE(gOffset); -// fputs(": ", stdout); // fputs() works, but it adds 80 bytes (in addition to puts() overhead) xmessage(": "); -#endif if (showHex) { uint8_t i; - for (i = 0; i < bytesPerLine; ++i) + for (i = 0; i < gBytesPerLine; ++i) { - PRBYTE(pagebuff[i]); + uint8_t ch = pagebuff[i]; + bool inverse = ShouldHighlight(ch); + if (inverse) + SETINV(); + PRBYTE(ch); + SETNORM(); Space(); } } @@ -104,13 +120,18 @@ void main() if (showASCII) { uint8_t i; - for (i = 0; i < bytesPerLine; ++i) + for (i = 0; i < gBytesPerLine; ++i) { - uint8_t ch = pagebuff[i] | 0x80; - if (ch > 0xA0) - putchar(ch); + uint8_t ch = pagebuff[i]; + bool inverse = ShouldHighlight(ch); + uint8_t ch7 = ch | 0x80; + if (inverse) + SETINV(); + if (ch7 > 0xA0) + COUT(ch7); else putchar('.'); + SETNORM(); } } @@ -122,6 +143,19 @@ void main() } +bool ShouldHighlight(uint8_t ch) +{ + // [TODO] parse command-line options to specify what data to highlight + if (gDumpMemory) + return ch >= 0x80; + + if (gBlockMode) + return ch == 0x4C; + + return false; +} + + uint8_t ByteFromMemory(uint32_t addr) { const uint8_t bank = addr >> 16; @@ -144,12 +178,35 @@ uint8_t ByteFromMemory(uint32_t addr) return *(uint8_t*)addr; } -// Returns a ProDOS error code; [TODO] sets gAmountRead? so we can stop at the end of the file + +uint8_t GetBlockIntoFileBuff(uint16_t block) +{ + struct RWBlockParams { uint8_t count; uint8_t devnum; uint8_t* buffer; uint16_t block; }; + static struct RWBlockParams blockParams = { 3, 0 /* dev */, filebuff, 0 }; + + if (gBlockValid && block == gCurrentBlock) + return 0; + + #define READ_BLOCK 0x80 + blockParams.devnum = gDevNum; + blockParams.block = block; + { + uint8_t err = ProDOS(READ_BLOCK, &blockParams); + if (err == 0) + { + gBlockValid = true; + gCurrentBlock = block; + } + return err; + } +} + +// Returns a ProDOS error code. Sets gAmountRead so we can stop at the end of the file. uint8_t ReadSome() { if (gDumpMemory) { - // Read from offset to offset+bytesPerLine-1 + // Read from gOffset to gOffset+gBytesPerLine-1 uint8_t i; for (i = 0; i < gBytesPerLine; ++i) pagebuff[i] = ByteFromMemory(gOffset + i); @@ -157,6 +214,23 @@ uint8_t ReadSome() return 0; // noErr } + if (gBlockMode) + { + uint8_t i; + for (i = 0; i < gBytesPerLine; ++i) + { + uint32_t offset = gOffset + i; + uint16_t withinBlock = offset & 511; + uint8_t err = GetBlockIntoFileBuff(offset / 512); + if (err) + xProDOS_err(err); + + pagebuff[i] = filebuff[withinBlock]; + } + gAmountRead = gBytesPerLine; + return 0; + } + xProDOS_err(0xFF); // [TODO] files not supported yet }