maple: send a 'device request' command

On an emulator, the receive buffer is filled with the correct/expected
data for 'device status'.

I found this experiment useful:

- it revealed a bug in my register struct generator code (the
  maple_if-related registers were not at the correct offsets)

- it validates my understanding about endianness-swapping between the
  maple bus and the SH4
This commit is contained in:
Zack Buhman 2023-12-09 01:31:34 +08:00
parent 3f30c96dcd
commit f1a32d0719
11 changed files with 242 additions and 173 deletions

View File

@ -1 +1,28 @@
all: main.elf
include common.mk include common.mk
MAIN_OBJ = \
start.o \
main.o \
load.o \
cache.o \
vga.o \
rgb.o \
holly/background.o \
holly/region_array.o \
holly/ta_fifo_polygon_converter.o \
holly/core.o \
maple.o \
scene.o \
macaw.data.o \
$(LIBGCC)
serial.elf: start.o serial_main.o load.o cache.o
$(LD) $(LDFLAGS) -T $(LIB)/alt.lds $^ -o $@
main.elf: $(MAIN_OBJ)
$(LD) $(LDFLAGS) -T $(LIB)/main.lds $^ -o $@
test.elf: $(MAIN_OBJ)
$(LD) $(LDFLAGS) -T $(LIB)/alt.lds $^ -o $@

View File

@ -7,13 +7,14 @@ AARCH = --isa=sh4 --little
AFLAGS = --fatal-warnings AFLAGS = --fatal-warnings
CARCH = -m4-single-only -ml CARCH = -m4-single-only -ml
CFLAGS += -falign-functions=4 -ffunction-sections -fdata-sections -fshort-enums -ffreestanding -nostdlib -Wno-error=narrowing CFLAGS += -falign-functions=4 -ffunction-sections -fdata-sections -fshort-enums -ffreestanding -nostdlib
CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable CFLAGS += -Wall -Werror -Wfatal-errors
CFLAGS += -Wno-error=narrowing -Wno-error=unused-variable
CFLAGS += -mfsca -funsafe-math-optimizations CFLAGS += -mfsca -funsafe-math-optimizations
DEPFLAGS = -MMD -E DEPFLAGS = -MMD -E
# --print-gc-sections # --print-gc-sections
LDFLAGS = --gc-sections --no-warn-rwx-segment --print-memory-usage --entry=_start --orphan-handling=error LDFLAGS = --gc-sections --no-warn-rwx-segment --print-memory-usage --entry=_start --orphan-handling=error
CXXFLAGS = -std=c++20 -fno-exceptions -fno-non-call-exceptions -fno-rtti -fno-threadsafe-statics CXXFLAGS = -std=c++23 -fno-exceptions -fno-non-call-exceptions -fno-rtti -fno-threadsafe-statics
TARGET = sh4-none-elf- TARGET = sh4-none-elf-
CC = $(TARGET)gcc CC = $(TARGET)gcc
@ -47,23 +48,6 @@ IP_OBJ = \
sg/sg_ini.o \ sg/sg_ini.o \
sg/aip.o sg/aip.o
MAIN_OBJ = \
start.o \
main.o \
load.o \
cache.o \
vga.o \
rgb.o \
holly/background.o \
holly/region_array.o \
holly/ta_fifo_polygon_converter.o \
holly/core.o \
scene.o \
macaw.data.o \
$(LIBGCC)
all: main.cdi
%.bin.o: %.bin %.bin.o: %.bin
$(BUILD_BINARY_O) $(BUILD_BINARY_O)
@ -87,15 +71,6 @@ all: main.cdi
%.o: %.cpp %.cpp.d %.o: %.cpp %.cpp.d
$(CXX) $(CARCH) $(CFLAGS) $(CXXFLAGS) $(OPT) $(DEBUG) -c $< -o $@ $(CXX) $(CARCH) $(CFLAGS) $(CXXFLAGS) $(OPT) $(DEBUG) -c $< -o $@
serial.elf: start.o serial_main.o load.o cache.o
$(LD) $(LDFLAGS) -T $(LIB)/alt.lds $^ -o $@
main.elf: $(MAIN_OBJ)
$(LD) $(LDFLAGS) -T $(LIB)/main.lds $^ -o $@
test.elf: $(MAIN_OBJ)
$(LD) $(LDFLAGS) -T $(LIB)/alt.lds $^ -o $@
%.bin: %.elf %.bin: %.elf
$(OBJCOPY) -O binary $< $@ $(OBJCOPY) -O binary $< $@

