Skip to content

Commit f77ab81

Browse files
committed
Regrouping
1 parent 0e3394b commit f77ab81

File tree

6 files changed

+235
-238
lines changed

6 files changed

+235
-238
lines changed

Core/Peripherals/Drive/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ target_include_directories(VACore PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
22

33
target_sources(VACore PRIVATE
44

5-
DiskEncoder.cpp
65
Drive.cpp
76
FloppyDrive.cpp
87
HardDrive.cpp

Core/Peripherals/Drive/Encoders/AmigaEncoder.cpp

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,211 @@
99

1010
#include "config.h"
1111
#include "AmigaEncoder.h"
12+
#include "DeviceError.h"
13+
#include "MFM.h"
14+
#include "utl/support/Bits.h"
15+
16+
namespace vamiga::AmigaEncoder {
17+
18+
void
19+
encodeAmigaTrack(MutableByteView track, TrackNr t, ByteView src)
20+
{
21+
const isize bsize = 512; // Block size in bytes
22+
const isize ssize = 1088; // MFM sector size in bytes
23+
const isize count = (isize)src.size() / bsize; // Number of sectors to encode
24+
25+
if (ADF_DEBUG) fprintf(stderr, "Encoding Amiga track %ld with %ld sectors\n", t, count);
26+
assert(src.size() % bsize == 0);
27+
28+
// Format track
29+
track.clear(0xAA);
30+
31+
// Encode all sectors
32+
for (SectorNr s = 0; s < count; s++)
33+
encodeAmigaSector(track, s * ssize, t, s, src.subspan(s * bsize, bsize));
34+
35+
// Compute a debug checksum
36+
if (ADF_DEBUG) fprintf(stderr, "Track %ld checksum = %x\n", t, track.fnv32());
37+
}
38+
39+
void
40+
encodeAmigaSector(MutableByteView track, isize offset, TrackNr t, SectorNr s, ByteView data)
41+
{
42+
const isize bsize = 512; // Block size in bytes
43+
const isize ssize = 1088; // MFM sector size in bytes
44+
45+
if (ADF_DEBUG) fprintf(stderr, "Encoding sector %ld\n", s);
46+
assert(data.size() == bsize);
47+
48+
// Block header layout:
49+
//
50+
// Start Size Value
51+
// Bytes before SYNC 00 4 0xAA 0xAA 0xAA 0xAA
52+
// SYNC mark 04 4 0x44 0x89 0x44 0x89
53+
// Track & sector info 08 8 Odd/Even encoded
54+
// Unused area 16 32 0xAA
55+
// Block checksum 48 8 Odd/Even encoded
56+
// Data checksum 56 8 Odd/Even encoded
57+
58+
auto it = track.cyclic_begin(offset);
59+
60+
// Bytes before SYNC
61+
it[0] = (it[-1] & 1) ? 0x2A : 0xAA;
62+
it[1] = 0xAA;
63+
it[2] = 0xAA;
64+
it[3] = 0xAA;
65+
66+
// SYNC mark
67+
u16 sync = 0x4489;
68+
it[4] = HI_BYTE(sync);
69+
it[5] = LO_BYTE(sync);
70+
it[6] = HI_BYTE(sync);
71+
it[7] = LO_BYTE(sync);
72+
73+
// Track and sector information
74+
u8 info[4] = { 0xFF, (u8)t, (u8)s, (u8)(11 - s) };
75+
MFM::encodeOddEven(&it[8], info, sizeof(info));
76+
77+
// Unused area
78+
for (isize i = 16; i < 48; i++)
79+
it[i] = 0xAA;
80+
81+
// Data
82+
MFM::encodeOddEven(&it[64], data.data(), bsize);
83+
84+
// Block checksum
85+
u8 bcheck[4] = { 0, 0, 0, 0 };
86+
for(isize i = 8; i < 48; i += 4) {
87+
bcheck[0] ^= it[i];
88+
bcheck[1] ^= it[i+1];
89+
bcheck[2] ^= it[i+2];
90+
bcheck[3] ^= it[i+3];
91+
}
92+
MFM::encodeOddEven(&it[48], bcheck, sizeof(bcheck));
93+
94+
// Data checksum
95+
u8 dcheck[4] = { 0, 0, 0, 0 };
96+
for(isize i = 64; i < ssize; i += 4) {
97+
dcheck[0] ^= it[i];
98+
dcheck[1] ^= it[i+1];
99+
dcheck[2] ^= it[i+2];
100+
dcheck[3] ^= it[i+3];
101+
}
102+
MFM::encodeOddEven(&it[56], dcheck, sizeof(dcheck));
103+
104+
// Add clock bits
105+
for(isize i = 8; i < ssize + 1; i++) {
106+
it[i] = MFM::addClockBits(it[i], it[i-1]);
107+
}
108+
}
109+
110+
void
111+
decodeAmigaTrack(ByteView track, TrackNr t, MutableByteView dst)
112+
{
113+
const isize bsize = 512; // Block size in bytes
114+
const isize count = (isize)dst.size() / bsize; // Number of sectors to decode
115+
116+
if (ADF_DEBUG) fprintf(stderr, "Decoding track %ld\n", t);
117+
assert(dst.size() % bsize == 0);
118+
119+
// Find all sectors
120+
auto offsets = seekSectors(track);
121+
122+
// Decode all sectors
123+
for (SectorNr s = 0; s < count; s++) {
124+
125+
if (!offsets.contains(s))
126+
throw DeviceError(DeviceError::DEV_SEEK_ERR);
127+
128+
auto *secData = dst.data() + s * bsize;
129+
decodeAmigaSector(track, offsets[s], span<u8>(secData, bsize));
130+
}
131+
}
132+
133+
void
134+
decodeAmigaSector(ByteView track, isize offset, MutableByteView dst)
135+
{
136+
const isize bsize = 512;
137+
assert(dst.size() == bsize);
138+
139+
if (MFM_DEBUG) fprintf(stderr, "Decoding sector at offset %ld\n", offset);
140+
141+
// Skip sync mark + sector header
142+
offset += 4 + 56;
143+
144+
// Determine the source address
145+
auto *mfmData = &track[offset];
146+
147+
// Decode sector data
148+
MFM::decodeOddEven(dst.data(), mfmData, bsize);
149+
}
150+
151+
optional<isize>
152+
trySeekSector(ByteView track, SectorNr s, isize offset)
153+
{
154+
constexpr isize syncMarkLen = 4;
155+
156+
// Search through all sync marks...
157+
auto it = track.cyclic_begin(offset);
158+
159+
for (isize i = 0; i < track.size() + syncMarkLen; ++i, ++it) {
160+
161+
// Scan MFM stream for $4489 $4489
162+
if (it[0] != 0x44) continue;
163+
if (it[1] != 0x89) continue;
164+
if (it[2] != 0x44) continue;
165+
if (it[3] != 0x89) continue;
166+
167+
// Make sure it's not a DOS track
168+
if (it[5] == 0x89) continue;
169+
170+
// Decode track & sector info
171+
u8 info[4]; MFM::decodeOddEven(info, &it[4], 4);
172+
173+
// Check if the sector number matches
174+
if (info[2] == s) return it.offset();
175+
}
176+
177+
return {};
178+
}
179+
180+
isize
181+
seekSector(ByteView track, SectorNr s, isize offset)
182+
{
183+
if (auto result = trySeekSector(track, s, offset))
184+
return *result;
185+
186+
throw DeviceError(DeviceError::DSK_INVALID_SECTOR_NUMBER);
187+
}
188+
189+
std::unordered_map<isize, isize>
190+
seekSectors(ByteView track)
191+
{
192+
constexpr isize syncMarkLen = 4;
193+
std::unordered_map<isize, isize> result;
194+
195+
// Search through all sync marks...
196+
auto it = track.cyclic_begin();
197+
198+
for (isize i = 0; i < track.size() + syncMarkLen; ++i, ++it) {
199+
200+
// Scan MFM stream for $4489 $4489
201+
if (it[0] != 0x44) continue;
202+
if (it[1] != 0x89) continue;
203+
if (it[2] != 0x44) continue;
204+
if (it[3] != 0x89) continue;
205+
206+
// Make sure it's not a DOS track
207+
if (it[5] == 0x89) continue;
208+
209+
// Decode track & sector info (info[2] = sector number)
210+
u8 info[4]; MFM::decodeOddEven(info, &it[4], 4);
211+
212+
// Record the offset
213+
result[info[2]] = it.offset();
214+
}
215+
216+
return result;
217+
}
218+
219+
}

Core/Peripherals/Drive/Encoders/AmigaEncoder.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,23 @@
99

1010
#pragma once
1111

12-
#include "DiskEncoder.h"
12+
#include "DeviceTypes.h"
13+
#include "utl/primitives/BitView.h"
1314

15+
namespace vamiga::AmigaEncoder {
16+
17+
// using namespace utl;
18+
19+
void encodeAmigaTrack(MutableByteView track, TrackNr t, ByteView src);
20+
void encodeAmigaSector(MutableByteView track, isize offset, TrackNr t, SectorNr s, ByteView src);
21+
22+
void decodeAmigaTrack(ByteView track, TrackNr t, MutableByteView dst);
23+
void decodeAmigaSector(ByteView track, isize offset, MutableByteView dst);
24+
25+
optional<isize> trySeekSector(ByteView track, SectorNr s, isize offset = 0);
26+
isize seekSector(ByteView track, SectorNr s, isize offset = 0);
27+
28+
// Computes a map from sector numbers to byte offsets
29+
std::unordered_map<isize, isize> seekSectors(ByteView track);
30+
31+
}

0 commit comments

Comments
 (0)