Skip to content

Commit

Permalink
swim: update IWM/ISM register block decoding
Browse files Browse the repository at this point in the history
Update the IWM/ISM register block decoding to match the description given in the
"SWIM Chip Users Reference". This allows us to validate the device response to
the guest OS which currently only does just enough to indicate that the floppy
drive is unavailable.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Message-ID: <20231004083806.757242-14-mark.cave-ayland@ilande.co.uk>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
  • Loading branch information
mcayland authored and vivier committed Oct 6, 2023
1 parent 5700420 commit 994af0b
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 84 deletions.
212 changes: 134 additions & 78 deletions hw/block/swim.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,28 @@
#include "hw/qdev-properties.h"
#include "trace.h"


/* IWM latch bits */

#define IWMLB_PHASE0 0
#define IWMLB_PHASE1 1
#define IWMLB_PHASE2 2
#define IWMLB_PHASE3 3
#define IWMLB_MOTORON 4
#define IWMLB_DRIVESEL 5
#define IWMLB_L6 6
#define IWMLB_L7 7

/* IWM registers */

#define IWM_PH0L 0
#define IWM_PH0H 1
#define IWM_PH1L 2
#define IWM_PH1H 3
#define IWM_PH2L 4
#define IWM_PH2H 5
#define IWM_PH3L 6
#define IWM_PH3H 7
#define IWM_MTROFF 8
#define IWM_MTRON 9
#define IWM_INTDRIVE 10
#define IWM_EXTDRIVE 11
#define IWM_Q6L 12
#define IWM_Q6H 13
#define IWM_Q7L 14
#define IWM_Q7H 15
#define IWM_READALLONES 0
#define IWM_READDATA 1
#define IWM_READSTATUS0 2
#define IWM_READSTATUS1 3
#define IWM_READWHANDSHAKE0 4
#define IWM_READWHANDSHAKE1 5
#define IWM_WRITESETMODE 6
#define IWM_WRITEDATA 7

/* SWIM registers */

Expand All @@ -62,8 +66,9 @@

#define REG_SHIFT 9

#define SWIM_MODE_IWM 0
#define SWIM_MODE_SWIM 1
#define SWIM_MODE_STATUS_BIT 6
#define SWIM_MODE_IWM 0
#define SWIM_MODE_ISM 1

/* bits in phase register */

Expand Down Expand Up @@ -127,10 +132,8 @@
#define SWIM_MOTON 0x80

static const char *iwm_reg_names[] = {
"PH0L", "PH0H", "PH1L", "PH1H",
"PH2L", "PH2H", "PH3L", "PH3H",
"MTROFF", "MTRON", "INTDRIVE", "EXTDRIVE",
"Q6L", "Q6H", "Q7L", "Q7H"
"READALLONES", "READDATA", "READSTATUS0", "READSTATUS1",
"READWHANDSHAKE0", "READWHANDSHAKE1", "WRITESETMODE", "WRITEDATA"
};

