trunk/src/emu/bus/vtech/memexp/floppy.c
| r31140 | r31141 | |
| 8 | 8 | Laser DD 20 |
| 9 | 9 | Dick Smith Electronics X-7304 |
| 10 | 10 | |
| 11 | | TODO: Broken currently, fix & modernize |
| 12 | | |
| 13 | 11 | ***************************************************************************/ |
| 14 | 12 | |
| 15 | 13 | #include "floppy.h" |
| 16 | 14 | #include "formats/vtech1_dsk.h" |
| 17 | 15 | |
| 18 | | |
| 19 | 16 | //************************************************************************** |
| 20 | | // CONSTANTS / MACROS |
| 21 | | //************************************************************************** |
| 22 | | |
| 23 | | #define VERBOSE 1 |
| 24 | | |
| 25 | | #define PHI0(n) (((n) >> 0) & 1) |
| 26 | | #define PHI1(n) (((n) >> 1) & 1) |
| 27 | | #define PHI2(n) (((n) >> 2) & 1) |
| 28 | | #define PHI3(n) (((n) >> 3) & 1) |
| 29 | | |
| 30 | | |
| 31 | | //************************************************************************** |
| 32 | | // FUNCTION PROTOTYPES |
| 33 | | //************************************************************************** |
| 34 | | |
| 35 | | static void laser_load_proc(device_image_interface &image); |
| 36 | | |
| 37 | | |
| 38 | | //************************************************************************** |
| 39 | 17 | // DEVICE DEFINITIONS |
| 40 | 18 | //************************************************************************** |
| 41 | 19 | |
| 42 | 20 | const device_type FLOPPY_CONTROLLER = &device_creator<floppy_controller_device>; |
| 43 | 21 | |
| 22 | DEVICE_ADDRESS_MAP_START(map, 8, floppy_controller_device) |
| 23 | AM_RANGE(0, 0) AM_WRITE(latch_w) |
| 24 | AM_RANGE(1, 1) AM_READ(shifter_r) |
| 25 | AM_RANGE(2, 2) AM_READ(rd_r) |
| 26 | AM_RANGE(3, 3) AM_READ(wpt_r) |
| 27 | ADDRESS_MAP_END |
| 28 | |
| 44 | 29 | //------------------------------------------------- |
| 45 | 30 | // rom_region - device-specific ROM region |
| 46 | 31 | //------------------------------------------------- |
| r31140 | r31141 | |
| 60 | 45 | // machine configurations |
| 61 | 46 | //------------------------------------------------- |
| 62 | 47 | |
| 63 | | static const floppy_interface laser_floppy_interface = |
| 64 | | { |
| 65 | | FLOPPY_STANDARD_5_25_DSHD, |
| 66 | | LEGACY_FLOPPY_OPTIONS_NAME(vtech1_only), |
| 67 | | NULL |
| 68 | | }; |
| 48 | FLOPPY_FORMATS_MEMBER( floppy_controller_device::floppy_formats ) |
| 49 | FLOPPY_MFI_FORMAT |
| 50 | FLOPPY_FORMATS_END |
| 69 | 51 | |
| 52 | static SLOT_INTERFACE_START( laser_floppies ) |
| 53 | SLOT_INTERFACE( "525", FLOPPY_525_SSSD ) |
| 54 | SLOT_INTERFACE_END |
| 55 | |
| 70 | 56 | static MACHINE_CONFIG_FRAGMENT( floppy_controller ) |
| 71 | 57 | MCFG_MEMEXP_SLOT_ADD("mem") |
| 72 | | MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(laser_floppy_interface) |
| 58 | MCFG_FLOPPY_DRIVE_ADD("0", laser_floppies, "525", floppy_controller_device::floppy_formats) |
| 59 | MCFG_FLOPPY_DRIVE_ADD("1", laser_floppies, "525", floppy_controller_device::floppy_formats) |
| 73 | 60 | MACHINE_CONFIG_END |
| 74 | 61 | |
| 75 | 62 | machine_config_constructor floppy_controller_device::device_mconfig_additions() const |
| r31140 | r31141 | |
| 77 | 64 | return MACHINE_CONFIG_NAME( floppy_controller ); |
| 78 | 65 | } |
| 79 | 66 | |
| 80 | | |
| 81 | 67 | //************************************************************************** |
| 82 | 68 | // LIVE DEVICE |
| 83 | 69 | //************************************************************************** |
| r31140 | r31141 | |
| 90 | 76 | device_t(mconfig, FLOPPY_CONTROLLER, "Laser/VZ Floppy Disk Controller", tag, owner, clock, "laserfdc", __FILE__), |
| 91 | 77 | device_memexp_interface(mconfig, *this), |
| 92 | 78 | m_memexp(*this, "mem"), |
| 93 | | m_floppy0(*this, "floppy0"), |
| 94 | | m_floppy1(*this, "floppy1") |
| 79 | m_floppy0(*this, "0"), |
| 80 | m_floppy1(*this, "1") |
| 95 | 81 | { |
| 96 | 82 | } |
| 97 | 83 | |
| r31140 | r31141 | |
| 101 | 87 | |
| 102 | 88 | void floppy_controller_device::device_start() |
| 103 | 89 | { |
| 104 | | m_drive = -1; |
| 105 | | m_fdc_track_x2[0] = 80; |
| 106 | | m_fdc_track_x2[1] = 80; |
| 107 | | m_fdc_wrprot[0] = 0x80; |
| 108 | | m_fdc_wrprot[1] = 0x80; |
| 109 | | m_fdc_status = 0; |
| 110 | | m_fdc_edge = 0; |
| 111 | | m_fdc_bits = 8; |
| 112 | | m_fdc_start = 0; |
| 113 | | m_fdc_write = 0; |
| 114 | | m_fdc_offs = 0; |
| 115 | | m_fdc_latch = 0; |
| 90 | save_item(NAME(m_latch)); |
| 91 | save_item(NAME(m_shifter)); |
| 92 | save_item(NAME(m_latching_inverter)); |
| 93 | save_item(NAME(m_current_cyl)); |
| 94 | save_item(NAME(m_last_latching_inverter_update_time)); |
| 95 | save_item(NAME(m_write_start_time)); |
| 96 | save_item(NAME(m_write_position)); |
| 116 | 97 | |
| 117 | | m_floppy0->floppy_install_load_proc(laser_load_proc); |
| 118 | | m_floppy1->floppy_install_load_proc(laser_load_proc); |
| 98 | // TODO: save m_write_buffer and rebuild m_floppy after load |
| 99 | |
| 100 | UINT8 *bios = memregion("software")->base(); |
| 101 | |
| 102 | // Obvious bugs... must have worked by sheer luck and very subtle |
| 103 | // timings. Our current z80 is not subtle enough. |
| 104 | |
| 105 | bios[0x1678] = 0x75; |
| 106 | bios[0x1688] = 0x85; |
| 119 | 107 | } |
| 120 | 108 | |
| 121 | 109 | //------------------------------------------------- |
| r31140 | r31141 | |
| 129 | 117 | |
| 130 | 118 | m_slot->m_program->install_rom(0x4000, 0x5fff, memregion("software")->base()); |
| 131 | 119 | |
| 132 | | m_slot->m_io->install_read_handler(0x10, 0x1f, read8_delegate(FUNC(floppy_controller_device::floppy_r), this)); |
| 133 | | m_slot->m_io->install_write_handler(0x10, 0x1f, write8_delegate(FUNC(floppy_controller_device::floppy_w), this)); |
| 120 | m_slot->m_io->install_device(0x10, 0x1f, *this, &floppy_controller_device::map); |
| 121 | |
| 122 | m_latch = 0x00; |
| 123 | m_floppy = NULL; |
| 124 | m_current_cyl = 0; |
| 125 | m_shifter = 0x00; |
| 126 | m_latching_inverter = false; |
| 127 | m_last_latching_inverter_update_time = machine().time(); |
| 128 | m_write_start_time = attotime::never; |
| 129 | m_write_position = 0; |
| 130 | memset(m_write_buffer, 0, sizeof(m_write_buffer)); |
| 134 | 131 | } |
| 135 | 132 | |
| 136 | 133 | |
| r31140 | r31141 | |
| 138 | 135 | // IMPLEMENTATION |
| 139 | 136 | //************************************************************************** |
| 140 | 137 | |
| 141 | | int floppy_controller_device::get_floppy_id(device_image_interface *image) |
| 142 | | { |
| 143 | | if (image == dynamic_cast<device_image_interface *>(m_floppy0.target())) |
| 144 | | return 0; |
| 145 | | if (image == dynamic_cast<device_image_interface *>(m_floppy1.target())) |
| 146 | | return 1; |
| 138 | // latch at +0 is linked to: |
| 139 | // bits 0-3: track step motor phases |
| 140 | // bit 5: write data (flux reversal on every level change) |
| 141 | // bit 6: !write request |
| 142 | // bits 4,7: floppy select |
| 147 | 143 | |
| 148 | | return -1; |
| 149 | | } |
| 150 | | |
| 151 | | device_image_interface *floppy_controller_device::get_floppy_device(int drive) |
| 144 | WRITE8_MEMBER(floppy_controller_device::latch_w) |
| 152 | 145 | { |
| 153 | | device_image_interface *image = NULL; |
| 146 | UINT8 diff = m_latch ^ data; |
| 147 | m_latch = data; |
| 154 | 148 | |
| 155 | | switch (drive) |
| 156 | | { |
| 157 | | case 0: |
| 158 | | image = dynamic_cast<device_image_interface *>(m_floppy0.target()); |
| 159 | | break; |
| 149 | floppy_image_device *newflop = NULL; |
| 150 | if(m_latch & 0x10) |
| 151 | newflop = m_floppy0->get_device(); |
| 152 | else if(m_latch & 0x80) |
| 153 | newflop = m_floppy1->get_device(); |
| 160 | 154 | |
| 161 | | case 1: |
| 162 | | image = dynamic_cast<device_image_interface *>(m_floppy1.target()); |
| 163 | | break; |
| 155 | if(newflop != m_floppy) { |
| 156 | update_latching_inverter(); |
| 157 | flush_writes(); |
| 158 | if(m_floppy) { |
| 159 | m_floppy->mon_w(1); |
| 160 | m_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); |
| 161 | } |
| 162 | if(newflop) { |
| 163 | newflop->set_rpm(85); |
| 164 | newflop->mon_w(0); |
| 165 | newflop->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(floppy_controller_device::index_callback), this)); |
| 166 | m_current_cyl = newflop->get_cyl() << 1; |
| 167 | } |
| 168 | m_floppy = newflop; |
| 164 | 169 | } |
| 165 | 170 | |
| 166 | | return image; |
| 171 | if(m_floppy) { |
| 172 | int cph = m_current_cyl & 3; |
| 173 | int pcyl = m_current_cyl; |
| 174 | if(!(m_latch & (1 << cph))) { |
| 175 | if(m_current_cyl < 84*2 && (m_latch & (1 << ((cph+1) & 3)))) |
| 176 | m_current_cyl++; |
| 177 | if(m_current_cyl && (m_latch & (1 << ((cph+3) & 3)))) |
| 178 | m_current_cyl--; |
| 179 | if(m_current_cyl != pcyl && !(m_current_cyl & 1)) { |
| 180 | m_floppy->dir_w(m_current_cyl < pcyl); |
| 181 | m_floppy->stp_w(true); |
| 182 | m_floppy->stp_w(false); |
| 183 | m_floppy->stp_w(true); |
| 184 | } |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | if(diff & 0x40) { |
| 189 | if(!(m_latch & 0x40)) { |
| 190 | m_write_start_time = machine().time(); |
| 191 | m_write_position = 0; |
| 192 | if(m_floppy) |
| 193 | m_floppy->set_write_splice(m_write_start_time); |
| 194 | |
| 195 | } else { |
| 196 | update_latching_inverter(); |
| 197 | flush_writes(); |
| 198 | m_write_start_time = attotime::never; |
| 199 | } |
| 200 | } |
| 201 | if(!(m_latch & 0x40) && (diff & 0x20)) { |
| 202 | if(m_write_position == ARRAY_LENGTH(m_write_buffer)) { |
| 203 | update_latching_inverter(); |
| 204 | flush_writes(true); |
| 205 | } |
| 206 | m_write_buffer[m_write_position++] = machine().time(); |
| 207 | } |
| 167 | 208 | } |
| 168 | 209 | |
| 169 | | static void laser_load_proc(device_image_interface &image) |
| 170 | | { |
| 171 | | floppy_controller_device *fdc = dynamic_cast<floppy_controller_device *>(image.device().owner()); |
| 172 | 210 | |
| 173 | | int id = fdc->get_floppy_id(&image); |
| 211 | // The read data line is connected to a flip/flop with inverted input |
| 212 | // connected to the input. That means it inverts its value on every |
| 213 | // floppy flux reversal. We'll call it a latching inverter. |
| 214 | // |
| 215 | // The latching inverter is connected to a 8-bits shift register. On |
| 216 | // reading the shifter address we get: |
| 217 | // - the inverted inverter output is shifted through the lsb of the shift register |
| 218 | // - the inverter is cleared |
| 174 | 219 | |
| 175 | | if (!image.is_readonly()) |
| 176 | | fdc->m_fdc_wrprot[id] = 0x00; |
| 177 | | else |
| 178 | | fdc->m_fdc_wrprot[id] = 0x80; |
| 220 | READ8_MEMBER(floppy_controller_device::shifter_r) |
| 221 | { |
| 222 | update_latching_inverter(); |
| 223 | m_shifter = (m_shifter << 1) | !m_latching_inverter; |
| 224 | m_latching_inverter = false; |
| 225 | return m_shifter; |
| 179 | 226 | } |
| 180 | 227 | |
| 181 | | void floppy_controller_device::get_track() |
| 182 | | { |
| 183 | | device_image_interface *image = get_floppy_device(m_drive); |
| 184 | 228 | |
| 185 | | /* drive selected or and image file ok? */ |
| 186 | | if (m_drive >= 0 && image->exists()) |
| 187 | | { |
| 188 | | int size, offs; |
| 189 | | size = TRKSIZE_VZ; |
| 190 | | offs = TRKSIZE_VZ * m_fdc_track_x2[m_drive]/2; |
| 191 | | image->fseek(offs, SEEK_SET); |
| 192 | | // some disks have slightly larger header, make sure we capture the checksum at the end of the track |
| 193 | | size = image->fread(m_fdc_data, size+4); |
| 194 | | if (VERBOSE) |
| 195 | | logerror("get track @$%05x $%04x bytes\n", offs, size); |
| 196 | | } |
| 197 | | m_fdc_offs = 0; |
| 198 | | m_fdc_write = 0; |
| 229 | // Linked to the latching inverter on bit 7, rest is floating |
| 230 | READ8_MEMBER(floppy_controller_device::rd_r) |
| 231 | { |
| 232 | update_latching_inverter(); |
| 233 | return m_latching_inverter ? 0x80 : 0x00; |
| 199 | 234 | } |
| 200 | 235 | |
| 201 | | void floppy_controller_device::put_track() |
| 236 | |
| 237 | // Linked to wp signal on bit 7, rest is floating |
| 238 | READ8_MEMBER(floppy_controller_device::wpt_r) |
| 202 | 239 | { |
| 203 | | /* drive selected and image file ok? */ |
| 204 | | if (m_drive >= 0 && floppy_get_device(machine(),m_drive) != NULL) |
| 205 | | { |
| 206 | | int size, offs; |
| 207 | | device_image_interface *image = get_floppy_device(m_drive); |
| 208 | | offs = TRKSIZE_VZ * m_fdc_track_x2[m_drive]/2; |
| 209 | | image->fseek(offs + m_fdc_start, SEEK_SET); |
| 210 | | size = image->fwrite(&m_fdc_data[m_fdc_start], m_fdc_write); |
| 211 | | if (VERBOSE) |
| 212 | | logerror("put track @$%05X+$%X $%04X/$%04X bytes\n", offs, m_fdc_start, size, m_fdc_write); |
| 213 | | } |
| 240 | return m_floppy && m_floppy->wpt_r() ? 0x80 : 0x00; |
| 214 | 241 | } |
| 215 | 242 | |
| 216 | | READ8_MEMBER( floppy_controller_device::floppy_r ) |
| 243 | void floppy_controller_device::update_latching_inverter() |
| 217 | 244 | { |
| 218 | | int data = 0xff; |
| 245 | attotime now = machine().time(); |
| 246 | if(!m_floppy) { |
| 247 | m_last_latching_inverter_update_time = now; |
| 248 | return; |
| 249 | } |
| 219 | 250 | |
| 220 | | switch (offset) |
| 221 | | { |
| 222 | | case 1: /* data (read-only) */ |
| 223 | | if (m_fdc_bits > 0) |
| 224 | | { |
| 225 | | if( m_fdc_status & 0x80 ) |
| 226 | | m_fdc_bits--; |
| 227 | | data = (m_data >> m_fdc_bits) & 0xff; |
| 228 | | if (VERBOSE) { |
| 229 | | logerror("vtech1_fdc_r bits %d%d%d%d%d%d%d%d\n", |
| 230 | | (data>>7)&1,(data>>6)&1,(data>>5)&1,(data>>4)&1, |
| 231 | | (data>>3)&1,(data>>2)&1,(data>>1)&1,(data>>0)&1 ); |
| 232 | | } |
| 233 | | } |
| 234 | | if (m_fdc_bits == 0) |
| 235 | | { |
| 236 | | m_data = m_fdc_data[m_fdc_offs]; |
| 237 | | if (VERBOSE) |
| 238 | | logerror("vtech1_fdc_r %d : data ($%04X) $%02X\n", offset, m_fdc_offs, m_data); |
| 239 | | if(m_fdc_status & 0x80) |
| 240 | | { |
| 241 | | m_fdc_bits = 8; |
| 242 | | m_fdc_offs = (m_fdc_offs + 1) % TRKSIZE_FM; |
| 243 | | } |
| 244 | | m_fdc_status &= ~0x80; |
| 245 | | } |
| 246 | | break; |
| 247 | | case 2: /* polling (read-only) */ |
| 248 | | /* fake */ |
| 249 | | if (m_drive >= 0) |
| 250 | | m_fdc_status |= 0x80; |
| 251 | | data = m_fdc_status; |
| 252 | | break; |
| 253 | | case 3: /* write protect status (read-only) */ |
| 254 | | if (m_drive >= 0) |
| 255 | | data = m_fdc_wrprot[m_drive]; |
| 256 | | if (VERBOSE) |
| 257 | | logerror("vtech1_fdc_r %d : write_protect $%02X\n", offset, data); |
| 258 | | break; |
| 251 | attotime when = m_last_latching_inverter_update_time; |
| 252 | for(;;) { |
| 253 | when = m_floppy->get_next_transition(when); |
| 254 | if(when == attotime::never || when > now) |
| 255 | break; |
| 256 | m_latching_inverter = !m_latching_inverter; |
| 259 | 257 | } |
| 260 | | return data; |
| 258 | m_last_latching_inverter_update_time = now; |
| 261 | 259 | } |
| 262 | 260 | |
| 263 | | WRITE8_MEMBER( floppy_controller_device::floppy_w ) |
| 261 | void floppy_controller_device::index_callback(floppy_image_device *floppy, int state) |
| 264 | 262 | { |
| 265 | | int drive; |
| 263 | update_latching_inverter(); |
| 264 | flush_writes(true); |
| 265 | } |
| 266 | 266 | |
| 267 | | switch (offset) |
| 268 | | { |
| 269 | | case 0: /* latch (write-only) */ |
| 270 | | drive = (data & 0x10) ? 0 : (data & 0x80) ? 1 : -1; |
| 271 | | if (drive != m_drive) |
| 272 | | { |
| 273 | | m_drive = drive; |
| 274 | | if (m_drive >= 0) |
| 275 | | get_track(); |
| 276 | | } |
| 277 | | if (m_drive >= 0) |
| 278 | | { |
| 279 | | if ((PHI0(data) && !(PHI1(data) || PHI2(data) || PHI3(data)) && PHI1(m_fdc_latch)) || |
| 280 | | (PHI1(data) && !(PHI0(data) || PHI2(data) || PHI3(data)) && PHI2(m_fdc_latch)) || |
| 281 | | (PHI2(data) && !(PHI0(data) || PHI1(data) || PHI3(data)) && PHI3(m_fdc_latch)) || |
| 282 | | (PHI3(data) && !(PHI0(data) || PHI1(data) || PHI2(data)) && PHI0(m_fdc_latch))) |
| 283 | | { |
| 284 | | if (m_fdc_track_x2[m_drive] > 0) |
| 285 | | m_fdc_track_x2[m_drive]--; |
| 286 | | if (VERBOSE) |
| 287 | | logerror("vtech1_fdc_w(%d) $%02X drive %d: stepout track #%2d.%d\n", offset, data, m_drive, m_fdc_track_x2[m_drive]/2,5*(m_fdc_track_x2[m_drive]&1)); |
| 288 | | if ((m_fdc_track_x2[m_drive] & 1) == 0) |
| 289 | | get_track(); |
| 290 | | } |
| 291 | | else |
| 292 | | if ((PHI0(data) && !(PHI1(data) || PHI2(data) || PHI3(data)) && PHI3(m_fdc_latch)) || |
| 293 | | (PHI1(data) && !(PHI0(data) || PHI2(data) || PHI3(data)) && PHI0(m_fdc_latch)) || |
| 294 | | (PHI2(data) && !(PHI0(data) || PHI1(data) || PHI3(data)) && PHI1(m_fdc_latch)) || |
| 295 | | (PHI3(data) && !(PHI0(data) || PHI1(data) || PHI2(data)) && PHI2(m_fdc_latch))) |
| 296 | | { |
| 297 | | if (m_fdc_track_x2[m_drive] < 2*40) |
| 298 | | m_fdc_track_x2[m_drive]++; |
| 299 | | if (VERBOSE) |
| 300 | | logerror("vtech1_fdc_w(%d) $%02X drive %d: stepin track #%2d.%d\n", offset, data, m_drive, m_fdc_track_x2[m_drive]/2,5*(m_fdc_track_x2[m_drive]&1)); |
| 301 | | if ((m_fdc_track_x2[m_drive] & 1) == 0) |
| 302 | | get_track(); |
| 303 | | } |
| 304 | | if ((data & 0x40) == 0) |
| 305 | | { |
| 306 | | m_data <<= 1; |
| 307 | | if ((m_fdc_latch ^ data) & 0x20) |
| 308 | | m_data |= 1; |
| 309 | | if ((m_fdc_edge ^= 1) == 0) |
| 310 | | { |
| 311 | | m_fdc_bits--; |
| 267 | void floppy_controller_device::flush_writes(bool keep_margin) |
| 268 | { |
| 269 | if(!m_floppy || m_write_start_time == attotime::never) |
| 270 | return; |
| 312 | 271 | |
| 313 | | if (m_fdc_bits == 0) |
| 314 | | { |
| 315 | | UINT8 value = 0; |
| 316 | | m_data &= 0xffff; |
| 317 | | if (m_data & 0x4000 ) value |= 0x80; |
| 318 | | if (m_data & 0x1000 ) value |= 0x40; |
| 319 | | if (m_data & 0x0400 ) value |= 0x20; |
| 320 | | if (m_data & 0x0100 ) value |= 0x10; |
| 321 | | if (m_data & 0x0040 ) value |= 0x08; |
| 322 | | if (m_data & 0x0010 ) value |= 0x04; |
| 323 | | if (m_data & 0x0004 ) value |= 0x02; |
| 324 | | if (m_data & 0x0001 ) value |= 0x01; |
| 325 | | if (VERBOSE) |
| 326 | | logerror("vtech1_fdc_w(%d) data($%04X) $%02X <- $%02X ($%04X)\n", offset, m_fdc_offs, m_fdc_data[m_fdc_offs], value, m_data); |
| 327 | | m_fdc_data[m_fdc_offs] = value; |
| 328 | | m_fdc_offs = (m_fdc_offs + 1) % TRKSIZE_FM; |
| 329 | | m_fdc_write++; |
| 330 | | m_fdc_bits = 8; |
| 331 | | } |
| 332 | | } |
| 333 | | } |
| 334 | | /* change of write signal? */ |
| 335 | | if ((m_fdc_latch ^ data) & 0x40) |
| 336 | | { |
| 337 | | /* falling edge? */ |
| 338 | | if (m_fdc_latch & 0x40) |
| 339 | | { |
| 340 | | m_fdc_start = m_fdc_offs; |
| 341 | | m_fdc_edge = 0; |
| 342 | | } |
| 343 | | else |
| 344 | | { |
| 345 | | /* data written to track before? */ |
| 346 | | if (m_fdc_write) |
| 347 | | put_track(); |
| 348 | | } |
| 349 | | m_fdc_bits = 8; |
| 350 | | m_fdc_write = 0; |
| 351 | | } |
| 352 | | } |
| 353 | | m_fdc_latch = data; |
| 354 | | break; |
| 272 | // Beware of time travel. Index pulse callback (which flushes) |
| 273 | // can be called with a machine().time() inferior to the last |
| 274 | // m_write_buffer value if the calling cpu instructions are not |
| 275 | // suspendable. |
| 276 | |
| 277 | attotime limit = machine().time(); |
| 278 | int kept_pos = m_write_position; |
| 279 | int kept_count = 0; |
| 280 | while(kept_pos > 0 && m_write_buffer[kept_pos-1] >= limit) { |
| 281 | kept_pos--; |
| 282 | kept_count++; |
| 355 | 283 | } |
| 284 | |
| 285 | if(keep_margin) { |
| 286 | attotime last = kept_pos ? m_write_buffer[kept_pos-1] : m_write_start_time; |
| 287 | attotime delta = limit-last; |
| 288 | delta = delta / 2; |
| 289 | limit = limit - delta; |
| 290 | } |
| 291 | m_write_position -= kept_count; |
| 292 | if(m_write_position && m_write_buffer[0] == m_write_start_time) { |
| 293 | if(m_write_position) |
| 294 | memmove(m_write_buffer, m_write_buffer+1, sizeof(m_write_buffer[0])*(m_write_position-1)); |
| 295 | m_write_position--; |
| 296 | } |
| 297 | m_floppy->write_flux(m_write_start_time, limit, m_write_position, m_write_buffer); |
| 298 | m_write_start_time = limit; |
| 299 | |
| 300 | if(kept_count != 0) |
| 301 | memmove(m_write_buffer, m_write_buffer+kept_pos, kept_count*sizeof(m_write_buffer[0])); |
| 302 | m_write_position = kept_count; |
| 356 | 303 | } |