Skip to content

Commit adbcb2c

Browse files
authored
Merge pull request #139 from davidgiven/sectors
Add support for required sectors, drive autodetection and fix homing on 8" drives.
2 parents 38700c7 + c47a563 commit adbcb2c

File tree

15 files changed

+466
-298
lines changed

15 files changed

+466
-298
lines changed

FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex

Lines changed: 252 additions & 252 deletions
Large diffs are not rendered by default.

FluxEngine.cydsn/main.c

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#define STEP_TOWARDS0 1
1818
#define STEP_AWAYFROM0 0
1919

20+
static bool drive0_present;
21+
static bool drive1_present;
22+
2023
static volatile uint32_t clock = 0; /* ms */
2124
static volatile bool index_irq = false;
2225

@@ -42,6 +45,8 @@ static volatile bool dma_underrun = false;
4245
#define DECLARE_REPLY_FRAME(STRUCT, TYPE) \
4346
STRUCT r = {.f = { .type = TYPE, .size = sizeof(STRUCT) }}
4447

48+
static void stop_motor(void);
49+
4550
static void system_timer_cb(void)
4651
{
4752
CyGlobalIntDisable;
@@ -104,7 +109,10 @@ static void print(const char* msg, ...)
104109
static void set_drive_flags(struct set_drive_frame* flags)
105110
{
106111
if (current_drive_flags.drive != flags->drive)
112+
{
113+
stop_motor();
107114
homed = false;
115+
}
108116

109117
current_drive_flags = *flags;
110118
DRIVESELECT_REG_Write(flags->drive ? 2 : 1); /* select drive 1 or 0 */
@@ -184,19 +192,19 @@ static void step(int dir)
184192
CyDelay(STEP_INTERVAL_TIME);
185193
}
186194

187-
static void home(void)
195+
/* returns true if it looks like a drive is attached */
196+
static bool home(void)
188197
{
189198
for (int i=0; i<100; i++)
190199
{
191200
/* Don't keep stepping forever, because if a drive's
192201
* not connected bad things happen. */
193202
if (TRACK0_REG_Read())
194-
break;
203+
return true;
195204
step(STEP_TOWARDS0);
196205
}
197206

198-
/* Step to -1, which should be a nop, to reset the disk on disk change. */
199-
step(STEP_TOWARDS0);
207+
return false;
200208
}
201209

202210
static void seek_to(int track)
@@ -761,6 +769,10 @@ static void cmd_erase(struct erase_frame* f)
761769

762770
static void cmd_set_drive(struct set_drive_frame* f)
763771
{
772+
if (drive0_present && !drive1_present)
773+
f->drive = 0;
774+
if (drive1_present && !drive0_present)
775+
f->drive = 1;
764776
set_drive_flags(f);
765777

766778
DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_SET_DRIVE_REPLY);
@@ -930,6 +942,18 @@ int main(void)
930942

931943
CyWdtStart(CYWDT_1024_TICKS, CYWDT_LPMODE_DISABLED);
932944

945+
current_drive_flags.drive = 0;
946+
start_motor();
947+
drive0_present = home();
948+
stop_motor();
949+
950+
current_drive_flags.drive = 1;
951+
start_motor();
952+
drive1_present = home();
953+
stop_motor();
954+
955+
print("drive 0: %s drive 1: %s", drive0_present ? "yes" : "no", drive1_present ? "yes" : "no");
956+
933957
/* UART_PutString("GO\r"); */
934958

935959
for (;;)

arch/ibm/ibm.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,24 @@ struct IbmIdam
3232
class IbmDecoder : public AbstractDecoder
3333
{
3434
public:
35-
IbmDecoder(unsigned sectorBase, bool ignoreSideByte=false):
35+
IbmDecoder(unsigned sectorBase, bool ignoreSideByte=false,
36+
const std::set<unsigned> requiredSectors=std::set<unsigned>()):
3637
_sectorBase(sectorBase),
37-
_ignoreSideByte(ignoreSideByte)
38+
_ignoreSideByte(ignoreSideByte),
39+
_requiredSectors(requiredSectors)
3840
{}
3941

4042
RecordType advanceToNextRecord();
4143
void decodeSectorRecord();
4244
void decodeDataRecord();
4345

46+
std::set<unsigned> requiredSectors(Track& track) const
47+
{ return _requiredSectors; }
48+
4449
private:
4550
unsigned _sectorBase;
4651
bool _ignoreSideByte;
52+
std::set<unsigned> _requiredSectors;
4753
unsigned _currentSectorSize;
4854
unsigned _currentHeaderLength;
4955
};

arch/macintosh/decoder.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,26 @@ void MacintoshDecoder::decodeDataRecord()
184184
_sector->data.clear();
185185
_sector->data.writer().append(userData.slice(12, 512)).append(userData.slice(0, 12));
186186
}
187+
188+
std::set<unsigned> MacintoshDecoder::requiredSectors(Track& track) const
189+
{
190+
int count;
191+
if (track.physicalTrack < 16)
192+
count = 12;
193+
else if (track.physicalTrack < 32)
194+
count = 11;
195+
else if (track.physicalTrack < 48)
196+
count = 10;
197+
else if (track.physicalTrack < 64)
198+
count = 9;
199+
else
200+
count = 8;
201+
202+
std::set<unsigned> sectors;
203+
do
204+
sectors.insert(count);
205+
while (count--);
206+
return sectors;
207+
}
208+
209+

