Compare commits

..

53 Commits

Author SHA1 Message Date
Anthony J. Bentley
00de7674af Now that install dirs are created, this error is unlikely to occur. 2014-10-03 15:17:49 -06:00
Anthony J. Bentley
32fa032a62 Makefile: Create install directories if they don’t exist. 2014-10-03 15:14:40 -06:00
Anthony J. Bentley
73e44cb803 Fix dependencies for Yacc files. Improve Makefile POSIX compliance.
Parallel building issue pointed out by murphm8 and chastai.
2014-09-26 15:27:52 -06:00
Anthony J. Bentley
3e4350afa4 Don't cast calls to malloc(). 2014-09-26 00:39:29 -06:00
Anthony J. Bentley
0d07caba60 Remove inconsistent version numbering. 2014-09-25 20:56:15 -06:00
Anthony J. Bentley
3992ce2502 Separate errors that shouldn't have been combined in the first place. 2014-09-25 20:40:25 -06:00
Anthony J. Bentley
215d6f0c5b Revert 97d431d1f4ad404e282e3781bd195be3f053734d; it breaks things. 2014-09-24 03:40:50 -06:00
Anthony J. Bentley
f3394f46b4 Fix MinGW target. 2014-09-24 03:17:33 -06:00
Anthony J. Bentley
e3df758897 Update license. 2014-09-24 03:07:43 -06:00
Anthony J. Bentley
d7319ecd00 Remove rgblib.
I have never used it and it's probably been broken for years.
2014-09-24 03:03:42 -06:00
Anthony J. Bentley
d661b3a532 Now that we replace missing libc functions, switch back to err(). 2014-09-24 02:50:39 -06:00
Anthony J. Bentley
c0be5ddbb2 Remove dead stores. 2014-09-24 01:19:05 -06:00
Anthony J. Bentley
97d431d1f4 rgbasm: Avoid unnecessary filename copying. 2014-09-24 00:52:00 -06:00
Anthony J. Bentley
a849e1107e Improve POSIX compliance in the Makefile.
Set .POSIX and don't use the += operator.
2014-09-24 00:38:19 -06:00
Anthony J. Bentley
a41bdff88f Wrap Makefile to 80 characters. 2014-09-24 00:28:14 -06:00
Anthony J. Bentley
cb383e6b1a Unclutter Makefile: use $Q instead of ${Q}. 2014-09-24 00:26:46 -06:00
Anthony J. Bentley
45b6872e2a rgbasm: Fix TOCTOU and reduce buffering. 2014-09-24 00:23:40 -06:00
Anthony J. Bentley
056109652d rgbasm: Don't allocate an unnecessary buffer. 2014-09-23 22:22:39 -06:00
Anthony J. Bentley
284600ef1f rgblink: Don't allocate unnecessary buffer. Delete unused flag. 2014-09-23 22:17:43 -06:00
YamaArashi
2bf31870a7 Cleaned up lexer
- separated the lexer into multiple functions so it is more readable
- fixed issue with long label names in macro arguments
- added error checking code to prevent buffer overflows
2014-08-22 21:44:18 -07:00
YamaArashi
6198cc185c Remove __LINE__ 2014-08-22 01:52:21 -07:00
YamaArashi
e4571bc0fc Make _NARG work 2014-08-21 19:53:42 -07:00
Anthony J. Bentley
46269240c8 Merge branch 'update-legacy-instructions' of https://github.com/yenatch/rgbds 2014-08-21 11:29:34 -06:00
YamaArashi
b1269ab53a Improve rgbasm performance 2014-08-21 02:57:43 -07:00
Anthony J. Bentley
3ecd169cd6 Revert previous commit. asmy.y is autogenerated from other .y files. 2014-02-21 03:20:44 -07:00
Anthony J. Bentley
2dab1474b8 asmy.y should not be in gitignore. 2014-02-21 00:56:34 -07:00
Anthony J. Bentley
08b1b97a45 Preserve the ability to set pad_value in rgbfix. 2014-02-09 02:58:00 -07:00
Anthony J. Bentley
17192ea6f0 Improve performance when padding: don't write a byte at a time. 2014-02-08 23:26:43 -07:00
Anthony J. Bentley
0f488b6759 Remove unused alloca() implementation. 2014-01-31 00:01:42 -07:00
yenatch
2ff286223b add instruction "ld hl, sp+nn"
The previous "ld hl, [sp+nn]" is incorrect, but remains for compatibility.
2014-01-14 11:51:18 -05:00
Anthony J. Bentley
af5f889326 Merge https://github.com/yenatch/rgbds 2014-01-12 21:30:39 -07:00
Anthony J. Bentley
3e92f33319 Provide a friendlier error when manpage directories don’t exist. 2014-01-11 18:46:33 -07:00
yenatch
0ffa4ce9ef rgbasm: let rgblink try to import undefined symbols
Manual imports are inconvenient and don't provide any functionality.
2014-01-07 18:14:58 -05:00
yenatch
fd4b5c8925 rgbasm: update manpage to include -v 2013-12-03 21:58:39 -05:00
yenatch
bc99ee2210 rgbasm: -v option (verbose) 2013-12-03 00:25:12 -05:00
Anthony J. Bentley
de269987f7 Add "jp hl" as a valid instruction.
"jp [hl]" has been around for decades even though it makes no sense.
This is better.
2013-09-05 20:51:58 -06:00
Anthony J. Bentley
7770827cce Redefine consistent names for section types, and document the changes. 2013-07-31 22:14:31 -06:00
Anthony J. Bentley
7ab9742299 Implement SRAM sections. 2013-07-31 20:15:40 -06:00
Anthony J. Bentley
6aecf65552 Fix incorrect manpage macro. 2013-07-23 19:04:02 -06:00
Anthony J. Bentley
2571dc459c Delete more files on clean. 2013-06-20 04:56:55 -06:00
Anthony J. Bentley
da19380cc4 Add a new WRAMX section type, for banked (CGB) WRAM sections. 2013-06-19 21:19:51 -06:00
Anthony J. Bentley
ab47428c0e Improve error message. 2013-05-28 02:23:48 -06:00
Anthony J. Bentley
23b29a9ae1 Fix bug recently introduced to fatalerror(). 2013-05-28 02:22:49 -06:00
Anthony J. Bentley
35448887af Implement VRAM banks. 2013-05-23 13:44:12 -06:00
Anthony J. Bentley
6ccd386587 Make it possible to disable emitting nop after halt. 2013-05-19 17:56:41 -06:00
Anthony J. Bentley
34d40a67c9 Remove unused variable. 2013-05-19 17:08:44 -06:00
Anthony J. Bentley
c21c0f458f Improve error messages. 2013-05-19 17:07:34 -06:00
Anthony J. Bentley
51c01e3aad Remove some dead code. 2013-05-19 16:14:31 -06:00
Anthony J. Bentley
d0d85abb97 Fix accidental case fallthrough. 2013-05-19 15:51:40 -06:00
Anthony J. Bentley
88ac0282e4 Add HTML manuals to the clean target. 2013-04-11 13:27:31 -06:00
Anthony J. Bentley
8811784b71 rgbfix: exit on invalid usage. 2013-04-11 09:28:38 -06:00
Anthony J. Bentley
6579743410 Add support for 8 MiB ROMs, the largest size possible with MBC5. 2012-12-26 21:41:47 -07:00
Anthony J. Bentley
b90406861d Readability (whitespace). 2012-12-26 21:12:52 -07:00
59 changed files with 1965 additions and 2398 deletions

10
LICENSE
View File

@@ -1,5 +1,5 @@
rgbasm, rgblink, and rgblib are derived from Justin Lloyd's RGBDS, which
is released under the following license:
rgbasm and rgblink are derived from Justin Lloyd's RGBDS, which is
released under the following license:
DO WHATEVER PUBLIC LICENSE*
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@@ -17,3 +17,9 @@ is released under the following license:
rgbfix was rewritten from scratch by Anthony J. Bentley, and is released
under the ISC license; see the source file for the text of the license.
extern/err.c is derived from the Musl C library, http://www.musl-libc.org,
and is released under the MIT license.
extern/strl.c is derived from the OpenBSD Project, http://www.openbsd.org,
and is released under the BSD license.

100
Makefile
View File

@@ -1,4 +1,6 @@
CFLAGS += -Wall -Iinclude -Iinclude/asm/gameboy -g -std=c99
.POSIX:
REALCFLAGS = ${CFLAGS} -Wall -Iinclude -Iinclude/asm/gameboy -g -std=c99
# User-defined variables
PREFIX = /usr/local
@@ -13,7 +15,6 @@ yacc_pre := \
src/asm/gameboy/yaccprt4.y
rgbasm_obj := \
src/asm/alloca.o \
src/asm/asmy.o \
src/asm/fstack.o \
src/asm/globlex.o \
@@ -23,11 +24,10 @@ rgbasm_obj := \
src/asm/output.o \
src/asm/rpn.o \
src/asm/symbol.o \
src/asm/gameboy/locallex.o
rgblib_obj := \
src/lib/library.o \
src/lib/main.o
src/asm/gameboy/locallex.o \
src/extern/err.o \
src/extern/strlcpy.o \
src/extern/strlcat.o
rgblink_obj := \
src/link/assign.o \
@@ -37,55 +37,53 @@ rgblink_obj := \
src/link/object.o \
src/link/output.o \
src/link/patch.o \
src/link/symbol.o
src/link/symbol.o \
src/extern/err.o
rgbfix_obj := \
src/fix/main.o
src/fix/main.o \
src/extern/err.o
all: rgbasm rgblib rgblink rgbfix
all: rgbasm rgblink rgbfix
clean:
${Q}rm -rf rgbasm rgbasm.exe ${rgbasm_obj}
${Q}rm -rf rgblib rgblib.exe ${rgblib_obj}
${Q}rm -rf rgblink rgblink.exe ${rgblink_obj}
${Q}rm -rf rgbfix rgbfix.exe ${rgbfix_obj}
${Q}rm -rf src/asm/asmy.c
$Qrm -rf rgbds.html
$Qrm -rf rgbasm rgbasm.exe ${rgbasm_obj} rgbasm.html
$Qrm -rf rgblink rgblink.exe ${rgblink_obj} rgblink.html
$Qrm -rf rgbfix rgbfix.exe ${rgbfix_obj} rgbfix.html
$Qrm -rf src/asm/asmy.c src/asm/asmy.h src/asm/asmy.y
install: all
${Q}install -s -m 555 rgbasm ${BINPREFIX}/rgbasm
${Q}install -s -m 555 rgbfix ${BINPREFIX}/rgbfix
${Q}install -s -m 555 rgblink ${BINPREFIX}/rgblink
${Q}install -s -m 555 rgblib ${BINPREFIX}/rgblib
${Q}install -m 444 src/rgbds.7 ${MANPREFIX}/man7/rgbds.7
${Q}install -m 444 src/asm/rgbasm.1 \
${MANPREFIX}/man1/rgbasm.1
${Q}install -m 444 src/fix/rgbfix.1 \
${MANPREFIX}/man1/rgbfix.1
${Q}install -m 444 src/link/rgblink.1 \
${MANPREFIX}/man1/rgblink.1
${Q}install -m 444 src/lib/rgblib.1 \
${MANPREFIX}/man1/rgblib.1
$Qmkdir -p ${BINPREFIX}
$Qinstall -s -m 555 rgbasm ${BINPREFIX}/rgbasm
$Qinstall -s -m 555 rgbfix ${BINPREFIX}/rgbfix
$Qinstall -s -m 555 rgblink ${BINPREFIX}/rgblink
$Qmkdir -p ${MANPREFIX}/man1 ${MANPREFIX}/man7
$Qinstall -m 444 src/rgbds.7 ${MANPREFIX}/man7/rgbds.7
$Qinstall -m 444 src/asm/rgbasm.1 ${MANPREFIX}/man1/rgbasm.1
$Qinstall -m 444 src/fix/rgbfix.1 ${MANPREFIX}/man1/rgbfix.1
$Qinstall -m 444 src/link/rgblink.1 ${MANPREFIX}/man1/rgblink.1
rgbasm: ${rgbasm_obj}
${Q}${CC} ${CFLAGS} -o $@ ${rgbasm_obj} -lm
rgblib: ${rgblib_obj}
${Q}${CC} ${CFLAGS} -o $@ ${rgblib_obj}
$Q${CC} ${REALCFLAGS} -o $@ ${rgbasm_obj} -lm
rgblink: ${rgblink_obj}
${Q}${CC} ${CFLAGS} -o $@ ${rgblink_obj}
$Q${CC} ${REALCFLAGS} -o $@ ${rgblink_obj}
rgbfix: ${rgbfix_obj}
${Q}${CC} ${CFLAGS} -o $@ ${rgbfix_obj}
$Q${CC} ${REALCFLAGS} -o $@ ${rgbfix_obj}
.y.c:
$Q${YACC} -d ${YFLAGS} -o $@ $<
.c.o:
${Q}${CC} ${CFLAGS} -c -o $@ $<
$Q${CC} ${REALCFLAGS} -c -o $@ $<
src/asm/asmy.c: src/asm/asmy.y
${Q}${YACC} -d -o $@ $<
src/asm/gameboy/locallex.c src/asm/globlex.c src/asm/lexer.c: src/asm/asmy.h
src/asm/asmy.h: src/asm/asmy.c
src/asm/asmy.y: ${yacc_pre}
${Q}cat ${yacc_pre} > $@
$Qcat ${yacc_pre} > $@
# Below is a target for the project maintainer to easily create win32 exes.
@@ -93,19 +91,23 @@ src/asm/asmy.y: ${yacc_pre}
# If you're building on Windows with Cygwin or Mingw, just follow the Unix
# install instructions instead.
mingw:
${Q}env PATH=/usr/local/mingw32/bin:/bin:/usr/bin:/usr/local/bin make CC=gcc CFLAGS="-I/usr/local/mingw32/include ${CFLAGS}"
${Q}mv rgbasm rgbasm.exe
${Q}mv rgblib rgblib.exe
${Q}mv rgblink rgblink.exe
${Q}mv rgbfix rgbfix.exe
$Qenv PATH=/usr/local/mingw32/bin:/bin:/usr/bin:/usr/local/bin \
make CC=gcc CFLAGS="-I/usr/local/mingw32/include \
-D__progname=\\\"\\\" ${CFLAGS}"
$Qmv rgbasm rgbasm.exe
$Qmv rgblink rgblink.exe
$Qmv rgbfix rgbfix.exe
# Below is a target for the project maintainer to easily create web manuals.
# It relies on mandoc: http://mdocml.bsd.lv
MANDOC = -Thtml -Oman=/rgbds/manual/%N/ -Ostyle=/rgbds/manual/manual.css -Ios=General
MANDOC = -Thtml -Ios=General -Oman=/rgbds/manual/%N/ \
-Ostyle=/rgbds/manual/manual.css
wwwman:
${Q}mandoc ${MANDOC} src/rgbds.7 | sed s/OpenBSD/General/ > rgbds.html
${Q}mandoc ${MANDOC} src/asm/rgbasm.1 | sed s/OpenBSD/General/ > rgbasm.html
${Q}mandoc ${MANDOC} src/fix/rgbfix.1 | sed s/OpenBSD/General/ > rgbfix.html
${Q}mandoc ${MANDOC} src/lib/rgblib.1 | sed s/OpenBSD/General/ > rgblib.html
${Q}mandoc ${MANDOC} src/link/rgblink.1 | sed s/OpenBSD/General/ > rgblink.html
$Qmandoc ${MANDOC} src/rgbds.7 | sed s/OpenBSD/General/ > rgbds.html
$Qmandoc ${MANDOC} src/asm/rgbasm.1 | sed s/OpenBSD/General/ > \
rgbasm.html
$Qmandoc ${MANDOC} src/fix/rgbfix.1 | sed s/OpenBSD/General/ > \
rgbfix.html
$Qmandoc ${MANDOC} src/link/rgblink.1 | sed s/OpenBSD/General/ > \
rgblink.html

1
README
View File

@@ -7,7 +7,6 @@ for the Game Boy and Game Boy Color. It consists of:
- rgbasm (assembler)
- rgblink (linker)
- rgblib (library manager)
- rgbfix (checksum/header fixer)
rgbds-linux is a fork of the original RGBDS which aims to make the programs

View File

@@ -42,7 +42,7 @@
<h3>Other ways than mnemonics to define data</h3>
<ul>
<li><a href="asm/db.htm">Defining constant data</a>
<li><a href="asm/ds.htm">Declaring variables in a BSS section</a>
<li><a href="asm/ds.htm">Declaring variables in a RAM section</a>
<li><a href="asm/incbin.htm">Including binary files</a>
</ul>
@@ -65,10 +65,7 @@
<li><a href="asm/expr_fix.htm">ATAN</a>
<li><a href="asm/expr_fix.htm">ATAN2</a>
<li><a href="asm/miscfunc.htm">BANK</a>
<li><a href="asm/section.htm">BSS</a>
<li><a href="asm/section.htm">CODE</a>
<li><a href="asm/expr_fix.htm">COS</a>
<li><a href="asm/section.htm">DATA</a>
<li><a href="asm/db.htm">DB</a>
<li><a href="asm/miscfunc.htm">DEF</a>
<li><a href="asm/expr_fix.htm">DIV</a>
@@ -101,6 +98,8 @@
<li><a href="asm/pops.htm">PUSHS</a>
<li><a href="asm/rept.htm">REPT</a>
<li><a href="asm/rs.htm">RB</a>
<li><a href="asm/section.htm">ROM0</a>
<li><a href="asm/section.htm">ROMX</a>
<li><a href="asm/rs.htm">RSRESET</a>
<li><a href="asm/rs.htm">RSSET</a>
<li><a href="asm/rs.htm">RW</a>
@@ -108,6 +107,7 @@
<li><a href="asm/set.htm">SET</a>
<li><a href="asm/shift.htm">SHIFT</a>
<li><a href="asm/expr_fix.htm">SIN</a>
<li><a href="asm/section.htm">SRAM</a>
<li><a href="asm/expr_str.htm">STRCAT</a>
<li><a href="asm/expr_str.htm">STRCMP</a>
<li><a href="asm/expr_str.htm">STRIN</a>
@@ -117,6 +117,8 @@
<li><a href="asm/expr_str.htm">STRUPR</a>
<li><a href="asm/expr_fix.htm">TAN</a>
<li><a href="asm/section.htm">VRAM</a>
<li><a href="asm/section.htm">WRAM0</a>
<li><a href="asm/section.htm">WRAMX</a>
<li><a href="asm/fail.htm">WARN</a>
<li><a href="asm/export.htm">XDEF</a>
<li><a href="asm/export.htm">XREF</a>

View File

@@ -10,13 +10,13 @@
<p><dfn>DB</dfn> defines a list of bytes that will be stored in the final image. Ideal for tables and text.</p>
<pre>DB 1,2,3,4,"This is a string"</pre>
<p>Alternatively you can use <dfn>DW</dfn> to store a list of words. Strings are not allowed as arguments to DW.</p>
<p>You can also use DB and DW without arguments. This works exactly like “DS 1” and “DS 2” respectively. Consequently DB and DW can be used in a BSS/HRAM/VRAM section.</p>
<p>You can also use DB and DW without arguments. This works exactly like “DS 1” and “DS 2” respectively. Consequently DB and DW can be used in a WRAM0/WRAMX/HRAM/VRAM/SRAM section.</p>
<h1>See also:</h1>
<ul>
<li><a href="expr_int.htm">Integer and Boolean expressions</a>
<li><a href="expr_fix.htm">Fixed-point expressions and functions</a>
<li><a href="expr_str.htm">String expressions, functions and formatting</a>
<li><a href="ds.htm">Declaring variables in a BSS section</a>
<li><a href="ds.htm">Declaring variables in a RAM section</a>
<li><a href="miscfunc.htm">Other functions</a>
</ul>

View File

@@ -7,7 +7,7 @@
</head>
<body>
<h1>DS</h1>
<p><dfn>DS</dfn> allocates a number of bytes. The content is undefined. This is the preferred method of allocationg space in a <a href="section.htm">BSS section</a>. You can however also use DB and DW without any arguments.</p>
<p><dfn>DS</dfn> allocates a number of bytes. The content is undefined. This is the preferred method of allocationg space in a <a href="section.htm">RAM section</a>. You can however also use DB and DW without any arguments.</p>
<pre>DS str_SIZEOF ;allocate str_SIZEOF bytes</pre>
<h1>See also:</h1>
<ul>