static const char *ism_reg_names[] = {
Expand Down Expand Up @@ -274,68 +277,99 @@ static const TypeInfo swim_bus_info = {
.instance_size = sizeof(SWIMBus),
};

static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value,
static void iwmctrl_write(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
SWIMCtrl *swimctrl = opaque;
uint8_t latch, reg, ism_bit;

reg >>= REG_SHIFT;
addr >>= REG_SHIFT;

/* A3-A1 select a latch, A0 specifies the value */
latch = (addr >> 1) & 7;
if (addr & 1) {
swimctrl->iwm_latches |= (1 << latch);
} else {
swimctrl->iwm_latches &= ~(1 << latch);
}

reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
(swimctrl->iwm_latches & 0x10) >> 4;

swimctrl->iwmregs[reg] = value;
trace_swim_iwmctrl_write(reg, iwm_reg_names[reg], size, value);

if (swimctrl->iwmregs[IWM_Q7H]) {
if (swimctrl->iwmregs[IWM_MTRON]) {
/* data register */
swimctrl->iwm_data = value;
} else {
/* mode register */
swimctrl->iwm_mode = value;
/* detect sequence to switch from IWM mode to SWIM mode */
switch (swimctrl->iwm_switch) {
case 0:
if (value == 0x57) {
swimctrl->iwm_switch++;
}
break;
case 1:
if (value == 0x17) {
swimctrl->iwm_switch++;
}
break;
case 2:
if (value == 0x57) {
swimctrl->iwm_switch++;
}
break;
case 3:
if (value == 0x57) {
swimctrl->mode = SWIM_MODE_SWIM;
swimctrl->iwm_switch = 0;
trace_swim_iwm_switch();

/* Switch to ISM registers */
memory_region_del_subregion(&swimctrl->swim,
&swimctrl->iwm);
memory_region_add_subregion(&swimctrl->swim, 0x0,
&swimctrl->ism);
}
break;
switch (reg) {
case IWM_WRITESETMODE:
/* detect sequence to switch from IWM mode to SWIM mode */
ism_bit = (value & (1 << SWIM_MODE_STATUS_BIT));

switch (swimctrl->iwm_switch) {
case 0:
if (ism_bit) { /* 1 */
swimctrl->iwm_switch++;
}
break;
case 1:
if (!ism_bit) { /* 0 */
swimctrl->iwm_switch++;
}
break;
case 2:
if (ism_bit) { /* 1 */
swimctrl->iwm_switch++;
}
break;
case 3:
if (ism_bit) { /* 1 */
swimctrl->iwm_switch++;

swimctrl->mode = SWIM_MODE_ISM;
swimctrl->swim_mode |= (1 << SWIM_MODE_STATUS_BIT);
swimctrl->iwm_switch = 0;
trace_swim_switch_to_ism();

/* Switch to ISM registers */
memory_region_del_subregion(&swimctrl->swim, &swimctrl->iwm);
memory_region_add_subregion(&swimctrl->swim, 0x0,
&swimctrl->ism);
}
break;
}
break;
default:
break;
}
}

static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size)
static uint64_t iwmctrl_read(void *opaque, hwaddr addr, unsigned size)
{
SWIMCtrl *swimctrl = opaque;
uint8_t value;
uint8_t latch, reg, value;

reg >>= REG_SHIFT;
addr >>= REG_SHIFT;

value = swimctrl->iwmregs[reg];
trace_swim_iwmctrl_read(reg, iwm_reg_names[reg], size, value);
/* A3-A1 select a latch, A0 specifies the value */
latch = (addr >> 1) & 7;
if (addr & 1) {
swimctrl->iwm_latches |= (1 << latch);
} else {
swimctrl->iwm_latches &= ~(1 << latch);
}

reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
(swimctrl->iwm_latches & 0x10) >> 4;

switch (reg) {
case IWM_READALLONES:
value = 0xff;
break;
default:
value = 0;
break;
}

trace_swim_iwmctrl_read(reg, iwm_reg_names[reg], size, value);
return value;
}

Expand All @@ -352,22 +386,39 @@ static void ismctrl_write(void *opaque, hwaddr reg, uint64_t value,

reg >>= REG_SHIFT;

trace_swim_swimctrl_write(reg, ism_reg_names[reg], size, value);
trace_swim_ismctrl_write(reg, ism_reg_names[reg], size, value);

switch (reg) {
case SWIM_WRITE_PHASE:
swimctrl->swim_phase = value;
break;
case SWIM_WRITE_MODE0:
swimctrl->swim_mode &= ~value;
/* Any access to MODE0 register resets PRAM index */
swimctrl->pram_idx = 0;

if (!(swimctrl->swim_mode & (1 << SWIM_MODE_STATUS_BIT))) {
/* Clearing the mode bit switches to IWM mode */
swimctrl->mode = SWIM_MODE_IWM;
swimctrl->iwm_latches = 0;
trace_swim_switch_to_iwm();

/* Switch to IWM registers */
memory_region_del_subregion(&swimctrl->swim, &swimctrl->ism);
memory_region_add_subregion(&swimctrl->swim, 0x0,
&swimctrl->iwm);
}
break;
case SWIM_WRITE_MODE1:
swimctrl->swim_mode |= value;
break;
case SWIM_WRITE_PARAMETER:
swimctrl->pram[swimctrl->pram_idx++] = value;
swimctrl->pram_idx &= 0xf;
break;
case SWIM_WRITE_DATA:
case SWIM_WRITE_MARK:
case SWIM_WRITE_CRC:
case SWIM_WRITE_PARAMETER:
case SWIM_WRITE_SETUP:
break;
}
Expand All @@ -390,16 +441,24 @@ static uint64_t ismctrl_read(void *opaque, hwaddr reg, unsigned size)
value = SWIM_SENSE;
}
break;
case SWIM_READ_PARAMETER:
value = swimctrl->pram[swimctrl->pram_idx++];
swimctrl->pram_idx &= 0xf;
break;
case SWIM_READ_STATUS:
value = swimctrl->swim_status & ~(1 << SWIM_MODE_STATUS_BIT);
if (swimctrl->swim_mode == SWIM_MODE_ISM) {
value |= (1 << SWIM_MODE_STATUS_BIT);
}
break;
case SWIM_READ_DATA:
case SWIM_READ_MARK:
case SWIM_READ_ERROR:
case SWIM_READ_PARAMETER:
case SWIM_READ_SETUP:
case SWIM_READ_STATUS:
break;
}

trace_swim_swimctrl_read(reg, ism_reg_names[reg], size, value);
trace_swim_ismctrl_read(reg, ism_reg_names[reg], size, value);
return value;
}

Expand All @@ -417,13 +476,11 @@ static void sysbus_swim_reset(DeviceState *d)

ctrl->mode = 0;
ctrl->iwm_switch = 0;
ctrl->iwm_data = 0;
ctrl->iwm_mode = 0;
memset(ctrl->iwmregs, 0, 16);
memset(ctrl->iwmregs, 0, sizeof(ctrl->iwmregs));

ctrl->swim_phase = 0;
ctrl->swim_mode = 0;
memset(ctrl->ismregs, 0, 16);
memset(ctrl->ismregs, 0, sizeof(ctrl->ismregs));
for (i = 0; i < SWIM_MAX_FD; i++) {
fd_recalibrate(&ctrl->drives[i]);
}
Expand Down Expand Up @@ -472,9 +529,8 @@ static const VMStateDescription vmstate_swim = {
VMSTATE_INT32(mode, SWIMCtrl),
/* IWM mode */
VMSTATE_INT32(iwm_switch, SWIMCtrl),
VMSTATE_UINT8_ARRAY(iwmregs, SWIMCtrl, 16),
VMSTATE_UINT8(iwm_data, SWIMCtrl),
VMSTATE_UINT8(iwm_mode, SWIMCtrl),
VMSTATE_UINT8(iwm_latches, SWIMCtrl),
VMSTATE_UINT8_ARRAY(iwmregs, SWIMCtrl, 8),
/* SWIM mode */
VMSTATE_UINT8_ARRAY(ismregs, SWIMCtrl, 16),
VMSTATE_UINT8(swim_phase, SWIMCtrl),
Expand Down
7 changes: 4 additions & 3 deletions hw/block/trace-events
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@ m25p80_binding(void *s) "[%p] Binding to IF_MTD drive"
m25p80_binding_no_bdrv(void *s) "[%p] No BDRV - binding to RAM"

# swim.c
swim_swimctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64
swim_swimctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64
swim_ismctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64
swim_ismctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64
swim_iwmctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64
swim_iwmctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64
swim_iwm_switch(void) "switch from IWM to SWIM mode"
swim_switch_to_ism(void) "switch from IWM to ISM mode"
swim_switch_to_iwm(void) "switch from ISM to IWM mode"
8 changes: 5 additions & 3 deletions include/hw/block/swim.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@ struct SWIMCtrl {
int mode;
/* IWM mode */
int iwm_switch;
uint8_t iwmregs[16];
uint8_t iwm_data;
uint8_t iwm_mode;
uint8_t iwm_latches;
uint8_t iwmregs[8];
/* SWIM mode */
uint8_t ismregs[16];
uint8_t swim_phase;
uint8_t swim_mode;
uint8_t swim_status;
uint8_t pram[16];
uint8_t pram_idx;
SWIMBus bus;
};

Expand Down

0 comments on commit 994af0b

Please sign in to comment.