]> git.proxmox.com Git - mirror_qemu.git/blame - hw/block/swim.c
Merge tag 'dirtylimit-dirtyrate-pull-request-20231010' of https://github.com/newfrida...
[mirror_qemu.git] / hw / block / swim.c
CommitLineData
c701ec62
LV
1/*
2 * QEMU Macintosh floppy disk controller emulator (SWIM)
3 *
4 * Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu>
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2. See
7 * the COPYING file in the top-level directory.
8 *
9 * Only the basic support: it allows to switch from IWM (Integrated WOZ
10 * Machine) mode to the SWIM mode and makes the linux driver happy.
11 */
12
13#include "qemu/osdep.h"
14#include "qemu/main-loop.h"
15#include "qapi/error.h"
16#include "sysemu/block-backend.h"
17#include "hw/sysbus.h"
18#include "migration/vmstate.h"
19#include "hw/block/block.h"
20#include "hw/block/swim.h"
21#include "hw/qdev-properties.h"
d05cad2b 22#include "trace.h"
c701ec62 23
994af0b2
MCA
24
25/* IWM latch bits */
26
27#define IWMLB_PHASE0 0
28#define IWMLB_PHASE1 1
29#define IWMLB_PHASE2 2
30#define IWMLB_PHASE3 3
31#define IWMLB_MOTORON 4
32#define IWMLB_DRIVESEL 5
33#define IWMLB_L6 6
34#define IWMLB_L7 7
35
c701ec62
LV
36/* IWM registers */
37
994af0b2
MCA
38#define IWM_READALLONES 0
39#define IWM_READDATA 1
40#define IWM_READSTATUS0 2
41#define IWM_READSTATUS1 3
42#define IWM_READWHANDSHAKE0 4
43#define IWM_READWHANDSHAKE1 5
44#define IWM_WRITESETMODE 6
45#define IWM_WRITEDATA 7
c701ec62
LV
46
47/* SWIM registers */
48
49#define SWIM_WRITE_DATA 0
50#define SWIM_WRITE_MARK 1
51#define SWIM_WRITE_CRC 2
52#define SWIM_WRITE_PARAMETER 3
53#define SWIM_WRITE_PHASE 4
54#define SWIM_WRITE_SETUP 5
55#define SWIM_WRITE_MODE0 6
56#define SWIM_WRITE_MODE1 7
57
58#define SWIM_READ_DATA 8
59#define SWIM_READ_MARK 9
60#define SWIM_READ_ERROR 10
61#define SWIM_READ_PARAMETER 11
62#define SWIM_READ_PHASE 12
63#define SWIM_READ_SETUP 13
64#define SWIM_READ_STATUS 14
65#define SWIM_READ_HANDSHAKE 15
66
67#define REG_SHIFT 9
68
994af0b2
MCA
69#define SWIM_MODE_STATUS_BIT 6
70#define SWIM_MODE_IWM 0
71#define SWIM_MODE_ISM 1
c701ec62
LV
72
73/* bits in phase register */
74
75#define SWIM_SEEK_NEGATIVE 0x074
76#define SWIM_STEP 0x071
77#define SWIM_MOTOR_ON 0x072
78#define SWIM_MOTOR_OFF 0x076
79#define SWIM_INDEX 0x073
80#define SWIM_EJECT 0x077
81#define SWIM_SETMFM 0x171
82#define SWIM_SETGCR 0x175
83#define SWIM_RELAX 0x033
84#define SWIM_LSTRB 0x008
85#define SWIM_CA_MASK 0x077
86
87/* Select values for swim_select and swim_readbit */
88
89#define SWIM_READ_DATA_0 0x074
90#define SWIM_TWOMEG_DRIVE 0x075
91#define SWIM_SINGLE_SIDED 0x076
92#define SWIM_DRIVE_PRESENT 0x077
93#define SWIM_DISK_IN 0x170
94#define SWIM_WRITE_PROT 0x171
95#define SWIM_TRACK_ZERO 0x172
96#define SWIM_TACHO 0x173
97#define SWIM_READ_DATA_1 0x174
98#define SWIM_MFM_MODE 0x175
99#define SWIM_SEEK_COMPLETE 0x176
100#define SWIM_ONEMEG_MEDIA 0x177
101
102/* Bits in handshake register */
103
104#define SWIM_MARK_BYTE 0x01
105#define SWIM_CRC_ZERO 0x02
106#define SWIM_RDDATA 0x04
107#define SWIM_SENSE 0x08
108#define SWIM_MOTEN 0x10
109#define SWIM_ERROR 0x20
110#define SWIM_DAT2BYTE 0x40
111#define SWIM_DAT1BYTE 0x80
112
113/* bits in setup register */
114
115#define SWIM_S_INV_WDATA 0x01
116#define SWIM_S_3_5_SELECT 0x02
117#define SWIM_S_GCR 0x04
118#define SWIM_S_FCLK_DIV2 0x08
119#define SWIM_S_ERROR_CORR 0x10
120#define SWIM_S_IBM_DRIVE 0x20
121#define SWIM_S_GCR_WRITE 0x40
122#define SWIM_S_TIMEOUT 0x80
123
124/* bits in mode register */
125
126#define SWIM_CLFIFO 0x01
127#define SWIM_ENBL1 0x02
128#define SWIM_ENBL2 0x04
129#define SWIM_ACTION 0x08
130#define SWIM_WRITE_MODE 0x10
131#define SWIM_HEDSEL 0x20
132#define SWIM_MOTON 0x80
133
57004204 134static const char *iwm_reg_names[] = {
994af0b2
MCA
135 "READALLONES", "READDATA", "READSTATUS0", "READSTATUS1",
136 "READWHANDSHAKE0", "READWHANDSHAKE1", "WRITESETMODE", "WRITEDATA"
57004204
MCA
137};
138
139static const char *ism_reg_names[] = {
d05cad2b
MCA
140 "WRITE_DATA", "WRITE_MARK", "WRITE_CRC", "WRITE_PARAMETER",
141 "WRITE_PHASE", "WRITE_SETUP", "WRITE_MODE0", "WRITE_MODE1",
142 "READ_DATA", "READ_MARK", "READ_ERROR", "READ_PARAMETER",
143 "READ_PHASE", "READ_SETUP", "READ_STATUS", "READ_HANDSHAKE"
144};
145
c701ec62
LV
146static void fd_recalibrate(FDrive *drive)
147{
148}
149
150static void swim_change_cb(void *opaque, bool load, Error **errp)
151{
152 FDrive *drive = opaque;
153
154 if (!load) {
155 blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
156 } else {
157 if (!blkconf_apply_backend_options(drive->conf,
86b1cf32
KW
158 !blk_supports_write_perm(drive->blk),
159 false, errp)) {
c701ec62
LV
160 return;
161 }
162 }
163}
164
165static const BlockDevOps swim_block_ops = {
166 .change_media_cb = swim_change_cb,
167};
168
169static Property swim_drive_properties[] = {
170 DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1),
171 DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf),
172 DEFINE_PROP_END_OF_LIST(),
173};
174
175static void swim_drive_realize(DeviceState *qdev, Error **errp)
176{
177 SWIMDrive *dev = SWIM_DRIVE(qdev);
178 SWIMBus *bus = SWIM_BUS(qdev->parent_bus);
179 FDrive *drive;
180 int ret;
181
182 if (dev->unit == -1) {
183 for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) {
184 drive = &bus->ctrl->drives[dev->unit];
185 if (!drive->blk) {
186 break;
187 }
188 }
189 }
190
191 if (dev->unit >= SWIM_MAX_FD) {
192 error_setg(errp, "Can't create floppy unit %d, bus supports "
193 "only %d units", dev->unit, SWIM_MAX_FD);
194 return;
195 }
196
197 drive = &bus->ctrl->drives[dev->unit];
198 if (drive->blk) {
199 error_setg(errp, "Floppy unit %d is in use", dev->unit);
200 return;
201 }
202
203 if (!dev->conf.blk) {
204 /* Anonymous BlockBackend for an empty drive */
205 dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
206 ret = blk_attach_dev(dev->conf.blk, qdev);
207 assert(ret == 0);
208 }
209
c56ee92f
RK
210 if (!blkconf_blocksizes(&dev->conf, errp)) {
211 return;
212 }
213
c701ec62
LV
214 if (dev->conf.logical_block_size != 512 ||
215 dev->conf.physical_block_size != 512)
216 {
217 error_setg(errp, "Physical and logical block size must "
218 "be 512 for floppy");
219 return;
220 }
221
222 /*
223 * rerror/werror aren't supported by fdc and therefore not even registered
224 * with qdev. So set the defaults manually before they are used in
225 * blkconf_apply_backend_options().
226 */
227 dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
228 dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
229
230 if (!blkconf_apply_backend_options(&dev->conf,
86b1cf32 231 !blk_supports_write_perm(dev->conf.blk),
c701ec62
LV
232 false, errp)) {
233 return;
234 }
235
236 /*
237 * 'enospc' is the default for -drive, 'report' is what blk_new() gives us
238 * for empty drives.
239 */
240 if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
241 blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
242 error_setg(errp, "fdc doesn't support drive option werror");
243 return;
244 }
245 if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
246 error_setg(errp, "fdc doesn't support drive option rerror");
247 return;
248 }
249
250 drive->conf = &dev->conf;
251 drive->blk = dev->conf.blk;
252 drive->swimctrl = bus->ctrl;
253
254 blk_set_dev_ops(drive->blk, &swim_block_ops, drive);
255}
256
257static void swim_drive_class_init(ObjectClass *klass, void *data)
258{
259 DeviceClass *k = DEVICE_CLASS(klass);
260 k->realize = swim_drive_realize;
261 set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
262 k->bus_type = TYPE_SWIM_BUS;
4f67d30b 263 device_class_set_props(k, swim_drive_properties);
c701ec62
LV
264 k->desc = "virtual SWIM drive";
265}
266
267static const TypeInfo swim_drive_info = {
268 .name = TYPE_SWIM_DRIVE,
269 .parent = TYPE_DEVICE,
270 .instance_size = sizeof(SWIMDrive),
271 .class_init = swim_drive_class_init,
272};
273
274static const TypeInfo swim_bus_info = {
275 .name = TYPE_SWIM_BUS,
276 .parent = TYPE_BUS,
277 .instance_size = sizeof(SWIMBus),
278};
279
994af0b2 280static void iwmctrl_write(void *opaque, hwaddr addr, uint64_t value,
c701ec62
LV
281 unsigned size)
282{
283 SWIMCtrl *swimctrl = opaque;
994af0b2 284 uint8_t latch, reg, ism_bit;
c701ec62 285
994af0b2
MCA
286 addr >>= REG_SHIFT;
287
288 /* A3-A1 select a latch, A0 specifies the value */
289 latch = (addr >> 1) & 7;
290 if (addr & 1) {
291 swimctrl->iwm_latches |= (1 << latch);
292 } else {
293 swimctrl->iwm_latches &= ~(1 << latch);
294 }
295
296 reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
297 (swimctrl->iwm_latches & 0x10) >> 4;
c701ec62 298
57004204
MCA
299 swimctrl->iwmregs[reg] = value;
300 trace_swim_iwmctrl_write(reg, iwm_reg_names[reg], size, value);
c701ec62 301
994af0b2
MCA
302 switch (reg) {
303 case IWM_WRITESETMODE:
304 /* detect sequence to switch from IWM mode to SWIM mode */
305 ism_bit = (value & (1 << SWIM_MODE_STATUS_BIT));
306
307 switch (swimctrl->iwm_switch) {
308 case 0:
309 if (ism_bit) { /* 1 */
310 swimctrl->iwm_switch++;
311 }
312 break;
313 case 1:
314 if (!ism_bit) { /* 0 */
315 swimctrl->iwm_switch++;
316 }
317 break;
318 case 2:
319 if (ism_bit) { /* 1 */
320 swimctrl->iwm_switch++;
c701ec62 321 }
994af0b2
MCA
322 break;
323 case 3:
324 if (ism_bit) { /* 1 */
325 swimctrl->iwm_switch++;
326
327 swimctrl->mode = SWIM_MODE_ISM;
328 swimctrl->swim_mode |= (1 << SWIM_MODE_STATUS_BIT);
329 swimctrl->iwm_switch = 0;
330 trace_swim_switch_to_ism();
331
332 /* Switch to ISM registers */
333 memory_region_del_subregion(&swimctrl->swim, &swimctrl->iwm);
334 memory_region_add_subregion(&swimctrl->swim, 0x0,
335 &swimctrl->ism);
336 }
337 break;
c701ec62 338 }
994af0b2
MCA
339 break;
340 default:
341 break;
c701ec62
LV
342 }
343}
344
994af0b2 345static uint64_t iwmctrl_read(void *opaque, hwaddr addr, unsigned size)
c701ec62
LV
346{
347 SWIMCtrl *swimctrl = opaque;
994af0b2 348 uint8_t latch, reg, value;
c701ec62 349
994af0b2 350 addr >>= REG_SHIFT;
c701ec62 351
994af0b2
MCA
352 /* A3-A1 select a latch, A0 specifies the value */
353 latch = (addr >> 1) & 7;
354 if (addr & 1) {
355 swimctrl->iwm_latches |= (1 << latch);
356 } else {
357 swimctrl->iwm_latches &= ~(1 << latch);
358 }
359
360 reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
361 (swimctrl->iwm_latches & 0x10) >> 4;
362
363 switch (reg) {
364 case IWM_READALLONES:
365 value = 0xff;
366 break;
367 default:
368 value = 0;
369 break;
370 }
c701ec62 371
994af0b2 372 trace_swim_iwmctrl_read(reg, iwm_reg_names[reg], size, value);
57004204 373 return value;
c701ec62
LV
374}
375
57004204
MCA
376static const MemoryRegionOps swimctrl_iwm_ops = {
377 .write = iwmctrl_write,
378 .read = iwmctrl_read,
379 .endianness = DEVICE_BIG_ENDIAN,
380};
381
382static void ismctrl_write(void *opaque, hwaddr reg, uint64_t value,
383 unsigned size)
c701ec62
LV
384{
385 SWIMCtrl *swimctrl = opaque;
386
c701ec62
LV
387 reg >>= REG_SHIFT;
388
994af0b2 389 trace_swim_ismctrl_write(reg, ism_reg_names[reg], size, value);
d05cad2b 390
c701ec62
LV
391 switch (reg) {
392 case SWIM_WRITE_PHASE:
393 swimctrl->swim_phase = value;
394 break;
395 case SWIM_WRITE_MODE0:
396 swimctrl->swim_mode &= ~value;
994af0b2
MCA
397 /* Any access to MODE0 register resets PRAM index */
398 swimctrl->pram_idx = 0;
399
400 if (!(swimctrl->swim_mode & (1 << SWIM_MODE_STATUS_BIT))) {
401 /* Clearing the mode bit switches to IWM mode */
402 swimctrl->mode = SWIM_MODE_IWM;
403 swimctrl->iwm_latches = 0;
404 trace_swim_switch_to_iwm();
405
406 /* Switch to IWM registers */
407 memory_region_del_subregion(&swimctrl->swim, &swimctrl->ism);
408 memory_region_add_subregion(&swimctrl->swim, 0x0,
409 &swimctrl->iwm);
410 }
c701ec62
LV
411 break;
412 case SWIM_WRITE_MODE1:
413 swimctrl->swim_mode |= value;
414 break;
994af0b2
MCA
415 case SWIM_WRITE_PARAMETER:
416 swimctrl->pram[swimctrl->pram_idx++] = value;
417 swimctrl->pram_idx &= 0xf;
418 break;
c701ec62
LV
419 case SWIM_WRITE_DATA:
420 case SWIM_WRITE_MARK:
421 case SWIM_WRITE_CRC:
c701ec62
LV
422 case SWIM_WRITE_SETUP:
423 break;
424 }
425}
426
57004204 427static uint64_t ismctrl_read(void *opaque, hwaddr reg, unsigned size)
c701ec62
LV
428{
429 SWIMCtrl *swimctrl = opaque;
430 uint32_t value = 0;
431
c701ec62
LV
432 reg >>= REG_SHIFT;
433
434 switch (reg) {
435 case SWIM_READ_PHASE:
436 value = swimctrl->swim_phase;
437 break;
438 case SWIM_READ_HANDSHAKE:
439 if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) {
440 /* always answer "no drive present" */
441 value = SWIM_SENSE;
442 }
443 break;
994af0b2
MCA
444 case SWIM_READ_PARAMETER:
445 value = swimctrl->pram[swimctrl->pram_idx++];
446 swimctrl->pram_idx &= 0xf;
447 break;
448 case SWIM_READ_STATUS:
449 value = swimctrl->swim_status & ~(1 << SWIM_MODE_STATUS_BIT);
450 if (swimctrl->swim_mode == SWIM_MODE_ISM) {
451 value |= (1 << SWIM_MODE_STATUS_BIT);
452 }
453 break;
c701ec62
LV
454 case SWIM_READ_DATA:
455 case SWIM_READ_MARK:
456 case SWIM_READ_ERROR:
c701ec62 457 case SWIM_READ_SETUP:
c701ec62
LV
458 break;
459 }
460
994af0b2 461 trace_swim_ismctrl_read(reg, ism_reg_names[reg], size, value);
c701ec62
LV
462 return value;
463}
464
57004204
MCA
465static const MemoryRegionOps swimctrl_ism_ops = {
466 .write = ismctrl_write,
467 .read = ismctrl_read,
468 .endianness = DEVICE_BIG_ENDIAN,
c701ec62
LV
469};
470
471static void sysbus_swim_reset(DeviceState *d)
472{
b694ed1f 473 Swim *sys = SWIM(d);
c701ec62
LV
474 SWIMCtrl *ctrl = &sys->ctrl;
475 int i;
476
477 ctrl->mode = 0;
478 ctrl->iwm_switch = 0;
994af0b2 479 memset(ctrl->iwmregs, 0, sizeof(ctrl->iwmregs));
57004204 480
c701ec62
LV
481 ctrl->swim_phase = 0;
482 ctrl->swim_mode = 0;
994af0b2 483 memset(ctrl->ismregs, 0, sizeof(ctrl->ismregs));
c701ec62
LV
484 for (i = 0; i < SWIM_MAX_FD; i++) {
485 fd_recalibrate(&ctrl->drives[i]);
486 }
487}
488
489static void sysbus_swim_init(Object *obj)
490{
491 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
b694ed1f 492 Swim *sbs = SWIM(obj);
c701ec62
LV
493 SWIMCtrl *swimctrl = &sbs->ctrl;
494
57004204
MCA
495 memory_region_init(&swimctrl->swim, obj, "swim", 0x2000);
496 memory_region_init_io(&swimctrl->iwm, obj, &swimctrl_iwm_ops, swimctrl,
497 "iwm", 0x2000);
498 memory_region_init_io(&swimctrl->ism, obj, &swimctrl_ism_ops, swimctrl,
499 "ism", 0x2000);
500 sysbus_init_mmio(sbd, &swimctrl->swim);
c701ec62
LV
501}
502
503static void sysbus_swim_realize(DeviceState *dev, Error **errp)
504{
b694ed1f 505 Swim *sys = SWIM(dev);
c701ec62
LV
506 SWIMCtrl *swimctrl = &sys->ctrl;
507
d637e1dc 508 qbus_init(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, NULL);
c701ec62 509 swimctrl->bus.ctrl = swimctrl;
57004204
MCA
510
511 /* Default register set is IWM */
512 memory_region_add_subregion(&swimctrl->swim, 0x0, &swimctrl->iwm);
c701ec62
LV
513}
514
515static const VMStateDescription vmstate_fdrive = {
516 .name = "fdrive",
517 .version_id = 1,
518 .minimum_version_id = 1,
519 .fields = (VMStateField[]) {
520 VMSTATE_END_OF_LIST()
521 },
522};
523
524static const VMStateDescription vmstate_swim = {
525 .name = "swim",
526 .version_id = 1,
527 .minimum_version_id = 1,
528 .fields = (VMStateField[]) {
529 VMSTATE_INT32(mode, SWIMCtrl),
530 /* IWM mode */
531 VMSTATE_INT32(iwm_switch, SWIMCtrl),
994af0b2
MCA
532 VMSTATE_UINT8(iwm_latches, SWIMCtrl),
533 VMSTATE_UINT8_ARRAY(iwmregs, SWIMCtrl, 8),
c701ec62 534 /* SWIM mode */
57004204 535 VMSTATE_UINT8_ARRAY(ismregs, SWIMCtrl, 16),
c701ec62
LV
536 VMSTATE_UINT8(swim_phase, SWIMCtrl),
537 VMSTATE_UINT8(swim_mode, SWIMCtrl),
538 /* Drives */
539 VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1,
540 vmstate_fdrive, FDrive),
541 VMSTATE_END_OF_LIST()
542 },
543};
544
545static const VMStateDescription vmstate_sysbus_swim = {
546 .name = "SWIM",
547 .version_id = 1,
548 .fields = (VMStateField[]) {
b694ed1f 549 VMSTATE_STRUCT(ctrl, Swim, 0, vmstate_swim, SWIMCtrl),
c701ec62
LV
550 VMSTATE_END_OF_LIST()
551 }
552};
553
554static void sysbus_swim_class_init(ObjectClass *oc, void *data)
555{
556 DeviceClass *dc = DEVICE_CLASS(oc);
557
558 dc->realize = sysbus_swim_realize;
559 dc->reset = sysbus_swim_reset;
560 dc->vmsd = &vmstate_sysbus_swim;
561}
562
563static const TypeInfo sysbus_swim_info = {
564 .name = TYPE_SWIM,
565 .parent = TYPE_SYS_BUS_DEVICE,
b694ed1f 566 .instance_size = sizeof(Swim),
c701ec62
LV
567 .instance_init = sysbus_swim_init,
568 .class_init = sysbus_swim_class_init,
569};
570
571static void swim_register_types(void)
572{
573 type_register_static(&sysbus_swim_info);
574 type_register_static(&swim_bus_info);
575 type_register_static(&swim_drive_info);
576}
577
578type_init(swim_register_types)