Skip to content

Commit 9bd2afe

Browse files
asiekierkaLukeUsher
authored andcommitted
ws: implement Karnak mapper ADPCM decoder
1 parent 7bcb9ae commit 9bd2afe

File tree

5 files changed

+63
-15
lines changed

5 files changed

+63
-15
lines changed

ares/ws/cartridge/cartridge.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,21 @@ struct Cartridge : IO, Thread {
115115
//karnak.cpp
116116
auto power() -> void;
117117
auto reset() -> void;
118+
auto adpcmReset() -> void;
119+
auto adpcmNext(n4 sample) -> void;
118120
auto main() -> void;
119121
auto step(u32 clocks) -> void;
120122

121123
//serialization.cpp
122124
auto serialize(serializer& s) -> void;
123125

124-
n1 timerEnable;
126+
n1 enable;
125127
n7 timerPeriod;
126128
n9 timerCounter;
129+
130+
n10 adpcmAccumulator;
131+
i5 adpcmStepIndex;
132+
n1 adpcmInputShift;
127133
} karnak;
128134

129135
struct FLASH {

ares/ws/cartridge/io.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,19 @@ auto Cartridge::readIO(n16 address) -> n8 {
7777
break;
7878

7979
case 0x00d6: //KARNAK_TIMER
80-
data.bit(7) = karnak.timerEnable;
80+
data.bit(7) = karnak.enable;
8181
data.bit(6, 0) = karnak.timerPeriod;
8282
break;
8383

84-
case 0x00d7: //KARNAK
84+
case 0x00d7:
85+
case 0x00d8: //KARNAK_ADPCM_INPUT
8586
data = 0xFF;
8687
break;
8788

88-
case 0x00d8:
89-
case 0x00d9:
90-
debug(unimplemented, "[KARNAK] ADPCM read ", hex(address, 2L));
89+
case 0x00d9: //KARNAK_ADPCM_OUTPUT
90+
if (karnak.adpcmAccumulator >= 0x300) data = 0x00;
91+
else if (karnak.adpcmAccumulator >= 0x200) data = 0xFF;
92+
else data = karnak.adpcmAccumulator >> 1;
9193
break;
9294

9395
}
@@ -174,13 +176,15 @@ auto Cartridge::writeIO(n16 address, n8 data) -> void {
174176
break;
175177

176178
case 0x00d6: //KARNAK_TIMER
177-
karnak.timerEnable = data.bit(7);
179+
karnak.enable = data.bit(7);
178180
karnak.timerPeriod = data.bit(6, 0);
181+
if (!karnak.enable) karnak.adpcmReset();
179182
break;
180183

181-
case 0x00d8:
182-
case 0x00d9:
183-
debug(unimplemented, "[KARNAK] ADPCM write ", hex(address, 2L), "=", hex(data, 2L));
184+
case 0x00d8: //KARNAK_ADPCM_INPUT
185+
if (!karnak.enable) return;
186+
karnak.adpcmNext(data >> (karnak.adpcmInputShift ? 0 : 4));
187+
karnak.adpcmInputShift ^= 1;
184188
break;
185189

186190
}

ares/ws/cartridge/karnak.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,58 @@
1+
static const n10 adpcmAccumulatorStep[16][16] = {
2+
{ 0, 0, 1, 2, 3, 5, 7, 10, 0, 0, -1, -2, -3, -5, -7, -10 },
3+
{ 0, 1, 2, 3, 4, 6, 8, 13, 0, -1, -2, -3, -4, -6, -8, -13 },
4+
{ 0, 1, 2, 4, 5, 7, 10, 15, 0, -1, -2, -4, -5, -7, -10, -15 },
5+
{ 0, 1, 3, 4, 6, 9, 13, 19, 0, -1, -3, -4, -6, -9, -13, -19 },
6+
{ 0, 2, 3, 5, 8, 11, 15, 23, 0, -2, -3, -5, -8, -11, -15, -23 },
7+
{ 0, 2, 4, 7, 10, 14, 19, 29, 0, -2, -4, -7, -10, -14, -19, -29 },
8+
{ 0, 3, 5, 8, 12, 16, 22, 33, 0, -3, -5, -8, -12, -16, -22, -33 },
9+
{ 1, 4, 7, 10, 15, 20, 29, 43, -1, -4, -7, -10, -15, -20, -29, -43 },
10+
{ 1, 4, 8, 13, 18, 25, 35, 53, -1, -4, -8, -13, -18, -25, -35, -53 },
11+
{ 1, 6, 10, 16, 22, 31, 43, 64, -1, -6, -10, -16, -22, -31, -43, -64 },
12+
{ 2, 7, 12, 19, 27, 37, 51, 76, -2, -7, -12, -19, -27, -37, -51, -76 },
13+
{ 2, 9, 16, 24, 34, 46, 64, 96, -2, -9, -16, -24, -34, -46, -64, -96 },
14+
{ 3, 11, 19, 29, 41, 57, 79, 117, -3, -11, -19, -29, -41, -57, -79, -117 },
15+
{ 4, 13, 24, 36, 50, 69, 96, 143, -4, -13, -24, -36, -50, -69, -96, -143 },
16+
{ 4, 16, 29, 44, 62, 85, 118, 175, -4, -16, -29, -44, -62, -85, -118, -175 },
17+
{ 6, 20, 36, 54, 76, 104, 144, 214, -6, -20, -36, -54, -76, -104, -144, -214 }
18+
};
19+
static const i4 adpcmIndexStep[8] = {
20+
-1, -1, 0, 0, 1, 2, 2, 3
21+
};
122

223
auto Cartridge::KARNAK::power() -> void {
324
Thread::create(384'000, std::bind_front(&Cartridge::KARNAK::main, this));
425

5-
timerEnable = 0;
26+
enable = 0;
627
timerPeriod = 0;
728
timerCounter = 0;
29+
30+
adpcmReset();
831
}
932

1033
auto Cartridge::KARNAK::reset() -> void {
1134
Thread::destroy();
1235
}
1336

37+
auto Cartridge::KARNAK::adpcmReset() -> void {
38+
adpcmAccumulator = 0x100;
39+
adpcmInputShift = 0;
40+
adpcmStepIndex = 0;
41+
}
42+
43+
auto Cartridge::KARNAK::adpcmNext(n4 sample) -> void {
44+
adpcmAccumulator += adpcmAccumulatorStep[adpcmStepIndex][sample];
45+
adpcmStepIndex = std::clamp(adpcmStepIndex + adpcmIndexStep[sample & 7], 0, 15);
46+
}
47+
1448
auto Cartridge::KARNAK::main() -> void {
15-
if(timerEnable) {
49+
if(enable) {
1650
if(!timerCounter) {
1751
timerCounter = (timerPeriod + 1) * 2;
1852
}
1953
timerCounter--;
2054
}
21-
cpu.irqLevel(CPU::Interrupt::Cartridge, timerEnable && !timerCounter);
55+
cpu.irqLevel(CPU::Interrupt::Cartridge, enable && !timerCounter);
2256
step(1);
2357
}
2458

ares/ws/cartridge/serialization.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ auto Cartridge::RTC::serialize(serializer& s) -> void {
5050
auto Cartridge::KARNAK::serialize(serializer& s) -> void {
5151
Thread::serialize(s);
5252

53-
s(timerEnable);
53+
s(enable);
5454
s(timerPeriod);
5555
s(timerCounter);
56+
57+
s(adpcmAccumulator);
58+
s(adpcmStepIndex);
59+
s(adpcmInputShift);
5660
}

ares/ws/system/serialization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
static const string SerializerVersion = "v144.3";
1+
static const string SerializerVersion = "v145.1";
22

33
auto System::serialize(bool synchronize) -> serializer {
44
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);

0 commit comments

Comments
 (0)