View File

@ -9,6 +9,8 @@
#include "holly/core_bits.h" #include "holly/core_bits.h"
#include "holly/ta_fifo_polygon_converter.h" #include "holly/ta_fifo_polygon_converter.h"
#include "systembus.h" #include "systembus.h"
#include "maple.h"
#include "maple_bits.h"
#include "holly/texture_memory_alloc.h" #include "holly/texture_memory_alloc.h"
@ -16,6 +18,7 @@
#include "load.h" #include "load.h"
#include "vga.h" #include "vga.h"
#include "rgb.h" #include "rgb.h"
#include "string.h"
#include "scene.h" #include "scene.h"
#include "macaw.h" #include "macaw.h"
@ -64,6 +67,32 @@ uint32_t * align_32byte(uint32_t * mem)
return reinterpret_cast<uint32_t *>(((reinterpret_cast<uint32_t>(_scene) + 31) & ~31)); return reinterpret_cast<uint32_t *>(((reinterpret_cast<uint32_t>(_scene) + 31) & ~31));
} }
void serial_int(const uint32_t n)
{
char num_buf[9];
string::hex<char>(num_buf, 8, n);
num_buf[8] = 0;
serial_string("0x");
serial_string(num_buf);
serial_string("\n");
}
void maple_test()
{
uint32_t _command_buf[(32 + 32) / 4];
uint32_t _receive_address[(32 + 32) / 4];
uint32_t * command_buf = align_32byte(_command_buf);
uint32_t * receive_address = align_32byte(_receive_address);
serial_int(mdstar::table_address(reinterpret_cast<uint32_t>(command_buf)));
maple_init_host_command(command_buf, receive_address);
maple_dma_start(command_buf);
for (int i = 0; i < 32; i++) {
serial_int(receive_address[i]);
}
}
extern "C" extern "C"
void main() void main()
{ {
@ -82,6 +111,8 @@ void main()
v_sync_in(); v_sync_in();
maple_test();
volatile uint16_t * framebuffer = reinterpret_cast<volatile uint16_t *>(&texture_memory[0]); volatile uint16_t * framebuffer = reinterpret_cast<volatile uint16_t *>(&texture_memory[0]);
for (int y = 0; y < 480; y++) { for (int y = 0; y < 480; y++) {
for (int x = 0; x < 640; x++) { for (int x = 0; x < 640; x++) {

View File

@ -1,11 +1,22 @@
#include <cstdint>
#include <bit>
#include "sh7091.h"
#include "sh7091_bits.h"
#include "systembus.h"
#include "systembus_bits.h"
#include "maple_bits.h"
#include "maple.h"
#define AP__PO__A (0b00 << 6) #define AP__PO__A (0b00 << 6)
#define AP__PO__B (0b01 << 6) #define AP__PO__B (0b01 << 6)
#define AP__PO__C (0b10 << 6) #define AP__PO__C (0b10 << 6)
#define AP__PO__D (0b11 << 6) #define AP__PO__D (0b11 << 6)
#define AP__DE__DEVICE = (1 << 5) #define AP__DE__DEVICE (1 << 5)
#define AP__DE__EXPANSION_DEVICE = (0 << 5) #define AP__DE__EXPANSION_DEVICE (0 << 5)
#define AP__DE__PORT = (0 << 5) #define AP__DE__PORT (0 << 5)
#define AP__LM(reg) ((reg) & 0b11111) #define AP__LM(reg) ((reg) & 0b11111)
@ -26,9 +37,9 @@ struct maple_host_command {
uint32_t protocol_data[N]; uint32_t protocol_data[N];
}; };
void maple_host_command(uint32_t * buf, uint32_t * receive_address) void maple_init_host_command(uint32_t * buf, uint32_t * receive_address)
{ {
auto command = reinterpet_cast<maple_host_command<1> *>(buf); auto command = reinterpret_cast<maple_host_command<1> *>(buf);
command->host_instruction = HOST_INSTRUCTION__END_FLAG command->host_instruction = HOST_INSTRUCTION__END_FLAG
| HOST_INSTRUCTION__PORT_SELECT__A | HOST_INSTRUCTION__PORT_SELECT__A
@ -40,10 +51,11 @@ void maple_host_command(uint32_t * buf, uint32_t * receive_address)
uint32_t destination_ap = AP__DE__DEVICE | AP__PO__A; uint32_t destination_ap = AP__DE__DEVICE | AP__PO__A;
uint32_t source_ap = AP__PO__A; uint32_t source_ap = AP__PO__A;
uint32_t data_size = 0; uint32_t data_size = 0;
command->protocol_data[0] = (command_code << 24) // maple bus is big endian
command->protocol_data[0] = std::byteswap( (command_code << 24)
| (destination_ap << 16) | (destination_ap << 16)
| (source_ap << 8) | (source_ap << 8)
| (data_size << 0); | (data_size << 0));
} }
void maple_dma_start(uint32_t * command_buf) void maple_dma_start(uint32_t * command_buf)
@ -56,28 +68,28 @@ void maple_dma_start(uint32_t * command_buf)
system.ISTNRM = ISTNRM__END_OF_DMA_MAPLE_DMA; system.ISTNRM = ISTNRM__END_OF_DMA_MAPLE_DMA;
// disable maple-DMA // disable maple-DMA
system.MDEN = mden::dma_enable::abort; maple_if.MDEN = mden::dma_enable::abort;
volatile uint32_t _dummy = system.MDST; volatile uint32_t _dummy = maple_if.MDST;
(void)_dummy; (void)_dummy;
// 20nsec * 0xc350 = 1ms // 20nsec * 0xc350 = 1ms
constexpr uint32_t one_msec = 0xc350; constexpr uint32_t one_msec = 0xc350;
system.MSYS = msys::time_out_counter(one_msec) maple_if.MSYS = msys::time_out_counter(one_msec)
| msys::sending_rate::_2M; | msys::sending_rate::_2M;
system.MDTSEL = mdtsel::trigger_select::software_initiation; maple_if.MDTSEL = mdtsel::trigger_select::software_initiation;
/* top address: the first/lowest address /* top address: the first/lowest address
bottom address: the last/highest address */ bottom address: the last/highest address */
system.MDAPRO = mdapro::security_code maple_if.MDAPRO = mdapro::security_code
| mdapro::top_address(0x00) | mdapro::top_address(0x00)
| mdapro::bottom_address(0x7f); | mdapro::bottom_address(0x7f);
system.MDSTAR = mdstar::table_address(command_buf); maple_if.MDSTAR = mdstar::table_address(reinterpret_cast<uint32_t>(command_buf));
system.MDEN = mden::dma_enable::enable; maple_if.MDEN = mden::dma_enable::enable;
system.MDST = mdst::start_status::start; maple_if.MDST = mdst::start_status::start;
// wait for completion // wait for completion
while ((system.ISTNRM & ISTNRM__END_OF_DMA_MAPLE_DMA) == 0); while ((system.ISTNRM & ISTNRM__END_OF_DMA_MAPLE_DMA) == 0);

80
maple.h
View File

@ -1,78 +1,6 @@
#pragma once
#include <cstdint> #include <cstdint>
#include "float_uint32.h" void maple_init_host_command(uint32_t * buf, uint32_t * receive_address);
void maple_dma_start(uint32_t * command_buf);
namespace mdstar {
constexpr uint32_t table_address(uint32_t num) { return (num & 0xfffffe0) << 0; }
}
namespace mdtsel {
namespace trigger_select {
constexpr uint32_t software_initiation = 0 << 0;
constexpr uint32_t v_blank_initiation = 1 << 0;
}
}
namespace mden {
namespace dma_enable {
constexpr uint32_t abort = 0 << 0;
constexpr uint32_t enable = 1 << 0;
constexpr uint32_t status(uint32_t reg) { return (reg >> 0) & 0x1; }
}
}
namespace mdst {
namespace start_status {
constexpr uint32_t status(uint32_t reg) { return (reg >> 0) & 0x1; }
constexpr uint32_t start = 1 << 0;
}
}
namespace msys {
constexpr uint32_t time_out_counter(uint32_t num) { return (num & 0xffff) << 16; }
constexpr uint32_t single_hard_trigger = 1 << 12;
namespace sending_rate {
constexpr uint32_t _2M = 0 << 8;
constexpr uint32_t _1M = 1 << 8;
}
constexpr uint32_t delay_time(uint32_t num) { return (num & 0xf) << 0; }
}
namespace mst {
constexpr uint32_t move_status(uint32_t reg) { return (reg >> 31) & 0x1; }
constexpr uint32_t internal_frame_monitor(uint32_t reg) { return (reg >> 24) & 0x7; }
constexpr uint32_t internal_state_monitor(uint32_t reg) { return (reg >> 16) & 0x3f; }
constexpr uint32_t line_monitor(uint32_t reg) { return (reg >> 0) & 0xff; }
}
namespace mshtcl {
constexpr uint32_t hard_dma_clear = 1 << 0;
}
namespace mdapro {
constexpr uint32_t security_code = 0x6155 << 16;
constexpr uint32_t top_address(uint32_t num) { return (num & 0x7f) << 8; }
constexpr uint32_t bottom_address(uint32_t num) { return (num & 0x7f) << 0; }
}
namespace mmsel {
namespace msb_selection {
constexpr uint32_t bit7 = 0 << 0;
constexpr uint32_t bit31 = 1 << 0;
}
}
namespace mtxdad {
constexpr uint32_t txd_address_counter(uint32_t reg) { return (reg >> 0) & 0x1fffffff; }
}
namespace mrxdad {
constexpr uint32_t rxd_address_counter(uint32_t reg) { return (reg >> 0) & 0x1fffffff; }
}
namespace mrxdbd {
constexpr uint32_t rxd_base_address(uint32_t reg) { return (reg >> 0) & 0x1fffffff; }
}

78
maple_bits.h Normal file
View File

@ -0,0 +1,78 @@
#include <cstdint>
#include "holly/float_uint32.h"
namespace mdstar {
constexpr uint32_t table_address(uint32_t num) { return (num & 0xfffffe0) << 0; }
}
namespace mdtsel {
namespace trigger_select {
constexpr uint32_t software_initiation = 0 << 0;
constexpr uint32_t v_blank_initiation = 1 << 0;
}
}
namespace mden {
namespace dma_enable {
constexpr uint32_t abort = 0 << 0;
constexpr uint32_t enable = 1 << 0;
constexpr uint32_t status(uint32_t reg) { return (reg >> 0) & 0x1; }
}
}
namespace mdst {
namespace start_status {
constexpr uint32_t status(uint32_t reg) { return (reg >> 0) & 0x1; }
constexpr uint32_t start = 1 << 0;
}
}
namespace msys {
constexpr uint32_t time_out_counter(uint32_t num) { return (num & 0xffff) << 16; }
constexpr uint32_t single_hard_trigger = 1 << 12;
namespace sending_rate {
constexpr uint32_t _2M = 0 << 8;
constexpr uint32_t _1M = 1 << 8;
}
constexpr uint32_t delay_time(uint32_t num) { return (num & 0xf) << 0; }
}
namespace mst {
constexpr uint32_t move_status(uint32_t reg) { return (reg >> 31) & 0x1; }
constexpr uint32_t internal_frame_monitor(uint32_t reg) { return (reg >> 24) & 0x7; }
constexpr uint32_t internal_state_monitor(uint32_t reg) { return (reg >> 16) & 0x3f; }
constexpr uint32_t line_monitor(uint32_t reg) { return (reg >> 0) & 0xff; }
}
namespace mshtcl {
constexpr uint32_t hard_dma_clear = 1 << 0;
}
namespace mdapro {
constexpr uint32_t security_code = 0x6155 << 16;
constexpr uint32_t top_address(uint32_t num) { return (num & 0x7f) << 8; }
constexpr uint32_t bottom_address(uint32_t num) { return (num & 0x7f) << 0; }
}
namespace mmsel {
namespace msb_selection {
constexpr uint32_t bit7 = 0 << 0;
constexpr uint32_t bit31 = 1 << 0;
}
}
namespace mtxdad {
constexpr uint32_t txd_address_counter(uint32_t reg) { return (reg >> 0) & 0x1fffffff; }
}
namespace mrxdad {
constexpr uint32_t rxd_address_counter(uint32_t reg) { return (reg >> 0) & 0x1fffffff; }
}
namespace mrxdbd {
constexpr uint32_t rxd_base_address(uint32_t reg) { return (reg >> 0) & 0x1fffffff; }
}

View File

@ -4,7 +4,7 @@ def should_autonewline(line):
return ( return (
"static_assert" not in line "static_assert" not in line
and "extern" not in line and "extern" not in line
and line.split()[1] != '=' # hacky; meh and (len(line.split()) < 2 or line.split()[1] != '=') # hacky; meh
) )
def _render(out, lines): def _render(out, lines):

View File

@ -51,8 +51,7 @@ def new_writer():
if last_block is not None: if last_block is not None:
yield "};" yield "};"
for address, name in stack: for address, name in stack:
relative_address = address - first_address yield f"static_assert((offsetof (struct {last_block.lower()}_reg, {name})) == {hex(address)});"
yield f"static_assert((offsetof (struct {last_block.lower()}_reg, {name})) == {hex(relative_address)});"
yield "" yield ""
stack = [] stack = []
@ -76,8 +75,8 @@ def new_writer():
if block != last_block: if block != last_block:
yield from terminate() yield from terminate()
first_address = address first_address = 0 # hmm...
last_address = address last_address = 0
size_total = 0 size_total = 0
reserved_num = 0 reserved_num = 0
yield f"struct {block.lower()}_reg {{" yield f"struct {block.lower()}_reg {{"

View File

@ -14,7 +14,7 @@ def blocks(rows):
blocks.append(block) blocks.append(block)
for block in blocks: for block in blocks:
yield f'extern struct {block.lower()}_reg {block} __asm("{block}");' yield f'extern struct {block.lower()}_reg {block.lower()} __asm("{block.lower()}");'
input_file = sys.argv[1] input_file = sys.argv[1]
rows = read_input(input_file) rows = read_input(input_file)

21
string.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <cstdint>
namespace string {
template <typename T>
inline void hex(T * c, uint32_t len, uint32_t n)
{
while (len > 0) {
uint32_t nib = n & 0xf;
n = n >> 4;
if (nib > 9) {
nib += (97 - 10);
} else {
nib += (48 - 0);
}
c[--len] = nib;
}
}
}

View File

@ -88,81 +88,83 @@ static_assert((offsetof (struct system_reg, G2DTNRM)) == 0x150);
static_assert((offsetof (struct system_reg, G2DTEXT)) == 0x154); static_assert((offsetof (struct system_reg, G2DTEXT)) == 0x154);
struct maple_if_reg { struct maple_if_reg {
reg8 _pad0[4];
reg32 MDSTAR; /* Maple-DMA command table address */ reg32 MDSTAR; /* Maple-DMA command table address */
reg8 _pad0[8]; reg8 _pad1[8];
reg32 MDTSEL; /* Maple-DMA trigger select */ reg32 MDTSEL; /* Maple-DMA trigger select */
reg32 MDEN; /* Maple-DMA enable */ reg32 MDEN; /* Maple-DMA enable */
reg32 MDST; /* Maple-DMA start */ reg32 MDST; /* Maple-DMA start */
reg8 _pad1[100]; reg8 _pad2[100];
reg32 MSYS; /* Maple system control */ reg32 MSYS; /* Maple system control */
reg32 MST; /* Maple status */ reg32 MST; /* Maple status */
reg32 MSHTCL; /* Maple-DMA hard trigger clear */ reg32 MSHTCL; /* Maple-DMA hard trigger clear */
reg32 MDAPRO; /* Maple-DMA address range */ reg32 MDAPRO; /* Maple-DMA address range */
reg8 _pad2[88]; reg8 _pad3[88];
reg32 MMSEL; /* Maple MSP selection */ reg32 MMSEL; /* Maple MSP selection */
reg8 _pad3[8]; reg8 _pad4[8];
reg32 MTXDAD; /* Maple TXD address counter */ reg32 MTXDAD; /* Maple TXD address counter */
reg32 MRXDAD; /* Maple RXD address counter */ reg32 MRXDAD; /* Maple RXD address counter */
reg32 MRXDBD; /* Maple RXD address base */ reg32 MRXDBD; /* Maple RXD address base */
}; };
static_assert((offsetof (struct maple_if_reg, MDSTAR)) == 0x0); static_assert((offsetof (struct maple_if_reg, MDSTAR)) == 0x4);
static_assert((offsetof (struct maple_if_reg, MDTSEL)) == 0xc); static_assert((offsetof (struct maple_if_reg, MDTSEL)) == 0x10);
static_assert((offsetof (struct maple_if_reg, MDEN)) == 0x10); static_assert((offsetof (struct maple_if_reg, MDEN)) == 0x14);
static_assert((offsetof (struct maple_if_reg, MDST)) == 0x14); static_assert((offsetof (struct maple_if_reg, MDST)) == 0x18);
static_assert((offsetof (struct maple_if_reg, MSYS)) == 0x7c); static_assert((offsetof (struct maple_if_reg, MSYS)) == 0x80);
static_assert((offsetof (struct maple_if_reg, MST)) == 0x80); static_assert((offsetof (struct maple_if_reg, MST)) == 0x84);
static_assert((offsetof (struct maple_if_reg, MSHTCL)) == 0x84); static_assert((offsetof (struct maple_if_reg, MSHTCL)) == 0x88);
static_assert((offsetof (struct maple_if_reg, MDAPRO)) == 0x88); static_assert((offsetof (struct maple_if_reg, MDAPRO)) == 0x8c);
static_assert((offsetof (struct maple_if_reg, MMSEL)) == 0xe4); static_assert((offsetof (struct maple_if_reg, MMSEL)) == 0xe8);
static_assert((offsetof (struct maple_if_reg, MTXDAD)) == 0xf0); static_assert((offsetof (struct maple_if_reg, MTXDAD)) == 0xf4);
static_assert((offsetof (struct maple_if_reg, MRXDAD)) == 0xf4); static_assert((offsetof (struct maple_if_reg, MRXDAD)) == 0xf8);
static_assert((offsetof (struct maple_if_reg, MRXDBD)) == 0xf8); static_assert((offsetof (struct maple_if_reg, MRXDBD)) == 0xfc);
struct g1_if_reg { struct g1_if_reg {
reg8 _pad0[4];
reg32 GDSTAR; /* GD-DMA start address */ reg32 GDSTAR; /* GD-DMA start address */
reg32 GDLEN; /* GD-DMA length */ reg32 GDLEN; /* GD-DMA length */
reg32 GDDIR; /* GD-DMA direction */ reg32 GDDIR; /* GD-DMA direction */
reg8 _pad0[4]; reg8 _pad1[4];
reg32 GDEN; /* GD-DMA enable */ reg32 GDEN; /* GD-DMA enable */
reg32 GDST; /* GD-DMA start */ reg32 GDST; /* GD-DMA start */
reg8 _pad1[100]; reg8 _pad2[100];
reg32 G1RRC; /* System ROM read access timing */ reg32 G1RRC; /* System ROM read access timing */
reg32 G1RWC; /* System ROM write access timing */ reg32 G1RWC; /* System ROM write access timing */
reg32 G1FRC; /* Flash ROM read access timing */ reg32 G1FRC; /* Flash ROM read access timing */
reg32 G1FWC; /* Flash ROM write access timing */ reg32 G1FWC; /* Flash ROM write access timing */
reg32 G1CRC; /* GD PIO read access timing */ reg32 G1CRC; /* GD PIO read access timing */
reg32 G1CWC; /* GD PIO write access timing */ reg32 G1CWC; /* GD PIO write access timing */
reg8 _pad2[8]; reg8 _pad3[8];
reg32 G1GDRC; /* GD-DMA read access timing */ reg32 G1GDRC; /* GD-DMA read access timing */
reg32 G1GDWC; /* GD-DMA write access timing */ reg32 G1GDWC; /* GD-DMA write access timing */
reg8 _pad3[8]; reg8 _pad4[8];
reg32 G1SYSM; /* System mode */ reg32 G1SYSM; /* System mode */
reg32 G1CRDYC; /* G1IORDY signal control */ reg32 G1CRDYC; /* G1IORDY signal control */
reg32 GDAPRO; /* GD-DMA address range */ reg32 GDAPRO; /* GD-DMA address range */
reg8 _pad4[56]; reg8 _pad5[56];
reg32 GDSTARD; /* GD-DMA address count (on Root Bus) */ reg32 GDSTARD; /* GD-DMA address count (on Root Bus) */
reg32 GDLEND; /* GD-DMA transfer counter */ reg32 GDLEND; /* GD-DMA transfer counter */
}; };
static_assert((offsetof (struct g1_if_reg, GDSTAR)) == 0x0); static_assert((offsetof (struct g1_if_reg, GDSTAR)) == 0x4);
static_assert((offsetof (struct g1_if_reg, GDLEN)) == 0x4); static_assert((offsetof (struct g1_if_reg, GDLEN)) == 0x8);
static_assert((offsetof (struct g1_if_reg, GDDIR)) == 0x8); static_assert((offsetof (struct g1_if_reg, GDDIR)) == 0xc);
static_assert((offsetof (struct g1_if_reg, GDEN)) == 0x10); static_assert((offsetof (struct g1_if_reg, GDEN)) == 0x14);
static_assert((offsetof (struct g1_if_reg, GDST)) == 0x14); static_assert((offsetof (struct g1_if_reg, GDST)) == 0x18);
static_assert((offsetof (struct g1_if_reg, G1RRC)) == 0x7c); static_assert((offsetof (struct g1_if_reg, G1RRC)) == 0x80);
static_assert((offsetof (struct g1_if_reg, G1RWC)) == 0x80); static_assert((offsetof (struct g1_if_reg, G1RWC)) == 0x84);
static_assert((offsetof (struct g1_if_reg, G1FRC)) == 0x84); static_assert((offsetof (struct g1_if_reg, G1FRC)) == 0x88);
static_assert((offsetof (struct g1_if_reg, G1FWC)) == 0x88); static_assert((offsetof (struct g1_if_reg, G1FWC)) == 0x8c);
static_assert((offsetof (struct g1_if_reg, G1CRC)) == 0x8c); static_assert((offsetof (struct g1_if_reg, G1CRC)) == 0x90);
static_assert((offsetof (struct g1_if_reg, G1CWC)) == 0x90); static_assert((offsetof (struct g1_if_reg, G1CWC)) == 0x94);
static_assert((offsetof (struct g1_if_reg, G1GDRC)) == 0x9c); static_assert((offsetof (struct g1_if_reg, G1GDRC)) == 0xa0);
static_assert((offsetof (struct g1_if_reg, G1GDWC)) == 0xa0); static_assert((offsetof (struct g1_if_reg, G1GDWC)) == 0xa4);
static_assert((offsetof (struct g1_if_reg, G1SYSM)) == 0xac); static_assert((offsetof (struct g1_if_reg, G1SYSM)) == 0xb0);
static_assert((offsetof (struct g1_if_reg, G1CRDYC)) == 0xb0); static_assert((offsetof (struct g1_if_reg, G1CRDYC)) == 0xb4);
static_assert((offsetof (struct g1_if_reg, GDAPRO)) == 0xb4); static_assert((offsetof (struct g1_if_reg, GDAPRO)) == 0xb8);
static_assert((offsetof (struct g1_if_reg, GDSTARD)) == 0xf0); static_assert((offsetof (struct g1_if_reg, GDSTARD)) == 0xf4);
static_assert((offsetof (struct g1_if_reg, GDLEND)) == 0xf4); static_assert((offsetof (struct g1_if_reg, GDLEND)) == 0xf8);
struct g2_if_reg { struct g2_if_reg {
reg32 ADSTAG; /* ACIA:G2-DMA G2 start address */ reg32 ADSTAG; /* ACIA:G2-DMA G2 start address */
@ -302,11 +304,7 @@ static_assert((offsetof (struct pvr_if_reg, PDSTARD)) == 0xf4);
static_assert((offsetof (struct pvr_if_reg, PDLEND)) == 0xf8); static_assert((offsetof (struct pvr_if_reg, PDLEND)) == 0xf8);
extern struct system_reg system __asm("system"); extern struct system_reg system __asm("system");
extern struct maple_if_reg maple_if __asm("maple_if"); extern struct maple_if_reg maple_if __asm("maple_if");
extern struct g1_if_reg g1_if __asm("g1_if"); extern struct g1_if_reg g1_if __asm("g1_if");
extern struct g2_if_reg g2_if __asm("g2_if"); extern struct g2_if_reg g2_if __asm("g2_if");
extern struct pvr_if_reg pvr_if __asm("pvr_if"); extern struct pvr_if_reg pvr_if __asm("pvr_if");