| 1 |
org #0100 |
| 2 |
|
| 3 |
ld hl,debug_buffer ; circular buffer for debug output |
| 4 |
ld (debug_ptr),hl |
| 5 |
|
| 6 |
; TODO simplify commandline parsing |
| 7 |
; parse commandline |
| 8 |
ld hl,#0081 |
| 9 |
parse_loop ld a,(hl) |
| 10 |
inc hl |
| 11 |
or a |
| 12 |
jp z,parse_end |
| 13 |
cp 13 |
| 14 |
jp z,parse_end |
| 15 |
cp ' ' |
| 16 |
jr z,parse_loop ; skip space |
| 17 |
cp 9 |
| 18 |
jr z,parse_loop ; skip tab |
| 19 |
ld c,a |
| 20 |
and #df ; to upper case |
| 21 |
cp 'D' |
| 22 |
jp z,check_debug |
| 23 |
cp 'S' |
| 24 |
jp z,check_s |
| 25 |
cp 'T' |
| 26 |
jp nz,unknown_option |
| 27 |
check_t ld a,(hl) |
| 28 |
inc hl |
| 29 |
and #df |
| 30 |
cp 'Y' |
| 31 |
jp nz,unknown_option |
| 32 |
ld a,(hl) |
| 33 |
inc hl |
| 34 |
and #df |
| 35 |
cp 'P' |
| 36 |
jp nz,unknown_option |
| 37 |
ld a,(hl) |
| 38 |
inc hl |
| 39 |
and #df |
| 40 |
cp 'E' |
| 41 |
jp nz,unknown_option |
| 42 |
ld a,(hl) |
| 43 |
inc hl |
| 44 |
cp '=' |
| 45 |
jp nz,unknown_option |
| 46 |
check_type ld a,(hl) |
| 47 |
inc hl |
| 48 |
and #df |
| 49 |
cp 'P' |
| 50 |
jp z,check_philips |
| 51 |
cp 'M' |
| 52 |
jr z,check_microsol |
| 53 |
cp 'N' |
| 54 |
jp nz,unknown_option |
| 55 |
|
| 56 |
check_national ld a,(hl) |
| 57 |
inc hl |
| 58 |
and #df |
| 59 |
cp 'A' |
| 60 |
jp nz,unknown_option |
| 61 |
ld a,(hl) |
| 62 |
inc hl |
| 63 |
and #df |
| 64 |
cp 'T' |
| 65 |
jp nz,unknown_option |
| 66 |
ld a,(hl) |
| 67 |
inc hl |
| 68 |
and #df |
| 69 |
cp 'I' |
| 70 |
jp nz,unknown_option |
| 71 |
ld a,(hl) |
| 72 |
inc hl |
| 73 |
and #df |
| 74 |
cp 'O' |
| 75 |
jp nz,unknown_option |
| 76 |
ld a,(hl) |
| 77 |
inc hl |
| 78 |
and #df |
| 79 |
cp 'N' |
| 80 |
jp nz,unknown_option |
| 81 |
ld a,(hl) |
| 82 |
inc hl |
| 83 |
and #df |
| 84 |
cp 'A' |
| 85 |
jp nz,unknown_option |
| 86 |
ld a,(hl) |
| 87 |
inc hl |
| 88 |
and #df |
| 89 |
cp 'L' |
| 90 |
jp nz,unknown_option |
| 91 |
ld de,natl_driver |
| 92 |
ld (driver),de |
| 93 |
jp parse_loop |
| 94 |
|
| 95 |
check_microsol ld a,(hl) |
| 96 |
inc hl |
| 97 |
and #df |
| 98 |
cp 'I' |
| 99 |
jp nz,unknown_option |
| 100 |
ld a,(hl) |
| 101 |
inc hl |
| 102 |
and #df |
| 103 |
cp 'C' |
| 104 |
jp nz,unknown_option |
| 105 |
ld a,(hl) |
| 106 |
inc hl |
| 107 |
and #df |
| 108 |
cp 'R' |
| 109 |
jp nz,unknown_option |
| 110 |
ld a,(hl) |
| 111 |
inc hl |
| 112 |
and #df |
| 113 |
cp 'O' |
| 114 |
jp nz,unknown_option |
| 115 |
ld a,(hl) |
| 116 |
inc hl |
| 117 |
and #df |
| 118 |
cp 'S' |
| 119 |
jp nz,unknown_option |
| 120 |
ld a,(hl) |
| 121 |
inc hl |
| 122 |
and #df |
| 123 |
cp 'O' |
| 124 |
jp nz,unknown_option |
| 125 |
ld a,(hl) |
| 126 |
inc hl |
| 127 |
and #df |
| 128 |
cp 'L' |
| 129 |
jp nz,unknown_option |
| 130 |
ld de,mics_driver |
| 131 |
ld (driver),de |
| 132 |
jp parse_loop |
| 133 |
|
| 134 |
check_philips ld a,(hl) |
| 135 |
inc hl |
| 136 |
and #df |
| 137 |
cp 'H' |
| 138 |
jp nz,unknown_option |
| 139 |
ld a,(hl) |
| 140 |
inc hl |
| 141 |
and #df |
| 142 |
cp 'I' |
| 143 |
jp nz,unknown_option |
| 144 |
ld a,(hl) |
| 145 |
inc hl |
| 146 |
and #df |
| 147 |
cp 'L' |
| 148 |
jp nz,unknown_option |
| 149 |
ld a,(hl) |
| 150 |
inc hl |
| 151 |
and #df |
| 152 |
cp 'I' |
| 153 |
jp nz,unknown_option |
| 154 |
ld a,(hl) |
| 155 |
inc hl |
| 156 |
and #df |
| 157 |
cp 'P' |
| 158 |
jp nz,unknown_option |
| 159 |
ld a,(hl) |
| 160 |
inc hl |
| 161 |
and #df |
| 162 |
cp 'S' |
| 163 |
jp nz,unknown_option |
| 164 |
ld de,phil_driver |
| 165 |
ld (driver),de |
| 166 |
jp parse_loop |
| 167 |
|
| 168 |
check_s ld a,(hl) |
| 169 |
inc hl |
| 170 |
and #df |
| 171 |
cp 'T' |
| 172 |
jp nz,unknown_option |
| 173 |
ld a,(hl) |
| 174 |
inc hl |
| 175 |
and #df |
| 176 |
cp 'A' |
| 177 |
jr z,check_start |
| 178 |
cp 'O' |
| 179 |
jp nz,unknown_option |
| 180 |
check_stop ld a,(hl) |
| 181 |
inc hl |
| 182 |
and #df |
| 183 |
cp 'P' |
| 184 |
jp nz,unknown_option |
| 185 |
ld a,(hl) |
| 186 |
inc hl |
| 187 |
cp '=' |
| 188 |
jp nz,unknown_option |
| 189 |
stop_option call parse_dec |
| 190 |
ld (stop_track),a |
| 191 |
ld a,1 |
| 192 |
ld (stop_set),a |
| 193 |
jp parse_loop |
| 194 |
|
| 195 |
check_start ld a,(hl) |
| 196 |
inc hl |
| 197 |
and #df |
| 198 |
cp 'R' |
| 199 |
jp nz,unknown_option |
| 200 |
ld a,(hl) |
| 201 |
inc hl |
| 202 |
and #df |
| 203 |
cp 'T' |
| 204 |
jp nz,unknown_option |
| 205 |
ld a,(hl) |
| 206 |
inc hl |
| 207 |
cp '=' |
| 208 |
jp nz,unknown_option |
| 209 |
start_option call parse_dec |
| 210 |
ld (start_track),a |
| 211 |
jp parse_loop |
| 212 |
|
| 213 |
check_debug ld a,(hl) |
| 214 |
inc hl |
| 215 |
and #df |
| 216 |
cp 'E' |
| 217 |
jp nz,unknown_option |
| 218 |
ld a,(hl) |
| 219 |
inc hl |
| 220 |
and #df |
| 221 |
cp 'B' |
| 222 |
jp nz,unknown_option |
| 223 |
ld a,(hl) |
| 224 |
inc hl |
| 225 |
and #df |
| 226 |
cp 'U' |
| 227 |
jp nz,unknown_option |
| 228 |
ld a,(hl) |
| 229 |
inc hl |
| 230 |
and #df |
| 231 |
cp 'G' |
| 232 |
jp nz,unknown_option |
| 233 |
ld a,(hl) |
| 234 |
inc hl |
| 235 |
cp '=' |
| 236 |
jp nz,unknown_option |
| 237 |
debug_option call parse_dec |
| 238 |
ld (debug),a |
| 239 |
jp parse_loop |
| 240 |
|
| 241 |
parse_end |
| 242 |
; TODO check start_track <= stop_track |
| 243 |
; and both <= 85 |
| 244 |
|
| 245 |
; Select the correct driver routines |
| 246 |
; For now we only have a driver for Philps machines |
| 247 |
ld hl,(driver) |
| 248 |
ld de,driver_routines |
| 249 |
ld bc,driver_size |
| 250 |
ldir |
| 251 |
|
| 252 |
ld a,'S' |
| 253 |
call debug_log |
| 254 |
call print_pc |
| 255 |
db "Read-DMK version 0.42",13,10 |
| 256 |
db 13,10 |
| 257 |
db "Insert source disk in drive A",13,10 |
| 258 |
db "Insert destination disk in drive B",13,10 |
| 259 |
db "Press any key to continue ...",0 |
| 260 |
ld ix,#009f |
| 261 |
ld iy,(#fcc0) |
| 262 |
call #001c |
| 263 |
call print_pc |
| 264 |
db 13,10,13,10,0 |
| 265 |
|
| 266 |
; loop over all cylinders and both sides |
| 267 |
ld a,(start_track) |
| 268 |
cylinder_loop ld (cylinder),a |
| 269 |
xor a |
| 270 |
side_loop ld (side),a ; start at side 0 |
| 271 |
|
| 272 |
; delete debug file, so that we never by accident end up with a leftover |
| 273 |
; old debug file |
| 274 |
ld de,fcb_debug |
| 275 |
ld c,#13 ; delete file |
| 276 |
call #0005 |
| 277 |
|
| 278 |
; Prepare drive: |
| 279 |
; - select drive, turn motor on |
| 280 |
; - select side |
| 281 |
; - seek to correct track |
| 282 |
ld a,'L' |
| 283 |
call debug_log |
| 284 |
call select_fdc |
| 285 |
call seek |
| 286 |
|
| 287 |
;; TODO currently we always restore the head to track 0 followed by a seek to |
| 288 |
;; the destination track. I tried to use a 'step-in' command instead, but I |
| 289 |
;; couldn't get this to work correctly. I suspect it's because I'm using the |
| 290 |
;; BDOS routines to save a file (although to the B drive) and that interferes |
| 291 |
;; with the state of the A drive. A possible improvement would be to buffer as |
| 292 |
;; much data in (v)ram before writing it out to disk. So minimize the number |
| 293 |
;; of switches between the A and B drives. |
| 294 |
|
| 295 |
call print_pc |
| 296 |
db 13,10 |
| 297 |
db "Cylinder: ",0 |
| 298 |
ld a,(cylinder) |
| 299 |
call print_dec_a |
| 300 |
call print_pc |
| 301 |
db " side: ",0 |
| 302 |
ld a,(side) |
| 303 |
call print_dec_a |
| 304 |
|
| 305 |
call select_fdc ; TODO is/was this call still/ever needed? |
| 306 |
|
| 307 |
|
| 308 |
; Use the "read address" WD2793 command in a loop to read all address marks |
| 309 |
; on this track. We start this loop right after the index pulse. During the |
| 310 |
; wait-for-next-byte-loop we also increase a counter, and the value of this |
| 311 |
; counter is stored together with the read-address-data. This counter value |
| 312 |
; will later be used to estimate the location of the address mark in the raw |
| 313 |
; track data. |
| 314 |
; |
| 315 |
; We also use this counter to make sure we have read all address marks of the |
| 316 |
; whole track. Experiments on a real MSX have shown that the counter has |
| 317 |
; approximately the value 0x38E0 after one revolution (though rotation speed |
| 318 |
; can vary). We stop the loop after the counter has reached value 0xc000. So |
| 319 |
; this makes sure we have read each address mark at least 3 times (see below |
| 320 |
; why this is needed). |
| 321 |
|
| 322 |
ld a,'R' |
| 323 |
call debug_log |
| 324 |
xor a ; for reasons explained below, we |
| 325 |
ld (retries),a ; sometimes need to retry |
| 326 |
retry call print_pc |
| 327 |
db " (attempt ",0 |
| 328 |
ld a,(retries) |
| 329 |
inc a |
| 330 |
call print_dec_a |
| 331 |
call print_pc |
| 332 |
db ")",13,10,0 |
| 333 |
|
| 334 |
xor a |
| 335 |
ld (addr_retries),a |
| 336 |
|
| 337 |
do_addr_retry |
| 338 |
ld a,'r' |
| 339 |
call debug_log |
| 340 |
call print_pc |
| 341 |
db "Read addresses ...",0 |
| 342 |
|
| 343 |
ld iy,(driver_rd_addr) |
| 344 |
jp (iy) |
| 345 |
|
| 346 |
addr_error ; 'Record not found' status bit was set. This means there |
| 347 |
; wasn't any address mark in this track. This e.g. happens |
| 348 |
; if you read the 81th track on a normal disk. |
| 349 |
; don't retry on this |
| 350 |
jr skip_addr |
| 351 |
|
| 352 |
read_addr_err call print_pc |
| 353 |
db "Read address command didn't return 6 bytes.",13,10,0 |
| 354 |
|
| 355 |
addr_retry ld a,(addr_retries) |
| 356 |
inc a |
| 357 |
ld (addr_retries),a |
| 358 |
cp 20 |
| 359 |
jp c,do_addr_retry |
| 360 |
|
| 361 |
call print_pc |
| 362 |
db "Couldn't reliably read address marks ... skipped",13,10,0 |
| 363 |
|
| 364 |
skip_addr ld de,addr_buffer+1 ; as long as it's > addr_buffer |
| 365 |
ld (addr_buf_end),de |
| 366 |
ld hl,0 |
| 367 |
jr addr_found |
| 368 |
|
| 369 |
addr_done ld (addr_buf_end),de |
| 370 |
|
| 371 |
|
| 372 |
; Now each address mark is read for at least 3 full revolutions. Analyze this |
| 373 |
; data to detect the number of address marks in one revolution. Note that it's |
| 374 |
; possible a single track contains several identical address marks. So |
| 375 |
; detecting the number of sectors in the track is not as simple as searching |
| 376 |
; for the 2nd occurrence of the 1st read address mark. |
| 377 |
; |
| 378 |
; Some examples (the latters 'A'-'Z' each represent a unique address mark): |
| 379 |
; * ABCDEFGHIABCDEFGHIABCDEFGHIABCD |
| 380 |
; -> 'normal' track with 9 unique address marks |
| 381 |
; * ABCDABEABCDABEABCDABEABC |
| 382 |
; -> 8 unique address marks, the marks A and B appear twice |
| 383 |
; * ABCABCABCABCABCABCABCA |
| 384 |
; -> the current algorithm detects a track with 3 unique address marks |
| 385 |
; so it cannot distinguish the track 'ABC' from 'ABCABC' |
| 386 |
; TODO fix this by taking the timing into account |
| 387 |
; |
| 388 |
; Note that the detection can fail if we did not read at least 2 full |
| 389 |
; revolutions. For example, suppose the actual track contains these marks: |
| 390 |
; 'AAAAAAABAA' (10 unique marks, mark A is duplicated 9 times). Now suppose we |
| 391 |
; only read 'AAAAAAABAAAAAAA'. Valid periods for this sequence could be 8, 9 |
| 392 |
; or 10. (The current algorithm would return 8). This ambiguity disappears if |
| 393 |
; we read at least 2 full revolutions. |
| 394 |
|
| 395 |
ld hl,0 |
| 396 |
next_period ld ix,(addr_buf_end) |
| 397 |
ld a,ixl |
| 398 |
and 7 |
| 399 |
jp nz,read_addr_err |
| 400 |
ld de,addr_buffer |
| 401 |
call get_period |
| 402 |
addr_found ld (nb_sectors),hl |
| 403 |
; TODO check not more than 64 (DMK cannot handle that) |
| 404 |
; if (nb_sectors > 64) error("not supported by dmk"); |
| 405 |
|
| 406 |
call print_pc |
| 407 |
db " found ",0 |
| 408 |
ld hl,(nb_sectors) |
| 409 |
call print_dec_hl ; TODO print_dec_a |
| 410 |
call print_pc |
| 411 |
db " sectors",13,10,0 |
| 412 |
|
| 413 |
; We now know the period after which the address marks start repeating. |
| 414 |
; Take the difference of the counter value that was stored at the 1st |
| 415 |
; and address mark and the 1st replica of this mark. |
| 416 |
; |
| 417 |
; This difference should be around 0x38E0 (tested on real machine). |
| 418 |
; TODO if measured value is far below 0x38E0, try doubling, tripling, ... |
| 419 |
; until it gets in range. |
| 420 |
|
| 421 |
ld hl,(nb_sectors) |
| 422 |
ld a,h |
| 423 |
or l |
| 424 |
jp z,read_track ; skip ticks-check |
| 425 |
add hl,hl |
| 426 |
add hl,hl |
| 427 |
add hl,hl |
| 428 |
ld de,addr_buffer |
| 429 |
add hl,de |
| 430 |
ld de,(addr_buf_end) |
| 431 |
or a |
| 432 |
sbc hl,de |
| 433 |
jr c,ok_periodic |
| 434 |
|
| 435 |
; period is whole buffer -> not periodic |
| 436 |
call print_pc |
| 437 |
db "Not periodic (read noise?)",13,10,0 |
| 438 |
jp addr_retry |
| 439 |
|
| 440 |
ok_periodic add hl,de |
| 441 |
ld de,ofst_amark_tick |
| 442 |
add hl,de |
| 443 |
ld a,(hl) |
| 444 |
inc hl |
| 445 |
ld h,(hl) |
| 446 |
ld l,a |
| 447 |
ld de,(addr_buffer+ofst_amark_tick) |
| 448 |
or a |
| 449 |
sbc hl,de |
| 450 |
ld (ticks),hl |
| 451 |
|
| 452 |
ld a,(debug) |
| 453 |
or a |
| 454 |
jr z,debug_2 |
| 455 |
call print_pc |
| 456 |
db ", ticks: ",0 |
| 457 |
ld hl,(ticks) |
| 458 |
call print_dec_hl ; is this info useful? |
| 459 |
call print_pc |
| 460 |
db 13,10,0 |
| 461 |
debug_2 |
| 462 |
|
| 463 |
; If there were read errors during the 'read address' command, then it's |
| 464 |
; possible the detected period is larger than one disk revolution. This for |
| 465 |
; example happened for the disks of 'New Vision Benelux'. |
| 466 |
; We read the address marks for about 3 revolutions, but if there was a read |
| 467 |
; error for e.g. an address mark in the 2nd revolution (so the read address |
| 468 |
; command didn't return the exact same 6 bytes than for revolution 1 and 3), |
| 469 |
; then the get_period routine won't detect the true period, but instead it |
| 470 |
; returns the full 3 revolutions as the period (without internal repetition). |
| 471 |
; We can detect this error by looking at the detected number of ticks for |
| 472 |
; the period. If the detected period is for a single revolution, it should |
| 473 |
; be in range [13834, 15290]. But if it's higher we've probably estimated |
| 474 |
; more than one revolution. |
| 475 |
|
| 476 |
; TODO also check for lower than 13834. |
| 477 |
ld hl,(ticks) |
| 478 |
ld de,(ticks_min) ; depends on driver |
| 479 |
or a |
| 480 |
sbc hl,de |
| 481 |
jr c,too_short |
| 482 |
add hl,de |
| 483 |
ld de,(ticks_max) ; depends on driver |
| 484 |
or a |
| 485 |
sbc hl,de |
| 486 |
jp nc,addr_retry ; maybe it works in the next attempt |
| 487 |
jr read_track |
| 488 |
|
| 489 |
too_short ld hl,(nb_sectors) |
| 490 |
jp next_period |
| 491 |
|
| 492 |
|
| 493 |
; Use the WD2793 "read track" command to get the raw track data. |
| 494 |
; Also store the number of read bytes. This is the track length. |
| 495 |
; The 'normal' track length is 6250 bytes, but this can also vary. |
| 496 |
|
| 497 |
read_track |
| 498 |
ld a,'t' |
| 499 |
call debug_log |
| 500 |
call print_pc |
| 501 |
db "Read track ...",0 |
| 502 |
|
| 503 |
;; TODO is this call required? |
| 504 |
;; Quibus reported a hang during 'Read track' at one point. |
| 505 |
;; The LED of drive B was turned on when that happened. |
| 506 |
;; The only way I can see how that's possible is that the |
| 507 |
;; slot in page was somehow changed. Any other explanations??? |
| 508 |
track_retry call select_fdc |
| 509 |
|
| 510 |
ld iy,(driver_rd_trck) |
| 511 |
jp (iy) |
| 512 |
|
| 513 |
|
| 514 |
track_too_much call print_pc |
| 515 |
db "Read track returned too much data",13,10,0 |
| 516 |
jr read_track |
| 517 |
|
| 518 |
track_err call print_pc |
| 519 |
db "Read track error",13,10,0 |
| 520 |
jp debug_exit |
| 521 |
track_no_start call print_pc |
| 522 |
db "Read track command failed to start!",13,10,0 |
| 523 |
jp debug_exit |
| 524 |
|
| 525 |
track_end |
| 526 |
ex de,hl |
| 527 |
ld (track_stop),hl ; store for later |
| 528 |
ld de,trck_buffer |
| 529 |
or a |
| 530 |
sbc hl,de |
| 531 |
ld (track_len),hl |
| 532 |
; TODO check in range [5938, 6562]? |
| 533 |
call print_pc |
| 534 |
db " length: ",0 |
| 535 |
ld hl,(track_len) |
| 536 |
call print_dec_hl |
| 537 |
call print_pc |
| 538 |
db 13,10,0 |
| 539 |
|
| 540 |
; Quibus reported a hang after the tool printed "Read track .. length=12438" |
| 541 |
; So it seemed the FDC somehow missed the index pulse and read the track data |
| 542 |
; twice. This causes a buffer overflow later in the tool. To workaround this |
| 543 |
; hardware quirk, we check that the tracklength in in range [5800..6700]. |
| 544 |
; That's +/-5% of the nominal track length. |
| 545 |
ld hl,(track_len) |
| 546 |
ld bc,6700+1 |
| 547 |
or a |
| 548 |
sbc hl,bc |
| 549 |
jr nc,wrong_length |
| 550 |
ld hl,(track_len) |
| 551 |
ld bc,5800 |
| 552 |
or a |
| 553 |
sbc hl,bc |
| 554 |
jr nc,length_ok |
| 555 |
|
| 556 |
wrong_length call print_pc |
| 557 |
db "Unexpected track length .. retrying ...",0 |
| 558 |
jp track_retry |
| 559 |
|
| 560 |
length_ok |
| 561 |
|
| 562 |
|
| 563 |
; Calculate the ratio between the number of ticks (the difference in counter |
| 564 |
; value) and the track length. A typical value for the former is around 14560, |
| 565 |
; for the latter it's around 6250. So the ratio between the two is smaller |
| 566 |
; than 1. We calculate this ration as a 0.16-bit fractional number. |
| 567 |
; Later this ratio will be used to estimate the position of the address marks |
| 568 |
; in the raw track. |
| 569 |
|
| 570 |
ld hl,(track_len) |
| 571 |
ld bc,(ticks) |
| 572 |
call frac_div |
| 573 |
ld (ratio),de |
| 574 |
|
| 575 |
|
| 576 |
|
| 577 |
; Copy the track data so that it is twice directly after each other in memory. |
| 578 |
; This is a cheap way to implement 'circular-reads': on a real disk, if you |
| 579 |
; read past the end of a track, you simply wrap around to the beginning of the |
| 580 |
; track. With the copy reads (that only wrap once!) now behave the same. |
| 581 |
; |
| 582 |
; Note that the first dozen or so bytes returned by the read track command are |
| 583 |
; totally unreliable. This is because the FDC has not yet seen any |
| 584 |
; synchronization marks, so it has no idea which bit in the stream is the first |
| 585 |
; bit of a byte. For us this is not a big problem because in the code below we |
| 586 |
; only scan for these synchronization marks. |
| 587 |
|
| 588 |
ld bc,(track_len) |
| 589 |
ld hl,trck_buffer |
| 590 |
ld d,h |
| 591 |
ld e,l |
| 592 |
add hl,bc |
| 593 |
ex de,hl |
| 594 |
ldir |
| 595 |
|
| 596 |
|
| 597 |
; Clear the DMK header. There is room for 64 IDAM entries. Unused position |
| 598 |
; should contain the value 0x0000. |
| 599 |
|
| 600 |
ld hl,dmk_header |
| 601 |
ld de,dmk_header+1 |
| 602 |
ld bc,sizeof_dmk_h-1 |
| 603 |
ld (hl),0 |
| 604 |
ldir |
| 605 |
|
| 606 |
|
| 607 |
; Later we fill search the position of address and data marks in the raw track |
| 608 |
; data. Clear that table now. Note that this table partly overlaps with the |
| 609 |
; addr_buffer (where we stored the result of the "read address" commands). |
| 610 |
; That's OK, from this point on we only need the first 64 entries from the |
| 611 |
; that table anymore. |
| 612 |
|
| 613 |
ld hl,offset_buffer |
| 614 |
ld de,offset_buffer+1 |
| 615 |
ld bc,sizeof_off_buf-1 |
| 616 |
ld (hl),0 |
| 617 |
ldir |
| 618 |
|
| 619 |
|
| 620 |
; Now, for each data adress mark (returned by the "read address" command), try |
| 621 |
; to locate it in the raw track data. For this we use the recorded counter |
| 622 |
; value for that address mark and the earlier calculated ratio. |
| 623 |
|
| 624 |
ld a,(nb_sectors) |
| 625 |
or a ; if there are no address marks on |
| 626 |
jp z,no_sectors ; this track we're done |
| 627 |
|
| 628 |
ld a,'A' |
| 629 |
call debug_log |
| 630 |
ld a,(debug) |
| 631 |
or a |
| 632 |
jr z,skip_ana_prt |
| 633 |
call print_pc |
| 634 |
db "Analyze raw track ... ",0 |
| 635 |
skip_ana_prt |
| 636 |
|
| 637 |
ld a,(nb_sectors) |
| 638 |
ld hl,offset_buffer ; store results in this table |
| 639 |
ld (ofst_buf_ptr),hl |
| 640 |
ld hl,addr_buffer |
| 641 |
|
| 642 |
addr_mark_loop ld (sector_cntr),a |
| 643 |
ld (addr_buf_ptr),hl |
| 644 |
|
| 645 |
ld a,(debug) |
| 646 |
or a |
| 647 |
jr z,skip_ana_prt2 |
| 648 |
push hl |
| 649 |
ld a,(sector_cntr) |
| 650 |
call print_dec_a |
| 651 |
call print_pc |
| 652 |
db " ",0 |
| 653 |
pop hl |
| 654 |
skip_ana_prt2 |
| 655 |
ld a,'a' |
| 656 |
call debug_log |
| 657 |
|
| 658 |
ld de,ofst_amark_tick |
| 659 |
add hl,de |
| 660 |
ld e,(hl) |
| 661 |
inc hl |
| 662 |
ld d,(hl) |
| 663 |
ld bc,(ratio) |
| 664 |
call mul_hi ; hl = (de * bc) >> 16 |
| 665 |
ld bc,trck_buffer |
| 666 |
add hl,bc |
| 667 |
ld (addr_estimate),hl |
| 668 |
|
| 669 |
|
| 670 |
; We can only use this calculated position as a (fairly good) estimate of the |
| 671 |
; position. The real position can be different for the following reasons: |
| 672 |
; - we recorded the counter at the end of the "read address" command, while |
| 673 |
; here we're looking for the start of the address mark |
| 674 |
; - the counter we've used does not 100% increase with a constant rate (e.g. |
| 675 |
; at the end of a command we have to do some extra stuff, and we don't |
| 676 |
; increase the counter during that time) |
| 677 |
; - the rotation speed (and maybe also the flux density?) is not 100% |
| 678 |
; constant |
| 679 |
; To compensate for this we only use the calculated position as the starting |
| 680 |
; point for the search. If we don't find the mark at exactly this position, we |
| 681 |
; try the adjacent few bytes (both up and down). Tests on a real machine have |
| 682 |
; shown that usually we find the mark withing 2 or 3 bytes from the calculated |
| 683 |
; position (but here we try up to 5 bytes (up and down) from the calculated |
| 684 |
; position). |
| 685 |
; TODO more tests on Quibus machine indicated that (in rare cases?) 5 bytes is |
| 686 |
; not enough. I've currently increased it up to 20 bytes. But that's most |
| 687 |
; likely too much (searching too far from the initial position has a risk of |
| 688 |
; finding a different mark in the wrong position) |
| 689 |
; |
| 690 |
; We look for the bytes 0xA1 0xA1 0xFE. The real address mark still has a 3rd |
| 691 |
; byte 0xA1 in front of this sequence. But tests on a real WD2793 have shown |
| 692 |
; that this byte is very often read wrong by the "read track" command. (Later |
| 693 |
; we will correct this so that the data in the DMK file has the correct |
| 694 |
; sequence A1 A1 A1 FE). |
| 695 |
; |
| 696 |
; The disk "Demo Kit Deluxe" has at the start of the track the sequence |
| 697 |
; "A1 A1 A1 FC" (instead of the usual sequence C2 C2 C2 FC). When doing tests |
| 698 |
; with this disk on a real machine, we found that the "read address" command |
| 699 |
; also returns the 6 bytes following the "A1 A1 A1 FC" sequence (the expected |
| 700 |
; sequence for an address mark is A1 A1 A1 FE). So it seems the WD2793 accepts |
| 701 |
; both FC and FE in the address mark sequence. |
| 702 |
|
| 703 |
ld de,ofst_tab |
| 704 |
ofst_next ld hl,(addr_estimate) ; restore initial estimate |
| 705 |
ld a,(de) |
| 706 |
inc de |
| 707 |
cp #80 |
| 708 |
jp z,ofst_err ; reached the end of the offset table |
| 709 |
ld c,a |
| 710 |
ld a,(de) |
| 711 |
inc de |
| 712 |
ld b,a ; 16-bit offset |
| 713 |
|
| 714 |
add hl,bc ; add offset |
| 715 |
ld a,(hl) |
| 716 |
cp #A1 |
| 717 |
jr nz,ofst_next |
| 718 |
inc hl |
| 719 |
ld a,(hl) |
| 720 |
cp #A1 |
| 721 |
jr nz,ofst_next |
| 722 |
inc hl |
| 723 |
ld a,(hl) |
| 724 |
cp #FE |
| 725 |
jr z,ofst_1 |
| 726 |
cp #FC ; see comments above |
| 727 |
jr nz,ofst_next |
| 728 |
ofst_1 |
| 729 |
dec hl |
| 730 |
dec hl |
| 731 |
dec hl ; points to start of A1 A1 A1 FE sequence |
| 732 |
ex de,hl |
| 733 |
ld hl,(ofst_buf_ptr) |
| 734 |
ld (hl),e |
| 735 |
inc hl |
| 736 |
ld (hl),d ; store location in offset_buffer |
| 737 |
|
| 738 |
;;push de |
| 739 |
;;call print_pc |
| 740 |
;;db " addr_mark=0x",0 |
| 741 |
;;pop hl |
| 742 |
;;call print_hex_hl |
| 743 |
|
| 744 |
; Now verify the CRC of the address mark. We use the data returned by the |
| 745 |
; "read address" command (not the data in the raw track). If there is a CRC |
| 746 |
; error we don't need to look for the data mark. |
| 747 |
; |
| 748 |
; Alternatively we could use the CRC-error-bit in the WD2793 status register |
| 749 |
; to see if there was a CRC error. Though I prefered to not do that to keep |
| 750 |
; the read-all-address-marks loop as fast as possible. |
| 751 |
; |
| 752 |
; The CRC value includes the 4 bytes of the address mark header (A1 A1 A1 FE) |
| 753 |
; and the 4 actual "C H R N" bytes stored in the address. |
| 754 |
|
| 755 |
ld hl,#B230 ; precalculated CRC for A1 A1 A1 FE |
| 756 |
ld de,(addr_buf_ptr) |
| 757 |
ld a,(de) ; C |
| 758 |
call crc_byte |
| 759 |
inc de |
| 760 |
ld a,(de) ; H |
| 761 |
call crc_byte |
| 762 |
inc de |
| 763 |
ld a,(de) ; R |
| 764 |
call crc_byte |
| 765 |
inc de |
| 766 |
ld a,(de) ; N |
| 767 |
call crc_byte |
| 768 |
inc de |
| 769 |
ld a,(de) ; CRC (high byte) |
| 770 |
cp h |
| 771 |
jr nz,addr_crc_err |
| 772 |
inc de |
| 773 |
ld a,(de) ; CRC (low byte) |
| 774 |
cp l |
| 775 |
jr nz,addr_crc_err |
| 776 |
|
| 777 |
;;call print_pc |
| 778 |
;;db " CRC-OK",0 |
| 779 |
|
| 780 |
; We found the address mark and it has a valid CRC. Now search for the data |
| 781 |
; mark. According to the WD2793 datasheet, the data mark should occur within |
| 782 |
; 43 bytes from (the end of) the address mark. |
| 783 |
; |
| 784 |
; A data mark starts with the sequence "A1 A1 A1 FB" (normal data mark) or |
| 785 |
; "A1 A1 A1 F8" (deleted data mark). But just as for the address mark, the |
| 786 |
; WD2793 "read track" command cannot reliably read the first A1 byte of this |
| 787 |
; sequence, so we ignore it while searching. |
| 788 |
|
| 789 |
ld hl,(ofst_buf_ptr) |
| 790 |
ld a,(hl) |
| 791 |
inc hl |
| 792 |
ld h,(hl) |
| 793 |
ld l,a ; hl = start of address mark |
| 794 |
ld de,10-1 |
| 795 |
add hl,de ; end of address mark |
| 796 |
|
| 797 |
ld b,43+4 ; should find data mark within 43 bytes |
| 798 |
data_mark_1 dec b |
| 799 |
jp z,data_err |
| 800 |
inc hl |
| 801 |
ld a,(hl) |
| 802 |
cp #A1 |
| 803 |
jr nz,data_mark_1 |
| 804 |
data_mark_2 dec b |
| 805 |
jp z,data_err |
| 806 |
inc hl |
| 807 |
ld a,(hl) |
| 808 |
cp #A1 |
| 809 |
jr nz,data_mark_1 |
| 810 |
data_mark_3 dec b |
| 811 |
jp z,data_err |
| 812 |
inc hl |
| 813 |
ld a,(hl) ; data mark type (deleted or normal) |
| 814 |
cp #A1 |
| 815 |
jr z,data_mark_3 |
| 816 |
cp #FB |
| 817 |
jr z,data_mark_found |
| 818 |
cp #F8 |
| 819 |
jr nz,data_mark_1 |
| 820 |
data_mark_found |
| 821 |
dec hl |
| 822 |
dec hl |
| 823 |
dec hl ; points to start of A1 A1 A1 FB sequence |
| 824 |
ld de,(track_stop) |
| 825 |
or a |
| 826 |
sbc hl,de |
| 827 |
jr c,data_mark_4 |
| 828 |
ld de,trck_buffer |
| 829 |
data_mark_4 add hl,de |
| 830 |
ex de,hl |
| 831 |
ld hl,(ofst_buf_ptr) |
| 832 |
inc hl |
| 833 |
inc hl |
| 834 |
ld (hl),e |
| 835 |
inc hl |
| 836 |
ld (hl),d ; data mark offset |
| 837 |
inc hl |
| 838 |
ld (hl),a ; data mark type |
| 839 |
|
| 840 |
;;push af |
| 841 |
;;push de |
| 842 |
;;call print_pc |
| 843 |
;;db " data_mark=0x",0 |
| 844 |
;;pop hl |
| 845 |
;;call print_hex_hl |
| 846 |
;;call print_pc |
| 847 |
;;db " type=0x",0 |
| 848 |
;;pop af |
| 849 |
;;call print_hex_a |
| 850 |
|
| 851 |
jr next_addr_mark |
| 852 |
|
| 853 |
addr_crc_err ; address mark had a CRC error (not an error for us) |
| 854 |
;;call print_pc |
| 855 |
;;db " CRC-ERR",0 |
| 856 |
jr next_addr_mark |
| 857 |
|
| 858 |
data_err ; didn't find data mark in time (not an error for us) |
| 859 |
;;call print_pc |
| 860 |
;;db " data mark not found",0 |
| 861 |
jr next_addr_mark |
| 862 |
|
| 863 |
|
| 864 |
; Also locate address and data marks for the other sectors in this track |
| 865 |
|
| 866 |
next_addr_mark |
| 867 |
;;call print_pc |
| 868 |
;;db 13,10,0 |
| 869 |
|
| 870 |
ld hl,(ofst_buf_ptr) |
| 871 |
ld de,sizeof_offinfo |
| 872 |
add hl,de |
| 873 |
ld (ofst_buf_ptr),hl |
| 874 |
ld hl,(addr_buf_ptr) |
| 875 |
ld de,sizeof_amark |
| 876 |
add hl,de |
| 877 |
ld a,(sector_cntr) |
| 878 |
dec a |
| 879 |
jp nz,addr_mark_loop |
| 880 |
|
| 881 |
ld a,(debug) |
| 882 |
or a |
| 883 |
jr z,skip_ana_prt3 |
| 884 |
call print_pc |
| 885 |
db 13,10,0 |
| 886 |
skip_ana_prt3 |
| 887 |
|
| 888 |
; We've located the address and data mark for each sector in the raw track |
| 889 |
; data. Now start overwriting the sector data in the raw track data with |
| 890 |
; data from an actual "read sector" command. Do this because tests on a real |
| 891 |
; WD2793 have shown that the data returned by "read sector" is more reliable |
| 892 |
; than the same data returned by "read track". This is especially true for a |
| 893 |
; sector that wrap around the end of the track (so past the index point). |
| 894 |
|
| 895 |
ld a,'S' |
| 896 |
call debug_log |
| 897 |
call print_pc |
| 898 |
db "Read sectors ... ",0 |
| 899 |
|
| 900 |
ld hl,sector_buffer |
| 901 |
ld (sector_buf_ptr),hl |
| 902 |
|
| 903 |
; The appraoch below reads the correct sector data even if there are multiple |
| 904 |
; sectors with the same ID present in the same track. It works well, but it's |
| 905 |
; very slow (see below for details about the used approach). It can take 45 |
| 906 |
; minutes to dump a whole disk using this appraoch! |
| 907 |
; In the majority of the cases the track does not have duplicate sectors IDs, |
| 908 |
; in that case we can use a much faster approach. |
| 909 |
|
| 910 |
ld hl,unique_buffer |
| 911 |
ld de,unique_buffer+1 |
| 912 |
ld bc,256-1 |
| 913 |
ld (hl),#ff |
| 914 |
ldir ; fill unique_buffer with #ff |
| 915 |
|
| 916 |
ld a,(nb_sectors) |
| 917 |
ld bc,sizeof_amark |
| 918 |
ld hl,addr_buffer+ofst_amark_R |
| 919 |
ld d,unique_buffer/256 |
| 920 |
count_loop ld e,(hl) ; 'R'-value of address-mark |
| 921 |
ex de,hl |
| 922 |
inc (hl) |
| 923 |
jr nz,read_slow ; if we increase #ff more than once |
| 924 |
ex de,hl ; it's non-zero, in that case there's |
| 925 |
add hl,bc ; a duplicate and we must use the |
| 926 |
dec a ; slow approach |
| 927 |
jr nz,count_loop |
| 928 |
|
| 929 |
read_fast ld a,1 |
| 930 |
jr set_speed |
| 931 |
read_slow xor a |
| 932 |
set_speed ld (read_speed),a |
| 933 |
|
| 934 |
ld hl,offset_buffer |
| 935 |
ld (ofst_buf_ptr),hl |
| 936 |
ld a,(nb_sectors) |
| 937 |
ld hl,addr_buffer |
| 938 |
|
| 939 |
sector_loop ld (sector_cntr),a |
| 940 |
ld (addr_buf_ptr),hl |
| 941 |
|
| 942 |
call print_dec_a |
| 943 |
call print_pc |
| 944 |
db " ",0 |
| 945 |
|
| 946 |
; Skip sectors for which we didn't find a data mark previously. |
| 947 |
|
| 948 |
ld hl,(ofst_buf_ptr) |
| 949 |
inc hl |
| 950 |
inc hl |
| 951 |
ld a,(hl) |
| 952 |
inc hl |
| 953 |
or (hl) |
| 954 |
jp z,next_sector |
| 955 |
|
| 956 |
|
| 957 |
; Reading a specific sector on some copy protected disks is not that simple |
| 958 |
; because it can happen that a sector with the same identification header (so |
| 959 |
; same address mark) appears multiple times on the same track. It's really |
| 960 |
; important that we read the correct version. |
| 961 |
; |
| 962 |
; To solve this, we wait till the index pulse, then execute some delay loop |
| 963 |
; (delay is based on the counter value we recorded during the "read address" |
| 964 |
; phase above) and only then we execute the "read sector" command. For extra |
| 965 |
; safety we measure the time between the start of the command and the moment |
| 966 |
; we receive the first data from the command. If this difference is too big we |
| 967 |
; adjust the delay value and try again. |
| 968 |
|
| 969 |
ld a,'s' |
| 970 |
call debug_log |
| 971 |
ld hl,64 |
| 972 |
ld (adjust_ofst),hl |
| 973 |
ld (adjust_scale),hl |
| 974 |
|
| 975 |
try_read_sector xor a |
| 976 |
retry_crc ld (crc_retries),a |
| 977 |
|
| 978 |
ld hl,(addr_buf_ptr) |
| 979 |
ld b,(hl) ; 'C' value from read address command |
| 980 |
inc hl ; 'H' |
| 981 |
inc hl |
| 982 |
ld c,(hl) ; 'R' |
| 983 |
inc hl ; 'N' |
| 984 |
inc hl ; CRC1 |
| 985 |
inc hl ; CRC2 |
| 986 |
inc hl |
| 987 |
ld a,(hl) |
| 988 |
inc hl |
| 989 |
ld h,(hl) |
| 990 |
ld l,a ; hl = counter value |
| 991 |
ld de,(adjust_ofst) |
| 992 |
or a ; counter value was recorded at end of the |
| 993 |
sbc hl,de ; "read address" command, we need to wait |
| 994 |
; till the start of the address mark, so |
| 995 |
; wait a bit less |
| 996 |
|
| 997 |
ld de,(sector_buf_ptr) |
| 998 |
ld iy,(driver_rd_sect) |
| 999 |
jp (iy) |
| 1000 |
sector_end |
| 1001 |
ex de,hl |
| 1002 |
ld de,(sector_buf_ptr) |
| 1003 |
or a ; sector length, should be one of |
| 1004 |
sbc hl,de ; 128, 256, 512 or 1024 |
| 1005 |
ld (sector_size),hl |
| 1006 |
ex de,hl |
| 1007 |
ld hl,(ofst_buf_ptr) |
| 1008 |
ld bc,ofst_oi_size |
| 1009 |
add hl,bc |
| 1010 |
ld (hl),e |
| 1011 |
inc hl |
| 1012 |
ld (hl),d ; store sector size |
| 1013 |
inc hl |
| 1014 |
ld bc,(sector_buf_ptr) |
| 1015 |
ld (hl),c |
| 1016 |
inc hl |
| 1017 |
ld (hl),b ; store pointer to sector data |
| 1018 |
|
| 1019 |
ld b,a |
| 1020 |
and 8 ; crc error? |
| 1021 |
jr z,read_no_crc_err |
| 1022 |
ld a,(crc_retries) ; Only when we have 5 crc errors, we |
| 1023 |
inc a ; believe it's an intentional crc error |
| 1024 |
cp 5 ; on the disk (and not some random read |
| 1025 |
jp c,retry_crc ; error on an (old) disk). |
| 1026 |
read_no_crc_err |
| 1027 |
ld a,(read_speed) |
| 1028 |
or a |
| 1029 |
jr nz,sector_ok |
| 1030 |
ld a,ixh |
| 1031 |
or a |
| 1032 |
jr nz,sector_retry |
| 1033 |
ld a,ixl |
| 1034 |
cp 150 |
| 1035 |
jr c,sector_ok |
| 1036 |
|
| 1037 |
sector_retry |
| 1038 |
ld a,'t' |
| 1039 |
call debug_log |
| 1040 |
ld a,(debug) |
| 1041 |
or a |
| 1042 |
jr z,debug_1 |
| 1043 |
push ix |
| 1044 |
call print_pc |
| 1045 |
db 13,10,"|",0 |
| 1046 |
pop hl |
| 1047 |
push hl |
| 1048 |
call print_hex_hl |
| 1049 |
call print_pc |
| 1050 |
db " ",0 |
| 1051 |
ld hl,(adjust_ofst) |
| 1052 |
call print_hex_hl |
| 1053 |
call print_pc |
| 1054 |
db " ",0 |
| 1055 |
ld hl,(adjust_scale) |
| 1056 |
call print_hex_hl |
| 1057 |
call print_pc |
| 1058 |
db "|",0 |
| 1059 |
pop ix |
| 1060 |
debug_1 |
| 1061 |
ld hl,(adjust_scale) |
| 1062 |
ld d,h |
| 1063 |
ld e,l |
| 1064 |
srl d |
| 1065 |
rr e |
| 1066 |
srl d |
| 1067 |
rr e |
| 1068 |
srl d |
| 1069 |
rr e |
| 1070 |
or a |
| 1071 |
sbc hl,de |
| 1072 |
ld (adjust_scale),hl ; scale = scale - scale/8 |
| 1073 |
ex de,hl |
| 1074 |
ld hl,(adjust_ofst) |
| 1075 |
ld a,ixh |
| 1076 |
cp 5 |
| 1077 |
jr c,sector_sub |
| 1078 |
add hl,de |
| 1079 |
jr sector_2 |
| 1080 |
sector_sub or a |
| 1081 |
sbc hl,de |
| 1082 |
sector_2: ld (adjust_ofst),hl |
| 1083 |
jp try_read_sector |
| 1084 |
|
| 1085 |
sector_ok ld a,'o' |
| 1086 |
call debug_log |
| 1087 |
ld hl,(ofst_buf_ptr) |
| 1088 |
ld de,ofst_oi_status |
| 1089 |
add hl,de |
| 1090 |
ld (hl),b ; b = status register |
| 1091 |
|
| 1092 |
|
| 1093 |
; We've read the sector, now copy it to the correct location in the raw track |
| 1094 |
; buffer. We can't immediately read it in the correct place because we have |
| 1095 |
; to perform a copy to a circular destination buffer (doing it inside the |
| 1096 |
; read-sector loop might be too slow). |
| 1097 |
|
| 1098 |
ld hl,(ofst_buf_ptr) |
| 1099 |
ld bc,ofst_oi_ptr+1 |
| 1100 |
add hl,bc |
| 1101 |
ld b,(hl) |
| 1102 |
dec hl |
| 1103 |
ld c,(hl) |
| 1104 |
dec hl ; bc = pointer to sector data |
| 1105 |
push bc |
| 1106 |
ld b,(hl) |
| 1107 |
dec hl |
| 1108 |
ld c,(hl) ; bc = sector size |
| 1109 |
|
| 1110 |
dec hl |
| 1111 |
dec hl |
| 1112 |
dec hl |
| 1113 |
dec hl |
| 1114 |
ld a,(hl) |
| 1115 |
inc hl |
| 1116 |
ld h,(hl) |
| 1117 |
ld l,a ; hl = pos of data mark |
| 1118 |
inc hl |
| 1119 |
inc hl |
| 1120 |
inc hl |
| 1121 |
inc hl ; position of actual sector data |
| 1122 |
ld de,(track_stop) |
| 1123 |
or a |
| 1124 |
sbc hl,de |
| 1125 |
jr c,circular_1 |
| 1126 |
ld de,trck_buffer |
| 1127 |
circular_1 add hl,de |
| 1128 |
ex de,hl |
| 1129 |
|
| 1130 |
pop hl ; hl = pointer to sector data |
| 1131 |
call circular_ldir |
| 1132 |
ld (sector_stop),de |
| 1133 |
|
| 1134 |
|
| 1135 |
; Did the "read sector" command return a CRC error? If so, we keep the CRC value |
| 1136 |
; from the raw track data. But if there was no CRC error, we calculate the |
| 1137 |
; correct CRC value and store that in the raw track data. Most of the time this |
| 1138 |
; calculated value will be the same as the value that is already present in the |
| 1139 |
; raw track data, though not in case the sector wrapped around the end of the |
| 1140 |
; track. |
| 1141 |
|
| 1142 |
ld hl,(ofst_buf_ptr) |
| 1143 |
ld bc,ofst_oi_status |
| 1144 |
add hl,bc |
| 1145 |
ld a,(hl) ; sector status |
| 1146 |
and 8 |
| 1147 |
jr nz,sector_crc_err ; skip calculating CRC |
| 1148 |
|
| 1149 |
;;push hl |
| 1150 |
;;call print_pc |
| 1151 |
;;db " CRC-OK",0 |
| 1152 |
;;pop hl |
| 1153 |
|
| 1154 |
dec hl |
| 1155 |
ld a,(hl) ; a = data mark type (is part of CRC) |
| 1156 |
inc hl |
| 1157 |
inc hl |
| 1158 |
ld c,(hl) |
| 1159 |
inc hl |
| 1160 |
ld b,(hl) ; bc = sector size |
| 1161 |
inc hl |
| 1162 |
ld e,(hl) |
| 1163 |
inc hl |
| 1164 |
ld d,(hl) ; de = pointer to sector data |
| 1165 |
|
| 1166 |
ld hl,#CDB4 ; precalculated CRC for sequence "A1 A1 A1" |
| 1167 |
push bc |
| 1168 |
call crc_byte |
| 1169 |
pop bc |
| 1170 |
sector_crc_loop ld a,(de) |
| 1171 |
inc de |
| 1172 |
push bc |
| 1173 |
call crc_byte |
| 1174 |
pop bc |
| 1175 |
dec bc |
| 1176 |
ld a,b |
| 1177 |
or c |
| 1178 |
jr nz,sector_crc_loop |
| 1179 |
|
| 1180 |
ex de,hl ; de = CRC value |
| 1181 |
ld hl,(sector_stop) |
| 1182 |
ld (hl),d ; CRC is stored big endian |
| 1183 |
inc hl |
| 1184 |
ld a,(track_stop) |
| 1185 |
cp l |
| 1186 |
jr nz,copy_crc_next |
| 1187 |
ld a,(track_stop+1) |
| 1188 |
cp h |
| 1189 |
jr nz,copy_crc_next |
| 1190 |
ld hl,trck_buffer |
| 1191 |
copy_crc_next ld (hl),e |
| 1192 |
|
| 1193 |
jr next_sector |
| 1194 |
|
| 1195 |
sector_crc_err ;;call print_pc |
| 1196 |
;;db " CRC-ERR",0 |
| 1197 |
|
| 1198 |
|
| 1199 |
; Sector data (and possibly CRC value) is stored in raw track buffer. |
| 1200 |
; Continue with the next sector. |
| 1201 |
|
| 1202 |
next_sector |
| 1203 |
ld hl,(sector_buf_ptr) |
| 1204 |
ld bc,(sector_size) |
| 1205 |
add hl,bc |
| 1206 |
ld (sector_buf_ptr),hl |
| 1207 |
ld a,h |
| 1208 |
cp debug_buffer/256 |
| 1209 |
jp nc,buffer_overflow |
| 1210 |
|
| 1211 |
;;call print_pc |
| 1212 |
;;db 13,10,0 |
| 1213 |
|
| 1214 |
ld hl,(ofst_buf_ptr) |
| 1215 |
ld de,sizeof_offinfo |
| 1216 |
add hl,de |
| 1217 |
ld (ofst_buf_ptr),hl |
| 1218 |
ld hl,(addr_buf_ptr) |
| 1219 |
ld de,sizeof_amark |
| 1220 |
add hl,de |
| 1221 |
ld a,(sector_cntr) |
| 1222 |
dec a |
| 1223 |
jp nz,sector_loop |
| 1224 |
|
| 1225 |
call print_pc |
| 1226 |
db 13,10,0 |
| 1227 |
|
| 1228 |
; At this point we've read the raw track data and overwritten it with data |
| 1229 |
; from "read sector" commands. Though we still need to make some more |
| 1230 |
; adjustments: |
| 1231 |
; - the read track command doesn't reliably read the first A1 byte in a |
| 1232 |
; address or data mark sequence. |
| 1233 |
; - I found that sometimes the "read sector" command had overwritten the |
| 1234 |
; address mark of another sector with different data (e.g. this happened |
| 1235 |
; while experimenting with the Pixess game disk which intentionally has |
| 1236 |
; overlapping sector) |
| 1237 |
; To fix both problems we now restore the address and data marks. |
| 1238 |
; |
| 1239 |
; We also record the position of the address marks in the DMK track header. |
| 1240 |
|
| 1241 |
ld a,'F' |
| 1242 |
call debug_log |
| 1243 |
ld a,(debug) |
| 1244 |
or a |
| 1245 |
jr z,skip_fix_prt |
| 1246 |
call print_pc |
| 1247 |
db "Fixup markers ...",13,10,0 |
| 1248 |
skip_fix_prt |
| 1249 |
|
| 1250 |
ld hl,offset_buffer |
| 1251 |
ld (ofst_buf_ptr),hl |
| 1252 |
ld hl,dmk_header |
| 1253 |
ld (dmk_ptr),hl |
| 1254 |
ld a,(nb_sectors) |
| 1255 |
ld hl,addr_buffer |
| 1256 |
|
| 1257 |
fixup_loop ld (sector_cntr),a |
| 1258 |
ld (addr_buf_ptr),hl |
| 1259 |
ld a,'f' |
| 1260 |
call debug_log |
| 1261 |
|
| 1262 |
ld hl,(ofst_buf_ptr) |
| 1263 |
ld e,(hl) |
| 1264 |
inc hl |
| 1265 |
ld d,(hl) ; de = pos of addr mark |
| 1266 |
inc hl |
| 1267 |
push hl |
| 1268 |
push de |
| 1269 |
|
| 1270 |
ld hl,addr_mark |
| 1271 |
ld bc,4 |
| 1272 |
call circular_ldir |
| 1273 |
ld hl,(addr_buf_ptr) |
| 1274 |
ld bc,6 |
| 1275 |
call circular_ldir |
| 1276 |
|
| 1277 |
pop hl ; pos of addr mark |
| 1278 |
ld de,trck_buffer |
| 1279 |
or a |
| 1280 |
sbc hl,de |
| 1281 |
ld de,#8083 |
| 1282 |
add hl,de |
| 1283 |
ex de,hl |
| 1284 |
ld hl,(dmk_ptr) |
| 1285 |
ld (hl),e |
| 1286 |
inc hl |
| 1287 |
ld (hl),d |
| 1288 |
inc hl |
| 1289 |
ld (dmk_ptr),hl |
| 1290 |
|
| 1291 |
pop hl |
| 1292 |
ld e,(hl) |
| 1293 |
inc hl |
| 1294 |
ld d,(hl) |
| 1295 |
ld a,e |
| 1296 |
or d |
| 1297 |
jr z,fixup_next ; no data mark |
| 1298 |
inc hl |
| 1299 |
push hl |
| 1300 |
|
| 1301 |
ld hl,addr_mark |
| 1302 |
ld bc,3 |
| 1303 |
call circular_ldir |
| 1304 |
pop hl |
| 1305 |
ld a,(hl) |
| 1306 |
ld (de),a ; copy data mark type |
| 1307 |
|
| 1308 |
fixup_next ld hl,(ofst_buf_ptr) |
| 1309 |
ld de,sizeof_offinfo |
| 1310 |
add hl,de |
| 1311 |
ld (ofst_buf_ptr),hl |
| 1312 |
ld hl,(addr_buf_ptr) |
| 1313 |
ld de,sizeof_amark |
| 1314 |
add hl,de |
| 1315 |
ld a,(sector_cntr) |
| 1316 |
dec a |
| 1317 |
jr nz,fixup_loop |
| 1318 |
|
| 1319 |
|
| 1320 |
; Done. ... Well, not quite ... |
| 1321 |
; In theory everything should be done at this point. However tests on a real |
| 1322 |
; machine have shown that for some disks we *sometimes* still get the wrong |
| 1323 |
; data at this point. This happened for disks which have overlapping sectors |
| 1324 |
; (e.g. sunrise disks). When I did a "read track" on such a disk, I found that |
| 1325 |
; the distance in bytes between the start of the sectors is sometimes N but |
| 1326 |
; sometimes N+1! Normally this doesn't matter (and this variation might be the |
| 1327 |
; reason why there are gaps between sectors). Though in case of overlapping |
| 1328 |
; sectors, if the relative start of the two sectors is shifted by a byte, then |
| 1329 |
; the CRC of the sectors will be different (in case of the sunrise protection, |
| 1330 |
; the CRC of the first sector is part of the data of the second sector). The |
| 1331 |
; only way I found to detect/correct this problem is to verify the CRCs of the |
| 1332 |
; sectors and if we find one that is not correct (while it should be) just try |
| 1333 |
; again and hope we get the correct relative distance on the next attempt. |
| 1334 |
; On a real machine I found that trying 3-4 times is enough to get the correct |
| 1335 |
; data. Here we try up to 20 times. |
| 1336 |
; |
| 1337 |
; ... And it gets even more complicated. Compjoetania disks (e.g. Pixess or |
| 1338 |
; NoiseDisk(?)) contain a track with a sector with the 'wrong' sectorsize. I |
| 1339 |
; mean in the track layout that sector completely looks like a 512 byte sector |
| 1340 |
; (so stuff like headers, gaps, CRC, ...). Only the sector size field has the |
| 1341 |
; value 255 instead of 2. The WD2793 only looks at the lowest 2 bits of this |
| 1342 |
; field, so for the WD2793 this is a 1024 byte sector. But with this larger |
| 1343 |
; size the sector actually overlaps with the next sector. And because only the |
| 1344 |
; size field was changed, the CRC of the sector is wrong (there's no correct |
| 1345 |
; CRC 1024 bytes after the start of the sector). And to make it even more |
| 1346 |
; complex: the distance between both sectors is not a multiple of 8 bits (I |
| 1347 |
; think). At least if you read the 1024-byte sector, the last part of that data |
| 1348 |
; does not show the sector headers etc of the next sector. The DMK file format |
| 1349 |
; cannot represent non-integer byte offsets. But luckily the content of that |
| 1350 |
; 1024 byte sector isn't checked by the software. That is the MSX software, but |
| 1351 |
; it was checked in earlier versions of READ-DMK in this verify step. And |
| 1352 |
; verification then failed. |
| 1353 |
; |
| 1354 |
; So what we do now is skip verification for overlapping sectors that have a |
| 1355 |
; CRC error. So for sunrise disks we do verify the (overlapping) sector, but |
| 1356 |
; for Compjoetania disks we don't. Non-overlapping sectors are always verified. |
| 1357 |
|
| 1358 |
ld a,'V' |
| 1359 |
call debug_log |
| 1360 |
call print_pc |
| 1361 |
db "Verifying ... ",0 |
| 1362 |
|
| 1363 |
ld hl,offset_buffer |
| 1364 |
ld a,(nb_sectors) |
| 1365 |
|
| 1366 |
verify_loop ld (sector_cntr),a |
| 1367 |
ld (ofst_buf_ptr),hl |
| 1368 |
|
| 1369 |
ld a,'v' |
| 1370 |
call debug_log |
| 1371 |
;;push hl |
| 1372 |
;;call print_dec_a ; TODO print_dec |
| 1373 |
;;call print_pc |
| 1374 |
;;db ": ",0 |
| 1375 |
;;pop hl |
| 1376 |
|
| 1377 |
inc hl |
| 1378 |
inc hl |
| 1379 |
ld e,(hl) |
| 1380 |
inc hl |
| 1381 |
ld d,(hl) ; de = location of data mark |
| 1382 |
ld a,e |
| 1383 |
or d |
| 1384 |
jp z,verify_next |
| 1385 |
|
| 1386 |
inc hl |
| 1387 |
inc hl |
| 1388 |
ld a,(hl) ; a = read sector status |
| 1389 |
ld (crc_status),a |
| 1390 |
inc hl |
| 1391 |
ld c,(hl) |
| 1392 |
inc hl |
| 1393 |
ld b,(hl) ; bc = sector length |
| 1394 |
inc hl |
| 1395 |
push bc |
| 1396 |
ld c,(hl) |
| 1397 |
inc hl |
| 1398 |
ld b,(hl) ; bc = sector data |
| 1399 |
inc hl |
| 1400 |
push bc |
| 1401 |
pop ix ; ix = sector data |
| 1402 |
ld c,(hl) |
| 1403 |
inc hl |
| 1404 |
ld b,(hl) |
| 1405 |
push bc |
| 1406 |
pop iy ; iy = addr mark of next sector |
| 1407 |
|
| 1408 |
verify_mark ld b,4 ; length of data mark |
| 1409 |
ld hl,#ffff ; initialize CRC |
| 1410 |
circular_crc1 ld a,(de) |
| 1411 |
inc de |
| 1412 |
push bc |
| 1413 |
call crc_byte |
| 1414 |
pop bc |
| 1415 |
ld a,(track_stop) |
| 1416 |
cp e |
| 1417 |
jr nz,circ_crc_next1 |
| 1418 |
ld a,(track_stop+1) |
| 1419 |
cp d |
| 1420 |
jr nz,circ_crc_next1 |
| 1421 |
ld de,trck_buffer |
| 1422 |
circ_crc_next1 djnz circular_crc1 |
| 1423 |
|
| 1424 |
ld a,'w' |
| 1425 |
call debug_log |
| 1426 |
pop bc ; bc = sector length |
| 1427 |
|
| 1428 |
check_overlap push hl |
| 1429 |
push de |
| 1430 |
push bc |
| 1431 |
push iy |
| 1432 |
pop hl ; hl = addr mark of next sector |
| 1433 |
or a |
| 1434 |
sbc hl,de ; hl = distance between this sector data and next sector header |
| 1435 |
jr nc,check_overlap1 |
| 1436 |
ld de,(track_len) |
| 1437 |
add hl,de ; handle wrapping |
| 1438 |
check_overlap1 inc bc |
| 1439 |
inc bc ; 2 CRC bytes |
| 1440 |
or a |
| 1441 |
sbc hl,bc ; distance smaller than sector size? |
| 1442 |
pop bc |
| 1443 |
pop de |
| 1444 |
pop hl |
| 1445 |
jr nc,verify_content ; not smaller -> no overlap |
| 1446 |
|
| 1447 |
overlap ld a,'0' |
| 1448 |
call debug_log |
| 1449 |
ld a,(crc_status) |
| 1450 |
and 8 |
| 1451 |
jr z,verify_content ; no CRC error -> verify sector content |
| 1452 |
ld a,'C' |
| 1453 |
call debug_log |
| 1454 |
jp verify_next ; overlap with CRC error -> skip verify |
| 1455 |
|
| 1456 |
verify_content |
| 1457 |
circular_crc ld a,(de) |
| 1458 |
cp (ix+0) |
| 1459 |
jr nz,verify_data |
| 1460 |
inc de |
| 1461 |
inc ix |
| 1462 |
push bc |
| 1463 |
call crc_byte |
| 1464 |
pop bc |
| 1465 |
ld a,(track_stop) |
| 1466 |
cp e |
| 1467 |
jr nz,circ_crc_next |
| 1468 |
ld a,(track_stop+1) |
| 1469 |
cp d |
| 1470 |
jr nz,circ_crc_next |
| 1471 |
ld de,trck_buffer |
| 1472 |
circ_crc_next dec bc |
| 1473 |
ld a,b |
| 1474 |
or c |
| 1475 |
jr nz,circular_crc |
| 1476 |
|
| 1477 |
ld a,'x' |
| 1478 |
call debug_log |
| 1479 |
ex de,hl |
| 1480 |
ld b,(hl) |
| 1481 |
inc hl |
| 1482 |
ld c,(hl) ; bc = on-disk CRC (stored big endian) |
| 1483 |
ex de,hl ; hl = calculated CRC |
| 1484 |
or a |
| 1485 |
sbc hl,bc |
| 1486 |
jr z,crc_match |
| 1487 |
|
| 1488 |
;;call print_pc |
| 1489 |
;;db " should have CRC error ... ", 0 |
| 1490 |
|
| 1491 |
crc_mismatch |
| 1492 |
ld a,'m' |
| 1493 |
call debug_log |
| 1494 |
ld a,(crc_status) |
| 1495 |
and 8 |
| 1496 |
jr nz,verify_next ; ok, read sector command also returned CRC err |
| 1497 |
ld a,'M' |
| 1498 |
jr verify_retry |
| 1499 |
|
| 1500 |
verify_data ld a,'D' |
| 1501 |
verify_retry call debug_log |
| 1502 |
call print_pc |
| 1503 |
db "FAILED",13,10,0 |
| 1504 |
|
| 1505 |
maybe_retry ld a,(retries) |
| 1506 |
inc a |
| 1507 |
ld (retries),a |
| 1508 |
cp 20 |
| 1509 |
jr c,do_retry |
| 1510 |
jp retry_error |
| 1511 |
|
| 1512 |
do_retry ld a,(debug) |
| 1513 |
or a |
| 1514 |
jr z,no_debug_write |
| 1515 |
call write_debug |
| 1516 |
call select_fdc |
| 1517 |
call seek |
| 1518 |
no_debug_write jp retry |
| 1519 |
|
| 1520 |
|
| 1521 |
crc_match |
| 1522 |
ld a,'n' |
| 1523 |
call debug_log |
| 1524 |
;;call print_pc |
| 1525 |
;;db " should not have CRC error ... ", 0 |
| 1526 |
ld a,(crc_status) |
| 1527 |
and 8 |
| 1528 |
ld a,'N' |
| 1529 |
jr nz,verify_retry ; CRC did match, but it shouldn't have |
| 1530 |
|
| 1531 |
verify_next ;;call print_pc |
| 1532 |
;;db "OK",13,10,0 |
| 1533 |
|
| 1534 |
ld hl,(ofst_buf_ptr) |
| 1535 |
ld de,sizeof_offinfo |
| 1536 |
add hl,de |
| 1537 |
ld a,(sector_cntr) |
| 1538 |
dec a |
| 1539 |
jp nz,verify_loop |
| 1540 |
verify_done |
| 1541 |
|
| 1542 |
|
| 1543 |
; Really done. |
| 1544 |
; Write the data to disk (the second drive). |
| 1545 |
; TODO this tool should also be usuable on machines with only one disk drive. |
| 1546 |
; So we should ask the user to swap disks. To make it more comfortable, we |
| 1547 |
; should try to minimize the number of required swaps. So we should buffer the |
| 1548 |
; data in (v)ram. |
| 1549 |
|
| 1550 |
success call enable_irq |
| 1551 |
|
| 1552 |
call print_pc |
| 1553 |
db "Success!!!",13,10,0 |
| 1554 |
|
| 1555 |
ld a,(cylinder) |
| 1556 |
ld hl,fcb+1+4 |
| 1557 |
ld b,'0'-1 |
| 1558 |
dec_loop inc b |
| 1559 |
sub 10 |
| 1560 |
jr nc,dec_loop |
| 1561 |
ld (hl),b |
| 1562 |
add a,'0'+10 |
| 1563 |
inc hl |
| 1564 |
ld (hl),a |
| 1565 |
ld a,(side) |
| 1566 |
add a,'0' |
| 1567 |
inc hl |
| 1568 |
inc hl |
| 1569 |
ld (hl),a |
| 1570 |
|
| 1571 |
retry_open ld de,fcb |
| 1572 |
ld c,#16 ; create file |
| 1573 |
call #0005 |
| 1574 |
or a |
| 1575 |
jp nz,open_error |
| 1576 |
|
| 1577 |
ld hl,1 |
| 1578 |
ld (fcb+14),hl ; set record size (1 byte) |
| 1579 |
ld hl,0 |
| 1580 |
ld (fcb+33),hl |
| 1581 |
ld (fcb+35),hl ; record number |
| 1582 |
|
| 1583 |
ld de,dmk_header |
| 1584 |
ld c,#1a ; set disk transfer address |
| 1585 |
call #0005 |
| 1586 |
|
| 1587 |
ld hl,(track_len) |
| 1588 |
ld bc,128 |
| 1589 |
add hl,bc ; hl = #bytes to write |
| 1590 |
ld de,fcb |
| 1591 |
ld c,#26 ; random block write |
| 1592 |
call #0005 |
| 1593 |
or a |
| 1594 |
jp nz,write_error |
| 1595 |
|
| 1596 |
ld de,fcb |
| 1597 |
ld c,#10 ; close file |
| 1598 |
call #0005 |
| 1599 |
or a |
| 1600 |
jp nz,close_error |
| 1601 |
|
| 1602 |
|
| 1603 |
ld a,(side) |
| 1604 |
inc a |
| 1605 |
cp 2 |
| 1606 |
jp nz,side_loop |
| 1607 |
|
| 1608 |
;; TODO use step-in |
| 1609 |
|
| 1610 |
ld a,(stop_track) |
| 1611 |
inc a |
| 1612 |
ld b,a |
| 1613 |
ld a,(cylinder) |
| 1614 |
inc a |
| 1615 |
cp b |
| 1616 |
jp nz,cylinder_loop |
| 1617 |
|
| 1618 |
|
| 1619 |
|
| 1620 |
|
| 1621 |
exit call deselect_fdc |
| 1622 |
call enable_irq |
| 1623 |
ld c,#00 |
| 1624 |
jp #0005 ; exit program |
| 1625 |
|
| 1626 |
|
| 1627 |
; We didn't find any sectors in this track. If we're already at cylinder 80 or |
| 1628 |
; higher this means we're done. Though if the user explicitly set the |
| 1629 |
; stop-cylinder, we continue until that cylinder. |
| 1630 |
; |
| 1631 |
; In case there's a 81th track on side 0, but not on side 1 we don't want to |
| 1632 |
; stop dumping because the combine-dmk tool expects to see always track info |
| 1633 |
; for both sides. |
| 1634 |
|
| 1635 |
no_sectors ld a,(cylinder) |
| 1636 |
cp 80 |
| 1637 |
jp c,verify_done ; not yet at cylinder 80 |
| 1638 |
ld a,(stop_set) |
| 1639 |
or a |
| 1640 |
jp nz,verify_done ; user explicitly set end-cylinder |
| 1641 |
ld a,(side) |
| 1642 |
or a |
| 1643 |
jp nz,verify_done ; if we're not on side 0, then continue |
| 1644 |
|
| 1645 |
call print_pc |
| 1646 |
db 13,10 |
| 1647 |
db "End of disk detected.",13,10,0 |
| 1648 |
jp exit |
| 1649 |
|
| 1650 |
|
| 1651 |
|
| 1652 |
|
| 1653 |
open_error call print_pc |
| 1654 |
db "Error opening file",0 |
| 1655 |
err_retry call print_pc |
| 1656 |
db " ... press key to retry ...",0 |
| 1657 |
ld ix,#009f |
| 1658 |
ld iy,(#fcc0) |
| 1659 |
call #001c |
| 1660 |
call print_pc |
| 1661 |
db 13,10,0 |
| 1662 |
jp retry_open |
| 1663 |
|
| 1664 |
write_error call print_pc |
| 1665 |
db "Error writing file",13,10,0 |
| 1666 |
delete_file ld de,fcb |
| 1667 |
ld c,#13 ; delete file |
| 1668 |
call #0005 ; when the disk is full we get a write error |
| 1669 |
; but it also leaves a zero-sized file behind |
| 1670 |
jr err_retry ; so here we delete it |
| 1671 |
close_error call print_pc |
| 1672 |
db "Error closing file",13,10,0 |
| 1673 |
jr delete_file |
| 1674 |
|
| 1675 |
|
| 1676 |
ofst_err call print_pc |
| 1677 |
db "Failed to find address mark in raw track data 0x",0 |
| 1678 |
ld hl,(addr_estimate) |
| 1679 |
call print_hex_hl |
| 1680 |
call print_pc |
| 1681 |
db 13,10,0 |
| 1682 |
jp maybe_retry |
| 1683 |
|
| 1684 |
sector_err call print_pc |
| 1685 |
db "Read sector command didn't find sector",0 |
| 1686 |
jp maybe_retry |
| 1687 |
|
| 1688 |
retry_error call print_pc |
| 1689 |
db "Unsuccessful after 20 retries :-(",13,10,0 |
| 1690 |
jr debug_exit |
| 1691 |
|
| 1692 |
buffer_overflow call print_pc |
| 1693 |
db "Sector buffer overflow",13,10,0 |
| 1694 |
debug_exit call write_debug |
| 1695 |
jp exit |
| 1696 |
|
| 1697 |
|
| 1698 |
|
| 1699 |
write_debug call print_pc |
| 1700 |
db "Writing debug file ...",13,10,0 |
| 1701 |
|
| 1702 |
ld de,fcb_debug |
| 1703 |
ld c,#16 ; create file |
| 1704 |
call #0005 |
| 1705 |
or a |
| 1706 |
jr nz,debug_error |
| 1707 |
|
| 1708 |
ld hl,1 |
| 1709 |
ld (fcb_debug+14),hl ; set record size (1 byte) |
| 1710 |
ld hl,0 |
| 1711 |
ld (fcb_debug+33),hl |
| 1712 |
ld (fcb_debug+35),hl ; record number |
| 1713 |
|
| 1714 |
ld de,#8000 |
| 1715 |
ld c,#1a ; set disk transfer address |
| 1716 |
call #0005 |
| 1717 |
|
| 1718 |
ld hl,#5000 ; write #8000 .. #D000 (20kB) |
| 1719 |
ld de,fcb_debug |
| 1720 |
ld c,#26 ; random block write |
| 1721 |
call #0005 |
| 1722 |
or a |
| 1723 |
jr nz,debug_error |
| 1724 |
|
| 1725 |
ld de,fcb_debug |
| 1726 |
ld c,#10 ; close file |
| 1727 |
call #0005 |
| 1728 |
or a |
| 1729 |
jr nz,debug_error |
| 1730 |
ret |
| 1731 |
|
| 1732 |
debug_error call print_pc |
| 1733 |
db "Error while writing debug file",13,10,0 |
| 1734 |
ret |
| 1735 |
|
| 1736 |
unknown_option call print_pc |
| 1737 |
db "Unknown command line option",13,10,0 |
| 1738 |
jp exit |
| 1739 |
expected_int call print_pc |
| 1740 |
db "Error parsing command line: expected integer",13,10,0 |
| 1741 |
jp exit |
| 1742 |
|
| 1743 |
|
| 1744 |
; We disable VDP IRQs because the BIOS print routine enables interrupts (EI) |
| 1745 |
; and that interferes with the low level drive settings we're doing (e.g. it |
| 1746 |
; can turn the motor off) a better solution would be to make sure we only print |
| 1747 |
; at non-critical places and/or restore all FDC state after a print. Or write |
| 1748 |
; our own printing routine. And of course there could be other IRQ sources in |
| 1749 |
; the MSX machine, so this is really only a hack (though would those other |
| 1750 |
; sources also trigger the motor timeout mechanism??) |
| 1751 |
|
| 1752 |
disable_irq di |
| 1753 |
ld a,(#f3e0) |
| 1754 |
and #df |
| 1755 |
out (#99),a |
| 1756 |
ld (#f3e0),a |
| 1757 |
ld a,1+128 |
| 1758 |
out (#99),a ; disable VDP IRQs |
| 1759 |
ret |
| 1760 |
|
| 1761 |
enable_irq di |
| 1762 |
ld a,(#f3e0) |
| 1763 |
or #20 |
| 1764 |
out (#99),a |
| 1765 |
ld (#f3e0),a |
| 1766 |
ld a,1+128 |
| 1767 |
out (#99),a |
| 1768 |
ei |
| 1769 |
ret |
| 1770 |
|
| 1771 |
|
| 1772 |
select_fdc call disable_irq |
| 1773 |
ld iy,(driver_select) |
| 1774 |
jp (iy) |
| 1775 |
|
| 1776 |
deselect_fdc ld iy,(driver_deselect) |
| 1777 |
jp (iy) |
| 1778 |
|
| 1779 |
seek ld iy,(driver_seek) |
| 1780 |
jp (iy) |
| 1781 |
|
| 1782 |
|
| 1783 |
|
| 1784 |
circular_ldir ld a,(hl) |
| 1785 |
ld (de),a |
| 1786 |
inc de |
| 1787 |
inc hl |
| 1788 |
ld a,(track_stop) |
| 1789 |
cp e |
| 1790 |
jr nz,ldir_next |
| 1791 |
ld a,(track_stop+1) |
| 1792 |
cp d |
| 1793 |
jr nz,ldir_next |
| 1794 |
ld de,trck_buffer |
| 1795 |
ldir_next dec bc |
| 1796 |
ld a,b |
| 1797 |
or c |
| 1798 |
jr nz,circular_ldir |
| 1799 |
ret |
| 1800 |
|
| 1801 |
|
| 1802 |
|
| 1803 |
delay: ld hl,50000 |
| 1804 |
delay0 ex (sp),hl |
| 1805 |
ex (sp),hl |
| 1806 |
dec hl |
| 1807 |
ld a,h |
| 1808 |
or l |
| 1809 |
jr nz,delay0 |
| 1810 |
ret |
| 1811 |
|
| 1812 |
|
| 1813 |
; Input: [DE] = ptr to start of block |
| 1814 |
; [IX] = ptr to end of block (right after end) |
| 1815 |
; [HL] = previous result (or zero), now search for a longer period |
| 1816 |
; Output [HL] = period |
| 1817 |
|
| 1818 |
get_period: inc hl |
| 1819 |
p_loop: push hl |
| 1820 |
push de |
| 1821 |
call test_period |
| 1822 |
pop de |
| 1823 |
pop hl |
| 1824 |
ret z |
| 1825 |
inc hl |
| 1826 |
jr p_loop |
| 1827 |
|
| 1828 |
; In: [de] = start |
| 1829 |
; [ix] = end |
| 1830 |
; [hl] = candidate period |
| 1831 |
; Out: Z -> period found |
| 1832 |
; NZ -> period not found |
| 1833 |
test_period: add hl,hl |
| 1834 |
add hl,hl |
| 1835 |
add hl,hl |
| 1836 |
add hl,de |
| 1837 |
t_loop: ld a,l |
| 1838 |
cp ixl |
| 1839 |
jr nz,test_1 |
| 1840 |
ld a,h |
| 1841 |
cp ixh |
| 1842 |
ret z |
| 1843 |
test_1: ld b,6 |
| 1844 |
c_loop ld a,(de) |
| 1845 |
cp (hl) |
| 1846 |
ret nz |
| 1847 |
inc hl |
| 1848 |
inc de |
| 1849 |
djnz c_loop |
| 1850 |
inc de |
| 1851 |
inc de |
| 1852 |
inc hl |
| 1853 |
inc hl |
| 1854 |
jr t_loop |
| 1855 |
|
| 1856 |
|
| 1857 |
; Fractional division. |
| 1858 |
; Requires that the divisor is strictly bigger than the dividend (BC > HL). |
| 1859 |
; In: [HL] Dividend |
| 1860 |
; [BC] Divisor |
| 1861 |
; Out: [DE] = fractional part of [HL]/[BC] |
| 1862 |
frac_div: ld a,b |
| 1863 |
cpl |
| 1864 |
ld b,a |
| 1865 |
ld a,c |
| 1866 |
cpl |
| 1867 |
ld c,a |
| 1868 |
inc bc ; bc = -divider |
| 1869 |
ld de,1 ; stop after 16 iterations |
| 1870 |
fdiv_loop add hl,hl ; hl <<= 1 |
| 1871 |
add hl,bc ; hl -= divider |
| 1872 |
jr c,fdiv1 ; hl.prev >= divider |
| 1873 |
sbc hl,bc ; restore hl (carry flag remains clear) |
| 1874 |
fdiv1 rl e |
| 1875 |
rl d ; adc de,de |
| 1876 |
jr nc,fdiv_loop |
| 1877 |
ret |
| 1878 |
|
| 1879 |
|
| 1880 |
; [HL] = mul-high([DE], [BC]) |
| 1881 |
mul_hi: ld hl,0 |
| 1882 |
ld a,16 |
| 1883 |
mul_loop srl d |
| 1884 |
rr e |
| 1885 |
jr nc,mul_skip |
| 1886 |
add hl,bc |
| 1887 |
mul_skip rr h |
| 1888 |
rr l |
| 1889 |
dec a |
| 1890 |
jr nz,mul_loop |
| 1891 |
ret |
| 1892 |
|
| 1893 |
|
| 1894 |
|
| 1895 |
; In: [HL] = current CRC value |
| 1896 |
; [A] = input byte |
| 1897 |
; Out [HL] = updated CRC Value |
| 1898 |
crc_byte: ld c,a |
| 1899 |
ld b,8 |
| 1900 |
crc_l: add hl,hl |
| 1901 |
jr c,crc_1 |
| 1902 |
crc_0: rlc c |
| 1903 |
jr c,crc_2 |
| 1904 |
jr crc_3 |
| 1905 |
crc_1: rlc c |
| 1906 |
jr c,crc_3 |
| 1907 |
crc_2 ld a,h |
| 1908 |
xor #10 |
| 1909 |
ld h,a |
| 1910 |
ld a,l |
| 1911 |
xor #21 |
| 1912 |
ld l,a |
| 1913 |
crc_3: djnz crc_l |
| 1914 |
ret |
| 1915 |
|
| 1916 |
|
| 1917 |
|
| 1918 |
|
| 1919 |
parse_dec ld b,0 |
| 1920 |
ld a,(hl) |
| 1921 |
parse_dec_loop inc hl |
| 1922 |
sub '0' |
| 1923 |
jp c,expected_int |
| 1924 |
cp '9'+1 |
| 1925 |
jp nc,expected_int |
| 1926 |
ld c,a |
| 1927 |
ld a,b |
| 1928 |
add a,a |
| 1929 |
add a,a |
| 1930 |
add a,a |
| 1931 |
add a,b |
| 1932 |
add a,b ; b*10 |
| 1933 |
add a,c |
| 1934 |
ld b,a |
| 1935 |
ld a,(hl) |
| 1936 |
or a |
| 1937 |
jr z,parse_dec_end |
| 1938 |
cp 13 |
| 1939 |
jr z,parse_dec_end |
| 1940 |
cp ' ' |
| 1941 |
jr z,parse_dec_end |
| 1942 |
cp 9 |
| 1943 |
jr nz,parse_dec_loop |
| 1944 |
parse_dec_end ld a,b |
| 1945 |
ret |
| 1946 |
|
| 1947 |
|
| 1948 |
|
| 1949 |
print_pc: pop hl |
| 1950 |
call print_str |
| 1951 |
jp (hl) |
| 1952 |
|
| 1953 |
print_str: ld a,(hl) |
| 1954 |
or a |
| 1955 |
ret z |
| 1956 |
ld ix,#00A2 |
| 1957 |
ld iy,(#fcc0) |
| 1958 |
call #001c |
| 1959 |
inc hl |
| 1960 |
jr print_str |
| 1961 |
|
| 1962 |
|
| 1963 |
print_hex_hl: ld a,h |
| 1964 |
call print_hex_a |
| 1965 |
ld a,l |
| 1966 |
print_hex_a: ld b,a |
| 1967 |
rrca |
| 1968 |
rrca |
| 1969 |
rrca |
| 1970 |
rrca |
| 1971 |
call print_hdig |
| 1972 |
ld a,b |
| 1973 |
print_hdig: and #0f |
| 1974 |
cp 10 |
| 1975 |
jr c,prt_1 |
| 1976 |
add a,'A'-'0'-10 |
| 1977 |
prt_1 add a,'0' |
| 1978 |
ld ix,#00A2 |
| 1979 |
ld iy,(#fcc0) |
| 1980 |
jp #001c |
| 1981 |
|
| 1982 |
|
| 1983 |
print_dec_hl ld e,0 ; number of non-zero digits |
| 1984 |
ld a,h |
| 1985 |
or l |
| 1986 |
jr z,print_dec_hl_3 ; hl==0 -> print at least one 0-digit |
| 1987 |
ld bc,-10000 |
| 1988 |
call print_dec_hl_1 |
| 1989 |
ld bc,-1000 |
| 1990 |
call print_dec_hl_1 |
| 1991 |
ld bc,-100 |
| 1992 |
call print_dec_hl_1 |
| 1993 |
ld c,-10 |
| 1994 |
call print_dec_hl_1 |
| 1995 |
ld c,-1 |
| 1996 |
print_dec_hl_1 ld a,-1 |
| 1997 |
print_dec_hl_2 inc a |
| 1998 |
add hl,bc |
| 1999 |
jr c,print_dec_hl_2 |
| 2000 |
sbc hl,bc |
| 2001 |
inc e |
| 2002 |
or a |
| 2003 |
jr nz,print_dec_hl_3 |
| 2004 |
dec e |
| 2005 |
ret z ; skip leading zeros |
| 2006 |
print_dec_hl_3 add a,'0' |
| 2007 |
ld ix,#00A2 |
| 2008 |
ld iy,(#fcc0) |
| 2009 |
jp #001c |
| 2010 |
|
| 2011 |
print_dec_a ld e,0 |
| 2012 |
or a |
| 2013 |
jr z,print_dec_a_3 |
| 2014 |
ld b,100 |
| 2015 |
call print_dec_a_1 |
| 2016 |
ld b,10 |
| 2017 |
call print_dec_a_1 |
| 2018 |
ld b,1 |
| 2019 |
print_dec_a_1 ld c,-1 |
| 2020 |
print_dec_a_2 inc c |
| 2021 |
sub b |
| 2022 |
jr nc,print_dec_a_2 |
| 2023 |
add a,b |
| 2024 |
ld b,a |
| 2025 |
inc e |
| 2026 |
ld a,c |
| 2027 |
or a |
| 2028 |
jr nz,print_dec_a_3 |
| 2029 |
dec e |
| 2030 |
jr z,print_dec_a_4 |
| 2031 |
print_dec_a_3 add a,'0' |
| 2032 |
ld ix,#00A2 |
| 2033 |
ld iy,(#fcc0) |
| 2034 |
call #001c |
| 2035 |
print_dec_a_4 ld a,b |
| 2036 |
ret |
| 2037 |
|
| 2038 |
|
| 2039 |
debug_log push hl |
| 2040 |
ld hl,(debug_ptr) |
| 2041 |
ld (hl),a |
| 2042 |
inc l |
| 2043 |
ld (debug_ptr),hl |
| 2044 |
pop hl |
| 2045 |
ret |
| 2046 |
|
| 2047 |
|
| 2048 |
|
| 2049 |
;--- |
| 2050 |
; Machine specific routines |
| 2051 |
; All these routine are still very much based on a WD2793 FDC. They only |
| 2052 |
; differ in how the WD2793 is connected to the MSX. Each 'driver' needs |
| 2053 |
; to implement 6 routines: |
| 2054 |
|
| 2055 |
; 1) select |
| 2056 |
; input: |
| 2057 |
; 'side' global variable |
| 2058 |
; output: - |
| 2059 |
; description: |
| 2060 |
; Needs to select the disk rom in page 1 (for memory mapped FDCs). |
| 2061 |
; Needs to select correct side, select drive A, turn motor on. |
| 2062 |
|
| 2063 |
; 2) deselct |
| 2064 |
; input: - |
| 2065 |
; output: - |
| 2066 |
; description: |
| 2067 |
; Called right before program exit. Should e.g. turn drive motor off. |
| 2068 |
|
| 2069 |
; 3) seek |
| 2070 |
; input: 'cylinder' |
| 2071 |
; output: - |
| 2072 |
; description: |
| 2073 |
; Should seek to the correct cylinder. E.g. by first seeking to track 0 |
| 2074 |
; and then seek to the requested cylinder. It's not allowed to use the data |
| 2075 |
; in the track for this seek (e.g. verify the destination track). |
| 2076 |
; TODO in the future we may add a step-in command as well. |
| 2077 |
|
| 2078 |
; 4) rd_addr |
| 2079 |
; input: - |
| 2080 |
; output: |
| 2081 |
; 'addr_buffer' is filled in |
| 2082 |
; [DE] points to end of addr_buffer |
| 2083 |
; description: |
| 2084 |
; Executes 'read address' commands in a loop and put the result in a buffer. |
| 2085 |
; During this loop it keep a counter running and on each successful read |
| 2086 |
; address command, the value of this counter is also stored in the buffer. |
| 2087 |
; return: |
| 2088 |
; on success this routine jumps to 'addr_done' |
| 2089 |
; on error it jumps to 'addr_error' |
| 2090 |
|
| 2091 |
; 5) rd_track |
| 2092 |
; input: - |
| 2093 |
; output: |
| 2094 |
; 'trck_buffer' is filled in |
| 2095 |
; [DE] points to the end of trck_buffer |
| 2096 |
; description: |
| 2097 |
; return: |
| 2098 |
; on success this routine jumps to 'track_end' |
| 2099 |
; on error it jumps to 'track_err' or 'track_too_much' |
| 2100 |
|
| 2101 |
; 6) rd_sector |
| 2102 |
; input: |
| 2103 |
; [B] = track number (number found in address mark, not physical track number) |
| 2104 |
; [C] = Sector number (found in address mark) |
| 2105 |
; [DE] = pointer to output buffer |
| 2106 |
; [HL] = delay value |
| 2107 |
; 'read_speed' global variable |
| 2108 |
; output: |
| 2109 |
; buffer is filled in |
| 2110 |
; [A] = WD2793 status register after command has ended (e.g. contains CRC status) |
| 2111 |
; [DE] = points to end of buffer |
| 2112 |
; [IX] = time between end-of-delay and first-byte-received |
| 2113 |
; description: |
| 2114 |
; Reads the sector with given number in the given buffer. This routine should |
| 2115 |
; wait for the index pulse and then delay for the given amount of time before |
| 2116 |
; actually starting the read sector command |
| 2117 |
; return: |
| 2118 |
; on success this routine jumps to sector_end |
| 2119 |
; on error it jumps to sector_err |
| 2120 |
|
| 2121 |
driver_routines |
| 2122 |
driver_select dw 0 |
| 2123 |
driver_deselect dw 0 |
| 2124 |
driver_seek dw 0 |
| 2125 |
driver_rd_addr dw 0 |
| 2126 |
driver_rd_trck dw 0 |
| 2127 |
driver_rd_sect dw 0 |
| 2128 |
ticks_min dw 0 |
| 2129 |
ticks_max dw 0 |
| 2130 |
driver_size equ $ - driver_routines |
| 2131 |
|
| 2132 |
driver dw phil_driver |
| 2133 |
|
| 2134 |
;--- |
| 2135 |
; Philips |
| 2136 |
|
| 2137 |
phil_status equ #7ff8 |
| 2138 |
phil_command equ #7ff8 |
| 2139 |
phil_track equ #7ff9 |
| 2140 |
phil_sector equ #7ffa |
| 2141 |
phil_data equ #7ffb |
| 2142 |
phil_control1 equ #7ffc |
| 2143 |
phil_control2 equ #7ffd |
| 2144 |
phil_stat2 equ #7fff |
| 2145 |
|
| 2146 |
phil_driver dw phil_select |
| 2147 |
dw phil_deselect |
| 2148 |
dw phil_seek |
| 2149 |
dw phil_rd_addr |
| 2150 |
dw phil_rd_trck |
| 2151 |
dw phil_rd_sector |
| 2152 |
dw 13834 |
| 2153 |
dw 15290 |
| 2154 |
|
| 2155 |
|
| 2156 |
; 1) select |
| 2157 |
phil_select ld a,(#f348) |
| 2158 |
ld h,#40 |
| 2159 |
call #0024 ; select FDC slot in page 1 |
| 2160 |
ld a,(side) |
| 2161 |
ld (phil_control1),a |
| 2162 |
ld a,#c0 ; motor on, led on, drive A |
| 2163 |
ld (phil_control2),a |
| 2164 |
ret |
| 2165 |
|
| 2166 |
|
| 2167 |
; 2) deselct |
| 2168 |
phil_deselect ld a,3 |
| 2169 |
ld (phil_control2),a |
| 2170 |
ret |
| 2171 |
|
| 2172 |
|
| 2173 |
; 3) seek |
| 2174 |
phil_seek |
| 2175 |
wait_busy_3 ld a,(phil_status) |
| 2176 |
and 1 |
| 2177 |
jr nz,wait_busy_3 |
| 2178 |
|
| 2179 |
ld a,#0b ; restore, load head |
| 2180 |
ld (phil_command),a |
| 2181 |
call delay |
| 2182 |
|
| 2183 |
wait_busy_4 ld a,(phil_status) |
| 2184 |
and 1 |
| 2185 |
jr nz,wait_busy_4 |
| 2186 |
|
| 2187 |
ld a,(cylinder) |
| 2188 |
ld (phil_data),a ; track |
| 2189 |
ld a,#18 ; seek |
| 2190 |
ld (phil_command),a |
| 2191 |
ret |
| 2192 |
|
| 2193 |
|
| 2194 |
; 4) rd_addr |
| 2195 |
phil_rd_addr: |
| 2196 |
ld de,addr_buffer |
| 2197 |
ld ix,0 ; counter |
| 2198 |
ld hl,phil_stat2 ; irq/dtrq |
| 2199 |
ld bc,phil_data |
| 2200 |
|
| 2201 |
wait_busy_1 ld a,(phil_status) |
| 2202 |
and 1 |
| 2203 |
jr nz,wait_busy_1 |
| 2204 |
|
| 2205 |
ld a,#d0 ; Forced interrupt command |
| 2206 |
ld (phil_command),a ; otherwise we don't see the index |
| 2207 |
ex (sp),hl |
| 2208 |
ex (sp),hl ; needed? |
| 2209 |
|
| 2210 |
wait_index_a1 ld a,(phil_status) |
| 2211 |
and 2 ; wait till index pulse = 0 |
| 2212 |
jr nz,wait_index_a1 |
| 2213 |
wait_index_b1 ld a,(phil_status) |
| 2214 |
and 2 ; wait till index pulse = 1 |
| 2215 |
jr z,wait_index_b1 |
| 2216 |
|
| 2217 |
addr_loop ld a,#c0 |
| 2218 |
ld (phil_command),a ; read addr |
| 2219 |
|
| 2220 |
; Note: the timinig of this loop is important! Don't change |
| 2221 |
; the instructions (e.g. JP->JR) without also changing the |
| 2222 |
; other timing critical routines below. |
| 2223 |
addr_wait inc ix ; 12 cycles <-- this subset |
| 2224 |
ld a,(hl) ; 8 <-- of the loop |
| 2225 |
add a,a ; 5 <-- takes |
| 2226 |
jp p,addr_end ; 11 <-- 47 |
| 2227 |
jp c,addr_wait ; 11 <-- cycles |
| 2228 |
ld a,(bc) ; 8 |
| 2229 |
ld (de),a ; 8 |
| 2230 |
inc de ; 7 |
| 2231 |
jp addr_wait ; 11 |
| 2232 |
addr_end |
| 2233 |
|
| 2234 |
ld a,(phil_status) |
| 2235 |
and 16 |
| 2236 |
jr nz,addr_error_ ; prefer to keep this a short jump |
| 2237 |
ld a,ixl |
| 2238 |
ld (de),a |
| 2239 |
inc de |
| 2240 |
ld a,ixh |
| 2241 |
ld (de),a ; store counter |
| 2242 |
inc de |
| 2243 |
inc ix |
| 2244 |
inc ix |
| 2245 |
cp #c0 |
| 2246 |
jp c,addr_loop |
| 2247 |
jp addr_done |
| 2248 |
|
| 2249 |
addr_error_ jp addr_error |
| 2250 |
|
| 2251 |
|
| 2252 |
; 5) rd_track |
| 2253 |
phil_rd_trck ld de,trck_buffer |
| 2254 |
ld hl,phil_stat2 ; irq/dtrq |
| 2255 |
ld bc,phil_data |
| 2256 |
ld ix,0 |
| 2257 |
ld a,#e0 ; read track |
| 2258 |
ld (phil_command),a |
| 2259 |
|
| 2260 |
track_wait2 ld a,(hl) |
| 2261 |
add a,a |
| 2262 |
jp p,track_err |
| 2263 |
jp nc,track_first |
| 2264 |
inc ix |
| 2265 |
ld a,ixh |
| 2266 |
inc a |
| 2267 |
jp nz,track_wait2 |
| 2268 |
jp track_no_start |
| 2269 |
|
| 2270 |
track_wait ld a,(hl) |
| 2271 |
add a,a |
| 2272 |
jp p,track_end |
| 2273 |
jp c,track_wait |
| 2274 |
track_first ld a,(bc) |
| 2275 |
ld (de),a |
| 2276 |
inc de |
| 2277 |
ld a,d |
| 2278 |
cp #be |
| 2279 |
jp c,track_wait |
| 2280 |
jp track_too_much |
| 2281 |
|
| 2282 |
|
| 2283 |
; 6) rd_sector |
| 2284 |
phil_rd_sector |
| 2285 |
ld a,#d0 ; Forced interrupt command |
| 2286 |
ld (phil_command),a ; otherwise we don't see the index |
| 2287 |
; pulse status bits |
| 2288 |
ld a,b |
| 2289 |
ld (phil_track),a |
| 2290 |
ld a,c |
| 2291 |
ld (phil_sector),a |
| 2292 |
|
| 2293 |
ld bc,phil_data |
| 2294 |
ld ix,0 |
| 2295 |
ld a,(read_speed) |
| 2296 |
or a |
| 2297 |
jr nz,fast_read_1 |
| 2298 |
|
| 2299 |
wait_index_a2 ld a,(phil_status) |
| 2300 |
and 2 ; wait till index pulse = 0 |
| 2301 |
jr nz,wait_index_a2 |
| 2302 |
wait_index_b2 ld a,(phil_status) |
| 2303 |
and 2 ; wait till index pulse = 1 |
| 2304 |
jr z,wait_index_b2 |
| 2305 |
|
| 2306 |
; This loop is tuned for an exact number of Z80 cycles! |
| 2307 |
delay_loop dec hl ; 7 cycles |
| 2308 |
ld a,(0) ; dummy read 14 cycles |
| 2309 |
nop ; 5 cycles |
| 2310 |
ld a,h ; 5 |
| 2311 |
or l ; 5 |
| 2312 |
jp nz,delay_loop ; 11 together 47 cycles |
| 2313 |
|
| 2314 |
fast_read_1 ld hl,phil_stat2 ; irq/dtrq |
| 2315 |
ld a,#80 ; read sector |
| 2316 |
ld (phil_command),a |
| 2317 |
|
| 2318 |
sector_wait1 inc ix ; count till first byte is received |
| 2319 |
ld a,(hl) |
| 2320 |
add a,a |
| 2321 |
jp p,sector_err ; command stopped before we got 1st byte |
| 2322 |
jp c,sector_wait1 |
| 2323 |
ld a,(bc) |
| 2324 |
ld (de),a |
| 2325 |
inc de |
| 2326 |
sector_wait2 ld a,(hl) |
| 2327 |
add a,a |
| 2328 |
jp p,sector_end_ |
| 2329 |
jp c,sector_wait2 |
| 2330 |
ld a,(bc) |
| 2331 |
ld (de),a |
| 2332 |
inc de |
| 2333 |
jp sector_wait2 |
| 2334 |
|
| 2335 |
sector_end_ ld a,(phil_status) |
| 2336 |
jp sector_end |
| 2337 |
|
| 2338 |
|
| 2339 |
;--- |
| 2340 |
; National |
| 2341 |
|
| 2342 |
natl_status equ #7fb8 |
| 2343 |
natl_command equ #7fb8 |
| 2344 |
natl_track equ #7fb9 |
| 2345 |
natl_sector equ #7fba |
| 2346 |
natl_data equ #7fbb |
| 2347 |
natl_control equ #7fbc |
| 2348 |
natl_stat2 equ #7fbc |
| 2349 |
|
| 2350 |
natl_driver dw natl_select |
| 2351 |
dw natl_deselect |
| 2352 |
dw natl_seek |
| 2353 |
dw natl_rd_addr |
| 2354 |
dw natl_rd_trck |
| 2355 |
dw natl_rd_sector |
| 2356 |
dw 13834 |
| 2357 |
dw 15290 |
| 2358 |
|
| 2359 |
|
| 2360 |
; 1) select |
| 2361 |
natl_select ld a,(#f348) |
| 2362 |
ld h,#40 |
| 2363 |
call #0024 ; select FDC slot in page 1 |
| 2364 |
ld a,(side) |
| 2365 |
rlca |
| 2366 |
rlca ; bit 2 = side |
| 2367 |
or #09 ; motor on, drive A |
| 2368 |
ld (natl_control),a |
| 2369 |
ret |
| 2370 |
|
| 2371 |
|
| 2372 |
; 2) deselct |
| 2373 |
natl_deselect xor a |
| 2374 |
ld (natl_control),a |
| 2375 |
ret |
| 2376 |
|
| 2377 |
|
| 2378 |
; 3) seek |
| 2379 |
natl_seek |
| 2380 |
natl_wait_3 ld a,(natl_status) |
| 2381 |
and 1 |
| 2382 |
jr nz,natl_wait_3 |
| 2383 |
|
| 2384 |
ld a,#0b ; restore, load head |
| 2385 |
ld (natl_command),a |
| 2386 |
call delay |
| 2387 |
|
| 2388 |
natl_wait_4 ld a,(natl_status) |
| 2389 |
and 1 |
| 2390 |
jr nz,natl_wait_4 |
| 2391 |
|
| 2392 |
ld a,(cylinder) |
| 2393 |
ld (natl_data),a ; track |
| 2394 |
ld a,#18 ; seek |
| 2395 |
ld (natl_command),a |
| 2396 |
ret |
| 2397 |
|
| 2398 |
|
| 2399 |
; 4) rd_addr |
| 2400 |
natl_rd_addr: |
| 2401 |
ld de,addr_buffer |
| 2402 |
ld ix,0 ; counter |
| 2403 |
ld hl,natl_stat2 ; irq/dtrq |
| 2404 |
ld bc,natl_data |
| 2405 |
|
| 2406 |
natl_busy_1 ld a,(natl_status) |
| 2407 |
and 1 |
| 2408 |
jr nz,natl_busy_1 |
| 2409 |
|
| 2410 |
ld a,#d0 ; Forced interrupt command |
| 2411 |
ld (natl_command),a ; otherwise we don't see the index |
| 2412 |
ex (sp),hl |
| 2413 |
ex (sp),hl ; needed? |
| 2414 |
|
| 2415 |
natl_index_a1 ld a,(natl_status) |
| 2416 |
and 2 ; wait till index pulse = 0 |
| 2417 |
jr nz,natl_index_a1 |
| 2418 |
natl_index_b1 ld a,(natl_status) |
| 2419 |
and 2 ; wait till index pulse = 1 |
| 2420 |
jr z,natl_index_b1 |
| 2421 |
|
| 2422 |
natl_addr_loop ld a,#c0 |
| 2423 |
ld (natl_command),a ; read addr |
| 2424 |
|
| 2425 |
; Note: the timinig of this loop is important! Don't change |
| 2426 |
; the instructions (e.g. JP->JR) without also changing the |
| 2427 |
; other timing critical routines below. |
| 2428 |
natl_addr_wait inc ix ; 12 cycles <-- this subset |
| 2429 |
ld a,(hl) ; 8 <-- of the loop |
| 2430 |
add a,a ; 5 <-- takes |
| 2431 |
jp c,natl_addr_end ; 11 <-- 47 |
| 2432 |
jp m,natl_addr_wait; 11 <-- cycles |
| 2433 |
ld a,(bc) ; 8 |
| 2434 |
ld (de),a ; 8 |
| 2435 |
inc de ; 7 |
| 2436 |
jp natl_addr_wait ; 11 |
| 2437 |
natl_addr_end |
| 2438 |
|
| 2439 |
ld a,(natl_status) |
| 2440 |
and 16 |
| 2441 |
jr nz,natl_addr_err ; prefer to keep this a short jump |
| 2442 |
ld a,ixl |
| 2443 |
ld (de),a |
| 2444 |
inc de |
| 2445 |
ld a,ixh |
| 2446 |
ld (de),a ; store counter |
| 2447 |
inc de |
| 2448 |
inc ix |
| 2449 |
inc ix |
| 2450 |
cp #c0 |
| 2451 |
jp c,natl_addr_loop |
| 2452 |
jp addr_done |
| 2453 |
|
| 2454 |
natl_addr_err jp addr_error |
| 2455 |
|
| 2456 |
|
| 2457 |
; 5) rd_track |
| 2458 |
natl_rd_trck ld de,trck_buffer |
| 2459 |
ld hl,natl_stat2 ; irq/dtrq |
| 2460 |
ld bc,natl_data |
| 2461 |
ld ix,0 |
| 2462 |
ld a,#e0 ; read track |
| 2463 |
ld (natl_command),a |
| 2464 |
|
| 2465 |
natl_trk_wt2 ld a,(hl) |
| 2466 |
add a,a |
| 2467 |
jp c,track_err |
| 2468 |
jp p,natl_trk_first |
| 2469 |
inc ix |
| 2470 |
ld a,ixh |
| 2471 |
inc a |
| 2472 |
jp nz,natl_trk_wt2 |
| 2473 |
jp track_no_start |
| 2474 |
|
| 2475 |
natl_trk_wait ld a,(hl) |
| 2476 |
add a,a |
| 2477 |
jp c,track_end |
| 2478 |
jp m,natl_trk_wait |
| 2479 |
natl_trk_first ld a,(bc) |
| 2480 |
ld (de),a |
| 2481 |
inc de |
| 2482 |
ld a,d |
| 2483 |
cp #be |
| 2484 |
jp c,natl_trk_wait |
| 2485 |
jp track_too_much |
| 2486 |
|
| 2487 |
|
| 2488 |
; 6) rd_sector |
| 2489 |
natl_rd_sector |
| 2490 |
ld a,#d0 ; Forced interrupt command |
| 2491 |
ld (natl_command),a ; otherwise we don't see the index |
| 2492 |
; pulse status bits |
| 2493 |
ld a,b |
| 2494 |
ld (natl_track),a |
| 2495 |
ld a,c |
| 2496 |
ld (natl_sector),a |
| 2497 |
|
| 2498 |
ld bc,natl_data |
| 2499 |
ld ix,0 |
| 2500 |
ld a,(read_speed) |
| 2501 |
or a |
| 2502 |
jr nz,natl_fast_read |
| 2503 |
|
| 2504 |
natl_index_a2 ld a,(natl_status) |
| 2505 |
and 2 ; wait till index pulse = 0 |
| 2506 |
jr nz,natl_index_a2 |
| 2507 |
natl_index_b2 ld a,(natl_status) |
| 2508 |
and 2 ; wait till index pulse = 1 |
| 2509 |
jr z,natl_index_b2 |
| 2510 |
|
| 2511 |
; This loop is tuned for an exact number of Z80 cycles! |
| 2512 |
natl_delay dec hl ; 7 cycles |
| 2513 |
ld a,(0) ; dummy read 14 cycles |
| 2514 |
nop ; 5 cycles |
| 2515 |
ld a,h ; 5 |
| 2516 |
or l ; 5 |
| 2517 |
jp nz,natl_delay ; 11 together 47 cycles |
| 2518 |
|
| 2519 |
natl_fast_read ld hl,natl_stat2 ; irq/dtrq |
| 2520 |
ld a,#80 ; read sector |
| 2521 |
ld (natl_command),a |
| 2522 |
|
| 2523 |
natl_sect_wt1 inc ix ; count till first byte is received |
| 2524 |
ld a,(hl) |
| 2525 |
add a,a |
| 2526 |
jp c,sector_err ; command stopped before we got 1st byte |
| 2527 |
jp m,natl_sect_wt1 |
| 2528 |
ld a,(bc) |
| 2529 |
ld (de),a |
| 2530 |
inc de |
| 2531 |
natl_sect_wt2 ld a,(hl) |
| 2532 |
add a,a |
| 2533 |
jp c,natl_sect_end |
| 2534 |
jp m,natl_sect_wt2 |
| 2535 |
ld a,(bc) |
| 2536 |
ld (de),a |
| 2537 |
inc de |
| 2538 |
jp natl_sect_wt2 |
| 2539 |
|
| 2540 |
natl_sect_end ld a,(natl_status) |
| 2541 |
jp sector_end |
| 2542 |
|
| 2543 |
;--- |
| 2544 |
; Microsol |
| 2545 |
|
| 2546 |
mics_status equ #d0 |
| 2547 |
mics_command equ #d0 |
| 2548 |
mics_track equ #d1 |
| 2549 |
mics_sector equ #d2 |
| 2550 |
mics_data equ #d3 |
| 2551 |
mics_control equ #d4 |
| 2552 |
mics_stat2 equ #d4 |
| 2553 |
|
| 2554 |
mics_driver dw mics_select |
| 2555 |
dw mics_deselect |
| 2556 |
dw mics_seek |
| 2557 |
dw mics_rd_addr |
| 2558 |
dw mics_rd_trck |
| 2559 |
dw mics_rd_sector |
| 2560 |
dw 14135 |
| 2561 |
dw 15622 |
| 2562 |
|
| 2563 |
|
| 2564 |
; 1) select |
| 2565 |
mics_select ld a,(side) |
| 2566 |
rlca |
| 2567 |
rlca |
| 2568 |
rlca |
| 2569 |
rlca ; bit 4 = side |
| 2570 |
or #21 ; bit 5 = motor, bit 0 = drive A |
| 2571 |
out (mics_control),a |
| 2572 |
ret |
| 2573 |
|
| 2574 |
|
| 2575 |
; 2) deselct |
| 2576 |
mics_deselect xor a ; no drive selected, motor off |
| 2577 |
out (mics_control),a |
| 2578 |
ret |
| 2579 |
|
| 2580 |
|
| 2581 |
; 3) seek |
| 2582 |
mics_seek |
| 2583 |
mics_busy_3 in a,(mics_status) |
| 2584 |
and 1 |
| 2585 |
jr nz,mics_busy_3 |
| 2586 |
|
| 2587 |
ld a,#0b ; restore, load head |
| 2588 |
out (mics_command),a |
| 2589 |
call delay |
| 2590 |
|
| 2591 |
mics_busy_4 in a,(mics_status) |
| 2592 |
and 1 |
| 2593 |
jr nz,mics_busy_4 |
| 2594 |
|
| 2595 |
ld a,(cylinder) |
| 2596 |
out (mics_data),a ; track |
| 2597 |
ld a,#18 ; seek |
| 2598 |
out (mics_command),a |
| 2599 |
ret |
| 2600 |
|
| 2601 |
|
| 2602 |
; 4) rd_addr |
| 2603 |
mics_rd_addr: |
| 2604 |
ld de,addr_buffer |
| 2605 |
ld hl,0 ; counter |
| 2606 |
|
| 2607 |
mics_busy_1 in a,(mics_status) |
| 2608 |
and 1 |
| 2609 |
jr nz,mics_busy_1 |
| 2610 |
|
| 2611 |
ld a,#d0 ; Forced interrupt command |
| 2612 |
out (mics_command),a ; otherwise we don't see the index |
| 2613 |
ex (sp),hl |
| 2614 |
ex (sp),hl ; needed? |
| 2615 |
|
| 2616 |
mics_index_a1 in a,(mics_status) |
| 2617 |
and 2 ; wait till index pulse = 0 |
| 2618 |
jr nz,mics_index_a1 |
| 2619 |
mics_index_b1 in a,(mics_status) |
| 2620 |
and 2 ; wait till index pulse = 1 |
| 2621 |
jr z,mics_index_b1 |
| 2622 |
|
| 2623 |
mics_addr_loop ld a,#c0 ; read addr |
| 2624 |
out (mics_command),a |
| 2625 |
|
| 2626 |
; Note: the timinig of this loop is important! Don't change |
| 2627 |
; the instructions (e.g. JP->JR) without also changing the |
| 2628 |
; other timing critical routines below. |
| 2629 |
mics_addr_wait inc hl ; 7 cycles <-- this |
| 2630 |
in a,(mics_stat2) ; 12 <-- takes |
| 2631 |
add a,a ; 5 <-- 46 |
| 2632 |
jp c,mics_addr_end ; 11 <-- cycles |
| 2633 |
jp m,mics_addr_wait ; 11 <-- |
| 2634 |
in a,(mics_data) ; 12 |
| 2635 |
ld (de),a ; 8 |
| 2636 |
inc de ; 7 |
| 2637 |
jp mics_addr_wait ; 11 |
| 2638 |
mics_addr_end |
| 2639 |
|
| 2640 |
in a,(mics_status) |
| 2641 |
and 16 ; record not found |
| 2642 |
jr nz,mics_addr_err ; prefer to keep this a short jump |
| 2643 |
ld a,l |
| 2644 |
ld (de),a |
| 2645 |
inc de |
| 2646 |
ld a,h |
| 2647 |
ld (de),a ; store counter |
| 2648 |
inc de |
| 2649 |
inc hl |
| 2650 |
inc hl |
| 2651 |
cp #c0 |
| 2652 |
jp c,mics_addr_loop |
| 2653 |
jp addr_done |
| 2654 |
|
| 2655 |
mics_addr_err jp addr_error |
| 2656 |
|
| 2657 |
|
| 2658 |
; 5) rd_track |
| 2659 |
mics_rd_trck ld de,trck_buffer |
| 2660 |
ld hl,0 |
| 2661 |
ld a,#e0 ; read track |
| 2662 |
out (mics_command),a |
| 2663 |
|
| 2664 |
mics_trk_wait2 in a,(mics_stat2) |
| 2665 |
add a,a |
| 2666 |
jp c,track_err |
| 2667 |
jp p,mics_trk_first |
| 2668 |
inc hl |
| 2669 |
ld a,h |
| 2670 |
inc a |
| 2671 |
jp nz,mics_trk_wait2 |
| 2672 |
jp track_no_start |
| 2673 |
|
| 2674 |
mics_trk_wait in a,(mics_stat2) |
| 2675 |
add a,a |
| 2676 |
jp c,track_end |
| 2677 |
jp m,mics_trk_wait |
| 2678 |
mics_trk_first in a,(mics_data) |
| 2679 |
ld (de),a |
| 2680 |
inc de |
| 2681 |
ld a,d |
| 2682 |
cp #be |
| 2683 |
jp c,mics_trk_wait |
| 2684 |
jp track_too_much |
| 2685 |
|
| 2686 |
|
| 2687 |
; 6) rd_sector |
| 2688 |
mics_rd_sector |
| 2689 |
ld a,#d0 ; Forced interrupt command |
| 2690 |
out (mics_command),a ; otherwise we don't see the index |
| 2691 |
; pulse status bits |
| 2692 |
ld a,b |
| 2693 |
out (mics_track),a |
| 2694 |
ld a,c |
| 2695 |
out (mics_sector),a |
| 2696 |
|
| 2697 |
ld ix,0 |
| 2698 |
ld a,(read_speed) |
| 2699 |
or a |
| 2700 |
jr nz,mics_fast_1 |
| 2701 |
|
| 2702 |
mics_index_a2 in a,(mics_status) |
| 2703 |
and 2 ; wait till index pulse = 0 |
| 2704 |
jr nz,mics_index_a2 |
| 2705 |
mics_index_b2 in a,(mics_status) |
| 2706 |
and 2 ; wait till index pulse = 1 |
| 2707 |
jr z,mics_index_b2 |
| 2708 |
|
| 2709 |
; This loop is tuned for an exact number of Z80 cycles! |
| 2710 |
mics_delay dec hl ; 7 cycles |
| 2711 |
cp 0 ; 8 (dummy compare) |
| 2712 |
nop ; 5 |
| 2713 |
nop ; 5 |
| 2714 |
ld a,h ; 5 |
| 2715 |
or l ; 5 |
| 2716 |
jp nz,mics_delay ; 11 together 46 cycles |
| 2717 |
|
| 2718 |
mics_fast_1 ld a,#80 ; read sector |
| 2719 |
out (mics_command),a |
| 2720 |
|
| 2721 |
mics_sctr_wt1 inc ix ; count till first byte is received |
| 2722 |
in a,(mics_stat2) |
| 2723 |
add a,a |
| 2724 |
jp c,sector_err ; command stopped before we got 1st byte |
| 2725 |
jp m,mics_sctr_wt1 |
| 2726 |
in a,(mics_data) |
| 2727 |
ld (de),a |
| 2728 |
inc de |
| 2729 |
mics_sctr_wt2 in a,(mics_stat2) |
| 2730 |
add a,a |
| 2731 |
jp c,mics_sctr_end |
| 2732 |
jp m,mics_sctr_wt2 |
| 2733 |
in a,(mics_data) |
| 2734 |
ld (de),a |
| 2735 |
inc de |
| 2736 |
jp mics_sctr_wt2 |
| 2737 |
|
| 2738 |
mics_sctr_end in a,(mics_status) |
| 2739 |
jp sector_end |
| 2740 |
|
| 2741 |
; ----- |
| 2742 |
|
| 2743 |
|
| 2744 |
|
| 2745 |
|
| 2746 |
ofst_tab: dw -6,-7,-5,-8,-4,-9,-3,-10,-2,-11,-1,-12,0 |
| 2747 |
dw -13,1,-14,2,-15,3,-16,4,-17,5,-18,6,-19,7 |
| 2748 |
dw -20,8,-21,9,-22,10,-23,11,-24,12,-25,13,-26 |
| 2749 |
dw 14,-27,15,-28,16,-29,17,-30,18,-31,29,-32 |
| 2750 |
dw 20,-33,21,-34,22,-35,23,-36,24,-37,25,-38 |
| 2751 |
dw 26,-39,27,-40,28,-41,29,-42,30,-43,31,-44 |
| 2752 |
dw #8080 |
| 2753 |
addr_mark db #A1,#A1,#A1,#FE |
| 2754 |
|
| 2755 |
debug db 0 |
| 2756 |
start_track db 0 ; initial value matters |
| 2757 |
stop_track db 81 ; by default we try 2 extra cylinders |
| 2758 |
stop_set db 0 |
| 2759 |
|
| 2760 |
|
| 2761 |
|
| 2762 |
fcb db 2 ; drive B |
| 2763 |
db "DMK-TT-S" ; filename |
| 2764 |
db "DAT" ; extension |
| 2765 |
ds 37-12 |
| 2766 |
fcb_debug db 2 ; drive B |
| 2767 |
db "DEBUG " ; filename |
| 2768 |
db "DAT" ; extension |
| 2769 |
ds 37-12 |
| 2770 |
|
| 2771 |
|
| 2772 |
|
| 2773 |
|
| 2774 |
; struct Addr_Mark |
| 2775 |
; byte C |
| 2776 |
; byte H |
| 2777 |
; byte R |
| 2778 |
; byte N |
| 2779 |
; word CRC |
| 2780 |
; word ticks |
| 2781 |
sizeof_amark equ 8 |
| 2782 |
ofst_amark_C equ 0 |
| 2783 |
ofst_amark_H equ 1 |
| 2784 |
ofst_amark_R equ 2 |
| 2785 |
ofst_amark_N equ 3 |
| 2786 |
ofst_amark_CRC equ 4 |
| 2787 |
ofst_amark_tick equ 6 |
| 2788 |
|
| 2789 |
|
| 2790 |
; struct Offset_Info |
| 2791 |
; word address_mark_offset |
| 2792 |
; word data_mark_offset |
| 2793 |
; byte data_mark_type |
| 2794 |
; byte read_sector_status |
| 2795 |
; word sector_size |
| 2796 |
sizeof_offinfo equ 10 |
| 2797 |
ofst_oi_addr equ 0 |
| 2798 |
ofst_oi_data equ 2 |
| 2799 |
ofst_oi_type equ 4 |
| 2800 |
ofst_oi_status equ 5 |
| 2801 |
ofst_oi_size equ 6 |
| 2802 |
ofst_oi_ptr equ 8 |
| 2803 |
|
| 2804 |
|
| 2805 |
sizeof_off_buf equ 64 * sizeof_offinfo |
| 2806 |
sizeof_dmk_h equ 128 |
| 2807 |
|
| 2808 |
|
| 2809 |
cylinder equ #8000 ; db 0 0 |
| 2810 |
side equ cylinder+ 1 ; db 0 1 |
| 2811 |
retries equ side+1 ; db 0 2 |
| 2812 |
nb_sectors equ retries+1 ; dw 0 3 |
| 2813 |
track_len equ nb_sectors+2 ; dw 0 5 |
| 2814 |
track_stop equ track_len+2 ; dw 0 7 |
| 2815 |
ticks equ track_stop+2 ; dw 0 9 |
| 2816 |
ratio equ ticks+2 ; dw 0 11 |
| 2817 |
|
| 2818 |
crc_retries equ ratio+2 ; db 0 13 |
| 2819 |
adjust_ofst equ crc_retries+1 ; dw 0 14 |
| 2820 |
adjust_scale equ adjust_ofst+2 ; dw 0 16 |
| 2821 |
sector_cntr equ adjust_scale+2 ; db 0 18 |
| 2822 |
sector_stop equ sector_cntr+1 ; dw 0 19 |
| 2823 |
addr_buf_ptr equ sector_stop+2 ; dw 0 21 |
| 2824 |
ofst_buf_ptr equ addr_buf_ptr+2 ; dw 0 23 |
| 2825 |
dmk_ptr equ ofst_buf_ptr+2 ; dw 0 25 |
| 2826 |
addr_estimate equ dmk_ptr+2 ; dw 0 27 |
| 2827 |
read_speed equ addr_estimate+2 ; db 0 29 |
| 2828 |
sector_buf_ptr equ read_speed+1 ; dw 0 30 |
| 2829 |
crc_status equ sector_buf_ptr+2; db 0 32 |
| 2830 |
debug_ptr equ crc_status+1 ; dw 0 33 |
| 2831 |
sector_size equ debug_ptr+2 ; dw 0 35 |
| 2832 |
addr_buf_end equ sector_size+2 ; dw 0 37 |
| 2833 |
addr_retries equ addr_buf_end+2 ; db 0 39 |
| 2834 |
|
| 2835 |
addr_buffer equ #8100 |
| 2836 |
offset_buffer equ addr_buffer+64*sizeof_amark ; can overlap part of addr_buffer |
| 2837 |
dmk_header equ offset_buffer+sizeof_off_buf |
| 2838 |
trck_buffer equ dmk_header+sizeof_dmk_h |
| 2839 |
sector_buffer equ trck_buffer+#1A00 ; overlaps 2nd copy of track`` |
| 2840 |
unique_buffer equ #CE00 ; possibly overlaps sector buffer (that's OK) |
| 2841 |
; must start at a 256-byte boundary |
| 2842 |
debug_buffer equ #CF00 ; must be 256-bytes aligned |