Work in progress on hexdump command (in C) and support for calling Davex routines and ProDOS from C.

This commit is contained in:
Dave Lyons
2020-08-31 04:42:53 -07:00
parent a5f80ae98d
commit 2d0ebfa6b0
5 changed files with 196 additions and 36 deletions

View File

@@ -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

View File

@@ -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"

View File

@@ -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);

View File

@@ -39,7 +39,6 @@ const char gDescription[] = "\x17This is the description";
const int kFive = 5;
void CROUT() { putchar('\r'); }
void Space() { putchar(' '); }
void main()

View File

@@ -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
}