}
</verb></tscreen>
-The Atari file format has only one attribute, <tt/RUNAD/ that allows to specify
-a symbol as the run address of the binary. If the attribute is omiteed, no run
-address is specified.
+The Atari file format has two attributes:
+
+<descrip>
+
+ <tag><tt>RUNAD = symbol</tt></tag>
+
+ 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.
+
+ <tag><tt>INITAD = memory_area : symbol</tt></tag>
+
+ 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.
+
+</descrip>
+
<tscreen><verb>
FORMATS {
{
static const IdentTok Attributes [] = {
{ "RUNAD", CFGTOK_RUNAD },
+ { "INITAD", CFGTOK_INITAD },
};
/* Remember the attributes read */
};
unsigned AttrFlags = atNone;
Import *RunAd = 0;
+ Import *InitAd;
+ MemoryArea *InitMem;
/* Read the attributes */
while (CfgTok == CFGTOK_IDENT) {
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");
CFGTOK_VERSION,
CFGTOK_FORMAT,
CFGTOK_RUNAD,
+ CFGTOK_INITAD,
CFGTOK_LOAD,
CFGTOK_RUN,
/* Data */
/*****************************************************************************/
+/* Linked list of memory area initialization addresses */
+typedef struct XexInitAd {
+ MemoryArea *InitMem;
+ Import *InitAd;
+ struct XexInitAd *next;
+} XexInitAd;
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 */
/*****************************************************************************/
D->F = 0;
D->Filename = 0;
D->RunAd = 0;
+ D->InitAds = 0;
D->HeadPos = 0;
D->HeadEnd = 0;
D->HeadSize = 0;
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)),
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 */
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 */
}
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"
%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;
.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 ICBAL,x ; address
+ 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"