romdevtools 0.16.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/AGENTS.md +75 -16
  2. package/CHANGELOG.md +316 -0
  3. package/examples/README.md +2 -0
  4. package/examples/atari2600/templates/platformer.asm +460 -0
  5. package/examples/atari2600/templates/racing.asm +463 -0
  6. package/examples/atari2600/templates/shmup.asm +386 -0
  7. package/examples/atari2600/templates/sports.asm +362 -0
  8. package/examples/atari7800/templates/default.c +49 -5
  9. package/examples/atari7800/templates/hello_sprite.c +48 -4
  10. package/examples/atari7800/templates/music_demo.c +47 -2
  11. package/examples/atari7800/templates/platformer.c +43 -4
  12. package/examples/atari7800/templates/puzzle.c +39 -4
  13. package/examples/atari7800/templates/racing.c +39 -4
  14. package/examples/atari7800/templates/shmup.c +40 -2
  15. package/examples/atari7800/templates/sports.c +36 -5
  16. package/examples/c64/templates/platformer.c +19 -5
  17. package/examples/c64/templates/puzzle.c +32 -2
  18. package/examples/c64/templates/shmup.c +28 -2
  19. package/examples/c64/templates/sports.c +30 -2
  20. package/examples/c64/templates/tile_engine.c +77 -27
  21. package/examples/gb/templates/default.c +110 -16
  22. package/examples/gb/templates/hello_sprite.c +15 -6
  23. package/examples/gb/templates/music_demo.c +36 -0
  24. package/examples/gb/templates/platformer.c +28 -6
  25. package/examples/gb/templates/puzzle.c +35 -4
  26. package/examples/gb/templates/racing.c +75 -10
  27. package/examples/gb/templates/shmup.c +41 -3
  28. package/examples/gb/templates/sports.c +51 -3
  29. package/examples/gb/templates/tile_engine.c +3 -2
  30. package/examples/gba/templates/gba_hello.c +29 -11
  31. package/examples/gba/templates/maxmod_demo.c +36 -2
  32. package/examples/gba/templates/platformer.c +3 -1
  33. package/examples/gba/templates/puzzle.c +15 -3
  34. package/examples/gba/templates/racing.c +65 -3
  35. package/examples/gba/templates/shmup.c +41 -4
  36. package/examples/gba/templates/sports.c +36 -2
  37. package/examples/gba/templates/tonc_hello.c +41 -5
  38. package/examples/gba/templates/tonc_hello_sprite.c +35 -1
  39. package/examples/gbc/templates/default.c +103 -26
  40. package/examples/gbc/templates/hello_sprite.c +12 -3
  41. package/examples/gbc/templates/music_demo.c +56 -12
  42. package/examples/gbc/templates/platformer.c +28 -6
  43. package/examples/gbc/templates/puzzle.c +35 -4
  44. package/examples/gbc/templates/racing.c +88 -21
  45. package/examples/gbc/templates/shmup.c +37 -3
  46. package/examples/gbc/templates/sports.c +48 -3
  47. package/examples/gbc/templates/tile_engine.c +3 -2
  48. package/examples/genesis/main.s +53 -1
  49. package/examples/genesis/templates/hello_sprite.c +25 -3
  50. package/examples/genesis/templates/puzzle.c +37 -3
  51. package/examples/genesis/templates/racing.c +44 -11
  52. package/examples/genesis/templates/sgdk_hello.c +34 -1
  53. package/examples/genesis/templates/shmup.c +31 -1
  54. package/examples/genesis/templates/shmup_2p.c +31 -0
  55. package/examples/genesis/templates/xgm2_demo.c +20 -0
  56. package/examples/gg/templates/default.c +56 -18
  57. package/examples/gg/templates/hello_sprite.c +25 -2
  58. package/examples/gg/templates/music_demo.c +24 -2
  59. package/examples/gg/templates/platformer.c +18 -12
  60. package/examples/gg/templates/puzzle.c +38 -7
  61. package/examples/gg/templates/racing.c +58 -9
  62. package/examples/gg/templates/shmup.c +47 -3
  63. package/examples/gg/templates/sports.c +57 -16
  64. package/examples/gg/templates/tile_engine.c +12 -6
  65. package/examples/lynx/templates/default.c +39 -8
  66. package/examples/lynx/templates/hello_sprite.c +15 -1
  67. package/examples/lynx/templates/music_demo.c +13 -1
  68. package/examples/lynx/templates/puzzle.c +28 -1
  69. package/examples/lynx/templates/racing.c +34 -7
  70. package/examples/lynx/templates/shmup.c +42 -3
  71. package/examples/lynx/templates/sports.c +29 -2
  72. package/examples/msx/platformer/main.c +213 -0
  73. package/examples/msx/puzzle/main.c +250 -0
  74. package/examples/msx/racing/main.c +249 -0
  75. package/examples/msx/shmup/main.c +288 -0
  76. package/examples/msx/sports/main.c +182 -0
  77. package/examples/nes/templates/default.c +67 -19
  78. package/examples/nes/templates/hello_sprite.c +35 -0
  79. package/examples/nes/templates/music_demo.c +40 -0
  80. package/examples/nes/templates/platformer.c +65 -6
  81. package/examples/nes/templates/puzzle.c +67 -6
  82. package/examples/nes/templates/racing.c +45 -13
  83. package/examples/nes/templates/shmup.c +51 -2
  84. package/examples/nes/templates/sports.c +51 -6
  85. package/examples/pce/catch_game/main.c +22 -3
  86. package/examples/pce/music_sfx/main.c +28 -1
  87. package/examples/pce/platformer/main.c +283 -0
  88. package/examples/pce/puzzle/main.c +304 -0
  89. package/examples/pce/racing/main.c +304 -0
  90. package/examples/pce/shmup/main.c +346 -0
  91. package/examples/pce/sports/main.c +254 -0
  92. package/examples/pce/sprite_move/main.c +7 -2
  93. package/examples/sms/main.c +35 -6
  94. package/examples/sms/templates/hello_sprite.c +29 -3
  95. package/examples/sms/templates/music_demo.c +18 -4
  96. package/examples/sms/templates/puzzle.c +34 -5
  97. package/examples/sms/templates/racing.c +39 -2
  98. package/examples/sms/templates/shmup.c +41 -2
  99. package/examples/sms/templates/shmup_2p.c +24 -1
  100. package/examples/sms/templates/sports.c +47 -4
  101. package/examples/snes/main.asm +108 -17
  102. package/examples/snes/templates/c-hello-data.asm +23 -0
  103. package/examples/snes/templates/c-hello.c +18 -1
  104. package/examples/snes/templates/default.c +50 -28
  105. package/examples/snes/templates/hello_sprite-data.asm +23 -0
  106. package/examples/snes/templates/hello_sprite.c +17 -1
  107. package/examples/snes/templates/music_demo-data.asm +23 -0
  108. package/examples/snes/templates/music_demo.c +22 -4
  109. package/examples/snes/templates/platformer-data.asm +22 -0
  110. package/examples/snes/templates/platformer.c +20 -2
  111. package/examples/snes/templates/puzzle-data.asm +22 -0
  112. package/examples/snes/templates/puzzle.c +21 -2
  113. package/examples/snes/templates/racing-data.asm +22 -0
  114. package/examples/snes/templates/racing.c +17 -1
  115. package/examples/snes/templates/shmup-data.asm +22 -0
  116. package/examples/snes/templates/shmup.c +20 -1
  117. package/examples/snes/templates/sports-data.asm +22 -0
  118. package/examples/snes/templates/sports.c +16 -1
  119. package/package.json +1 -1
  120. package/src/cheats/gamegenie.js +0 -1
  121. package/src/cli/smoke.js +1 -3
  122. package/src/cores/wasm/vice_x64_libretro.js +1 -1
  123. package/src/cores/wasm/vice_x64_libretro.wasm +0 -0
  124. package/src/host/LibretroHost.js +191 -16
  125. package/src/host/callbacks.js +9 -1
  126. package/src/host/chafa-render.js +2 -0
  127. package/src/host/dsp-state.js +2 -2
  128. package/src/host/gpgx-state.js +4 -0
  129. package/src/host/types.js +15 -8
  130. package/src/http/routes.js +1 -1
  131. package/src/http/tool-registry.js +26 -1
  132. package/src/mcp/server.js +1 -1
  133. package/src/mcp/state.js +36 -0
  134. package/src/mcp/tools/address-to-symbol.js +0 -1
  135. package/src/mcp/tools/art-loaders.js +1 -1
  136. package/src/mcp/tools/cart-parts.js +75 -4
  137. package/src/mcp/tools/classify-region.js +1 -1
  138. package/src/mcp/tools/diff-roms.js +1 -1
  139. package/src/mcp/tools/disasm-rebuild.js +507 -0
  140. package/src/mcp/tools/disasm.js +97 -9
  141. package/src/mcp/tools/find-references.js +1 -2
  142. package/src/mcp/tools/font-map.js +1 -1
  143. package/src/mcp/tools/frame.js +168 -3
  144. package/src/mcp/tools/index.js +0 -49
  145. package/src/mcp/tools/input-layout.js +0 -1
  146. package/src/mcp/tools/input.js +33 -3
  147. package/src/mcp/tools/lifecycle.js +18 -4
  148. package/src/mcp/tools/lospec.js +0 -19
  149. package/src/mcp/tools/platform-docs.js +1 -1
  150. package/src/mcp/tools/platform-tools.js +4 -4
  151. package/src/mcp/tools/project.js +54 -11
  152. package/src/mcp/tools/reinject.js +0 -1
  153. package/src/mcp/tools/rom-id.js +2 -2
  154. package/src/mcp/tools/snippets.js +2 -2
  155. package/src/mcp/tools/sprite-pipeline.js +1 -2
  156. package/src/mcp/tools/state.js +201 -14
  157. package/src/mcp/tools/tile-inspect.js +1 -1
  158. package/src/mcp/tools/toolchain.js +105 -12
  159. package/src/mcp/tools/watch-memory.js +137 -16
  160. package/src/platforms/_guides/ROMHACKING_PLAYBOOK.md +34 -0
  161. package/src/platforms/atari2600/TROUBLESHOOTING.md +6 -0
  162. package/src/platforms/atari7800/TROUBLESHOOTING.md +6 -0
  163. package/src/platforms/c64/MENTAL_MODEL.md +45 -1
  164. package/src/platforms/c64/TROUBLESHOOTING.md +6 -0
  165. package/src/platforms/c64/d64.js +280 -0
  166. package/src/platforms/c64/sid.js +0 -2
  167. package/src/platforms/common/metasprite-adapters.js +1 -1
  168. package/src/platforms/common/metasprite-codegen.js +3 -3
  169. package/src/platforms/common/registers.js +5 -3
  170. package/src/platforms/gb/MENTAL_MODEL.md +10 -0
  171. package/src/platforms/gb/TROUBLESHOOTING.md +6 -0
  172. package/src/platforms/gb/lib/c/gb_runtime.c +4 -4
  173. package/src/platforms/gba/TROUBLESHOOTING.md +6 -0
  174. package/src/platforms/gbc/TROUBLESHOOTING.md +6 -0
  175. package/src/platforms/gbc/lib/c/gb_runtime.c +4 -4
  176. package/src/platforms/genesis/TROUBLESHOOTING.md +6 -0
  177. package/src/platforms/gg/TROUBLESHOOTING.md +6 -0
  178. package/src/platforms/lynx/TROUBLESHOOTING.md +6 -0
  179. package/src/platforms/msx/MENTAL_MODEL.md +10 -6
  180. package/src/platforms/msx/TROUBLESHOOTING.md +6 -0
  181. package/src/platforms/nes/MENTAL_MODEL.md +63 -2
  182. package/src/platforms/nes/TROUBLESHOOTING.md +6 -0
  183. package/src/platforms/nes/image-to-tilemap.js +3 -0
  184. package/src/platforms/nes/lib/asm/famitone2.s +5 -1
  185. package/src/platforms/pce/MENTAL_MODEL.md +9 -4
  186. package/src/platforms/pce/TROUBLESHOOTING.md +6 -0
  187. package/src/platforms/pce/lib/c/pce_video.c +1 -1
  188. package/src/platforms/sms/TROUBLESHOOTING.md +6 -0
  189. package/src/platforms/snes/TROUBLESHOOTING.md +6 -0
  190. package/src/platforms/snes/brr.js +0 -2
  191. package/src/playtest/playtest.js +0 -7
  192. package/src/rom-id/identifier.js +15 -0
  193. package/src/toolchains/asar/asar.js +0 -9
  194. package/src/toolchains/assemble-snippet.js +30 -12
  195. package/src/toolchains/cc65/ines.js +145 -0
  196. package/src/toolchains/cc65/presets/nes/chr-ram-runtime.cfg +14 -1
  197. package/src/toolchains/cc65/presets/nes/chr-rom.cfg +83 -0
  198. package/src/toolchains/cc65/presets/nes/chr-rom.crt0.s +153 -0
  199. package/src/toolchains/common/reassemble.js +10 -3
  200. package/src/toolchains/common/sdk-cache.js +1 -1
  201. package/src/toolchains/genesis-c/genesis-c.js +5 -3
  202. package/src/toolchains/index.js +27 -3
  203. package/src/toolchains/parse-errors.js +78 -1
  204. package/src/toolchains/sdcc/preflight-lint.js +5 -1
  205. package/src/toolchains/sdcc/sdcc.js +1 -1
  206. package/src/toolchains/sjasm/sjasm.js +1 -1
  207. package/src/toolchains/snes-c/snes-c.js +2 -2
  208. package/src/toolchains/vasm68k/vasm68k.js +2 -4
  209. package/src/toolchains/wladx/wladx.js +1 -1
