1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
gbromgen
========
gbromgen is an auxiliary post-processing tool for libstdgb meant to make it
easier to organize a Game Boy ROM image. It takes input from a simple
JSON-encoded specification and outputs a runnable binary image created by
altering the output of SDCC's `makebin` program.
It requires SDCC (for `makebin`) and Python 3 to run.
Usage
-----
$ gbromgen [options] spec
`spec` is the specification file. Use the option `-h` or `--help` for
information about the command line arguments.
Specification File
------------------
The spec file is encoded as a JSON object. All fields of this object are
optional except for `hex`, which is the code for your program (in `ihx`
format).
### Basic configuration
A simple spec file might resemble the following:
``` json
{
"name": "HELLO",
"hex": "hello.ihx",
"output": "hello.gb"
}
```
The `name` field is a short name to be stored on the ROM. Some programs use it
to store the program's version information as well.
The `hex` field is a file path relative to the location of the spec file which
serves as the input for processing. This file will be passed to SDCC's
`makebin` to be converted to binary before `gbromgen` processes it
further. This hex file is usually generated by `sdcc` after finishing
compilation.
The `output` field is a file path relative to the location of the spec file
where the final executable ROM file will be placed.
### Header level fields
In addition to `name`, `hex`, and `output`, the following top-level fields may
be used:
- `const-fields`: (object) Definition of constant integer fields to be written
into the ROM (see below).
- `mbc`: (string) Specification of the cartridge type (see below).
- `ram-banks`: (integer) The number of RAM banks on the cartridge.
- `rom-banks`: (integer) The number of ROM banks to be written.
- `tilesets`: (array of object) Defined tilesets for the ROM (see below).
- `vblank`: (string) Name of a function to be executed at the vblank interrupt.
### Constant integer fields
You can define constant integer fields in your C code and assign them values in
the spec. This includes pointers. This field in the spec is an object with
string keys and unsigned integer values, as such:
``` json
{
"my_field": 120,
"my_other_field": 0x30
}
```
### Cartridge types
If your cartridge is not a simple ROM, you may specify what hardware it has (as
is allowable by the Game Boy spec). The following combinations are valid:
- `mbc1`
- `mbc1+ram`
- `batt+mbc1+ram`
- `mbc2`
- `batt+mbc2`
- `ram`
- `batt+ram`
- `mmm01`
- `mmm01+sram`
- `batt+mmm01+sram`
- `batt+mbc3+timer`
- `batt+mbc3+ram+timer`
- `mbc3`
- `mbc3+ram`
- `batt+mbc3+ram`
- `mbc5`
- `mbc5+ram`
- `batt+mbc5+ram`
- `mbc5+rumble`
- `mbc5+rumble+sram`
- `batt+mbc5+rumble+sram`
### Tilesets
One of the most tedious part of Game Boy development is encoding your graphics
in the Game Boy format and embedding them in the binary. Tools have existed
which generate assembler and C code for embedding, but this poses some
problems:
1. SDCC cannot be told to store data in ROM banks; it is limited to 16k if
using switchable banks and 32k if using a normal ROM.
2. The image you drew is not linked to the generated graphics. Every time you
want to change it, you must regenerate the encoded binary and reinsert it
into your code.
3. Your binary graphics data are now taking up space in your source code
files. This not only inflates the disk footprint of your code base, it
clutters your code with data that are basically meaningless when in the
programming mindset of reading and interpreting source code.
gbromgen addresses these problems by allowing you to point to images containing
tilesets and associate the image with some variables in your code. Currently,
there are three fields that need to be defined in your spec for each tileset:
- `img`: (string) relative file path to the image file
- `data`: (string) the name of a `const uint8_t (* const)[GB_BYTES_PER_TILE]`
in your code which will be set to wherever gbromgen puts the converted data.
- `bank`: (string or integer) If string, the name of a `const uint8_t` in your
code which will be set to the bank number into which gbromgen puts your
converted data. If integer, this forces gbromgen to assign this tileset to
that bank number. If the bank number is 0 or more than the number of banks,
it will be skipped entirely.
Your spec definition might look something like this:
``` json
{
...
"tilesets": [
{
"img": "normal-tiles.png",
"data": "NORMAL_TILES",
"bank": 1
},
{
"img": "dark-tiles.png",
"data": "DARK_TILES",
"bank": "DARK_TILES_BANK"
}
]
}
```
In your code, you might put placeholders as such:
``` c
const uint8_t (* const NORMAL_TILES)[GB_BYTES_PER_TILE] = NULL;
const uint8_t (* const DARK_TILES)[GB_BYTES_PER_TILE] = NULL;
const uint8_t NORMAL_TILES_BANK = 1;
const uint8_t DARK_TILES_BANK = 0;
```
|