The framework is still under development
The documentation in this section refers to the Game Bub Core Framework
as of v1.1-beta. The framework is not finalized, and may change
based on developer feedback.
Reference: Interfaces¶
As described in Core Structure, cores select from and configure a variety of interfaces to interact with the hardware via the framework.
import chisel3._
import net.gamebub.framework.Core
import net.gamebub.framework.interface._
class MyCore extends Module with Core {
val io = IO(new Bundle {
// Hardware interfaces are declared as elements of this Bundle
})
}
| Port Name | Interface Class | Required |
|---|---|---|
clocks |
ClocksV0 |
Yes |
video |
VideoV0 |
Yes |
host |
HostV0 |
Yes |
audio |
AudioV0 |
No |
input |
InputV0 |
No |
vibrate |
VibrateV0 |
No |
cartridge |
CartridgePortV0 |
No |
link |
LinkPortV0 |
No |
pmod |
PmodV0 |
No |
sram |
SramV0 |
No |
sdram |
SdramV0 |
No |
videoFilter |
VideoFilterBasicV0 |
No |
Clocks (clocks: ClocksV0)¶
Required. This interface provides the root 50 MHz clock to the core, and allows the core to provide necessary clocks to the framework (system clock, display clock, SPI clock).
The system clock, generated by the core, is the clock used with all interfaces, unless otherwise specified.
Parameters¶
clockSystemHz: Frequency in Hz of the system clock.clockDisplayHz: Frequency in Hz of the LCD interface clock. Must fall within the range returned byClocksV0.getClockDisplayHz(...).clockSpiHz: Frequency in Hz of the clock used to sample the MCU SPI bus. Must be at least 160 MHz.
Helpers¶
ClocksV0.getClockDisplayHz: (Double) => (Int, Int): provides a tuple of the minimum and maximum allowable display clock frequencies (in Hz), based on the given frame period in seconds (e.g.1.0 / 60.0).
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
clockIn50M |
Input | Clock |
50 MHz reference clock input |
clockOutSystem |
Output | Clock |
System clock |
clockOutDisplay |
Output | Clock |
Display clock |
clockOutSpi |
Output | Clock |
Host MCU SPI clock |
locked |
Output | Bool |
High when the core's clocks are stable and locked (i.e. PLL output) |
Video (video: VideoV0)¶
Required. This interface allows the core to produce video output. The signals are referenced to the system clock.
Parameters¶
videoWidth: Width of the active video signal (in pixels)videoHeight: Height of the active video signal (in pixels)colorDepthR: Bit-depth of the red channelcolorDepthG: Bit-depth of the green channelcolorDepthB: Bit-depth of the blue channelframePeriod: Video frame period (in seconds), e.g.1.0 / 60.0
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
data.r |
Output | UInt |
Video data: red channel |
data.g |
Output | UInt |
Video data: green channel |
data.b |
Output | UInt |
Video data: blue channel |
dataEnable |
Output | Bool |
High during video output |
vblank |
Output | Bool |
Pulse high at the end of each frame |
hblank |
Output | Bool |
Pulse high at the end of each line |
Host (host: HostV0)¶
Required. This interface allows the host MCU to communicate with the core. There are two main interfaces: the memory interface, and the command interface. Both interfaces use the system clock.
The memory interface is a simple memory interface (no pipelining or bursting), where a single 32-bit address is transmitted, along with a 32-bit data word read or write. enable goes high to indicate a new request is starting, with the given address, and whether it is a read (write low) or write (write high). Writes also come with dataWrite. When the core has completed the request, it must raise done. If the request was a read, dataRead must also be valid.
All memory accesses take at least two cycles: the first cycle starts when enable goes high, and the earliest it can end is on the second cycle (when done goes high). However, if the core needs additional time to handle the request, it can delay raising done until the third, fourth, or a later cycle.
The next transaction can start immediately on the cycle after done goes high.
Addresses beginning with 0xFxxxxxxx are reserved for use by the framework. Except as explicitly specified (e.g. for the command interface), the core must not map its own registers or memory at these addresses.
There are two command interfaces: commandHost (for Host -> Core commands), and commandCore (for Core -> Host) commands. Each provides a separate request / response channel.
The command interfaces are described in a later section.
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
mem.enable |
Input | Bool |
High when a transaction is going on |
mem.write |
Input | Bool |
High if the transaction is a write, low if it is a read |
mem.address |
Input | UInt(32.W) |
The 32-bit byte address |
mem.dataWrite |
Input | UInt(32.W) |
32-bit data written by the host |
mem.dataRead |
Output | UInt(32.W) |
32-bit data read by the host, valid when done goes high |
mem.done |
Output | Bool |
High for one cycle when the transaction is completed |
commandHost.request |
Input | Bool |
High during a host-initiated request |
commandHost.busy |
Output | Bool |
Set high when the core acknowledges the request |
commandHost.done |
Output | Bool |
Set high when the core completes the request |
commandHost.error |
Output | Bool |
Set high if the request completes in an error |
commandCore.request |
Output | Bool |
High during a core-initiated request |
commandCore.busy |
Input | Bool |
High when the host acknowledges the request |
commandCore.done |
Input | Bool |
High when the host completes the request |
commandCore.error |
Input | Bool |
High if the requested completed in an error |
Audio (audio: AudioV0)¶
Optional. This interface allows the core to produce audio output. The signals are referenced to the system clock.
The sample rate is always 48000 Hz, so the core should update left and right at 48 kHz.
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
left |
Output | SInt(16.W) |
16-bit signed PCM audio sample for the left channel |
right |
Output | SInt(16.W) |
16-bit signed PCM audio sample for the right channel |
Input (input: InputV0)¶
Optional. This interface allows the core to receive button input. Each button signal is active-high and synchronized into the system clock domain.
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
buttons.a |
Input | Bool |
Action button 'A' |
buttons.b |
Input | Bool |
Action button 'B' |
buttons.x |
Input | Bool |
Action button 'X' |
buttons.y |
Input | Bool |
Action button 'Y' |
buttons.up |
Input | Bool |
D-Pad button 'Up' |
buttons.down |
Input | Bool |
D-Pad button 'Down' |
buttons.left |
Input | Bool |
D-Pad button 'Left' |
buttons.right |
Input | Bool |
D-Pad button 'Right' |
buttons.l |
Input | Bool |
Shoulder button 'L' |
buttons.r |
Input | Bool |
Shoulder button 'R' |
buttons.start |
Input | Bool |
Menu button 'Start' |
buttons.select |
Input | Bool |
Menu button 'Select' |
Vibrate (vibrate: VibrateV0)¶
Optional. This interface allows the core to produce haptic feedback (vibration).
The mode can be either:
Off(0b00)On(0b01)Brake(0b10)
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
mode |
Output | VibrateV0.Mode() |
Output to the vibration motor |
Cartridge Port (cartridge: CartridgePortV0)¶
Optional. This interface allows the core to access the cartridge slot. Note that cartridge power must be enabled in the core.json metadata file.
Cartridge pins go through level shifters, and the I/O voltage is controlled automatically by the hardware based on a shape-detecting switch in the cartridge slot.
For each direction signal, high (1) indicates output from FPGA to cartridge, 0 indicates input from cartridge to FPGA.
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
enabled |
Output | Bool |
High to enable cartridge level shifters. |
switch |
Input | Bool |
High when a DMG/CGB cartridge is inserted (5 V), low otherwise (3.3 V) |
bank0In / bank0Out |
In / Out | UInt(8.W) |
Address bus lines A16 through A23. |
bank0Dir |
Output | Bool |
Direction for Bank 0 |
bank1In / bank1Out |
In / Out | UInt(8.W) |
Address/Data bus lines AD8 through AD15. |
bank1Dir |
Output | Bool |
Direction for Bank 1 |
bank2In / bank2Out |
In / Out | UInt(8.W) |
Address/Data bus lines AD0 through AD7. |
bank2Dir |
Output | Bool |
Direction for Bank 2 |
bank3In / bank3Out |
In / Out | UInt(4.W) |
Control pins: bit 0 = nCS1, 1 = nRD, 2 = nWR, 3 = PHI |
bank3Dir |
Output | Bool |
Direction for Bank 3 control pins |
pin30In / pin30Out |
In / Out | Bool |
Pin 30: nRST / nCS2 |
pin30Dir |
Output | Bool |
Direction for Pin 30 |
pin31In / pin31Out |
In / Out | Bool |
Pin 31: VIN / nIRQ |
pin31Dir |
Output | Bool |
Direction for Pin 31 |
Link Port (link: LinkPortV0)¶
Optional. This interface allows the core to access the link port. The voltage is automatically controlled by the cartridge shape-detector switch.
For each direction signal, high (1) indicates output, 0 indicates input.
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
soIn, soOut, soDir |
In / Out / Out | Bool |
SO pin |
siIn, siOut, siDir |
In / Out / Out | Bool |
SI pin |
sdIn, sdOut, sdDir |
In / Out / Out | Bool |
SD pin |
scIn, scOut, scDir |
In / Out / Out | Bool |
SC pin |
PMOD (pmod: PmodV0)¶
Optional. This interface allows the core to access the PMOD connector at the top of the device. All I/Os are 3.3 V and unbuffered.
For each direction signal, high (1) indicates output, 0 indicates input.
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
in |
Input | UInt(4.W) |
Input from PMOD header |
out |
Output | UInt(4.W) |
Output to PMOD header |
dir |
Output | UInt(4.W) |
Pin direction mask |
SDRAM (sdram: SdramV0)¶
Optional. This interface allows the core to access SDRAM memory chips.
For each direction signal, high (1) indicates output, 0 indicates input.
Game Bub Rev4 has 2x 32 MiB SDRAM chips with a 16-bit data bus.
Parameters¶
addressWidth: Row/column address bus width (default: 13)dataWidth: Data bus width (default: 16)bankWidth: Bank addres width (default: 2)chips: Number of parallel chips / chip-select lines (default: 1)
Helpers¶
SdramV0.numChips: Int: exposes the number of SDRAM chips available on the target
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
clock |
Output | Clock |
SDRAM clock |
cke |
Output | Bool |
Clock enable |
cs |
Output | UInt |
Active-low chip select |
ras, cas, we |
Output | Bool |
Active-low command strobe lines |
dqm |
Output | UInt |
Active-high data byte mask |
bank |
Output | UInt |
Bank address |
address |
Output | UInt |
Address bus |
dataIn |
Input | UInt |
Data bus input |
dataOut |
Output | UInt |
Data bus output |
dataDir |
Output | Bool |
Data bus direction |
SRAM (sram: SramV0)¶
Optional. This interface allows the core to access asynchronous SRAM memory chips.
For each direction signal, high (1) indicates output, 0 indicates input.
Game Bub Rev4 has a 512 KiB, 16-bit data bus asynchronous SRAM chip.
Parameters¶
addressWidth: Address bus width (default: 18)dataWidth: Data bus width (default: 16)
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
ceN |
Output | Bool |
Active-low chip enable |
weN |
Output | Bool |
Active-low write enable |
oeN |
Output | Bool |
Active-low output enable |
writeMaskN |
Output | UInt |
Active-low byte write masks |
address |
Output | UInt |
Address bus |
dataIn |
Input | UInt |
Data bus input |
dataOut |
Output | UInt |
Data bus output |
dataDir |
Output | Bool |
Data bus direction |
Video Filter (videoFilter: VideoFilterBasicV0)¶
Optional. This interface allows the core to apply filter effects to video output after scaling.
These signals are in the display clock domain, not the system clock domain.
Parameters¶
colorInDepthR: Bit-depth of the red channel (must matchvideo)colorInDepthG: Bit-depth of the green channel (must matchvideo)colorInDepthB: Bit-depth of the blue channel (must matchvideo)latency: Latency from filter input to output (in clock cycles)
Port Signals¶
| Signal | Direction | Type | Description |
|---|---|---|---|
clock |
Input | Clock |
Display clock |
reset |
Input | Reset |
Filter reset signal (active-high) |
dataIn.r |
Input | UInt |
Input color data (red channel) |
dataIn.g |
Input | UInt |
Input color data (green channel) |
dataIn.b |
Input | UInt |
Input color data (blue channel) |
dataOut.r |
Output | UInt(8.W) |
Output color data (red channel) |
dataOut.g |
Output | UInt(8.W) |
Output color data (green channel) |
dataOut.b |
Output | UInt(8.W) |
Output color data (blue channel) |
Host/Core Commands¶
To begin a request, the initiator raises request high, and holds it high for the duration of the request. The receiver then raises the busy signal, to indicate it is working on the request. When the receiver is finished, it raises the done signal (and the error signal, if the command completed in an error).
After the initiator is done handling the response, they must lower request. Then, they may raise request again to send a new request, and the whole process repeats.
Parameters and Results¶
Request parameters and results are transmitted using the memory bus, in the regions 0xF000_0000 (Host -> Core) and 0xF000_1000 (Core -> Host). Each parameter and result is 32 bits.
Before raising request, the host writes its command opcode to 0xF000_0000, its first parameter (if there is one) to 0xF000_0004, its second parameter (if there is one) to 0xF000_0008, etc.
Upon request completion (when done goes high), the host will read the first result word from 0xF000_0000, the second result word from 0xF000_0004, etc.
For Core -> Host commands, the same interface holds true, but in reverse, at starting at 0xF000_1000. That is, when request is raised by the core, the host will read the opcode from 0xF000_1000, the first parameter from 0xF000_1004, etc. And similarly, before it raises done, it will write the first result word to 0xF000_1000, the second to 0xF000_1004, etc.
Host -> Core commands¶
GetStatus (0x0000)¶
Called by the host to request the status of the core. No parameters. The result is a single value, indicating the status:
StatusUnknown = 0: unknown statusStatusInitialize = 1: the core is initializing itselfStatusSetup = 2: the core has initialized, and is ready for the host to transmit commands and memory accessesStatusCoreHalt = 3: the core has been set up, and is halted in resetStatusCoreRun = 4: the core is actively running
CoreRun (0x0100)¶
Called by the host to start core execution (taking it out of reset).
No parameters or results.
The core should transition to StatusCoreRun.
CoreHalt (0x0101)¶
Called by the host to halt core execution (putting it into reset).
No parameters or results.
The core should transition to StatusCoreHalt.
SetupComplete (0x0102)¶
Called by the host to indicate that it is done setting up the core (files and settings have been transmitted).
No parameters or results.
The core should finalize its setup and transition to StatusCoreHalt.
NotifyFocus (0x0200)¶
Called by the host to indicate that the core gained or lost UI focus. When not focused, video may be obscured by a menu, audio may be silenced, and the core will not receive any input.
The core may choose to (but does not have to) pause itself.
One parameter: 1 if the core has gained focus, 0 if the core has lost focus. No results.
FileWriteStart (0x0300)¶
Called by the host before it starts writing a file to the core via the host memory interface.
One parameter: the file ID, defined in files.json. No results.
FileWriteEnd (0x0301)¶
Called by the host when it has finished writing the file.
Three parameters: 1. The file ID 2. The total size of the file transferred, in bytes 3. Reserved (0)
No results.
FileReadStart (0x0302)¶
Called by the host before it starts reading a file from the core via the host memory interface.
One parameter: the file ID. One result: the file size in bytes.
FileReadEnd (0x0303)¶
Called by the host when it has finished reading the file.
One parameter: the file ID. No results.
Core -> Host commands¶
There are no core initiated commands yet.