Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/snes/chip/sdd1/sdd1.cpp
2 views
1
#include <snes/snes.hpp>
2
3
#define SDD1_CPP
4
namespace SNES {
5
6
SDD1 sdd1;
7
8
#include "decomp.cpp"
9
#include "serialization.cpp"
10
11
void SDD1::init() {
12
}
13
14
void SDD1::load() {
15
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
16
//buffer address and transfer size information for use in SDD1::mcu_read()
17
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
18
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
19
}
20
21
void SDD1::unload() {
22
}
23
24
void SDD1::power() {
25
}
26
27
void SDD1::reset() {
28
sdd1_enable = 0x00;
29
xfer_enable = 0x00;
30
dma_ready = false;
31
32
mmc[0] = 0 << 20;
33
mmc[1] = 1 << 20;
34
mmc[2] = 2 << 20;
35
mmc[3] = 3 << 20;
36
37
for(unsigned i = 0; i < 8; i++) {
38
dma[i].addr = 0;
39
dma[i].size = 0;
40
}
41
}
42
43
uint8 SDD1::mmio_read(unsigned addr) {
44
addr &= 0xffff;
45
46
if((addr & 0x4380) == 0x4300) {
47
return cpu.mmio_read(addr);
48
}
49
50
switch(addr) {
51
case 0x4804: return mmc[0] >> 20;
52
case 0x4805: return mmc[1] >> 20;
53
case 0x4806: return mmc[2] >> 20;
54
case 0x4807: return mmc[3] >> 20;
55
}
56
57
return cpu.regs.mdr;
58
}
59
60
void SDD1::mmio_write(unsigned addr, uint8 data) {
61
addr &= 0xffff;
62
63
if((addr & 0x4380) == 0x4300) {
64
unsigned channel = (addr >> 4) & 7;
65
switch(addr & 15) {
66
case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break;
67
case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break;
68
case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break;
69
70
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
71
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
72
}
73
return cpu.mmio_write(addr, data);
74
}
75
76
switch(addr) {
77
case 0x4800: sdd1_enable = data; break;
78
case 0x4801: xfer_enable = data; break;
79
80
case 0x4804: mmc[0] = data << 20; break;
81
case 0x4805: mmc[1] = data << 20; break;
82
case 0x4806: mmc[2] = data << 20; break;
83
case 0x4807: mmc[3] = data << 20; break;
84
}
85
}
86
87
uint8 SDD1::rom_read(unsigned addr) {
88
return cartridge.rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
89
}
90
91
//SDD1::mcu_read() is mapped to $c0-ff:0000-ffff
92
//the design is meant to be as close to the hardware design as possible, thus this code
93
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation.
94
//
95
//the real S-DD1 cannot see $420b (DMA enable) writes, as they are not placed on the bus.
96
//however, $43x0-$43xf writes (DMAx channel settings) most likely do appear on the bus.
97
//the S-DD1 also requires fixed addresses for transfers, which wouldn't be necessary if
98
//it could see $420b writes (eg it would know when the transfer should begin.)
99
//
100
//the hardware needs a way to distinguish program code after $4801 writes from DMA
101
//decompression that follows soon after.
102
//
103
//the only plausible design for hardware would be for the S-DD1 to spy on DMAx settings,
104
//and begin spooling decompression on writes to $4801 that activate a channel. after that,
105
//it feeds decompressed data only when the ROM read address matches the DMA channel address.
106
//
107
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
108
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
109
uint8 SDD1::mcu_read(unsigned addr) {
110
if(sdd1_enable & xfer_enable) {
111
//at least one channel has S-DD1 decompression enabled ...
112
for(unsigned i = 0; i < 8; i++) {
113
if(sdd1_enable & xfer_enable & (1 << i)) {
114
//S-DD1 always uses fixed transfer mode, so address will not change during transfer
115
if(addr == dma[i].addr) {
116
if(!dma_ready) {
117
//prepare streaming decompression
118
decomp.init(addr);
119
dma_ready = true;
120
}
121
122
//fetch a decompressed byte; once finished, disable channel and invalidate buffer
123
uint8 data = decomp.read();
124
if(--dma[i].size == 0) {
125
dma_ready = false;
126
xfer_enable &= ~(1 << i);
127
}
128
129
return data;
130
} //address matched
131
} //channel enabled
132
} //channel loop
133
} //S-DD1 decompressor enabled
134
135
//S-DD1 decompression mode inactive; return ROM data
136
return cartridge.rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
137
}
138
139
void SDD1::mcu_write(unsigned addr, uint8 data) {
140
}
141
142
SDD1::SDD1() {
143
}
144
145
SDD1::~SDD1() {
146
}
147
148
}
149
150