@@ -35,6 +35,22 @@ static const u32 tile_solid_1[8] = {
35
35
  0x11111111, 0x11111111, 0x11111111, 0x11111111,
36
36
  0x11111111, 0x11111111, 0x11111111, 0x11111111,
37
37
  };
38
+ /* BG court tiles (4bpp). The court fills BG1 so the arena isn't flat black
39
+ * (paddles+ball alone on black read as blank to a human — frame verify <92%).
40
+ * TILE_COURT (idx1 green): the playing surface, tiled across the screen.
41
+ * TILE_NET (idx2 white): a dashed vertical centre net. */
42
+ #define TILE_COURT 1
43
+ #define TILE_NET 2
44
+ /* Court surface as a two-green checkerboard (idx1 + idx3) so no single colour
45
+ * dominates the screen — a flat one-colour court still trips the blank check. */
46
+ static const u32 tile_court[8] = {
47
+ 0x11331133, 0x11331133, 0x11331133, 0x11331133,
48
+ 0x33113311, 0x33113311, 0x33113311, 0x33113311,
49
+ };
50
+ static const u32 tile_net[8] = {
51
+ 0x00022000, 0x00022000, 0x00000000, 0x00000000,
52
+ 0x00022000, 0x00022000, 0x00000000, 0x00000000,
53
+ };
38
54
 
