Restructure
This commit is contained in:
112
src/backend/core/mmio/AI.cpp
Normal file
112
src/backend/core/mmio/AI.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include <core/mmio/AI.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <core/Audio.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void AI::Reset() {
|
||||
dmaEnable = 0;
|
||||
dacRate = 0;
|
||||
bitrate = 0;
|
||||
dmaCount = 0;
|
||||
dmaAddrCarry = false;
|
||||
cycles = 0;
|
||||
memset(dmaLen, 0, 2);
|
||||
memset(dmaAddr, 0, 2);
|
||||
dac = {44100, N64_CPU_FREQ / dac.freq, 16};
|
||||
}
|
||||
|
||||
auto AI::Read(u32 addr) const -> u32 {
|
||||
if(addr == 0x0450000C) {
|
||||
u32 val = 0;
|
||||
val |= (dmaCount > 1);
|
||||
val |= 1 << 20;
|
||||
val |= 1 << 24;
|
||||
val |= (dmaEnable << 25);
|
||||
val |= (dmaCount > 0) << 30;
|
||||
val |= (dmaCount > 1) << 31;
|
||||
return val;
|
||||
}
|
||||
|
||||
return dmaLen[0];
|
||||
}
|
||||
|
||||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
switch(addr) {
|
||||
case 0x04500000:
|
||||
if(dmaCount < 2) {
|
||||
dmaAddr[dmaCount] = val & 0xFFFFFF & ~7;
|
||||
}
|
||||
break;
|
||||
case 0x04500004: {
|
||||
u32 len = (val & 0x3FFFF) & ~7;
|
||||
if((dmaCount < 2) && len) {
|
||||
// if(dmaCount == 0) InterruptRaise(mem.mmio.mi, regs, Interrupt::AI);
|
||||
dmaLen[dmaCount] = len;
|
||||
dmaCount++;
|
||||
}
|
||||
} break;
|
||||
case 0x04500008:
|
||||
dmaEnable = val & 1;
|
||||
break;
|
||||
case 0x0450000C:
|
||||
InterruptLower(mem.mmio.mi, regs, Interrupt::AI);
|
||||
break;
|
||||
case 0x04500010: {
|
||||
u32 old_dac_freq = dac.freq;
|
||||
dacRate = val & 0x3FFF;
|
||||
dac.freq = max(1, N64_CPU_FREQ / 2 / (dacRate + 1)) * 1.037;
|
||||
dac.period = N64_CPU_FREQ / dac.freq;
|
||||
if(old_dac_freq != dac.freq) {
|
||||
AdjustSampleRate(dac.freq);
|
||||
}
|
||||
} break;
|
||||
case 0x04500014:
|
||||
bitrate = val & 0xF;
|
||||
dac.precision = bitrate + 1;
|
||||
break;
|
||||
default:
|
||||
util::panic("Unhandled AI write at addr {:08X} with val {:08X}\n", addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
void AI::Step(Mem& mem, Registers& regs, int cpuCycles, float volumeL, float volumeR) {
|
||||
cycles += cpuCycles;
|
||||
while(cycles > dac.period) {
|
||||
if (dmaCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(dmaLen[0] && dmaEnable) {
|
||||
if(volumeR > 0 && volumeL > 0) {
|
||||
u32 addrHi = ((dmaAddr[0] >> 13) + dmaAddrCarry) & 0x7FF;
|
||||
dmaAddr[0] = (addrHi << 13) | (dmaAddr[0] & 0x1FFF);
|
||||
u32 data = util::ReadAccess<u32>(mem.mmio.rdp.rdram.data(), dmaAddr[0] & RDRAM_DSIZE);
|
||||
s16 l = s16(data >> 16);
|
||||
s16 r = s16(data);
|
||||
|
||||
PushSample((float) l / INT16_MAX, volumeL, (float) r / INT16_MAX, volumeR);
|
||||
|
||||
u32 addrLo = (dmaAddr[0] + 4) & 0x1FFF;
|
||||
dmaAddr[0] = (dmaAddr[0] & ~0x1FFF) | addrLo;
|
||||
dmaAddrCarry = addrLo == 0;
|
||||
}
|
||||
dmaLen[0] -= 4;
|
||||
}
|
||||
|
||||
if(!dmaLen[0]) {
|
||||
if(--dmaCount > 0) {
|
||||
InterruptRaise(mem.mmio.mi, regs, Interrupt::AI);
|
||||
dmaAddr[0] = dmaAddr[1];
|
||||
dmaLen[0] = dmaLen[1];
|
||||
}
|
||||
}
|
||||
|
||||
cycles -= dac.period;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
30
src/backend/core/mmio/AI.hpp
Normal file
30
src/backend/core/mmio/AI.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
struct Mem;
|
||||
struct Registers;
|
||||
|
||||
struct AI {
|
||||
AI() = default;
|
||||
void Reset();
|
||||
auto Read(u32) const -> u32;
|
||||
void Write(Mem&, Registers&, u32, u32);
|
||||
void Step(Mem&, Registers&, int, float, float);
|
||||
bool dmaEnable{};
|
||||
u16 dacRate{};
|
||||
u8 bitrate{};
|
||||
int dmaCount{};
|
||||
u32 dmaLen[2]{};
|
||||
u32 dmaAddr[2]{};
|
||||
bool dmaAddrCarry{};
|
||||
int cycles{};
|
||||
|
||||
struct {
|
||||
u32 freq{44100};
|
||||
u32 period{N64_CPU_FREQ / freq};
|
||||
u32 precision{16};
|
||||
} dac;
|
||||
};
|
||||
}
|
||||
59
src/backend/core/mmio/Interrupt.cpp
Normal file
59
src/backend/core/mmio/Interrupt.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void InterruptRaise(MI &mi, Registers ®s, Interrupt intr) {
|
||||
switch(intr) {
|
||||
case Interrupt::VI:
|
||||
mi.miIntr.vi = true;
|
||||
break;
|
||||
case Interrupt::SI:
|
||||
mi.miIntr.si = true;
|
||||
break;
|
||||
case Interrupt::PI:
|
||||
mi.miIntr.pi = true;
|
||||
break;
|
||||
case Interrupt::AI:
|
||||
mi.miIntr.ai = true;
|
||||
break;
|
||||
case Interrupt::DP:
|
||||
mi.miIntr.dp = true;
|
||||
break;
|
||||
case Interrupt::SP:
|
||||
mi.miIntr.sp = true;
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateInterrupt(mi, regs);
|
||||
}
|
||||
|
||||
void InterruptLower(MI &mi, Registers ®s, Interrupt intr) {
|
||||
switch(intr) {
|
||||
case Interrupt::VI:
|
||||
mi.miIntr.vi = false;
|
||||
break;
|
||||
case Interrupt::SI:
|
||||
mi.miIntr.si = false;
|
||||
break;
|
||||
case Interrupt::PI:
|
||||
mi.miIntr.pi = false;
|
||||
break;
|
||||
case Interrupt::AI:
|
||||
mi.miIntr.ai = false;
|
||||
break;
|
||||
case Interrupt::DP:
|
||||
mi.miIntr.dp = false;
|
||||
break;
|
||||
case Interrupt::SP:
|
||||
mi.miIntr.sp = false;
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateInterrupt(mi, regs);
|
||||
}
|
||||
void UpdateInterrupt(MI &mi, Registers ®s) {
|
||||
bool interrupt = mi.miIntr.raw & mi.miIntrMask.raw;
|
||||
regs.cop0.cause.ip2 = interrupt;
|
||||
}
|
||||
}
|
||||
16
src/backend/core/mmio/Interrupt.hpp
Normal file
16
src/backend/core/mmio/Interrupt.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
struct Registers;
|
||||
|
||||
enum class Interrupt : u8 {
|
||||
VI, SI, PI, AI, DP, SP
|
||||
};
|
||||
|
||||
void InterruptRaise(MI &mi, Registers ®s, Interrupt intr);
|
||||
void InterruptLower(MI &mi, Registers ®s, Interrupt intr);
|
||||
void UpdateInterrupt(MI &mi, Registers ®s);
|
||||
}
|
||||
84
src/backend/core/mmio/MI.cpp
Normal file
84
src/backend/core/mmio/MI.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
#define MI_VERSION_REG 0x02020102
|
||||
|
||||
namespace n64 {
|
||||
MI::MI() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void MI::Reset() {
|
||||
miIntrMask.raw = 0;
|
||||
miIntr.raw = 0;
|
||||
miMode = 0;
|
||||
}
|
||||
|
||||
auto MI::Read(u32 paddr) const -> u32 {
|
||||
switch(paddr & 0xF) {
|
||||
case 0x0: return miMode & 0x3FF;
|
||||
case 0x4: return MI_VERSION_REG;
|
||||
case 0x8: return miIntr.raw & 0x3F;
|
||||
case 0xC: return miIntrMask.raw & 0x3F;
|
||||
default:
|
||||
util::panic("Unhandled MI[{:08X}] read\n", paddr);
|
||||
}
|
||||
}
|
||||
|
||||
void MI::Write(Registers& regs, u32 paddr, u32 val) {
|
||||
switch(paddr & 0xF) {
|
||||
case 0x0:
|
||||
miMode &= 0xFFFFFF80;
|
||||
miMode |= val & 0x7F;
|
||||
if (val & (1 << 7)) {
|
||||
miMode &= ~(1 << 7);
|
||||
}
|
||||
|
||||
if (val & (1 << 8)) {
|
||||
miMode |= 1 << 7;
|
||||
}
|
||||
|
||||
if (val & (1 << 9)) {
|
||||
miMode &= ~(1 << 8);
|
||||
}
|
||||
|
||||
if (val & (1 << 10)) {
|
||||
miMode |= 1 << 8;
|
||||
}
|
||||
|
||||
if (val & (1 << 11)) {
|
||||
InterruptLower(*this, regs, Interrupt::DP);
|
||||
}
|
||||
|
||||
if (val & (1 << 12)) {
|
||||
miMode &= ~(1 << 9);
|
||||
}
|
||||
|
||||
if (val & (1 << 13)) {
|
||||
miMode |= 1 << 9;
|
||||
}
|
||||
break;
|
||||
case 0x4: break;
|
||||
case 0xC:
|
||||
for (int bit = 0; bit < 6; bit++) {
|
||||
int clearbit = bit << 1;
|
||||
int setbit = (bit << 1) + 1;
|
||||
|
||||
if (val & (1 << clearbit)) {
|
||||
miIntrMask.raw &= ~(1 << bit);
|
||||
}
|
||||
|
||||
if (val & (1 << setbit)) {
|
||||
miIntrMask.raw |= 1 << bit;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateInterrupt(*this, regs);
|
||||
break;
|
||||
default:
|
||||
util::panic("Unhandled MI[{:08X}] write ({:08X})\n", val, paddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/backend/core/mmio/MI.hpp
Normal file
30
src/backend/core/mmio/MI.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
union MIIntr {
|
||||
struct {
|
||||
unsigned sp: 1;
|
||||
unsigned si: 1;
|
||||
unsigned ai: 1;
|
||||
unsigned vi: 1;
|
||||
unsigned pi: 1;
|
||||
unsigned dp: 1;
|
||||
unsigned: 26;
|
||||
};
|
||||
u32 raw;
|
||||
};
|
||||
|
||||
struct Registers;
|
||||
|
||||
struct MI {
|
||||
MI();
|
||||
void Reset();
|
||||
[[nodiscard]] auto Read(u32) const -> u32;
|
||||
void Write(Registers& regs, u32, u32);
|
||||
|
||||
u32 miMode;
|
||||
MIIntr miIntr{}, miIntrMask{};
|
||||
};
|
||||
}
|
||||
90
src/backend/core/mmio/PI.cpp
Normal file
90
src/backend/core/mmio/PI.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <core/mmio/PI.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
PI::PI() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void PI::Reset() {
|
||||
dramAddr = 0;
|
||||
cartAddr = 0;
|
||||
rdLen = 0;
|
||||
wrLen = 0;
|
||||
memset(stub, 0, 8);
|
||||
}
|
||||
|
||||
auto PI::Read(MI& mi, u32 addr) const -> u32 {
|
||||
switch(addr) {
|
||||
case 0x04600000: return dramAddr;
|
||||
case 0x04600004: return cartAddr;
|
||||
case 0x04600008: return rdLen;
|
||||
case 0x0460000C: return wrLen;
|
||||
case 0x04600010: {
|
||||
u32 value = 0;
|
||||
value |= (0 << 0); // Is PI DMA active? No, because it's instant
|
||||
value |= (0 << 1); // Is PI IO busy? No, because it's instant
|
||||
value |= (0 << 2); // PI IO error?
|
||||
value |= (mi.miIntr.pi << 3); // PI interrupt?
|
||||
return value;
|
||||
}
|
||||
case 0x04600014: case 0x04600018: case 0x0460001C: case 0x04600020:
|
||||
case 0x04600024: case 0x04600028: case 0x0460002C: case 0x04600030:
|
||||
return stub[(addr & 0xff) - 5];
|
||||
default:
|
||||
util::panic("Unhandled PI[{:08X}] read\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
MI& mi = mem.mmio.mi;
|
||||
switch(addr) {
|
||||
case 0x04600000: dramAddr = val & 0xFFFFFF; break;
|
||||
case 0x04600004: cartAddr = val; break;
|
||||
case 0x04600008: {
|
||||
u32 len = (val & 0x00FFFFFF) + 1;
|
||||
u32 cart_addr = cartAddr & 0xFFFFFFFE;
|
||||
u32 dram_addr = dramAddr & 0x007FFFFE;
|
||||
if (dram_addr & 0x7) {
|
||||
len -= dram_addr & 0x7;
|
||||
}
|
||||
rdLen = len;
|
||||
for(int i = 0; i < len; i++) {
|
||||
mem.cart[BYTE_ADDRESS(cart_addr + i) & mem.romMask] = mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE];
|
||||
}
|
||||
dramAddr = dram_addr + len;
|
||||
cartAddr = cart_addr + len;
|
||||
InterruptRaise(mi, regs, Interrupt::PI);
|
||||
//util::print("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})\n", len, dramAddr, cartAddr);
|
||||
} break;
|
||||
case 0x0460000C: {
|
||||
u32 len = (val & 0x00FFFFFF) + 1;
|
||||
u32 cart_addr = cartAddr & 0xFFFFFFFE;
|
||||
u32 dram_addr = dramAddr & 0x007FFFFE;
|
||||
if (dram_addr & 0x7) {
|
||||
len -= (dram_addr & 0x7);
|
||||
}
|
||||
wrLen = len;
|
||||
for(int i = 0; i < len; i++) {
|
||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE] = mem.cart[BYTE_ADDRESS(cart_addr + i) & mem.romMask];
|
||||
}
|
||||
dramAddr = dram_addr + len;
|
||||
cartAddr = cart_addr + len;
|
||||
InterruptRaise(mi, regs, Interrupt::PI);
|
||||
//util::print("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})\n", len, cart_addr, dram_addr);
|
||||
} break;
|
||||
case 0x04600010:
|
||||
if(val & 2) {
|
||||
InterruptLower(mi, regs, Interrupt::PI);
|
||||
} break;
|
||||
case 0x04600014: case 0x04600018: case 0x0460001C: case 0x04600020:
|
||||
case 0x04600024: case 0x04600028: case 0x0460002C: case 0x04600030:
|
||||
stub[(addr & 0xff) - 5] = val & 0xff;
|
||||
break;
|
||||
default:
|
||||
util::panic("Unhandled PI[{:08X}] write ({:08X})\n", val, addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/backend/core/mmio/PI.hpp
Normal file
19
src/backend/core/mmio/PI.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
struct Mem;
|
||||
struct Registers;
|
||||
|
||||
struct PI {
|
||||
PI();
|
||||
void Reset();
|
||||
auto Read(MI&, u32) const -> u32;
|
||||
void Write(Mem&, Registers&, u32, u32);
|
||||
u32 dramAddr{}, cartAddr{};
|
||||
u32 rdLen{}, wrLen{};
|
||||
u32 stub[8]{};
|
||||
};
|
||||
}
|
||||
277
src/backend/core/mmio/PIF.cpp
Normal file
277
src/backend/core/mmio/PIF.cpp
Normal file
@@ -0,0 +1,277 @@
|
||||
#include <core/mmio/PIF.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <log.hpp>
|
||||
#include <MupenMovie.hpp>
|
||||
|
||||
namespace n64 {
|
||||
static int channel = 0;
|
||||
|
||||
void ProcessPIFCommands(u8* pifRam, Controller& controller, Mem& mem) {
|
||||
u8 control = pifRam[63];
|
||||
|
||||
if(control & 1) {
|
||||
channel = 0;
|
||||
for(int i = 0; i < 63;) {
|
||||
u8* cmd = &pifRam[i++];
|
||||
u8 t = cmd[0] & 0x3f;
|
||||
|
||||
if(t == 0 || t == 0x3D) {
|
||||
channel++;
|
||||
} else if (t == 0x3E) {
|
||||
break;
|
||||
} else if (t == 0x3F) {
|
||||
continue;
|
||||
} else {
|
||||
u8 r = pifRam[i++];
|
||||
r |= (1 << 7);
|
||||
if(r == 0xFE) {
|
||||
break;
|
||||
}
|
||||
|
||||
u8 rlen = r & 0x3F;
|
||||
u8* res = &pifRam[i + t];
|
||||
switch(cmd[2]) {
|
||||
case 0xff:
|
||||
res[0] = 0x05;
|
||||
res[1] = 0x00;
|
||||
res[2] = 0x01;
|
||||
channel++;
|
||||
break;
|
||||
case 0:
|
||||
res[0] = 0x05;
|
||||
res[1] = 0x00;
|
||||
res[2] = 0x01;
|
||||
break;
|
||||
case 1:
|
||||
if(tas_movie_loaded()) {
|
||||
controller = tas_next_inputs();
|
||||
}
|
||||
res[0] = controller.byte1;
|
||||
res[1] = controller.byte2;
|
||||
res[2] = controller.joy_x;
|
||||
res[3] = controller.joy_y;
|
||||
break;
|
||||
case 2: case 3: res[0] = 0; break;
|
||||
default: util::panic("Unimplemented PIF command {}", cmd[2]);
|
||||
}
|
||||
|
||||
i += t + rlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(control & 8) {
|
||||
pifRam[63] &= ~8;
|
||||
}
|
||||
|
||||
if (control & 0x30) {
|
||||
pifRam[63] = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo) {
|
||||
u32 cicType = cartInfo.cicType;
|
||||
bool pal = cartInfo.isPAL;
|
||||
mem.Write32<false>(regs, 0x1FC007E4, cicSeeds[cicType], regs.pc);
|
||||
|
||||
switch(cicType) {
|
||||
case CIC_NUS_6101:
|
||||
mem.Write32<false>(regs, 0x318, RDRAM_SIZE, regs.pc);
|
||||
regs.gpr[2] = (s64)0xFFFFFFFFDF6445CC;
|
||||
regs.gpr[3] = (s64)0xFFFFFFFFDF6445CC;
|
||||
regs.gpr[4] = 0x45CC;
|
||||
regs.gpr[5] = 0x73EE317A;
|
||||
regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C;
|
||||
regs.gpr[7] = (s64)0xFFFFFFFFA4001F08;
|
||||
regs.gpr[8] = 0xC0;
|
||||
regs.gpr[10] = 0x40;
|
||||
regs.gpr[11] = (s64)0xFFFFFFFFA4000040;
|
||||
regs.gpr[12] = (s64)0xFFFFFFFFC7601FAC;
|
||||
regs.gpr[13] = (s64)0xFFFFFFFFC7601FAC;
|
||||
regs.gpr[14] = (s64)0xFFFFFFFFB48E2ED6;
|
||||
regs.gpr[15] = (s64)0xFFFFFFFFBA1A7D4B;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[22] = 0x000000000000003F;
|
||||
regs.gpr[23] = 0x0000000000000001;
|
||||
regs.gpr[24] = 0x0000000000000002;
|
||||
regs.gpr[25] = (s64)0xFFFFFFFF905F4718;
|
||||
regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0;
|
||||
regs.gpr[31] = (s64)0xFFFFFFFFA4001550;
|
||||
regs.lo = (s64)0xFFFFFFFFBA1A7D4B;
|
||||
regs.hi = (s64)0xFFFFFFFF997EC317;
|
||||
break;
|
||||
case CIC_NUS_7102:
|
||||
mem.Write32<false>(regs, 0x318, RDRAM_SIZE, regs.pc);
|
||||
regs.gpr[1] = 0x0000000000000001;
|
||||
regs.gpr[2] = 0x000000001E324416;
|
||||
regs.gpr[3] = 0x000000001E324416;
|
||||
regs.gpr[4] = 0x0000000000004416;
|
||||
regs.gpr[5] = 0x000000000EC5D9AF;
|
||||
regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C;
|
||||
regs.gpr[7] = (s64)0xFFFFFFFFA4001F08;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = (s64)0xFFFFFFFFA4000040;
|
||||
regs.gpr[12] = 0x00000000495D3D7B;
|
||||
regs.gpr[13] = (s64)0xFFFFFFFF8B3DFA1E;
|
||||
regs.gpr[14] = 0x000000004798E4D4;
|
||||
regs.gpr[15] = (s64)0xFFFFFFFFF1D30682;
|
||||
regs.gpr[22] = 0x000000000000003F;
|
||||
regs.gpr[23] = 0x0000000000000007;
|
||||
regs.gpr[25] = 0x0000000013D05CAB;
|
||||
regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0;
|
||||
regs.gpr[31] = (s64)0xFFFFFFFFA4001554;
|
||||
|
||||
regs.lo = (s64)0xFFFFFFFFF1D30682;
|
||||
regs.hi = 0x0000000010054A98;
|
||||
break;
|
||||
case CIC_NUS_6102_7101:
|
||||
mem.Write32<false>(regs, 0x318, RDRAM_SIZE, regs.pc);
|
||||
regs.gpr[1] = 0x0000000000000001;
|
||||
regs.gpr[2] = 0x000000000EBDA536;
|
||||
regs.gpr[3] = 0x000000000EBDA536;
|
||||
regs.gpr[4] = 0x000000000000A536;
|
||||
regs.gpr[5] = (s64)0xFFFFFFFFC0F1D859;
|
||||
regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C;
|
||||
regs.gpr[7] = (s64)0xFFFFFFFFA4001F08;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = (s64)0xFFFFFFFFA4000040;
|
||||
regs.gpr[12] = (s64)0xFFFFFFFFED10D0B3;
|
||||
regs.gpr[13] = 0x000000001402A4CC;
|
||||
regs.gpr[14] = 0x000000002DE108EA;
|
||||
regs.gpr[15] = 0x000000003103E121;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[25] = (s64)0xFFFFFFFF9DEBB54F;
|
||||
regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0;
|
||||
regs.gpr[31] = (s64)0xFFFFFFFFA4001550;
|
||||
|
||||
regs.hi = 0x000000003FC18657;
|
||||
regs.lo = 0x000000003103E121;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = (s64)0xFFFFFFFFA4001554;
|
||||
}
|
||||
break;
|
||||
case CIC_NUS_6103_7103:
|
||||
mem.Write32<false>(regs, 0x318, RDRAM_SIZE, regs.pc);
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000001;
|
||||
regs.gpr[2] = 0x0000000049A5EE96;
|
||||
regs.gpr[3] = 0x0000000049A5EE96;
|
||||
regs.gpr[4] = 0x000000000000EE96;
|
||||
regs.gpr[5] = (s64)0xFFFFFFFFD4646273;
|
||||
regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C;
|
||||
regs.gpr[7] = (s64)0xFFFFFFFFA4001F08;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = (s64)0xFFFFFFFFA4000040;
|
||||
regs.gpr[12] = (s64)0xFFFFFFFFCE9DFBF7;
|
||||
regs.gpr[13] = (s64)0xFFFFFFFFCE9DFBF7;
|
||||
regs.gpr[14] = 0x000000001AF99984;
|
||||
regs.gpr[15] = 0x0000000018B63D28;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000000;
|
||||
regs.gpr[24] = 0x0000000000000000;
|
||||
regs.gpr[25] = (s64)0xFFFFFFFF825B21C9;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = (s64)0xFFFFFFFFA4001550;
|
||||
|
||||
regs.lo = 0x0000000018B63D28;
|
||||
regs.hi = 0x00000000625C2BBE;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = (s64)0xFFFFFFFFA4001554;
|
||||
}
|
||||
break;
|
||||
case CIC_NUS_6105_7105:
|
||||
mem.Write32<false>(regs, 0x3F0, RDRAM_SIZE, regs.pc);
|
||||
regs.gpr[2] = (s64)0xFFFFFFFFF58B0FBF;
|
||||
regs.gpr[3] = (s64)0xFFFFFFFFF58B0FBF;
|
||||
regs.gpr[4] = 0x0000000000000FBF;
|
||||
regs.gpr[5] = (s64)0xFFFFFFFFDECAAAD1;
|
||||
regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C;
|
||||
regs.gpr[7] = (s64)0xFFFFFFFFA4001F08;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = (s64)0xFFFFFFFFA4000040;
|
||||
regs.gpr[12] = (s64)0xFFFFFFFF9651F81E;
|
||||
regs.gpr[13] = 0x000000002D42AAC5;
|
||||
regs.gpr[14] = 0x00000000489B52CF;
|
||||
regs.gpr[15] = 0x0000000056584D60;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[24] = 0x0000000000000002;
|
||||
regs.gpr[25] = (s64)0xFFFFFFFFCDCE565F;
|
||||
regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0;
|
||||
regs.gpr[31] = (s64)0xFFFFFFFFA4001550;
|
||||
|
||||
regs.lo = 0x0000000056584D60;
|
||||
regs.hi = 0x000000004BE35D1F;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = (s64)0xFFFFFFFFA4001554;
|
||||
}
|
||||
|
||||
mem.Write32<false>(regs, 0x04001000, 0x3C0DBFC0, regs.pc);
|
||||
mem.Write32<false>(regs, 0x04001004, 0x8DA807FC, regs.pc);
|
||||
mem.Write32<false>(regs, 0x04001008, 0x25AD07C0, regs.pc);
|
||||
mem.Write32<false>(regs, 0x0400100C, 0x31080080, regs.pc);
|
||||
mem.Write32<false>(regs, 0x04001000, 0x5500FFFC, regs.pc);
|
||||
mem.Write32<false>(regs, 0x04001004, 0x3C0DBFC0, regs.pc);
|
||||
mem.Write32<false>(regs, 0x04001008, 0x8DA80024, regs.pc);
|
||||
mem.Write32<false>(regs, 0x0400100C, 0x3C0BB000, regs.pc);
|
||||
break;
|
||||
case CIC_NUS_6106_7106:
|
||||
regs.gpr[2] = (s64)0xFFFFFFFFA95930A4;
|
||||
regs.gpr[3] = (s64)0xFFFFFFFFA95930A4;
|
||||
regs.gpr[4] = 0x00000000000030A4;
|
||||
regs.gpr[5] = (s64)0xFFFFFFFFB04DC903;
|
||||
regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C;
|
||||
regs.gpr[7] = (s64)0xFFFFFFFFA4001F08;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = (s64)0xFFFFFFFFA4000040;
|
||||
regs.gpr[12] = (s64)0xFFFFFFFFBCB59510;
|
||||
regs.gpr[13] = (s64)0xFFFFFFFFBCB59510;
|
||||
regs.gpr[14] = 0x000000000CF85C13;
|
||||
regs.gpr[15] = 0x000000007A3C07F4;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[24] = 0x0000000000000002;
|
||||
regs.gpr[25] = 0x00000000465E3F72;
|
||||
regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = (s64)0xFFFFFFFFA4001550;
|
||||
|
||||
regs.lo = 0x000000007A3C07F4;
|
||||
regs.hi = 0x0000000023953898;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = (s64)0xFFFFFFFFA4001554;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
regs.gpr[22] = (cicSeeds[cicType] >> 8) & 0xFF;
|
||||
regs.cop0.Reset();
|
||||
}
|
||||
|
||||
}
|
||||
66
src/backend/core/mmio/PIF.hpp
Normal file
66
src/backend/core/mmio/PIF.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
struct Controller {
|
||||
union {
|
||||
u8 byte1;
|
||||
struct {
|
||||
bool dp_right:1;
|
||||
bool dp_left:1;
|
||||
bool dp_down:1;
|
||||
bool dp_up:1;
|
||||
bool start:1;
|
||||
bool z:1;
|
||||
bool b:1;
|
||||
bool a:1;
|
||||
};
|
||||
};
|
||||
union {
|
||||
u8 byte2;
|
||||
struct {
|
||||
bool c_right:1;
|
||||
bool c_left:1;
|
||||
bool c_down:1;
|
||||
bool c_up:1;
|
||||
bool r:1;
|
||||
bool l:1;
|
||||
bool zero:1;
|
||||
bool joy_reset:1;
|
||||
};
|
||||
};
|
||||
s8 joy_x;
|
||||
s8 joy_y;
|
||||
};
|
||||
|
||||
static_assert(sizeof(Controller) == 4);
|
||||
|
||||
struct Mem;
|
||||
struct Registers;
|
||||
|
||||
const u32 cicSeeds[] = {
|
||||
0x0,
|
||||
0x00043F3F, // CIC_NUS_6101
|
||||
0x00043F3F, // CIC_NUS_7102
|
||||
0x00003F3F, // CIC_NUS_6102_7101
|
||||
0x0000783F, // CIC_NUS_6103_7103
|
||||
0x0000913F, // CIC_NUS_6105_7105
|
||||
0x0000853F, // CIC_NUS_6106_7106
|
||||
};
|
||||
|
||||
enum CICType {
|
||||
UNKNOWN_CIC_TYPE,
|
||||
CIC_NUS_6101,
|
||||
CIC_NUS_7102,
|
||||
CIC_NUS_6102_7101,
|
||||
CIC_NUS_6103_7103,
|
||||
CIC_NUS_6105_7105,
|
||||
CIC_NUS_6106_7106
|
||||
};
|
||||
|
||||
struct CartInfo;
|
||||
|
||||
void ProcessPIFCommands(u8*, Controller&, Mem&);
|
||||
void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo);
|
||||
}
|
||||
37
src/backend/core/mmio/RI.cpp
Normal file
37
src/backend/core/mmio/RI.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <core/mmio/RI.hpp>
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
RI::RI() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void RI::Reset() {
|
||||
mode = 0xE;
|
||||
config = 0x40;
|
||||
select = 0x14;
|
||||
refresh = 0x63634;
|
||||
}
|
||||
|
||||
auto RI::Read(u32 addr) const -> u32 {
|
||||
switch(addr) {
|
||||
case 0x04700000: return mode;
|
||||
case 0x04700004: return config;
|
||||
case 0x0470000C: return select;
|
||||
case 0x04700010: return refresh;
|
||||
default:
|
||||
util::panic("Unhandled RI[{:08X}] read\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
void RI::Write(u32 addr, u32 val) {
|
||||
switch(addr) {
|
||||
case 0x04700000: mode = val; break;
|
||||
case 0x04700004: config = val; break;
|
||||
case 0x0470000C: select = val; break;
|
||||
case 0x04700010: refresh = val; break;
|
||||
default:
|
||||
util::panic("Unhandled RI[{:08X}] write with val {:08X}\n", addr, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/backend/core/mmio/RI.hpp
Normal file
14
src/backend/core/mmio/RI.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
struct RI {
|
||||
RI();
|
||||
void Reset();
|
||||
auto Read(u32) const -> u32;
|
||||
void Write(u32, u32);
|
||||
u32 mode{0xE}, config{0x40}, select{0x14}, refresh{0x63634};
|
||||
};
|
||||
|
||||
}
|
||||
79
src/backend/core/mmio/SI.cpp
Normal file
79
src/backend/core/mmio/SI.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <core/mmio/SI.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
#include <Scheduler.hpp>
|
||||
|
||||
namespace n64 {
|
||||
SI::SI() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void SI::Reset() {
|
||||
status.raw = 0;
|
||||
dramAddr = 0;
|
||||
pifAddr = 0;
|
||||
memset(&controller, 0, sizeof(Controller));
|
||||
}
|
||||
|
||||
auto SI::Read(MI& mi, u32 addr) const -> u32 {
|
||||
switch(addr) {
|
||||
case 0x04800000: return dramAddr;
|
||||
case 0x04800004: case 0x04800010: return pifAddr;
|
||||
case 0x0480000C: return 0;
|
||||
case 0x04800018: {
|
||||
u32 val = 0;
|
||||
val |= status.dmaBusy;
|
||||
val |= (0 << 1);
|
||||
val |= (0 << 3);
|
||||
val |= (mi.miIntr.si << 12);
|
||||
return val;
|
||||
}
|
||||
default:
|
||||
util::panic("Unhandled SI[{:08X}] read\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
void DMA(Mem& mem, Registers& regs) {
|
||||
MMIO& mmio = mem.mmio;
|
||||
SI& si = mmio.si;
|
||||
si.status.dmaBusy = false;
|
||||
if(si.toDram) {
|
||||
ProcessPIFCommands(mem.pifRam, si.controller, mem);
|
||||
for(int i = 0; i < 64; i++) {
|
||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)] = mem.pifRam[i];
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < 64; i++) {
|
||||
mem.pifRam[i] = mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)];
|
||||
}
|
||||
util::debug("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})\n", si.pifAddr, si.dramAddr);
|
||||
ProcessPIFCommands(mem.pifRam, si.controller, mem);
|
||||
}
|
||||
InterruptRaise(mem.mmio.mi, regs, Interrupt::SI);
|
||||
}
|
||||
|
||||
void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
switch(addr) {
|
||||
case 0x04800000:
|
||||
dramAddr = val & RDRAM_DSIZE;
|
||||
break;
|
||||
case 0x04800004: {
|
||||
pifAddr = val & 0x1FFFFFFF;
|
||||
status.dmaBusy = true;
|
||||
toDram = true;
|
||||
scheduler.enqueueRelative({SI_DMA_DELAY, DMA});
|
||||
} break;
|
||||
case 0x04800010: {
|
||||
pifAddr = val & 0x1FFFFFFF;
|
||||
status.dmaBusy = true;
|
||||
toDram = false;
|
||||
scheduler.enqueueRelative({SI_DMA_DELAY, DMA});
|
||||
util::debug("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})\n", dramAddr, val & 0x1FFFFFFF);
|
||||
} break;
|
||||
case 0x04800018:
|
||||
InterruptLower(mem.mmio.mi, regs, Interrupt::SI);
|
||||
break;
|
||||
default:
|
||||
util::panic("Unhandled SI[%08X] write (%08X)\n", addr, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
src/backend/core/mmio/SI.hpp
Normal file
38
src/backend/core/mmio/SI.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/mmio/PIF.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
union SIStatus {
|
||||
u32 raw{};
|
||||
struct {
|
||||
unsigned dmaBusy:1;
|
||||
unsigned ioBusy:1;
|
||||
unsigned reserved:1;
|
||||
unsigned dmaErr:1;
|
||||
unsigned:8;
|
||||
unsigned intr:1;
|
||||
};
|
||||
};
|
||||
|
||||
struct Mem;
|
||||
|
||||
struct SI {
|
||||
SI();
|
||||
void Reset();
|
||||
SIStatus status{};
|
||||
u32 dramAddr{};
|
||||
u32 pifAddr{};
|
||||
Controller controller{};
|
||||
|
||||
bool toDram = false;
|
||||
|
||||
auto Read(MI&, u32) const -> u32;
|
||||
void Write(Mem&, Registers&, u32, u32);
|
||||
};
|
||||
|
||||
static void DMA(Mem& mem, Registers& regs);
|
||||
}
|
||||
87
src/backend/core/mmio/VI.cpp
Normal file
87
src/backend/core/mmio/VI.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <core/mmio/VI.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
VI::VI () {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void VI::Reset() {
|
||||
status.raw = 0xF;
|
||||
intr = 256;
|
||||
origin = 0;
|
||||
width = 320;
|
||||
current = 0;
|
||||
vsync = 0;
|
||||
hsync = 0;
|
||||
numHalflines = 262;
|
||||
numFields = 1;
|
||||
cyclesPerHalfline = 1000;
|
||||
}
|
||||
|
||||
u32 VI::Read(u32 paddr) const {
|
||||
switch(paddr) {
|
||||
case 0x04400000: return status.raw;
|
||||
case 0x04400004: return origin;
|
||||
case 0x04400008: return width;
|
||||
case 0x0440000C: return intr;
|
||||
case 0x04400010: return current << 1;
|
||||
case 0x04400014: return burst.raw;
|
||||
case 0x04400018: return vsync;
|
||||
case 0x0440001C: return hsync;
|
||||
case 0x04400020: return hsyncLeap.raw;
|
||||
case 0x04400024: return hstart.raw;
|
||||
case 0x04400028: return vstart.raw;
|
||||
case 0x0440002C: return vburst;
|
||||
case 0x04400030: return xscale.raw;
|
||||
case 0x04400034: return yscale.raw;
|
||||
default:
|
||||
util::panic("Unimplemented VI[%08X] read\n", paddr);
|
||||
}
|
||||
}
|
||||
|
||||
void VI::Write(MI& mi, Registers& regs, u32 paddr, u32 val) {
|
||||
switch(paddr) {
|
||||
case 0x04400000:
|
||||
status.raw = val;
|
||||
numFields = status.serrate ? 2 : 1;
|
||||
break;
|
||||
case 0x04400004: {
|
||||
u32 masked = val & 0xFFFFFF;
|
||||
if(origin != masked) {
|
||||
swaps++;
|
||||
}
|
||||
origin = masked;
|
||||
} break;
|
||||
case 0x04400008: {
|
||||
width = val & 0x7FF;
|
||||
} break;
|
||||
case 0x0440000C: {
|
||||
intr = val & 0x3FF;
|
||||
} break;
|
||||
case 0x04400010:
|
||||
InterruptLower(mi, regs, Interrupt::VI);
|
||||
break;
|
||||
case 0x04400014: burst.raw = val; break;
|
||||
case 0x04400018: {
|
||||
vsync = val & 0x3FF;
|
||||
numHalflines = vsync >> 1;
|
||||
cyclesPerHalfline = N64_CYCLES_PER_FRAME / numHalflines;
|
||||
} break;
|
||||
case 0x0440001C: {
|
||||
hsync = val & 0x3FF;
|
||||
} break;
|
||||
case 0x04400020: hsyncLeap.raw = val; break;
|
||||
case 0x04400024: hstart.raw = val; break;
|
||||
case 0x04400028: vstart.raw = val; break;
|
||||
case 0x0440002C: vburst = val; break;
|
||||
case 0x04400030: xscale.raw = val; break;
|
||||
case 0x04400034: yscale.raw = val; break;
|
||||
default:
|
||||
util::panic("Unimplemented VI[%08X] write (%08X)\n", paddr, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
106
src/backend/core/mmio/VI.hpp
Normal file
106
src/backend/core/mmio/VI.hpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
|
||||
namespace n64 {
|
||||
union VIBurst {
|
||||
/*struct {
|
||||
unsigned hsyncW:8;
|
||||
unsigned burstW:8;
|
||||
unsigned vsyncW:4;
|
||||
unsigned burstStart:10;
|
||||
unsigned:2;
|
||||
};*/
|
||||
u32 raw;
|
||||
};
|
||||
|
||||
union VIHsyncLeap {
|
||||
/*struct {
|
||||
unsigned leapB:10;
|
||||
unsigned:6;
|
||||
unsigned leapA:10;
|
||||
unsigned:6;
|
||||
};*/
|
||||
u32 raw;
|
||||
} ;
|
||||
|
||||
union VIVideo {
|
||||
struct {
|
||||
unsigned end:10;
|
||||
unsigned:6;
|
||||
unsigned start:10;
|
||||
unsigned:6;
|
||||
};
|
||||
u32 raw;
|
||||
};
|
||||
|
||||
union AxisScale {
|
||||
u32 raw;
|
||||
struct {
|
||||
unsigned scaleDecimal:10;
|
||||
unsigned scaleInteger:2;
|
||||
unsigned subpixelOffsetDecimal:10;
|
||||
unsigned subpixelOffsetInteger:2;
|
||||
unsigned:4;
|
||||
};
|
||||
struct {
|
||||
unsigned scale:12;
|
||||
unsigned subpixelOffset:12;
|
||||
unsigned:4;
|
||||
};
|
||||
};
|
||||
|
||||
enum VIFormat {
|
||||
blank = 0,
|
||||
reserved = 1,
|
||||
f5553 = 2,
|
||||
f8888 = 3
|
||||
};
|
||||
|
||||
union VIStatus {
|
||||
struct {
|
||||
u8 type:2;
|
||||
bool gamma_dither_enable:1;
|
||||
bool gamma_enable:1;
|
||||
bool divot_enable:1;
|
||||
bool reserved_always_off:1;
|
||||
bool serrate:1;
|
||||
bool reserved_diagnostics_only:1;
|
||||
unsigned antialias_mode:3;
|
||||
unsigned:21;
|
||||
};
|
||||
|
||||
u32 raw;
|
||||
};
|
||||
|
||||
union AxisStart {
|
||||
u32 raw;
|
||||
struct {
|
||||
unsigned end:10;
|
||||
unsigned:6;
|
||||
unsigned start:10;
|
||||
unsigned:6;
|
||||
};
|
||||
};
|
||||
|
||||
struct MI;
|
||||
struct Registers;
|
||||
|
||||
struct VI {
|
||||
VI();
|
||||
void Reset();
|
||||
[[nodiscard]] u32 Read(u32) const;
|
||||
void Write(MI&, Registers&, u32, u32);
|
||||
AxisScale xscale{}, yscale{};
|
||||
VIHsyncLeap hsyncLeap{};
|
||||
VIStatus status{};
|
||||
VIBurst burst{};
|
||||
u32 vburst{};
|
||||
u32 origin, width, current;
|
||||
u32 vsync, hsync, intr;
|
||||
AxisStart hstart{}, vstart{};
|
||||
int swaps{};
|
||||
int numHalflines;
|
||||
int numFields;
|
||||
int cyclesPerHalfline;
|
||||
};
|
||||
} // backend
|
||||
Reference in New Issue
Block a user