]> git.proxmox.com Git - mirror_qemu.git/blob - hw/block/swim.c
linux-user/alpha: Set FPE_FLTUNK for gentrap ROPRAND
[mirror_qemu.git] / hw / block / swim.c
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"
22
23 /* IWM registers */
24
25 #define IWM_PH0L 0
26 #define IWM_PH0H 1
27 #define IWM_PH1L 2
28 #define IWM_PH1H 3
29 #define IWM_PH2L 4
30 #define IWM_PH2H 5
31 #define IWM_PH3L 6
32 #define IWM_PH3H 7
33 #define IWM_MTROFF 8
34 #define IWM_MTRON 9
35 #define IWM_INTDRIVE 10
36 #define IWM_EXTDRIVE 11
37 #define IWM_Q6L 12
38 #define IWM_Q6H 13
39 #define IWM_Q7L 14
40 #define IWM_Q7H 15
41
42 /* SWIM registers */
43
44 #define SWIM_WRITE_DATA 0
45 #define SWIM_WRITE_MARK 1
46 #define SWIM_WRITE_CRC 2
47 #define SWIM_WRITE_PARAMETER 3
48 #define SWIM_WRITE_PHASE 4
49 #define SWIM_WRITE_SETUP 5
50 #define SWIM_WRITE_MODE0 6
51 #define SWIM_WRITE_MODE1 7
52
53 #define SWIM_READ_DATA 8
54 #define SWIM_READ_MARK 9
55 #define SWIM_READ_ERROR 10
56 #define SWIM_READ_PARAMETER 11
57 #define SWIM_READ_PHASE 12
58 #define SWIM_READ_SETUP 13
59 #define SWIM_READ_STATUS 14
60 #define SWIM_READ_HANDSHAKE 15
61
62 #define REG_SHIFT 9
63
64 #define SWIM_MODE_IWM 0
65 #define SWIM_MODE_SWIM 1
66
67 /* bits in phase register */
68
69 #define SWIM_SEEK_NEGATIVE 0x074
70 #define SWIM_STEP 0x071
71 #define SWIM_MOTOR_ON 0x072
72 #define SWIM_MOTOR_OFF 0x076
73 #define SWIM_INDEX 0x073
74 #define SWIM_EJECT 0x077
75 #define SWIM_SETMFM 0x171
76 #define SWIM_SETGCR 0x175
77 #define SWIM_RELAX 0x033
78 #define SWIM_LSTRB 0x008
79 #define SWIM_CA_MASK 0x077
80
81 /* Select values for swim_select and swim_readbit */
82
83 #define SWIM_READ_DATA_0 0x074
84 #define SWIM_TWOMEG_DRIVE 0x075
85 #define SWIM_SINGLE_SIDED 0x076
86 #define SWIM_DRIVE_PRESENT 0x077
87 #define SWIM_DISK_IN 0x170
88 #define SWIM_WRITE_PROT 0x171
89 #define SWIM_TRACK_ZERO 0x172
90 #define SWIM_TACHO 0x173
91 #define SWIM_READ_DATA_1 0x174
92 #define SWIM_MFM_MODE 0x175
93 #define SWIM_SEEK_COMPLETE 0x176
94 #define SWIM_ONEMEG_MEDIA 0x177
95
96 /* Bits in handshake register */
97
98 #define SWIM_MARK_BYTE 0x01
99 #define SWIM_CRC_ZERO 0x02
100 #define SWIM_RDDATA 0x04
101 #define SWIM_SENSE 0x08
102 #define SWIM_MOTEN 0x10
103 #define SWIM_ERROR 0x20
104 #define SWIM_DAT2BYTE 0x40
105 #define SWIM_DAT1BYTE 0x80
106
107 /* bits in setup register */
108
109 #define SWIM_S_INV_WDATA 0x01
110 #define SWIM_S_3_5_SELECT 0x02
111 #define SWIM_S_GCR 0x04
112 #define SWIM_S_FCLK_DIV2 0x08
113 #define SWIM_S_ERROR_CORR 0x10
114 #define SWIM_S_IBM_DRIVE 0x20
115 #define SWIM_S_GCR_WRITE 0x40
116 #define SWIM_S_TIMEOUT 0x80
117
118 /* bits in mode register */
119
120 #define SWIM_CLFIFO 0x01
121 #define SWIM_ENBL1 0x02
122 #define SWIM_ENBL2 0x04
123 #define SWIM_ACTION 0x08
124 #define SWIM_WRITE_MODE 0x10
125 #define SWIM_HEDSEL 0x20
126 #define SWIM_MOTON 0x80
127
128 static void fd_recalibrate(FDrive *drive)
129 {
130 }
131
132 static void swim_change_cb(void *opaque, bool load, Error **errp)
133 {
134 FDrive *drive = opaque;
135
136 if (!load) {
137 blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
138 } else {
139 if (!blkconf_apply_backend_options(drive->conf,
140 !blk_supports_write_perm(drive->blk),
141 false, errp)) {
142 return;
143 }
144 }
145 }
146
147 static const BlockDevOps swim_block_ops = {
148 .change_media_cb = swim_change_cb,
149 };
150
151 static Property swim_drive_properties[] = {
152 DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1),
153 DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf),
154 DEFINE_PROP_END_OF_LIST(),
155 };
156
157 static void swim_drive_realize(DeviceState *qdev, Error **errp)
158 {
159 SWIMDrive *dev = SWIM_DRIVE(qdev);
160 SWIMBus *bus = SWIM_BUS(qdev->parent_bus);
161 FDrive *drive;
162 int ret;
163
164 if (dev->unit == -1) {
165 for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) {
166 drive = &bus->ctrl->drives[dev->unit];
167 if (!drive->blk) {
168 break;
169 }
170 }
171 }
172
173 if (dev->unit >= SWIM_MAX_FD) {
174 error_setg(errp, "Can't create floppy unit %d, bus supports "
175 "only %d units", dev->unit, SWIM_MAX_FD);
176 return;
177 }
178
179 drive = &bus->ctrl->drives[dev->unit];
180 if (drive->blk) {
181 error_setg(errp, "Floppy unit %d is in use", dev->unit);
182 return;
183 }
184
185 if (!dev->conf.blk) {
186 /* Anonymous BlockBackend for an empty drive */
187 dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
188 ret = blk_attach_dev(dev->conf.blk, qdev);
189 assert(ret == 0);
190 }
191
192 if (!blkconf_blocksizes(&dev->conf, errp)) {
193 return;
194 }
195
196 if (dev->conf.logical_block_size != 512 ||
197 dev->conf.physical_block_size != 512)
198 {
199 error_setg(errp, "Physical and logical block size must "
200 "be 512 for floppy");
201 return;
202 }
203
204 /*
205 * rerror/werror aren't supported by fdc and therefore not even registered
206 * with qdev. So set the defaults manually before they are used in
207 * blkconf_apply_backend_options().
208 */
209 dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
210 dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
211
212 if (!blkconf_apply_backend_options(&dev->conf,
213 !blk_supports_write_perm(dev->conf.blk),
214 false, errp)) {
215 return;
216 }
217
218 /*
219 * 'enospc' is the default for -drive, 'report' is what blk_new() gives us
220 * for empty drives.
221 */
222 if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
223 blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
224 error_setg(errp, "fdc doesn't support drive option werror");
225 return;
226 }
227 if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
228 error_setg(errp, "fdc doesn't support drive option rerror");
229 return;
230 }
231
232 drive->conf = &dev->conf;
233 drive->blk = dev->conf.blk;
234 drive->swimctrl = bus->ctrl;
235
236 blk_set_dev_ops(drive->blk, &swim_block_ops, drive);
237 }
238
239 static void swim_drive_class_init(ObjectClass *klass, void *data)
240 {
241 DeviceClass *k = DEVICE_CLASS(klass);
242 k->realize = swim_drive_realize;
243 set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
244 k->bus_type = TYPE_SWIM_BUS;
245 device_class_set_props(k, swim_drive_properties);
246 k->desc = "virtual SWIM drive";
247 }
248
249 static const TypeInfo swim_drive_info = {
250 .name = TYPE_SWIM_DRIVE,
251 .parent = TYPE_DEVICE,
252 .instance_size = sizeof(SWIMDrive),
253 .class_init = swim_drive_class_init,
254 };
255
256 static const TypeInfo swim_bus_info = {
257 .name = TYPE_SWIM_BUS,
258 .parent = TYPE_BUS,
259 .instance_size = sizeof(SWIMBus),
260 };
261
262 static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value,
263 unsigned size)
264 {
265 SWIMCtrl *swimctrl = opaque;
266
267 reg >>= REG_SHIFT;
268
269 swimctrl->regs[reg >> 1] = reg & 1;
270
271 if (swimctrl->regs[IWM_Q6] &&
272 swimctrl->regs[IWM_Q7]) {
273 if (swimctrl->regs[IWM_MTR]) {
274 /* data register */
275 swimctrl->iwm_data = value;
276 } else {
277 /* mode register */
278 swimctrl->iwm_mode = value;
279 /* detect sequence to switch from IWM mode to SWIM mode */
280 switch (swimctrl->iwm_switch) {
281 case 0:
282 if (value == 0x57) {
283 swimctrl->iwm_switch++;
284 }
285 break;
286 case 1:
287 if (value == 0x17) {
288 swimctrl->iwm_switch++;
289 }
290 break;
291 case 2:
292 if (value == 0x57) {
293 swimctrl->iwm_switch++;
294 }
295 break;
296 case 3:
297 if (value == 0x57) {
298 swimctrl->mode = SWIM_MODE_SWIM;
299 swimctrl->iwm_switch = 0;
300 }
301 break;
302 }
303 }
304 }
305 }
306
307 static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size)
308 {
309 SWIMCtrl *swimctrl = opaque;
310
311 reg >>= REG_SHIFT;
312
313 swimctrl->regs[reg >> 1] = reg & 1;
314
315 return 0;
316 }
317
318 static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value,
319 unsigned size)
320 {
321 SWIMCtrl *swimctrl = opaque;
322
323 if (swimctrl->mode == SWIM_MODE_IWM) {
324 iwmctrl_write(opaque, reg, value, size);
325 return;
326 }
327
328 reg >>= REG_SHIFT;
329
330 switch (reg) {
331 case SWIM_WRITE_PHASE:
332 swimctrl->swim_phase = value;
333 break;
334 case SWIM_WRITE_MODE0:
335 swimctrl->swim_mode &= ~value;
336 break;
337 case SWIM_WRITE_MODE1:
338 swimctrl->swim_mode |= value;
339 break;
340 case SWIM_WRITE_DATA:
341 case SWIM_WRITE_MARK:
342 case SWIM_WRITE_CRC:
343 case SWIM_WRITE_PARAMETER:
344 case SWIM_WRITE_SETUP:
345 break;
346 }
347 }
348
349 static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size)
350 {
351 SWIMCtrl *swimctrl = opaque;
352 uint32_t value = 0;
353
354 if (swimctrl->mode == SWIM_MODE_IWM) {
355 return iwmctrl_read(opaque, reg, size);
356 }
357
358 reg >>= REG_SHIFT;
359
360 switch (reg) {
361 case SWIM_READ_PHASE:
362 value = swimctrl->swim_phase;
363 break;
364 case SWIM_READ_HANDSHAKE:
365 if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) {
366 /* always answer "no drive present" */
367 value = SWIM_SENSE;
368 }
369 break;
370 case SWIM_READ_DATA:
371 case SWIM_READ_MARK:
372 case SWIM_READ_ERROR:
373 case SWIM_READ_PARAMETER:
374 case SWIM_READ_SETUP:
375 case SWIM_READ_STATUS:
376 break;
377 }
378
379 return value;
380 }
381
382 static const MemoryRegionOps swimctrl_mem_ops = {
383 .write = swimctrl_write,
384 .read = swimctrl_read,
385 .endianness = DEVICE_NATIVE_ENDIAN,
386 };
387
388 static void sysbus_swim_reset(DeviceState *d)
389 {
390 Swim *sys = SWIM(d);
391 SWIMCtrl *ctrl = &sys->ctrl;
392 int i;
393
394 ctrl->mode = 0;
395 ctrl->iwm_switch = 0;
396 for (i = 0; i < 8; i++) {
397 ctrl->regs[i] = 0;
398 }
399 ctrl->iwm_data = 0;
400 ctrl->iwm_mode = 0;
401 ctrl->swim_phase = 0;
402 ctrl->swim_mode = 0;
403 for (i = 0; i < SWIM_MAX_FD; i++) {
404 fd_recalibrate(&ctrl->drives[i]);
405 }
406 }
407
408 static void sysbus_swim_init(Object *obj)
409 {
410 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
411 Swim *sbs = SWIM(obj);
412 SWIMCtrl *swimctrl = &sbs->ctrl;
413
414 memory_region_init_io(&swimctrl->iomem, obj, &swimctrl_mem_ops, swimctrl,
415 "swim", 0x2000);
416 sysbus_init_mmio(sbd, &swimctrl->iomem);
417 }
418
419 static void sysbus_swim_realize(DeviceState *dev, Error **errp)
420 {
421 Swim *sys = SWIM(dev);
422 SWIMCtrl *swimctrl = &sys->ctrl;
423
424 qbus_init(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, NULL);
425 swimctrl->bus.ctrl = swimctrl;
426 }
427
428 static const VMStateDescription vmstate_fdrive = {
429 .name = "fdrive",
430 .version_id = 1,
431 .minimum_version_id = 1,
432 .fields = (VMStateField[]) {
433 VMSTATE_END_OF_LIST()
434 },
435 };
436
437 static const VMStateDescription vmstate_swim = {
438 .name = "swim",
439 .version_id = 1,
440 .minimum_version_id = 1,
441 .fields = (VMStateField[]) {
442 VMSTATE_INT32(mode, SWIMCtrl),
443 /* IWM mode */
444 VMSTATE_INT32(iwm_switch, SWIMCtrl),
445 VMSTATE_UINT16_ARRAY(regs, SWIMCtrl, 8),
446 VMSTATE_UINT8(iwm_data, SWIMCtrl),
447 VMSTATE_UINT8(iwm_mode, SWIMCtrl),
448 /* SWIM mode */
449 VMSTATE_UINT8(swim_phase, SWIMCtrl),
450 VMSTATE_UINT8(swim_mode, SWIMCtrl),
451 /* Drives */
452 VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1,
453 vmstate_fdrive, FDrive),
454 VMSTATE_END_OF_LIST()
455 },
456 };
457
458 static const VMStateDescription vmstate_sysbus_swim = {
459 .name = "SWIM",
460 .version_id = 1,
461 .fields = (VMStateField[]) {
462 VMSTATE_STRUCT(ctrl, Swim, 0, vmstate_swim, SWIMCtrl),
463 VMSTATE_END_OF_LIST()
464 }
465 };
466
467 static void sysbus_swim_class_init(ObjectClass *oc, void *data)
468 {
469 DeviceClass *dc = DEVICE_CLASS(oc);
470
471 dc->realize = sysbus_swim_realize;
472 dc->reset = sysbus_swim_reset;
473 dc->vmsd = &vmstate_sysbus_swim;
474 }
475
476 static const TypeInfo sysbus_swim_info = {
477 .name = TYPE_SWIM,
478 .parent = TYPE_SYS_BUS_DEVICE,
479 .instance_size = sizeof(Swim),
480 .instance_init = sysbus_swim_init,
481 .class_init = sysbus_swim_class_init,
482 };
483
484 static void swim_register_types(void)
485 {
486 type_register_static(&sysbus_swim_info);
487 type_register_static(&swim_bus_info);
488 type_register_static(&swim_drive_info);
489 }
490
491 type_init(swim_register_types)