39
55
  static OBJ_ATTR obj_buffer[128];
40
56
 
@@ -76,9 +92,27 @@ int main(void) {
76
92
 
77
93
  sfx_init();
78
94
 
79
- /* TTE for scores + hint. */
95
+ /* TTE for scores + hint (BG0). */
80
96
  tte_init_chr4c_default(0, BG_CBB(0) | BG_SBB(31));
81
- REG_DISPCNT = DCNT_MODE0 | DCNT_BG0 | DCNT_OBJ | DCNT_OBJ_1D;
97
+
98
+ /* Court background on BG1 so the arena reads as a real Pong court, not
99
+ * flat black. Tiles in char-block 1, map in screen-block 29. */
100
+ pal_bg_mem[1] = RGB15(2, 12, 4); /* court green (light) */
101
+ pal_bg_mem[2] = CLR_WHITE; /* net */
102
+ pal_bg_mem[3] = RGB15(1, 8, 3); /* court green (dark) */
103
+ tonccpy(&tile_mem[1][TILE_COURT], tile_court, sizeof(tile_court));
104
+ tonccpy(&tile_mem[1][TILE_NET], tile_net, sizeof(tile_net));
105
+ {
106
+ SCR_ENTRY *cmap = se_mem[29];
107
+ int tx, ty;
108
+ for (ty = 0; ty < 32; ty++)
109
+ for (tx = 0; tx < 32; tx++)
110
+ cmap[ty * 32 + tx] = SE_BUILD(
111
+ (tx == 15) ? TILE_NET : TILE_COURT, 0, 0, 0);
112
+ }
113
+ REG_BG1CNT = BG_CBB(1) | BG_SBB(29) | BG_REG_32x32 | BG_4BPP | BG_PRIO(3);
114
+
115
+ REG_DISPCNT = DCNT_MODE0 | DCNT_BG0 | DCNT_BG1 | DCNT_OBJ | DCNT_OBJ_1D;
82
116
  tte_write("#{P:16,2}P1");
83
117
  tte_write("#{P:208,2}P2");
84
118
  tte_write("#{P:36,150}UP/DOWN MOVES YOUR PADDLE");
@@ -31,17 +31,53 @@
31
31
 
32
32
  #include <tonc.h>
33
33
 
34
+ /* ── Backdrop tiles (4bpp, 8 rows × 32 bits) ─────────────────────────
35
+ * Two solid colour tiles so the whole BG0 map reads as a checkerboard,
36
+ * not a flat blank backdrop. Every nibble of tile 1 = palette index 1,
37
+ * every nibble of tile 2 = palette index 2 — so the tile is one solid
38
+ * colour. (m3_fill's tiled-mode equivalent: paint the whole screen.) */
39
+ static const u32 tile_solid1[8] = {
40
+ 0x11111111, 0x11111111, 0x11111111, 0x11111111,
41
+ 0x11111111, 0x11111111, 0x11111111, 0x11111111,
42
+ };
43
+ static const u32 tile_solid2[8] = {
44
+ 0x22222222, 0x22222222, 0x22222222, 0x22222222,
45
+ 0x22222222, 0x22222222, 0x22222222, 0x22222222,
46
+ };
47
+
34
48
  int main(void) {
49
+ /* ── Filled tiled backdrop on BG0 ────────────────────────────
50
+ * Without this the screen is just the black backdrop colour and a
51
+ * few text glyphs — which reads as "blank". We lay a two-tone
52
+ * checkerboard across the entire 32x32 BG0 map so a clear majority
53
+ * of the screen is coloured (the GBA tiled-mode analogue of
54
+ * m3_fill-ing a Mode-3 framebuffer). Tile data → char-block 0,
55
+ * map → screen-block 28 (clear of TTE's char-block 2 / SBB 30). */
56
+ pal_bg_mem[0] = CLR_BLACK;
57
+ pal_bg_mem[1] = RGB15(3, 6, 14); /* deep sky blue */
58
+ pal_bg_mem[2] = RGB15(2, 4, 9); /* darker navy */
59
+ tonccpy(&tile_mem[0][1], tile_solid1, sizeof(tile_solid1));
60
+ tonccpy(&tile_mem[0][2], tile_solid2, sizeof(tile_solid2));
61
+ REG_BG0CNT = BG_CBB(0) | BG_SBB(28) | BG_REG_32x32 | BG_4BPP | BG_PRIO(3);
62
+ {
63
+ SCR_ENTRY *map = se_mem[28];
64
+ for (int ty = 0; ty < 32; ty++)
65
+ for (int tx = 0; tx < 32; tx++)
66
+ map[ty * 32 + tx] = SE_BUILD(1 + ((tx ^ ty) & 1), 0, 0, 0);
67
+ }
68
+
35
69
  /* Initialise TTE in 4-bits-per-pixel chr-mode with the built-in
36
70
  * sys8 font. Cleanest API in the entire GBA ecosystem — one call
37
- * gets you a usable text terminal on BG0.
71
+ * gets you a usable text terminal. We put it on BG1 (char-block 2,
72
+ * screen-block 30) so it sits cleanly in front of the BG0 backdrop.
38
73
  *
39
74
  * NOTE: we deliberately do NOT call tte_init_con() — that lives
40
75
  * in the excluded tte_iohook.c (the libsysbase bridge). Without
41
76
  * it, printf/iprintf don't route through TTE — but `tte_write` /
42
77
  * `tte_printf` work directly without any libsysbase plumbing,
43
78
  * which is what the Tonc tutorial uses everywhere anyway. */
44
- tte_init_chr4c_default(0, BG_CBB(0) | BG_SBB(31));
79
+ tte_init_chr4c_default(1, BG_CBB(2) | BG_SBB(30));
80
+ REG_BG1CNT |= BG_PRIO(0); /* text in front of the backdrop */
45
81
 
46
82
  /* ── IRQ setup ── REQUIRED for VBlankIntrWait() to work ──────
47
83
  * Without this, the BIOS halts the CPU on the first
@@ -50,9 +86,9 @@ int main(void) {
50
86
  irq_init(NULL);
51
87
  irq_add(II_VBLANK, NULL);
52
88
 
53
- /* Set DISPCNT — turn on BG0 (where TTE drew the font tiles into
54
- * char-base 0 + screen-base 31). DCNT_MODE0 is the tile-BG mode. */
55
- REG_DISPCNT = DCNT_MODE0 | DCNT_BG0;
89
+ /* Set DISPCNT — turn on BG0 (the filled backdrop) and BG1 (TTE
90
+ * text). DCNT_MODE0 is the tile-BG mode. */
91
+ REG_DISPCNT = DCNT_MODE0 | DCNT_BG0 | DCNT_BG1;
56
92
 
57
93
  /* Draw text. tte_write moves the internal cursor; \n wraps. */
58
94
  tte_write("#{P:32,32}"); /* position cursor at pixel (32,32) */
@@ -35,6 +35,19 @@ static const u32 sprite_tile[8] = {
35
35
  0x11111111, 0x11111111, 0x11111111, 0x11111111,
36
36
  };
37
37
 
38
+ /* ── Backdrop tiles (4bpp) ───────────────────────────────────────────
39
+ * Two solid-colour BG tiles so we can lay a two-tone checkerboard across
40
+ * the whole BG0 map. Without a filled backdrop the screen is just the
41
+ * black backdrop colour and one tiny sprite — which reads as "blank". */
42
+ static const u32 bg_tile1[8] = {
43
+ 0x11111111, 0x11111111, 0x11111111, 0x11111111,
44
+ 0x11111111, 0x11111111, 0x11111111, 0x11111111,
45
+ };
46
+ static const u32 bg_tile2[8] = {
47
+ 0x22222222, 0x22222222, 0x22222222, 0x22222222,
48
+ 0x22222222, 0x22222222, 0x22222222, 0x22222222,
49
+ };
50
+
38
51
  /* Shadow OAM. Tonc's recommended pattern: allocate your own 128-slot
39
52
  * buffer in WRAM, mutate it freely each frame, then oam_copy to push
40
53
  * the changes to OAM hardware via DMA. */
@@ -81,12 +94,33 @@ int main(void) {
81
94
  ATTR2_PALBANK(0) | 0);
82
95
  obj_set_pos(&obj_buffer[0], x, y);
83
96
 
97
+ /* ── Filled checkerboard backdrop on BG0 ─────────────────────
98
+ * Lay a two-tone checkerboard across the whole 32x32 BG0 map so the
99
+ * frame has real content behind the sprite instead of a flat black
100
+ * backdrop (which reads as "blank"). BG tiles → char-block 0, map →
101
+ * screen-block 28 (the OBJ tiles live in char-block 4, so there's no
102
+ * clash). */
103
+ pal_bg_mem[0] = CLR_BLACK;
104
+ pal_bg_mem[1] = RGB15(3, 6, 14); /* deep sky blue */
105
+ pal_bg_mem[2] = RGB15(2, 4, 9); /* darker navy */
106
+ tonccpy(&tile_mem[0][1], bg_tile1, sizeof(bg_tile1));
107
+ tonccpy(&tile_mem[0][2], bg_tile2, sizeof(bg_tile2));
108
+ REG_BG0CNT = BG_CBB(0) | BG_SBB(28) | BG_REG_32x32 | BG_4BPP | BG_PRIO(3);
109
+ {
110
+ SCR_ENTRY *map = se_mem[28];
111
+ int tx, ty;
112
+ for (ty = 0; ty < 32; ty++)
113
+ for (tx = 0; tx < 32; tx++)
114
+ map[ty * 32 + tx] = SE_BUILD(1 + ((tx ^ ty) & 1), 0, 0, 0);
115
+ }
116
+
84
117
  /* ── Display setup ───────────────────────────────────────────
85
118
  * DCNT_MODE0 — tiled mode (so BG0..3 are tile maps)
119
+ * DCNT_BG0 — enable the checkerboard backdrop
86
120
  * DCNT_OBJ — enable sprites
87
121
  * DCNT_OBJ_1D — linear OAM tile addressing (vs the 2D matrix
88
122
  * layout that's almost always wrong) */
89
- REG_DISPCNT = DCNT_MODE0 | DCNT_OBJ | DCNT_OBJ_1D;
123
+ REG_DISPCNT = DCNT_MODE0 | DCNT_BG0 | DCNT_OBJ | DCNT_OBJ_1D;
90
124
 
91
125
  /* ── Game loop ───────────────────────────────────────────────
92
126
  * key_poll() updates the key state — call it once per frame.
@@ -1,19 +1,23 @@
1
1
  /* ── default.c — minimal Game Boy Color (CGB) starter ─────────────
2
2
  *
3
- * Boots the LCD, cycles a real CGB background palette via the BCPS
4
- * + BCPD palette-RAM registers. Smallest possible "ROM that does
5
- * something visible IN COLOR" use this as the starting point when
6
- * you want CGB-mode color, not DMG greyscale.
3
+ * A "hello, it works! IN COLOR" screen: a tiled background (two bands
4
+ * + a centre box) drawn with a real CGB palette, plus a sprite that
5
+ * bounces around. The very first GBC build shows recognizable content
6
+ * not a flat colour. Use this as the starting point when you're not
7
+ * yet sure what you want to build; edit from here.
7
8
  *
8
9
  * GBC-specific notes:
9
10
  * - CGB uses BCPS/BCPD ($FF68/$FF69) to write into 64 bytes of
10
- * palette RAM (8 BG palettes × 4 colors × 2 bytes each, BGR555
11
- * little-endian). DMG-only BGP ($FF47) does nothing in CGB mode.
11
+ * palette RAM (8 BG palettes × 4 colours × 2 bytes each, BGR555
12
+ * little-endian) and OCPS/OCPD for the sprite palettes. The DMG-only
13
+ * BGP/OBP0/OBP1 ($FF47-$49) registers do nothing in CGB mode.
14
+ * - You MUST put tiles in VRAM and enable the BG (LCDC bit 0) or the
15
+ * screen stays one flat colour — the #1 GB "why is it blank" footgun.
16
+ * We upload tiles to $8000 and select LCDC_TILE_DATA_LO (unsigned
17
+ * $8000 addressing) so tile index N lives at $8000 + N*16.
12
18
  * - patchGbHeader on a .gbc file sets $0143 = $80 (CGB-aware) by
13
- * default. The corresponding `.gb` default uses BGP — don't
19
+ * default. The corresponding `.gb` default uses DMG BGP — don't
14
20
  * cross-pollinate the two trees.
15
- * - This template is intentionally DIFFERENT from examples/gb/
16
- * templates/default.c — that one demonstrates DMG palettes.
17
21
  *
18
22
  * For something more game-shaped, peek at other templates in this dir:
19
23
  * - hello_sprite — sprite + d-pad movement
@@ -25,37 +29,110 @@
25
29
  #include "gb_hardware.h"
26
30
  #include "gb_runtime.h"
27
31
 
28
- static const uint16_t palettes[4] = {
29
- 0x7FFF, /* white */
30
- 0x3DEF, /* light grey */
31
- 0x2108, /* dark grey */
32
- 0x0000, /* black */
32
+ /* Three 8×8 tiles, 2bpp (16 bytes each: row N = byte 2N low-bits, 2N+1
33
+ * high-bits). Colour index per tile pixel selects into the 4-colour
34
+ * palette below.
35
+ * tile 0 — blank (all colour 0 — reserved so OAM Y=0 doesn't glitch)
36
+ * tile 1 — solid (all colour 1 — the background fill / bands)
37
+ * tile 2 — sprite (a filled diamond in colour 3) */
38
+ static const uint8_t tiles[3 * 16] = {
39
+ /* tile 0: blank */
40
+ 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,
41
+ /* tile 1: solid colour 1 (low plane all-on, high plane all-off) */
42
+ 0xFF,0x00, 0xFF,0x00, 0xFF,0x00, 0xFF,0x00,
43
+ 0xFF,0x00, 0xFF,0x00, 0xFF,0x00, 0xFF,0x00,
44
+ /* tile 2: diamond in colour 3 (both planes set on the diamond pixels) */
45
+ 0x18,0x18, 0x3C,0x3C, 0x7E,0x7E, 0xFF,0xFF,
46
+ 0xFF,0xFF, 0x7E,0x7E, 0x3C,0x3C, 0x18,0x18,
33
47
  };
34
48
 
49
+ /* BG palette 0 (BGR555). Colour 0 = backdrop, colour 1 = the bands/box.
50
+ * We cycle colour 1 through these four shades each ~32 frames so you can
51
+ * SEE the CGB palette path is alive. */
52
+ static const uint16_t bg_fill_cycle[4] = {
53
+ 0x03FF, /* yellow-ish */
54
+ 0x7C00, /* blue */
55
+ 0x03E0, /* green */
56
+ 0x001F, /* red */
57
+ };
58
+
59
+ /* Sprite palette (OBJ palette 0): 0 transparent, 3 = white diamond. */
60
+ static const uint16_t obj_pal[4] = {
61
+ 0x0000, /* 0 transparent (sprite colour 0 never drawn) */
62
+ 0x7FFF, /* 1 white */
63
+ 0x03E0, /* 2 green */
64
+ 0x7FFF, /* 3 white */
65
+ };
66
+
67
+ static void set_bg_color1(uint16_t bgr555) {
68
+ /* Write BG palette 0: colour 0 = dark backdrop, colour 1 = bgr555. */
69
+ BCPS = 0x80; /* palette 0, colour 0, auto-inc */
70
+ BCPD = 0x08; BCPD = 0x21; /* colour 0 = dark grey (0x2108) */
71
+ BCPD = (uint8_t)(bgr555 & 0xFF); /* colour 1 lo */
72
+ BCPD = (uint8_t)((bgr555 >> 8) & 0xFF); /* colour 1 hi */
73
+ }
74
+
35
75
  void main(void) {
36
- uint8_t i;
76
+ uint8_t x, y;
77
+ uint8_t sx = 76, sy = 64; /* sprite screen position */
78
+ int8_t dx = 1, dy = 1; /* sprite velocity */
37
79
  uint8_t shade = 0;
38
80
  uint16_t frame = 0;
81
+ uint8_t *bg_map = BG_MAP_0; /* $9800 */
82
+ uint8_t i;
39
83
 
84
+ /* 1. LCD off (safely — lcd_init_default checks LCDC.7 first). */
40
85
  lcd_init_default();
86
+ LCDC = 0;
41
87
 
42
- /* Initial BG palette = all 4 entries cycle to the same shade. */
43
- BCPS = 0x80;
88
+ /* 2. Tiles VRAM at $8000 (unsigned addressing, see LCDC_TILE_DATA_LO). */
89
+ memcpy_vram((void *)0x8000, tiles, sizeof(tiles));
90
+
91
+ /* 3. Palettes. */
92
+ set_bg_color1(bg_fill_cycle[0]);
93
+ OCPS = 0x80;
44
94
  for (i = 0; i < 4; i++) {
45
- BCPD = (uint8_t)(palettes[shade] & 0xFF);
46
- BCPD = (uint8_t)((palettes[shade] >> 8) & 0xFF);
95
+ OCPD = (uint8_t)(obj_pal[i] & 0xFF);
96
+ OCPD = (uint8_t)((obj_pal[i] >> 8) & 0xFF);
97
+ }
98
+
99
+ /* 4. Paint the BG map (32×32; we fill the visible 20×18). Background
100
+ * is tile 0 (blank → backdrop colour); two solid bands + a centre
101
+ * box are tile 1 so the screen reads as real content. */
102
+ for (y = 0; y < 32; y++)
103
+ for (x = 0; x < 32; x++)
104
+ bg_map[y * 32 + x] = 0;
105
+ for (x = 0; x < 20; x++) {
106
+ bg_map[2 * 32 + x] = 1; /* top band (row 2) */
107
+ bg_map[15 * 32 + x] = 1; /* bottom band (row 15) */
47
108
  }
109
+ for (y = 6; y < 12; y++)
110
+ for (x = 6; x < 14; x++)
111
+ bg_map[y * 32 + x] = 1; /* centre box */
112
+
113
+ /* 5. Initial sprite. */
114
+ oam_clear();
115
+ oam_set(0, (uint8_t)(sy + 16), (uint8_t)(sx + 8), 2, 0);
116
+
117
+ /* 6. LCD on with BG + OBJ + $8000 tile addressing. */
118
+ LCDC = LCDC_LCD_ON | LCDC_BG_ON | LCDC_OBJ_ON | LCDC_TILE_DATA_LO;
48
119
 
49
120
  for (;;) {
50
121
  wait_vblank();
122
+ oam_dma_flush();
123
+
51
124
  frame++;
52
- if ((frame & 0x1F) == 0) { /* every 32 frames */
53
- shade = (shade + 1) & 0x03;
54
- BCPS = 0x80;
55
- for (i = 0; i < 4; i++) {
56
- BCPD = (uint8_t)(palettes[shade] & 0xFF);
57
- BCPD = (uint8_t)((palettes[shade] >> 8) & 0xFF);
58
- }
125
+ if ((frame & 0x1F) == 0) { /* every 32 frames: cycle BG colour */
126
+ shade = (uint8_t)((shade + 1) & 0x03);
127
+ set_bg_color1(bg_fill_cycle[shade]);
59
128
  }
129
+
130
+ /* Bounce the sprite around the 160×144 visible area. */
131
+ sx = (uint8_t)(sx + dx);
132
+ sy = (uint8_t)(sy + dy);
133
+ if (sx < 1 || sx > 152) dx = (int8_t)-dx;
134
+ if (sy < 1 || sy > 136) dy = (int8_t)-dy;
135
+ oam_clear();
136
+ oam_set(0, (uint8_t)(sy + 16), (uint8_t)(sx + 8), 2, 0);
60
137
  }
61
138
  }
@@ -54,6 +54,8 @@ void main(void) {
54
54
  uint8_t x = 80; /* hardware X = screen X + 8 */
55
55
  uint8_t y = 80; /* hardware Y = screen Y + 16 */
56
56
  uint8_t i;
57
+ uint8_t *bg_map;
58
+ uint16_t j;
57
59
 
58
60
  /* ── 1. LCD off (safe whether it was on or off) ──────────────────
59
61
  * lcd_init_default() checks LCDC.7 and only waits for vblank if the
@@ -71,6 +73,13 @@ void main(void) {
71
73
  * TROUBLESHOOTING.md "VRAM stays empty / sprite never appears". */
72
74
  memcpy_vram((uint8_t *)0x8010, tile_data, 16);
73
75
 
76
+ /* ── 2b. Fill the BG tilemap so the screen isn't an empty backdrop. ──
77
+ * With LCDC_TILE_DATA_LO ($8000 addressing) BG tile index 1 == our tile
78
+ * at $8010 — so we tile the whole 32×32 BG map with it. Pointer-walk write
79
+ * (NOT bg_map[k]=1, which SDCC sm83 miscompiles into VRAM). */
80
+ bg_map = (uint8_t *)0x9800;
81
+ for (j = 0; j < 32u * 32u; j++) *bg_map++ = 1;
82
+
74
83
  /* ── 3. Object palette 0 (CGB path) ──────────────────────────────
75
84
  * OCPS bit 7 = auto-increment after each write; bits 5..3 = palette
76
85
  * index (0..7); bits 2..1 = color index (0..3); bit 0 = MSB select.
@@ -102,9 +111,9 @@ void main(void) {
102
111
  oam_dma_flush();
103
112
 
104
113
  /* ── 5. Turn the LCD back on with BG + OBJ enabled. ──────────────
105
- * LCDC bits: 0x80=LCD on, 0x02=OBJ on, 0x10=tile data at $8000.
106
- * (BG remains off we have no BG map set up.) */
107
- LCDC = LCDC_LCD_ON | LCDC_OBJ_ON | LCDC_TILE_DATA_LO;
114
+ * LCDC bits: 0x80=LCD on, 0x01=BG on, 0x02=OBJ on, 0x10=tile data at $8000.
115
+ * BG is on now that we filled the BG map in step 2b. */
116
+ LCDC = LCDC_LCD_ON | LCDC_BG_ON | LCDC_OBJ_ON | LCDC_TILE_DATA_LO;
108
117
 
109
118
  /* ── 6. APU on — let the player beep ──────────────────────────── */
110
119
  sound_init();
@@ -23,6 +23,9 @@
23
23
 
24
24
  extern const huge_song_t sample_song;
25
25
 
26
+ /* CGB BG palette 0: backdrop colour cycles (bg_colors[shade]) while
27
+ * colours 1..3 stay fixed and bright, so the checkerboard backdrop below
28
+ * always shows several distinct colours (not a single flat field). */
26
29
  static const uint16_t bg_colors[4] = {
27
30
  0x4210, /* dim purple */
28
31
  0x4308, /* dim blue */
@@ -30,21 +33,66 @@ static const uint16_t bg_colors[4] = {
30
33
  0x0017, /* dim red */
31
34
  };
32
35
 
36
+ /* Two 8×8 2bpp tiles so the BG isn't a single flat colour:
37
+ * tile 1 — solid colour 1
38
+ * tile 2 — solid colour 2
39
+ * Checkerboarded across the BG map below. */
40
+ static const uint8_t tile_solid1[16] = {
41
+ 0xFF,0x00, 0xFF,0x00, 0xFF,0x00, 0xFF,0x00,
42
+ 0xFF,0x00, 0xFF,0x00, 0xFF,0x00, 0xFF,0x00,
43
+ };
44
+ static const uint8_t tile_solid2[16] = {
45
+ 0x00,0xFF, 0x00,0xFF, 0x00,0xFF, 0x00,0xFF,
46
+ 0x00,0xFF, 0x00,0xFF, 0x00,0xFF, 0x00,0xFF,
47
+ };
48
+
49
+ /* Write CGB BG palette 0 with the current backdrop shade plus fixed bright
50
+ * colours 1..3 (blue / green / white) so the checkerboard is multi-colour. */
51
+ static void set_bg_palette(uint8_t shade) {
52
+ BCPS = 0x80; /* auto-increment, start at palette 0 colour 0 */
53
+ /* colour 0 — animated backdrop */
54
+ BCPD = (uint8_t)(bg_colors[shade] & 0xFFu);
55
+ BCPD = (uint8_t)((bg_colors[shade] >> 8) & 0xFFu);
56
+ /* colour 1 — bright blue */
57
+ BCPD = (uint8_t)(0x7C00u & 0xFFu);
58
+ BCPD = (uint8_t)((0x7C00u >> 8) & 0xFFu);
59
+ /* colour 2 — bright green */
60
+ BCPD = (uint8_t)(0x03E0u & 0xFFu);
61
+ BCPD = (uint8_t)((0x03E0u >> 8) & 0xFFu);
62
+ /* colour 3 — white */
63
+ BCPD = (uint8_t)(0x7FFFu & 0xFFu);
64
+ BCPD = (uint8_t)((0x7FFFu >> 8) & 0xFFu);
65
+ }
66
+
33
67
  void main(void) {
34
- uint8_t i;
35
68
  uint8_t shade = 0;
36
69
  uint16_t frame = 0;
70
+ uint8_t *bg_map;
71
+ uint16_t j;
37
72
 
38
73
  lcd_init_default();
39
- sound_init();
74
+ LCDC = 0; /* LCD off so we can write VRAM freely */
40
75
 
41
- /* Write the initial CGB BG palette 0 (4 entries, same colour). */
42
- BCPS = 0x80; /* auto-increment, start at index 0 */
43
- for (i = 0; i < 4; i++) {
44
- BCPD = (uint8_t)(bg_colors[shade] & 0xFFu);
45
- BCPD = (uint8_t)((bg_colors[shade] >> 8) & 0xFFu);
76
+ /* Upload two tiles to VRAM slots 1 ($8010) and 2 ($8020). Use
77
+ * memcpy_vram (pointer-walk) an indexed dst[i]=src[i] loop into VRAM
78
+ * is miscompiled by SDCC sm83. */
79
+ memcpy_vram((uint8_t *)0x8010, tile_solid1, 16);
80
+ memcpy_vram((uint8_t *)0x8020, tile_solid2, 16);
81
+
82
+ /* Checkerboard the 32×32 BG map at $9800 with tiles 1 and 2. Pointer-walk
83
+ * (NOT bg_map[k]=..., which SDCC sm83 miscompiles into VRAM). */
84
+ bg_map = (uint8_t *)0x9800;
85
+ for (j = 0; j < 32u * 32u; j++) {
86
+ *bg_map++ = (uint8_t)((((j ^ (j >> 5)) & 1u) ? 1u : 2u));
46
87
  }
47
88
 
89
+ set_bg_palette(shade);
90
+
91
+ /* LCD on with BG enabled, $8000 tile-data addressing. */
92
+ LCDC = LCDC_LCD_ON | LCDC_BG_ON | LCDC_TILE_DATA_LO;
93
+
94
+ sound_init();
95
+
48
96
  hUGE_init(&sample_song);
49
97
 
50
98
  for (;;) {
@@ -53,11 +101,7 @@ void main(void) {
53
101
  frame++;
54
102
  if ((frame & 0x3F) == 0) { /* every 64 frames ≈ 1 s */
55
103
  shade = (uint8_t)((shade + 1) & 0x03);
56
- BCPS = 0x80;
57
- for (i = 0; i < 4; i++) {
58
- BCPD = (uint8_t)(bg_colors[shade] & 0xFFu);
59
- BCPD = (uint8_t)((bg_colors[shade] >> 8) & 0xFFu);
60
- }
104
+ set_bg_palette(shade);
61
105
  }
62
106
  }
63
107
  }
@@ -28,9 +28,26 @@ static const uint8_t tile_platform[16] = {
28
28
  0xFF,0xFF, 0x80,0x80, 0x80,0x80, 0x80,0x80,
29
29
  0x80,0x80, 0x80,0x80, 0x80,0x80, 0xFF,0xFF,
30
30
  };
31
+ /* ── Backdrop tiles ───────────────────────────────────────────────────
32
+ * Fill the whole world so the screen is never one flat colour (the #1 GB
33
+ * "why is it blank" footgun). tile_sky is a sparse dot pattern over the
34
+ * sky; tile_ground is a textured dirt fill under the floor line. */
35
+ static const uint8_t tile_sky[16] = {
36
+ 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x20,0x20,
37
+ 0x00,0x00, 0x00,0x00, 0x02,0x02, 0x00,0x00,
38
+ };
39
+ static const uint8_t tile_ground[16] = {
40
+ 0xFF,0x00, 0xDB,0x24, 0xFF,0x00, 0x6D,0x92,
41
+ 0xFF,0x00, 0xDB,0x24, 0xFF,0x00, 0x6D,0x92,
42
+ };
43
+ #define T_BLANK 0
44
+ #define T_PLATFORM 2
45
+ #define T_SKY 3
46
+ #define T_GROUND 4
31
47
 
32
48
  static const uint16_t obj_palette[4] = { 0x7FFF, 0x001F, 0x03E0, 0x7C00 };
33
- static const uint16_t bg_palette[4] = { 0x7FFF, 0x5294, 0x294A, 0x0000 };
49
+ /* BG palette: 0 sky-blue, 1 mid, 2 dirt-dark, 3 near-black detail. */
50
+ static const uint16_t bg_palette[4] = { 0x7E10, 0x5294, 0x114A, 0x0000 };
34
51
 
35
52
  typedef struct { int16_t x, y, w, h; } Rect;
36
53
 
@@ -61,8 +78,9 @@ static uint8_t on_platform(int16_t px, int16_t py) {
61
78
 
62
79
  static void upload_tile(uint8_t slot, const uint8_t *src) {
63
80
  uint8_t *dst = (uint8_t *)(0x8000 + slot * 16);
64
- uint8_t i;
65
- for (i = 0; i < 16; i++) dst[i] = src[i];
81
+ /* memcpy_vram (pointer-walk) — NOT an indexed dst[i]=src[i] loop, which
82
+ * SDCC sm83 miscompiles when dst points into VRAM ($8000-$9FFF). */
83
+ memcpy_vram(dst, src, 16);
66
84
  }
67
85
 
68
86
  static void paint_platforms(void) {
@@ -74,8 +92,10 @@ static void paint_platforms(void) {
74
92
  const Rect *p;
75
93
  /* k MUST be uint16_t: 32*18 = 576 > 255, so a uint8_t counter would
76
94
  * never reach the bound and this loop would spin forever (the BG map
77
- * never clears, main() never starts). Classic SDCC limited-range trap. */
78
- for (k = 0; k < 32 * 18; k++) map[k] = 0; /* blank tile slot 0 */
95
+ * never clears, main() never starts). Classic SDCC limited-range trap.
96
+ * Fill sky above the floor line (row 16 = y 128) and textured ground
97
+ * at and below it, so the whole world is a real scene, not blank. */
98
+ for (k = 0; k < 32 * 18; k++) map[k] = (k >= 16 * 32) ? T_GROUND : T_SKY;
79
99
  for (i = 0; i < N_PLATFORMS; i++) {
80
100
  p = &platforms[i];
81
101
  cx = p->x >> 3;
@@ -84,7 +104,7 @@ static void paint_platforms(void) {
84
104
  ch = (p->h + 7) >> 3;
85
105
  for (j = 0; j < cw; j++) {
86
106
  if (cx + j < 32 && cy < 32)
87
- map[cy * 32 + cx + j] = 2; /* tile slot 2 = platform */
107
+ map[cy * 32 + cx + j] = T_PLATFORM; /* platform top edge */
88
108
  }
89
109
  }
90
110
  }
@@ -111,6 +131,8 @@ void main(void) {
111
131
  upload_tile(0, tile_blank);
112
132
  upload_tile(1, tile_player);
113
133
  upload_tile(2, tile_platform);
134
+ upload_tile(T_SKY, tile_sky);
135
+ upload_tile(T_GROUND, tile_ground);
114
136
 
115
137
  OCPS = 0x80;
116
138
  for (i = 0; i < 4; i++) {
@@ -21,8 +21,22 @@
21
21
  #define T_R 1
22
22
  #define T_G 2
23
23
  #define T_B 3
24
-
25
- static const uint8_t tile_blank[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
24
+ #define T_WALL 4
25
+
26
+ /* tile_blank is the EMPTY-cell / backdrop tile. It is NOT all-zero: a
27
+ * subtle dither (colour 0 + faint colour 1) so the empty playfield and the
28
+ * area around the well read as a textured surface, never one flat colour
29
+ * (the #1 GB "why is it blank" footgun). Locked blocks / the active piece
30
+ * overdraw it with the R/G/B shape tiles. */
31
+ static const uint8_t tile_blank[16] = {
32
+ 0x00,0x00, 0x22,0x00, 0x00,0x00, 0x88,0x00,
33
+ 0x00,0x00, 0x22,0x00, 0x00,0x00, 0x88,0x00,
34
+ };
35
+ /* Well frame: a solid colour-2 border drawn around the play area. */
36
+ static const uint8_t tile_wall[16] = {
37
+ 0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF,
38
+ 0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF,
39
+ };
26
40
  /* Three distinct tile shapes (since GB BG is 2bpp, we differentiate
27
41
  * by *shape*, not colour-on-CGB). The CGB palette path could give us
28
42
  * real colours; for DMG-compatibility we use shape. */
@@ -127,8 +141,23 @@ static void lock_piece(void) {
127
141
 
128
142
  static void upload_tile(uint8_t slot, const uint8_t *src) {
129
143
  uint8_t *dst = (uint8_t *)(0x8000 + slot * 16);
130
- uint8_t i;
131
- for (i = 0; i < 16; i++) dst[i] = src[i];
144
+ /* memcpy_vram (pointer-walk) — NOT an indexed dst[i]=src[i] loop, which
145
+ * SDCC sm83 miscompiles when dst points into VRAM ($8000-$9FFF). */
146
+ memcpy_vram(dst, src, 16);
147
+ }
148
+
149
+ /* Draw the well frame around the 6×12 play area. Grid cells live at
150
+ * map[(row+1)*32 + (col+7)] (rows 1..12, cols 7..12), so the frame is the
151
+ * column to each side (6 and 13) and the floor row just below (row 13). */
152
+ static void draw_well(void) {
153
+ uint8_t *map = (uint8_t *)0x9800;
154
+ uint8_t r;
155
+ for (r = 1; r <= 12; r++) {
156
+ map[r * 32 + 6] = T_WALL; /* left wall */
157
+ map[r * 32 + 13] = T_WALL; /* right wall */
158
+ }
159
+ for (r = 6; r <= 13; r++)
160
+ map[13 * 32 + r] = T_WALL; /* floor */
132
161
  }
133
162
 
134
163
  void main(void) {
@@ -145,6 +174,7 @@ void main(void) {
145
174
  upload_tile(T_R, tile_r);
146
175
  upload_tile(T_G, tile_g);
147
176
  upload_tile(T_B, tile_b);
177
+ upload_tile(T_WALL, tile_wall);
148
178
 
149
179
  BCPS = 0x80;
150
180
  for (i = 0; i < 4; i++) {
@@ -165,6 +195,7 @@ void main(void) {
165
195
  score = 0;
166
196
  fall_timer = 0;
167
197
  new_piece();
198
+ draw_well();
168
199
  draw_grid();
169
200
 
170
201
  LCDC = LCDC_LCD_ON | LCDC_BG_ON | LCDC_TILE_DATA_LO;