ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
_build.c
Go to the documentation of this file.
1/*****************************************************************************
2 * ugBASIC - an isomorphic BASIC language compiler for retrocomputers *
3 *****************************************************************************
4 * Copyright 2021-2024 Marco Spedaletti (asimov@mclink.it)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *----------------------------------------------------------------------------
18 * Concesso in licenza secondo i termini della Licenza Apache, versione 2.0
19 * (la "Licenza"); è proibito usare questo file se non in conformità alla
20 * Licenza. Una copia della Licenza è disponibile all'indirizzo:
21 *
22 * http://www.apache.org/licenses/LICENSE-2.0
23 *
24 * Se non richiesto dalla legislazione vigente o concordato per iscritto,
25 * il software distribuito nei termini della Licenza è distribuito
26 * "COSÌ COM'È", SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO, esplicite o
27 * implicite. Consultare la Licenza per il testo specifico che regola le
28 * autorizzazioni e le limitazioni previste dalla medesima.
29 ****************************************************************************/
30
31/****************************************************************************
32 * INCLUDE SECTION
33 ****************************************************************************/
34
35#include "../../ugbc.h"
36
37#include <errno.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40
41/****************************************************************************
42 * CODE SECTION
43 ****************************************************************************/
44
45extern char OUTPUT_FILE_TYPE_AS_STRING[][16];
46
47static void apply_cartridge_header( Environment * _environment, char * _cartridge, long _size ) {
48
49 // 0100-0103 — Entry point
50 // After displaying the Nintendo logo, the built-in boot ROM jumps to the address $0100,
51 // which should then jump to the actual main program in the cartridge. Most commercial games
52 // fill this 4-byte area with a nop instruction followed by a jp $0150.
53
54 // _cartridge[ 0x100 ] = 0x00; // NOP
55 // _cartridge[ 0x101 ] = 0xc3; // JP $0150
56 // _cartridge[ 0x102 ] = 0x50; // |
57 // _cartridge[ 0x103 ] = 0x01; // |
58
59 // 0104-0133 — Nintendo logo
60 // This area contains a bitmap image that is displayed when the Game Boy is powered on.
61 // It must match the following (hexadecimal) dump, otherwise the boot ROM won’t allow
62 // the game to run:
63
64 // char nintendoLogo[] = { 0xce, 0xed, 0x66, 0x66, 0xcc, 0x0d, 0x00, 0x0b,
65 // 0x03, 0x73, 0x00, 0x83, 0x00, 0x0c, 0x00, 0x0d,
66 // 0x00, 0x08, 0x11, 0x1f, 0x88, 0x89, 0x00, 0x0e,
67 // 0xdc, 0xcc, 0x6e, 0xe6, 0xdd, 0xdd, 0xd9, 0x99,
68 // 0xbb, 0xbb, 0x67, 0x63, 0x6e, 0x0e, 0xec, 0xcc,
69 // 0xdd, 0xdc, 0x99, 0x9f, 0xbb, 0xb9, 0x33, 0x3e };
70 // memcpy( &_cartridge[0x104], nintendoLogo, sizeof( nintendoLogo ) );
71
72 // 0134-0143 — Title
73 // These bytes contain the title of the game in upper case ASCII. If the title is
74 // less than 16 characters long, the remaining bytes should be padded with $00s.
75 // Parts of this area actually have a different meaning on later cartridges,
76 // reducing the actual title size to 15 ($0134–$0142) or 11 ($0134–$013E) characters;
77 // see below.
78
79 // int actualSizeForName = 11;
80
81 // memset( &_cartridge[0x134], 0, actualSizeForName );
82 // if ( _environment->program.name ) {
83 // strncpy( &_cartridge[0x134], strtoupper( _environment->program.name ), actualSizeForName);
84 // } else {
85 // strncpy( &_cartridge[0x134], strtoupper( basename( _environment->exeFileName ) ), actualSizeForName );
86 // }
87
88 // 013F-0142 — Manufacturer code
89 // In older cartridges these bytes were part of the Title (see above). In newer cartridges they
90 // contain a 4-character manufacturer code (in uppercase ASCII). The purpose of the manufacturer
91 // code is unknown.
92
93 // _cartridge[0x13f] = 'U';
94 // _cartridge[0x140] = 'G';
95 // _cartridge[0x141] = 'B';
96 // _cartridge[0x141] = 'S';
97
98 // 0143 — CGB flag
99 // In older cartridges this byte was part of the Title (see above). The CGB and later models interpret
100 // this byte to decide whether to enable Color mode (“CGB Mode”) or to fall back to monochrome
101 // compatibility mode (“Non-CGB Mode”).
102 //
103 // Typical values are:
104 //
105 // Value Meaning
106 // $80 The game supports CGB enhancements, but is backwards compatible with monochrome Game Boys
107 // $C0 The game works on CGB only (the hardware ignores bit 6, so this really functions the same as $80)
108 // Setting bit 7 will trigger a write of this register value to KEY0 register which sets the CPU mode.
109
110 if ( _environment->currentMode == TILEMAP_MODE_BGB ) {
111 _cartridge[0x143] = 0x00;
112 } else {
113 _cartridge[0x143] = 0x80;
114 }
115
116 // 0144–0145 — New licensee code
117 // This area contains a two-character ASCII “licensee code” indicating the game’s publisher. It is
118 // only meaningful if the Old licensee is exactly $33 (which is the case for essentially all games
119 // made after the SGB was released); otherwise, the old code must be considered.
120
121 // _cartridge[0x144] = 0x00;
122 // _cartridge[0x145] = 0x00;
123
124 // 014D — Header checksum
125 // This byte contains an 8-bit checksum computed from the cartridge header bytes $0134–014C.
126 // The boot ROM computes the checksum as follows:
127
128 unsigned char checksum = 0;
129 for (unsigned short address = 0x0134; address <= 0x014c; address++) {
130 checksum = checksum - (unsigned char) (_cartridge[address]) - 1;
131 }
132
133 _cartridge[0x14d] = checksum;
134
135 // 014E-014F — Global checksum
136 // These bytes contain a 16-bit (big-endian) checksum simply computed as the sum of all the bytes
137 // of the cartridge ROM (except these two checksum bytes).
138
139 /* Update complement checksum */
140
141 /* Update checksum */
142 int chk = 0, i;
143 _cartridge[0x14e] = 0;
144 _cartridge[0x14f] = 0;
145 for (i = 0; i < _size; ++i) {
146 chk += (unsigned char) (_cartridge[i] );
147 }
148 _cartridge[0x14e] = (unsigned char) ((chk >> 8) & 0xff);
149 _cartridge[0x14f] = (unsigned char) (chk & 0xff);
150
151}
152
153void generate_gb( Environment * _environment ) {
154
155 char commandLine[8*MAX_TEMPORARY_STORAGE];
156 char executableName[MAX_TEMPORARY_STORAGE];
157 char binaryName[MAX_TEMPORARY_STORAGE];
158 char binaryNameDefinitive[MAX_TEMPORARY_STORAGE];
159 char listingFileName[MAX_TEMPORARY_STORAGE];
160
161 BUILD_SAFE_REMOVE( _environment, _environment->exeFileName );
162
163 BUILD_TOOLCHAIN_Z88DK_GET_EXECUTABLE_Z80ASM( _environment, executableName );
164
165 BUILD_TOOLCHAIN_Z88DK_GET_LISTING_FILE( _environment, listingFileName );
166
167 BUILD_TOOLCHAIN_Z88DK_EXEC( _environment, "gb", executableName, listingFileName, "gbz80" );
168
169 char * p;
170
171 if ( _environment->listingFileName ) {
172 strcopy( binaryName, _environment->asmFileName );
173 p = strstr( binaryName, ".asm" );
174 if ( p ) {
175 *(p+1) = 'l';
176 *(p+2) = 'i';
177 *(p+3) = 's';
178 *(p+4) = 0;
179 }
180 TRACE2( " renaming %s to %s", binaryName, _environment->listingFileName );
181 BUILD_SAFE_MOVE( _environment, binaryName, _environment->listingFileName );
182 }
183
184 strcopy( binaryName, _environment->asmFileName );
185 p = strstr( binaryName, ".asm" );
186 if ( p ) {
187 *(p+1) = 'o';
188 *(p+2) = 0;
189 }
190 system_remove_safe( _environment, binaryName );
191
192 strcopy( binaryName, _environment->asmFileName );
193 p = strstr( binaryName, ".asm" );
194 if ( p ) {
195 *p = 0;
196 --p;
197 strcat( p, "_code.bin");
198 }
199
200 FILE * binaryFile = fopen( binaryName, "rb" );
201 fseek( binaryFile, 0, SEEK_END );
202 long size = ftell( binaryFile );
203 fseek( binaryFile, 0, SEEK_SET );
204 char * part = malloc( size );
205 (void)!fread( part, size, 1, binaryFile );
206 fclose( binaryFile );
207
208 strcopy( binaryName, _environment->asmFileName );
209 p = strstr( binaryName, ".asm" );
210 if ( p ) {
211 *p = 0;
212 --p;
213 strcat( p, ".bin");
214 }
215
216 binaryFile = fopen( binaryName, "wb" );
217 fwrite( part, size, 1, binaryFile );
218 fclose( binaryFile );
219
220 strcopy( binaryName, _environment->asmFileName );
221 p = strstr( binaryName, ".asm" );
222 if ( p ) {
223 *p = 0;
224 --p;
225 strcat( p, "_data.bin");
226 }
227
228 binaryFile = fopen( binaryName, "rb" );
229 fseek( binaryFile, 0, SEEK_END );
230 size = ftell( binaryFile );
231 fseek( binaryFile, 0, SEEK_SET );
232 part = malloc( size );
233 (void)!fread( part, size, 1, binaryFile );
234 fclose( binaryFile );
235
236 strcopy( binaryName, _environment->asmFileName );
237 p = strstr( binaryName, ".asm" );
238 if ( p ) {
239 *p = 0;
240 --p;
241 strcat( p, ".bin");
242 }
243
244 binaryFile = fopen( binaryName, "a+b" );
245 fwrite( part, size, 1, binaryFile );
246 fclose( binaryFile );
247
248 strcopy( binaryNameDefinitive, _environment->exeFileName );
249 p = strstr( binaryNameDefinitive, ".gb" );
250 if ( p ) {
251 *p = 0;
252 --p;
253 strcat( p, ".bin");
254 }
255 BUILD_SAFE_MOVE( _environment, binaryName, binaryNameDefinitive );
256
257 BUILD_TOOLCHAIN_Z88DK_GET_EXECUTABLE_APPMAKE( _environment, executableName );
258
259 char pipes[256];
260
261 #ifdef _WIN32
262 strcopy( pipes, ">nul 2>nul");
263 #else
264 strcopy( pipes, ">/dev/null 2>/dev/null");
265 #endif
266
267 sprintf( commandLine, "\"%s\" +gb -b \"%s\" %s",
268 executableName,
269 binaryNameDefinitive,
270 pipes );
271
272 if ( system_call( _environment, commandLine ) ) {
273 printf("The compilation of assembly program failed.\n\n");
274 printf("Please use option '-I' to install chain tool.\n\n");
275 return;
276 };
277
278 if ( strstr( _environment->exeFileName, ".gb.gb" ) ) {
279 strcopy( binaryNameDefinitive, _environment->exeFileName );
280 p = strstr( binaryNameDefinitive, ".gb" );
281 if ( p ) {
282 *p = 0;
283 --p;
284 strcat( p, ".gb");
285 }
286 BUILD_SAFE_MOVE( _environment, binaryNameDefinitive, _environment->exeFileName );
287 }
288
289 char * cartridge;
290 binaryFile = fopen( _environment->exeFileName, "rb" );
291 fseek( binaryFile, 0, SEEK_END );
292 size = ftell( binaryFile );
293 cartridge = malloc( size );
294 fseek( binaryFile, 0, SEEK_SET );
295 (void)!fread( cartridge, size, 1, binaryFile );
296 fclose( binaryFile );
297
298 apply_cartridge_header( _environment, cartridge, size );
299
300 binaryFile = fopen( _environment->exeFileName, "wb" );
301 fwrite( cartridge, size, 1, binaryFile );
302 fclose( binaryFile );
303
304
305
306// strcopy( binaryName, _environment->asmFileName );
307// p = strstr( binaryName, ".asm" );
308// if ( p ) {
309// strcat( p, "_data_user.bin");
310// }
311// remove(binaryName);
312
313// strcopy( binaryName, _environment->asmFileName );
314// p = strstr( binaryName, ".asm" );
315// if ( p ) {
316// strcat( p, "_code_user.bin");
317// }
318// remove(binaryName);
319
320// }
321
322// void generate_rom( Environment * _environment ) {
323
324// char commandLine[8*MAX_TEMPORARY_STORAGE];
325// char executableName[MAX_TEMPORARY_STORAGE];
326// char binaryName[MAX_TEMPORARY_STORAGE];
327// char listingFileName[MAX_TEMPORARY_STORAGE];
328
329// char * p;
330
331// strcopy( binaryName, _environment->asmFileName );
332// p = strstr( binaryName, ".asm" );
333// if ( p ) {
334// *p = 0;
335// --p;
336// strcat( p, ".bin");
337// }
338
339// BUILD_TOOLCHAIN_Z88DK_GET_EXECUTABLE_APPMAKE( _environment, executableName );
340
341// char pipes[256];
342
343// #ifdef _WIN32
344// strcopy( pipes, ">nul 2>nul");
345// #else
346// strcopy( pipes, ">/dev/null 2>/dev/null");
347// #endif
348
349// sprintf( commandLine, "\"%s\" +msxrom -b \"%s\" %s",
350// executableName,
351// binaryName,
352// pipes );
353
354// p = strstr( binaryName, ".bin" );
355// if ( p ) {
356// *(p+1) = 'r';
357// *(p+2) = 'o';
358// *(p+3) = 'm';
359// }
360
361// if ( system_call( _environment, commandLine ) ) {
362// printf("The compilation of assembly program failed.\n\n");
363// printf("Please use option '-I' to install chain tool.\n\n");
364// return;
365// };
366
367// remove( _environment->exeFileName );
368
369// BUILD_SAFE_MOVE( _environment, binaryName, _environment->exeFileName );
370
371// char symbolName[MAX_TEMPORARY_STORAGE];
372// strcopy( symbolName, _environment->exeFileName );
373// p = strstr( symbolName, ".rom" );
374// if ( p ) {
375// *p = 0;
376// --p;
377// strcat( p, ".sym");
378
379// strcopy( binaryName, _environment->asmFileName );
380// p = strstr( binaryName, ".asm" );
381// if ( p ) {
382// *p = 0;
383// --p;
384// strcat( p, ".sym");
385// BUILD_SAFE_MOVE( _environment, binaryName, symbolName );
386// }
387// }
388
389// if ( _environment->listingFileName ) {
390// strcopy( binaryName, _environment->asmFileName );
391// p = strstr( binaryName, ".asm" );
392// if ( p ) {
393// *p = 0;
394// --p;
395// strcat( p, ".lis");
396// BUILD_SAFE_MOVE( _environment, binaryName, _environment->listingFileName );
397// }
398
399// if ( _environment->profileFileName && _environment->profileCycles ) {
400// strcopy( binaryName, _environment->profileFileName );
401// if ( _environment->executerFileName ) {
402// sprintf(executableName, "%s", _environment->executerFileName );
403// } else if( access( "runz80.exe", F_OK ) == 0 ) {
404// sprintf(executableName, "%s", "runz80.exe" );
405// } else {
406// sprintf(executableName, "%s", "runz80" );
407// }
408
409// sprintf( commandLine, "\"%s\" -m -p \"%s\" %d -l 4000 \"%s\" -R 4010 -u \"%s\" \"%s\"",
410// executableName,
411// binaryName,
412// _environment->profileCycles ? _environment->profileCycles : 1000000,
413// _environment->exeFileName,
414// _environment->listingFileName,
415// pipes );
416
417// if ( system_call( _environment, commandLine ) ) {
418// printf("The profiling of assembly program failed.\n\n");
419// return;
420// };
421
422// }
423
424// }
425
426// strcopy( binaryName, _environment->asmFileName );
427// p = strstr( binaryName, ".asm" );
428// if ( p ) {
429// strcat( p, "_data_user.bin");
430// }
431// remove(binaryName);
432
433// strcopy( binaryName, _environment->asmFileName );
434// p = strstr( binaryName, ".asm" );
435// if ( p ) {
436// strcat( p, "_code_user.bin");
437// }
438// remove(binaryName);
439
440}
441
442void target_cleanup( Environment * _environment ) {
443
444 if ( _environment->exeFileName ) {
445
446 char binFileName[MAX_TEMPORARY_STORAGE];
447
448 // strcopy( binFileName, _environment->exeFileName );
449 // char * p = strrchr( binFileName, '.' );
450 // memcpy( p, ".bin", 4 );
451
452 remove( _environment->configurationFileName );
453 // remove( binFileName );
454 remove( _environment->asmFileName );
455
456 if ( _environment->analysis && _environment->listingFileName ) {
457 target_analysis( _environment );
458 }
459
460 }
461
462}
463void target_linkage( Environment * _environment ) {
464
465 switch( _environment->outputFileType ) {
467 generate_gb( _environment );
468 break;
469 default:
471 }
472
473}
int system_call(Environment *_environment, char *_commandline)
Call an external executable.
int system_remove_safe(Environment *_environment, char *_filename)
void target_linkage(Environment *_environment)
Convert C64's assembly to executable.
Definition _build.c:327
void target_cleanup(Environment *_environment)
Definition _build.c:343
void target_analysis(Environment *_environment)
Definition _cleanup.c:68
int size
Definition _optimizer.c:678
void generate_gb(Environment *_environment)
Definition _build.c:153
#define TILEMAP_MODE_BGB
Definition gb.h:230
char * listingFileName
Definition ugbc.h:2305
int currentMode
Definition ugbc.h:2696
int analysis
Definition ugbc.h:2365
char * configurationFileName
Definition ugbc.h:2295
OutputFileType outputFileType
Definition ugbc.h:2452
char * asmFileName
Definition ugbc.h:2285
char * exeFileName
Definition ugbc.h:2290
void * malloc(YYSIZE_T)
@ OUTPUT_FILE_TYPE_GB
Definition ugbc.h:271
#define BUILD_SAFE_REMOVE(_environment, filename)
Definition ugbc.h:4748
#define MAX_TEMPORARY_STORAGE
Definition ugbc.h:563
#define BUILD_TOOLCHAIN_Z88DK_GET_LISTING_FILE(_environment, listingFileName)
Definition ugbc.h:4810
struct _Environment Environment
Structure of compilation environment.
#define BUILD_TOOLCHAIN_Z88DK_GET_EXECUTABLE_Z80ASM(_environment, executableName)
Definition ugbc.h:4795
#define BUILD_SAFE_MOVE(_environment, source, destination)
Definition ugbc.h:4751
#define TRACE2(s, p1, p2)
Definition ugbc.h:88
#define BUILD_TOOLCHAIN_Z88DK_EXEC(_environment, target, executableName, listingFileName, cpu)
Definition ugbc.h:4818
#define CRITICAL_UNSUPPORTED_OUTPUT_FILE_TYPE(t)
Definition ugbc.h:3537
#define BUILD_TOOLCHAIN_Z88DK_GET_EXECUTABLE_APPMAKE(_environment, executableName)
Definition ugbc.h:4840
char OUTPUT_FILE_TYPE_AS_STRING[][16]
char * strcopy(char *_dest, char *_source)