1414
1515from greaseweazle import error
1616from greaseweazle .codec import codec
17- from greaseweazle .codec .ibm .ibm import decode , encode , fm_encode , mfm_encode
17+ from greaseweazle .codec .ibm .ibm import decode , encode , fm_encode
1818from greaseweazle .track import MasterTrack , PLL , PLLTrack
1919from greaseweazle .flux import HasFlux
2020
2121default_revs = 1
2222
2323bad_sector = b'-=[BAD SECTOR]=-'
2424
25- mfm_sync = bitarray (endian = 'big' )
26- mfm_sync .frombytes (mfm_encode (encode (b'\x00 \xfb ' )))
25+ min_sync = 1000
26+ max_sync = 0
27+ min_sync_zero = 1000
28+ max_sync_zero = 0
29+ min_datasync = 1000
30+ max_datasync = 0
2731
28- fm_sync = bitarray (endian = 'big' )
29- fm_sync .frombytes (fm_encode (encode (b'\x00 \x00 \x00 \x00 \x00 \x01 ' )))
3032
3133
32- #Sector starts with 23 * 16 zero bits, then a 0001 sync word followed by the adress field
33- #There is an 18us "splice" between the address field and the following data field sync
34- #The documentation is not very clear on the exact number of bits in the data sync field
35- #The splice plus the data sync add up to a non-integer number of bits, so we
36- #need to search for the data sync pattern to locate the data
37-
38- #"Manual" FM encoding....
39- fm_datasync = bitarray ("101010101010101010101010101010101010101010101010101010101011" )
40-
4134
4235def csum (dat ):
4336 #CRC with poly x^16 + x^8 + 1
@@ -49,31 +42,65 @@ def csum(dat):
4942 return y
5043
5144class Mode (Enum ):
52- FM , MFM = range ( 2 )
45+ FM = 0
5346 def __str__ (self ):
54- NAMES = [ 'Data General FM' , 'Data General MFM' ]
47+ NAMES = [ 'Data General FM' ]
5548 return f'{ NAMES [self .value ]} '
5649
5750class DataGeneral (codec .Codec ):
51+ '''
52+ Data General 8" floppy disk format, from DG document 015-000088-00, flowchart page G-4
53+
54+ Sector read:
55+ <sector index pulse> <704uS delay> <sector address sync bit> <16 bits sector address (preamble) <20 uS delay> <64 uS delay> <data sync bit> <data 512 bits><crc 16 bits>
56+
57+ Sector write:
58+ <sector index pulse> <704uS delay> <sector address sync bit> <16 bits sector address (preamble) <20 uS delay> <write zeros for 160 uS -> 40 zero bits> <data sync bit> <data 512 bits><crc 16 bits>
5859
60+ Formatting operation:
61+ <sector index pulse> <160 uS delay> <352 bits '0'> <0000000000000001> <16 bits sector address> <352 bits '0'> <3520 bits 'dont care'>
62+
63+ The actual number of zero bits before the sector address sync bit observed in disk images varies between 572 and 740
64+
65+ '''
66+
5967 time_per_rev = 0.166
6068
6169 verify_revs : float = default_revs
6270
6371 def __init__ (self , cyl : int , head : int , config ):
64- if config .mode is Mode .FM :
65- self .clock = 2e-6
66- self .bps = 512
67- self .sync = fm_sync
68- self .datasync = fm_datasync
69- self .presync_bytes = 21
70- self .sync_bytes = 6
71- else :
72- self .clock = 2e-6
73- self .bps = 512
74- self .sync = mfm_sync
75- self .presync_bytes = 34
76- self .sync_bytes = 2
72+
73+ self .clock = 2e-6
74+ self .bps = 512
75+
76+ self .address_sync = b'\x00 \x01 '
77+ self .data_sync = b'\x00 \x01 '
78+
79+ self .address_sync_fmbits = bitarray (endian = 'big' )
80+ self .address_sync_fmbits .frombytes (fm_encode (encode (self .address_sync )))
81+
82+ self .data_sync_fmbits = bitarray (endian = 'big' )
83+ self .data_sync_fmbits .frombytes (fm_encode (encode (self .data_sync )))
84+
85+ #According to the documentation, there is a 704uS delay before the drive reads the sync word for the sector address (preamble)
86+ #This is equivalent to 704 presync FM bits followed by 0x0001 (32 FM bits) sync word
87+ #The actual number of FM bits before the sector address sync word observed in disk images varies between 572 and 740
88+ self .pre_addresssync_read_fm_bits = 560
89+ #self.pre_addresssync_read_fm_bits = 100
90+
91+ #self.pre_addresssync_write_fm_bits = 704
92+ self .pre_addresssync_write_fm_bytes = 44
93+
94+ #there is a 20us + 64us delay before the data sync bit is read corresponding to a total of 84 FM bits + 2 fm sync bits
95+ #When writing, there is a 20uS delay, then 40 zero bits followed by a one bit (the sync bit) are written
96+ #The actual number of zero (FM) bits before the data sync bit observed in disk images varies between 97 and 98
97+ #equivalent to 66 FM bits followed by 0x0001 (32 FM bits) syncword. For reading, use minimum of 60 FM bits before the syncword
98+
99+ self .pre_datasync_read_fm_bits = 60
100+ #self.pre_datasync_write_fm_bits = 150 #20 + 160 + 2 = 150 presync + 32 sync word 0x0001
101+ self .pre_datasync_write_fm_bytes = 5 #20 + 160 + 2 = 150 presync + 32 sync word 0x0001
102+
103+
77104 self .cyl , self .head = cyl , head
78105 self .config = config
79106 self .sector : List [Optional [bytes ]]
@@ -114,6 +141,13 @@ def set_img_track(self, tdat: bytes) -> int:
114141 return totsize
115142
116143 def decode_flux (self , track : HasFlux , pll : Optional [PLL ]= None ) -> None :
144+ global min_sync
145+ global max_sync
146+ global min_sync_zero
147+ global max_sync_zero
148+ global min_datasync
149+ global max_datasync
150+
117151 flux = track .flux ()
118152 if flux .time_per_rev < self .time_per_rev / 2 :
119153 flux .identify_hard_sectors ()
@@ -148,23 +182,62 @@ def decode_flux(self, track: HasFlux, pll: Optional[PLL]=None) -> None:
148182 #print(bits[s:e])
149183 data = decode (bits [s :e ].tobytes ())
150184 #print(data.hex())
151- offs = bits [s :e ].search (self .sync )
185+
186+ #Start searching for sync after a minimum delay of pre_addresssync_read_bits
187+ offs = bits [s + self .pre_addresssync_read_fm_bits :e ].search (self .address_sync_fmbits )
152188 if (off := next (offs , None )) is None :
153189 continue
154- off += (self .sync_bytes ) * 16
190+
191+ numsync = self .pre_addresssync_read_fm_bits + off + len (self .address_sync_fmbits )
192+ #Get offset of first preamble bit
193+ off += self .pre_addresssync_read_fm_bits + len (self .address_sync_fmbits )
194+
195+
196+ #Reed 2 byte preamb;e
155197 data = decode (bits [s + off :s + off + 2 * 16 ].tobytes ())
156- #print(data.hex())
198+
199+ #Extract track# and sector#
157200 track = data [0 ] & 0x7F
158201 sector = data [1 ] >> 2
159- #print(f'Track {track}, Sector {sector}')
202+
203+
204+ if numsync < min_sync :
205+ min_sync = numsync
206+ if numsync > max_sync :
207+ max_sync = numsync
160208
209+ numsynczero = 0
161210
162- dataoffs = bits [s + off + 2 * 16 :e ].search (self .datasync )
211+ for kk in range (s + numsync - 4 , s , - 2 ):
212+ if bits [kk :kk + 2 ] != bitarray ('10' ):
213+ break
214+ numsynczero += 2
215+
216+ if numsynczero < min_sync_zero :
217+ min_sync_zero = numsynczero
218+ if numsynczero > max_sync_zero :
219+ max_sync_zero = numsynczero
220+ #print(f'Track {track}, Sector {sector}, after {numsync} sync bits, {numsynczero} zero value sync bits, min sync {min_sync}, max sync {max_sync}, min zero {min_sync_zero}, max zero {max_sync_zero}')
221+
222+ dsyncstart = off + 2 * 16
223+ #Skip to the start of the data sync, skip over 2 byte preamble plus minimum delay of pre_datasync_read_bits
224+ off += 2 * 16 + self .pre_datasync_read_fm_bits
225+ dataoffs = bits [s + off :e ].search (self .data_sync_fmbits )
163226
164227 if (dataoff := next (dataoffs , None )) is None :
165228 continue
229+
230+ dataoff += off + len (self .data_sync_fmbits )
231+ numdsync = dataoff - dsyncstart
232+
233+ if numdsync < min_datasync :
234+ min_datasync = numdsync
235+ if numdsync > max_datasync :
236+ max_datasync = numdsync
237+
238+ #print(f'Data sync {numdsync} bits, min {min_datasync}, max {max_datasync}')
166239
167- data = decode (bits [s + off + 2 * 16 + dataoff + len ( self . datasync ) : s + off + 2 * 16 + dataoff + len ( self . datasync ) + 518 * 16 ].tobytes ())
240+ data = decode (bits [s + dataoff : s + dataoff + 518 * 16 ].tobytes ())
168241 #print(data[:512].hex())
169242 #print(data[512:514].hex())
170243 #print(data[514:].hex())
@@ -177,20 +250,33 @@ def decode_flux(self, track: HasFlux, pll: Optional[PLL]=None) -> None:
177250
178251
179252 def master_track (self ) -> MasterTrack :
180- raise error .Fatal ('NOT IMPLEMENTED' )
181253 t = bytes ()
182254 slen = int ((self .time_per_rev / self .clock / self .nsec / 16 ))
183255
184256 for sec_id in range (self .nsec ):
185- s = encode (bytes (self .presync_bytes ))
186- s += encode (b'\xfb ' * self .sync_bytes )
257+ #
258+ s = encode (b'\x00 ' * self .pre_addresssync_write_fm_bytes )
259+ s += encode (self .address_sync )
260+
261+
262+
187263 sector = self .sector [sec_id ]
264+ trackid = self .cyl & 7
265+ sectorenc = (sec_id & 0xF ) << 2
266+ preamble = struct .pack ('>BB' , trackid , sectorenc )
267+
268+ s += encode (preamble )
269+
270+ s += encode (b'\x00 ' * self .pre_datasync_write_fm_bytes )
271+ s += encode (self .data_sync )
272+
188273 data = bad_sector * (self .bps // 16 ) if sector is None else sector
189- s += encode (data + bytes ([csum (data )]))
274+
275+ s += encode (data + csum (data ).to_bytes (2 , 'big' ))
190276 s += encode (bytes (slen - len (s )// 2 ))
191277 t += s
192278
193- t = mfm_encode ( t ) if self . config . mode is Mode . MFM else fm_encode (t )
279+ t = fm_encode (t )
194280
195281 hardsector_bits = [slen * 16 * i for i in range (self .nsec )]
196282
@@ -222,8 +308,6 @@ def add_param(self, key: str, val) -> None:
222308 elif key == 'mode' :
223309 if val == 'fm' :
224310 self .mode = Mode .FM
225- elif val == 'mfm' :
226- self .mode = Mode .MFM
227311 else :
228312 raise error .Fatal ('unrecognised mode %s' % val )
229313 else :
0 commit comments