arch/macintosh/macintosh.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class MacintoshDecoder : public AbstractDecoder
1818
RecordType advanceToNextRecord();
1919
void decodeSectorRecord();
2020
void decodeDataRecord();
21+
22+
std::set<unsigned> requiredSectors(Track& track) const;
2123
};
2224

2325
#endif

doc/building.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,21 @@ You should now have a working board, so it's time to test it.
225225
are cheap and just have the 3.5" connectors. Some are _very_ cheap and
226226
have a single 3.5" connector, after the twist.)
227227

228-
FluxEngine uses, sadly, non-standard disk numbering (there are reasons).
229-
Drive 0 is the one nearest the motherboard; that is, before the twist.
230-
Drive 1 is the one at the end of the cable; that is, after the twist.
231-
Drive 0 is the default. If you only have one drive, remember to plug the
232-
drive into the connector _before_ the twist. (Or you can tell the client
233-
to select drive 1 by using `-s :d=1`.)
228+
If you have **two** drives, plug them into both connectors. FluxEngine,
229+
sadly, non-standard disk numbering (there are reasons). Drive 0 is the
230+
one nearest the motherboard; that is, before the twist. Drive 1 is the
231+
one at the end of the cable; that is, after the twist. Drive 0 is the
232+
default. You can tell the client to select drive 1 by using `-s :d=1`.
233+
234+
If you have **one** drive, you may plug it into _either_ connector.
235+
FluxEngine will autodetect it and treat it as drive 0. However, you'll
236+
get the most reliable electrical signal if you plug it in at the end of
237+
the cable.
238+
239+
**A note on termination:** some 5.25" drives require jumper configuration
240+
to tell them whether they're at the end of the cable or in the middle of
241+
the cable. 3.5" drives don't, and my 5.25" drives don't, so I can't
242+
advise there. Consult your drive datasheet for details.
234243