View File

@@ -8,47 +8,54 @@
<body>
<h1>SECTION</h1>
<p>Before you can start writing code you must define a section. This tells the assembler what kind of data follows and if it is code where to put it.</p>
<pre>SECTION "CoolStuff",CODE</pre>
<pre>SECTION "CoolStuff",ROMX</pre>
<p>This switches to the section called <b>"CoolStuff"</b> (or creates it if it doesn't already exits) and it defines it as a code section. All sections within a sourcefile must be identified by a <em>unique</em> name.</p>
<table>
<caption>Section types</caption>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Function</th>
</tr>
</thead>
<tr>
<td>CODE</td>
<td>A code section. The linker decides where to put this. For the Gameboy it also decides which bank to put it in except #0 (the HOME bank).</td>
</tr>
<tr>
<td>DATA</td>
<td>Really just a synonym for CODE.</td>
</tr>
<tr>
<td>BSS</td>
<td>This section is for variables. For the Gameboy it will be placed where the Gameboy RAM is.</td>
</tr>
<tr>
<td>HOME</td>
<td>Gameboy ONLY: A code section that will be placed in Gameboy bank #0.</td>
</tr>
<tr>
<td>VRAM</td>
<td>Gameboy ONLY: This section is for allocating VRAM and will be placed where the Gameboy VRAM is.</td>
</tr>
<tr>
<td>HRAM</td>
<td>Gameboy ONLY: This section is for allocating variables in the high RAM area ($FF80-$FFFE) and will be placed there. Suggested by Jens Ch. Restemeier. NOTE WELL: if you use this method of allocating HRAM the assembler will NOT choose the short addressingmode in the LD instruction because the actual address calculation is done by the linker! If you find this undesirable you can use <a href="rs.htm">RSSET/RB/RW</a> instead or use the LDIO mnemonic. The address calculation is then done by the assembler.</td>
</tr>
</table>
<p>Possible section types are as follows:
<dl>
<dt>ROM0</dt>
<dd>A ROM section. Mapped to memory at $0000$3fff.</dd>
<dt>ROMX</dt>
<dd>A banked ROM section. Mapped to memory at $4000$7fff. Valid banks range from 1 to 511.</dd>
<dt>VRAM</dt>
<dd>A banked video RAM section. Mapped to memory at $8000$9fff. Can only allocate memory, not fill it. Valid banks range from 0 to 1.</dd>
<dt>SRAM</dt>
<dd>A banked external (save) RAM section. Mapped to memory at $a000$bfff. Can only allocate memory, not fill it. Valid banks range from 0 to 3.</dd>
<dt>WRAM0</dt>
<dd>A general-purpose RAM section. Mapped to memory at $c000$cfff. Can only allocate memory, not fill it.</dd>
<dt>WRAMX</dt>
<dd>A banked general-purpose RAM section. Mapped to memory at $d000$dfff. Can only allocate memory, not fill it. Valid banks range from 1 to 7.</dd>
<dt>HRAM</dt>
<dd>A high RAM section. Mapped to memory at $ff80$fffe. Can only allocate memory, not fill it. NOTE WELL: if you use this method of allocating HRAM the assembler will NOT choose the short addressingmode in the LD instruction because the actual address calculation is done by the linker! If you find this undesirable you can use <a href="rs.htm">RSSET/RB/RW</a> instead or use the LDIO mnemonic. The address calculation is then done by the assembler.</dd>
</dl>
<p>The following deprecated section names are aliases for some of the above sections:
<dl>
<dt>HOME</dt>
<dd>Alias for ROM0.</dd>
<dt>CODE</dt>
<dt>DATA</dt>
<dd>Alias for ROMX.</dd>
<dt>BSS</dt>
<dd>Alias for WRAM0.</dd>
</dl>
<p>Due to quite a lot of emails requesting an ORG directive you can now add an address to the sectiontype for the Gameboy:</p>
<pre>SECTION "CoolStuff",HOME[$1234]</pre>
<p>This will force the section to address $1234. This also works with the other sectiontypes. For CODE/DATA sections the linker will then place the section in any bank at the address you specify. If you also want to specify the bank you can do:</p>
<pre>SECTION "CoolStuff",DATA[$4567],BANK[3]</pre>
<pre>SECTION "CoolStuff",ROM0[$1234]</pre>
<p>This will force the section to address $1234. This also works with the other sectiontypes. For ROMX sections the linker will then place the section in any bank at the address you specify. If you also want to specify the bank you can do:</p>
<pre>SECTION "CoolStuff",ROMX[$4567],BANK[3]</pre>
<p>And if you only want to force the section into a certain bank, and not it's position within the bank, that's also possible:</p>
<pre>SECTION "CoolStuff",CODE,BANK[7]</pre>
<pre>SECTION "CoolStuff",ROMX,BANK[7]</pre>
<p><strong>HINT:</strong> If you think this is a lot of typing for doing a simple ORG type thing you can quite easily write an intelligent macro (called ORG for example) that uses <a href="expr_str.htm">\@</a> for the sectionname and determines correct sectiontype etc as arguments for SECTION</p>
<h1>See also:</h1>
<ul>
@@ -58,6 +65,6 @@
<li><a href="pops.htm">POPS and PUSHS:</a> The section stack.
</ul>
<hr>
<p>Last updated <EFBFBD>18 July 1997 by <a href="mailto:surfsmurf@matilde.demon.co.uk">Carsten Sorensen</a></p>
<p>Last updated 18 July 1997 by <a href="mailto:surfsmurf@matilde.demon.co.uk">Carsten Sorensen</a></p>
</body>
</html>

View File

@@ -12,7 +12,6 @@
<li><a href="geninfo.htm">ASMotor General Information</a>
<li><a href="asm.htm">xASM Documentation</a>
<li><a href="link.htm">xLink Documentation</a>
<li><a href="lib.htm">xLib Documentation</a>
<li><a href="fix.htm">RGBFix Documentation</a>
<li><a href="rgb0.htm">The RGB0-2 ObjectFileFormat</a>
</ul>

View File

@@ -1,47 +0,0 @@
<!DOCTYPE HTML PUBliC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>xLib</title>
<link rel="stylesheet" type="text/css" href="./style.css">
</head>
<body>
<h1>xLib Documentation</h1>
<h2>Table of Contents</h2>
<ul>
<li><a href="#history"> History</A>
<li><a href="#usage"> Usage</A>
<li><a href="#commands"> The commands</A>
</ul>
<hr>
<h2 id="history">History</h2>
<table>
<caption>The history of xLib</caption>
<thead>
<tr>
<th scope="col">Version</th>
<th scope="col">Dated</th>
<th scope="col">Release notes</th>
</tr>
</thead>
<tr>
<td>1.0</td>
<td>21 Sep. 1997</td>
<td>First release</td>
</tr>
</table>
<h2 id="usage">Usage</h2>
<pre> xlib library command [module1 module2 ... modulen]</pre>
<h2 id="commands">The Commands</h2>
<p>The <b>command</b> specified after <b>library</b> on the <a href="#Usage">commandline</a> tells xLib what to do.
<p>The following commands are available:
<ul>
<li>a — Adds (or replaces if already present) the modules to the library
<li>d — Deletes the modules specified from the library
<li>l — Lists the library contents
<li>x — Extracts the modules from the library
</ul>
<hr>
<p>Last updated 21 September 1997 by <a href="mailto:surfsmurf@matilde.demon.co.uk">Carsten Sorensen</a></p>
</body>
</html>

View File

@@ -104,27 +104,14 @@
<p>A line starting with # is ignored.
<p>If you use libraries they will only be included if one of the objects actually reference them. This works on a SECTION level and not on a module level. This means that when you write libraries you can put each subroutine in its own SECTION so only the relevant bits are included.
<h2 id="operationtg">Operation for Gameboy (-tg)</h2>
<p><a href="asm.htm#sections">Sections</a> created with <b>HOME</b> in the assembler are placed in the GB bank #0 (the fixed bank $0000-$3FFF) in the order they are loaded from the objectfiles specified in the linkfile. So you want the first file in the linkfile to contain your header. <b>CODE/DATA</b> sections are placed in <em>any bank other than #0</em>. This means you have absolutely <em>no</em> control over which sections goes where. This insures minimal slack (unused bytes) at the end of each bank in the image.
<p><a href="asm.htm#sections">Sections</a> created with <b>ROM0</b> in the assembler are placed in the GB bank #0 (the fixed bank $0000-$3FFF) in the order they are loaded from the objectfiles specified in the linkfile. So you want the first file in the linkfile to contain your header. <b>ROMX</b> sections are placed in <em>any bank other than #0</em>. This means you have absolutely <em>no</em> control over which sections goes where. This insures minimal slack (unused bytes) at the end of each bank in the image.
<p>Currently the linker doesn't calculate the GB checksums.
You must use <a href="fix.htm">RGBFix</a> to do this.
<h3 id="smallmode">Operation for Gameboy small mode (-ts)</h3>
<p>Small mode forces all <b>DATA/CODE</b> sections to be of type <b>HOME</b> and increases the <b>HOME</b> section size from 16kB to 32kB. This also means that <b>CODE/DATA/HOME</b> sections are written to the final image in the order you have specified in the linkfile.
<p>Small mode forces all <b>ROMX</b> sections to be of type <b>ROM0</b> and increases the <b>ROM0</b> section size from 16kB to 32kB. This also means that <b>ROM0/ROMX</b> sections are written to the final image in the order you have specified on the command line.
<p>Currently the linker doesn't calculate the GB checksums. You must use <a href="fix.htm">RGBFix</a> to do this.
<h2 id="psion2">Operation for Psion2 relocatable modules (-tp)</h2>
<p>This is a fileformat for the Psion2 that allows you to load your code into where ever there's any free space. The only sections types allowed are <b>HOME, DATA and BSS</b>. All CODE and DATA sections are written to the output file in the order specified in the linkfile. The BSS are actually then expanded to DATA sections filled with zeroes and appended. This might change later.
<p>The file looks like this (all values are big endian):
<pre>
LONG NumberOfDataBytes
REPT NumberOfDataBytes
DB x
ENDR
LONG NumberOfPatches
REPT NumberOfPatches
LONG x ; A value to add to the word at address x in the code
ENDR
</pre>
<hr>
<p>Last updated 08 October 1997 by <a href="mailto:surfsmurf@matilde.demon.co.uk">Carsten Sorensen</a></p>
</body>

View File

@@ -50,10 +50,10 @@
REPT NumberOfSections
LONG Size ;Size in bytes of this section
BYTE Type ;0 = BSS
BYTE Type ;0 = WRAM0
;1 = VRAM
;2 = CODE
;3 = HOME
;2 = ROMX
;3 = ROM0
;4 = HRAM
LONG Org ;Only present in RGB1. Address to fix this
;section at. -1 if the linker should
@@ -61,8 +61,8 @@
LONG Bank ;Only present in RGB1. Bank to load this
;section into. -1 if the linker should
;decide (normal operation). This field is
;only valid for CODE sections.
IF Type==CODE || Type==HOME
;only valid for ROMX sections.
IF Type==ROMX || Type==ROM0
BYTE Data[Size]
LONG NumberOfPatches

View File

@@ -17,8 +17,6 @@
#include "localasm.h"
#include "asmotor.h"
extern SLONG nLineNo;
extern ULONG nTotalLines;
extern ULONG nPC;

View File

@@ -9,6 +9,8 @@
#ifndef ASMOTOR_ASM_FSTACK_H
#define ASMOTOR_ASM_FSTACK_H
#include <stdio.h>
#include "asm/asm.h"
#include "asm/types.h"
#include "asm/lexer.h"
@@ -27,14 +29,17 @@ struct sContext {
ULONG nREPTBlockSize;
};
extern ULONG fstk_RunInclude(char *s);
void
fstk_RunInclude(char *);
extern void fstk_RunMacroArg(SLONG s);
extern ULONG fstk_Init(char *s);
void
fstk_Init(char *);
extern void fstk_Dump(void);
extern void fstk_AddIncludePath(char *s);
extern ULONG fstk_RunMacro(char *s);
extern void fstk_RunRept(ULONG count);
extern void fstk_FindFile(char *s);
FILE *
fstk_FindFile(char *);
extern int yywrap(void);

View File

@@ -5,7 +5,8 @@
#include "asm/types.h"
#define LEXHASHSIZE 512
#define LEXHASHSIZE (1 << 11)
#define MAXSTRLEN 255
struct sLexInitString {
char *tzName;
@@ -18,7 +19,9 @@ struct sLexFloat {
};
struct yy_buffer_state {
char *pBufferStart;
char *pBufferRealStart; // actual starting address
char *pBufferStart; // address where the data is initially written
// after the "safety margin"
char *pBuffer;
ULONG nBufferSize;
ULONG oAtLineStart;

View File

@@ -1,10 +1,13 @@
#ifndef ASMOTOR_MAIN_H
#define ASMOTOR_MAIN_H
#include <stdbool.h>
struct sOptions {
char gbgfx[4];
char binary[2];
SLONG fillchar;
bool verbose;
//-1 == random
};
@@ -19,10 +22,8 @@ extern void opt_Push(void);
extern void opt_Pop(void);
extern void opt_Parse(char *s);
void fatalerror(char *s);
void yyerror(char *s);
extern char temptext[1024];
void fatalerror(const char *fmt, ...);
void yyerror(const char *fmt, ...);
#define YY_FATAL_ERROR fatalerror

View File

@@ -30,7 +30,7 @@
* Section:
* LONG SizeInBytes
* char Type
* if( Type!=BSS )
* if( Type!=WRAM0 )
* {
* char Data[SizeInBytes]
* Patches
@@ -95,11 +95,13 @@ enum {
};
enum {
SECT_BSS = 0,
SECT_WRAM0 = 0,
SECT_VRAM,
SECT_CODE,
SECT_HOME,
SECT_HRAM
SECT_ROMX,
SECT_ROM0,
SECT_HRAM,
SECT_WRAMX,
SECT_SRAM
};
enum {

View File

@@ -3,7 +3,7 @@
#include "asm/types.h"
#define HASHSIZE 73
#define HASHSIZE (1 << 16)
#define MAXSYMLEN 256
struct sSymbol {
@@ -35,6 +35,7 @@ struct sSymbol {
#define SYMF_CONST 0x200 /* symbol has a constant value, will
* not be changed during linking */
ULONG calchash(char *s);
void sym_PrepPass1(void);
void sym_PrepPass2(void);
void sym_AddLocalReloc(char *tzSym);

View File

@@ -1,9 +1,7 @@
#ifndef ASMOTOR_ASM_TYPES_H
#define ASMOTOR_ASM_TYPES_H
#if defined(AMIGA) || defined(__GNUC__)
#define _MAX_PATH 512
#endif
typedef unsigned char UBYTE;
typedef signed char SBYTE;

View File

@@ -1,21 +0,0 @@
/* asmotor.h
*
* Contains defines for every program in the ASMotor package
*
* Copyright 1997 Carsten Sorensen
*
*/
#ifndef ASMOTOR_ASMOTOR_H
#define ASMOTOR_ASMOTOR_H
#define ASMOTOR
#define ASMOTOR_VERSION "1.10-linux"
#define ASM_VERSION "1.08c"
#define LINK_VERSION "1.06c"
#define RGBFIX_VERSION "1.02"
#define LIB_VERSION "1.00"
#endif

63
include/extern/err.h vendored Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright © 2005-2013 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef EXTERN_ERR_H
#define EXTERN_ERR_H
#ifdef ERR_IN_LIBC
#include <err.h>
#else
#include <stdarg.h>
#define warn rgbds_warn
#define vwarn rgbds_vwarn
#define warnx rgbds_warnx
#define vwarnx rgbds_vwarnx
#define err rgbds_err
#define verr rgbds_verr
#define errx rgbds_errx
#define verrx rgbds_verrx
#ifdef __cplusplus
extern "C" {
#endif
void warn(const char *, ...);
void vwarn(const char *, va_list);
void warnx(const char *, ...);
void vwarnx(const char *, va_list);
void err(int, const char *, ...);
void verr(int, const char *, va_list);
void errx(int, const char *, ...);
void verrx(int, const char *, va_list);
#ifdef __cplusplus
}
#endif
#endif
#endif

13
include/extern/strl.h vendored Normal file
View File

@@ -0,0 +1,13 @@
#ifndef STRL_H
#define STRL_H
#ifdef STRL_IN_LIBC
#include <string.h>
#else
#define strlcpy rgbds_strlcpy
#define strlcat rgbds_strlcat
size_t strlcpy(char *, const char *, size_t);
size_t strlcat(char *, const char *, size_t);
#endif
#endif

View File

@@ -1,13 +0,0 @@
#ifndef ASMOTOR_LIB_LIBRARY_H
#define ASMOTOR_LIB_LIBRARY_H
#include "lib/libwrap.h"
extern sLibrary *lib_Read(char *filename);
extern BBOOL lib_Write(sLibrary * lib, char *filename);
extern sLibrary *lib_AddReplace(sLibrary * lib, char *filename);
extern void lib_Free(sLibrary * lib);
extern sLibrary *lib_DeleteModule(sLibrary * lib, char *filename);
extern sLibrary *lib_Find(sLibrary * lib, char *filename);
#endif

View File

@@ -1,19 +0,0 @@
#ifndef ASMOTOR_LIB_LIBWRAP_H
#define ASMOTOR_LIB_LIBWRAP_H
#include "lib/types.h"
#define MAXNAMELENGTH 256
struct LibraryWrapper {
char tName[MAXNAMELENGTH];
UWORD uwTime;
UWORD uwDate;
SLONG nByteLength;
UBYTE *pData;
struct LibraryWrapper *pNext;
};
typedef struct LibraryWrapper sLibrary;
#endif

View File

@@ -1,16 +0,0 @@
#ifndef ASMOTOR_LIB_TYPES_H
#define ASMOTOR_LIB_TYPES_H
#if defined(AMIGA) || defined(__GNUC__)
#define _MAX_PATH 512
#endif
typedef unsigned char UBYTE;
typedef signed char SBYTE;
typedef unsigned short UWORD;
typedef signed short SWORD;
typedef unsigned long ULONG;
typedef signed long SLONG;
typedef signed char BBOOL;
#endif

View File

@@ -4,12 +4,14 @@
#include "link/types.h"
enum eBankDefine {
BANK_HOME = 0,
BANK_BSS = 256,
BANK_VRAM,
BANK_HRAM
BANK_ROM0 = 0,
BANK_WRAM0 = 512,
BANK_WRAMX,
BANK_VRAM = 520,
BANK_HRAM = 522,
BANK_SRAM = 523
};
#define MAXBANKS 259
#define MAXBANKS 527
extern SLONG area_Avail(SLONG bank);
extern void AssignSections(void);

View File

@@ -1,9 +1,7 @@
#ifndef ASMOTOR_LINK_LINK_H
#define ASMOTOR_LINK_LINK_H
#if defined(AMIGA) || defined(__GNUC__)
#define _MAX_PATH 512
#endif
#include "link/types.h"
@@ -51,11 +49,13 @@ enum eRpnData {
};
enum eSectionType {
SECT_BSS,
SECT_WRAM0,
SECT_VRAM,
SECT_CODE,
SECT_HOME,
SECT_HRAM
SECT_ROMX,
SECT_ROM0,
SECT_HRAM,
SECT_WRAMX,
SECT_SRAM
};
struct sSection {

View File

@@ -2,6 +2,5 @@
#define ASMOTOR_LINK_OBJECT_H
extern void obj_Readfile(char *tzObjectfile);
extern void lib_Readfile(char *tzLibfile);
#endif

View File

@@ -1,9 +1,7 @@
#ifndef ASMOTOR_LINK_TYPES_H
#define ASMOTOR_LINK_TYPES_H
#if defined(AMIGA) || defined(__GNUC__)
#define _MAX_PATH 512
#endif
typedef unsigned char UBYTE;
typedef signed char SBYTE;

View File

@@ -1,466 +0,0 @@
/* alloca.c -- allocate automatically reclaimed memory
(Mostly) portable public-domain implementation -- D A Gwyn
This implementation of the PWB library alloca function,
which is used to allocate space off the run-time stack so
that it is automatically reclaimed upon procedure exit,
was inspired by discussions with J. Q. Johnson of Cornell.
J.Otto Tennant <jot@cray.com> contributed the Cray support.
There are some preprocessor constants that can
be defined when compiling for your specific system, for
improved efficiency; however, the defaults should be okay.
The general concept of this implementation is to keep
track of all alloca-allocated blocks, and reclaim any
that are found to be deeper in the stack than the current
invocation. This heuristic does not reclaim storage as
soon as it becomes invalid, but it will do so eventually.
As a special case, alloca(0) reclaims storage without
allocating any. It is a good idea to use alloca(0) in
your main control loop, etc. to force garbage collection. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef emacs
#include "blockinput.h"
#endif
/* If compiling with GCC 2, this file's not needed. */
#if !defined (__GNUC__) || __GNUC__ < 2
/* If someone has defined alloca as a macro,
there must be some other way alloca is supposed to work. */
#ifndef alloca
#ifdef emacs
#ifdef static
/* actually, only want this if static is defined as ""
-- this is for usg, in which emacs must undefine static
in order to make unexec workable
*/
#ifndef STACK_DIRECTION
you lose-- must know STACK_DIRECTION at compile - time
#endif /* STACK_DIRECTION undefined */
#endif /* static */
#endif /* emacs */
/* If your stack is a linked list of frames, you have to
provide an "address metric" ADDRESS_FUNCTION macro. */
#if defined (CRAY) && defined (CRAY_STACKSEG_END)
long i00afunc();
#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
#else
#define ADDRESS_FUNCTION(arg) &(arg)
#endif
#if __STDC__
typedef void *pointer;
#else
typedef char *pointer;
#endif
#define NULL 0
/* Different portions of Emacs need to call different versions of
malloc. The Emacs executable needs alloca to call xmalloc, because
ordinary malloc isn't protected from input signals. On the other
hand, the utilities in lib-src need alloca to call malloc; some of
them are very simple, and don't have an xmalloc routine.
Non-Emacs programs expect this to call use xmalloc.
Callers below should use malloc. */
/* Carsten Sorensen 09/09/97
* Commented out the following, I want malloc!
#ifndef emacs
#define malloc xmalloc
#endif
extern pointer malloc ();
And added the following line:
*/
#include <stdlib.h>
/* Define STACK_DIRECTION if you know the direction of stack
growth for your system; otherwise it will be automatically
deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
#ifndef STACK_DIRECTION
#define STACK_DIRECTION 0 /* Direction unknown. */
#endif
#if STACK_DIRECTION != 0
#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
#else /* STACK_DIRECTION == 0; need run-time code. */
static int stack_dir; /* 1 or -1 once known. */
#define STACK_DIR stack_dir
static void
find_stack_direction()
{
static char *addr = NULL; /* Address of first `dummy', once
* known. */
auto char dummy; /* To get stack address. */
if (addr == NULL) { /* Initial entry. */
addr = ADDRESS_FUNCTION(dummy);
find_stack_direction(); /* Recurse once. */
} else {
/* Second entry. */
if (ADDRESS_FUNCTION(dummy) > addr)
stack_dir = 1; /* Stack grew upward. */
else
stack_dir = -1; /* Stack grew downward. */
}
}
#endif /* STACK_DIRECTION == 0 */
/* An "alloca header" is used to:
(a) chain together all alloca'ed blocks;
(b) keep track of stack depth.
It is very important that sizeof(header) agree with malloc
alignment chunk size. The following default should work okay. */
#ifndef ALIGN_SIZE
#define ALIGN_SIZE sizeof(double)
#endif
typedef union hdr {
char align[ALIGN_SIZE]; /* To force sizeof(header). */
struct {
union hdr *next;/* For chaining headers. */
char *deep; /* For stack depth measure. */
} h;
} header;
static header *last_alloca_header = NULL; /* -> last alloca header. */
/* Return a pointer to at least SIZE bytes of storage,
which will be automatically reclaimed upon exit from
the procedure that called alloca. Originally, this space
was supposed to be taken from the current stack frame of the
caller, but that method cannot be made to work for some
implementations of C, for example under Gould's UTX/32. */
pointer
alloca(size)
unsigned size;
{
auto char probe; /* Probes stack depth: */
register char *depth = ADDRESS_FUNCTION(probe);
#if STACK_DIRECTION == 0
if (STACK_DIR == 0) /* Unknown growth direction. */
find_stack_direction();
#endif
/* Reclaim garbage, defined as all alloca'd storage that was allocated
* from deeper in the stack than currently. */
{
register header *hp; /* Traverses linked list. */
#ifdef emacs
BLOCK_INPUT;
#endif
for (hp = last_alloca_header; hp != NULL;)
if ((STACK_DIR > 0 && hp->h.deep > depth)
|| (STACK_DIR < 0 && hp->h.deep < depth)) {
register header *np = hp->h.next;
free((pointer) hp); /* Collect garbage. */
hp = np; /* -> next header. */
} else
break; /* Rest are not deeper. */
last_alloca_header = hp; /* -> last valid storage. */
#ifdef emacs
UNBLOCK_INPUT;
#endif
}
if (size == 0)
return NULL; /* No allocation required. */
/* Allocate combined header + user data storage. */
{
register pointer new = malloc(sizeof(header) + size);
/* Address of header. */
((header *) new)->h.next = last_alloca_header;
((header *) new)->h.deep = depth;
last_alloca_header = (header *) new;
/* User storage begins just after header. */
return (pointer) ((char *) new + sizeof(header));
}
}
#if defined (CRAY) && defined (CRAY_STACKSEG_END)
#ifdef DEBUG_I00AFUNC
#include <stdio.h>
#endif
#ifndef CRAY_STACK
#define CRAY_STACK
#ifndef CRAY2
/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
struct stack_control_header {
long shgrow:32; /* Number of times stack has grown. */
long shaseg:32; /* Size of increments to stack. */
long shhwm:32; /* High water mark of stack. */
long shsize:32; /* Current size of stack (all segments). */
};
/* The stack segment linkage control information occurs at
the high-address end of a stack segment. (The stack
grows from low addresses to high addresses.) The initial
part of the stack segment linkage control information is
0200 (octal) words. This provides for register storage
for the routine which overflows the stack. */
struct stack_segment_linkage {
long ss[0200]; /* 0200 overflow words. */
long sssize:32; /* Number of words in this segment. */
long ssbase:32; /* Offset to stack base. */
long:32;
long sspseg:32; /* Offset to linkage control of previous
* segment of stack. */
long:32;
long sstcpt:32; /* Pointer to task common address block. */
long sscsnm; /* Private control structure number for
* microtasking. */
long ssusr1; /* Reserved for user. */
long ssusr2; /* Reserved for user. */
long sstpid; /* Process ID for pid based multi-tasking. */
long ssgvup; /* Pointer to multitasking thread giveup. */
long sscray[7]; /* Reserved for Cray Research. */
long ssa0;
long ssa1;
long ssa2;
long ssa3;
long ssa4;
long ssa5;
long ssa6;
long ssa7;
long sss0;
long sss1;
long sss2;
long sss3;
long sss4;
long sss5;
long sss6;
long sss7;
};
#else /* CRAY2 */
/* The following structure defines the vector of words
returned by the STKSTAT library routine. */
struct stk_stat {
long now; /* Current total stack size. */
long maxc; /* Amount of contiguous space which would be
* required to satisfy the maximum stack
* demand to date. */
long high_water; /* Stack high-water mark. */
long overflows; /* Number of stack overflow ($STKOFEN) calls. */
long hits; /* Number of internal buffer hits. */
long extends; /* Number of block extensions. */
long stko_mallocs; /* Block allocations by $STKOFEN. */
long underflows; /* Number of stack underflow calls ($STKRETN). */
long stko_free; /* Number of deallocations by $STKRETN. */
long stkm_free; /* Number of deallocations by $STKMRET. */
long segments; /* Current number of stack segments. */
long maxs; /* Maximum number of stack segments so far. */
long pad_size; /* Stack pad size. */
long current_address; /* Current stack segment address. */
long current_size; /* Current stack segment size. This number is
* actually corrupted by STKSTAT to include
* the fifteen word trailer area. */
long initial_address; /* Address of initial segment. */
long initial_size; /* Size of initial segment. */
};
/* The following structure describes the data structure which trails
any stack segment. I think that the description in 'asdef' is
out of date. I only describe the parts that I am sure about. */
struct stk_trailer {
long this_address; /* Address of this block. */
long this_size; /* Size of this block (does not include this
* trailer). */
long unknown2;
long unknown3;
long link; /* Address of trailer block of previous
* segment. */
long unknown5;
long unknown6;
long unknown7;
long unknown8;
long unknown9;
long unknown10;
long unknown11;
long unknown12;
long unknown13;
long unknown14;
};
#endif /* CRAY2 */
#endif /* not CRAY_STACK */
#ifdef CRAY2
/* Determine a "stack measure" for an arbitrary ADDRESS.
I doubt that "lint" will like this much. */
static long
i00afunc(long *address)
{
struct stk_stat status;
struct stk_trailer *trailer;
long *block, size;
long result = 0;
/* We want to iterate through all of the segments. The first step is
* to get the stack status structure. We could do this more quickly
* and more directly, perhaps, by referencing the $LM00 common block,
* but I know that this works. */
STKSTAT(&status);
/* Set up the iteration. */
trailer = (struct stk_trailer *) (status.current_address
+ status.current_size - 15);
/* There must be at least one stack segment. Therefore it is a fatal
* error if "trailer" is null. */
if (trailer == 0)
abort();
/* Discard segments that do not contain our argument address. */
while (trailer != 0) {
block = (long *) trailer->this_address;
size = trailer->this_size;
if (block == 0 || size == 0)
abort();
trailer = (struct stk_trailer *) trailer->link;
if ((block <= address) && (address < (block + size)))
break;
}
/* Set the result to the offset in this segment and add the sizes of
* all predecessor segments. */
result = address - block;
if (trailer == 0) {
return result;
}
do {
if (trailer->this_size <= 0)
abort();
result += trailer->this_size;
trailer = (struct stk_trailer *) trailer->link;
}
while (trailer != 0);
/* We are done. Note that if you present a bogus address (one not in
* any segment), you will get a different number back, formed from
* subtracting the address of the first block. This is probably not
* what you want. */
return (result);
}
#else /* not CRAY2 */
/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
Determine the number of the cell within the stack,
given the address of the cell. The purpose of this
routine is to linearize, in some sense, stack addresses
for alloca. */
static long
i00afunc(long address)
{
long stkl = 0;
long size, pseg, this_segment, stack;
long result = 0;
struct stack_segment_linkage *ssptr;
/* Register B67 contains the address of the end of the current stack
* segment. If you (as a subprogram) store your registers on the
* stack and find that you are past the contents of B67, you have
* overflowed the segment.
*
* B67 also points to the stack segment linkage control area, which is
* what we are really interested in. */
stkl = CRAY_STACKSEG_END();
ssptr = (struct stack_segment_linkage *) stkl;
/* If one subtracts 'size' from the end of the segment, one has the
* address of the first word of the segment.
*
* If this is not the first segment, 'pseg' will be nonzero. */
pseg = ssptr->sspseg;
size = ssptr->sssize;
this_segment = stkl - size;
/* It is possible that calling this routine itself caused a stack
* overflow. Discard stack segments which do not contain the target
* address. */
while (!(this_segment <= address && address <= stkl)) {
#ifdef DEBUG_I00AFUNC
fprintf(stderr, "%011o %011o %011o\n", this_segment, address,
stkl);
#endif
if (pseg == 0)
break;
stkl = stkl - pseg;
ssptr = (struct stack_segment_linkage *) stkl;
size = ssptr->sssize;
pseg = ssptr->sspseg;
this_segment = stkl - size;
}
result = address - this_segment;
/* If you subtract pseg from the current end of the stack, you get the
* address of the previous stack segment's end. This seems a little
* convoluted to me, but I'll bet you save a cycle somewhere. */
while (pseg != 0) {
#ifdef DEBUG_I00AFUNC
fprintf(stderr, "%011o %011o\n", pseg, size);
#endif
stkl = stkl - pseg;
ssptr = (struct stack_segment_linkage *) stkl;
size = ssptr->sssize;
pseg = ssptr->sspseg;
result += size;
}
return (result);
}
#endif /* not CRAY2 */
#endif /* CRAY */
#endif /* no alloca */
#endif /* not GCC version 2 */

View File

@@ -5,6 +5,8 @@
*
*/
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -14,6 +16,8 @@
#include "asm/types.h"
#include "asm/main.h"
#include "asm/lexer.h"
#include "extern/err.h"
#include "extern/strl.h"
/*
* RGBAsm - FSTACK.C (FileStack routines)
@@ -62,8 +66,7 @@ pushcontext(void)
while (*ppFileStack)
ppFileStack = &((*ppFileStack)->pNext);
if ((*ppFileStack =
(struct sContext *) malloc(sizeof(struct sContext))) != NULL) {
if ((*ppFileStack = malloc(sizeof(struct sContext))) != NULL) {
(*ppFileStack)->FlexHandle = CurrentFlexHandle;
(*ppFileStack)->pNext = NULL;
strcpy((char *) (*ppFileStack)->tzFileName,
@@ -163,7 +166,7 @@ yywrap(void)
/*
* RGBAsm - FSTACK.C (FileStack routines)
*
* Dump the context stack to stdout
* Dump the context stack to stderr
*
*/
@@ -175,11 +178,12 @@ fstk_Dump(void)
pLastFile = pFileStack;
while (pLastFile) {
printf("%s(%ld) -> ", pLastFile->tzFileName, pLastFile->nLine);
fprintf(stderr, "%s(%ld) -> ", pLastFile->tzFileName,
pLastFile->nLine);
pLastFile = pLastFile->pNext;
}
printf("%s(%ld)", tzCurrentFileName, nLineNo);
fprintf(stderr, "%s(%ld)", tzCurrentFileName, nLineNo);
}
/*
* RGBAsm - FSTACK.C (FileStack routines)
@@ -194,28 +198,33 @@ fstk_AddIncludePath(char *s)
strcpy(IncludePaths[NextIncPath++], s);
}
void
fstk_FindFile(char *s)
FILE *
fstk_FindFile(char *fname)
{
char t[_MAX_PATH + 1];
SLONG i = -1;
char path[PATH_MAX];
int i;
FILE *f;
strcpy(t, s);
if ((f = fopen(fname, "rb")) != NULL || errno != ENOENT) {
return f;
}
while (i < NextIncPath) {
FILE *f;
if ((f = fopen(t, "rb")) != NULL) {
fclose(f);
strcpy(s, t);
return;
for (i = 0; i < NextIncPath; ++i) {
if (strlcpy(path, IncludePaths[i], sizeof path) >=
sizeof path) {
continue;
}
i += 1;
if (i < NextIncPath) {
strcpy(t, IncludePaths[i]);
strcat(t, s);
if (strlcat(path, fname, sizeof path) >= sizeof path) {
continue;
}
if ((f = fopen(path, "rb")) != NULL || errno != ENOENT) {
return f;
}
}
errno = ENOENT;
return NULL;
}
/*
* RGBAsm - FSTACK.C (FileStack routines)
@@ -224,33 +233,30 @@ fstk_FindFile(char *s)
*
*/
ULONG
void
fstk_RunInclude(char *tzFileName)
{
FILE *f;
//printf("INCLUDE: %s\n", s);
f = fstk_FindFile(tzFileName);
fstk_FindFile(tzFileName);
//printf("INCLUDING: %s\n", tzFileName);
if (f == NULL) {
err(1, "Unable to open included file '%s'",
tzFileName);
}
if ((f = fopen(tzFileName, "r")) != NULL) {
pushcontext();
nLineNo = 1;
nCurrentStatus = STAT_isInclude;
strcpy(tzCurrentFileName, tzFileName);
pCurrentFile = f;
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
yy_switch_to_buffer(CurrentFlexHandle);
pushcontext();
nLineNo = 1;
nCurrentStatus = STAT_isInclude;
strcpy(tzCurrentFileName, tzFileName);
pCurrentFile = f;
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
yy_switch_to_buffer(CurrentFlexHandle);
//Dirty hack to give the INCLUDE directive a linefeed
//Dirty hack to give the INCLUDE directive a linefeed
yyunput('\n');
nLineNo -= 1;
return (1);
} else
return (0);
yyunput('\n');
nLineNo -= 1;
}
/*
* RGBAsm - FSTACK.C (FileStack routines)
@@ -326,7 +332,7 @@ fstk_RunString(char *s)
yy_scan_bytes(pSym->pMacro, strlen(pSym->pMacro));
yy_switch_to_buffer(CurrentFlexHandle);
} else
yyerror("No such string symbol");
yyerror("No such string symbol '%s'", s);
}
/*
* RGBAsm - FSTACK.C (FileStack routines)
@@ -359,7 +365,7 @@ fstk_RunRept(ULONG count)
*
*/
ULONG
void
fstk_Init(char *s)
{
char tzFileName[_MAX_PATH + 1];
@@ -367,17 +373,16 @@ fstk_Init(char *s)
sym_AddString("__FILE__", s);
strcpy(tzFileName, s);
fstk_FindFile(tzFileName);
pFileStack = NULL;
if ((pCurrentFile = fopen(tzFileName, "r")) != NULL) {
nMacroCount = 0;
nCurrentStatus = STAT_isInclude;
strcpy(tzCurrentFileName, tzFileName);
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
yy_switch_to_buffer(CurrentFlexHandle);
nLineNo = 1;
return (1);
} else
return (0);
pCurrentFile = fopen(tzFileName, "rb");
if (pCurrentFile == NULL) {
err(1, "Unable to open file '%s'", tzFileName);
}
nMacroCount = 0;
nCurrentStatus = STAT_isInclude;
strcpy(tzCurrentFileName, tzFileName);
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
yy_switch_to_buffer(CurrentFlexHandle);
nLineNo = 1;
}

View File

@@ -1,4 +1,4 @@
%token T_SECT_BSS T_SECT_VRAM T_SECT_CODE T_SECT_HOME T_SECT_HRAM
%token T_SECT_WRAM0 T_SECT_VRAM T_SECT_ROMX T_SECT_ROM0 T_SECT_HRAM T_SECT_WRAMX T_SECT_SRAM
%token T_Z80_ADC T_Z80_ADD T_Z80_AND
%token T_Z80_BIT

View File

@@ -1,48 +1,98 @@
section : T_POP_SECTION string ',' sectiontype
{ out_NewSection($2,$4); }
| T_POP_SECTION string ',' sectiontype '[' const ']'
{
if( $6>=0 && $6<0x10000 )
out_NewAbsSection($2,$4,$6,-1);
else
yyerror( "Address must be 16-bit" );
section:
T_POP_SECTION string ',' sectiontype
{
out_NewSection($2,$4);
}
| T_POP_SECTION string ',' sectiontype '[' const ']'
{
if( $6>=0 && $6<0x10000 )
out_NewAbsSection($2,$4,$6,-1);
else
yyerror("Address $%x not 16-bit", $6);
}
| T_POP_SECTION string ',' sectiontype ',' T_OP_BANK '[' const ']'
{
if( $4==SECT_ROMX ) {
if( $8>=1 && $8<=0x1ff )
out_NewAbsSection($2,$4,-1,$8);
else
yyerror("ROM bank value $%x out of range (1 to $1ff)", $8);
} else if ($4 == SECT_SRAM) {
if ($8 >= 0 && $8 <= 3) {
out_NewAbsSection($2, $4, -1, $8);
} else {
yyerror("SRAM bank value $%x out of range (0 to 3)", $8);
}
} else if ($4 == SECT_WRAMX) {
if ($8 >= 1 && $8 <= 7) {
out_NewAbsSection($2, $4, -1, $8);
} else {
yyerror("WRAMX bank value $%x out of range (1 to 7)", $8);
}
} else if ($4 == SECT_VRAM) {
if ($8 >= 0 && $8 <= 1) {
out_NewAbsSection($2, $4, -1, $8);
} else {
yyerror("VRAM bank value $%x out of range (0 to 1)", $8);
}
} else {
yyerror("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections");
}
}
| T_POP_SECTION string ',' sectiontype '[' const ']' ',' T_OP_BANK '[' const ']'
{
if( $4==SECT_ROMX ) {
if( $6>=0 && $6<0x10000 ) {
if( $11>=1 && $11<=0x1ff )
out_NewAbsSection($2,$4,$6,$11);
else
yyerror("ROM bank value $%x out of range (1 to $1ff)", $11);
} else
yyerror("Address $%x not 16-bit", $6);
} else if ($4 == SECT_SRAM) {
if ($6 >= 0 && $6 < 0x10000) {
if ($11 >= 0 && $11 <= 3) {
out_NewAbsSection($2, $4, $6, $11);
} else {
yyerror("SRAM bank value $%x out of range (0 to 3)", $11);
}
| T_POP_SECTION string ',' sectiontype ',' T_OP_BANK '[' const ']'
{
if( $4==SECT_CODE )
{
if( $8>=1 && $8<=255 )
out_NewAbsSection($2,$4,-1,$8);
else
yyerror( "BANK value out of range" );
}
else
yyerror( "BANK only allowed for CODE/DATA" );
} else {
yyerror("Address $%x not 16-bit", $6);
}
} else if ($4 == SECT_WRAMX) {
if ($6 >= 0 && $6 < 0x10000) {
if ($11 >= 1 && $11 <= 7) {
out_NewAbsSection($2, $4, $6, $11);
} else {
yyerror("WRAMX bank value $%x out of range (1 to 7)", $11);
}
| T_POP_SECTION string ',' sectiontype '[' const ']' ',' T_OP_BANK '[' const ']'
{
if( $4==SECT_CODE )
{
if( $6>=0 && $6<0x10000 )
{
if( $11>=1 && $11<=255 )
out_NewAbsSection($2,$4,$6,$11);
else
yyerror( "BANK value out of range" );
}
else
yyerror( "Address must be 16-bit" );
}
else
yyerror( "BANK only allowed for CODE/DATA" );
} else {
yyerror("Address $%x not 16-bit", $6);
}
} else if ($4 == SECT_VRAM) {
if ($6 >= 0 && $6 < 0x10000) {
if ($11 >= 0 && $11 <= 1) {
out_NewAbsSection($2,$4,$6,$11);
} else {
yyerror("VRAM bank value $%x out of range (0 to 1)", $11);
}
} else {
yyerror("Address $%x not 16-bit", $6);
}
} else {
yyerror("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections");
}
}
;
sectiontype : T_SECT_BSS { $$=SECT_BSS; }
| T_SECT_VRAM { $$=SECT_VRAM; }
| T_SECT_CODE { $$=SECT_CODE; }
| T_SECT_HOME { $$=SECT_HOME; }
| T_SECT_HRAM { $$=SECT_HRAM; }
sectiontype:
T_SECT_WRAM0 { $$=SECT_WRAM0; }
| T_SECT_VRAM { $$=SECT_VRAM; }
| T_SECT_ROMX { $$=SECT_ROMX; }
| T_SECT_ROM0 { $$=SECT_ROM0; }
| T_SECT_HRAM { $$=SECT_HRAM; }
| T_SECT_WRAMX { $$=SECT_WRAMX; }
| T_SECT_SRAM { $$=SECT_SRAM; }
;
@@ -155,8 +205,13 @@ z80_ex : T_Z80_EX T_MODE_HL comma T_MODE_SP_IND
{ out_AbsByte(0xE3); }
;
z80_halt : T_Z80_HALT
{ out_AbsByte(0x76); out_AbsByte(0x00); }
z80_halt: T_Z80_HALT
{
out_AbsByte(0x76);
if (haltnop) {
out_AbsByte(0x00);
}
}
;
z80_inc : T_Z80_INC reg_r
@@ -171,6 +226,8 @@ z80_jp : T_Z80_JP const_16bit
{ out_AbsByte(0xC2|($2<<3)); out_RelWord(&$4); }
| T_Z80_JP T_MODE_HL_IND
{ out_AbsByte(0xE9); }
| T_Z80_JP T_MODE_HL
{ out_AbsByte(0xE9); }
;
z80_jr : T_Z80_JR const_PCrel
@@ -198,7 +255,7 @@ z80_ldio : T_Z80_LDIO T_MODE_A comma op_mem_ind
if( (!rpn_isReloc(&$4))
&& ($4.nVal<0 || ($4.nVal>0xFF && $4.nVal<0xFF00) || $4.nVal>0xFFFF) )
{
yyerror( "Source must be in the IO/HRAM area" );
yyerror("Source address $%x not in HRAM ($FF00 to $FFFE)", $4.nVal);
}
out_AbsByte(0xF0);
@@ -212,7 +269,7 @@ z80_ldio : T_Z80_LDIO T_MODE_A comma op_mem_ind
if( (!rpn_isReloc(&$2))
&& ($2.nVal<0 || ($2.nVal>0xFF && $2.nVal<0xFF00) || $2.nVal>0xFFFF) )
{
yyerror( "Destination must be in the IO/HRAM area" );
yyerror("Destination address $%x not in HRAM ($FF00 to $FFFE)", $2.nVal);
}
out_AbsByte(0xE0);
@@ -233,6 +290,8 @@ z80_ld : z80_ld_mem
z80_ld_hl : T_Z80_LD T_MODE_HL comma '[' T_MODE_SP const_8bit ']'
{ out_AbsByte(0xF8); out_RelByte(&$6); }
| T_Z80_LD T_MODE_HL comma T_MODE_SP const_8bit
{ out_AbsByte(0xF8); out_RelByte(&$5); }
| T_Z80_LD T_MODE_HL comma const_16bit
{ out_AbsByte(0x01|(REG_HL<<4)); out_RelWord(&$4); }
;
@@ -273,7 +332,7 @@ z80_ld_r : T_Z80_LD reg_r comma const_8bit
{
if( ($2==REG_HL_IND) && ($4==REG_HL_IND) )
{
yyerror( "LD (HL),(HL) not allowed" );
yyerror("LD [HL],[HL] not a valid instruction");
}
else
out_AbsByte(0x40|($2<<3)|$4);
@@ -286,7 +345,7 @@ z80_ld_a : T_Z80_LD reg_r comma T_MODE_C_IND
out_AbsByte(0xF2);
else
{
yyerror( "Destination operand must be A" );
yyerror("Destination operand must be A");
}
}
| T_Z80_LD reg_r comma reg_rr
@@ -295,7 +354,7 @@ z80_ld_a : T_Z80_LD reg_r comma T_MODE_C_IND
out_AbsByte(0x0A|($4<<4));
else
{
yyerror( "Destination operand must be A" );
yyerror("Destination operand must be A");
}
}
| T_Z80_LD reg_r comma op_mem_ind
@@ -315,7 +374,7 @@ z80_ld_a : T_Z80_LD reg_r comma T_MODE_C_IND
}
else
{
yyerror( "Destination operand must be A" );
yyerror("Destination operand must be A");
}
}
;
@@ -392,11 +451,11 @@ z80_rst : T_Z80_RST const_8bit
{
if( rpn_isReloc(&$2) )
{
yyerror( "Address for RST must be absolute" );
yyerror("Address for RST must be absolute");
}
else if( ($2.nVal&0x38)!=$2.nVal )
{
yyerror( "Invalid address for RST" );
yyerror("Invalid address $%x for RST", $2.nVal);
}
else
out_AbsByte(0xC7|$2.nVal);

View File

@@ -316,12 +316,17 @@ struct sLexInitString staticstrings[] = {
{"else", T_POP_ELSE},
{"endc", T_POP_ENDC},
{"bss", T_SECT_BSS},
{"wram0", T_SECT_WRAM0},
{"bss", T_SECT_WRAM0}, /* deprecated */
{"vram", T_SECT_VRAM},
{"code", T_SECT_CODE},
{"data", T_SECT_CODE},
{"home", T_SECT_HOME},
{"code", T_SECT_ROMX}, /* deprecated */
{"data", T_SECT_ROMX}, /* deprecated */
{"romx", T_SECT_ROMX},
{"home", T_SECT_ROM0}, /* deprecated */
{"rom0", T_SECT_ROM0},
{"hram", T_SECT_HRAM},
{"wramx", T_SECT_WRAMX},
{"sram", T_SECT_SRAM},
{NAME_RB, T_POP_RB},
{NAME_RW, T_POP_RW},

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,8 @@
#include <math.h>
#include <getopt.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -17,15 +19,11 @@
#include "asm/fstack.h"
#include "asm/output.h"
#include "asm/main.h"
#include "extern/err.h"
int yyparse(void);
void setuplex(void);
#ifdef AMIGA
__near long __stack = 65536L;
#endif
/*
* RGBAsm - MAIN.C
*
@@ -33,14 +31,14 @@ __near long __stack = 65536L;
*
*/
bool haltnop;
clock_t nStartClock, nEndClock;
SLONG nLineNo;
ULONG nTotalLines, nPass, nPC, nIFDepth, nErrors;
extern int yydebug;
char temptext[1024];
/*
* RGBAsm - MAIN.C
*
@@ -136,9 +134,8 @@ opt_Parse(char *s)
newopt.gbgfx[2] = s[3];
newopt.gbgfx[3] = s[4];
} else {
fprintf(stderr, "Must specify exactly 4 characters "
"for option 'g'\n");
exit(1);
errx(1, "Must specify exactly 4 characters for "
"option 'g'");
}
break;
case 'b':
@@ -146,9 +143,8 @@ opt_Parse(char *s)
newopt.binary[0] = s[1];
newopt.binary[1] = s[2];
} else {
fprintf(stderr, "Must specify exactly 2 characters "
"for option 'b'\n");
exit(1);
errx(1, "Must specify exactly 2 characters for option "
"'b'");
}
break;
case 'z':
@@ -157,12 +153,10 @@ opt_Parse(char *s)
result = sscanf(&s[1], "%lx", &newopt.fillchar);
if (!((result == EOF) || (result == 1))) {
fprintf(stderr,
"Invalid argument for option 'z'\n");
exit(1);
errx(1, "Invalid argument for option 'z'");
}
} else {
fprintf(stderr, "Invalid argument for option 'z'\n");
errx(1, "Invalid argument for option 'z'");
exit(1);
}
break;
@@ -179,9 +173,7 @@ opt_Push(void)
{
struct sOptionStackEntry *pOpt;
if ((pOpt =
(struct sOptionStackEntry *)
malloc(sizeof(struct sOptionStackEntry))) != NULL) {
if ((pOpt = malloc(sizeof(struct sOptionStackEntry))) != NULL) {
pOpt->Options = CurrentOptions;
pOpt->pNext = pOptionStack;
pOptionStack = pOpt;
@@ -209,19 +201,33 @@ opt_Pop(void)
*
*/
void
yyerror(char *s)
void
verror(const char *fmt, va_list args)
{
printf("*ERROR*\t");
fprintf(stderr, "ERROR:\t");
fstk_Dump();
printf(" :\n\t%s\n", s);
fprintf(stderr, " :\n\t");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
nErrors += 1;
}
void
fatalerror(char *s)
yyerror(const char *fmt, ...)
{
yyerror(s);
va_list args;
va_start(args, fmt);
verror(fmt, args);
va_end(args);
}
void
fatalerror(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
verror(fmt, args);
va_end(args);
exit(5);
}
/*
@@ -234,9 +240,8 @@ fatalerror(char *s)
void
PrintUsage(void)
{
printf("RGBAsm v" ASM_VERSION " (part of ASMotor " ASMOTOR_VERSION
")\n\n");
printf("Usage: rgbasm [-b chars] [-g chars] [-i path] [-o outfile] [-p pad_value] file\n");
printf("Usage: rgbasm [-v] [-h] [-b chars] [-g chars] [-i path] [-o outfile] [-p pad_value]\n"
" file\n");
exit(1);
}
/*
@@ -256,6 +261,8 @@ main(int argc, char *argv[])
char *tzMainfile;
haltnop = true;
if (argc == 1)
PrintUsage();
@@ -268,22 +275,23 @@ main(int argc, char *argv[])
DefaultOptions.binary[0] = '0';
DefaultOptions.binary[1] = '1';
DefaultOptions.fillchar = 0;
DefaultOptions.verbose = false;
opt_SetCurrentOptions(&DefaultOptions);
newopt = CurrentOptions;
while ((ch = getopt(argc, argv, "b:g:i:o:p:")) != -1) {
while ((ch = getopt(argc, argv, "b:g:hi:o:p:v")) != -1) {
switch (ch) {
case 'b':
if (strlen(optarg) == 2) {
newopt.binary[0] = optarg[1];
newopt.binary[1] = optarg[2];
} else {
fprintf(stderr, "Must specify exactly "
"2 characters for option 'b'\n");
exit(1);
errx(1, "Must specify exactly 2 characters for "
"option 'b'");
}
break;
case 'g':
if (strlen(optarg) == 4) {
newopt.gbgfx[0] = optarg[1];
@@ -291,11 +299,13 @@ main(int argc, char *argv[])
newopt.gbgfx[2] = optarg[3];
newopt.gbgfx[3] = optarg[4];
} else {
fprintf(stderr, "Must specify exactly "
"4 characters for option 'g'\n");
exit(1);
errx(1, "Must specify exactly 4 characters for "
"option 'g'");
}
break;
case 'h':
haltnop = false;
break;
case 'i':
fstk_AddIncludePath(optarg);
break;
@@ -305,16 +315,16 @@ main(int argc, char *argv[])
case 'p':
newopt.fillchar = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
fprintf(stderr,
"Invalid argument for option 'p'\n");
exit(1);
errx(1, "Invalid argument for option 'p'");
}
if (newopt.fillchar < 0 || newopt.fillchar > 0xFF) {
fprintf(stderr, "Argument for option 'p' "
"must be between 0 and 0xFF\n");
exit(1);
errx(1, "Argument for option 'p' must be "
"between 0 and 0xFF");
}
break;
case 'v':
newopt.verbose = true;
break;
default:
PrintUsage();
}
@@ -326,12 +336,13 @@ main(int argc, char *argv[])
DefaultOptions = CurrentOptions;
/* tzMainfile=argv[argn++]; argc-=1; */
tzMainfile = argv[argc - 1];
setuplex();
printf("Assembling %s\n", tzMainfile);
if (CurrentOptions.verbose) {
printf("Assembling %s\n", tzMainfile);
}
nStartClock = clock();
@@ -342,35 +353,40 @@ main(int argc, char *argv[])
nPass = 1;
nErrors = 0;
sym_PrepPass1();
if (fstk_Init(tzMainfile)) {
fstk_Init(tzMainfile);
if (CurrentOptions.verbose) {
printf("Pass 1...\n");
}
yy_set_state(LEX_STATE_NORMAL);
opt_SetCurrentOptions(&DefaultOptions);
yy_set_state(LEX_STATE_NORMAL);
opt_SetCurrentOptions(&DefaultOptions);
if (yyparse() == 0 && nErrors == 0) {
if (nIFDepth == 0) {
nTotalLines = 0;
nLineNo = 1;
nIFDepth = 0;
nPC = 0;
nPass = 2;
nErrors = 0;
sym_PrepPass2();
out_PrepPass2();
fstk_Init(tzMainfile);
yy_set_state(LEX_STATE_NORMAL);
opt_SetCurrentOptions(&DefaultOptions);
if (yyparse() == 0 && nErrors == 0) {
if (nIFDepth == 0) {
nTotalLines = 0;
nLineNo = 1;
nIFDepth = 0;
nPC = 0;
nPass = 2;
nErrors = 0;
sym_PrepPass2();
out_PrepPass2();
fstk_Init(tzMainfile);
yy_set_state(LEX_STATE_NORMAL);
opt_SetCurrentOptions(&DefaultOptions);
if (CurrentOptions.verbose) {
printf("Pass 2...\n");
}
if (yyparse() == 0 && nErrors == 0) {
double timespent;
if (yyparse() == 0 && nErrors == 0) {
double timespent;
nEndClock = clock();
timespent =
((double) (nEndClock - nStartClock))
/ (double) CLOCKS_PER_SEC;
nEndClock = clock();
timespent =
((double) (nEndClock - nStartClock))
/ (double) CLOCKS_PER_SEC;
if (CurrentOptions.verbose) {
printf
("Success! %ld lines in %d.%02d seconds ",
nTotalLines, (int) timespent,
@@ -382,29 +398,22 @@ main(int argc, char *argv[])
printf("(%d lines/minute)\n",
(int) (60 / timespent *
nTotalLines));
out_WriteObject();
} else {
printf
("Assembly aborted in pass 2 (%ld errors)!\n",
nErrors);
//sym_PrintSymbolTable();
exit(5);
}
out_WriteObject();
} else {
fprintf(stderr,
"Unterminated IF construct (%ld levels)!\n",
nIFDepth);
exit(1);
printf
("Assembly aborted in pass 2 (%ld errors)!\n",
nErrors);
//sym_PrintSymbolTable();
exit(5);
}
} else {
fprintf(stderr,
"Assembly aborted in pass 1 (%ld errors)!\n",
nErrors);
exit(1);
errx(1, "Unterminated IF construct (%ld levels)!",
nIFDepth);
}
} else {
printf("File '%s' not found\n", tzMainfile);
exit(5);
errx(1, "Assembly aborted in pass 1 (%ld errors)!",
nErrors);
}
return (0);
return 0;
}

View File

@@ -5,6 +5,7 @@
*
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -16,6 +17,7 @@
#include "asm/main.h"
#include "asm/rpn.h"
#include "asm/fstack.h"
#include "extern/err.h"
#define SECTIONCHUNK 0x4000
@@ -42,6 +44,7 @@ struct PatchSymbol {
ULONG ID;
struct sSymbol *pSymbol;
struct PatchSymbol *pNext;
struct PatchSymbol *pBucketNext; // next symbol in hash table bucket
};
struct SectionStackEntry {
@@ -55,9 +58,11 @@ struct SectionStackEntry {
*
*/
struct PatchSymbol *tHashedPatchSymbols[HASHSIZE];
struct Section *pSectionList = NULL, *pCurrentSection = NULL;
struct PatchSymbol *pPatchSymbols = NULL;
char tzObjectname[_MAX_PATH];
struct PatchSymbol **ppPatchSymbolsTail = &pPatchSymbols;
char *tzObjectname;
struct SectionStackEntry *pSectionStack = NULL;
/*
@@ -72,9 +77,7 @@ out_PushSection(void)
{
struct SectionStackEntry *pSect;
if ((pSect =
(struct SectionStackEntry *)
malloc(sizeof(struct SectionStackEntry))) != NULL) {
if ((pSect = malloc(sizeof(struct SectionStackEntry))) != NULL) {
pSect->pSection = pCurrentSection;
pSect->pNext = pSectionStack;
pSectionStack = pSect;
@@ -251,8 +254,8 @@ writesection(struct Section * pSect, FILE * f)
fputlong(pSect->nBank, f);
//RGB1 addition
if ((pSect->nType == SECT_HOME)
|| (pSect->nType == SECT_CODE)) {
if ((pSect->nType == SECT_ROM0)
|| (pSect->nType == SECT_ROMX)) {
struct Patch *pPatch;
fwrite(pSect->tData, 1, pSect->nPC, f);
@@ -326,30 +329,30 @@ ULONG
addsymbol(struct sSymbol * pSym)
{
struct PatchSymbol *pPSym, **ppPSym;
ULONG ID = 0;
static ULONG nextID = 0;
ULONG hash;
pPSym = pPatchSymbols;
ppPSym = &(pPatchSymbols);
hash = calchash(pSym->tzName);
ppPSym = &(tHashedPatchSymbols[hash]);
while (pPSym) {
if (pSym == pPSym->pSymbol)
return (pPSym->ID);
ppPSym = &(pPSym->pNext);
pPSym = pPSym->pNext;
ID += 1;
while ((*ppPSym) != NULL) {
if (pSym == (*ppPSym)->pSymbol)
return (*ppPSym)->ID;
ppPSym = &((*ppPSym)->pBucketNext);
}
if ((*ppPSym = pPSym =
(struct PatchSymbol *) malloc(sizeof(struct PatchSymbol))) !=
NULL) {
if ((*ppPSym = pPSym = malloc(sizeof(struct PatchSymbol))) != NULL) {
pPSym->pNext = NULL;
pPSym->pBucketNext = NULL;
pPSym->pSymbol = pSym;
pPSym->ID = ID;
return (ID);
pPSym->ID = nextID++;
} else
fatalerror("No memory for patchsymbol");
return ((ULONG) - 1);
*ppPatchSymbolsTail = pPSym;
ppPatchSymbolsTail = &(pPSym->pNext);
return pPSym->ID;
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
@@ -384,24 +387,17 @@ addexports(void)
struct Patch *
allocpatch(void)
{
struct Patch *pPatch, **ppPatch;
struct Patch *pPatch;
pPatch = pCurrentSection->pPatches;
ppPatch = &(pCurrentSection->pPatches);
while (pPatch) {
ppPatch = &(pPatch->pNext);
pPatch = pPatch->pNext;
}
if ((*ppPatch = pPatch =
(struct Patch *) malloc(sizeof(struct Patch))) != NULL) {
pPatch->pNext = NULL;
if ((pPatch = malloc(sizeof(struct Patch))) != NULL) {
pPatch->pNext = pCurrentSection->pPatches;
pPatch->nRPNSize = 0;
pPatch->pRPN = NULL;
} else
fatalerror("No memory for patch");
pCurrentSection->pPatches = pPatch;
return (pPatch);
}
/*
@@ -471,7 +467,7 @@ createpatch(ULONG type, struct Expression * expr)
break;
}
}
if ((pPatch->pRPN = (UBYTE *) malloc(rpnptr)) != NULL) {
if ((pPatch->pRPN = malloc(rpnptr)) != NULL) {
memcpy(pPatch->pRPN, rpnexpr, rpnptr);
pPatch->nRPNSize = rpnptr;
}
@@ -503,13 +499,16 @@ void
checkcodesection(SLONG size)
{
checksection();
if ((pCurrentSection->nType == SECT_HOME
|| pCurrentSection->nType == SECT_CODE)
&& (pCurrentSection->nPC + size <= MAXSECTIONSIZE)) {
if (pCurrentSection->nType != SECT_ROM0 &&
pCurrentSection->nType != SECT_ROMX) {
errx(1, "Section '%s' cannot contain code or data (not a "
"ROM0 or ROMX)", pCurrentSection->pzName);
}
if (pCurrentSection->nPC + size <= MAXSECTIONSIZE) {
if (((pCurrentSection->nPC % SECTIONCHUNK) >
((pCurrentSection->nPC + size) % SECTIONCHUNK))
&& (pCurrentSection->nType == SECT_HOME
|| pCurrentSection->nType == SECT_CODE)) {
&& (pCurrentSection->nType == SECT_ROM0
|| pCurrentSection->nType == SECT_ROMX)) {
if ((pCurrentSection->tData =
(UBYTE *) realloc(pCurrentSection->tData,
((pCurrentSection->nPC +
@@ -522,8 +521,7 @@ checkcodesection(SLONG size)
}
return;
} else
fatalerror
("Section can't contain initialized data or section limit exceeded");
errx(1, "Section '%s' is too big", pCurrentSection->pzName);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
@@ -592,8 +590,10 @@ out_PrepPass2(void)
void
out_SetFileName(char *s)
{
strcpy(tzObjectname, s);
printf("Output filename %s\n", s);
tzObjectname = s;
if (CurrentOptions.verbose) {
printf("Output filename %s\n", s);
}
pSectionList = NULL;
pCurrentSection = NULL;
pPatchSymbols = NULL;
@@ -628,11 +628,8 @@ out_FindSection(char *pzName, ULONG secttype, SLONG org,
pSect = pSect->pNext;
}
if ((*ppSect =
(pSect =
(struct Section *) malloc(sizeof(struct Section)))) != NULL) {
if ((pSect->pzName =
(char *) malloc(strlen(pzName) + 1)) != NULL) {
if ((*ppSect = (pSect = malloc(sizeof(struct Section)))) != NULL) {
if ((pSect->pzName = malloc(strlen(pzName) + 1)) != NULL) {
strcpy(pSect->pzName, pzName);
pSect->nType = secttype;
pSect->nPC = 0;
@@ -642,8 +639,7 @@ out_FindSection(char *pzName, ULONG secttype, SLONG org,
pSect->pPatches = NULL;
pPatchSymbols = NULL;
if ((pSect->tData =
(UBYTE *) malloc(SECTIONCHUNK)) != NULL) {
if ((pSect->tData = malloc(SECTIONCHUNK)) != NULL) {
return (pSect);
} else
fatalerror("Not enough memory for section");
@@ -724,8 +720,8 @@ void
out_Skip(int skip)
{
checksection();
if (!((pCurrentSection->nType == SECT_HOME)
|| (pCurrentSection->nType == SECT_CODE))) {
if (!((pCurrentSection->nType == SECT_ROM0)
|| (pCurrentSection->nType == SECT_ROMX))) {
pCurrentSection->nPC += skip;
nPC += skip;
pPCSymbol->nValue += skip;
@@ -905,30 +901,30 @@ out_BinaryFile(char *s)
{
FILE *f;
fstk_FindFile(s);
f = fstk_FindFile(s);
if (f == NULL) {
err(1, "Unable to open incbin file '%s'", s);
}
if ((f = fopen(s, "rb")) != NULL) {
SLONG fsize;
SLONG fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fseek(f, 0, SEEK_SET);
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fseek(f, 0, SEEK_SET);
checkcodesection(fsize);
checkcodesection(fsize);
if (nPass == 2) {
SLONG dest = nPC;
SLONG todo = fsize;
if (nPass == 2) {
SLONG dest = nPC;
SLONG todo = fsize;
while (todo--)
pCurrentSection->tData[dest++] = fgetc(f);
}
pCurrentSection->nPC += fsize;
nPC += fsize;
pPCSymbol->nValue += fsize;
fclose(f);
} else
fatalerror("File not found");
while (todo--)
pCurrentSection->tData[dest++] = fgetc(f);
}
pCurrentSection->nPC += fsize;
nPC += fsize;
pPCSymbol->nValue += fsize;
fclose(f);
}
void
@@ -942,36 +938,36 @@ out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length)
if (length < 0)
fatalerror("Number of bytes to read must be greater than zero");
fstk_FindFile(s);
f = fstk_FindFile(s);
if (f == NULL) {
err(1, "Unable to open included file '%s'", s);
}
if ((f = fopen(s, "rb")) != NULL) {
SLONG fsize;
SLONG fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fseek(f, 0, SEEK_END);
fsize = ftell(f);
if (start_pos >= fsize)
fatalerror("Specified start position is greater than length of file");
if (start_pos >= fsize)
fatalerror("Specified start position is greater than length of file");
if ((start_pos + length) > fsize)
fatalerror("Specified range in INCBIN is out of bounds");
if ((start_pos + length) > fsize)
fatalerror("Specified range in INCBIN is out of bounds");
fseek(f, start_pos, SEEK_SET);
fseek(f, start_pos, SEEK_SET);
checkcodesection(length);
checkcodesection(length);
if (nPass == 2) {
SLONG dest = nPC;
SLONG todo = length;
if (nPass == 2) {
SLONG dest = nPC;
SLONG todo = length;
while (todo--)
pCurrentSection->tData[dest++] = fgetc(f);
}
pCurrentSection->nPC += length;
nPC += length;
pPCSymbol->nValue += length;
while (todo--)
pCurrentSection->tData[dest++] = fgetc(f);
}
pCurrentSection->nPC += length;
nPC += length;
pPCSymbol->nValue += length;
fclose(f);
} else
fatalerror("File not found");
fclose(f);
}

View File

@@ -6,6 +6,8 @@
.Nd Game Boy assembler
.Sh SYNOPSIS
.Nm rgbasm
.Op Fl v
.Op Fl h
.Op Fl b Ar chars
.Op Fl g Ar chars
.Op Fl i Ar path
@@ -24,6 +26,17 @@ The defaults are 01.
.It Fl g Ar chars
Change the four characters used for binary constants.
The defaults are 0123.
.It Fl h
By default,
.Nm
inserts a
.Sq nop
instruction immediately after any
.Sq halt
instruction.
The
.Fl h
option disables this behavior.
.It Fl i Ar path
Add an include path.
.It Fl o Ar outfile
@@ -31,6 +44,8 @@ Write an object file to the given filename.
.It Fl p Ar pad_value
When padding an image, pad with this value.
The default is 0x00.
.It Fl v
Be verbose.
.El
.Sh EXAMPLES
Assembling a basic source file is simple:
@@ -45,7 +60,6 @@ and
.Sh SEE ALSO
.Xr rgbds 7 ,
.Xr rgbfix 1 ,
.Xr rgblib 1 ,
.Xr rgblink 1 ,
.Xr gbz80 7
.Sh HISTORY

View File

@@ -155,8 +155,7 @@ rpn_Bank(struct Expression * expr, char *tzSym)
psym = sym_FindSymbol(tzSym);
if (nPass == 2 && psym == NULL) {
sprintf(temptext, "'%s' not defined", tzSym);
yyerror(temptext);
yyerror("'%s' not defined", tzSym);
}
expr->isReloc = 1;
pushbyte(expr, RPN_BANK);

View File

@@ -26,7 +26,6 @@ struct sSymbol *tHashedSymbols[HASHSIZE];
struct sSymbol *pScope = NULL;
struct sSymbol *pPCSymbol = NULL;
struct sSymbol *p_NARGSymbol = NULL;
struct sSymbol *p__LINE__Symbol = NULL;
char *currentmacroargs[MAXMACROARGS + 1];
char *newmacroargs[MAXMACROARGS + 1];
char SavedTIME[256];
@@ -44,12 +43,6 @@ Callback_NARG(struct sSymbol * sym)
return (i);
}
SLONG
Callback__LINE__(struct sSymbol * sym)
{
sym = sym;
return (nLineNo);
}
/*
* RGBAsm - SYMBOL.C - Symboltable stuff
*
@@ -75,10 +68,10 @@ getvaluefield(struct sSymbol * sym)
ULONG
calchash(char *s)
{
ULONG hash = 0;
ULONG hash = 5381;
while (*s != 0)
hash += (*s++);
hash = (hash * 33) ^ (*s++);
return (hash % HASHSIZE);
}
@@ -101,8 +94,7 @@ createsymbol(char *s)
while ((*ppsym) != NULL)
ppsym = &((*ppsym)->pNext);
if (((*ppsym) =
(struct sSymbol *) malloc(sizeof(struct sSymbol))) != NULL) {
if (((*ppsym) = malloc(sizeof(struct sSymbol))) != NULL) {
strcpy((*ppsym)->tzName, s);
(*ppsym)->nValue = 0;
(*ppsym)->nType = 0;
@@ -217,8 +209,7 @@ sym_Purge(char *tzName)
free(pSym);
} else {
sprintf(temptext, "'%s' not defined", tzName);
yyerror(temptext);
yyerror("'%s' not defined", tzName);
}
}
/*
@@ -245,10 +236,8 @@ sym_isConstDefined(char *tzName)
nType & (SYMF_EQU | SYMF_SET | SYMF_MACRO | SYMF_STRING)) {
return (1);
} else {
sprintf(temptext,
"'%s' is not allowed as argument to the DEF function",
tzName);
fatalerror(temptext);
fatalerror("'%s' is not allowed as argument to the "
"DEF function", tzName);
}
}
return (0);
@@ -309,8 +298,7 @@ sym_GetStringValue(char *tzSym)
if ((pSym = sym_FindSymbol(tzSym)) != NULL)
return (pSym->pMacro);
else {
sprintf(temptext, "Stringsymbol '%s' not defined", tzSym);
yyerror(temptext);
yyerror("Stringsymbol '%s' not defined", tzSym);
}
return (NULL);
@@ -339,8 +327,7 @@ sym_GetConstantValue(char *s)
fatalerror("Expression must have a constant value");
}
} else {
sprintf(temptext, "'%s' not defined", s);
yyerror(temptext);
yyerror("'%s' not defined", s);
}
return (0);
@@ -365,27 +352,23 @@ sym_GetValue(char *s)
if ((psym = findsymbol(s, pscope)) != NULL) {
if (psym->nType & SYMF_DEFINED) {
if (psym->nType & (SYMF_MACRO | SYMF_STRING)) {
sprintf(temptext,
"'%s' is a macro or string symbol", s);
yyerror(temptext);
yyerror("'%s' is a macro or string symbol", s);
}
return (getvaluefield(psym));
} else {
if ((nPass == 1) || (psym->nType & SYMF_IMPORT)) {
/* 0x80 seems like a good default value... */
return (0x80);
} else {
sprintf(temptext, "'%s' not defined", s);
yyerror(temptext);
if (nPass == 2) {
/* Assume undefined symbols are imported from somewhere else */
psym->nType |= SYMF_IMPORT;
}
/* 0x80 seems like a good default value... */
return (0x80);
}
} else {
if (nPass == 1) {
createsymbol(s);
return (0x80);
} else {
sprintf(temptext, "'%s' not defined", s);
yyerror(temptext);
yyerror("'%s' not defined", s);
}
}
@@ -411,18 +394,14 @@ sym_GetDefinedValue(char *s)
if ((psym = findsymbol(s, pscope)) != NULL) {
if ((psym->nType & SYMF_DEFINED)) {
if (psym->nType & (SYMF_MACRO | SYMF_STRING)) {
sprintf(temptext,
"'%s' is a macro or string symbol", s);
yyerror(temptext);
yyerror("'%s' is a macro or string symbol", s);
}
return (getvaluefield(psym));
} else {
sprintf(temptext, "'%s' not defined", s);
yyerror(temptext);
yyerror("'%s' not defined", s);
}
} else {
sprintf(temptext, "'%s' not defined", s);
yyerror(temptext);
yyerror("'%s' not defined", s);
}
return (0);
@@ -558,9 +537,7 @@ sym_AddEqu(char *tzSym, SLONG value)
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
sprintf(temptext, "'%s' already defined",
tzSym);
yyerror(temptext);
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
@@ -586,15 +563,13 @@ sym_AddString(char *tzSym, char *tzValue)
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
sprintf(temptext, "'%s' already defined", tzSym);
yyerror(temptext);
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
if (nsym) {
if ((nsym->pMacro =
(char *) malloc(strlen(tzValue) + 1)) != NULL)
if ((nsym->pMacro = malloc(strlen(tzValue) + 1)) != NULL)
strcpy(nsym->pMacro, tzValue);
else
fatalerror("No memory for stringequate");
@@ -661,9 +636,7 @@ sym_AddLocalReloc(char *tzSym)
if (pScope) {
if ((nsym = findsymbol(tzSym, pScope)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
sprintf(temptext,
"'%s' already defined", tzSym);
yyerror(temptext);
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
@@ -696,9 +669,7 @@ sym_AddReloc(char *tzSym)
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
sprintf(temptext, "'%s' already defined",
tzSym);
yyerror(temptext);
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
@@ -739,8 +710,7 @@ sym_Export(char *tzSym)
if (nsym->nType & SYMF_DEFINED)
return;
}
sprintf(temptext, "'%s' not defined", tzSym);
yyerror(temptext);
yyerror("'%s' not defined", tzSym);
}
}
@@ -759,8 +729,7 @@ sym_Import(char *tzSym)
struct sSymbol *nsym;
if (findsymbol(tzSym, NULL)) {
sprintf(temptext, "'%s' already defined", tzSym);
yyerror(temptext);
yyerror("'%s' already defined", tzSym);
}
if ((nsym = createsymbol(tzSym)) != NULL)
nsym->nType |= SYMF_IMPORT;
@@ -811,9 +780,7 @@ sym_AddMacro(char *tzSym)
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
sprintf(temptext, "'%s' already defined",
tzSym);
yyerror(temptext);
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
@@ -872,6 +839,10 @@ sym_PrepPass2(void)
sym_AddString("__TIME__", SavedTIME);
sym_AddString("__DATE__", SavedDATE);
sym_AddSet("_RS", 0);
sym_AddEqu("_NARG", 0);
p_NARGSymbol = findsymbol("_NARG", NULL);
p_NARGSymbol->Callback = Callback_NARG;
}
/*
* RGBAsm - SYMBOL.C - Symboltable stuff
@@ -899,11 +870,7 @@ sym_Init(void)
sym_AddEqu("_NARG", 0);
p_NARGSymbol = findsymbol("_NARG", NULL);
p_NARGSymbol->Callback = Callback_NARG;
sym_AddEqu("__LINE__", 0);
p__LINE__Symbol = findsymbol("__LINE__", NULL);
p__LINE__Symbol->Callback = Callback__LINE__;
sym_AddEqu("__ASM__", (SLONG) (atof(ASM_VERSION) * 65536));
sym_AddSet("_RS", 0);
if (time(&tod) != -1) {

View File

@@ -1,6 +1,7 @@
%{
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -15,17 +16,43 @@
#include "asm/main.h"
#include "asm/lexer.h"
extern bool haltnop;
char *tzNewMacro;
ULONG ulNewMacroSize;
ULONG symvaluetostring( char *dest, char *sym )
size_t symvaluetostring(char *dest, size_t maxLength, char *sym)
{
if( sym_isString(sym) )
strcpy( dest, sym_GetStringValue(sym) );
else
sprintf( dest, "$%lX", sym_GetConstantValue(sym) );
size_t length;
return( strlen(dest) );
if (sym_isString(sym)) {
char *src = sym_GetStringValue(sym);
size_t i;
for (i = 0; src[i] != 0; i++) {
if (i >= maxLength) {
fatalerror("Symbol value too long to fit buffer");
}
dest[i] = src[i];
}
length = i;
} else {
ULONG value = sym_GetConstantValue(sym);
int fullLength = snprintf(dest, maxLength + 1, "$%lX", value);
if (fullLength < 0) {
fatalerror("snprintf encoding error");
} else {
length = (size_t)fullLength;
if (length > maxLength) {
fatalerror("Symbol value too long to fit buffer");
}
}
}
return length;
}
ULONG str2int( char *s )
@@ -103,8 +130,7 @@ void copyrept( void )
src=pCurrentBuffer->pBuffer;
ulNewMacroSize=len;
if( (tzNewMacro=(char *)malloc(ulNewMacroSize+1))!=NULL )
{
if ((tzNewMacro = malloc(ulNewMacroSize + 1)) != NULL) {
ULONG i;
tzNewMacro[ulNewMacroSize]=0;
@@ -113,8 +139,7 @@ void copyrept( void )
if( (tzNewMacro[i]=src[i])=='\n' )
nLineNo+=1;
}
}
else
} else
fatalerror( "No mem for REPT block" );
yyskipbytes( ulNewMacroSize+4 );
@@ -328,36 +353,12 @@ void if_skip_to_endc( void )
nLineNo-=1;
}
#ifdef PCENGINE
ULONG ZP( struct Expression *expr )
{
return( (!rpn_isReloc(expr)) && (expr->nVal>0x1FFF) && (expr->nVal<0x2100) );
}
void out_ZPByte( struct Expression *expr )
{
if( rpn_isReloc(expr) )
{
rpn_CheckZP(expr,expr);
out_RelByte(expr);
}
else
{
if( ZP(expr) )
out_AbsByte(expr->nVal-0x2000);
else
fatalerror( "Value not in zeropage");
}
}
#endif
%}
%union
{
char tzSym[MAXSYMLEN+1];
char tzString[256];
char tzSym[MAXSYMLEN + 1];
char tzString[MAXSTRLEN + 1];
struct Expression sVal;
SLONG nConstValue;
}

View File

@@ -47,8 +47,7 @@ macro : T_ID
if( !fstk_RunMacro($1) )
{
fprintf(stderr, "Macro '%s' not defined", $1);
yyerror( "No such macro" );
yyerror("Macro '%s' not defined", $1);
}
}
;
@@ -138,11 +137,11 @@ pushs : T_POP_PUSHS
;
fail : T_POP_FAIL string
{ fatalerror($2); }
{ fatalerror("%s", $2); }
;
warn : T_POP_WARN string
{ yyerror($2); }
{ yyerror("%s", $2); }
;
shift : T_POP_SHIFT
@@ -266,11 +265,7 @@ set : T_LABEL T_POP_SET const
include : T_POP_INCLUDE string
{
if( !fstk_RunInclude($2) )
{
fprintf(stderr, "Could not open file '%s' : %s\n", $2, strerror(errno));
yyerror( "File not found" );
}
fstk_RunInclude($2);
}
;
@@ -328,7 +323,7 @@ const_3bit : const
{
if( ($1<0) || ($1>7) )
{
yyerror( "Immediate value must be 3-bit" );
yyerror("Immediate value must be 3-bit");
}
else
$$=$1&0x7;
@@ -366,7 +361,7 @@ const_PCrel : relocconst
{
$$ = $1;
if( !rpn_isPCRelative(&$1) )
yyerror( "Expression must be PC-relative" );
yyerror("Expression must be PC-relative");
}
;
@@ -374,7 +369,7 @@ const_8bit : relocconst
{
if( (!rpn_isReloc(&$1)) && (($1.nVal<-128) || ($1.nVal>255)) )
{
yyerror( "Expression must be 8-bit" );
yyerror("Expression must be 8-bit");
}
$$=$1;
}
@@ -384,7 +379,7 @@ const_16bit : relocconst
{
if( (!rpn_isReloc(&$1)) && (($1.nVal<-32768) || ($1.nVal>65535)) )
{
yyerror( "Expression must be 16-bit" );
yyerror("Expression must be 16-bit");
}
$$=$1;
}

92
src/extern/err.c vendored Normal file
View File

@@ -0,0 +1,92 @@
/*
* Copyright © 2005-2013 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "extern/err.h"
#ifndef __MINGW32__
extern char *__progname;
#endif
void rgbds_vwarn(const char *fmt, va_list ap)
{
fprintf (stderr, "%s: ", __progname);
if (fmt) {
vfprintf(stderr, fmt, ap);
fputs (": ", stderr);
}
perror(0);
}
void rgbds_vwarnx(const char *fmt, va_list ap)
{
fprintf (stderr, "%s: ", __progname);
if (fmt) vfprintf(stderr, fmt, ap);
putc('\n', stderr);
}
void rgbds_verr(int status, const char *fmt, va_list ap)
{
vwarn(fmt, ap);
exit(status);
}
void rgbds_verrx(int status, const char *fmt, va_list ap)
{
vwarnx(fmt, ap);
exit(status);
}
void rgbds_warn(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarn(fmt, ap);
va_end(ap);
}
void rgbds_warnx(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarnx(fmt, ap);
va_end(ap);
}
void rgbds_err(int status, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
verr(status, fmt, ap);
va_end(ap);
}
void rgbds_errx(int status, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
verrx(status, fmt, ap);
va_end(ap);
}

55
src/extern/strlcat.c vendored Normal file
View File

@@ -0,0 +1,55 @@
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
rgbds_strlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}

51
src/extern/strlcpy.c vendored Normal file
View File

@@ -0,0 +1,51 @@
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
rgbds_strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}

View File

@@ -22,6 +22,8 @@
#include <string.h>
#include <unistd.h>
#include "extern/err.h"
static void
usage(void)
{
@@ -29,6 +31,7 @@ usage(void)
"[-l licensee_id]\n" " [-m mbc_type] [-n rom_version] "
"[-p pad_value] [-r ram_size]\n"
" [-t title_str] file.gb\n");
exit(1);
}
int
@@ -46,9 +49,7 @@ main(int argc, char *argv[])
usage();
if ((rom = fopen(argv[argc - 1], "rb+")) == NULL) {
fprintf(stderr, "Error opening file %s: \n", argv[argc - 1]);
perror(NULL);
exit(1);
err(1, "Error opening file %s", argv[argc - 1]);
}
/*
@@ -92,9 +93,8 @@ main(int argc, char *argv[])
setid = true;
if (strlen(optarg) != 4) {
fprintf(stderr, "Game ID %s must be exactly 4 "
"characters\n", optarg);
exit(1);
errx(1, "Game ID %s must be exactly 4 "
"characters", optarg);
}
id = optarg;
@@ -106,10 +106,8 @@ main(int argc, char *argv[])
setnewlicensee = true;
if (strlen(optarg) != 2) {
fprintf(stderr,
"New licensee code %s is not the correct "
"length of 2 characters\n", optarg);
exit(1);
errx(1, "New licensee code %s is not the "
"correct length of 2 characters", optarg);
}
newlicensee = optarg;
@@ -119,15 +117,11 @@ main(int argc, char *argv[])
licensee = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
fprintf(stderr,
"Invalid argument for option 'l'\n");
exit(1);
errx(1, "Invalid argument for option 'l'");
}
if (licensee < 0 || licensee > 0xFF) {
fprintf(stderr,
"Argument for option 'l' must be "
"between 0 and 255\n");
exit(1);
errx(1, "Argument for option 'l' must be "
"between 0 and 255");
}
break;
case 'm':
@@ -135,15 +129,11 @@ main(int argc, char *argv[])
cartridge = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
fprintf(stderr,
"Invalid argument for option 'm'\n");
exit(1);
errx(1, "Invalid argument for option 'm'");
}
if (cartridge < 0 || cartridge > 0xFF) {
fprintf(stderr,
"Argument for option 'm' must be "
"between 0 and 255\n");
exit(1);
errx(1, "Argument for option 'm' must be "
"between 0 and 255");
}
break;
case 'n':
@@ -151,15 +141,11 @@ main(int argc, char *argv[])
version = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
fprintf(stderr,
"Invalid argument for option 'n'\n");
exit(1);
errx(1, "Invalid argument for option 'n'");
}
if (version < 0 || version > 0xFF) {
fprintf(stderr,
"Argument for option 'n' must be "
"between 0 and 255\n");
exit(1);
errx(1, "Argument for option 'n' must be "
"between 0 and 255");
}
break;
case 'p':
@@ -167,15 +153,11 @@ main(int argc, char *argv[])
padvalue = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
fprintf(stderr,
"Invalid argument for option 'p'\n");
exit(1);
errx(1, "Invalid argument for option 'p'");
}
if (padvalue < 0 || padvalue > 0xFF) {
fprintf(stderr,
"Argument for option 'p' must be "
"between 0 and 255\n");
exit(1);
errx(1, "Argument for option 'p' must be "
"between 0 and 255");
}
break;
case 'r':
@@ -183,14 +165,11 @@ main(int argc, char *argv[])
ramsize = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
fprintf(stderr,
"Invalid argument for option 'r'\n");
errx(1, "Invalid argument for option 'r'");
}
if (ramsize < 0 || ramsize > 0xFF) {
fprintf(stderr,
"Argument for option 'r' must be "
"between 0 and 255\n");
exit(1);
errx(1, "Argument for option 'r' must be "
"between 0 and 255");
}
break;
case 's':
@@ -200,15 +179,13 @@ main(int argc, char *argv[])
settitle = true;
if (strlen(optarg) > 16) {
fprintf(stderr, "Title %s is greater than the "
"maximum of 16 characters\n", optarg);
exit(1);
errx(1, "Title %s is greater than the "
"maximum of 16 characters", optarg);
}
if (strlen(optarg) == 16)
fprintf(stderr,
"Title %s is 16 chars, it is best "
"to keep it to 15 or fewer\n", optarg);
warnx("Title %s is 16 chars, it is best to "
"keep it to 15 or fewer", optarg);
title = optarg;
break;
@@ -220,8 +197,6 @@ main(int argc, char *argv[])
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
/*
* Write changes to ROM
@@ -314,8 +289,7 @@ main(int argc, char *argv[])
byte |= 1 << 6;
if (byte & 0x3F)
fprintf(stderr,
"Color flag conflicts with game title\n");
warnx("Color flag conflicts with game title");
fseek(rom, 0x143, SEEK_SET);
fputc(byte, rom);
@@ -352,9 +326,8 @@ main(int argc, char *argv[])
*/
if (!setlicensee)
fprintf(stderr,
"You should probably set both '-s' and "
"'-l 0x33'\n");
warnx("You should probably set both '-s' and "
"'-l 0x33'");
fseek(rom, 0x146, SEEK_SET);
fputc(3, rom);
@@ -379,6 +352,7 @@ main(int argc, char *argv[])
/* We will pad the ROM to match the size given in the header. */
int romsize, newsize, headbyte;
uint8_t *buf;
fseek(rom, 0, SEEK_END);
romsize = ftell(rom);
newsize = 0x8000;
@@ -389,14 +363,17 @@ main(int argc, char *argv[])
headbyte++;
}
while (newsize != ftell(rom)) /* ROM needs resizing */
fputc(padvalue, rom);
if (newsize > 0x800000) /* ROM is bigger than 8MiB */
fprintf(stderr, "ROM size is bigger than 8MiB\n");
warnx("ROM size is bigger than 8MiB");
buf = malloc(newsize - romsize);
memset(buf, padvalue, newsize - romsize);
fwrite(buf, 1, newsize - romsize, rom);
fseek(rom, 0x148, SEEK_SET);
fputc(headbyte, rom);
free(buf);
}
if (setramsize) {

View File

@@ -104,7 +104,7 @@ Most values in the ROM header are only cosmetic.
The bare minimum requirements for a workable image are checksums, the Nintendo
logo, and (if needed) the CGB/SGB flags.
It is a good idea to pad the image to a valid size as well
.Pq Dq valid No meaning a multiple of 32KiB .
.Pq Do valid Dc meaning a multiple of 32KiB .
.Pp
The following will make a plain, no-color Game Boy game without checking for
a valid size:
@@ -130,7 +130,6 @@ of the game
.Sh SEE ALSO
.Xr rgbds 7 ,
.Xr rgbasm 1 ,
.Xr rgblib 1 ,
.Xr rgblink 1 ,
.Xr gbz80 7
.Sh HISTORY

View File

@@ -1,306 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/types.h"
#include "lib/libwrap.h"
SLONG
file_Length(FILE * f)
{
ULONG r, p;
p = ftell(f);
fseek(f, 0, SEEK_END);
r = ftell(f);
fseek(f, p, SEEK_SET);
return (r);
}
SLONG
file_ReadASCIIz(char *b, FILE * f)
{
SLONG r = 0;
while ((*b++ = fgetc(f)) != 0)
r += 1;
return (r + 1);
}
void
file_WriteASCIIz(char *b, FILE * f)
{
while (*b)
fputc(*b++, f);
fputc(0, f);
}
UWORD
file_ReadWord(FILE * f)
{
UWORD r;
r = fgetc(f);
r |= fgetc(f) << 8;
return (r);
}
void
file_WriteWord(UWORD w, FILE * f)
{
fputc(w, f);
fputc(w >> 8, f);
}
ULONG
file_ReadLong(FILE * f)
{
ULONG r;
r = fgetc(f);
r |= fgetc(f) << 8;
r |= fgetc(f) << 16;
r |= fgetc(f) << 24;
return (r);
}
void
file_WriteLong(UWORD w, FILE * f)
{
fputc(w, f);
fputc(w >> 8, f);
fputc(w >> 16, f);
fputc(w >> 24, f);
}
sLibrary *
lib_ReadLib0(FILE * f, SLONG size)
{
if (size) {
sLibrary *l = NULL, *first = NULL;
while (size > 0) {
if (l == NULL) {
l = malloc(sizeof *l);
if (!l) {
fprintf(stderr, "Out of memory\n");
exit(1);
}
first = l;
} else {
l->pNext = malloc(sizeof *l->pNext);
if (!l->pNext) {
fprintf(stderr, "Out of memory\n");
exit(1);
}
l = l->pNext;
}
size -= file_ReadASCIIz(l->tName, f);
l->uwTime = file_ReadWord(f);
size -= 2;
l->uwDate = file_ReadWord(f);
size -= 2;
l->nByteLength = file_ReadLong(f);
size -= 4;
if ((l->pData = malloc(l->nByteLength))) {
fread(l->pData, sizeof(UBYTE), l->nByteLength,
f);
size -= l->nByteLength;
} else {
fprintf(stderr, "Out of memory\n");
exit(1);
}
l->pNext = NULL;
}
return (first);
}
return (NULL);
}
sLibrary *
lib_Read(char *filename)
{
FILE *f;
if ((f = fopen(filename, "rb"))) {
SLONG size;
char ID[5];
size = file_Length(f);
if (size == 0) {
fclose(f);
return (NULL);
}
fread(ID, sizeof(char), 4, f);
ID[4] = 0;
size -= 4;
if (strcmp(ID, "XLB0") == 0) {
sLibrary *r;
r = lib_ReadLib0(f, size);
fclose(f);
printf("Library '%s' opened\n", filename);
return (r);
} else {
fclose(f);
fprintf(stderr, "Not a valid xLib library\n");
exit(1);
}
} else {
printf
("Library '%s' not found, it will be created if necessary\n",
filename);
return (NULL);
}
}
BBOOL
lib_Write(sLibrary * lib, char *filename)
{
FILE *f;
if ((f = fopen(filename, "wb"))) {
fwrite("XLB0", sizeof(char), 4, f);
while (lib) {
file_WriteASCIIz(lib->tName, f);
file_WriteWord(lib->uwTime, f);
file_WriteWord(lib->uwDate, f);
file_WriteLong(lib->nByteLength, f);
fwrite(lib->pData, sizeof(UBYTE), lib->nByteLength, f);
lib = lib->pNext;
}
fclose(f);
printf("Library '%s' closed\n", filename);
return (1);
}
return (0);
}
sLibrary *
lib_Find(sLibrary * lib, char *filename)
{
if (strlen(filename) >= MAXNAMELENGTH) {
fprintf(stderr, "Module name too long: %s\n", filename);
exit(1);
}
while (lib) {
if (strcmp(lib->tName, filename) == 0)
break;
lib = lib->pNext;
}
return (lib);
}
sLibrary *
lib_AddReplace(sLibrary * lib, char *filename)
{
FILE *f;
if ((f = fopen(filename, "rb"))) {
sLibrary *module;
if (strlen(filename) >= MAXNAMELENGTH) {
fprintf(stderr, "Module name too long: %s\n",
filename);
exit(1);
}
if ((module = lib_Find(lib, filename)) == NULL) {
module = malloc(sizeof *module);
if (!module) {
fprintf(stderr, "Out of memory\n");
exit(1);
}
module->pNext = lib;
lib = module;
} else {
/* Module already exists */
free(module->pData);
}
module->nByteLength = file_Length(f);
strcpy(module->tName, filename);
module->pData = malloc(module->nByteLength);
if (!module->pData) {
fprintf(stderr, "Out of memory\n");
exit(1);
}
fread(module->pData, sizeof(UBYTE), module->nByteLength, f);
printf("Added module '%s'\n", filename);
fclose(f);
}
return (lib);
}
sLibrary *
lib_DeleteModule(sLibrary * lib, char *filename)
{
sLibrary **pp, **first;
BBOOL found = 0;
pp = &lib;
first = pp;
if (strlen(filename) >= MAXNAMELENGTH) {
fprintf(stderr, "Module name too long: %s\n", filename);
exit(1);
}
while ((*pp) && (!found)) {
if (strcmp((*pp)->tName, filename) == 0) {
sLibrary *t;
t = *pp;
if (t->pData)
free(t->pData);
*pp = t->pNext;
free(t);
found = 1;
}
pp = &((*pp)->pNext);
}
if (!found) {
fprintf(stderr, "Module not found\n");
exit(1);
} else
printf("Module '%s' deleted from library\n", filename);
return (*first);
}
void
lib_Free(sLibrary * lib)
{
while (lib) {
sLibrary *l;
if (lib->pData)
free(lib->pData);
l = lib;
lib = lib->pNext;
free(l);
}
}

View File

@@ -1,120 +0,0 @@
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "asmotor.h"
#include "lib/types.h"
#include "lib/library.h"
/*
* Print the usagescreen
*
*/
static void
usage(void)
{
printf("RGBLib v" LIB_VERSION " (part of ASMotor " ASMOTOR_VERSION ")\n\n");
printf("usage: rgblib file [add | delete | extract | list] [module ...]\n");
exit(1);
}
/*
* The main routine
*
*/
int
main(int argc, char *argv[])
{
SLONG argn = 0;
char *libname;
argc -= 1;
argn += 1;
if (argc >= 2) {
sLibrary *lib;
lib = lib_Read(libname = argv[argn++]);
argc -= 1;
if (strcmp(argv[argn], "add") == 0) {
argn += 1;
argc -= 1;
while (argc) {
lib = lib_AddReplace(lib, argv[argn++]);
argc -= 1;
}
lib_Write(lib, libname);
lib_Free(lib);
} else if (strcmp(argv[argn], "delete") == 0) {
argn += 1;
argc -= 1;
while (argc) {
lib =
lib_DeleteModule(lib, argv[argn++]);
argc -= 1;
}
lib_Write(lib, libname);
lib_Free(lib);
} else if (strcmp(argv[argn], "extract") == 0) {
argn += 1;
argc -= 1;
while (argc) {
sLibrary *l;
l = lib_Find(lib, argv[argn]);
if (l) {
FILE *f;
if ((f = fopen(argv[argn], "wb"))) {
fwrite(l->pData,
sizeof(UBYTE),
l->nByteLength,
f);
fclose(f);
printf
("Extracted module '%s'\n",
argv[argn]);
} else {
fprintf(stderr,
"Unable to write module '%s': ", argv[argn]);
perror(NULL);
exit(1);
}
} else {
fprintf(stderr, "Module not found\n");
exit(1);
}
argn += 1;
argc -= 1;
}
lib_Free(lib);
} else if (strcmp(argv[argn], "list") == 0) {
argn += 1;
argc -= 1;
sLibrary *l;
l = lib;
while (l) {
printf("%10ld %s\n",
l->nByteLength,
l->tName);
l = l->pNext;
}
} else
usage();
} else
usage();
return (0);
}

View File

@@ -1,36 +0,0 @@
.Dd $Mdocdate$
.Dt RGBLIB 1
.Os RGBDS Manual
.Sh NAME
.Nm rgblib
.Nd Game Boy library manager
.Sh SYNOPSIS
.Nm rgblib
.Ar library
.Op add | delete | extract | list
.Ar module ...
.Sh DESCRIPTION
The
.Nm
program manages libraries for use with
.Xr rgblink 1 .
.Bl -tag -width Ds
.It add
Add the given modules to the library.
.It delete
Delete the given modules from the library.
.It extract
Extract the given modules from the library.
.It list
List all the modules in the library.
.El
.Sh SEE ALSO
.Xr rgbds 7 ,
.Xr rgbasm 1 ,
.Xr rgbfix 1 ,
.Xr rgblink 1 ,
.Xr gbz80 7
.Sh HISTORY
.Nm
was originally released by Carsten S\(/orensen as part of the ASMotor package,
and was later packaged in RGBDS by Justin Lloyd.

View File

@@ -1,6 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include "extern/err.h"
#include "link/mylink.h"
#include "link/main.h"
#include "link/symbol.h"
@@ -15,8 +16,14 @@ struct sFreeArea {
struct sFreeArea *BankFree[MAXBANKS];
SLONG MaxAvail[MAXBANKS];
SLONG MaxBankUsed;
SLONG MaxWBankUsed;
SLONG MaxSBankUsed;
SLONG MaxVBankUsed;
#define DOMAXBANK(x) {if( (x)>MaxBankUsed ) MaxBankUsed=(x);}
#define DOMAXWBANK(x) {if( (x)>MaxWBankUsed ) MaxWBankUsed=(x);}
#define DOMAXSBANK(x) {if( (x)>MaxSBankUsed ) MaxSBankUsed=(x);}
#define DOMAXVBANK(x) {if( (x)>MaxVBankUsed ) MaxVBankUsed=(x);}
SLONG
area_Avail(SLONG bank)
@@ -57,7 +64,6 @@ area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
struct sFreeArea *pNewArea;
if ((pNewArea =
(struct sFreeArea *)
malloc(sizeof(struct sFreeArea)))
!= NULL) {
*pNewArea = *pArea;
@@ -71,9 +77,7 @@ area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
return (org);
} else {
fprintf(stderr,
"Out of memory!\n");
exit(1);
err(1, NULL);
}
}
}
@@ -85,12 +89,52 @@ area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
return (-1);
}
SLONG
area_AllocAbsCODEAnyBank(SLONG org, SLONG size)
SLONG
area_AllocAbsSRAMAnyBank(SLONG org, SLONG size)
{
int i;
for (i = 0; i < 4; ++i) {
if (area_AllocAbs(&BankFree[BANK_SRAM + i], org, size) == org) {
return BANK_SRAM + i;
}
}
return -1;
}
SLONG
area_AllocAbsWRAMAnyBank(SLONG org, SLONG size)
{
SLONG i;
for (i = 1; i <= 255; i += 1) {
for (i = 1; i <= 7; i += 1) {
if (area_AllocAbs(&BankFree[BANK_WRAMX + i - 1], org, size) == org) {
return BANK_WRAMX + i - 1;
}
}
return -1;
}
SLONG
area_AllocAbsVRAMAnyBank(SLONG org, SLONG size)
{
if (area_AllocAbs(&BankFree[BANK_VRAM], org, size) == org) {
return BANK_VRAM;
}
if (area_AllocAbs(&BankFree[BANK_VRAM + 1], org, size) == org) {
return BANK_VRAM + 1;
}
return -1;
}
SLONG
area_AllocAbsROMXAnyBank(SLONG org, SLONG size)
{
SLONG i;
for (i = 1; i <= 511; i += 1) {
if (area_AllocAbs(&BankFree[i], org, size) == org)
return (i);
}
@@ -121,12 +165,12 @@ area_Alloc(struct sFreeArea ** ppArea, SLONG size)
return (-1);
}
SLONG
area_AllocCODEAnyBank(SLONG size)
SLONG
area_AllocVRAMAnyBank(SLONG size)
{
SLONG i, org;
for (i = 1; i <= 255; i += 1) {
for (i = BANK_VRAM; i <= BANK_VRAM + 1; i += 1) {
if ((org = area_Alloc(&BankFree[i], size)) != -1)
return ((i << 16) | org);
}
@@ -134,6 +178,103 @@ area_AllocCODEAnyBank(SLONG size)
return (-1);
}
SLONG
area_AllocSRAMAnyBank(SLONG size)
{
SLONG i, org;
for (i = 0; i < 4; ++i) {
if ((org = area_Alloc(&BankFree[BANK_SRAM + i], size)) != -1) {
return (i << 16) | org;
}
}
return -1;
}
SLONG
area_AllocWRAMAnyBank(SLONG size)
{
SLONG i, org;
for (i = 1; i <= 7; i += 1) {
if ((org = area_Alloc(&BankFree[BANK_WRAMX + i - 1], size)) != -1) {
return (i << 16) | org;
}
}
return -1;
}
SLONG
area_AllocROMXAnyBank(SLONG size)
{
SLONG i, org;
for (i = 1; i <= 511; i += 1) {
if ((org = area_Alloc(&BankFree[i], size)) != -1)
return ((i << 16) | org);
}
return (-1);
}
struct sSection *
FindLargestWRAM(void)
{
struct sSection *pSection, *r = NULL;
SLONG nLargest = 0;
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0 && pSection->Type == SECT_WRAMX) {
if (pSection->nByteSize > nLargest) {
nLargest = pSection->nByteSize;
r = pSection;
}
}
pSection = pSection->pNext;
}
return r;
}
struct sSection *
FindLargestVRAM(void)
{
struct sSection *pSection, *r = NULL;
SLONG nLargest = 0;
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0 && pSection->Type == SECT_VRAM) {
if (pSection->nByteSize > nLargest) {
nLargest = pSection->nByteSize;
r = pSection;
}
}
pSection = pSection->pNext;
}
return r;
}
struct sSection *
FindLargestSRAM(void)
{
struct sSection *pSection, *r = NULL;
SLONG nLargest = 0;
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0 && pSection->Type == SECT_SRAM) {
if (pSection->nByteSize > nLargest) {
nLargest = pSection->nByteSize;
r = pSection;
}
}
pSection = pSection->pNext;
}
return r;
}
struct sSection *
FindLargestCode(void)
{
@@ -142,7 +283,7 @@ FindLargestCode(void)
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0 && pSection->Type == SECT_CODE) {
if (pSection->oAssigned == 0 && pSection->Type == SECT_ROMX) {
if (pSection->nByteSize > nLargest) {
nLargest = pSection->nByteSize;
r = pSection;
@@ -153,6 +294,63 @@ FindLargestCode(void)
return (r);
}
void
AssignVRAMSections(void)
{
struct sSection *pSection;
while ((pSection = FindLargestVRAM())) {
SLONG org;
if ((org = area_AllocVRAMAnyBank(pSection->nByteSize)) != -1) {
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->oAssigned = 1;
DOMAXVBANK(pSection->nBank);
} else {
errx(1, "Unable to place VRAM section anywhere");
}
}
}
void
AssignSRAMSections(void)
{
struct sSection *pSection;
while ((pSection = FindLargestSRAM())) {
SLONG org;
if ((org = area_AllocSRAMAnyBank(pSection->nByteSize)) != -1) {
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->oAssigned = 1;
DOMAXSBANK(pSection->nBank);
} else {
errx(1, "Unable to place SRAM section anywhere");
}
}
}
void
AssignWRAMSections(void)
{
struct sSection *pSection;
while ((pSection = FindLargestWRAM())) {
SLONG org;
if ((org = area_AllocWRAMAnyBank(pSection->nByteSize)) != -1) {
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->oAssigned = 1;
DOMAXWBANK(pSection->nBank);
} else {
errx(1, "Unable to place WRAMX section anywhere");
}
}
}
void
AssignCodeSections(void)
{
@@ -161,15 +359,13 @@ AssignCodeSections(void)
while ((pSection = FindLargestCode())) {
SLONG org;
if ((org = area_AllocCODEAnyBank(pSection->nByteSize)) != -1) {
if ((org = area_AllocROMXAnyBank(pSection->nByteSize)) != -1) {
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->oAssigned = 1;
DOMAXBANK(pSection->nBank);
} else {
fprintf(stderr,
"Unable to place CODE section anywhere\n");
exit(1);
errx(1, "Unable to place ROMX section anywhere");
}
}
}
@@ -191,11 +387,11 @@ AssignSections(void)
BankFree[i] = malloc(sizeof *BankFree[i]);
if (!BankFree[i]) {
fprintf(stderr, "Out of memory!\n");
exit(1);
err(1, NULL);
}
if (i == 0) {
/* ROM0 bank */
BankFree[i]->nOrg = 0x0000;
if (options & OPT_SMALL) {
BankFree[i]->nSize = 0x8000;
@@ -204,7 +400,8 @@ AssignSections(void)
BankFree[i]->nSize = 0x4000;
MaxAvail[i] = 0x4000;
}
} else if (i >= 1 && i <= 255) {
} else if (i >= 1 && i <= 511) {
/* Swappable ROM bank */
BankFree[i]->nOrg = 0x4000;
/*
* Now, this shouldn't really be necessary... but for
@@ -217,15 +414,28 @@ AssignSections(void)
BankFree[i]->nSize = 0x4000;
MaxAvail[i] = 0x4000;
}
} else if (i == BANK_BSS) {
} else if (i == BANK_WRAM0) {
/* WRAM */
BankFree[i]->nOrg = 0xC000;
BankFree[i]->nSize = 0x1000;
MaxAvail[i] = 0x1000;
} else if (i >= BANK_SRAM && i <= BANK_SRAM + 3) {
/* Swappable SRAM bank */
BankFree[i]->nOrg = 0xA000;
BankFree[i]->nSize = 0x2000;
MaxAvail[i] = 0x2000;
} else if (i == BANK_VRAM) {
} else if (i >= BANK_WRAMX && i <= BANK_WRAMX + 6) {
/* Swappable WRAM bank */
BankFree[i]->nOrg = 0xD000;
BankFree[i]->nSize = 0x1000;
MaxAvail[i] = 0x1000;
} else if (i == BANK_VRAM || i == BANK_VRAM + 1) {
/* Swappable VRAM bank */
BankFree[i]->nOrg = 0x8000;
BankFree[i]->nSize = 0x2000;
MaxAvail[i] = 0x2000;
} else if (i == BANK_HRAM) {
/* HRAM */
BankFree[i]->nOrg = 0xFF80;
BankFree[i]->nSize = 0x007F;
MaxAvail[i] = 0x007F;
@@ -247,55 +457,191 @@ AssignSections(void)
/* User wants to have a say... */
switch (pSection->Type) {
case SECT_BSS:
case SECT_WRAM0:
if (area_AllocAbs
(&BankFree[BANK_BSS], pSection->nOrg,
(&BankFree[BANK_WRAM0], pSection->nOrg,
pSection->nByteSize) != pSection->nOrg) {
fprintf(stderr,
"Unable to load fixed BSS section "
"at $%lX\n", pSection->nOrg);
exit(1);
errx(1,
"Unable to load fixed WRAM0 "
"section at $%lX", pSection->nOrg);
}
pSection->oAssigned = 1;
pSection->nBank = BANK_BSS;
pSection->nBank = BANK_WRAM0;
break;
case SECT_HRAM:
if (area_AllocAbs
(&BankFree[BANK_HRAM], pSection->nOrg,
pSection->nByteSize) != pSection->nOrg) {
fprintf(stderr, "Unable to load fixed "
"HRAM section at $%lX\n",
pSection->nOrg);
exit(1);
errx(1, "Unable to load fixed HRAM "
"section at $%lX", pSection->nOrg);
}
pSection->oAssigned = 1;
pSection->nBank = BANK_HRAM;
break;
case SECT_SRAM:
if (pSection->nBank == -1) {
/*
* User doesn't care which bank.
* Therefore he must here be specifying
* position within the bank.
* Defer until later.
*/
;
} else {
/*
* User specified which bank to use.
* Does he also care about position
* within the bank?
*/
if (pSection->nOrg == -1) {
/*
* Nope, any position will do
* Again, we'll do that later
*
*/
;
} else {
/*
* Bank and position within the
* bank are hardcoded.
*/
if (pSection->nBank >= 0
&& pSection->nBank <= 3) {
pSection->nBank +=
BANK_SRAM;
if (area_AllocAbs
(&BankFree
[pSection->nBank],
pSection->nOrg,
pSection->nByteSize)
!= pSection->nOrg) {
errx(1,
"Unable to load fixed SRAM section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
DOMAXVBANK(pSection->
nBank);
pSection->oAssigned = 1;
} else {
errx(1,
"Unable to load fixed SRAM section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
}
}
break;
case SECT_WRAMX:
if (pSection->nBank == -1) {
/*
* User doesn't care which bank.
* Therefore he must here be specifying
* position within the bank.
* Defer until later.
*/
;
} else {
/*
* User specified which bank to use.
* Does he also care about position
* within the bank?
*/
if (pSection->nOrg == -1) {
/*
* Nope, any position will do
* Again, we'll do that later
*
*/
;
} else {
/*
* Bank and position within the
* bank are hardcoded.
*/
if (pSection->nBank >= 1
&& pSection->nBank <= 7) {
pSection->nBank +=
BANK_WRAMX;
if (area_AllocAbs
(&BankFree
[pSection->nBank],
pSection->nOrg,
pSection->nByteSize)
!= pSection->nOrg) {
errx(1,
"Unable to load fixed WRAMX section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
DOMAXWBANK(pSection->
nBank);
pSection->oAssigned = 1;
} else {
errx(1,
"Unable to load fixed WRAMX section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
}
}
break;
case SECT_VRAM:
if (pSection->nBank == -1) {
/*
* User doesn't care which bank.
* Therefore he must here be specifying
* position within the bank.
* Defer until later.
*/
;
} else {
/*
* User specified which bank to use.
* Does he also care about position
* within the bank?
*/
if (pSection->nOrg == -1) {
/*
* Nope, any position will do
* Again, we'll do that later
*
*/
;
} else {
/*
* Bank and position within the
* bank are hardcoded.
*/
if (pSection->nBank >= 0
&& pSection->nBank <= 1) {
pSection->nBank +=
BANK_VRAM;
if (area_AllocAbs
(&BankFree
[pSection->nBank],
pSection->nOrg,
pSection->nByteSize)
!= pSection->nOrg) {
errx(1,
"Unable to load fixed VRAM section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
DOMAXVBANK(pSection->
nBank);
pSection->oAssigned = 1;
} else {
errx(1,
"Unable to load fixed VRAM section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
}
}
break;
case SECT_ROM0:
if (area_AllocAbs
(&BankFree[BANK_VRAM], pSection->nOrg,
(&BankFree[BANK_ROM0], pSection->nOrg,
pSection->nByteSize) != pSection->nOrg) {
fprintf(stderr, "Unable to load fixed "
"VRAM section at $%lX\n",
pSection->nOrg);
exit(1);
errx(1, "Unable to load fixed ROM0 "
"section at $%lX", pSection->nOrg);
}
pSection->oAssigned = 1;
pSection->nBank = BANK_VRAM;
pSection->nBank = BANK_ROM0;
break;
case SECT_HOME:
if (area_AllocAbs
(&BankFree[BANK_HOME], pSection->nOrg,
pSection->nByteSize) != pSection->nOrg) {
fprintf(stderr, "Unable to load fixed "
"HOME section at $%lX\n",
pSection->nOrg);
exit(1);
}
pSection->oAssigned = 1;
pSection->nBank = BANK_HOME;
break;
case SECT_CODE:
case SECT_ROMX:
if (pSection->nBank == -1) {
/*
* User doesn't care which bank, so he must want to
@@ -327,7 +673,7 @@ AssignSections(void)
*/
if (pSection->nBank >= 1
&& pSection->nBank <= 255) {
&& pSection->nBank <= 511) {
if (area_AllocAbs
(&BankFree
[pSection->nBank],
@@ -335,15 +681,15 @@ AssignSections(void)
pSection->
nByteSize) !=
pSection->nOrg) {
fprintf(stderr, "Unable to load fixed CODE/DATA section at $%lX in bank $%02lX\n", pSection->nOrg, pSection->nBank);
exit(1);
errx(1,
"Unable to load fixed ROMX section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
DOMAXBANK(pSection->
nBank);
pSection->oAssigned = 1;
} else {
fprintf(stderr, "Unable to load fixed CODE/DATA section at $%lX in bank $%02lX\n", pSection->nOrg, pSection->nBank);
exit(1);
errx(1,
"Unable to load fixed ROMX section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
}
@@ -355,54 +701,139 @@ AssignSections(void)
}
/*
* Next, let's assign all the bankfixed ONLY CODE sections...
* Next, let's assign all the bankfixed ONLY ROMX sections...
*
*/
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0
&& pSection->Type == SECT_CODE
&& pSection->Type == SECT_ROMX
&& pSection->nOrg == -1 && pSection->nBank != -1) {
/* User wants to have a say... and he's pissed */
if (pSection->nBank >= 1 && pSection->nBank <= 255) {
if (pSection->nBank >= 1 && pSection->nBank <= 511) {
if ((pSection->nOrg =
area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize)) == -1) {
fprintf(stderr, "Unable to load fixed CODE/DATA section into bank $%02lX\n", pSection->nBank);
exit(1);
errx(1,
"Unable to load fixed ROMX section into bank $%02lX", pSection->nBank);
}
pSection->oAssigned = 1;
DOMAXBANK(pSection->nBank);
} else {
fprintf(stderr, "Unable to load fixed CODE/DATA section into bank $%02lX\n", pSection->nBank);
exit(1);
errx(1, "Unable to load fixed ROMX section into bank $%02lX", pSection->nBank);
}
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_SRAM
&& pSection->nOrg == -1 && pSection->nBank != -1) {
pSection->nBank += BANK_SRAM;
/* User wants to have a say... and he's pissed */
if (pSection->nBank >= BANK_SRAM && pSection->nBank <= BANK_SRAM + 3) {
if ((pSection->nOrg =
area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize)) == -1) {
errx(1, "Unable to load fixed SRAM section into bank $%02lX", pSection->nBank);
}
pSection->oAssigned = 1;
DOMAXSBANK(pSection->nBank);
} else {
errx(1, "Unable to load fixed VRAM section into bank $%02lX", pSection->nBank);
}
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_VRAM
&& pSection->nOrg == -1 && pSection->nBank != -1) {
pSection->nBank += BANK_VRAM;
/* User wants to have a say... and he's pissed */
if (pSection->nBank >= BANK_VRAM && pSection->nBank <= BANK_VRAM + 1) {
if ((pSection->nOrg =
area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize)) == -1) {
errx(1, "Unable to load fixed VRAM section into bank $%02lX", pSection->nBank);
}
pSection->oAssigned = 1;
DOMAXVBANK(pSection->nBank);
} else {
errx(1, "Unable to load fixed VRAM section into bank $%02lX", pSection->nBank);
}
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_WRAMX
&& pSection->nOrg == -1 && pSection->nBank != -1) {
pSection->nBank += BANK_WRAMX;
/* User wants to have a say... and he's pissed */
if (pSection->nBank >= BANK_WRAMX && pSection->nBank <= BANK_WRAMX + 6) {
if ((pSection->nOrg =
area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize)) == -1) {
errx(1, "Unable to load fixed WRAMX section into bank $%02lX", pSection->nBank - BANK_WRAMX);
}
pSection->oAssigned = 1;
DOMAXWBANK(pSection->nBank);
} else {
errx(1, "Unable to load fixed WRAMX section into bank $%02lX", pSection->nBank - BANK_WRAMX);
}
}
pSection = pSection->pNext;
}
/*
* Now, let's assign all the floating bank but fixed CODE sections...
* Now, let's assign all the floating bank but fixed ROMX sections...
*
*/
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0
&& pSection->Type == SECT_CODE
&& pSection->Type == SECT_ROMX
&& pSection->nOrg != -1 && pSection->nBank == -1) {
/* User wants to have a say... and he's back with a
* vengeance */
if ((pSection->nBank =
area_AllocAbsCODEAnyBank(pSection->nOrg,
area_AllocAbsROMXAnyBank(pSection->nOrg,
pSection->nByteSize)) ==
-1) {
fprintf(stderr, "Unable to load fixed CODE/DATA section at $%lX into any bank\n", pSection->nOrg);
exit(1);
errx(1, "Unable to load fixed ROMX section at $%lX into any bank", pSection->nOrg);
}
pSection->oAssigned = 1;
DOMAXBANK(pSection->nBank);
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_VRAM
&& pSection->nOrg != -1 && pSection->nBank == -1) {
/* User wants to have a say... and he's back with a
* vengeance */
if ((pSection->nBank =
area_AllocAbsVRAMAnyBank(pSection->nOrg,
pSection->nByteSize)) ==
-1) {
errx(1, "Unable to load fixed VRAM section at $%lX into any bank", pSection->nOrg);
}
pSection->oAssigned = 1;
DOMAXVBANK(pSection->nBank);
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_SRAM
&& pSection->nOrg != -1 && pSection->nBank == -1) {
/* User wants to have a say... and he's back with a
* vengeance */
if ((pSection->nBank =
area_AllocAbsSRAMAnyBank(pSection->nOrg,
pSection->nByteSize)) ==
-1) {
errx(1, "Unable to load fixed SRAM section at $%lX into any bank", pSection->nOrg);
}
pSection->oAssigned = 1;
DOMAXSBANK(pSection->nBank);
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_WRAMX
&& pSection->nOrg != -1 && pSection->nBank == -1) {
/* User wants to have a say... and he's back with a
* vengeance */
if ((pSection->nBank =
area_AllocAbsWRAMAnyBank(pSection->nOrg,
pSection->nByteSize)) ==
-1) {
errx(1, "Unable to load fixed WRAMX section at $%lX into any bank", pSection->nOrg);
}
pSection->oAssigned = 1;
DOMAXWBANK(pSection->nBank);
}
pSection = pSection->pNext;
}
@@ -417,51 +848,43 @@ AssignSections(void)
while (pSection) {
if (pSection->oAssigned == 0) {
switch (pSection->Type) {
case SECT_BSS:
case SECT_WRAM0:
if ((pSection->nOrg =
area_Alloc(&BankFree[BANK_BSS],
area_Alloc(&BankFree[BANK_WRAM0],
pSection->nByteSize)) == -1) {
fprintf(stderr, "BSS section too large\n");
exit(1);
errx(1, "WRAM0 section too large");
}
pSection->nBank = BANK_BSS;
pSection->nBank = BANK_WRAM0;
pSection->oAssigned = 1;
break;
case SECT_HRAM:
if ((pSection->nOrg =
area_Alloc(&BankFree[BANK_HRAM],
pSection->nByteSize)) == -1) {
fprintf(stderr, "HRAM section too large\n");
exit(1);
errx(1, "HRAM section too large");
}
pSection->nBank = BANK_HRAM;
pSection->oAssigned = 1;
break;
case SECT_SRAM:
break;
case SECT_VRAM:
break;
case SECT_WRAMX:
break;
case SECT_ROM0:
if ((pSection->nOrg =
area_Alloc(&BankFree[BANK_VRAM],
area_Alloc(&BankFree[BANK_ROM0],
pSection->nByteSize)) == -1) {
fprintf(stderr, "VRAM section too large\n");
exit(1);
errx(1, "ROM0 section too large");
}
pSection->nBank = BANK_VRAM;
pSection->nBank = BANK_ROM0;
pSection->oAssigned = 1;
break;
case SECT_HOME:
if ((pSection->nOrg =
area_Alloc(&BankFree[BANK_HOME],
pSection->nByteSize)) == -1) {
fprintf(stderr, "HOME section too large\n");
exit(1);
}
pSection->nBank = BANK_HOME;
pSection->oAssigned = 1;
break;
case SECT_CODE:
case SECT_ROMX:
break;
default:
fprintf(stderr, "(INTERNAL) Unknown section type!\n");
exit(1);
errx(1, "(INTERNAL) Unknown section type!");
break;
}
}
@@ -469,6 +892,9 @@ AssignSections(void)
}
AssignCodeSections();
AssignVRAMSections();
AssignWRAMSections();
AssignSRAMSections();
}
void

View File

@@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include "extern/err.h"
#include "link/types.h"
#include "link/mylink.h"
#include "link/main.h"
@@ -91,9 +92,8 @@ AddNeededModules(void)
}
if (options & OPT_SMART_C_LINK) {
if (!addmodulecontaining(smartlinkstartsymbol)) {
fprintf(stderr, "Can't find start symbol '%s'\n",
errx(1, "Can't find start symbol '%s'",
smartlinkstartsymbol);
exit(1);
} else
printf("Smart linking with symbol '%s'\n",
smartlinkstartsymbol);

View File

@@ -4,8 +4,7 @@
#include <string.h>
#include <unistd.h>
#include "asmotor.h"
#include "extern/err.h"
#include "link/object.h"
#include "link/output.h"
#include "link/assign.h"
@@ -34,9 +33,7 @@ char smartlinkstartsymbol[256];
static void
usage(void)
{
printf("RGBLink v" LINK_VERSION " (part of ASMotor " ASMOTOR_VERSION
")\n\n");
printf("usage: rgblink [-t] [-l library] [-m mapfile] [-n symfile] [-o outfile]\n");
printf("usage: rgblink [-t] [-m mapfile] [-n symfile] [-o outfile]\n");
printf("\t [-s symbol] [-z pad_value] objectfile [...]\n");
exit(1);
@@ -58,9 +55,6 @@ main(int argc, char *argv[])
while ((ch = getopt(argc, argv, "l:m:n:o:p:s:t")) != -1) {
switch (ch) {
case 'l':
lib_Readfile(optarg);
break;
case 'm':
SetMapfileName(optarg);
break;
@@ -73,8 +67,7 @@ main(int argc, char *argv[])
case 'p':
fillchar = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
fprintf(stderr, "Invalid argument for option 'p'\n");
exit(1);
errx(1, "Invalid argument for option 'p'");
}
if (fillchar < 0 || fillchar > 0xFF) {
fprintf(stderr, "Argument for option 'p' must be between 0 and 0xFF");

View File

@@ -3,8 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include "asmotor.h"
#include "extern/err.h"
#include "link/main.h"
#include "link/mylink.h"
#include "link/assign.h"
@@ -20,9 +19,7 @@ SetMapfileName(char *name)
mf = fopen(name, "w");
if (mf == NULL) {
fprintf(stderr, "Cannot open mapfile '%s': ", name);
perror(NULL);
exit(1);
err(1, "Cannot open mapfile '%s'", name);
}
}
@@ -32,11 +29,10 @@ SetSymfileName(char *name)
sf = fopen(name, "w");
if (sf == NULL) {
fprintf(stderr, "Cannot open symfile '%s'\n", name);
exit(1);
err(1, "Cannot open symfile '%s'", name);
}
fprintf(sf, ";File generated by xLink v" LINK_VERSION "\n\n");
fprintf(sf, ";File generated by rgblink\n\n");
}
void
@@ -59,17 +55,17 @@ MapfileInitBank(SLONG bank)
currentbank = bank;
if (bank == 0)
fprintf(mf, "Bank #0 (HOME):\n");
else if (bank <= 255)
else if (bank < BANK_WRAM0)
fprintf(mf, "Bank #%ld:\n", bank);
else if (bank == BANK_BSS)
fprintf(mf, "BSS:\n");
else if (bank == BANK_WRAM0)
fprintf(mf, "WRAM0:\n");
else if (bank == BANK_HRAM)
fprintf(mf, "HRAM:\n");
else if (bank == BANK_VRAM)
fprintf(mf, "VRAM:\n");
else if (bank == BANK_VRAM || bank == BANK_VRAM + 1)
fprintf(mf, "VRAM Bank #%ld:\n", bank - BANK_VRAM);
}
if (sf) {
sfbank = (bank >= 1 && bank <= 255) ? bank : 0;
sfbank = (bank >= 1 && bank <= 511) ? bank : 0;
}
}

View File

@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include "extern/err.h"
#include "link/mylink.h"
#include "link/main.h"
@@ -80,8 +81,7 @@ AllocSection(void)
*ppSections = malloc(sizeof **ppSections);
if (!*ppSections) {
fprintf(stderr, "Out of memory!\n");
exit(1);
err(1, NULL);
}
(*ppSections)->tSymbols = tSymbols;
(*ppSections)->pNext = NULL;
@@ -102,15 +102,13 @@ obj_ReadSymbol(FILE * f)
pSym = malloc(sizeof *pSym);
if (!pSym) {
fprintf(stderr, "Out of memory!\n");
exit(1);
err(1, NULL);
}
readasciiz(s, f);
pSym->pzName = malloc(strlen(s) + 1);
if (!pSym->pzName) {
fprintf(stderr, "Out of memory!\n");
exit(1);
err(1, NULL);
}
strcpy(pSym->pzName, s);
@@ -139,10 +137,10 @@ obj_ReadRGB0Section(FILE * f)
/* does the user want the -s mode? */
if ((options & OPT_SMALL) && (pSection->Type == SECT_CODE)) {
pSection->Type = SECT_HOME;
if ((options & OPT_SMALL) && (pSection->Type == SECT_ROMX)) {
pSection->Type = SECT_ROM0;
}
if ((pSection->Type == SECT_CODE) || (pSection->Type == SECT_HOME)) {
if ((pSection->Type == SECT_ROMX) || (pSection->Type == SECT_ROM0)) {
/*
* These sectiontypes contain data...
*
@@ -150,7 +148,7 @@ obj_ReadRGB0Section(FILE * f)
if (pSection->nByteSize) {
pSection->pData = malloc(pSection->nByteSize);
if (!pSection->pData) {
fprintf(stderr, "Out of memory!\n");
err(1, NULL);
}
SLONG nNumberOfPatches;
@@ -169,7 +167,7 @@ obj_ReadRGB0Section(FILE * f)
while (nNumberOfPatches--) {
pPatch = malloc(sizeof *pPatch);
if (!pPatch) {
fprintf(stderr, "Out of memory!\n");
err(1, NULL);
}
*ppPatch = pPatch;
@@ -177,7 +175,7 @@ obj_ReadRGB0Section(FILE * f)
pPatch->pzFilename = malloc(strlen(s) + 1);
if (!pPatch->pzFilename) {
fprintf(stderr, "Out of memory!\n");
err(1, NULL);
}
strcpy(pPatch->pzFilename, s);
@@ -193,8 +191,7 @@ obj_ReadRGB0Section(FILE * f)
if ((pPatch->nRPNSize = readlong(f)) > 0) {
pPatch->pRPN = malloc(pPatch->nRPNSize);
if (!pPatch->pRPN) {
fprintf(stderr, "Out of memory!\n");
exit(1);
err(1, NULL);
}
fread(pPatch->pRPN, sizeof(UBYTE),
@@ -228,8 +225,7 @@ obj_ReadRGB0(FILE * pObjfile)
if (nNumberOfSymbols) {
tSymbols = malloc(nNumberOfSymbols * sizeof(struct sSymbol *));
if (!tSymbols) {
fprintf(stderr, "Out of memory!\n");
exit(1);
err(1, NULL);
}
for (i = 0; i < nNumberOfSymbols; i += 1)
@@ -294,10 +290,10 @@ obj_ReadRGB1Section(FILE * f)
/* does the user want the -s mode? */
if ((options & OPT_SMALL) && (pSection->Type == SECT_CODE)) {
pSection->Type = SECT_HOME;
if ((options & OPT_SMALL) && (pSection->Type == SECT_ROMX)) {
pSection->Type = SECT_ROM0;
}
if ((pSection->Type == SECT_CODE) || (pSection->Type == SECT_HOME)) {
if ((pSection->Type == SECT_ROMX) || (pSection->Type == SECT_ROM0)) {
/*
* These sectiontypes contain data...
*
@@ -305,8 +301,7 @@ obj_ReadRGB1Section(FILE * f)
if (pSection->nByteSize) {
pSection->pData = malloc(pSection->nByteSize);
if (!pSection->pData) {
fprintf(stderr, "Out of memory!\n");
exit(1);
err(1, NULL);
}
SLONG nNumberOfPatches;
@@ -325,14 +320,14 @@ obj_ReadRGB1Section(FILE * f)
while (nNumberOfPatches--) {
pPatch = malloc(sizeof *pPatch);
if (!pPatch) {
fprintf(stderr, "Out of memory!\n");
err(1, NULL);
}
*ppPatch = pPatch;
readasciiz(s, f);
pPatch->pzFilename = malloc(strlen(s) + 1);
if (!pPatch->pzFilename) {
fprintf(stderr, "Out of memory!\n");
err(1, NULL);
}
strcpy(pPatch->pzFilename, s);
@@ -342,7 +337,7 @@ obj_ReadRGB1Section(FILE * f)
if ((pPatch->nRPNSize = readlong(f)) > 0) {
pPatch->pRPN = malloc(pPatch->nRPNSize);
if (!pPatch->pRPN) {
fprintf(stderr, "Out of memory!\n");
err(1, NULL);
}
fread(pPatch->pRPN, sizeof(UBYTE),
@@ -376,7 +371,7 @@ obj_ReadRGB1(FILE * pObjfile)
if (nNumberOfSymbols) {
tSymbols = malloc(nNumberOfSymbols * sizeof *tSymbols);
if (!tSymbols) {
fprintf(stderr, "Out of memory!\n");
err(1, NULL);
}
for (i = 0; i < nNumberOfSymbols; i += 1)
@@ -440,14 +435,10 @@ obj_ReadOpenFile(FILE * pObjfile, char *tzObjectfile)
obj_ReadRGB1(pObjfile);
break;
default:
fprintf(stderr, "'%s' is an unsupported version",
tzObjectfile);
exit(1);
break;
errx(1, "'%s' is an unsupported version", tzObjectfile);
}
} else {
fprintf(stderr, "'%s' is not a valid object\n", tzObjectfile);
exit(1);
errx(1, "'%s' is not a valid object", tzObjectfile);
}
}
@@ -463,10 +454,7 @@ obj_Readfile(char *tzObjectfile)
pObjfile = fopen(tzObjectfile, "rb");
if (pObjfile == NULL) {
fprintf(stderr, "Unable to open object '%s': ",
tzObjectfile);
perror(NULL);
exit(1);
err(1, "Unable to open object '%s'", tzObjectfile);
}
obj_ReadOpenFile(pObjfile, tzObjectfile);
fclose(pObjfile);
@@ -506,34 +494,3 @@ lib_ReadXLB0(FILE * f)
obj_ReadOpenFile(f, name);
}
}
void
lib_Readfile(char *tzLibfile)
{
FILE *pObjfile;
oReadLib = 1;
pObjfile = fopen(tzLibfile, "rb");
if (pObjfile == NULL) {
fprintf(stderr, "Unable to open object '%s': ", tzLibfile);
perror(NULL);
exit(1);
}
if (!pObjfile) {
fprintf(stderr, "Unable to open '%s'\n", tzLibfile);
exit(1);
}
char tzHeader[5];
fread(tzHeader, sizeof(char), 4, pObjfile);
tzHeader[4] = 0;
if (strcmp(tzHeader, "XLB0") == 0)
lib_ReadXLB0(pObjfile);
else {
fprintf(stderr, "'%s' is an invalid library\n",
tzLibfile);
exit(1);
}
fclose(pObjfile);
}

View File

@@ -7,8 +7,7 @@
#include "link/main.h"
#include "link/assign.h"
char tzOutname[_MAX_PATH];
BBOOL oOutput = 0;
char *tzOutname;
void
writehome(FILE * f)
@@ -16,16 +15,16 @@ writehome(FILE * f)
struct sSection *pSect;
UBYTE *mem;
mem = malloc(MaxAvail[BANK_HOME]);
mem = malloc(MaxAvail[BANK_ROM0]);
if (!mem)
return;
memset(mem, fillchar, MaxAvail[BANK_HOME]);
memset(mem, fillchar, MaxAvail[BANK_ROM0]);
MapfileInitBank(0);
pSect = pSections;
while (pSect) {
if (pSect->Type == SECT_HOME) {
if (pSect->Type == SECT_ROM0) {
memcpy(mem + pSect->nOrg, pSect->pData,
pSect->nByteSize);
MapfileWriteSection(pSect);
@@ -35,7 +34,7 @@ writehome(FILE * f)
MapfileCloseBank(area_Avail(0));
fwrite(mem, 1, MaxAvail[BANK_HOME], f);
fwrite(mem, 1, MaxAvail[BANK_ROM0], f);
free(mem);
}
@@ -54,7 +53,7 @@ writebank(FILE * f, SLONG bank)
pSect = pSections;
while (pSect) {
if (pSect->Type == SECT_CODE && pSect->nBank == bank) {
if (pSect->Type == SECT_ROMX && pSect->nBank == bank) {
memcpy(mem + pSect->nOrg - 0x4000, pSect->pData,
pSect->nByteSize);
MapfileWriteSection(pSect);
@@ -71,8 +70,7 @@ writebank(FILE * f, SLONG bank)
void
out_Setname(char *tzOutputfile)
{
strcpy(tzOutname, tzOutputfile);
oOutput = 1;
tzOutname = tzOutputfile;
}
void

View File

@@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include "extern/err.h"
#include "link/mylink.h"
#include "link/symbol.h"
#include "link/main.h"
@@ -46,8 +47,7 @@ getsymvalue(SLONG symid)
default:
break;
}
fprintf(stderr, "*INTERNAL* UNKNOWN SYMBOL TYPE\n");
exit(1);
errx(1, "*INTERNAL* UNKNOWN SYMBOL TYPE");
}
SLONG
@@ -64,8 +64,7 @@ getsymbank(SLONG symid)
default:
break;
}
fprintf(stderr, "*INTERNAL* UNKNOWN SYMBOL TYPE\n");
exit(1);
errx(1, "*INTERNAL* UNKNOWN SYMBOL TYPE");
}
SLONG
@@ -159,20 +158,18 @@ calcrpn(struct sPatch * pPatch)
t = rpnpop();
rpnpush(t & 0xFF);
if (t < 0 || (t > 0xFF && t < 0xFF00) || t > 0xFFFF) {
fprintf(stderr,
"%s(%ld) : Value must be in the HRAM area\n",
errx(1,
"%s(%ld) : Value must be in the HRAM area",
pPatch->pzFilename, pPatch->nLineNo);
exit(1);
}
break;
case RPN_PCEZP:
t = rpnpop();
rpnpush(t & 0xFF);
if (t < 0x2000 || t > 0x20FF) {
fprintf(stderr,
"%s(%ld) : Value must be in the ZP area\n",
errx(1,
"%s(%ld) : Value must be in the ZP area",
pPatch->pzFilename, pPatch->nLineNo);
exit(1);
}
break;
case RPN_CONST:
@@ -217,11 +214,10 @@ calcrpn(struct sPatch * pPatch)
high |= (*rpn++) << 24;
t = rpnpop();
if (t < low || t > high) {
fprintf(stderr,
"%s(%ld) : Value must be in the range [%ld;%ld]\n",
errx(1,
"%s(%ld) : Value must be in the range [%ld;%ld]",
pPatch->pzFilename,
pPatch->nLineNo, low, high);
exit(1);
}
rpnpush(t);
size -= 8;
@@ -255,11 +251,10 @@ Patch(void)
pSect->pData[pPatch->nOffset] =
(UBYTE) t;
} else {
fprintf(stderr,
"%s(%ld) : Value must be 8-bit\n",
errx(1,
"%s(%ld) : Value must be 8-bit",
pPatch->pzFilename,
pPatch->nLineNo);
exit(1);
}
break;
case PATCH_WORD_L:
@@ -280,11 +275,10 @@ Patch(void)
1] = t & 0xFF;
}
} else {
fprintf(stderr,
"%s(%ld) : Value must be 16-bit\n",
errx(1,
"%s(%ld) : Value must be 16-bit",
pPatch->pzFilename,
pPatch->nLineNo);
exit(1);
}
break;
case PATCH_LONG_L:

View File

@@ -21,20 +21,14 @@ program links objects created by
.Xr rgbasm 1
into a single Game Boy ROM file.
.Pp
By default, HOME sections created by the assembler are placed in the 16KiB
bank 0, and CODE/DATA sections are placed in any bank except bank 0.
By default, ROM0 sections created by the assembler are placed in the 16KiB
bank 0, and ROMX sections are placed in any bank except bank 0.
If your ROM will only be 32KiB, you can use the
.Fl t
option to override this.
.Pp
The arguments are as follows:
.Bl -tag -width Ds
.It Fl l Ar library
Include a referenced library module created with
.Xr rgblib 1 .
Note that specified libraries will be included only if needed\(emthat is, if
a SECTION from a library is referenced by an object file.
Only the relevant SECTION will be included, rather than the entire module.
.It Fl m Ar mapfile
Write a mapfile to the given filename.
.It Fl n Ar symfile
@@ -50,7 +44,7 @@ The default is 0x00.
Write a tiny
.Pq 32KiB
ROM file.
This forces all DATA/CODE sections to be of type HOME, and increases the HOME
This forces all ROMX sections to be of type ROM0, and increases the ROM0
section size from 16KiB to 32KiB.
.El
.Sh EXAMPLES
@@ -70,7 +64,6 @@ to fix these so that the program will actually run in a Game Boy:
.Xr rgbds 7 ,
.Xr rgbasm 1 ,
.Xr rgbfix 1 ,
.Xr rgblib 1 ,
.Xr gbz80 7
.Sh HISTORY
.Nm

View File

@@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include "extern/err.h"
#include "link/main.h"
#include "link/patch.h"
#include "link/types.h"
@@ -53,8 +54,7 @@ sym_GetValue(char *tzName)
}
}
fprintf(stderr, "Unknown symbol '%s'\n", tzName);
exit(1);
errx(1, "Unknown symbol '%s'", tzName);
}
}
@@ -72,8 +72,7 @@ sym_GetBank(char *tzName)
}
}
fprintf(stderr, "Unknown symbol '%s'\n", tzName);
exit(1);
errx(1, "Unknown symbol '%s'", tzName);
}
void
@@ -93,10 +92,7 @@ sym_CreateSymbol(char *tzName, SLONG nValue, SBYTE nBank)
if (nBank == -1)
return;
fprintf(stderr,
"Symbol '%s' defined more than once\n",
tzName);
exit(1);
errx(1, "Symbol '%s' defined more than once", tzName);
}
}

View File

@@ -13,7 +13,6 @@ To get a working ROM image from a single assembly source file:
.Sh SEE ALSO
.Xr rgbasm 1 ,
.Xr rgbfix 1 ,
.Xr rgblib 1 ,
.Xr rgblink 1 ,
.Xr gbz80 7
.Sh HISTORY