Skip to content

Commit de4580d

Browse files
joevtdingusdev
authored andcommitted
swim3: Rename int_drive and fix mode change.
Rename int_drive to drive_1 or selected_drive which is selected by a new mode_change method. mode_change fixes some logic issues with the original code with regards to changes to SWIM3_GO and SWIM3_GO_STEP bits.
1 parent 54db971 commit de4580d

File tree

2 files changed

+98
-38
lines changed

2 files changed

+98
-38
lines changed

devices/floppy/swim3.cpp

Lines changed: 95 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,14 @@ Swim3Ctrl::Swim3Ctrl()
4646

4747
// Attach virtual Superdrive to the internal drive connector
4848
// TODO: make SWIM3/drive wiring user selectable
49-
this->int_drive = std::unique_ptr<MacSuperdrive::MacSuperDrive>
49+
this->drive_1 = std::unique_ptr<MacSuperdrive::MacSuperDrive>
5050
(new MacSuperdrive::MacSuperDrive("Superdrive1"));
5151
}
5252

5353
void Swim3Ctrl::reset()
5454
{
5555
this->setup_reg = 0;
56+
this->selected_drive = nullptr;
5657
this->mode_reg = 0;
5758
this->int_reg = 0;
5859
this->int_flags = 0;
@@ -94,7 +95,7 @@ int Swim3Ctrl::device_postinit()
9495
std::string fd_image_path = GET_STR_PROP("fdd_img");
9596
int fd_write_prot = GET_BIN_PROP("fdd_wr_prot");
9697
if (!fd_image_path.empty()) {
97-
this->int_drive->insert_disk(fd_image_path, fd_write_prot);
98+
this->drive_1->insert_disk(fd_image_path, fd_write_prot);
9899
}
99100

100101
return 0;
@@ -116,14 +117,17 @@ uint8_t Swim3Ctrl::read(uint8_t reg_offset)
116117
case Swim3Reg::Setup:
117118
return this->setup_reg;
118119
case Swim3Reg::Handshake_Mode1:
119-
if (this->mode_reg & SWIM3_DRIVE_1) { // internal drive?
120+
if (this->selected_drive) {
120121
status_addr = ((this->mode_reg & SWIM3_HEAD_SELECT) >> 2) | (this->phase_lines & 7);
121-
rddata_val = this->int_drive->status(status_addr) & 1;
122+
rddata_val = this->selected_drive->status(status_addr) & 1;
122123

123124
// transfer rddata_val to both bit 2 (RDDATA) and bit 3 (SENSE)
124125
// because those signals seem to be historically wired together
125126
return (rddata_val << 2) | (rddata_val << 3);
126127
}
128+
else {
129+
LOG_F(ERROR, "SWIM3: read Handshake_Mode1; no drive selected yet");
130+
}
127131
return 0xC; // report both RdData & Sense high
128132
case Swim3Reg::Interrupt_Flags:
129133
old_int_flags = this->int_flags;
@@ -164,41 +168,31 @@ void Swim3Ctrl::write(uint8_t reg_offset, uint8_t value)
164168
case Swim3Reg::Phase:
165169
this->phase_lines = value & 0xF;
166170
if (this->phase_lines & 8) { // CA3 aka LSTRB high -> sending a command to the drive
167-
if (this->mode_reg & SWIM3_DRIVE_1) { // if internal drive is selected
168-
this->int_drive->command(
169-
((this->mode_reg & SWIM3_HEAD_SELECT) >> 3) | (this->phase_lines & 3),
170-
(value >> 2) & 1
171-
);
172-
}
173-
} else if (this->phase_lines == 4 && (this->mode_reg & SWIM3_DRIVE_1)) {
171+
uint8_t command_addr = ((this->mode_reg & SWIM3_HEAD_SELECT) >> 3) | (this->phase_lines & 3);
172+
uint8_t val = (value >> 2) & 1;
173+
if (this->selected_drive) {
174+
this->selected_drive->command(command_addr, val);
175+
} else
176+
LOG_F(ERROR, "SWIM3: command %-17s addr=0x%X, value=%d; no drive selected yet",
177+
MacSuperdrive::get_command_name(command_addr).c_str(), command_addr, val);
178+
} else if (this->phase_lines == 4) {
179+
// Select_Head_0 or Select_Head_1
174180
status_addr = ((this->mode_reg & SWIM3_HEAD_SELECT) >> 2) | (this->phase_lines & 7);
175-
this->rd_line = this->int_drive->status(status_addr) & 1;
181+
if (this->selected_drive)
182+
this->rd_line = this->selected_drive->status(status_addr) & 1;
183+
else
184+
LOG_F(ERROR, "SWIM3: status %-13s 0x%X; no drive selected yet",
185+
MacSuperdrive::get_status_name(status_addr).c_str(), status_addr);
176186
}
177187
break;
178188
case Swim3Reg::Setup:
179189
this->setup_reg = value;
180190
break;
181191
case Swim3Reg::Status_Mode0:
182-
// ones in value clear the corresponding bits in the mode register
183-
if ((this->mode_reg & value) & (SWIM3_GO | SWIM3_GO_STEP)) {
184-
if (value & SWIM3_GO_STEP) {
185-
stop_stepping();
186-
} else {
187-
stop_disk_access();
188-
}
189-
}
190-
this->mode_reg &= ~value;
192+
this->mode_change(this->mode_reg & ~value);
191193
break;
192194
case Swim3Reg::Handshake_Mode1:
193-
// ones in value set the corresponding bits in the mode register
194-
if ((this->mode_reg ^ value) & (SWIM3_GO | SWIM3_GO_STEP)) {
195-
if (value & SWIM3_GO_STEP) {
196-
start_stepping();
197-
} else {
198-
start_disk_access();
199-
}
200-
}
201-
this->mode_reg |= value;
195+
this->mode_change(this->mode_reg | value);
202196
break;
203197
case Swim3Reg::Step:
204198
this->step_count = value;
@@ -235,7 +229,10 @@ void Swim3Ctrl::do_step()
235229
{
236230
if (this->mode_reg & SWIM3_GO_STEP && this->step_count) { // are we still stepping?
237231
// instruct the drive to perform single step in current direction
238-
this->int_drive->command(MacSuperdrive::CommandAddr::Do_Step, 0);
232+
if (this->selected_drive)
233+
this->selected_drive->command(MacSuperdrive::CommandAddr::Do_Step, 0);
234+
else
235+
LOG_F(ERROR, "SWIM3: do_step; no drive selected yet");
239236
if (--this->step_count == 0) {
240237
if (this->step_timer_id) {
241238
this->stop_stepping();
@@ -317,8 +314,13 @@ void Swim3Ctrl::start_disk_access()
317314

318315
this->target_sect = this->first_sec;
319316

317+
if (!this->selected_drive) {
318+
LOG_F(ERROR, "SWIM3: start_disk_access; no drive selected yet");
319+
return;
320+
}
321+
320322
this->access_timer_id = TimerManager::get_instance()->add_oneshot_timer(
321-
this->int_drive->sync_to_disk(),
323+
this->selected_drive->sync_to_disk(),
322324
[this]() {
323325
this->cur_state = SWIM3_ADDR_MARK_SEARCH;
324326
this->disk_access();
@@ -331,9 +333,14 @@ void Swim3Ctrl::disk_access()
331333
MacSuperdrive::SectorHdr hdr;
332334
uint64_t delay;
333335

336+
if (!this->selected_drive) {
337+
LOG_F(ERROR, "SWIM3: disk access; no drive selected yet");
338+
return;
339+
}
340+
334341
switch(this->cur_state) {
335342
case SWIM3_ADDR_MARK_SEARCH:
336-
hdr = this->int_drive->current_sector_header();
343+
hdr = this->selected_drive->current_sector_header();
337344
// update the corresponding SWIM3 registers
338345
this->cur_track = ((hdr.side & 1) << 7) | (hdr.track & 0x7F);
339346
this->cur_sector = 0x80 /* CRC/checksum valid */ | (hdr.sector & 0x7F);
@@ -344,16 +351,16 @@ void Swim3Ctrl::disk_access()
344351
if ((this->cur_sector & 0x7F) == this->target_sect) {
345352
// sector matches -> transfer its data
346353
this->cur_state = SWIM3_DATA_XFER;
347-
delay = this->int_drive->sector_data_delay();
354+
delay = this->selected_drive->sector_data_delay();
348355
} else {
349356
// move to next address mark
350357
this->cur_state = SWIM3_ADDR_MARK_SEARCH;
351-
delay = this->int_drive->next_sector_delay();
358+
delay = this->selected_drive->next_sector_delay();
352359
}
353360
break;
354361
case SWIM3_DATA_XFER:
355362
// transfer sector data over DMA
356-
this->dma_ch->push_data(this->int_drive->get_sector_data_ptr(this->cur_sector & 0x7F), 512);
363+
this->dma_ch->push_data(this->selected_drive->get_sector_data_ptr(this->cur_sector & 0x7F), 512);
357364
if (--this->xfer_cnt == 0) {
358365
this->stop_disk_access();
359366
// generate sector_done interrupt
@@ -362,7 +369,7 @@ void Swim3Ctrl::disk_access()
362369
return;
363370
}
364371
this->cur_state = SWIM3_ADDR_MARK_SEARCH;
365-
delay = this->int_drive->next_addr_mark_delay(&this->target_sect);
372+
delay = this->selected_drive->next_addr_mark_delay(&this->target_sect);
366373
break;
367374
default:
368375
LOG_F(ERROR, "SWIM3: unknown disk access phase 0x%X", this->cur_state);
@@ -424,6 +431,57 @@ uint8_t Swim3Ctrl::calc_timer_val()
424431
}
425432
}
426433

434+
void Swim3Ctrl::mode_change(uint8_t new_mode)
435+
{
436+
uint8_t changed_bits = this->mode_reg ^ new_mode;
437+
438+
if (changed_bits & (SWIM3_DRIVE_1 | SWIM3_DRIVE_2)) {
439+
this->selected_drive = nullptr;
440+
this->cur_track = 0xFF;
441+
this->cur_sector = 0x7F;
442+
443+
switch (new_mode & (SWIM3_DRIVE_1 | SWIM3_DRIVE_2)) {
444+
case 0:
445+
break;
446+
case SWIM3_DRIVE_1:
447+
if (this->drive_1)
448+
this->selected_drive = this->drive_1.get();
449+
break;
450+
case SWIM3_DRIVE_2:
451+
break;
452+
case SWIM3_DRIVE_1 | SWIM3_DRIVE_2:
453+
LOG_F(ERROR, "SWIM3: both drives selected, selecting drive 1");
454+
if (this->drive_1)
455+
this->selected_drive = this->drive_1.get();
456+
break;
457+
}
458+
if (this->xfer_cnt) {
459+
LOG_F(ERROR, "SWIM3: selecting drive while xfer still in progress");
460+
}
461+
}
462+
463+
if (changed_bits & SWIM3_GO_STEP) {
464+
if (new_mode & SWIM3_GO_STEP)
465+
start_stepping();
466+
else
467+
stop_stepping();
468+
if (changed_bits & SWIM3_GO) {
469+
LOG_F(ERROR, "SWIM3: attempt to change GO and GO_STEP, ignoring GO");
470+
}
471+
}
472+
else
473+
if (changed_bits & SWIM3_GO) {
474+
if (new_mode & SWIM3_GO)
475+
start_disk_access();
476+
else {
477+
stop_disk_access();
478+
this->cur_sector &= ~0x80;
479+
}
480+
}
481+
482+
this->mode_reg = new_mode;
483+
}
484+
427485
// floppy disk formats properties for the cases
428486
// where disk format needs to be specified manually
429487
static const std::vector<std::string> FloppyFormats = {

devices/floppy/swim3.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,11 @@ class Swim3Ctrl : public HWComponent {
113113
void stop_disk_access();
114114
void init_timer(const uint8_t start_val);
115115
uint8_t calc_timer_val();
116+
void mode_change(uint8_t new_mode);
116117

117118
private:
118-
std::unique_ptr<MacSuperdrive::MacSuperDrive> int_drive;
119+
std::unique_ptr<MacSuperdrive::MacSuperDrive> drive_1;
120+
MacSuperdrive::MacSuperDrive *selected_drive;
119121

120122
DmaBidirChannel* dma_ch;
121123

0 commit comments

Comments
 (0)