235244
3. **Important.** Make sure that no disk you care about is in the drive.
236245
(Because if your wiring is wrong and a disk is inserted, you'll corrupt

doc/disk-ibm.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,28 @@ of the disk image will vary depending on the format.
4141

4242
Configuration options you'll want include:
4343

44-
- `--sector-id-base`: specifies the ID of the first sector; this defaults
45-
to 1. Some formats (like the Acorn ones) start at 0. This can't be
44+
- `--ibm-sector-id-base=N`: specifies the ID of the first sector; this defaults
45+
to 1. Some formats (like the Acorn ones) start at 0. This can't be
4646
autodetected because FluxEngine can't distinguish between a disk which
4747
starts at sector 1 and a disk which starts at sector 0 but all the sector
4848
0s are missing.
4949

50-
- `--ignore-side-byte`: each sector header describes the location of the
50+
- `--ibm-ignore-side-byte=true|false`: each sector header describes the location of the
5151
sector: sector ID, track and side. Some formats use the wrong side ID, so
5252
the sectors on side 1 are labelled as belonging to side 0. This causes
5353
FluxEngine to see duplicate sectors (as it can't distinguish between the
5454
two sides). This option tells FluxEngine to ignore the side byte completely
5555
and use the physical side instead.
5656

57+
- `--ibm-required-sectors=range`: if you know how many sectors to expect per
58+
track, you can improve reads by telling FluxEngine what to expect here. If
59+
a track is read and a sector on this list is _not_ present, then FluxEngine
60+
assumes the read failed and will retry. This avoids the situation where
61+
FluxEngine can't tell the difference between a sector missing because it's
62+
bad or a sector missing because it was never written in the first place. If
63+
sectors are seen outside the range here, it will still be read. You can use
64+
the same syntax as for track specifiers: e.g. `0-9`, `0,1,2,3`, etc.
65+
5766

5867
Writing disks
5968
-------------

lib/dataspec.cc

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,31 @@ std::vector<std::string> DataSpec::split(
1515
{
1616
std::vector<std::string> ret;
1717

18-
size_t start = 0;
19-
size_t end = 0;
20-
size_t len = 0;
21-
do
22-
{
23-
end = s.find(delimiter,start);
24-
len = end - start;
25-
std::string token = s.substr(start, len);
26-
ret.emplace_back( token );
27-
start += len + delimiter.length();
28-
}
29-
while (end != std::string::npos);
18+
if (!s.empty())
19+
{
20+
size_t start = 0;
21+
size_t end = 0;
22+
size_t len = 0;
23+
do
24+
{
25+
end = s.find(delimiter,start);
26+
len = end - start;
27+
std::string token = s.substr(start, len);
28+
ret.emplace_back( token );
29+
start += len + delimiter.length();
30+
}
31+
while (end != std::string::npos);
32+
}
33+
3034
return ret;
3135
}
3236

33-
DataSpec::Modifier DataSpec::parseMod(const std::string& spec)
37+
std::set<unsigned> DataSpec::parseRange(const std::string& data)
3438
{
35-
static const std::regex MOD_REGEX("([a-z]*)=([-x+0-9,]*)");
36-
static const std::regex DATA_REGEX("([0-9]+)(?:(?:-([0-9]+))|(?:\\+([0-9]+)))?(?:x([0-9]+))?");
39+
static const std::regex DATA_REGEX("([0-9]+)(?:(?:-([0-9]+))|(?:\\+([0-9]+)))?(?:x([0-9]+))?");
3740

38-
std::smatch match;
39-
if (!std::regex_match(spec, match, MOD_REGEX))
40-
Error() << "invalid data modifier syntax '" << spec << "'";
41-
42-
Modifier m;
43-
m.name = match[1];
44-
m.source = spec;
45-
for (auto& data : split(match[2], ","))
41+
std::set<unsigned> result;
42+
for (auto& data : split(data, ","))
4643
{
4744
int start = 0;
4845
int count = 1;
@@ -64,17 +61,32 @@ DataSpec::Modifier DataSpec::parseMod(const std::string& spec)
6461
Error() << "mod '" << data << "' specifies an illegal quantity";
6562

6663
for (int i = start; i < (start+count); i += step)
67-
m.data.insert(i);
64+
result.insert(i);
6865
}
6966

67+
return result;
68+
}
69+
70+
DataSpec::Modifier DataSpec::parseMod(const std::string& spec)
71+
{
72+
static const std::regex MOD_REGEX("([a-z]*)=([-x+0-9,]*)");
73+
74+
std::smatch match;
75+
if (!std::regex_match(spec, match, MOD_REGEX))
76+
Error() << "invalid data modifier syntax '" << spec << "'";
77+
78+
Modifier m;
79+
m.name = match[1];
80+
m.source = spec;
81+
m.data = parseRange(match[2]);
7082
return m;
7183
}
7284

7385
void DataSpec::set(const std::string& spec)
7486
{
7587
std::vector<std::string> words = split(spec, ":");
7688
if (words.size() == 0)
77-
Error() << "empty data specification (you have to specify *something*)";
89+
return;
7890

7991
filename = words[0];
8092
if (words.size() > 1)

lib/dataspec.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class DataSpec
3434
public:
3535
static std::vector<std::string> split(
3636
const std::string& s, const std::string& delimiter);
37+
static std::set<unsigned> parseRange(const std::string& spec);
38+
3739
static Modifier parseMod(const std::string& spec);
3840

3941
public:
@@ -117,4 +119,34 @@ class DataSpecFlag : public Flag
117119
DataSpec _value;
118120
};
119121

122+
class RangeFlag : public Flag
123+
{
124+
public:
125+
RangeFlag(const std::vector<std::string>& names, const std::string helptext,
126+
const std::string& defaultValue):
127+
Flag(names, helptext),
128+
_stringValue(defaultValue),
129+
_value(DataSpec::parseRange(defaultValue))
130+
{}
131+
132+
const std::set<unsigned>& get() const
133+
{ checkInitialised(); return _value; }
134+
135+
operator const std::set<unsigned>& () const
136+
{ return get(); }
137+
138+
bool hasArgument() const { return true; }
139+
const std::string defaultValueAsString() const { return _stringValue; }
140+
141+
void set(const std::string& value)
142+
{
143+
_stringValue = value;
144+
_value = DataSpec::parseRange(value);
145+
}
146+
147+
private:
148+
std::string _stringValue;
149+
std::set<unsigned> _value;
150+
};
151+
120152
#endif

lib/decoders/decoders.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,10 @@ void AbstractDecoder::pushRecord(const Fluxmap::Position& start, const Fluxmap::
8888
_track->rawrecords.push_back(record);
8989
_fmr->seek(here);
9090
}
91+
92+
std::set<unsigned> AbstractDecoder::requiredSectors(Track& track) const
93+
{
94+
static std::set<unsigned> empty;
95+
return empty;
96+
}
97+

0 commit comments

Comments
 (0)