migrated to sourcehut

This commit is contained in:
nytpu 2020-12-01 10:34:50 -07:00
parent 6b24ac5549
commit e5a944b8db
30 changed files with 1 additions and 1867 deletions

5
.gitignore vendored
View File

@ -1,5 +0,0 @@
/build/
/obj/
/dep/
/res/
Session.vim

9
.gitmodules vendored
View File

@ -1,9 +0,0 @@
[submodule "include/gb-vwf"]
path = include/gb-vwf
url = https://github.com/ISSOtm/gb-vwf
[submodule "include/rgbds-structs"]
path = include/rgbds-structs
url = https://github.com/ISSOtm/rgbds-structs
[submodule "include/hardware.inc"]
path = include/hardware.inc
url = https://github.com/gbdev/hardware.inc

24
LICENSE
View File

@ -1,24 +0,0 @@
MIT License
Copyright (c) 2020 nytpu
This project incorporates code from:
Copyright (c) 2020 Eldred Habert
Copyright (c) 2018 Damian Yerrick
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.

117
Makefile
View File

@ -1,117 +0,0 @@
.SUFFIXES:
################################################
# #
# CONSTANT DEFINITIONS #
# #
################################################
# Directory constants
SRCDIR := src
BINDIR := build
OBJDIR := obj
DEPDIR := dep
RESDIR := res
# Program constants
MKDIR := $(shell which mkdir)
# Shortcut if you want to use a local copy of RGBDS
RGBDS =
RGBASM = $(RGBDS)rgbasm
RGBLINK = $(RGBDS)rgblink
RGBFIX = $(RGBDS)rgbfix
RGBGFX = $(RGBDS)rgbgfx
ROM = $(ROMNAME).$(ROMEXT)
# Argument constants
INCDIRS = $(SRCDIR)/ include/
WARNINGS = all extra
ASFLAGS = -p $(PADVALUE) $(addprefix -i,$(INCDIRS)) $(addprefix -W,$(WARNINGS))
LDFLAGS = -p $(PADVALUE)
FIXFLAGS = -p $(PADVALUE) -v -i "$(GAMEID)" -k "$(LICENSEE)" -l $(OLDLIC) -m $(MBC) -n $(VERSION) -r $(SRAMSIZE) -t $(TITLE)
# The list of "root" ASM files that RGBASM will be invoked on
SRCS = $(wildcard $(SRCDIR)/*.asm)
## Project-specific configuration
# Use this to override the above
include project.mk
################################################
# #
# RESOURCE FILES #
# #
################################################
# By default, asset recipes convert files in `res/` into other files in `res/`
# This line causes assets not found in `res/` to be also looked for in `src/res/`
# "Source" assets can thus be safely stored there without `make clean` removing them
VPATH := $(SRCDIR)
$(RESDIR)/%.1bpp: $(RESDIR)/%.png
@$(MKDIR) -p $(@D)
$(RGBGFX) -d 1 -o $@ $<
$(RESDIR)/%.2bpp: $(RESDIR)/%.png
@$(MKDIR) -p $(@D)
$(RGBGFX) -t $@.tilemap -u -o $@ $<
$(RESDIR)/%.tilemap: $(RESDIR)/%.2bpp
# Define how to compress files using the PackBits16 codec
# Compressor script requires Python 3
$(RESDIR)/%.pb16 $(RESDIR)/%.pb16.size: $(RESDIR)/% tools/pb16.py
@$(MKDIR) -p $(@D)
tools/pb16.py $< $(RESDIR)/$*.pb16
echo 'NB_PB16_BLOCKS equ (' `wc -c $< | cut -d ' ' -f 1` ' + 15) / 16' > $(RESDIR)/$*.pb16.size
# Define how to compress files using the PackBits8 codec
# Compressor script requires Python 3
$(RESDIR)/%.pb8 $(RESDIR)/%.pb8.size: $(RESDIR)/% tools/pb8.py
@$(MKDIR) -p $(@D)
tools/pb8.py $< $(RESDIR)/$*.pb8
echo 'NB_PB8_BLOCKS equ (' `wc -c $< | cut -d ' ' -f 1` ' + 7) / 8' > $(RESDIR)/$*.pb8.size
###############################################
# #
# COMPILATION #
# #
###############################################
# `all` (Default target): build the ROM
all: $(BINDIR)/$(ROM)
.PHONY: all
# `clean`: Clean temp and bin files
clean:
-rm -rf $(BINDIR) $(OBJDIR) $(DEPDIR) $(RESDIR)
.PHONY: clean
# `rebuild`: Build everything from scratch
# It's important to do these two in order if we're using more than one job
rebuild:
$(MAKE) clean
$(MAKE) all
.PHONY: rebuild
# How to build a ROM
$(BINDIR)/%.$(ROMEXT) $(BINDIR)/%.sym $(BINDIR)/%.map: $(patsubst $(SRCDIR)/%.asm,$(OBJDIR)/%.o,$(SRCS))
@$(MKDIR) -p $(@D)
$(RGBASM) $(ASFLAGS) -o $(OBJDIR)/build_date.o $(SRCDIR)/res/build_date.asm
$(RGBLINK) $(LDFLAGS) -m $(BINDIR)/$*.map -n $(BINDIR)/$*.sym -o $(BINDIR)/$*.$(ROMEXT) $^ $(OBJDIR)/build_date.o \
&& $(RGBFIX) -v $(FIXFLAGS) $(BINDIR)/$*.$(ROMEXT)
# `.mk` files are auto-generated dependency lists of the "root" ASM files, to save a lot of hassle.
# Also add all obj dependencies to the dep file too, so Make knows to remake it
# Caution: some of these flags were added in RGBDS 0.4.0, using an earlier version WILL NOT WORK
# (and produce weird errors)
$(OBJDIR)/%.o $(DEPDIR)/%.mk: $(SRCDIR)/%.asm
@$(MKDIR) -p $(dir $(OBJDIR)/$* $(DEPDIR)/$*)
$(RGBASM) $(ASFLAGS) -M $(DEPDIR)/$*.mk -MG -MP -MQ $(OBJDIR)/$*.o -MQ $(DEPDIR)/$*.mk -o $(OBJDIR)/$*.o $<
ifneq ($(MAKECMDGOALS),clean)
-include $(patsubst $(SRCDIR)/%.asm,$(DEPDIR)/%.mk,$(SRCS))
endif

View File

@ -1,28 +1,5 @@
# ankano — an arkanoid clone for the game boy
written like a [real programmer][1], sloppily and with no discernable structure.
pure sharp lr35902 (gbz80) assembly.
work in progress, check back soon.
### made using:
* [hardware.inc][] — lots of hardware definitions to make life easier
* [rgbds-structs][] — structs!
* [gb-vwf][] — variable width font engine
* [gb-starter-kit][] — my project template is adapted from this
* [rgbds][] — for compiling, linking, etc.
* [sameboy][] — testing and debugging
* [everdrive-gb x5][] — for running it on real metal
[1]: https://www.ee.ryerson.ca/~elf/hack/realmen.html
[hardware.inc]: https://github.com/gbdev/hardware.inc
[rgbds-structs]: https://github.com/ISSOtm/rgbds-structs
[gb-vwf]: https://github.com/ISSOtm/gb-vwf
[gb-starter-kit]: https://github.com/ISSOtm/gb-starter-kit
[rgbds]: https://rgbds.gbdev.io/
[sameboy]: https://sameboy.github.io/
[everdrive-gb x5]: https://krikzz.com/store/home/47-everdrive-gb.html
[Migrated to sourcehut, view the code here](https://git.sr.ht/~nytpu/ankano)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,74 +0,0 @@
; Copyright (C) 2018-2020 Eldred Habert
;
; Modified by:
; Copyright (C) 2020 Alex Gentilucci
; - added vwf library
; - added charmap
; - remove sgb stuff
;
; This file is licensed under the terms of the MIT License.
; For more license details, see LICENSE or <https://mit-license.org/>.
; include the libraries
INCLUDE "hardware.inc/hardware.inc"
rev_Check_hardware_inc 3.0
INCLUDE "rgbds-structs/structs.asm"
;INCLUDE "gb-vwf/vwf.asm"
; a couple more hardware defines
NB_SPRITES equ 40
; I generally discourage the use of pseudo-instructions for a variety of reasons,
; but this one includes a label, and manually giving them different names is tedious.
wait_vram: MACRO
.waitVRAM\@
ldh a, [rSTAT]
and STATF_BUSY
jr nz, .waitVRAM\@
ENDM
; `ld b, X` followed by `ld c, Y` is wasteful (same with other reg pairs).
; This writes to both halves of the pair at once, without sacrificing readability
; Example usage: `lb bc, X, Y`
lb: MACRO
assert -128 <= (\2) && (\2) <= 255, "Second argument to `lb` must be 8-bit!"
assert -128 <= (\3) && (\3) <= 255, "Third argument to `lb` must be 8-bit!"
ld \1, ((\2) << 8) | (\3)
ENDM
; 64 bytes, should be sufficient for most purposes. If you're really starved on
; memory check your stack usage and consider setting this to 32 instead.
; 16 is probably not enough.
STACK_SIZE equ $40
; Use this to cause a crash.
; I don't recommend using this unless you want a condition:
; `call cc, Crash` is 3 bytes (`cc` being a condition); `error cc` is only 2 bytes
; This should help minimize the impact of error checking
error: MACRO
IF _NARG == 0
rst Crash
ELSE
assert Crash == $0038
; This assembles to XX FF (with XX being the `jr` instruction)
; If the condition is fulfilled, this jumps to the operand: $FF
; $FF encodes the instruction `rst $38`!
jr \1, @-1
ENDC
ENDM
newcharmap primary_font
CHARS equs "0123456789ABCDEFGHUJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz .!?:-"
CHAR = 0
REPT STRLEN("{CHARS}")
charmap STRSUB("{CHARS}", CHAR + 1, 1), CHAR
CHAR = CHAR + 1
ENDR

@ -1 +0,0 @@
Subproject commit 069a91674451b9aa2a4ba17dfd923740b37e64b3

@ -1 +0,0 @@
Subproject commit 3082d5d5e92652024d39a1e0033245227c5acbbc

@ -1 +0,0 @@
Subproject commit 0937be788a578b95f3272eb96431065aea2dc929

View File

@ -1,66 +0,0 @@
# This file contains project configuration
# Value that the ROM will be filled with
PADVALUE := 0xFF
## Header constants (passed to RGBFIX)
# ROM version (typically starting at 0 and incremented for each published version)
VERSION := 0
# 4-ASCII letter game ID
GAMEID := AKNO
# Game title, up to 11 ASCII chars
TITLE := ANKANO
# New licensee, 2 ASCII chars
# Homebrew games FTW!
LICENSEE := HB
# Old licensee, please set to 0x33 (required to get SGB compatibility)
OLDLIC := 0x33
# MBC type, tells which hardware is in the cart
# See https://gbdev.io/pandocs/#_0147-cartridge-type or consult any copy of Pan Docs
# If using no MBC, consider enabling `-t` below
MBC := 0x13
# ROM size is set automatically by RGBFIX
# Size of the on-board SRAM; MBC type should indicate the presence of RAM
# See https://gbdev.io/pandocs/#_0149-ram-size or consult any copy of Pan Docs
# Set this to 0 when using MBC2's built-in SRAM
SRAMSIZE := 0x03
# ROM name
ROMNAME := ankano
ROMEXT := gb
# Compilation parameters, uncomment to apply, comment to cancel
# "Sensible defaults" are included
# Disable automatic `nop` after `halt`
ASFLAGS += -h
# Export all labels
# This means they must all have unique names, but they will all show up in the .sym and .map files
# ASFLAGS += -E
# Game Boy Color compatible
# FIXFLAGS += -c
# Game Boy Color required
# FIXFLAGS += -C
# Super Game Boy compatible
# FIXFLAGS += -s
# Game Boy mode
LDFLAGS += -d
# No banked WRAM mode
LDFLAGS += -w
# 32k mode
# LDFLAGS += -t

View File

@ -1,578 +0,0 @@
; Copyright (C) 2018-2020 Eldred Habert
;
; This software is provided 'as-is', without any express or implied
; warranty. In no event will the authors be held liable for any damages
; arising from the use of this software.
;
; Permission is granted to anyone to use this software for any purpose,
; including commercial applications, and to alter it and redistribute it
; freely, subject to the following restrictions:
;
; 1. The origin of this software must not be misrepresented; you must not
; claim that you wrote the original software. If you use this software
; in a product, an acknowledgment in the product documentation would be
; appreciated but is not required.
; 2. Altered source versions must be plainly marked as such, and must not be
; misrepresented as being the original software.
; 3. This notice may not be removed or altered from any source distribution.
INCLUDE "defines.asm"
newcharmap crash_handler
CHARS equs "0123456789ABCDEF-GHIJKLMNOPQR:SUVWXYZabcdefghijklmnopqrTstuvwxyz! "
CHAR = 0
REPT STRLEN("{CHARS}")
charmap STRSUB("{CHARS}", CHAR + 1, 1), CHAR
CHAR = CHAR + 1
ENDR
SECTION "Crash handler", ROM0
HandleCrash::
; We will use VRAM as scratch, since we are going to overwrite it for
; screen output anyways. The thing is, we need to turn the LCD off
; *without* affecting flags... fun task, eh?
; Note: it's assumed that this was jumped to with IME off.
; Don't call this directly, use `rst Crash`.
ld [wCrashA], a ; We need to have at least one working register, so...
ldh a, [rIE] ; We're also going to overwrite this
ld [wCrashIE], a
ldh a, [rLCDC]
ld [wCrashLCDC], a
ld a, LCDCF_ON ; Make sure the LCD is turned on to avoid waiting infinitely
ldh [rLCDC], a
ld a, IEF_VBLANK
ld [rIE], a
ld a, 0 ; `xor a` would overwrite flags
ld [rIF], a ; No point in backing up that register, it's always changing
halt ; With interrupts disabled, this will exit when `IE & IF != 0`
nop ; Handle hardware bug if it becomes true *before* starting to execute the instruction (1-cycle window)
; We're now in VBlank! So we can now use VRAM as scratch for some cycles
ld a, 0
ldh [rLCDC], a ; Turn off LCD so VRAM can always be safely accessed
; Save regs
ld [vCrashSP], sp
ld sp, vCrashSP
push hl
push de
push bc
ld a, [wCrashA]
push af
; We need to have all the data in bank 0, but we can't guarantee we were there
ld a, [rVBK]
ld [vCrashVBK], a
bit 0, a
jr z, .bank0
; Oh noes. We need to copy the data across banks!
ld [vCrashDumpScreen], a ; Use this as a scratch byte
ld hl, vCrashAF
ld c, 5 * 2
.copyAcross
ld b, [hl]
xor a
ldh [rVBK], a
ld [hl], b
inc l ; inc hl
inc a ; ld a, 1
ldh [rVBK], a
dec c
jr nz, .copyAcross
ld a, [vCrashDumpScreen]
ld hl, rVBK
ld [hl], 0
.bank0
ld [vCrashVBK], a
; Kill sound for this screen
xor a
ldh [rNR52], a
inc a ; ld a, 1
ldh [rVBK], a
ld hl, vCrashDumpScreen
ld b, SCRN_Y_B
.writeAttrRow
xor a
ld c, SCRN_X_B + 1
rst MemsetSmall
ld a, l
add a, SCRN_VX_B - SCRN_X_B - 1
ld l, a
dec b
jr nz, .writeAttrRow
xor a
ldh [rVBK], a
; Load palettes
ld a, $03
ldh [rBGP], a
ld a, $80
ldh [rBCPS], a
xor a
ld c, LOW(rBCPD)
ldh [c], a
ldh [c], a
dec a ; ld a, $FF
REPT 3 * 2
ldh [c], a
ENDR
; TODO: SGB palettes?
ld a, SCRN_VY - SCRN_Y
ldh [rSCY], a
ld a, SCRN_VX - SCRN_X - 4
ldh [rSCX], a
; Copy 1bpp font, compressed using PB8 by PinoBatch
ld hl, .font
ld de, $9000
INCLUDE "res/crash_font.1bpp.pb8.size"
ld c, NB_PB8_BLOCKS
PURGE NB_PB8_BLOCKS
.pb8BlockLoop
; Register map for PB8 decompression
; HL: source address in boot ROM
; DE: destination address in VRAM
; A: Current literal value
; B: Repeat bits, terminated by 1000...
; C: Number of 8-byte blocks left in this block
; Source address in HL lets the repeat bits go straight to B,
; bypassing A and avoiding spilling registers to the stack.
ld b, [hl]
inc hl
; Shift a 1 into lower bit of shift value. Once this bit
; reaches the carry, B becomes 0 and the byte is over
scf
rl b
.pb8BitLoop
; If not a repeat, load a literal byte
jr c,.pb8Repeat
ld a, [hli]
.pb8Repeat
; Decompressed data uses colors 0 and 3, so write twice
ld [de], a
inc e ; inc de
ld [de], a
inc de
sla b
jr nz, .pb8BitLoop
dec c
jr nz, .pb8BlockLoop
; Copy the registers to the dump viewers
ld hl, vDumpHL
ld de, vCrashHL
ld c, 4
rst MemcpySmall
; We're now going to draw the screen, top to bottom
ld hl, vCrashDumpScreen
; First 3 lines of text
ld de, .header
ld b, 3
.writeHeaderLine
ld a, " "
ld [hli], a
ld c, 19
rst MemcpySmall
ld a, " "
ld [hli], a
ld a, l
add a, SCRN_VX_B - SCRN_X_B - 1
ld l, a
dec b
jr nz, .writeHeaderLine
; Blank line
ld a, " "
ld c, SCRN_X_B + 1
rst MemsetSmall
; AF and console model
ld l, LOW(vCrashDumpScreen.row4)
ld c, 4
rst MemcpySmall
pop bc
call .printHexBC
ld c, 8
rst MemcpySmall
ldh a, [hConsoleType]
call .printHexA
ld a, " "
ld [hli], a
ld [hli], a
ld [hli], a
; BC and DE
ld l, LOW(vCrashDumpScreen.row5)
ld c, 4
rst MemcpySmall
pop bc
call .printHexBC
ld c, 6
rst MemcpySmall
pop bc
call .printHexBC
ld a, " "
ld [hli], a
ld [hli], a
ld [hli], a
; Now, the two memory dumps
.writeDump
ld a, l
add a, SCRN_VX_B - SCRN_X_B - 1
ld l, a
ld c, 4
rst MemcpySmall
pop bc
push bc
call .printHexBC
ld de, .viewStr
ld c, 7
rst MemcpySmall
pop de
call .printDump
ld de, .spStr
bit 7, l
jr z, .writeDump
ld de, .hwRegsStrs
ld l, LOW(vCrashDumpScreen.row14)
ld c, 6
rst MemcpySmall
ld a, [wCrashLCDC]
call .printHexA
ld c, 4
rst MemcpySmall
ldh a, [rKEY1]
call .printHexA
ld c, 4
rst MemcpySmall
ld a, [wCrashIE]
call .printHexA
ld [hl], " "
ld l, LOW(vCrashDumpScreen.row15)
ld c, 7
rst MemcpySmall
.writeBank
ld a, " "
ld [hli], a
ld a, [de]
inc de
ld [hli], a
cp " "
jr z, .banksDone
ld a, [de]
inc de
ld c, a
ld a, [de]
inc de
ld b, a
ld a, [bc]
call .printHexA
jr .writeBank
.banksDone
ld l, LOW(vCrashDumpScreen.row16)
ld [hli], a
ld de, BuildDate
ld c, 19
.writeBuildDate
ld a, [de]
inc de
; Build date is in ASCII, translate it to our custom encoding
sub $30
cp 10
jr c, .digit
add a, $13
.digit
ld [hli], a
dec c
jr nz, .writeBuildDate
ld a, " "
ld [hli], a
ld l, LOW(vCrashDumpScreen.row17)
ld c, SCRN_X_B + 1
rst MemsetSmall
; Start displaying
ld a, LCDCF_ON | LCDCF_BG9C00 | LCDCF_BGON
ldh [rLCDC], a
xor a
ld [vWhichDump], a
ld [vHeldKeys], a ; Mark all keys as "previously held"
ld a, 30
ld [vUnlockCounter], a
.loop
; The code never lags, and IE is equal to IEF_VBLANK
xor a
ldh [rIF], a
halt
; Poll joypad
ld c, LOW(rP1)
ld a, P1F_GET_DPAD
call .poll
ld b, a
swap b
ld a, P1F_GET_BTN
call .poll
and b
ld b, a
ld a, $30
ldh [c], a
ld hl, vHeldKeys
ld a, [hl]
cpl
or b
ld c, a ; Buttons pressed just now
ld a, b
ld [hli], a
assert vHeldKeys + 1 == vUnlockCounter
ld a, [hli]
and a
jr z, .unlocked
ld a, b
and PADF_B | PADF_A
jr nz, .loop
dec hl
dec [hl]
jr .loop
.unlocked
assert vUnlockCounter + 1 == vWhichDump
bit PADB_B, c
ld a, [hl]
jr nz, .noDumpSwitch
xor 2
ld [hl], a
.noDumpSwitch
ld b, a
scf
adc a, l
ld l, a
adc a, h
sub l
ld h, a
; Process input, compute 16-bit offset to add to current addr
ld de, 0
bit PADB_START, c
jr nz, .noInc
inc de
.noInc
rlc c ; Check if Down was pressed
jr c, .noDown
ld a, [vHeldKeys]
rra ; Carry reset iff A held
sbc a, a
cpl
or $0F ; $FF if held, $0F otherwise
ld e, a
; ld d, 0
inc de
.noDown
rlc c ; Check if Up was pressed
jr c, .noUp
ld a, [vHeldKeys]
rra ; Carry reset iff A held
sbc a, a
and $F0 ; $00 if held, $F0 otherwise
ld e, a
ld d, $FF
.noUp
; Add offset to cur address, and store back
ld a, [hl]
add a, e
ld e, a
ld [hli], a
ld a, [hl]
adc a, d
ld d, a
ld [hl], a
; Compute pointer to "view:" number
rrc b ; 0 or 1
ld a, b
xor HIGH(vCrashDumpScreen.row5 + 47)
ld h, a
ld a, b
rrca ; 0 or $80
xor LOW(vCrashDumpScreen.row5 + 47)
ld l, a
call .printDump
; Now, let's highlight the selected dump region
ld a, [vWhichDump] ; 0 or 2
swap a ; 0 or 32
add a, 56
ld e, a
ld c, LOW(rBCPD)
ld a, $86
ldh [rBCPS], a
.wait
ldh a, [rLY]
cp e
jr nz, .wait
; CGB pal is more critical because it can only be written during Mode 0
ld a, LOW($294A)
ldh [c], a
ld a, HIGH($294A)
ldh [c], a
ld a, $43
ldh [rBGP], a
ld a, e
add a, 3 * 8
ld e, a
ld a, $86
ldh [rBCPS], a
.waitAfter
ldh a, [rLY]
sub e
jr nz, .waitAfter
dec a ; ld a, $FF
ldh [c], a
ldh [c], a
ld a, $03
ldh [rBGP], a
jp .loop
.poll
ldh [c], a
REPT 6
ldh a, [c]
ENDR
or $F0
ret
.printHexBC
call .printHexB
ld a, c
.printHexA
ld b, a
.printHexB
ld a, b
and $F0
swap a
ld [hli], a
ld a, b
and $0F
ld [hli], a
ret
.printDump
ld b, d
ld c, e
call .printHexBC
ld a, " "
ld [hli], a
ld [hli], a
ld a, e
sub 8
ld e, a
ld a, d
sbc 0
ld d, a
.writeDumpLine
ld a, l
add a, SCRN_VX_B - SCRN_X_B - 1
ld l, a
ld a, " "
ld [hli], a
.writeDumpWord
ld a, [de]
inc de
call .printHexA
ld a, [de]
inc de
call .printHexA
ld a, " "
ld [hli], a
bit 4, l
jr nz, .writeDumpWord
ld a, l
and $7F
jr nz, .writeDumpLine
ret
.font
INCBIN "res/crash_font.1bpp.pb8"
.header
; 0123456789ABCDEFGHI 19 chars
db "GAME CRASH!! Please"
db "send a clear pic of"
db "this screen to devs"
db " AF:"
db " Model:"
db " BC:"
db " DE:"
db " HL:"
.viewStr
db " View:"
.spStr
db " SP:"
.hwRegsStrs
db " LCDC:"
db " K1:"
db " IE:"
db " Bank:", "R", LOW(hCurROMBank), HIGH(hCurROMBank), "V", LOW(vCrashVBK), HIGH(vCrashVBK), "W", LOW(rSVBK), HIGH(rSVBK), " "
; This is made to be as small as possible, since the footprint of this should be minimal
; Unfortunately, I don't think I can do better
SECTION "Crash handler scratch", WRAM0
wCrashA: db ; We need at least one working register, and A allows accessing memory
wCrashIE: db
wCrashLCDC: db
SECTION UNION "9C00 tilemap", VRAM[$9C00],BANK[0]
; Put the crash dump screen at the bottom-right of the 9C00 tilemap, since that tends to be unused space
ds SCRN_VX_B * (SCRN_VY_B - SCRN_Y_B - 2) ; 2 rows reserved as scratch space
ds SCRN_X_B ; Try not to overwrite the window area
ds 2 * 1 ; Free stack entries (we spill into the above by 1 entry, though :/)
; These are the initial values of the registers
; They are popped off the stack when printed, freeing up stack space
vCrashAF: dw
vCrashBC: dw
vCrashDE: dw
vCrashHL: dw
vCrashSP: dw
ds SCRN_X_B
vHeldKeys: db ; Keys held on previous frame
vUnlockCounter: db ; How many frames until dumps are "unlocked"
vWhichDump: db
vDumpHL: dw
vDumpSP: dw
vCrashVBK: db
ds 4 ; Unused
ds SCRN_VX_B - SCRN_X_B - 1
vCrashDumpScreen:
ds SCRN_X_B + 1
ROW = 0
REPT SCRN_Y_B - 1
ROW = ROW + 1
ROW_LABEL equs ".row{d:ROW}"
ds SCRN_VX_B - SCRN_X_B - 1
ROW_LABEL
ds SCRN_X_B + 1
PURGE ROW_LABEL
ENDR

View File

@ -1,149 +0,0 @@
; Copyright (C) 2020 nytpu
; This file incorporates code from:
; Copyright (C) 2018-2020 Eldred Habert
;
; This file is licensed under the terms of the MIT License.
; For more license details, see LICENSE or <https://mit-license.org/>.
INCLUDE "defines.asm"
SECTION "Header", ROM0[$100]
; the rom's entry point
; 4 bytes available, sub d8 takes 2, jr r8 takes 2
sub $11 ; this helps check if we're on cgb more efficiently
jr EntryPoint
; the header itself. allocate blank space, as it's taken care of by rgbfix.
ds $150 - @, 0
EntryPoint:
; in case there's anything that should be done on boot but not on reset
ld [hConsoleType], a
Reset::
di ; disable interrupts while we set up
; kill sound
xor a
ldh [rNR52], a
; wait for vblank and turn lcd off
.waitVBlank
ldh a, [rLY]
cp SCRN_Y
jr c, .waitVBlank
xor a
ldh [rLCDC], a
ld sp, wStackBottom
; set up oam dma function in hram
ld a, BANK(OAMDMA)
; no need to write bank number to hram var, interrupts aren't active
ld [rROMB0], a
ld hl, OAMDMA
lb bc, OAMDMA.end - OAMDMA, LOW(hOAMDMA)
.copyOAMDMA
ld a, [hli]
ldh [c], a
inc c
dec b
jr nz, .copyOAMDMA
; set all palettes
ld a, %11100100
ld [rBGP], a
ld [OAMF_PAL0], a
ld [OAMF_PAL1], a
; You will also need to reset your handlers' variables below
; I recommend reading through, understanding, and customizing this file
; in its entirety anyways. This whole file is the "global" game init,
; so it's strongly tied to your own game.
; I don't recommend clearing large amounts of RAM, nor to init things
; here that can be initialized later.
; reset variables necessary for the vblank handler to function correctly
xor a
ldh [hVBlankFlag], a
ldh [hOAMHigh], a
ldh [hCanSoftReset], a
dec a ; ld a, $FF
ldh [hHeldKeys], a
; load the rom bank for the intro animation
; important to do it before enabling interrupts
ld a, BANK(Intro)
ldh [hCurROMBank], a
ld [rROMB0], a
; select interrupts enabled initially
ld a, IEF_VBLANK
ldh [rIE], a
xor a
ei ; only takes effect after the following instruction
ldh [rIF], a ; clears "accumulated" interrupts
; init shadow regs
; a is still 0 from previous section, but may need to uncomment this later
; xor a
ldh [hSCY], a
ldh [hSCX], a
ld a, LCDCF_ON | LCDCF_BGON
ldh [hLCDC], a
; And turn the LCD on!
ldh [rLCDC], a
; clear oam, so it doesn't display garbage
; this will get committed to hardware oam after the end of the first
; frame, but the hardware doesn't display it, so that's fine.
ld hl, wShadowOAM
ld c, NB_SPRITES * 4
xor a
rst MemsetSmall
ld a, h ; ld a, HIGH(wShadowOAM)
ldh [hOAMHigh], a
; `Intro`'s bank has already been loaded earlier
jp Intro
SECTION "OAM DMA routine", ROMX
; oam dma prevents access to most memory, but never hram.
; this starts an oam dma transfer, then waits for it to complete.
; it gets copied to hram and is called there from the vblank handler
OAMDMA:
ldh [rDMA], a
ld a, NB_SPRITES
.wait
dec a
jr nz, .wait
ret
.end
SECTION "Global vars", HRAM
; copy of the currently-loaded rom bank, so the handlers can restore it
; make sure to always write to it before writing to romb0
hCurROMBank:: db
; 0 if cgb (including dmg mode and gba), non-zero for other models
hConsoleType:: db
; useful for storing temporary data if you run out of registers
hTempByte:: db
SECTION "OAM DMA", HRAM
hOAMDMA::
ds OAMDMA.end - OAMDMA
SECTION UNION "Shadow OAM", WRAM0,ALIGN[8]
wShadowOAM::
ds NB_SPRITES * 4
; This ensures that the stack is at the very end of WRAM
SECTION "Stack", WRAM0[$E000 - STACK_SIZE]
ds STACK_SIZE
wStackBottom:

View File

@ -1,13 +0,0 @@
; Copyright (C) 2020 nytpu
; This file is licensed under the terms of the MIT License.
; For more license details, see LICENSE or <https://mit-license.org/>.
INCLUDE "defines.asm"
SECTION "Intro", ROMX
; render the intro scene
Intro::
; TODO: animate intro logo
; TODO: create start screen
jp EnterMainLoop

View File

@ -1,73 +0,0 @@
; Copyright (C) 2020 nytpu
; This file is licensed under the terms of the MIT License.
; For more license details, see LICENSE or <https://mit-license.org/>.
INCLUDE "defines.asm"
SECTION "Game Loop", ROM0
EnterMainLoop::
di
; wait for vblank and turn lcd off
.waitVBlank
ldh a, [rLY]
cp SCRN_Y
jr c, .waitVBlank
xor a
ldh [rLCDC], a ; will burn screen if not done during vblank
; loading in main gameplay tiles and such
ld a, BANK(GameTiles)
ldh [hCurROMBank], a
ld [rROMB0], a
ld de, GameTiles.bgTiles
ld hl, $9000
INCLUDE "res/game_map.2bpp.pb16.size"
ld bc, NB_PB16_BLOCKS
PURGE NB_PB16_BLOCKS
call pb16_unpack_block
ld de, GameTiles.bgTileMap
ld hl, $9800
ld bc, GameTiles.bgTileMapEnd - GameTiles.bgTileMap
call LCDMemcpy
ld de, GameTiles.spriteTiles
ld hl, $8000
INCLUDE "res/spritemap.2bpp.pb16.size"
ld b, NB_PB16_BLOCKS
PURGE NB_PB16_BLOCKS
call pb16_unpack_block
ld a, LCDCF_ON | LCDCF_BGON | LCDCF_BG9800 | LCDCF_BG8800
ldh [rLCDC], a
ei
; soft reset during gameplay is fine
ld a, 1
ldh [hCanSoftReset], a
MainLoop:
ld hl, hHeldKeys
bit 0, [hl]
jr z, .notA
ld a, %00011011
ld [rBGP], a
.notA
ld a, %11100100
ld [hBGP], a
.keypadDone
; if there's any more time before vblank
rst WaitVBlank
jr MainLoop
SECTION "Gameplay Tiles", ROMX
GameTiles:
.bgTiles
INCBIN "res/game_map.2bpp.pb16"
.bgTileMap
INCBIN "res/game_map.2bpp.tilemap"
.bgTileMapEnd
.spriteTiles
INCBIN "res/spritemap.2bpp.pb16"

View File

@ -1,151 +0,0 @@
; Copyright (C) 2018-2020 Eldred Habert
;
; This software is provided 'as-is', without any express or implied
; warranty. In no event will the authors be held liable for any damages
; arising from the use of this software.
;
; Permission is granted to anyone to use this software for any purpose,
; including commercial applications, and to alter it and redistribute it
; freely, subject to the following restrictions:
;
; 1. The origin of this software must not be misrepresented; you must not
; claim that you wrote the original software. If you use this software
; in a product, an acknowledgment in the product documentation would be
; appreciated but is not required.
; 2. Altered source versions must be plainly marked as such, and must not be
; misrepresented as being the original software.
; 3. This notice may not be removed or altered from any source distribution.
INCLUDE "defines.asm"
INCLUDE "res/rand.asm"
EXPORT randstate ; Defined in the above, exported here to avoid touching the file
SECTION "LCDMemsetSmallFromB", ROM0
; Writes a value to all bytes in an area of memory
; Works when the destination is in VRAM, even while the LCD is on
; @param hl Beginning of area to fill
; @param c Amount of bytes to write (0 causes 256 bytes to be written)
; @param a Value to write
; @return c 0
; @return hl Pointer to the byte after the last written one
; @return b Equal to a
; @return f Z set, C reset
LCDMemsetSmall::
ld b, a
; Writes a value to all bytes in an area of memory
; Works when the destination is in VRAM, even while the LCD is on
; Protip: you may want to use `lb bc,` to set both B and C at the same time
; @param hl Beginning of area to fill
; @param c Amount of bytes to write (0 causes 256 bytes to be written)
; @param b Value to write
; @return c 0
; @return hl Pointer to the byte after the last written one
; @return b Equal to a
; @return f Z set, C reset
LCDMemsetSmallFromB::
wait_vram
ld a, b
ld [hli], a
dec c
jr nz, LCDMemsetSmallFromB
ret
SECTION "LCDMemset", ROM0
; Writes a value to all bytes in an area of memory
; Works when the destination is in VRAM, even while the LCD is on
; @param hl Beginning of area to fill
; @param bc Amount of bytes to write (0 causes 65536 bytes to be written)
; @param a Value to write
; @return bc 0
; @return hl Pointer to the byte after the last written one
; @return d Equal to parameter passed in a
; @return a 0
; @return f Z set, C reset
LCDMemset::
ld d, a
; Writes a value to all bytes in an area of memory
; Works when the destination is in VRAM, even while the LCD is on
; @param hl Beginning of area to fill
; @param bc Amount of bytes to write (0 causes 65536 bytes to be written)
; @param d Value to write
; @return bc 0
; @return hl Pointer to the byte after the last written one
; @return a 0
; @return f Z set, C reset
LCDMemsetFromD::
wait_vram
ld a, d
ld [hli], a
dec bc
ld a, b
or c
jr nz, LCDMemsetFromD
ret
SECTION "LCDMemcpySmall", ROM0
; Copies a block of memory somewhere else
; Works when the source or destination is in VRAM, even while the LCD is on
; @param de Pointer to beginning of block to copy
; @param hl Pointer to where to copy (bytes will be written from there onwards)
; @param c Amount of bytes to copy (0 causes 256 bytes to be copied)
; @return de Pointer to byte after last copied one
; @return hl Pointer to byte after last written one
; @return c 0
; @return a Last byte copied
; @return f Z set, C reset
LCDMemcpySmall::
wait_vram
ld a, [de]
ld [hli], a
inc de
dec c
jr nz, LCDMemcpySmall
ret
SECTION "LCDMemcpy", ROM0
; Copies a block of memory somewhere else
; Works when the source or destination is in VRAM, even while the LCD is on
; @param de Pointer to beginning of block to copy
; @param hl Pointer to where to copy (bytes will be written from there onwards)
; @param bc Amount of bytes to copy (0 causes 65536 bytes to be copied)
; @return de Pointer to byte after last copied one
; @return hl Pointer to byte after last written one
; @return bc 0
; @return a 0
; @return f Z set, C reset
LCDMemcpy::
wait_vram
ld a, [de]
ld [hli], a
inc de
dec bc
ld a, b
or c
jr nz, LCDMemcpy
ret
SECTION "Memcpy", ROM0
; Copies a block of memory somewhere else
; @param de Pointer to beginning of block to copy
; @param hl Pointer to where to copy (bytes will be written from there onwards)
; @param bc Amount of bytes to copy (0 causes 65536 bytes to be copied)
; @return de Pointer to byte after last copied one
; @return hl Pointer to byte after last written one
; @return bc 0
; @return a 0
; @return f Z set, C reset
Memcpy::
ld a, [de]
ld [hli], a
inc de
dec bc
ld a, b
or c
jr nz, Memcpy
ret

View File

@ -1,11 +0,0 @@
; Copyright (C) 2018-2020 Eldred Habert
;
; This file is licensed under the terms of the MIT License.
; For more license details, see LICENSE or <https://mit-license.org/>.
SECTION "Build date", ROM0
db "Built "
BuildDate::
db __ISO_8601_UTC__
db 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

View File

@ -1,66 +0,0 @@
; Pseudorandom number generator
;
; Copyright 2018 Damian Yerrick
;
; This software is provided 'as-is', without any express or implied
; warranty. In no event will the authors be held liable for any damages
; arising from the use of this software.
;
; Permission is granted to anyone to use this software for any purpose,
; including commercial applications, and to alter it and redistribute it
; freely, subject to the following restrictions:
;
; 1. The origin of this software must not be misrepresented; you must not
; claim that you wrote the original software. If you use this software
; in a product, an acknowledgment in the product documentation would be
; appreciated but is not required.
; 2. Altered source versions must be plainly marked as such, and must not be
; misrepresented as being the original software.
; 3. This notice may not be removed or altered from any source distribution.
section "rand_ram",WRAM0
randstate: ds 4
section "rand",ROM0
;;
; Generates a pseudorandom 16-bit integer in BC
; using the LCG formula from cc65 rand():
; x[i + 1] = x[i] * 0x01010101 + 0x31415927
; @return A=B=state bits 31-24 (which have the best entropy),
; C=state bits 23-16, DHL trashed
rand::
; Load bits 31-8 of the current value to BCA
ld hl,randstate+3
ld a,[hl-]
ld b,a
ld a,[hl-]
ld c,a
ld a,[hl-] ; skip D; thanks ISSOtm for the idea
; Used to load bits 7-0 to E. Reading [HL] each time turned out
; no slower and saved 1 byte.
; Multiply by 0x01010101
add [hl]
ld d,a
adc c
ld c,a
adc b
ld b,a
; Add 0x31415927 and write back
ld a,[hl]
add $27
ld [hl+],a
ld a,d
adc $59
ld [hl+],a
ld a,c
adc $41
ld [hl+],a
ld c,a
ld a,b
adc $31
ld [hl],a
ld b,a
ret

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 B

View File

@ -1,92 +0,0 @@
; PB16 decompression for Game Boy
; Copyright 2018 Damian Yerrick
;
; This software is provided 'as-is', without any express or implied
; warranty. In no event will the authors be held liable for any damages
; arising from the use of this software.
;
; Permission is granted to anyone to use this software for any purpose,
; including commercial applications, and to alter it and redistribute it
; freely, subject to the following restrictions:
;
; 1. The origin of this software must not be misrepresented; you must not
; claim that you wrote the original software. If you use this software
; in a product, an acknowledgment in the product documentation would be
; appreciated but is not required.
; 2. Altered source versions must be plainly marked as such, and must not be
; misrepresented as being the original software.
; 3. This notice may not be removed or altered from any source distribution.
;
; This software has been modified by Eldred Habert (ISSOtm):
; - Removal of .inc file
; - Different variable allocation
section "pb16 temp byte", HRAM
pb16_byte0: db
section "pb16", ROM0
; The PB16 format is a starting point toward efficient RLE image
; codecs on Game Boy and Super NES.
;
; 0: Load a literal byte
; 1: Repeat from 2 bytes ago
pb16_unpack_packet:
; Read first bit of control byte. Treat B as a ring counter with
; a 1 bit as the sentinel. Once the 1 bit reaches carry, B will
; become 0, meaning the 8-byte packet is complete.
ld a,[de]
inc de
scf
rla
ld b,a
.byteloop:
; If the bit from the control byte is clear, plane 0 is is literal
jr nc,.p0_is_literal
ldh a,[pb16_byte0]
jr .have_p0
.p0_is_literal:
ld a,[de]
inc de
ldh [pb16_byte0],a
.have_p0:
ld [hl+],a
; Read next bit. If it's clear, plane 1 is is literal.
ld a,c
sla b
jr c,.have_p1
.p1_is_copy:
ld a,[de]
inc de
ld c,a
.have_p1:
ld [hl+],a
; Read next bit of control byte
sla b
jr nz,.byteloop
ret
;;
; Unpacks 2*B packets from DE to HL, producing 8 bytes per packet.
; About 127 cycles (2 scanlines) per 8-byte packet; filling CHR RAM
; thus takes (6144/8)*127 = about 97536 cycles or 93 ms
pb16_unpack_block::
; Prefill with zeroes
xor a
ldh [pb16_byte0],a
ld c,a
.packetloop:
push bc
call pb16_unpack_packet
call pb16_unpack_packet
ld a,c
pop bc
ld c,a
dec b
jr nz,.packetloop
ret

View File

@ -1,268 +0,0 @@
; Copyright (C) 2018-2020 Eldred Habert
;
; This software is provided 'as-is', without any express or implied
; warranty. In no event will the authors be held liable for any damages
; arising from the use of this software.
;
; Permission is granted to anyone to use this software for any purpose,
; including commercial applications, and to alter it and redistribute it
; freely, subject to the following restrictions:
;
; 1. The origin of this software must not be misrepresented; you must not
; claim that you wrote the original software. If you use this software
; in a product, an acknowledgment in the product documentation would be
; appreciated but is not required.
; 2. Altered source versions must be plainly marked as such, and must not be
; misrepresented as being the original software.
; 3. This notice may not be removed or altered from any source distribution.
INCLUDE "defines.asm"
SECTION "Vectors", ROM0[0]
NULL::
; This traps jumps to $0000, which is a common "default" pointer
; $FFFF is another one, but reads rIE as the instruction byte
; Thus, we put two `nop`s that may serve as operands, before soft-crashing
; The operand will always be 0, so even jumps will work fine. Nice!
nop
nop
rst Crash
ds $08 - @ ; 5 free bytes
; Waits for the next VBlank beginning
; Requires the VBlank handler to be able to trigger, otherwise will loop infinitely
; This means IME should be set, the VBlank interrupt should be selected in IE,
; and the LCD should be turned on.
; WARNING: Be careful if calling this with IME reset (`di`), if this was compiled
; with the `-h` flag, then a hardware bug is very likely to cause this routine to
; go horribly wrong.
; Note: the VBlank handler recognizes being called from this function (through `hVBlankFlag`),
; and does not try to save registers if so. To be safe, consider all registers to be destroyed.
; @destroy Possibly every register. The VBlank handler stops preserving anything when executed from this function
WaitVBlank::
ld a, 1
ldh [hVBlankFlag], a
.wait
halt
jr .wait
ds $10 - 1 - @ ; 0 free bytes
MemsetLoop:
ld a, d
; You probably don't want to use this for writing to VRAM while the LCD is on. See LCDMemset.
Memset::
ld [hli], a
ld d, a
dec bc
ld a, b
or c
jr nz, MemsetLoop
ret
ds $18 - @ ; 0 free bytes
MemcpySmall::
ld a, [de]
ld [hli], a
inc de
dec c
jr nz, MemcpySmall
ret
ds $20 - @ ; 1 free byte
MemsetSmall::
ld [hli], a
dec c
jr nz, MemsetSmall
ret
ds $28 - 3 - @ ; 0 free bytes
; Dereferences `hl` and jumps there
; All other registers are passed to the called code intact, except Z is reset
; Soft-crashes if the jump target is in RAM
; @param hl Pointer to an address to jump to
JumpToPtr::
ld a, [hli]
ld h, [hl]
ld l, a
; Jump to some address
; All registers are passed to the called code intact, except Z is reset
; (`jp CallHL` is equivalent to `jp hl`, but with the extra error checking on top)
; Soft-crashes if attempting to jump to RAM
; @param hl The address of the code to jump to
CallHL::
bit 7, h
error nz
jp hl
ds $30 - @ ; 3 free bytes
; Jumps to some address
; All registers are passed to the target code intact, except Z is reset
; (`jp CallDE` would be equivalent to `jp de` if that instruction existed)
; Soft-crashes if attempting to jump to RAM
; @param de The address of the code to jump to
CallDE::
bit 7, d
push de
ret z ; No jumping to RAM, boy!
rst Crash
ds $38 - @ ; 3 free bytes
; Perform a soft-crash. Prints debug info on-screen
Crash::
di ; Doing this as soon as possible to avoid interrupts messing up
jp HandleCrash
ds $40 - @
; VBlank handler
push af
ldh a, [hLCDC]
ldh [rLCDC], a
jp VBlankHandler
ds $48 - @
; STAT handler
reti
ds $50 - @
; Timer handler
reti
ds $58 - @
; Serial handler
reti
ds $60 - @
; Joypad handler (useless)
reti
SECTION "VBlank handler", ROM0
VBlankHandler:
ldh a, [hSCY]
ldh [rSCY], a
ldh a, [hSCX]
ldh [rSCX], a
ldh a, [hBGP]
ldh [rBGP], a
ldh a, [hOBP0]
ldh [rOBP0], a
ldh a, [hOBP1]
ldh [rOBP1], a
; OAM DMA can occur late in the handler, because it will still work even
; outside of VBlank. Sprites just will not appear on the scanline(s)
; during which it's running.
ldh a, [hOAMHigh]
and a
jr z, .noOAMTransfer
call hOAMDMA
xor a
ldh [hOAMHigh], a
.noOAMTransfer
; Put all operations that cannot be interrupted above this line
; For example, OAM DMA (can't jump to ROM in the middle of it),
; VRAM accesses (can't screw up timing), etc
ei
ldh a, [hVBlankFlag]
and a
jr z, .lagFrame
xor a
ldh [hVBlankFlag], a
ld c, LOW(rP1)
ld a, $20 ; Select D-pad
ldh [c], a
REPT 6
ldh a, [c]
ENDR
or $F0 ; Set 4 upper bits (give them consistency)
ld b, a
; Filter impossible D-pad combinations
and $0C ; Filter only Down and Up
ld a, b
jr nz, .notUpAndDown
or $0C ; If both are pressed, "unpress" them
ld b, a
.notUpAndDown
and $03 ; Filter only Left and Right
jr nz, .notLeftAndRight
; If both are pressed, "unpress" them
inc b
inc b
inc b
.notLeftAndRight
swap b ; Put D-pad buttons in upper nibble
ld a, $10 ; Select buttons
ldh [c], a
REPT 6
ldh a, [c]
ENDR
; On SsAB held, soft-reset
and $0F
jr z, .perhapsReset
.dontReset
or $F0 ; Set 4 upper bits
xor b ; Mix with D-pad bits, and invert all bits (such that pressed=1) thanks to "or $F0"
ld b, a
; Release joypad
ld a, $30
ldh [c], a
ldh a, [hHeldKeys]
cpl
and b
ldh [hPressedKeys], a
ld a, b
ldh [hHeldKeys], a
pop af ; Pop off return address as well to exit infinite loop
.lagFrame
pop af
ret
.perhapsReset
ldh a, [hCanSoftReset]
and a
jr z, .dontReset
jp Reset
SECTION "VBlank HRAM", HRAM
; DO NOT TOUCH THIS
; When this flag is set, the VBlank handler will assume the caller is `WaitVBlank`,
; and attempt to exit it. You don't want that to happen outside of that function.
hVBlankFlag:: db
; High byte of the address of the OAM buffer to use.
; When this is non-zero, the VBlank handler will write that value to rDMA, and
; reset it.
hOAMHigh:: db
; Shadow registers for a bunch of hardware regs.
; Writing to these causes them to take effect more or less immediately, so these
; are copied to the hardware regs by the VBlank handler, taking effect between frames.
; They also come in handy for "resetting" them if modifying them mid-frame for raster FX.
hLCDC:: db
hSCY:: db
hSCX:: db
hBGP:: db
hOBP0:: db
hOBP1:: db
; Keys that are currently being held, and that became held just this frame, respectively.
; Each bit represents a button, with that bit set == button pressed
; Button order: Down, Up, Left, Right, Start, select, B, A
; U+D and L+R are filtered out by software, so they will never happen
hHeldKeys:: db
hPressedKeys:: db
; If this is 0, pressing SsAB at the same time will not reset the game
hCanSoftReset:: db

View File

@ -1,76 +0,0 @@
#!/usr/bin/env python
"""
PB16 encoder
Copyright 2018 Damian Yerrick
[License: zlib]
PB16 can be thought of as either of two things:
- Run-length encoding (RLE) of two interleaved streams, with
unary-coded run lengths
- LZSS with a fixed distance of 2 and a fixed copy length of 1
Each packet represents 8 bytes of uncompressed data. The bits
of the first byte in a packet, ordered from MSB to LSB, encode
which of the following eight bytes repeat the byte 2 bytes back.
A 0 means a literal byte follows; a 1 means a repeat.
It's similar to the PB8 codec that I've used for NES CHR data,
adapted to the interleaving of Game Boy and Super NES CHR data.
"""
import itertools
import sys
import argparse
def ichunk(data, count):
"""Turn an iterable into lists of a fixed length."""
data = iter(data)
while True:
b = list(itertools.islice(data, count))
if len(b) == 0: break
yield b
def pb16(data):
"""Compress an iterable of bytes into a generator of PB16 packets."""
prev = [0, 0]
for unco in ichunk(data, 8):
# Pad the chunk to a multiple of 2 then to 8 bytes
if len(unco) < 8:
if len(unco) == 1:
unco.append(prev[1])
elif len(unco) % 2:
unco.append(unco[-2])
unco.extend(unco[-2:]*(8 - len(unco)))
packet = bytearray(1)
for i, value in enumerate(unco):
if value == prev[i % 2]:
packet[0] |= 0x80 >> i
else:
packet.append(value)
prev[i % 2] = value
yield packet
def parse_argv(argv):
p = argparse.ArgumentParser()
p.add_argument("infile")
p.add_argument("outfile")
return p.parse_args(argv[1:])
def main(argv=None):
args = parse_argv(argv or sys.argv)
with open(args.infile, "rb") as infp:
data = infp.read()
with open(args.outfile, "wb") as outfp:
outfp.writelines(pb16(data))
def test():
tests = [
()
]
s = b"ABAHBHCHCECEFEFE"
print(b''.join(pb16(s)).hex())
if __name__=='__main__':
main()
## test()

View File

@ -1,68 +0,0 @@
#!/usr/bin/env python
"""
PB8 encoder
Copyright 2019 Damian Yerrick
[License: zlib]
PB8 can be thought of as either of two things:
- Run-length encoding (RLE) of a stream, with unary-coded run lengths
- LZSS with a fixed distance of 1 and a fixed copy length of 1
Each packet represents 8 bytes of uncompressed data. The bits
of the first byte in a packet, ordered from MSB to LSB, encode
which of the following eight bytes repeat the previous byte.
A 0 means a literal byte follows; a 1 means a repeat.
"""
import itertools
import sys
import argparse
def ichunk(data, count):
"""Turn an iterable into lists of a fixed length."""
data = iter(data)
while True:
b = list(itertools.islice(data, count))
if len(b) == 0: break
yield b
def pb8(data):
"""Compress an iterable of bytes into a generator of PB8 packets."""
prev = 0
for unco in ichunk(data, 8):
# Pad the chunk to a multiple of 8 bytes
if len(unco) < 8:
unco.extend(unco[-1:]*(8 - len(unco)))
packet = bytearray(1)
for i, value in enumerate(unco):
if value == prev:
packet[0] |= 0x80 >> i
else:
packet.append(value)
prev = value
yield packet
def parse_argv(argv):
p = argparse.ArgumentParser()
p.add_argument("infile")
p.add_argument("outfile")
return p.parse_args(argv[1:])
def main(argv=None):
args = parse_argv(argv or sys.argv)
with open(args.infile, "rb") as infp:
data = infp.read()
with open(args.outfile, "wb") as outfp:
outfp.writelines(pb8(data))
def test():
tests = [
()
]
s = b"ABAHBHCHCECEFEFE"
print(b''.join(pb8(s)).hex())
if __name__=='__main__':
main()
## test()