From 5199df364ae8860ee4dbb8fba3b62fddb0ba801f Mon Sep 17 00:00:00 2001 From: Sebastian Riedel Date: Fri, 4 Feb 2022 02:07:03 +0100 Subject: [PATCH 1/5] Switch to makebin --- game/makefile | 3 +- ihx2gb/ihx2gb.js | 257 --------------------------------------- ihx2gb/package-lock.json | 26 ---- ihx2gb/package.json | 10 -- 4 files changed, 2 insertions(+), 294 deletions(-) delete mode 100644 ihx2gb/ihx2gb.js delete mode 100644 ihx2gb/package-lock.json delete mode 100644 ihx2gb/package.json diff --git a/game/makefile b/game/makefile index fe32ea9..27e66c0 100644 --- a/game/makefile +++ b/game/makefile @@ -1,5 +1,6 @@ CC = sdcc ASMC = sdasgb +MKROM = makebin CFLAGS = -c -mgbz80 ASMFLAGS = -plosgffjw LINKFLAGS = -mgbz80 --no-std-crt0 --data-loc 0xc0a0 @@ -36,7 +37,7 @@ obj/dependencies: $(SRCFILES) bin/BubbleFactory.gb: obj/game.ihx @mkdir -p bin - node ../ihx2gb --name BUBBLEFACT --licensee DH --cartridge 0x1B --ram 1 --version 1 $< $@ + $(MKROM) -Z -yn BUBBLEFACT -yk DH -yt 0x1B -ya 1 -yS -yp0x014C=1 $< $@ obj/game.ihx: $(OBJFILES) @mkdir -p obj diff --git a/ihx2gb/ihx2gb.js b/ihx2gb/ihx2gb.js deleted file mode 100644 index 7445dc9..0000000 --- a/ihx2gb/ihx2gb.js +++ /dev/null @@ -1,257 +0,0 @@ -"use strict"; - -const fs = require("fs"); -const path = require("path"); -const commander = require("commander"); -const Overflow = require("overflow-js").Overflow; - -function parseHexPair(string, index) { - return parseInt(string.substr(index, 2), 16); -} - -function writeLogo(buffer) { - const logoBuffer = Buffer.from([ - 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, - 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, - 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E - ]); - - logoBuffer.copy(buffer, 0x0104); -} - -function writeTitle(buffer, title) { - if(title.length > 11) { - console.warn(`warning: title longer than 11 characters, later characters will be ignored`); - } - - if(/^[A-Z0-9 ]*$/g.test(title) == false) { - console.error("title may only have uppercase letters, digits, and spaces"); - process.exit(1); - } - - const startAddress = 0x0134; - buffer.fill(0x00, startAddress, startAddress + 11); - buffer.write(title, startAddress, Math.min(title.length, 11), "ascii"); -} - -function writeManufacturerCode(buffer, code) { - if(code.length > 4) { - console.warn(`warning: manufacturer code longer than 4 characters, later characters will be ignored`); - } - - if(/^[A-Z0-9 ]*$/g.test(code) == false) { - console.error("manufacturer code may only have uppercase letters, digits, and spaces"); - process.exit(1); - } - - const startAddress = 0x013F; - buffer.fill(0x00, startAddress, startAddress + 4); - buffer.write(code, startAddress, Math.min(code.length, 4), "ascii"); -} - -function writeCGBFlag(buffer, flag) { - buffer.writeUInt8(flag, 0x0143); -} - -function writeLicenseeCode(buffer, code) { - if(code.length > 2) { - console.warn(`warning: licensee code longer than 2 characters, later characters will be ignored`); - } - - if(/^[a-zA-Z0-9 ]*$/g.test(code) == false) { - console.error("licensee code may only have letters, digits, and spaces"); - process.exit(1); - } - - const startAddress = 0x0144; - buffer.fill(0xFF, startAddress, startAddress + 2); - buffer.write(code, startAddress, Math.min(code.length, 2), "ascii"); -} - -function writeSGBFlag(buffer, flag) { - buffer.writeUInt8(flag, 0x0146); -} - -function writeCartridgeType(buffer, type) { - buffer.writeUInt8(type, 0x0147); -} - -function writeROMSize(buffer, size) { - buffer.writeUInt8(size, 0x0148); -} - -function writeRAMSize(buffer, size) { - buffer.writeUInt8(size, 0x0149); -} - -function writeDestinationCode(buffer, code) { - buffer.writeUInt8(code, 0x014A); -} - -function writeOldLicenseeCode(buffer, code) { - buffer.writeUInt8(code, 0x014B); -} - -function writeROMVersion(buffer, version) { - buffer.writeUInt8(version, 0x014C); -} - -function writeHeaderChecksum(buffer) { - let x = Overflow.ubyte(0); - for(let index = 0x0134; index <= 0x014C; index++) { - x = x.minus(buffer[index]).minus(1); - } - buffer.writeUInt8(x.value, 0x014D); -} - -function writeROMChecksum(buffer) { - let x = Overflow.ushort(0); - for(let index = 0x00; index < buffer.length; index++) { - if(index == 0x014E || index == 0x014F) { - continue; - } - x = x.plus(buffer[index]); - } - buffer.writeUInt16BE(x.value, 0x014E); -} - -function processMap(mapFilePath, symOutputPath) { - if(fs.existsSync(mapFilePath) == false) { - return; - } - - const regex = /^[\s]+([0-9A-F]{8}) _([a-zA-Z0-9_]+)/; - - const text = fs.readFileSync(mapFilePath, "utf8"); - const lines = text.split(/[\n\r]+/g); - const addresses = []; - lines.forEach((line) => { - const match = regex.exec(line); - if(match == null) { - return; - } - const address = match[1]; - const symbol = match[2]; - - addresses.push({ - "address" : address, - "symbol" : symbol - }); - }); - - const symbolLines = [ - "; Generated by IHX2GB", - "" - ]; - addresses.forEach((address) => { - symbolLines.push(`00:${address.address.substr(4)} ${address.symbol}`); - }); - - fs.writeFileSync(symOutputFilePath, symbolLines.join("\n")); -} - -commander - .usage("[options] ") - .option("-n, --name [value]", "The name in the header. Default: \"MY GAME\"", "MY GAME") - .option("-m, --manufacturer [code]", "The manufacturer code. Default: \"\"", "") - .option("-c, --cgb [flag]", "The decimal Game Boy Color support flag. 128 for CGB+GB, 192 for CGB-only. Default: 0", "0", parseInt) - .option("-l, --licensee [code]", "The ASCII licensee code. Default: \"00\"", "00") - .option("-s, --sgb [flag]", "The decimal Super Game Boy support flag. 3 to enable. Default: 0", "0", parseInt) - .option("-t, --cartridge [type]", "The decimal cartridge type. Default: 0", "0", parseInt) - .option("-r, --rom [code]", "The decimal ROM size code. File will be 32KB << value, except for 82, 83, and 84. Default: 0", "0", parseInt) - .option("-a, --ram [code]", "The decimal external RAM size code. Default: 0", "0", parseInt) - .option("-d, --destination [code]", "The destination code. 0 for Japan, 1 for international. Default: 1", "1", parseInt) - .option("--oldlicensee [code]", "The decimal old licensee code. 51 to use new licensee code. SGB will not work if != 51. Default: 51", "51", parseInt) - .option("-v, --version [version]", "The ROM version. Default: 0", "0", parseInt) - -commander.on("--help", () => { - console.log("Go to http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header for header details, including values for Cartridge Type, ROM Size, and RAM Size. That site lists codes in hex, but must be provided here in decimal."); - console.log(""); -}); - -commander.parse(process.argv); - -if(commander.rom > 8) { - let n = 32768; - for(let i=0; i < commander.rom; i++) { - n *= 2; - } - console.error("rom size codes > 8 unsupported. Fun fact, you asked me to make a file " + (n) + " bytes big! Wow!"); - process.exit(1); -} - -if(commander.args.length != 2) { - console.error("must provide both an input and output file"); - process.exit(1); -} - -const inputFilePath = path.resolve(commander.args[0]); -const outputFilePath = path.resolve(commander.args[1]); - -const inputFileDirectory = path.dirname(inputFilePath); -const inputFileBasename = path.basename(inputFilePath, path.extname(inputFilePath)); -const mapFilePath = path.join(inputFileDirectory, inputFileBasename + ".map"); - -const outputFileDirectory = path.dirname(outputFilePath); -const outputFileBasename = path.basename(outputFilePath, path.extname(outputFilePath)); -const symOutputFilePath = path.join(outputFileDirectory, outputFileBasename + ".sym"); - -processMap(mapFilePath, symOutputFilePath); - -const ihxText = fs.readFileSync(inputFilePath, { "encoding" : "utf8" }); -const ihxRecords = ihxText.split(/[\n\r]+/g).filter((record) => { return record.length > 0; }); -const gbBuffer = Buffer.alloc(32768 << commander.rom, 0xFF); - -let baseAddress = 0; - -ihxRecords.forEach((record) => { - let head = 0; - - if(record[head] != ":") { - console.error("not an ihx file"); - process.exit(1); - } - - head +=1; - - const dataLength = parseHexPair(record, head); - head += 2; - - const address = baseAddress + (parseHexPair(record, head) << 8) + parseHexPair(record, head + 2); - head += 4; - - const type = parseHexPair(record, head); - head += 2; - - if(type == 0) { - // Data Record, copy bytes - for(let index = 0; index < dataLength; index++) { - const byte = parseHexPair(record, head); - head += 2; - - gbBuffer[address + index] = byte; - } - } else if(type == 1) { - // EOF Record. - } else { - console.error("unsupported record type"); - process.exit(1); - } -}); - -writeLogo(gbBuffer); -writeTitle(gbBuffer, commander.name); -writeManufacturerCode(gbBuffer, commander.manufacturer); -writeCGBFlag(gbBuffer, commander.cgb); -writeLicenseeCode(gbBuffer, commander.licensee); -writeSGBFlag(gbBuffer, commander.sgb); -writeCartridgeType(gbBuffer, commander.cartridge); -writeROMSize(gbBuffer, commander.rom); -writeRAMSize(gbBuffer, commander.ram); -writeDestinationCode(gbBuffer, commander.destination); -writeOldLicenseeCode(gbBuffer, commander.oldlicensee); -writeROMVersion(gbBuffer, commander.version); -writeHeaderChecksum(gbBuffer); -writeROMChecksum(gbBuffer); - -fs.writeFileSync(outputFilePath, gbBuffer); diff --git a/ihx2gb/package-lock.json b/ihx2gb/package-lock.json deleted file mode 100644 index 78345e8..0000000 --- a/ihx2gb/package-lock.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "ihx2gb", - "version": "0.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "requires": { - "graceful-readlink": ">= 1.0.0" - } - }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" - }, - "overflow-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/overflow-js/-/overflow-js-1.0.0.tgz", - "integrity": "sha1-G8S//0Qg5Rc5ZuvWd8SASR7phPA=" - } - } -} diff --git a/ihx2gb/package.json b/ihx2gb/package.json deleted file mode 100644 index 2aa81c8..0000000 --- a/ihx2gb/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "ihx2gb", - "description": "converts intel ihx files to game boy format", - "version": "0.0.0", - "main": "ihx2gb", - "dependencies": { - "commander": "~2.9.0", - "overflow-js": "~1.0.0" - } -} From ead33fcd4d74b5b716450dd92c0e1ce4604b5e1e Mon Sep 17 00:00:00 2001 From: Sebastian Riedel Date: Fri, 4 Feb 2022 16:25:57 +0100 Subject: [PATCH 2/5] Update README and improve makefile --- README.md | 5 +++-- game/makefile | 37 +++++++++++++++++++++---------------- img2gb/package-lock.json | 2 +- makefile | 19 +++++++++++++++++++ stringc/package-lock.json | 2 +- 5 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 makefile diff --git a/README.md b/README.md index 6c8da4f..2794362 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,12 @@ I built this project on macOS. The instructions should be pretty easy to follow The build pipeline has dependencies on [node.js](http://nodejs.org) and [SDCC](http://sdcc.sourceforge.net). You'll need to install them. ### Dependencies -`cd` into `ihx2gb/` and run `npm install`. - `cd` into `img2gb/` and run `npm install`. `cd` into `stringc/` and run `npm install`. ### Building the Game `cd` into `game/` and run `make` or `make debug`. + +### Building the Game and Dependencies +Just run `make`, `make debug` or `make run` in the root folder. \ No newline at end of file diff --git a/game/makefile b/game/makefile index 27e66c0..2799cdd 100644 --- a/game/makefile +++ b/game/makefile @@ -1,6 +1,8 @@ CC = sdcc ASMC = sdasgb MKROM = makebin +EMU = sameboy +NODE = node CFLAGS = -c -mgbz80 ASMFLAGS = -plosgffjw LINKFLAGS = -mgbz80 --no-std-crt0 --data-loc 0xc0a0 @@ -14,44 +16,47 @@ OBJS = $(SRCS:.c=.o) SRCFILES = $(patsubst %.c,src/%.c,$(SRCS)) OBJFILES = $(patsubst %.s,obj/%.rel,$(ASMS)) $(patsubst %.c,obj/%.rel,$(SRCS)) +.PHONY: build debug run clean + build: obj/dependencies bin/BubbleFactory.gb debug: CFLAGS += -DDEBUG debug: build src/data_strings.c: data/strings.json - node ../stringc data/stringsMap.json $< $@ + $(NODE) ../stringc data/stringsMap.json $< $@ src/data_gfx_%.c: data/gfx/%.png - node ../img2gb -n $(notdir $(basename $<)) $< $@ + $(NODE) ../img2gb -n $(notdir $(basename $<)) $< $@ -obj/dependencies: $(SRCFILES) +obj/dependencies: $(SRCFILES) | obj/ @echo "regenerate dependency file" - @mkdir -p obj - @rm -f obj/dependencies + @$(RM) -f obj/dependencies @for srcFile in $(SRCFILES) ; do \ { printf "obj/"; $(CC) -MM $$srcFile; } >> obj/dependencies ; \ done -include obj/dependencies -bin/BubbleFactory.gb: obj/game.ihx - @mkdir -p bin +bin/BubbleFactory.gb: obj/game.ihx | bin/ $(MKROM) -Z -yn BUBBLEFACT -yk DH -yt 0x1B -ya 1 -yS -yp0x014C=1 $< $@ -obj/game.ihx: $(OBJFILES) - @mkdir -p obj +obj/game.ihx: $(OBJFILES) | obj/ $(CC) $(LINKFLAGS) $^ -o $@ -obj/%.rel: src/%.c - @mkdir -p obj +obj/%.rel: src/%.c | obj/ $(CC) $(CFLAGS) $< -o $@ -obj/%.rel: src/%.s - @mkdir -p obj +obj/%.rel: src/%.s | obj/ $(ASMC) $(ASMFLAGS) $@ $< +%/: + @mkdir -p $@ + +run: build + $(EMU) bin/BubbleFactory.gb + clean: - rm -rf src/data_* - rm -rf obj - rm -rf bin + $(RM) -rf src/data_* + $(RM) -rf obj + $(RM) -rf bin diff --git a/img2gb/package-lock.json b/img2gb/package-lock.json index 1995d27..f1f5bd5 100644 --- a/img2gb/package-lock.json +++ b/img2gb/package-lock.json @@ -1,7 +1,7 @@ { "name": "img2gb", "version": "0.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, "dependencies": { "commander": { diff --git a/makefile b/makefile new file mode 100644 index 0000000..4648552 --- /dev/null +++ b/makefile @@ -0,0 +1,19 @@ +.PHONY: build debug tools run clean + +build: tools + $(MAKE) -C game/ $@ + +debug: tools + $(MAKE) -C game/ $@ + +run: tools + $(MAKE) -C game/ $@ + +clean: + $(MAKE) -C game/ $@ + $(RM) -rf img2gb/node_modules stringc/node_modules + +tools: img2gb/node_modules stringc/node_modules + +%/node_modules: + cd $* && npm install \ No newline at end of file diff --git a/stringc/package-lock.json b/stringc/package-lock.json index 64f85c0..900a929 100644 --- a/stringc/package-lock.json +++ b/stringc/package-lock.json @@ -1,7 +1,7 @@ { "name": "stringc", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, "dependencies": { "commander": { From ca4bd2e455d243bf7d3532088a74809cc73d4962 Mon Sep 17 00:00:00 2001 From: Sebastian Riedel Date: Fri, 4 Feb 2022 17:25:01 +0100 Subject: [PATCH 3/5] Allow custom SDCC paths --- README.md | 9 ++++++++- game/makefile | 7 ++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2794362..3cc26e5 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,11 @@ The build pipeline has dependencies on [node.js](http://nodejs.org) and [SDCC](h `cd` into `game/` and run `make` or `make debug`. ### Building the Game and Dependencies -Just run `make`, `make debug` or `make run` in the root folder. \ No newline at end of file +Just run `make`, `make debug` or `make run` in the root folder. + +### Building with an SDCC Snapshot +*This is for versions of SDCC that aren't installed* +``` +SDCC_HOME=/path/to/sdcc/share/sdcc/ +make SDCCBIN=${SDCC_HOME}../../bin/ +``` \ No newline at end of file diff --git a/game/makefile b/game/makefile index 2799cdd..7cf218c 100644 --- a/game/makefile +++ b/game/makefile @@ -1,6 +1,7 @@ -CC = sdcc -ASMC = sdasgb -MKROM = makebin +SDCCBIN = +CC = $(SDCCBIN)sdcc +ASMC = $(SDCCBIN)sdasgb +MKROM = $(SDCCBIN)makebin EMU = sameboy NODE = node CFLAGS = -c -mgbz80 From 8b6b5402699e252db09e9d4e4749ae115d41d818 Mon Sep 17 00:00:00 2001 From: Sebastian Riedel Date: Fri, 4 Feb 2022 19:50:21 +0100 Subject: [PATCH 4/5] Add more debug flags and statistic tools --- game/makefile | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/game/makefile b/game/makefile index 7cf218c..2fd6471 100644 --- a/game/makefile +++ b/game/makefile @@ -1,12 +1,15 @@ SDCCBIN = CC = $(SDCCBIN)sdcc -ASMC = $(SDCCBIN)sdasgb +AS = $(SDCCBIN)sdasgb MKROM = $(SDCCBIN)makebin +# https://github.com/LIJI32/SameBoy or any other emulator EMU = sameboy +# https://github.com/bbbbbr/romusage +ROMUSE = romusage NODE = node CFLAGS = -c -mgbz80 -ASMFLAGS = -plosgffjw -LINKFLAGS = -mgbz80 --no-std-crt0 --data-loc 0xc0a0 +ASFLAGS = -plosgffjw +LDFLAGS = -mgbz80 --no-std-crt0 --data-loc 0xc0a0 GFXS = $(notdir $(shell find data/gfx -name '*.png')) GFXSRC = $(patsubst %.png,data_gfx_%.c,$(GFXS)) @@ -17,11 +20,14 @@ OBJS = $(SRCS:.c=.o) SRCFILES = $(patsubst %.c,src/%.c,$(SRCS)) OBJFILES = $(patsubst %.s,obj/%.rel,$(ASMS)) $(patsubst %.c,obj/%.rel,$(SRCS)) -.PHONY: build debug run clean +ROM = BubbleFactory -build: obj/dependencies bin/BubbleFactory.gb +.PHONY: build debug run clean spaceleft statistics -debug: CFLAGS += -DDEBUG +build: obj/dependencies bin/$(ROM).gb + +debug: CFLAGS += -DDEBUG --debug +debug: LDFLAGS += -Wl-y debug: build src/data_strings.c: data/strings.json @@ -39,23 +45,33 @@ obj/dependencies: $(SRCFILES) | obj/ -include obj/dependencies -bin/BubbleFactory.gb: obj/game.ihx | bin/ +bin/$(ROM).gb: obj/game.ihx | bin/ $(MKROM) -Z -yn BUBBLEFACT -yk DH -yt 0x1B -ya 1 -yS -yp0x014C=1 $< $@ + cp obj/game.sym bin/$(ROM).sym + cp obj/game.noi bin/$(ROM).noi + test -e obj/game.cdb && cp obj/game.cdb bin/$(ROM).cdb obj/game.ihx: $(OBJFILES) | obj/ - $(CC) $(LINKFLAGS) $^ -o $@ + $(CC) $(LDFLAGS) $^ -o $@ obj/%.rel: src/%.c | obj/ $(CC) $(CFLAGS) $< -o $@ obj/%.rel: src/%.s | obj/ - $(ASMC) $(ASMFLAGS) $@ $< + $(AS) $(ASFLAGS) $@ $< %/: @mkdir -p $@ +spaceleft: build + $(ROMUSE) bin/$(ROM).noi -g -E + +statistics: build + test -e bin/$(ROM).cdb && $(ROMUSE) bin/$(ROM).cdb -g + $(ROMUSE) bin/$(ROM).noi -G -E -sH -a + run: build - $(EMU) bin/BubbleFactory.gb + $(EMU) $(ROM) clean: $(RM) -rf src/data_* From d26108bf3ab971b05a7618f2f1c89e7ba76e4442 Mon Sep 17 00:00:00 2001 From: Sebastian Riedel Date: Fri, 4 Feb 2022 20:11:17 +0100 Subject: [PATCH 5/5] Invert file existence checks --- game/makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/game/makefile b/game/makefile index 2fd6471..50a3f9d 100644 --- a/game/makefile +++ b/game/makefile @@ -49,7 +49,7 @@ bin/$(ROM).gb: obj/game.ihx | bin/ $(MKROM) -Z -yn BUBBLEFACT -yk DH -yt 0x1B -ya 1 -yS -yp0x014C=1 $< $@ cp obj/game.sym bin/$(ROM).sym cp obj/game.noi bin/$(ROM).noi - test -e obj/game.cdb && cp obj/game.cdb bin/$(ROM).cdb + test \! -s obj/game.cdb || cp obj/game.cdb bin/$(ROM).cdb obj/game.ihx: $(OBJFILES) | obj/ $(CC) $(LDFLAGS) $^ -o $@ @@ -67,11 +67,11 @@ spaceleft: build $(ROMUSE) bin/$(ROM).noi -g -E statistics: build - test -e bin/$(ROM).cdb && $(ROMUSE) bin/$(ROM).cdb -g + test \! -s bin/$(ROM).cdb || $(ROMUSE) bin/$(ROM).cdb -g $(ROMUSE) bin/$(ROM).noi -G -E -sH -a run: build - $(EMU) $(ROM) + $(EMU) bin/$(ROM).gb clean: $(RM) -rf src/data_*