64 for (index = 0; index <= 1; index++) {
114 volatile u32 *siocnt;
123 u8 mask30 = control & 0x30;
126 if (mask30 == 0 && (
mode = control & 0x88) == 8) {
127 u8 serialError = control & 4;
138 *((
volatile s8 *)siocnt + 1) &= ~0x40;
143 }
else if (mask30 == 0) {
160 if (((control << 26) >> 30) > 1)
169 volatile u32 *siocnt;
180 u8 serialError = control & 4;
191 *((
volatile s8 *)siocnt + 1) &= ~0x40;
205 if (((control << 26) >> 30) > 1)
219 volatile u32 *siocnt;
236 if (((control << 26) >> 30) > 1)
266 *(
u16 *)(pkt + 2) = sum;
310 *(
u32 *)&flags[4] = 0;
313 for (i = 0; i <= 3; i++) {
322 for (i = 0; i <= 1; i++) {
327 if (flags[i] == 1 && (
s16)sum == -1) {
351 volatile u32 *sioControl;
370 sendState->
isParent = (*sioControl << 25) >> 31;
373 u32 idleWord = SERIAL_IDLE_HALFWORD;
376 ((volatile u16 *)sioControl)[1] = idleWord;
377 swap = sendState->sendBuffer[1];
378 sendState->sendBuffer[1] = sendState->sendBuffer[0];
379 sendState->sendBuffer[0] = swap;
381 ((volatile u16 *)sioControl)[1] =
382 sendState->sendBuffer[1][sendState->sendIndex];
395 if (recv[channel] == SERIAL_IDLE_HALFWORD &&
396 receiveState->receiveIndex[channel] >= SERIAL_PACKET_HALFWORDS) {
397 receiveState->receiveIndex[channel] = -1;
399 receiveIndex = receiveState->receiveIndex[channel];
400 incoming = receiveState->incomingBuffer[channel];
401 incoming[receiveIndex] = recv[channel];
402 if (receiveIndex == SERIAL_PACKET_HALFWORDS - 1) {
403 u16 *swap = receiveState->readyBuffer[channel];
405 receiveState->readyBuffer[channel] = incoming;
406 receiveState->incomingBuffer[channel] = swap;
407 receiveState->channelFlags[channel] |= 1;
412 if (tailState->isParent != 0)
415 tailState->receiveIndex[channel]++;
417 receiveState = tailState;
421 if (tailState->mode == 8) {
423 REG_SIOCNT16 |= SIO_START;
424 REG_TM3CNT_H = TIMER_ENABLE | TIMER_INTR_ENABLE;
456 u32 savedInterruptMaster;
476 u32 savedInterruptMaster;
492#define SERIAL_DEFINE_WAIT(name, pending) \
496 if (pending != 0) { \
500 } while (count < SERIAL_TRANSFER_TIMEOUT_FRAMES && pending != 0); \
601 }
else if (own->
active == 1) {
619 if (peer->
flags == 1) {
620 if (peer->
active & 0x80) {
653 if (own->
flags == 2) {
654 if (peer->peerFlags != 2) {
655 gSerialReceiveDest = 0;
717#undef SERIAL_DEFINE_WAIT
#define Cpu_Fill32(value, destination, size)
pret's CpuFill32: repeats one word through the BIOS CpuSet service.
static __inline__ void Dma_Set(const volatile void *source, volatile void *destination, u32 control, volatile u32 *channel)
Starts a DMA transfer: stores the source, destination and control words into channel's registers with...
#define Dma_Fill32(value, destination, size)
Fills size bytes at destination with the word value by DMA3.
void AudioCommand_PlayFar(s32 id)
void Runtime_SetIrqHandler(u32 irq, s32 vcount, InterruptHandler handler)
Installs handler for interrupt irq and enables that interrupt, or with a null handler disables it and...
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
struct EffectStep gMapCellBuffer[]
Map cells; battle effects reuse this as a particle array.
#define BG_SCREEN_BLOCK(n)
#define RCNT_SIO_MODE
RCNT's mode: 0 leaves the port to SIOCNT's serial modes; bit 15 alone makes it general-purpose pins.
#define TIMER_INTR_ENABLE
TMxCNT_H flags, as pret names them.
#define DMA_COPY_WORDS(n)
#define Io_Write16(v, reg)
Writes a value to a 16-bit register or memory location.
#define IRQ_UNLOCK(saved)
Restores the IME value saved by IRQ_LOCK.
#define IME_DISABLE(ime)
Disables interrupts.
#define IRQ_LOCK(saved)
Disables interrupts and saves IME in saved; IRQ_UNLOCK restores it.
#define IME_SAVE(ime, saved)
Saves the original IME value in saved.
volatile u32 gKeysHeld
Keys down now.
What every part of the runtime object shares: its includes and the library call two parts make.
void SerialRuntime_DisableTransfer(void)
Disables the serial and timer 3 interrupts, stops the transfer timer and clears gSerialRuntime....
void SerialRuntime_EnableTransferTimer(void)
Lets the timer start transfers again once a link mode is set, by setting gSerialRuntime....
void SerialRuntime_WaitForSend(void)
s32 SerialRuntime_BeginReceive(void *destination)
Starts receiving the partner's blocks into destination: sets the receive destination and clears the r...
void SerialRuntime_WaitForTransfers(void)
Waits until both the send and the receive have finished, giving up after 600000 frames.
void SerialTest_Delay(void)
An empty routine the link test calls to waste time.
s32 SerialRuntime_BeginSend(void *source, s32 size)
Starts sending size bytes from source to the partner in 20-byte blocks: sets the send source,...
void SerialRuntime_RemoveIrqHandlers(void)
Clears gSerialExchangeActive, which stops the per-frame exchange, and removes the link interrupt hand...
void BattleLink_ResetTransferState(void)
u32 SerialRuntime_WaitForStatusMask(s32 mask)
Waits a frame at a time until every status bit in mask is set in gLinkStatus, then returns this conso...
s32 SerialRuntime_PollStatus(void)
As SerialRuntime_PollAndTransfer, without exchanging data: WaitFrames calls it once a frame while gSe...
void SerialRuntime_WaitForReceive(void)
@ SERIAL_PACKET_HALFWORDS
@ SERIAL_TIMER_RELOAD
Timer 3's reload: 13981 cycles from one halfword transfer to the next.
@ SERIAL_TRANSFER_TIMEOUT_FRAMES
void SerialRuntime_PrepareSendPacket(void *payload)
Builds the packet to send in sendBuffer[0]: [0] the sequence number, [1] the consoles not yet heard f...
s32 SerialRuntime_PollAndTransfer(void *send, void *receive)
Looks for the link partner and, once connected, does one exchange (as SerialRuntime_ExchangePayloads)...
void SerialTest_Run(void)
A link cable test left in the game: it shows a row of tiles, receives blocks into the map cell buffer...
s32 SerialRuntime_GetActiveTransfers(void)
Returns bit 0 while a send runs and bit 1 while a receive runs.
#define SERIAL_DEFINE_WAIT(name, pending)
Each waits a frame at a time until pending is 0, giving up after 600000 frames: the send,...
void SerialRuntime_Initialize(void)
Resets the serial port into multiplayer mode, installs the serial and timer 3 interrupt handlers,...
void SerialRuntime_StepBlockTransfer(void)
Runs each VBlank after the exchange, called by System_VBlankHandler: moves the bulk transfer on by on...
s32 SerialRuntime_ExchangePayloads(void *send, void *receive)
Once connected (phase 1), gathers the received payloads into receive and builds the next packet from ...
u8 SerialRuntime_CollectReceivedPayloads(void *payload)
Swaps in the packets the interrupt handler finished, then copies the payload of each one whose checks...
void SerialRuntime_HandleTransferInterrupt(void)
The serial and timer 3 interrupt, installed by SerialRuntime_Initialize: each one moves a halfword.
volatile u16 gLinkStatus
Link status, updated by the VBlank exchange handler.
volatile u16 gSerialSendSize
volatile: tagged where it steers, in SerialRuntime_StepBlockTransfer (tbs runtime....
static s32 SerialRuntime_AddParentFlag(s32 status)
struct SerialRuntime gSerialRuntime
volatile u8 gSerialBlockSequence
volatile: tagged where it steers, in SerialRuntime_StepBlockTransfer (tbs runtime....
volatile u16 gSerialReceivedSize
volatile: tagged where it steers, in BattleLink_ReceiveActions (tbs battle.c) and LinkLobby_ReceivePa...
u16 gSerialExchangeActive
static __inline__ void SerialRuntime_ResetTransferState(void)
u8 gSerialPeerPayloads[4][24]
struct SerialTransferState gSerialTransfer
A link cable packet: its sequence number, the consoles not yet heard from, its checksum and a 24-byte...
u16 checksum
The complement of the sum of the packet's first 14 halfwords, taken with this field 0.
The link cable's runtime: its mode and phase, the consoles heard from, the send position and the pack...
u8 storage[0x100]
The buffers' memory: two 32-byte send buffers, then 96 bytes a console for its incoming,...
u8 mode
SIOCNT's bits 7 and 3 when this console armed timer 3 to clock the transfers: 8 then,...
u16 * readyBuffer[4]
Each console's last complete packet, swapped in by the interrupt.
u16 * sendBuffer[2]
The packet being built ([0]) and the packet being sent ([1]).
u8 channelFlags[4]
Set by the interrupt for each console and cleared each frame.
s32 sendIndex
The halfword of sendBuffer[1] sent next; -1 between packets, when 0xfefe is sent and the two send buf...
u8 transferEnabled
Nonzero lets a new packet restart timer 3.
u8 phase
0 looking for the partner, 1 connected
u16 * incomingBuffer[4]
Each console's packet being received; two are used.
u8 currentMask
the consoles heard from this frame
u8 sequence
The packet sequence number, counted up each frame once connected.
u16 * pendingBuffer[4]
The packets the frame code checks and copies, swapped with readyBuffer each frame.
u8 isParent
SIOCNT's bit 6, copied by each transfer interrupt; nonzero adds 0x1000 to the link status.
u8 receivedMask
the consoles heard from since the link began
A console's block transfer state, exchanged with the partner each VBlank: its block sequence,...
u8 peerFlags
The send state: 1 a block with more to follow, 2 the last block, 0 idle.
u8 flags
The receive state: 1 receiving, 2 the last block taken, 0 idle.
u8 status
0x80 sending or 0x81 receiving when started; the receiver counts blocks (status + 1,...
u8 payload[20]
one block of the data sent
u8 active
The sequence number of the block in payload; as receiver, the one it expects with bit 7 set to ask fo...