Discussion about software development for the old-school Gameboys, ranging from the "Gray brick" to Gameboy Color
(Launched in 2008)
You are not logged in.
Hello all!
I am very excited to get going on my game. I have been working on a demo. I am trying to add some new tile data to my build and when i add the file containing the data array the screen goes blue. There is also an error in the logs "MBC1 unknown address". I believe the issue has to do with banking. It seems that my banks are not setup correctly. Below is a link to the code. you can run make to build a working rom. If you look in the make file you can comment out lines 34,35 and uncomment 38,39 to make the build break.
Link: https://drive.google.com/file/d/1xu94HH … sp=sharing
Thanks!
Offline
I think i found out how to fix it, but i am a little confused. I changed the " unsigned char" to "static const unsigned char" in hud-font.c This seemed to force the compiler to store the code under _CODE_4 instead of _DATA. Can anyone shed some light on this?
Offline
Which version of gbdk are you using? I'm using gbdk3-2.93 and get a better error message:
lcc -Wl-yt3 -Wl-yo8 -Wl-ya0 -o build/first.gb ./src2/bank-1/my-world-map.o ./src2/bank-1/my-world-tiles.o ./src2/bank-2/astroid-tiles.o ./src2/bank-2/ShipTiles.o ./src2/bank-3/hud-border.o ./src2/bank-3/hud-window.o obj/main.o ERROR: address overflow (addr cbd6 >= 8000)
This error message is trying to tell you that you ran out of space in one of the rom banks, as it calculated that address 0xCBD6 is still within one of the ROM banks, which usually are from 0x4000--0x7FFF resp. 0x0000--0x3FFF for Rom Bank 0.
The reason is that you data is much too big, as you never tell the compiler that the data is constant. Thus, it correctly assumes that you could change the data at one point in time and it needs to reside in RAM.
Constant data is put into the ROM directly, whereas pre-initialized non-constant data needs to be copied to RAM when the program is initially booted up. Thus, each ROM bank must hold a copy of the data and RAM needs to be big enough to hold it, too. Because the initialization happens in ROM bank 0, the compiler tries to copy all the initialization data to ROM bank 0 first and ran out of space there as well. I actually noticed that the compiler doesn't care if it runs from ROM bank 0 into ROM bank 1 as it assumes to be able to do that. The initialization code for RAM is very bad as it produces code copy single bytes to target locations instead of doing a memcpy, at least for me.
That's why changing data to const works in your case. The static keyword does something else: It changes linkage from default external linkage to internal linkage. Internal symbols are only visible within one compilation unit (one C file), whereas external symbols are visible globally. You cannot define a variable to have internal linkage and external linkage at the same time. Doing so will result in a linker error if the variable is used anywhere:
?ASlink-Warning-Undefined Global _WorldTiles referenced by module lcc70320
You can find and debug these errors using the map and listing files. See the GBDK docs for help how to activate them. This way you can know the RAM usage and the ROM usage of your data.
You should also know that your Makefile does not actually work, as the default compilation rule is used for all your sources:
lcc -c -o src2/bank-1/my-world-map.o src2/bank-1/my-world-map.c
The default rule is $(CC) -c -o $@ $<. As you see, the flags specifying RAM and ROM banks are missing. Use make -r to run make without default rules. Let's check the rules:
./src2/bank-1/%.c.o: %.c
This rule expects to find a my-world-map.c file at the root of your tree next to the Makefile. It also expects a dependency to file ./src2/bank-1/my-world-map.c.o, which isn't there either.
There are many ways to solve this. I chose a somewhat generic way where you specify each file by hand and each attribute for each file by hand but provide a generic rule for all files:
CC = lcc TARGET ?= build/first.gb BUILD_DIR ?= ./build MKDIR_P ?= mkdir -p ASSETS_FOLDER = assets SRC = \ main.c \ bank-1/my-world-map.c \ bank-1/my-world-tiles.c \ bank-2/astroid-tiles.c \ bank-2/ShipTiles.c \ bank-3/hud-border.c \ bank-3/hud-window.c \ bank-4/hud-font.c OBJS = $(addprefix obj/, $(SRC:.c=.o)) rebuild: clean $(TARGET) cleanafter # # Link banks # # ROM+MBC1+RAM : -Wl-yt2 # # 4 ROM banks : -Wl-yo4 # # 1 RAM banks : -Wl-ya0 # # Make Byte 0x0143 in Header 0xC0 for CGB exclusive title. $(TARGET): $(OBJS) $(CC) -Wl-m -Wl-yt3 -Wl-yo8 -Wl-ya0 -Wl-yp0x143=0xC0 -o $@ $(OBJS) # -------------------------- # enable secondexpansion used to depend on directories .SECONDEXPANSION: # keep listing and map files .PRECIOUS: *.lst *.map # Compilation-unit-specific flags obj/main.o: BANKS := obj/bank-1/%.o: BANKS := -Wf-bo1 -Wf-ba0 obj/bank-2/%.o: BANKS := -Wf-bo2 -Wf-ba0 obj/bank-3/%.o: BANKS := -Wf-bo3 -Wf-ba0 obj/bank-4/%.o: BANKS := -Wf-bo4 -Wf-ba0 # Generic compilation rule # depend on directory being created first using second expansion obj/%.o: src2/%.c | $$(dir $$@) $(CC) -Wa-l $(BANKS) -c -o $@ $< # Rule to create directories .PRECIOUS: %/ %/: mkdir -p $@ # --- cleans --- clean: rm -rf $(OBJS) $(OBJS:.o:.lst) cleanafter: rm -rf $(OBJS)
Btw, it's kind of bad style to include c files in other c files. You might want to rethink that.
Also, there's an error in hud.c where you switch to the wrong ROM bank and the palette data references palette 0x00 instead of 0x02.
Before:
After:
cYa,
Tauwasser
Last edited by Tauwasser (2019-04-27 19:00:42)
Offline
Thanks for the reply. I am using GBDK 2.96a
Offline
Here's a shell script that gives a RAM/ROM summary such as below. It's helpful for tracking how much space is available in given banks.
$ bash linker_report.bash GroupBy(Seg),sum(Size) CABS,0 CODE,10625 CODE_1,15027 CODE_2,14931 CODE_3,14712 DABS,0 DATA,1574 GSFINAL,0 GSINIT,1232 HOME,0
The script is written for Linux but should work on Windows if you install binaries for perl, grep and datamash (they exist).
I didn't see a way to get LCC to generate this kind of report on it's own, but maybe it's just buried somewhere.
#!/bin/bash # find all the data allocation rows in the linker symbol output # dump them into a csv # display them in a table (datamash) or load the csv in libre office calc rm linker_summary.csv echo "File,Seg,Size" > linker_summary.csv; grep -R "flags" Release/* | grep ".sym" | perl -pe 's/(.*)\.sym\:\s*\d+\s_([0-9A-Z_]*)\s*size\s*([0-9A-F]*)\s*flags.*/ /; print $1 . "," . $2 . "," . hex($3) . ","' >> linker_summary.csv datamash --headers --field-separator=, --no-strict --ignore-case --narm --sort --group 2 sum 3 < linker_summary.csv #loffice -calc linker_summary.csv
Offline
Thank you soooo much! I will put this to good use.
Offline
Here is the makefile i ended up with, any thoughts?
CC = lcc -Wa-l -Wl-m TARGET ?= build/game.gb BUILD_DIR ?= ./build MKDIR_P ?= mkdir -p ASSETS_FOLDER = assets GAME_PATH ?= game-src TARGET ?= build/game.gb ROOT_SRCS = $(shell find src -name '*.c') ROOT_SRCS := $(subst src/,,$(ROOT_SRCS)) ROOT_OBJS = $(addprefix obj/, $(ROOT_SRCS:.c=.o)) BANK_1_SRCS = $(shell find src/assets/bank-1 -name '*.c') BANK_1_SRCS := $(subst src/,,$(BANK_1_SRCS)) BANK_1_OBJS = $(addprefix obj/, $(BANK_1_SRCS:.c=.o)) OBJS = $(ROOT_OBJS) $(BANK_1_OBJS) game: clean $(TARGET) cleanafter # Link banks # ROM+MBC1+RAM : -Wl-yt2 # 4 ROM banks : -Wl-yo4 # 1 RAM banks : -Wl-ya0 # Make Byte 0x0143 in Header 0xC0 for CGB exclusive title. $(TARGET): $(OBJS) $(CC) -Wl-yt2 -Wl-yo4 -Wl-ya0 -Wl-yp0x143=0xC0 -o $@ $(OBJS) # enable secondexpansion used to depend on directories .SECONDEXPANSION: # keep listing and map files .PRECIOUS: *.lst *.map obj/assets/bank-1/%.o: src/assets/bank-1/%.c | $$(dir $$@) $(CC) -Wf-bo1 -Wf-ba0 -c -o $@ $< obj/%.o: src/%.c $(CC) -c -o $@ $< # Rule to create directories .PRECIOUS: %/ %/: mkdir -p $@ # --- cleans --- clean: rm -r $(OBJS) $(OBJS:.o:.lst) 2>/dev/null || true cleanafter: rm -rf $(OBJS) 2>/dev/null || true
Last edited by ben0910 (2019-06-01 23:46:05)
Offline
To target MBC1, I think you will want :
-Wl-yt1 instead of: -Wl-yt2
And if you want 1 RAM bank on the MBC (in addition to the built-in RAM):
-Wl-ya1 instead of: -Wl-ya0
http://gbdk.sourceforge.net/tools.html
-yo Number of rom banks (default: 2)
-ya Number of ram banks (default: 0)
-yt MBC type (default: no MBC)
Last edited by bbbbbr (2019-06-02 09:58:38)
Offline