From b03ae76b54d77f435088cacf12d3cfd9873f05ed Mon Sep 17 00:00:00 2001 From: Daniel Serpell Date: Mon, 18 Feb 2019 00:24:52 -0300 Subject: [PATCH] Add support for INITAD to the Atari binary format. --- doc/ld65.sgml | 21 ++++++++++++--- src/ld65/config.c | 21 +++++++++++++++ src/ld65/scanner.h | 1 + src/ld65/xex.c | 43 ++++++++++++++++++++++++++++++- src/ld65/xex.h | 2 ++ testcode/lib/atari/multi-xex.cfg | 8 ++++-- testcode/lib/atari/multi-xex.s | 19 +++++++++++++- testcode/lib/atari/multi.xex | Bin 0 -> 157 bytes 8 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 testcode/lib/atari/multi.xex diff --git a/doc/ld65.sgml b/doc/ld65.sgml index 9116eb442..3f159b39b 100644 --- a/doc/ld65.sgml +++ b/doc/ld65.sgml @@ -938,9 +938,24 @@ has several attributes that may be defined here. } -The Atari file format has only one attribute, + + RUNAD = symbol + + Specify a symbol as the run address of the binary, the loader will call this + address after all the file is loaded in memory. If the attribute is omitted, + no run address is included in the file. + + INITAD = memory_area : symbol + + Specify a symbol as the initialization address for the given memory area. + The binary loader will call this address just after the memory area is loaded + into memory, before continuing loading the rest of the file. + + + FORMATS { diff --git a/src/ld65/config.c b/src/ld65/config.c index fafbed290..f8bff2ac0 100644 --- a/src/ld65/config.c +++ b/src/ld65/config.c @@ -1007,6 +1007,7 @@ static void ParseXex (void) { static const IdentTok Attributes [] = { { "RUNAD", CFGTOK_RUNAD }, + { "INITAD", CFGTOK_INITAD }, }; /* Remember the attributes read */ @@ -1017,6 +1018,8 @@ static void ParseXex (void) }; unsigned AttrFlags = atNone; Import *RunAd = 0; + Import *InitAd; + MemoryArea *InitMem; /* Read the attributes */ while (CfgTok == CFGTOK_IDENT) { @@ -1046,6 +1049,24 @@ static void ParseXex (void) CfgNextTok (); break; + case CFGTOK_INITAD: + /* We expect a memory area followed by a colon and an identifier */ + CfgAssureIdent (); + InitMem = CfgGetMemory (GetStrBufId (&CfgSVal)); + CfgNextTok (); + CfgConsumeColon (); + CfgAssureIdent (); + /* Generate an import for the symbol */ + InitAd = InsertImport (GenImport (GetStrBufId (&CfgSVal), ADDR_SIZE_ABS)); + /* Remember the file position */ + CollAppend (&InitAd->RefLines, GenLineInfo (&CfgErrorPos)); + /* Eat the identifier token */ + CfgNextTok (); + /* Add to XEX */ + if (XexAddInitAd (XexFmtDesc, InitMem, InitAd)) + CfgError (&CfgErrorPos, "INITAD already given for memory area"); + break; + default: FAIL ("Unexpected attribute token"); diff --git a/src/ld65/scanner.h b/src/ld65/scanner.h index 77fa91da8..aeabbdca8 100644 --- a/src/ld65/scanner.h +++ b/src/ld65/scanner.h @@ -94,6 +94,7 @@ typedef enum { CFGTOK_VERSION, CFGTOK_FORMAT, CFGTOK_RUNAD, + CFGTOK_INITAD, CFGTOK_LOAD, CFGTOK_RUN, diff --git a/src/ld65/xex.c b/src/ld65/xex.c index 18190c063..e7674949a 100644 --- a/src/ld65/xex.c +++ b/src/ld65/xex.c @@ -58,6 +58,12 @@ /* Data */ /*****************************************************************************/ +/* Linked list of memory area initialization addresses */ +typedef struct XexInitAd { + MemoryArea *InitMem; + Import *InitAd; + struct XexInitAd *next; +} XexInitAd; struct XexDesc { @@ -65,13 +71,13 @@ struct XexDesc { FILE* F; /* Output file */ const char* Filename; /* Name of output file */ Import* RunAd; /* Run Address */ + XexInitAd* InitAds; /* List of Init Addresses */ unsigned long HeadPos; /* Position in the file of current header */ unsigned long HeadEnd; /* End address of current header */ unsigned long HeadSize; /* Last header size, can be removed if zero */ }; - /*****************************************************************************/ /* Code */ /*****************************************************************************/ @@ -89,6 +95,7 @@ XexDesc* NewXexDesc (void) D->F = 0; D->Filename = 0; D->RunAd = 0; + D->InitAds = 0; D->HeadPos = 0; D->HeadEnd = 0; D->HeadSize = 0; @@ -113,7 +120,34 @@ void XexSetRunAd (XexDesc* D, Import *RunAd) D->RunAd = RunAd; } +XexInitAd* XexSearchInitMem(XexDesc* D, MemoryArea *InitMem) +{ + XexInitAd* I; + for (I=D->InitAds; I != 0; I=I->next) + { + if (I->InitMem == InitMem) + return I; + } + return NULL; +} + +int XexAddInitAd (XexDesc* D, MemoryArea *InitMem, Import *InitAd) +/* Sets and INITAD for the given memory area */ +{ + XexInitAd* I; + + /* Search for repeated entry */ + if (XexSearchInitMem (D, InitMem)) + return 1; + + I = xmalloc (sizeof (XexInitAd)); + I->InitAd = InitAd; + I->InitMem = InitMem; + I->next = D->InitAds; + D->InitAds = I; + return 0; +} static unsigned XexWriteExpr (ExprNode* E, int Signed, unsigned Size, unsigned long Offs attribute ((unused)), @@ -369,8 +403,15 @@ void XexWriteTarget (XexDesc* D, struct File* F) for (I = 0; I < CollCount (&F->MemoryAreas); ++I) { /* Get this entry */ MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, I); + /* See if we have an init address for this area */ + XexInitAd* I = XexSearchInitMem (D, M); Print (stdout, 1, " ATARI EXE Dumping `%s'\n", GetString (M->Name)); XexWriteMem (D, M); + if (I) { + Write16 (D->F, 0x2E2); + Write16 (D->F, 0x2E3); + Write16 (D->F, GetExportVal (I->InitAd->Exp)); + } } /* Write RUNAD at file end */ diff --git a/src/ld65/xex.h b/src/ld65/xex.h index c74f78eca..2eb80de86 100644 --- a/src/ld65/xex.h +++ b/src/ld65/xex.h @@ -69,6 +69,8 @@ void XexWriteTarget (XexDesc* D, File* F); void XexSetRunAd (XexDesc* D, Import *RunAd); /* Set the RUNAD export */ +int XexAddInitAd (XexDesc* D, MemoryArea *InitMem, Import *InitAd); +/* Sets and INITAD for the given memory area */ /* End of xex.h */ diff --git a/testcode/lib/atari/multi-xex.cfg b/testcode/lib/atari/multi-xex.cfg index 18dfff820..7558aa895 100644 --- a/testcode/lib/atari/multi-xex.cfg +++ b/testcode/lib/atari/multi-xex.cfg @@ -3,10 +3,12 @@ FEATURES { } MEMORY { ZP: file = "", define = yes, start = $0082, size = $007E; + # First memory segment in file, show message + LOADER: file = %O, start = $680, size = 128; # First memory segment in file, load over COLOR registers: COLOR: file = %O, start = $2C4, size = 5; # Second memory segment, load at page 6: - PAGE6: file = %O, start = $600, size = 256; + PAGE6: file = %O, start = $600, size = 128; # Third memory segment in file, load over SDLST register: SDLST: file = %O, start = $230, size = 2; # Main segment, load at "STARTADDRESS" @@ -16,11 +18,13 @@ FILES { %O: format = atari; } FORMATS { - atari: runad = start; + atari: runad = start, + initad = LOADER: show_load; } SEGMENTS { ZEROPAGE: load = ZP, type = zp, optional = yes; # Place segments in memory areas: + LOADER: load = LOADER, type = rw; COLOR: load = COLOR, type = rw; PAGE6: load = PAGE6, type = rw; SDLST: load = SDLST, type = rw; diff --git a/testcode/lib/atari/multi-xex.s b/testcode/lib/atari/multi-xex.s index 7957ddf64..cdf43469d 100644 --- a/testcode/lib/atari/multi-xex.s +++ b/testcode/lib/atari/multi-xex.s @@ -14,8 +14,25 @@ .macpack atari ; Default RUNAD is "start", export that: - .export start + .export start, show_load +; Loader + .segment "LOADER" +show_load: + ldx #0 ; channel 0 + lda #msg_load + sta ICBAH,x + lda #$FF + sta ICBLL,x ; length + sta ICBLH,x + lda #PUTREC + sta ICCOM,x + jmp CIOV + +msg_load: + .byte "Loading....", ATEOL ; We load color values directly into registers .segment "COLOR" diff --git a/testcode/lib/atari/multi.xex b/testcode/lib/atari/multi.xex new file mode 100644 index 0000000000000000000000000000000000000000..7da39ad47af630bef4edab9f21e06b7162e98e88 GIT binary patch literal 157 zcmezWzkzKz+aiXQbLP4*uVkC+%DnRbTo2~Cp3Eyb=Q=U_ggx=ePfW?oOV%(0lQ&>8 UWCEI?$E4@Op!b03Arpfh0RH4B!2kdN literal 0 HcmV?d00001 -- 2.39.2