Skip to content

Instantly share code, notes, and snippets.

@deadprogram
Last active September 21, 2019 16:12
Show Gist options
  • Save deadprogram/b8ef4d1e51c88ec23c92e197d291b625 to your computer and use it in GitHub Desktop.
Save deadprogram/b8ef4d1e51c88ec23c92e197d291b625 to your computer and use it in GitHub Desktop.
// +build gameboyadvance
package machine
import (
"image/color"
"runtime/volatile"
"unsafe"
)
var (
// IO maps the I/O Peripherals.
IO = (*IORegs)(unsafe.Pointer(uintptr(0x04000000)))
)
// IOMap is the memory mapping of the IO Registers.
//
// Full IO Map:
// https://www.akkit.org/info/gbatek.htm#gbaiomap
type IORegs struct {
LCD LCDRegs
Sound SoundRegs
_ [0x100 - 0x0B0]byte // DMA
Timer [4]Timer // Timers
_ [0x10]byte // Unused
_ [0x130 - 0x120]byte // Serial 1
Keypad Keypad
_ [0x200 - 0x134]byte // Serial 2
Int InterruptRegs
}
type LCDRegs struct {
DISPCNT volatile.Register16 // R/W - LCD Control
_ volatile.Register16 // R/W - Undocumented - Green Swap
DISPSTAT volatile.Register16 // R/W - General LCD Status (STAT,LYC)
VCOUNT volatile.Register16 // R - Vertical Counter (LY)
BG0CNT volatile.Register16 // R/W - BG0 Control
BG1CNT volatile.Register16 // R/W - BG1 Control
BG2CNT volatile.Register16 // R/W - BG2 Control
BG3CNT volatile.Register16 // R/W - BG3 Control
BG0HOFS volatile.Register16 // W - BG0 X-Offset
BG0VOFS volatile.Register16 // W - BG0 Y-Offset
BG1HOFS volatile.Register16 // W - BG1 X-Offset
BG1VOFS volatile.Register16 // W - BG1 Y-Offset
BG2HOFS volatile.Register16 // W - BG2 X-Offset
BG2VOFS volatile.Register16 // W - BG2 Y-Offset
BG3HOFS volatile.Register16 // W - BG3 X-Offset
BG3VOFS volatile.Register16 // W - BG3 Y-Offset
BG2PA volatile.Register16 // W - BG2 Rotation/Scaling Parameter A (dx)
BG2PB volatile.Register16 // W - BG2 Rotation/Scaling Parameter B (dmx)
BG2PC volatile.Register16 // W - BG2 Rotation/Scaling Parameter C (dy)
BG2PD volatile.Register16 // W - BG2 Rotation/Scaling Parameter D (dmy)
BG2X volatile.Register32 // W - BG2 Reference Point X-Coordinate
BG2Y volatile.Register32 // W - BG2 Reference Point Y-Coordinate
BG3PA volatile.Register16 // W - BG3 Rotation/Scaling Parameter A (dx)
BG3PB volatile.Register16 // W - BG3 Rotation/Scaling Parameter B (dmx)
BG3PC volatile.Register16 // W - BG3 Rotation/Scaling Parameter C (dy)
BG3PD volatile.Register16 // W - BG3 Rotation/Scaling Parameter D (dmy)
BG3X volatile.Register32 // W - BG3 Reference Point X-Coordinate
BG3Y volatile.Register32 // W - BG3 Reference Point Y-Coordinate
WIN0H volatile.Register16 // W - Window 0 Horizontal Dimensions
WIN1H volatile.Register16 // W - Window 1 Horizontal Dimensions
WIN0V volatile.Register16 // W - Window 0 Vertical Dimensions
WIN1V volatile.Register16 // W - Window 1 Vertical Dimensions
WININ volatile.Register16 // R/W - Inside of Window 0 and 1
WINOUT volatile.Register16 // R/W - Inside of OBJ Window & Outside of Windows
MOSAIC volatile.Register16 // W - Mosaic Size
_ volatile.Register16 // - - Not used
BLDCNT volatile.Register16 // R/W - Color Special Effects Selection
BLDALPHA volatile.Register16 // W - Alpha Blending Coefficients
BLDY volatile.Register16 // W - Brightness (Fade-In/Out) Coefficient
_ volatile.Register32 // - - Not used
_ volatile.Register32 // - - Not used
}
// DISPCNT Register Constants
const (
DISPCNT_MODE1 = 1
DISPCNT_MODE2 = 2
DISPCNT_MODE3 = 3
DISPCNT_MODE4 = 4
DISPCNT_MODE5 = 5
DISPCNT_FRAME_SELECT = 1 << 4
DISPCNT_HBLANK_INTERVAL_FREE = 1 << 5
DISPCNT_OBJ_VRAM_MAP_1D = 1 << 6
DISPCNT_FORCED_BLANK = 1 << 7
DISPCNT_DISPLAY_BG0 = 1 << 8
DISPCNT_DISPLAY_BG1 = 1 << 9
DISPCNT_DISPLAY_BG2 = 1 << 10
DISPCNT_DISPLAY_BG3 = 1 << 11
DISPCNT_DISPLAY_OBJ = 1 << 12
DISPCNT_MODE_MASK = 0x7
DISPCNT_BG_MASK = 0xf << 8
)
// DISPSTAT Register Constants
const (
DISPSTAT_VBLANK = 1 << iota // V-Blank flag (Read only) (1=VBlank) (set in line 160..226; not 227)
DISPSTAT_HBLANK // H-Blank flag (Read only) (1=HBlank) (toggled in all lines, 0..227)
DISPSTAT_VCOUNTER // V-Counter flag (Read only) (1=Match) (set in selected line)
DISPSTAT_VBLANK_IRQ // V-Blank IRQ Enable (1=Enable)
DISPSTAT_HBLANK_IRQ // H-Blank IRQ Enable (1=Enable)
DISPSTAT_VCOUNTER_IRQ // V-Counter IRQ Enable (1=Enable)
)
type SoundRegs struct {
SOUND1CNT_L volatile.Register16 // R/W - Channel 1 Sweep register (NR10)
SOUND1CNT_H volatile.Register16 // R/W - Channel 1 Duty/Length/Envelope (NR11, NR12)
SOUND1CNT_X volatile.Register16 // R/W - Channel 1 Frequency/Control (NR13, NR14)
_ volatile.Register16 // - - Not used
SOUND2CNT_L volatile.Register16 // R/W - Channel 2 Duty/Length/Envelope (NR21, NR22)
_ volatile.Register16 // - - Not used
SOUND2CNT_H volatile.Register16 // R/W - Channel 2 Frequency/Control (NR23, NR24)
_ volatile.Register16 // - - Not used
SOUND3CNT_L volatile.Register16 // R/W - Channel 3 Stop/Wave RAM select (NR30)
SOUND3CNT_H volatile.Register16 // R/W - Channel 3 Length/Volume (NR31, NR32)
SOUND3CNT_X volatile.Register16 // R/W - Channel 3 Frequency/Control (NR33, NR34)
_ volatile.Register16 // - - Not used
SOUND4CNT_L volatile.Register16 // R/W - Channel 4 Length/Envelope (NR41, NR42)
_ volatile.Register16 // - - Not used
SOUND4CNT_H volatile.Register16 // R/W - Channel 4 Frequency/Control (NR43, NR44)
_ volatile.Register16 // - - Not used
SOUNDCNT_L volatile.Register16 // R/W - Control Stereo/Volume/Enable (NR50, NR51)
SOUNDCNT_H volatile.Register16 // R/W - Control Mixing/DMA Control
SOUNDCNT_X volatile.Register16 // R/W - Control Sound on/off (NR52)
_ volatile.Register16 // - - Not used
SOUNDBIAS volatile.Register16 // BIAS- Sound PWM Control
_ [3]volatile.Register16 // - - Not used
WAVE_RAM [2][8]byte // R/W - Channel 3 Wave Pattern RAM (2 banks!!)
FIFO_A volatile.Register32 // W - Channel A FIFO, Data 0-3
FIFO_B volatile.Register32 // W - Channel B FIFO, Data 0-3
_ [4]volatile.Register16 // Not used
}
type InterruptRegs struct {
Request volatile.Register16 // R/W - Interrupt Request
Ack volatile.Register16 // R/W - Interrupt Active (R) / Acknowledge (W)
_ volatile.Register32 // - - Not used
Enable volatile.Register16 // R/W - Interrupt Master Enable
}
type PinMode uint8
// Set has not been implemented.
func (p Pin) Set(value bool) {
// do nothing
}
var (
DisplayMode3 = Mode3DisplayBuffer{(*[160][240]volatile.Register16)(unsafe.Pointer(uintptr(0x06000000)))}
Display = DisplayMode3 // default to the Mode3 display buffer.
)
type Mode3DisplayBuffer struct {
port *[160][240]volatile.Register16
}
func (d Mode3DisplayBuffer) Configure() {
// Use video mode 3 (in BG2, a 16bpp bitmap in VRAM) and
// Enable BG2 (BG0 = 1, BG1 = 2, BG2 = 4, ...)
IO.LCD.DISPCNT.Set(DISPCNT_MODE3 | DISPCNT_DISPLAY_BG2)
}
func (d Mode3DisplayBuffer) Size() (x, y int16) {
return 240, 160
}
func (d Mode3DisplayBuffer) SetPixel(x, y int16, c color.RGBA) {
d.port[y][x].Set(uint16(c.R)&0x1f | uint16(c.G)&0x1f<<5 | uint16(c.B)&0x1f<<10)
}
func (d Mode3DisplayBuffer) Display() error {
// disable forced blank so we can see screen
IO.LCD.DISPCNT.ClearBits(DISPCNT_FORCED_BLANK)
return nil
}
type Keypad struct {
Status volatile.Register16 // R - Key Status
Control volatile.Register16 // R/W - Key Interrupt Control
}
// A Key represents one of the possible keys.
type Key uint16
// Keypad constants
const (
KEY_A Key = 1 << iota
KEY_B
KEY_SELECT
KEY_START
KEY_RIGHT
KEY_LEFT
KEY_UP
KEY_DOWN
KEY_RB
KEY_LB
// KEY_ANY has the bits for every key set.
KEY_ANY Key = 0x3FF
KEY_IRQ_ENABLE = 1 << 14
KEY_IRQ_ALL = 1 << 15
)
func (k *Keypad) WakeOn(keys ...Key) {
var mask uint16
for _, k := range keys {
mask |= uint16(k)
}
k.Control.ClearBits(uint16(KEY_ANY))
k.Control.SetBits(mask)
}
type Timer struct {
Counter volatile.Register16 // R/W - Counter (R) / Reload (W)
Control volatile.Register16 // R/W - Flags (see TIMER_*)
}
// Timer constants
const (
TIMER_PRESCALE_1 = 0
TIMER_PRESCALE_64 = 1
TIMER_PRESCALE_256 = 2
TIMER_PRESCALE_1024 = 3
TIMER_COUNT_OVERFLOWS = 1 << 2
TIMER_IRQ_ENABLE = 1 << 6
TIMER_START = 1 << 7
)
func (t *Timer) Start() {
t.Control.SetBits(TIMER_START)
}
func (t *Timer) Stop() {
t.Control.ClearBits(TIMER_START)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment