diff --git a/AltairZ80/altairz80_cpu.c b/AltairZ80/altairz80_cpu.c
index 24a84cd1..3ffe1d70 100644
--- a/AltairZ80/altairz80_cpu.c
+++ b/AltairZ80/altairz80_cpu.c
@@ -2084,14 +2084,31 @@ static t_stat sim_instr_mmu (void) {
register uint32 cbits;
register uint32 op;
register uint32 adr;
- /* tStates contains the number of t-states executed. One t-state is executed
- in one microsecond on a 1MHz CPU. tStates is used for real-time simulations. */
- register uint32 tStates;
- uint32 tStatesInSlice; /* number of t-states in 10 mSec time-slice */
+
+ /* The clock frequency simulation works as follows:
+ For each 8080 or Z80 instruction one can determine the number of t-states
+ needed for its execution. One t-state is executed in one microsecond on a
+ 1MHz CPU. The variable sliceLength defines a time interval of typically
+ 10 ms. When the clock frequency (clockFrequency) is known one can compute
+ the number of t-states which need to be completed in this slice:
+ tStatesInSlice = sliceLength * clockFrequency. The variable tStates counts
+ how many t-states have already been completed. startTime is initialized
+ with the current time when tStates is 0 at the beginning.
+
+ Periodically there is a check whether tStates >= tStatesInSlice.
+ If this is true case three things happen:
+
+ 1. startTime is incremented by sliceLength giving the new expected current time.
+ 2. tStates is decremented by tStatesInSlice.
+ 3. In case startTime is in the future there is a sleep until startTime
+ is equal to the current time.
+ */
+ register uint32 tStates; /* number of t-states executed in the current time-slice */
+ uint32 tStatesInSlice; /* number of t-states in a 10 mSec time-slice */
uint32 startTime, now;
int32 tStateModifier = FALSE;
- switch_cpu_now = TRUE; /* hharte */
+ switch_cpu_now = TRUE;
AF = AF_S;
BC = BC_S;
@@ -2127,11 +2144,13 @@ static t_stat sim_instr_mmu (void) {
}
if (specialProcessing) { /* quick check for special processing */
+
+ /* check for CPU clock frequency simulation + enough t-states executed */
if (clockFrequency && (tStates >= tStatesInSlice)) {
/* clockFrequency != 0 implies that real time clock is available */
- startTime += sliceLength;
- tStates -= tStatesInSlice;
- if (startTime > (now = sim_os_msec()))
+ startTime += sliceLength; /* advance start time to new expected current time */
+ tStates -= tStatesInSlice; /* reduce by t-states executed in a slice */
+ if (startTime > (now = sim_os_msec())) /* if expected time is in the future, sleep */
sim_os_ms_sleep(startTime - now);
}
diff --git a/AltairZ80/altairz80_dsk.c b/AltairZ80/altairz80_dsk.c
index 84445408..7264bc05 100644
--- a/AltairZ80/altairz80_dsk.c
+++ b/AltairZ80/altairz80_dsk.c
@@ -145,7 +145,7 @@
#define UNIT_DSK_WLK (1 << UNIT_V_DSK_WLK)
#define DSK_SECTSIZE 137 /* size of sector */
#define DSK_SECT 32 /* sectors per track */
-#define MAX_TRACKS 254 /* number of tracks,
+#define MAX_TRACKS 2048 /* number of tracks,
original Altair has 77 tracks only */
#define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT)
#define MAX_DSK_SIZE (DSK_TRACSIZE * MAX_TRACKS)
diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c
index c191fa2b..fb86e726 100644
--- a/AltairZ80/altairz80_hdsk.c
+++ b/AltairZ80/altairz80_hdsk.c
@@ -187,6 +187,102 @@ static int32 mits[SPT32] = { 0, 17, 2, 19, 4, 21, 6, 23,
measured in CP/M sectors of size 128 bytes. Standard format "HDSK" must be
first as index 0 is used as default in some cases.
*/
+
+/*
+ The structure of a Disk Parameter Block in CP/M is as follows:
+
+ +---+---+---+---+---+---+---+---+---+---+
+ |SPT|BSH|BLM|EXM|DSM|DRM|AL0|AL1|CKS|OFF|
+ +---+---+---+---+---+---+---+---+---+---+
+ 16B 8B 8B 8B 16B 16B 8B 8B 16B 16B
+
+where each is a byte or word value, as shown by the 8b or 16b indicator
+below the field.
+
+The following field abbreviations are used in the figure above:
+ SPT is the total number of sectors per track.
+ BSH is the data allocation block shift factor, determined by
+ the data block allocation size.
+ BLM is the data allocation block mask (2[BSH-1]).
+ EXM is the extent mask, determined by the data block
+ allocation size and the number of disk blocks.
+ DSM determines the total storage capacity of the disk drive.
+ DRM determines the total number of directory entries that
+ can be stored on this drive.
+ AL0, AL1 determine reserved directory blocks.
+ CKS is the size of the directory check vector.
+
+ OFF is the number of reserved tracks at the beginning of the
+ (logical) disk.
+
+The values of BSH and BLM determine the data allocation size BLS, which is
+not an entry in the DPB. Given that the designer has selected a value for
+BLS, the values of BSH and BLM are shown in the following table.
+
+ BLS BSH BLM
+ 1,024 3 7
+ 2,048 4 15
+ 4,096 5 31
+ 8,192 6 63
+ 16,384 7 127
+
+where all values are in decimal. The value of EXM depends upon both the BLS
+and whether the DSM value is less than 256 or greater than 255, as shown in
+the table below.
+
+ EXM values
+ BLS DSM<256 DSM>255
+ 1,024 0 N/A
+ 2,048 1 0
+ 4,096 3 1
+ 8,192 7 3
+ 16,384 15 7
+
+The value of DSM is the maximum data block number supported by this
+particular drive, measured in BLS units. The product (DSM + 1) is the total
+number of bytes held by the drive and must be within the capacity of the
+physical disk, not counting the reserved operating system tracks.
+
+The DRM entry is the one less than the total number of directory entries
+that can take on a 16-bit value. The values of AL0 and AL1, however, are
+determined by DRM. The values AL0 and AL1 can together be considered a
+string of 16-bits, as shown below.
+
+ |--------- AL0 ---------|-------- AL1 ----------|
+ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
+
+Position 00 corresponds to the high-order bit of the byte labeled AL0 and
+15 corresponds to the low-order bit of the byte labeled AL1. Each bit
+position reserves a data block for number of directory entries, thus
+allowing a total of 16 data blocks to be assigned for directory entries
+(bits are assigned starting at 00 and filled to the right until position
+15). Each directory entry occupies 32 bytes, resulting in the following
+tabulation:
+
+ BLS Directory Entries
+ 1,024 32 times # bits
+ 2,048 64 times # bits
+ 4,096 128 times # bits
+ 8,192 256 times # bits
+ 16,384 512 times # bits
+
+Thus, if DRM = 127 (128 directory entries) and BLS = 1024, there are 32
+directory entries per block, requiring 4 reserved blocks. In this case, the
+4 high-order bits of AL0 are set, resulting in the values AL0 = 0F0H and
+AL1 = 00H.
+
+The CKS value is determined as follows: if the disk drive media is
+removable, then CKS = (DRM + 1)/4, where DRM is the last directory entry
+number. If the media are fixed, then set CKS = 0 (no directory records are
+checked in this case).
+
+Finally, the OFF field determines the number of tracks that are skipped at
+the beginning of the physical disk. This value is automatically added
+whenever SETTRK is called and can be used as a mechanism for skipping
+reserved operating system tracks or for partitioning a large disk into
+smaller segmented sections.
+
+ */
static DPB dpb[] = {
/* name capac spt bsh blm exm dsm drm
al0 al1 cks off psh phm ss off skew */
@@ -241,7 +337,10 @@ static DPB dpb[] = {
{ "SSDD8S", 512512, SPT52, 0x04, 0x0F, 0x01, 242, 0x007F,
0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, standard8 }, /* Standard 8" SS DD with skew */
- { "DSDD8", 1025024, SPT52, 0x04, 0x0F, 0x00, 493, 0x007F,
+ { "DSSD8S", 512512, SPT26, 0x03, 0x07, 0x00, 487, 0x007F,
+ 0xF0, 0x00, 0x0000, 0x0004, 0x00, 0x00, 0, 0, standard8 }, /* Standard 8" DS SD with skew */
+
+ { "DSDD8", 1025024, SPT52, 0x04, 0x0F, 0x00, 493, 0x007F, // psco test
0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, NULL }, /* Standard 8" DS DD */
{ "DSDD8S", 1025024, SPT52, 0x04, 0x0F, 0x00, 493, 0x007F,
diff --git a/AltairZ80/altairz80_sio.c b/AltairZ80/altairz80_sio.c
index 0322122e..9e8263ac 100644
--- a/AltairZ80/altairz80_sio.c
+++ b/AltairZ80/altairz80_sio.c
@@ -138,6 +138,8 @@ static const char* sio_description(DEVICE *dptr);
static const char* simh_description(DEVICE *dptr);
static const char* ptr_description(DEVICE *dptr);
static const char* ptp_description(DEVICE *dptr);
+static t_stat ptpptr_dev_set_port(UNIT *uptr, int32 value, CONST char *cptr, void *desc);
+static t_stat ptpptr_dev_show_port(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static void mapAltairPorts(void);
int32 nulldev (const int32 port, const int32 io, const int32 data);
int32 sr_dev (const int32 port, const int32 io, const int32 data);
@@ -288,6 +290,10 @@ static int32 warnUnassignedPort = 0; /* display a warning message if
int32 keyboardInterrupt = FALSE; /* keyboard interrupt pending */
uint32 keyboardInterruptHandler = 0x0038;/* address of keyboard interrupt handler */
+/* PTR/PTP port assignments (read only) */
+static int32 ptpptrStatusPort = 0x12; /* default status port for PTP/PTR device */
+static int32 ptpptrDataPort = 0x13; /* default data port for PTP/PTR device */
+
static TMLN TerminalLines[TERMINALS] = { /* four terminals */
{ 0 }
};
@@ -320,7 +326,7 @@ static REG sio_reg[] = {
"BOOL to determine whether terminal input is attached to a file"), REG_RO },
/* TRUE iff terminal input is attached to a file */
{ HRDATAD (TSTATUS, sio_unit.u3, 8,
- "BOOL to determine whethere a character is available") },
+ "BOOL to determine whether a character is available") },
/* TRUE iff a character available in sio_unit.buf */
{ DRDATAD (TBUFFER, sio_unit.buf, 8,
"Input buffer register") },
@@ -388,6 +394,9 @@ DEVICE sio_dev = {
};
static MTAB ptpptr_mod[] = {
+ { MTAB_XTD|MTAB_VDV, 0, "PORT", "PORT",
+ &ptpptr_dev_set_port, &ptpptr_dev_show_port, NULL,
+ "Set status and data port for PTP/PTR device" },
{ 0 }
};
@@ -396,7 +405,9 @@ static UNIT ptr_unit = {
};
static REG ptr_reg[] = {
- { HRDATAD (STAT, ptr_unit.u3, 8, "Status register") },
+ { HRDATAD (PTRSTATUSPORT, ptpptrStatusPort, 8, "PTR status port (shared with PTP)"), REG_RO },
+ { HRDATAD (PTRDATAPORT, ptpptrDataPort, 8, "PTR data port (shared with PTP)"), REG_RO },
+ { HRDATAD (PTRSTATUS, ptr_unit.u3, 8, "PTR Status register") },
{ NULL }
};
@@ -417,12 +428,18 @@ static UNIT ptp_unit = {
UDATA (NULL, UNIT_ATTABLE, 0)
};
+static REG ptp_reg[] = {
+ { HRDATAD (PTPSTATUSPORT, ptpptrStatusPort, 8, "PTP status port (shared with PTR)"), REG_RO },
+ { HRDATAD (PTPDATAPORT, ptpptrDataPort, 8, "PTP data port (shared with PTR)"), REG_RO },
+ { NULL }
+};
+
static const char* ptp_description(DEVICE *dptr) {
return "Paper Tape Puncher";
}
DEVICE ptp_dev = {
- "PTP", &ptp_unit, NULL, ptpptr_mod,
+ "PTP", &ptp_unit, ptp_reg, ptpptr_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, NULL, NULL,
@@ -992,6 +1009,33 @@ static uint32 equalSIP(SIO_PORT_INFO x, SIO_PORT_INFO y) {
(x.sio_reset == y.sio_reset) && (x.hasOUT == y.hasOUT);
}
+static t_stat ptpptr_dev_set_port(UNIT *uptr, int32 value, CONST char *cptr, void *desc) {
+ int32 result, n, statusPort, dataPort;
+ if (cptr == NULL)
+ return SCPE_ARG;
+ result = sscanf(cptr, "%x/%x%n", &statusPort, &dataPort, &n);
+ if ((result != 2) || (result == EOF) || (cptr[n] != 0))
+ return SCPE_ARG;
+ if (statusPort != (statusPort & 0xff)) {
+ sim_printf("Truncating status port 0x%x to 0x%02x.\n", statusPort, statusPort & 0xff);
+ statusPort &= 0xff;
+ }
+ if (dataPort != (dataPort & 0xff)) {
+ sim_printf("Truncating data port 0x%x to 0x%02x.\n", dataPort, dataPort & 0xff);
+ dataPort &= 0xff;
+ }
+ sim_map_resource(statusPort, 1, RESOURCE_TYPE_IO, &sio1s, "sio1s", ptp_dev.flags & ptr_dev.flags & DEV_DIS);
+ ptpptrStatusPort = statusPort;
+ sim_map_resource(dataPort, 1, RESOURCE_TYPE_IO, &sio1d, "sio1d", ptp_dev.flags & ptr_dev.flags & DEV_DIS);
+ ptpptrDataPort = dataPort;
+ return SCPE_OK;
+}
+
+static t_stat ptpptr_dev_show_port(FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
+ fprintf(st, "\n\tStatus port = 0x%02x\n\t Data port = 0x%02x\n", ptpptrStatusPort, ptpptrDataPort);
+ return SCPE_OK;
+}
+
static t_stat sio_dev_set_port(UNIT *uptr, int32 value, CONST char *cptr, void *desc) {
int32 result, n, position, isDataPort;
SIO_PORT_INFO sip = { 0 }, old;
diff --git a/AltairZ80/altairz80_sys.c b/AltairZ80/altairz80_sys.c
index 93706090..34c5c987 100644
--- a/AltairZ80/altairz80_sys.c
+++ b/AltairZ80/altairz80_sys.c
@@ -68,6 +68,7 @@ extern DEVICE hdc1001_dev;
extern DEVICE jade_dev;
extern DEVICE tarbell_dev;
+extern DEVICE icom_dev;
extern DEVICE m2sio0_dev;
extern DEVICE m2sio1_dev;
extern DEVICE pmmi_dev;
@@ -127,6 +128,8 @@ DEVICE *sim_devices[] = {
&jade_dev,
/* Tarbell Devices */
&tarbell_dev,
+ /* iCOM Devices */
+ &icom_dev,
/* MITS 88-2SIO */
&m2sio0_dev,
&m2sio1_dev,
diff --git a/AltairZ80/s100_2sio.c b/AltairZ80/s100_2sio.c
index b741cc06..2d941ede 100644
--- a/AltairZ80/s100_2sio.c
+++ b/AltairZ80/s100_2sio.c
@@ -288,61 +288,61 @@ static REG m2sio1_reg[] = {
};
DEVICE m2sio0_dev = {
- M2SIO0_SNAME, /* name */
- m2sio0_unit, /* unit */
- m2sio0_reg, /* registers */
- m2sio_mod, /* modifiers */
- 1, /* # units */
- 10, /* address radix */
- 31, /* address width */
- 1, /* address increment */
- 8, /* data radix */
- 8, /* data width */
- NULL, /* examine routine */
- NULL, /* deposit routine */
- &m2sio0_reset, /* reset routine */
- NULL, /* boot routine */
- &m2sio_attach, /* attach routine */
- &m2sio_detach, /* detach routine */
- &m2sio0_ctx, /* context */
+ M2SIO0_SNAME, /* name */
+ m2sio0_unit, /* unit */
+ m2sio0_reg, /* registers */
+ m2sio_mod, /* modifiers */
+ 1, /* # units */
+ 10, /* address radix */
+ 31, /* address width */
+ 1, /* address increment */
+ 8, /* data radix */
+ 8, /* data width */
+ NULL, /* examine routine */
+ NULL, /* deposit routine */
+ &m2sio0_reset, /* reset routine */
+ NULL, /* boot routine */
+ &m2sio_attach, /* attach routine */
+ &m2sio_detach, /* detach routine */
+ &m2sio0_ctx, /* context */
(DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX), /* flags */
- 0, /* debug control */
- m2sio_dt, /* debug flags */
- NULL, /* mem size routine */
- NULL, /* logical name */
- NULL, /* help */
- NULL, /* attach help */
- NULL, /* context for help */
- &m2sio_description /* description */
+ 0, /* debug control */
+ m2sio_dt, /* debug flags */
+ NULL, /* mem size routine */
+ NULL, /* logical name */
+ NULL, /* help */
+ NULL, /* attach help */
+ NULL, /* context for help */
+ &m2sio_description /* description */
};
DEVICE m2sio1_dev = {
- M2SIO1_SNAME, /* name */
- m2sio1_unit, /* unit */
- m2sio1_reg, /* registers */
- m2sio_mod, /* modifiers */
- 1, /* # units */
- 10, /* address radix */
- 31, /* address width */
- 1, /* address increment */
- 8, /* data radix */
- 8, /* data width */
- NULL, /* examine routine */
- NULL, /* deposit routine */
- &m2sio1_reset, /* reset routine */
- NULL, /* boot routine */
- &m2sio_attach, /* attach routine */
- &m2sio_detach, /* detach routine */
- &m2sio1_ctx, /* context */
+ M2SIO1_SNAME, /* name */
+ m2sio1_unit, /* unit */
+ m2sio1_reg, /* registers */
+ m2sio_mod, /* modifiers */
+ 1, /* # units */
+ 10, /* address radix */
+ 31, /* address width */
+ 1, /* address increment */
+ 8, /* data radix */
+ 8, /* data width */
+ NULL, /* examine routine */
+ NULL, /* deposit routine */
+ &m2sio1_reset, /* reset routine */
+ NULL, /* boot routine */
+ &m2sio_attach, /* attach routine */
+ &m2sio_detach, /* detach routine */
+ &m2sio1_ctx, /* context */
(DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX), /* flags */
- 0, /* debug control */
- m2sio_dt, /* debug flags */
- NULL, /* mem size routine */
- NULL, /* logical name */
- NULL, /* help */
- NULL, /* attach help */
- NULL, /* context for help */
- &m2sio_description /* description */
+ 0, /* debug control */
+ m2sio_dt, /* debug flags */
+ NULL, /* mem size routine */
+ NULL, /* logical name */
+ NULL, /* help */
+ NULL, /* attach help */
+ NULL, /* context for help */
+ &m2sio_description /* description */
};
static const char* m2sio_description(DEVICE *dptr)
@@ -365,10 +365,10 @@ static t_stat m2sio_reset(DEVICE *dptr, int32 (*routine)(const int32, const int3
M2SIO_CTX *xptr;
int32 c;
- xptr = dptr->ctxt;
+ xptr = (M2SIO_CTX *) dptr->ctxt;
/* Connect/Disconnect I/O Ports at base address */
- if(sim_map_resource(xptr->pnp.io_base, xptr->pnp.io_size, RESOURCE_TYPE_IO, routine, dptr->name, dptr->flags & DEV_DIS) != 0) {
+ if (sim_map_resource(xptr->pnp.io_base, xptr->pnp.io_size, RESOURCE_TYPE_IO, routine, dptr->name, dptr->flags & DEV_DIS) != 0) {
sim_debug(ERROR_MSG, dptr, "error mapping I/O resource at 0x%02x.\n", xptr->pnp.io_base);
return SCPE_ARG;
}
@@ -402,7 +402,7 @@ static t_stat m2sio_svc(UNIT *uptr)
int32 c,s,stb;
t_stat r;
- xptr = uptr->dptr->ctxt;
+ xptr = (M2SIO_CTX *) uptr->dptr->ctxt;
/* Check for new incoming connection */
if (uptr->flags & UNIT_ATT) {
@@ -500,7 +500,7 @@ static t_stat m2sio_attach(UNIT *uptr, CONST char *cptr)
M2SIO_CTX *xptr;
t_stat r;
- xptr = uptr->dptr->ctxt;
+ xptr = (M2SIO_CTX *) uptr->dptr->ctxt;
sim_debug(VERBOSE_MSG, uptr->dptr, "attach (%s).\n", cptr);
@@ -525,7 +525,7 @@ static t_stat m2sio_detach(UNIT *uptr)
sim_debug(VERBOSE_MSG, uptr->dptr, "detach.\n");
if (uptr->flags & UNIT_ATT) {
- xptr = uptr->dptr->ctxt;
+ xptr = (M2SIO_CTX *) uptr->dptr->ctxt;
sim_cancel(uptr);
@@ -541,7 +541,7 @@ static t_stat m2sio_set_baud(UNIT *uptr, int32 value, const char *cptr, void *de
int32 baud;
t_stat r = SCPE_ARG;
- xptr = uptr->dptr->ctxt;
+ xptr = (M2SIO_CTX *) uptr->dptr->ctxt;
if (!(uptr->flags & UNIT_ATT)) {
return SCPE_UNATT;
@@ -576,7 +576,7 @@ static t_stat m2sio_show_baud(FILE *st, UNIT *uptr, int32 value, const void *des
{
M2SIO_CTX *xptr;
- xptr = uptr->dptr->ctxt;
+ xptr = (M2SIO_CTX *) uptr->dptr->ctxt;
if (uptr->flags & UNIT_ATT) {
fprintf(st, "Baud rate: %d", xptr->baud);
@@ -589,10 +589,10 @@ static t_stat m2sio_config_line(UNIT *uptr)
{
M2SIO_CTX *xptr;
char config[20];
- char *fmt;
+ const char *fmt;
t_stat r = SCPE_IERR;
- xptr = uptr->dptr->ctxt;
+ xptr = (M2SIO_CTX *) uptr->dptr->ctxt;
if (xptr != NULL) {
switch (xptr->ctb & M2SIO_FMTMSK) {
@@ -687,7 +687,7 @@ static int32 m2sio_stat(DEVICE *dptr, int32 io, int32 data)
M2SIO_CTX *xptr;
int32 r,s;
- xptr = dptr->ctxt;
+ xptr = (M2SIO_CTX *) dptr->ctxt;
if (io == IO_RD) {
r = xptr->stb;
@@ -748,7 +748,7 @@ static int32 m2sio_data(DEVICE *dptr, int32 io, int32 data)
M2SIO_CTX *xptr;
int32 r;
- xptr = dptr->ctxt;
+ xptr = (M2SIO_CTX *) dptr->ctxt;
if (io == IO_RD) {
r = xptr->rxb;
diff --git a/AltairZ80/s100_hayes.c b/AltairZ80/s100_hayes.c
index cf378186..5467cf60 100644
--- a/AltairZ80/s100_hayes.c
+++ b/AltairZ80/s100_hayes.c
@@ -236,13 +236,9 @@ static const char* hayes_description(DEVICE *dptr)
static t_stat hayes_reset(DEVICE *dptr)
{
- HAYES_CTX *xptr;
-
- xptr = dptr->ctxt;
-
/* Connect/Disconnect I/O Ports at base address */
- if(sim_map_resource(xptr->pnp.io_base, xptr->pnp.io_size, RESOURCE_TYPE_IO, &hayes_io, dptr->name, dptr->flags & DEV_DIS) != 0) {
- sim_debug(ERROR_MSG, dptr, "error mapping I/O resource at 0x%02x.\n", xptr->pnp.io_base);
+ if (sim_map_resource(hayes_ctx.pnp.io_base, hayes_ctx.pnp.io_size, RESOURCE_TYPE_IO, &hayes_io, dptr->name, dptr->flags & DEV_DIS) != 0) {
+ sim_debug(ERROR_MSG, dptr, "error mapping I/O resource at 0x%02x.\n", hayes_ctx.pnp.io_base);
return SCPE_ARG;
}
@@ -250,19 +246,19 @@ static t_stat hayes_reset(DEVICE *dptr)
dptr->units[0].dptr = dptr;
/* Enable TMXR modem control passthru */
- tmxr_set_modem_control_passthru(xptr->tmxr);
+ tmxr_set_modem_control_passthru(hayes_ctx.tmxr);
/* Reset status registers */
- xptr->ireg0 = 0;
- xptr->ireg1 = HAYES_RI;
- xptr->oreg1 = HAYES_8BIT | HAYES_PI;
- xptr->oreg2 = 0;
- xptr->oreg3 = 0;
- xptr->txp = 0;
- xptr->dtr = 0;
- xptr->intmsk = 0;
- xptr->timer = 0;
- xptr->baud = HAYES_BAUD;
+ hayes_ctx.ireg0 = 0;
+ hayes_ctx.ireg1 = HAYES_RI;
+ hayes_ctx.oreg1 = HAYES_8BIT | HAYES_PI;
+ hayes_ctx.oreg2 = 0;
+ hayes_ctx.oreg3 = 0;
+ hayes_ctx.txp = 0;
+ hayes_ctx.dtr = 0;
+ hayes_ctx.intmsk = 0;
+ hayes_ctx.timer = 0;
+ hayes_ctx.baud = HAYES_BAUD;
if (!(dptr->flags & DEV_DIS)) {
sim_activate(&dptr->units[0], dptr->units[0].wait);
@@ -277,32 +273,29 @@ static t_stat hayes_reset(DEVICE *dptr)
static t_stat hayes_svc(UNIT *uptr)
{
- HAYES_CTX *xptr;
int32 c,s,ireg1;
t_stat r;
uint32 ms;
- xptr = uptr->dptr->ctxt;
-
/* Check for new incoming connection */
if (uptr->flags & UNIT_ATT) {
- if (tmxr_poll_conn(xptr->tmxr) >= 0) { /* poll connection */
+ if (tmxr_poll_conn(hayes_ctx.tmxr) >= 0) { /* poll connection */
sim_debug(STATUS_MSG, uptr->dptr, "new connection.\n");
}
}
/* Update incoming modem status bits */
if (uptr->flags & UNIT_ATT) {
- tmxr_set_get_modem_bits(xptr->tmln, 0, 0, &s);
+ tmxr_set_get_modem_bits(hayes_ctx.tmln, 0, 0, &s);
- ireg1 = xptr->ireg1;
+ ireg1 = hayes_ctx.ireg1;
- xptr->ireg1 &= ~HAYES_RI;
- xptr->ireg1 |= (s & TMXR_MDM_RNG) ? 0 : HAYES_RI; /* Active Low */
+ hayes_ctx.ireg1 &= ~HAYES_RI;
+ hayes_ctx.ireg1 |= (s & TMXR_MDM_RNG) ? 0 : HAYES_RI; /* Active Low */
/* RI status changed */
- if ((ireg1 ^ xptr->ireg1) & HAYES_RI) {
- sim_debug(STATUS_MSG, uptr->dptr, "RI state changed to %s.\n", (xptr->ireg1 & HAYES_RI) ? "LOW" : "HIGH");
+ if ((ireg1 ^ hayes_ctx.ireg1) & HAYES_RI) {
+ sim_debug(STATUS_MSG, uptr->dptr, "RI state changed to %s.\n", (hayes_ctx.ireg1 & HAYES_RI) ? "LOW" : "HIGH");
/*
** The Hayes does not have DTR or RTS control signals.
@@ -310,17 +303,17 @@ static t_stat hayes_svc(UNIT *uptr)
** is active and there is no way to tell TMXR to ignore
** them, so we raise DTR here on RI.
*/
- if (!(xptr->ireg1 & HAYES_RI)) { /* RI is active low */
+ if (!(hayes_ctx.ireg1 & HAYES_RI)) { /* RI is active low */
hayes_set_dtr(uptr, 1);
}
}
- xptr->ireg1 &= ~HAYES_CD;
- xptr->ireg1 |= (s & TMXR_MDM_DCD) ? HAYES_CD : 0; /* Active High */
+ hayes_ctx.ireg1 &= ~HAYES_CD;
+ hayes_ctx.ireg1 |= (s & TMXR_MDM_DCD) ? HAYES_CD : 0; /* Active High */
/* CD status changed */
- if ((ireg1 ^ xptr->ireg1) & HAYES_CD) {
- sim_debug(STATUS_MSG, uptr->dptr, "CD state changed to %s.\n", (xptr->ireg1 & HAYES_CD) ? "HIGH" : "LOW");
+ if ((ireg1 ^ hayes_ctx.ireg1) & HAYES_CD) {
+ sim_debug(STATUS_MSG, uptr->dptr, "CD state changed to %s.\n", (hayes_ctx.ireg1 & HAYES_CD) ? "HIGH" : "LOW");
/*
** The Hayes does not have DTR or RTS control signals.
@@ -328,21 +321,21 @@ static t_stat hayes_svc(UNIT *uptr)
** is active and there is no way to tell TMXR to
** ignore them, so we drop DTR here on loss of CD.
*/
- if (!(xptr->ireg1 & HAYES_CD)) {
+ if (!(hayes_ctx.ireg1 & HAYES_CD)) {
hayes_set_dtr(uptr, 0);
}
}
}
/* TX data */
- if (xptr->txp && xptr->oreg2 & HAYES_TXE) {
+ if (hayes_ctx.txp && hayes_ctx.oreg2 & HAYES_TXE) {
if (uptr->flags & UNIT_ATT) {
- r = tmxr_putc_ln(xptr->tmln, xptr->oreg0);
+ r = tmxr_putc_ln(hayes_ctx.tmln, hayes_ctx.oreg0);
} else {
- r = sim_putchar(xptr->oreg0);
+ r = sim_putchar(hayes_ctx.oreg0);
}
- xptr->txp = 0; /* Reset TX Pending */
+ hayes_ctx.txp = 0; /* Reset TX Pending */
if (r == SCPE_LOST) {
sim_debug(STATUS_MSG, uptr->dptr, "lost connection.\n");
@@ -350,41 +343,41 @@ static t_stat hayes_svc(UNIT *uptr)
}
/* Update TRE if not set and no character pending */
- if (!xptr->txp && !(xptr->ireg1 & HAYES_TRE)) {
+ if (!hayes_ctx.txp && !(hayes_ctx.ireg1 & HAYES_TRE)) {
if (uptr->flags & UNIT_ATT) {
- tmxr_poll_tx(xptr->tmxr);
- xptr->ireg1 |= (tmxr_txdone_ln(xptr->tmln)) ? HAYES_TRE : 0;
+ tmxr_poll_tx(hayes_ctx.tmxr);
+ hayes_ctx.ireg1 |= (tmxr_txdone_ln(hayes_ctx.tmln)) ? HAYES_TRE : 0;
} else {
- xptr->ireg1 |= HAYES_TRE;
+ hayes_ctx.ireg1 |= HAYES_TRE;
}
}
/* Check for Data if RX buffer empty */
- if (!(xptr->ireg1 & HAYES_RRF)) {
+ if (!(hayes_ctx.ireg1 & HAYES_RRF)) {
if (uptr->flags & UNIT_ATT) {
- tmxr_poll_rx(xptr->tmxr);
+ tmxr_poll_rx(hayes_ctx.tmxr);
- c = tmxr_getc_ln(xptr->tmln);
+ c = tmxr_getc_ln(hayes_ctx.tmln);
} else {
c = sim_poll_kbd();
}
if (c & (TMXR_VALID | SCPE_KFLAG)) {
- xptr->ireg0 = c & 0xff;
- xptr->ireg1 |= HAYES_RRF;
- xptr->ireg1 &= ~(HAYES_FE | HAYES_OE | HAYES_PE);
+ hayes_ctx.ireg0 = c & 0xff;
+ hayes_ctx.ireg1 |= HAYES_RRF;
+ hayes_ctx.ireg1 &= ~(HAYES_FE | HAYES_OE | HAYES_PE);
}
}
/* Timer */
ms = sim_os_msec();
- if (xptr->timer && ms > xptr->timer) {
- if (!(xptr->ireg1 & HAYES_TMR)) {
+ if (hayes_ctx.timer && ms > hayes_ctx.timer) {
+ if (!(hayes_ctx.ireg1 & HAYES_TMR)) {
sim_debug(VERBOSE_MSG, uptr->dptr, "50ms timer triggered.\n");
}
- xptr->ireg1 |= HAYES_TMR;
+ hayes_ctx.ireg1 |= HAYES_TMR;
}
/* Don't let TMXR clobber our wait time */
@@ -399,18 +392,15 @@ static t_stat hayes_svc(UNIT *uptr)
/* Attach routine */
static t_stat hayes_attach(UNIT *uptr, CONST char *cptr)
{
- HAYES_CTX *xptr;
t_stat r;
- xptr = uptr->dptr->ctxt;
-
sim_debug(VERBOSE_MSG, uptr->dptr, "attach (%s).\n", cptr);
- if ((r = tmxr_attach(xptr->tmxr, uptr, cptr)) == SCPE_OK) {
+ if ((r = tmxr_attach(hayes_ctx.tmxr, uptr, cptr)) == SCPE_OK) {
- xptr->flags = uptr->flags; /* Save Flags */
+ hayes_ctx.flags = uptr->flags; /* Save Flags */
- xptr->tmln->rcve = 1;
+ hayes_ctx.tmln->rcve = 1;
hayes_config_line(uptr);
@@ -419,8 +409,8 @@ static t_stat hayes_attach(UNIT *uptr, CONST char *cptr)
** We raise RTS here for use to provide DCD/RI signals.
** We drop DTR as that is tied to the other functions.
*/
- tmxr_set_get_modem_bits(xptr->tmln, TMXR_MDM_RTS, TMXR_MDM_DTR, NULL);
- xptr->dtr = 0;
+ tmxr_set_get_modem_bits(hayes_ctx.tmln, TMXR_MDM_RTS, TMXR_MDM_DTR, NULL);
+ hayes_ctx.dtr = 0;
sim_debug(STATUS_MSG, uptr->dptr, "Raising RTS. Dropping DTR.\n");
sim_activate(uptr, uptr->wait);
@@ -435,18 +425,14 @@ static t_stat hayes_attach(UNIT *uptr, CONST char *cptr)
/* Detach routine */
static t_stat hayes_detach(UNIT *uptr)
{
- HAYES_CTX *xptr;
-
sim_debug(VERBOSE_MSG, uptr->dptr, "detach.\n");
if (uptr->flags & UNIT_ATT) {
- xptr = uptr->dptr->ctxt;
-
- uptr->flags = xptr->flags; /* Restore Flags */
+ uptr->flags = hayes_ctx.flags; /* Restore Flags */
sim_cancel(uptr);
- return (tmxr_detach(xptr->tmxr, uptr));
+ return (tmxr_detach(hayes_ctx.tmxr, uptr));
}
return SCPE_UNATT;
@@ -454,112 +440,102 @@ static t_stat hayes_detach(UNIT *uptr)
static t_stat hayes_config_line(UNIT *uptr)
{
- HAYES_CTX *xptr;
char config[20];
char b,p,s;
t_stat r = SCPE_IERR;
- xptr = uptr->dptr->ctxt;
+ switch (hayes_ctx.oreg1 & HAYES_BMSK) {
+ case HAYES_5BIT:
+ b = '5';
+ break;
- if (xptr != NULL) {
- switch (xptr->oreg1 & HAYES_BMSK) {
- case HAYES_5BIT:
- b = '5';
- break;
+ case HAYES_6BIT:
+ b = '6';
+ break;
- case HAYES_6BIT:
- b = '6';
- break;
+ case HAYES_7BIT:
+ b = '7';
+ break;
- case HAYES_7BIT:
- b = '7';
- break;
-
- case HAYES_8BIT:
- default:
- b = '8';
- break;
- }
-
- switch (xptr->oreg1 & HAYES_PMSK) {
- case HAYES_OPAR:
- p = 'O';
- break;
-
- case HAYES_EPAR:
- p = 'E';
- break;
-
- default:
- p = 'N';
- break;
- }
-
- switch (xptr->oreg1 & HAYES_SMSK) {
- case HAYES_2SB:
- s = '2';
- break;
-
- case HAYES_1SB:
- default:
- s = '1';
- break;
- }
-
- sprintf(config, "%d-%c%c%c", xptr->baud, b,p,s);
-
- r = tmxr_set_config_line(xptr->tmln, config);
-
- if (r) {
- sim_debug(ERROR_MSG, uptr->dptr, "error %d setting port configuration to '%s'.\n", r, config);
- } else {
- sim_debug(STATUS_MSG, uptr->dptr, "port configuration set to '%s'.\n", config);
- }
-
- /*
- ** AltairZ80 and TMXR refuse to want to play together
- ** nicely when the CLOCK register is set to anything
- ** other than 0.
- **
- ** This work-around is for those of us that may wish
- ** to run irrelevant, old software, that use TMXR and
- ** rely on some semblance of timing (Remote CP/M, BYE,
- ** RBBS, PCGET/PUT, Xmodem, MEX, Modem7, or most
- ** other communications software), on contemprary
- ** hardware.
- **
- ** Serial ports are self-limiting and sockets will run
- ** at the clocked CPU speed.
- */
- xptr->tmln->txbps = 0; /* Get TMXR's rate-limiting out of our way */
- xptr->tmln->rxbps = 0; /* Get TMXR's rate-limiting out of our way */
+ case HAYES_8BIT:
+ default:
+ b = '8';
+ break;
}
+ switch (hayes_ctx.oreg1 & HAYES_PMSK) {
+ case HAYES_OPAR:
+ p = 'O';
+ break;
+
+ case HAYES_EPAR:
+ p = 'E';
+ break;
+
+ default:
+ p = 'N';
+ break;
+ }
+
+ switch (hayes_ctx.oreg1 & HAYES_SMSK) {
+ case HAYES_2SB:
+ s = '2';
+ break;
+
+ case HAYES_1SB:
+ default:
+ s = '1';
+ break;
+ }
+
+ sprintf(config, "%d-%c%c%c", hayes_ctx.baud, b,p,s);
+
+ r = tmxr_set_config_line(hayes_ctx.tmln, config);
+
+ if (r) {
+ sim_debug(ERROR_MSG, uptr->dptr, "error %d setting port configuration to '%s'.\n", r, config);
+ } else {
+ sim_debug(STATUS_MSG, uptr->dptr, "port configuration set to '%s'.\n", config);
+ }
+
+ /*
+ ** AltairZ80 and TMXR refuse to want to play together
+ ** nicely when the CLOCK register is set to anything
+ ** other than 0.
+ **
+ ** This work-around is for those of us that may wish
+ ** to run irrelevant, old software, that use TMXR and
+ ** rely on some semblance of timing (Remote CP/M, BYE,
+ ** RBBS, PCGET/PUT, Xmodem, MEX, Modem7, or most
+ ** other communications software), on contemprary
+ ** hardware.
+ **
+ ** Serial ports are self-limiting and sockets will run
+ ** at the clocked CPU speed.
+ */
+ hayes_ctx.tmln->txbps = 0; /* Get TMXR's rate-limiting out of our way */
+ hayes_ctx.tmln->rxbps = 0; /* Get TMXR's rate-limiting out of our way */
+
return r;
}
static t_stat hayes_set_dtr(UNIT *uptr, int32 flag)
{
- HAYES_CTX *xptr;
t_stat r = SCPE_IERR;
- xptr = uptr->dptr->ctxt;
-
- if (xptr != NULL) {
- if (xptr->dtr && !flag) {
- r = tmxr_set_get_modem_bits(xptr->tmln, 0, TMXR_MDM_DTR, NULL);
- sim_debug(STATUS_MSG, uptr->dptr, "Dropping DTR.\n");
- } else if (!xptr->dtr && flag) {
- r = tmxr_set_get_modem_bits(xptr->tmln, TMXR_MDM_DTR, 0, NULL);
- sim_debug(STATUS_MSG, uptr->dptr, "Raising DTR.\n");
- }
-
- xptr->dtr = flag;
+ if (hayes_ctx.dtr && !flag) {
+ r = tmxr_set_get_modem_bits(hayes_ctx.tmln, 0, TMXR_MDM_DTR, NULL);
+ sim_debug(STATUS_MSG, uptr->dptr, "Dropping DTR.\n");
+ } else if (!hayes_ctx.dtr && flag) {
+ r = tmxr_set_get_modem_bits(hayes_ctx.tmln, TMXR_MDM_DTR, 0, NULL);
+ sim_debug(STATUS_MSG, uptr->dptr, "Raising DTR.\n");
}
+ hayes_ctx.dtr = flag;
return r;
}
+
static int32 hayes_io(int32 addr, int32 io, int32 data)
{
int32 r;
@@ -602,18 +578,15 @@ static int32 hayes_io(int32 addr, int32 io, int32 data)
*/
static int32 hayes_reg0(int32 io, int32 data)
{
- HAYES_CTX *xptr;
int32 r;
- xptr = hayes_dev.ctxt;
-
if (io == IO_RD) {
- r = xptr->ireg0;
- xptr->ireg1 &= ~(HAYES_RRF);
+ r = hayes_ctx.ireg0;
+ hayes_ctx.ireg1 &= ~(HAYES_RRF);
} else {
- xptr->oreg0 = data;
- xptr->ireg1 &= ~(HAYES_TRE);
- xptr->txp = 1;
+ hayes_ctx.oreg0 = data;
+ hayes_ctx.ireg1 &= ~(HAYES_TRE);
+ hayes_ctx.txp = 1;
r = 0x00;
}
@@ -629,16 +602,13 @@ static int32 hayes_reg0(int32 io, int32 data)
*/
static int32 hayes_reg1(int32 io, int32 data)
{
- HAYES_CTX *xptr;
int32 r;
- xptr = hayes_dev.ctxt;
-
if (io == IO_RD) {
- r = xptr->ireg1;
- xptr->ireg1 &= ~(HAYES_FE | HAYES_OE | HAYES_PE);
+ r = hayes_ctx.ireg1;
+ hayes_ctx.ireg1 &= ~(HAYES_FE | HAYES_OE | HAYES_PE);
} else {
- xptr->oreg1 = data; /* Set UART configuration */
+ hayes_ctx.oreg1 = data; /* Set UART configuration */
hayes_config_line(&hayes_dev.units[0]);
@@ -656,14 +626,11 @@ static int32 hayes_reg1(int32 io, int32 data)
*/
static int32 hayes_reg2(int32 io, int32 data)
{
- HAYES_CTX *xptr;
int32 oreg2;
- xptr = hayes_dev.ctxt;
-
if (io == IO_WR) {
- oreg2 = xptr->oreg2; /* Save previous value */
- xptr->oreg2 = data; /* Set new value */
+ oreg2 = hayes_ctx.oreg2; /* Save previous value */
+ hayes_ctx.oreg2 = data; /* Set new value */
sim_debug(DEBUG_MSG, &hayes_dev, "oreg2 %02X -> %02X\n", oreg2, data);
@@ -685,7 +652,7 @@ static int32 hayes_reg2(int32 io, int32 data)
/* Did the line configuration change? */
if ((oreg2 & HAYES_LMSK) != (data & HAYES_LMSK)) {
- xptr->baud = (data & HAYES_BRS) ? 300 : 110;
+ hayes_ctx.baud = (data & HAYES_BRS) ? 300 : 110;
hayes_config_line(&hayes_dev.units[0]);
}
@@ -702,13 +669,9 @@ static int32 hayes_reg2(int32 io, int32 data)
*/
static int32 hayes_reg3(int32 io, int32 data)
{
- HAYES_CTX *xptr;
-
- xptr = hayes_dev.ctxt;
-
if (io == IO_WR) {
- xptr->timer = sim_os_msec() + 50; /* Set timeout to 50ms */
- xptr->ireg1 &= ~(HAYES_TMR); /* Clear timer status */
+ hayes_ctx.timer = sim_os_msec() + 50; /* Set timeout to 50ms */
+ hayes_ctx.ireg1 &= ~(HAYES_TMR); /* Clear timer status */
}
return(0x00);
diff --git a/AltairZ80/s100_icom.c b/AltairZ80/s100_icom.c
new file mode 100644
index 00000000..fbfe863e
--- /dev/null
+++ b/AltairZ80/s100_icom.c
@@ -0,0 +1,1462 @@
+/* s100_icom.c: iCOM FD3712/FD3812 Flexible Disk System
+
+ Created by Patrick Linstruth (patrick@deltecent.com)
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ PETER SCHORN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of Patrick Linstruth shall not
+ be used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from Patrick Linstruth.
+*/
+
+/*
+ These functions support simulated iCOM FD3712 and FD3812
+ floppy disk systems. The FD3712 supports IBM Diskette type 1
+ single-density and the FD3812 also supports IBM Diskette
+ type 2D double-density.
+
+ The interface board provides 2 I/O ports:
+
+ Command Register Port C0 Output
+ Data In Register Port C0 Input
+ Data Out Register Port C1 Output
+
+ +---------------------------------------------------------+
+ | |
+ | COMMAND SET |
+ | |
+ +---------------------------------------------------------+
+ | COMMAND | 7 6 5 4 3 2 1 0 | BUSY | HEX CODE |
+ +---------------------------------------------------------+
+ | EXAMINE STATUS | 0 0 0 0 0 0 0 0 | No | 00 |
+ | READ | 0 0 0 0 0 0 1 1 | Yes | 03 |
+ | WRITE | 0 0 0 0 0 1 0 1 | Yes | 05 |
+ | READ CRC | 0 0 0 0 0 1 1 1 | Yes | 07 |
+ | SEEK | 0 0 0 0 1 0 0 1 | Yes | 09 |
+ | CLEAR ERROR FLAGS | 0 0 0 0 1 0 1 1 | No | 0B |
+ | SEEK TRACK ZERO | 0 0 0 0 1 1 0 1 | Yes | 0D |
+ | WRITE DEL DATA MARK | 0 0 0 0 1 1 1 1 | Yes | 0F |
+ | LOAD TRACK ADDRESS | 0 0 0 1 0 0 0 1 | No | 11 |
+ | LOAD UNIT/SECTOR | 0 0 1 0 0 0 0 1 | No | 21 |
+ | LOAD WRITE BUFFER | 0 0 1 1 0 0 0 1 | No | 31 |
+ | EXAMINE READ BUFFER | 0 1 0 0 0 0 0 0 | No | 40 |
+ | SHIFT READ BUFFER | 0 1 0 0 0 0 0 1 | No | 41 |
+ | CLEAR CONTROLLER | 1 0 0 0 0 0 0 1 | No | 81 |
+ | LOAD CONFIGURATION* | 0 0 0 1 1 0 0 1 | No | 15 |
+ +---------------------------------------------------------+
+ | * FD3812 Only |
+ +---------------------------------------------------------+
+
+ +---------------------------------------------------------------+
+ | |
+ | DISK STATUS BITS |
+ | |
+ +---------------------------------------------------------------+
+ | BIT | STATUS SIGNAL | DESCRIPTION |
+ +---------------------------------------------------------------+
+ | 7 | DELETED DATA MARK | The simulator does not implement |
+ | | | this bit. |
+ +---------------------------------------------------------------+
+ | 6 | MEDIA STATUS | This bit is always set. |
+ +---------------------------------------------------------------+
+ | 5 | DRIVE FAIL | This bit is set if any if a drive |
+ | | | is not attached using the |
+ | | | "ATTACH" command or there is a |
+ | | | problem reading from or writing |
+ | | | to the attached file. |
+ +---------------------------------------------------------------+
+ | 4 | WRITE PROTECT | This bit is set if the selected |
+ | | | drive contains a write protected |
+ | | | diskette. This condition should |
+ | | | not be tested if the selected |
+ | | | drive has a "DRIVE FAIL" status. |
+ | | | Use "SET ICOM WRTPROT" to write |
+ | | | protect an attached diskette and |
+ | | | "SET ICOM WRTENB" to enable |
+ | | | writing. |
+ +---------------------------------------------------------------+
+ | 3 | CRC ERROR | This bit is set when an error has |
+ | | | occurred during the previous |
+ | | | command. This bit must be tested |
+ | | | after all read, write, and seek |
+ | | | operations. The simulator does |
+ | | | not implement this bit. |
+ +---------------------------------------------------------------+
+ | 2 | UNIT SELECT MSB | Bits 2 and 1 contain the address |
+ +---------------------------| of the drive currently being |
+ | 1 | UNIT SELECT LSB | selected by the controller. |
+ +---------------------------------------------------------------+
+ | 0 | BUSY | This bit is set when a read, |
+ | | | write, seek command is sent to |
+ | | | the controller. |
+ +---------------------------------------------------------------+
+
+ B = Memory Size - 16K
+
+ 32K: B = 32K - 16K = 16K = 04000H
+ 48K: B = 48K = 16K = 32K = 08000H
+ 62K: B = 62K = 16K = 46K = 0B800H
+ 64K: B = 64K = 16K = 48K = 0C000H
+
+ +----------------------------------------------------------------------+
+ | |
+ | CP/M 1.41 Single Density Disk Layout |
+ | |
+ +----------------------------------------------------------------------+
+ | Track | Sector | Image Offset | Memory Address | Module |
+ +----------------------------------------------------------------------+
+ | 00 | 01 | 0000-007FH | 0080H | SD Disk Boot Loader |
+ +----------------------------------------------------------------------+
+ | 00 | 02-17 | 0080-087FH | 2900H+B | CCP |
+ +----------------------------------------------------------------------+
+ | 00 | 18-26 | 0880-0CFFH | 3100H+B | BDOS |
+ | 01 | 01-17 | 0D00-157FH | 3580H+B | BDOS |
+ +----------------------------------------------------------------------+
+ | 01 | 18-21 | 1580-177FH | 3E00H+B | BIOS |
+ +----------------------------------------------------------------------+
+ | 01 | 22-26 | | Not Used |
+ +----------------------------------------------------------------------+
+
+ +----------------------------------------------------------------------+
+ | |
+ | CP/M 1.41 Double Density Disk Layout |
+ | |
+ +----------------------------------------------------------------------+
+ | Track | Sector | Image Offset | Memory Address | Module |
+ +----------------------------------------------------------------------+
+ | 00 | 01 | 0000-007FH | 0080H | DD Disk Boot Loader |
+ +----------------------------------------------------------------------+
+ | 00 | 02-26 | | | Not Used |
+ +----------------------------------------------------------------------+
+ | 01 | 01-09 | 0D00-14FFH | 2900H+B | CCP |
+ +----------------------------------------------------------------------+
+ | 01 | 10-21 | 1500-21FFH | 3100H+B | BDOS |
+ +----------------------------------------------------------------------+
+ | 01 | 22-23 | 2200-23FFH | 3E00H+B | BIOS |
+ +----------------------------------------------------------------------+
+ | 01 | 24-26 | | | Not Used |
+ +----------------------------------------------------------------------+
+
+*/
+
+/* #define DBG_MSG */
+
+#include "altairz80_defs.h"
+#include "sim_imd.h"
+
+#ifdef DBG_MSG
+#define DBG_PRINT(args) sim_printf args
+#else
+#define DBG_PRINT(args)
+#endif
+
+extern uint32 PCX;
+extern t_stat set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+extern t_stat set_iobase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
+ int32 (*routine)(const int32, const int32, const int32), const char* name, uint8 unmap);
+extern DEVICE *find_dev (const char *cptr);
+extern uint32 getClockFrequency(void);
+
+#define ICOM_MAX_DRIVES 4
+#define ICOM_SD_SECTOR_LEN 128
+#define ICOM_DD_SECTOR_LEN 256
+#define ICOM_SPT 26
+#define ICOM_TRACKS 77
+#define ICOM_SD_CAPACITY (256256) /* Default iCOM Single Density Disk Capacity */
+#define ICOM_DD_CAPACITY (509184) /* Default iCOM Double Density Disk Capacity */
+
+#define ICOM_IO_BASE 0xc0
+#define ICOM_IO_SIZE 2
+
+#define ICOM_PROM_BASE 0xf000
+#define ICOM_PROM_SIZE 1024
+#define ICOM_PROM_MASK (ICOM_PROM_SIZE-1)
+#define ICOM_MEM_BASE 0xf400
+#define ICOM_MEM_SIZE 256 /* Must be on a page boundary */
+#define ICOM_MEM_MASK (ICOM_MEM_SIZE-1)
+
+static uint8 icom_mem[ICOM_MEM_SIZE];
+
+/* iCOM PROMs are 1024 bytes */
+
+static uint8 icom_3712_prom[ICOM_PROM_SIZE] = {
+ 0xc3, 0x73, 0xf0, 0x20, 0x41, 0x4c, 0x54, 0x41,
+ 0x49, 0x52, 0x43, 0x20, 0xc3, 0x85, 0xf0, 0x15,
+ 0xc3, 0xa6, 0xf0, 0xc3, 0xc7, 0xf0, 0xc3, 0x06,
+ 0xf4, 0xc3, 0x09, 0xf4, 0xc3, 0x0c, 0xf4, 0xc3,
+ 0x0f, 0xf4, 0xc3, 0x12, 0xf4, 0xc3, 0x15, 0xf4,
+ 0xc3, 0x6b, 0xf1, 0xc3, 0x73, 0xf1, 0xc3, 0x6e,
+ 0xf1, 0xc3, 0x7d, 0xf1, 0xc3, 0x82, 0xf1, 0xc3,
+ 0x88, 0xf1, 0xc3, 0xc5, 0xf1, 0xc9, 0x00, 0x00,
+ 0xc3, 0x64, 0xf1, 0xc3, 0x5a, 0xf2, 0x20, 0x33,
+ 0x37, 0x31, 0x32, 0x2d, 0x56, 0x32, 0x31, 0x20,
+ 0x28, 0x43, 0x29, 0x20, 0x4c, 0x49, 0x46, 0x45,
+ 0x42, 0x4f, 0x41, 0x54, 0x20, 0x41, 0x53, 0x53,
+ 0x4f, 0x43, 0x49, 0x41, 0x54, 0x45, 0x53, 0x20,
+ 0x31, 0x39, 0x37, 0x39, 0x20, 0x21, 0xe0, 0xf3,
+ 0xc3, 0x7f, 0xf0, 0x21, 0xf0, 0xf3, 0xc3, 0x7f,
+ 0xf0, 0x21, 0x68, 0xf3, 0xc3, 0x7f, 0xf0, 0x31,
+ 0x80, 0x00, 0xcd, 0x8f, 0xf2, 0x31, 0x80, 0x00,
+ 0xcd, 0x5a, 0xf2, 0x0e, 0x00, 0xcd, 0x6e, 0xf1,
+ 0x01, 0x80, 0x00, 0xcd, 0x82, 0xf1, 0xcd, 0x88,
+ 0xf1, 0xc2, 0x88, 0xf0, 0x21, 0x00, 0xf4, 0xeb,
+ 0x21, 0x10, 0xf0, 0xc3, 0x80, 0x00, 0x22, 0x40,
+ 0xf4, 0x11, 0xf0, 0xff, 0x19, 0x11, 0x20, 0xf4,
+ 0x06, 0x10, 0xcd, 0x86, 0xf2, 0x11, 0x80, 0xff,
+ 0x19, 0xaf, 0x32, 0x48, 0xf4, 0xcd, 0x4f, 0xf1,
+ 0xaf, 0x32, 0x04, 0x00, 0xc3, 0x28, 0xf1, 0x31,
+ 0x00, 0x01, 0xcd, 0x5a, 0xf2, 0x0e, 0x00, 0xcd,
+ 0x6e, 0xf1, 0x2a, 0x40, 0xf4, 0x11, 0x00, 0xeb,
+ 0x19, 0x24, 0x3e, 0x04, 0xcd, 0xf7, 0xf0, 0x0e,
+ 0x01, 0xcd, 0x6e, 0xf1, 0x2a, 0x40, 0xf4, 0x11,
+ 0x00, 0xeb, 0x19, 0x11, 0x80, 0x0c, 0x19, 0x3e,
+ 0x01, 0xcd, 0xf7, 0xf0, 0xc3, 0x28, 0xf1, 0x32,
+ 0x32, 0xf4, 0x22, 0x33, 0xf4, 0x3a, 0x41, 0xf4,
+ 0x3d, 0xbc, 0xda, 0x0b, 0xf1, 0xcd, 0x88, 0xf1,
+ 0xc2, 0xc7, 0xf0, 0x2a, 0x33, 0xf4, 0x11, 0x80,
+ 0x01, 0x19, 0x3a, 0x32, 0xf4, 0xc6, 0x03, 0xfe,
+ 0x1b, 0xda, 0xf7, 0xf0, 0xd6, 0x1a, 0x11, 0x00,
+ 0xf3, 0x19, 0xfe, 0x01, 0xc2, 0xf7, 0xf0, 0xc9,
+ 0x01, 0x80, 0x00, 0xcd, 0x82, 0xf1, 0x3e, 0xc3,
+ 0x32, 0x00, 0x00, 0x32, 0x05, 0x00, 0x2a, 0x40,
+ 0xf4, 0x23, 0x23, 0x23, 0x22, 0x01, 0x00, 0x11,
+ 0x03, 0xf3, 0x19, 0x22, 0x06, 0x00, 0x3a, 0x04,
+ 0x00, 0x4f, 0x11, 0xfa, 0xf7, 0x19, 0xe9, 0x7e,
+ 0xb7, 0xc8, 0x4e, 0x23, 0xe5, 0xcd, 0x5c, 0xf1,
+ 0xe1, 0xc3, 0x4f, 0xf1, 0x2a, 0x40, 0xf4, 0x11,
+ 0x0c, 0x00, 0x19, 0xe9, 0x21, 0x00, 0xf4, 0x06,
+ 0x00, 0x09, 0xc9, 0xc3, 0x67, 0xf2, 0x79, 0x32,
+ 0x31, 0xf4, 0xc9, 0x79, 0x32, 0x30, 0xf4, 0x3e,
+ 0xff, 0x32, 0x27, 0xf4, 0xc9, 0x79, 0x32, 0x32,
+ 0xf4, 0xc9, 0x60, 0x69, 0x22, 0x33, 0xf4, 0xc9,
+ 0xcd, 0x0a, 0xf2, 0xc2, 0x06, 0xf2, 0x0e, 0x0a,
+ 0x3e, 0x03, 0xcd, 0x71, 0xf2, 0xe6, 0x28, 0xca,
+ 0xa4, 0xf1, 0xcd, 0x7e, 0xf2, 0x0d, 0xc2, 0x90,
+ 0xf1, 0xc3, 0x06, 0xf2, 0x2a, 0x33, 0xf4, 0x0e,
+ 0x80, 0x3e, 0x40, 0xd3, 0xc0, 0xdb, 0xc0, 0x77,
+ 0x23, 0xaf, 0xd3, 0xc0, 0x0d, 0x3e, 0x41, 0xd3,
+ 0xc0, 0xdb, 0xc0, 0x77, 0x23, 0xaf, 0xd3, 0xc0,
+ 0x0d, 0xc2, 0xb5, 0xf1, 0xc9, 0xcd, 0x0a, 0xf2,
+ 0xc2, 0x06, 0xf2, 0x2a, 0x33, 0xf4, 0x0e, 0x80,
+ 0x7e, 0xd3, 0xc1, 0x3e, 0x31, 0xd3, 0xc0, 0xaf,
+ 0xd3, 0xc0, 0x23, 0x0d, 0xc2, 0xd0, 0xf1, 0x0e,
+ 0x0a, 0x3e, 0x05, 0xcd, 0x71, 0xf2, 0xe6, 0x20,
+ 0xca, 0xf1, 0xf1, 0xcd, 0x7e, 0xf2, 0xc3, 0x06,
+ 0xf2, 0x3a, 0x2f, 0xf4, 0xe6, 0x40, 0xc8, 0x3e,
+ 0x07, 0xcd, 0x71, 0xf2, 0xe6, 0x28, 0xc8, 0xcd,
+ 0x7e, 0xf2, 0x0d, 0xc2, 0xe1, 0xf1, 0x3e, 0x01,
+ 0xb7, 0xc9, 0xaf, 0xd3, 0xc1, 0x3e, 0x15, 0xcd,
+ 0x80, 0xf2, 0xcd, 0x19, 0xf2, 0xcd, 0x2d, 0xf2,
+ 0xc9, 0x3a, 0x30, 0xf4, 0xe6, 0x03, 0x0f, 0x0f,
+ 0x4f, 0x3a, 0x32, 0xf4, 0xb1, 0xd3, 0xc1, 0x3e,
+ 0x21, 0xcd, 0x80, 0xf2, 0xc9, 0x0e, 0x02, 0x3a,
+ 0x31, 0xf4, 0x21, 0x27, 0xf4, 0xbe, 0xc8, 0x77,
+ 0x3a, 0x31, 0xf4, 0xd3, 0xc1, 0x3e, 0x11, 0xcd,
+ 0x80, 0xf2, 0x3e, 0x09, 0xcd, 0x71, 0xf2, 0xe6,
+ 0x28, 0xc8, 0xcd, 0x7e, 0xf2, 0x36, 0xff, 0x0d,
+ 0xc2, 0x2d, 0xf2, 0xcd, 0x62, 0xf2, 0x3e, 0x02,
+ 0xb7, 0xc9, 0xaf, 0x32, 0x30, 0xf4, 0x3c, 0x32,
+ 0x32, 0xf4, 0x3e, 0x81, 0xcd, 0x80, 0xf2, 0xcd,
+ 0x19, 0xf2, 0x3e, 0xff, 0x32, 0x27, 0xf4, 0x3e,
+ 0x0d, 0xcd, 0x80, 0xf2, 0xdb, 0xc0, 0xe6, 0x01,
+ 0xc2, 0x74, 0xf2, 0xdb, 0xc0, 0xc9, 0x3e, 0x0b,
+ 0xd3, 0xc0, 0xaf, 0xd3, 0xc0, 0xc9, 0x7e, 0x12,
+ 0x23, 0x13, 0x05, 0xc2, 0x86, 0xf2, 0xc9, 0x11,
+ 0x00, 0xf4, 0x06, 0x08, 0x3e, 0xc3, 0x12, 0x13,
+ 0x7e, 0x12, 0x23, 0x13, 0x7e, 0x12, 0x23, 0x13,
+ 0x05, 0xc2, 0x94, 0xf2, 0xc9, 0x3e, 0x03, 0xd3,
+ 0x10, 0x3e, 0x11, 0xd3, 0x10, 0xc9, 0xdb, 0x10,
+ 0xe6, 0x01, 0x3e, 0x00, 0xc8, 0x2f, 0xc9, 0xdb,
+ 0x10, 0xe6, 0x01, 0xca, 0xb7, 0xf2, 0xdb, 0x11,
+ 0xe6, 0x7f, 0xca, 0xb7, 0xf2, 0xc9, 0xdb, 0x10,
+ 0xe6, 0x02, 0xca, 0xc6, 0xf2, 0x79, 0xd3, 0x11,
+ 0xc9, 0xc9, 0xc9, 0xdb, 0x00, 0xe6, 0x01, 0x3e,
+ 0x00, 0xc0, 0x2f, 0xc9, 0xdb, 0x00, 0xe6, 0x01,
+ 0xc2, 0xdc, 0xf2, 0xdb, 0x01, 0xe6, 0x7f, 0xca,
+ 0xdc, 0xf2, 0xc9, 0xdb, 0x00, 0xe6, 0x80, 0xc2,
+ 0xeb, 0xf2, 0x79, 0xd3, 0x01, 0xc9, 0x3a, 0x48,
+ 0xf4, 0xb7, 0xc2, 0x0c, 0xf3, 0x3e, 0x11, 0xd3,
+ 0x03, 0xaf, 0xd3, 0x02, 0x32, 0x47, 0xf4, 0x3e,
+ 0x84, 0x32, 0x48, 0xf4, 0x79, 0xfe, 0x0a, 0xc2,
+ 0x1a, 0xf3, 0x32, 0x49, 0xf4, 0x3a, 0x47, 0xf4,
+ 0xb7, 0xc8, 0x79, 0xfe, 0x08, 0xca, 0x4f, 0xf3,
+ 0xfe, 0x09, 0xca, 0x5a, 0xf3, 0xfe, 0x0d, 0xca,
+ 0x38, 0xf3, 0xd8, 0x3a, 0x47, 0xf4, 0x3c, 0xe5,
+ 0x21, 0x48, 0xf4, 0xbe, 0xe1, 0xc2, 0x48, 0xf3,
+ 0x3a, 0x47, 0xf4, 0xb7, 0xc2, 0x47, 0xf3, 0x3a,
+ 0x49, 0xf4, 0xfe, 0x0d, 0xc8, 0x0e, 0x0a, 0xaf,
+ 0x32, 0x47, 0xf4, 0x79, 0x32, 0x49, 0xf4, 0xdb,
+ 0x02, 0xe6, 0x11, 0xca, 0x4f, 0xf3, 0x79, 0xd3,
+ 0x03, 0xc9, 0x0e, 0x20, 0xcd, 0x0c, 0xf3, 0x3a,
+ 0x47, 0xf4, 0xe6, 0x07, 0xc2, 0x5a, 0xf3, 0xc9,
+ 0xa8, 0xf3, 0xd2, 0xf2, 0xa1, 0xf3, 0x78, 0xf3,
+ 0x8e, 0xf3, 0xf6, 0xf2, 0x8e, 0xf3, 0x78, 0xf3,
+ 0xcd, 0x84, 0xf3, 0xca, 0x78, 0xf3, 0x7e, 0xe6,
+ 0x7f, 0x36, 0x00, 0xc9, 0x21, 0x4b, 0xf4, 0x7e,
+ 0xb7, 0xcc, 0x1f, 0xc0, 0x77, 0xc9, 0x3a, 0x4a,
+ 0xf4, 0xfe, 0x0d, 0xc2, 0x98, 0xf3, 0xb9, 0xc8,
+ 0x79, 0x32, 0x4a, 0xf4, 0x41, 0xcd, 0x19, 0xc0,
+ 0xc9, 0xcd, 0x84, 0xf3, 0xc8, 0x3e, 0xff, 0xc9,
+ 0x21, 0x00, 0x00, 0x22, 0x4a, 0xf4, 0xc9, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xd1, 0xf2, 0xd2, 0xf2, 0xd3, 0xf2, 0xdc, 0xf2,
+ 0xeb, 0xf2, 0xf6, 0xf2, 0xeb, 0xf2, 0xdc, 0xf2,
+ 0xa5, 0xf2, 0xd2, 0xf2, 0xae, 0xf2, 0xb7, 0xf2,
+ 0xc6, 0xf2, 0xf6, 0xf2, 0xc6, 0xf2, 0xb7, 0xf2,
+};
+
+static uint8 icom_3812_prom[ICOM_PROM_SIZE] = {
+ 0xc3, 0x46, 0xf0, 0x06, 0x80, 0x7e, 0x12, 0x23,
+ 0x13, 0x05, 0xc2, 0x05, 0xf0, 0xc9, 0xff, 0x3a,
+ 0xc3, 0x6d, 0xf0, 0xc3, 0x8a, 0xf0, 0x79, 0x32,
+ 0x31, 0xf4, 0xc9, 0x79, 0x32, 0x32, 0xf4, 0xc9,
+ 0x60, 0x69, 0x22, 0x33, 0xf4, 0xc9, 0xff, 0xff,
+ 0xc3, 0x08, 0xf1, 0xc3, 0x14, 0xf1, 0xc3, 0x16,
+ 0xf0, 0xc3, 0x1b, 0xf0, 0xc3, 0x20, 0xf0, 0xc3,
+ 0x30, 0xf1, 0xc3, 0x7b, 0xf1, 0xc3, 0x21, 0xf1,
+ 0xc3, 0x61, 0xf3, 0xc3, 0xa4, 0xf3, 0x31, 0x80,
+ 0x00, 0xcd, 0xa4, 0xf3, 0x21, 0x00, 0x00, 0x22,
+ 0x30, 0xf4, 0x0e, 0x01, 0xcd, 0x1b, 0xf0, 0x21,
+ 0x80, 0x00, 0x22, 0x33, 0xf4, 0xcd, 0x30, 0xf1,
+ 0xc2, 0x46, 0xf0, 0x21, 0x00, 0xf4, 0xeb, 0x21,
+ 0x10, 0xf0, 0xc3, 0x80, 0x00, 0x22, 0x40, 0xf4,
+ 0x11, 0xf0, 0xff, 0x19, 0x11, 0x20, 0xf4, 0x06,
+ 0x10, 0xcd, 0x05, 0xf0, 0x11, 0x80, 0xff, 0x19,
+ 0xcd, 0xdf, 0xf3, 0xaf, 0x32, 0x04, 0x00, 0xc3,
+ 0xe1, 0xf0, 0x31, 0x00, 0x01, 0xcd, 0xa4, 0xf3,
+ 0x21, 0x00, 0x01, 0x22, 0x30, 0xf4, 0x2a, 0x40,
+ 0xf4, 0x11, 0x00, 0xeb, 0x19, 0x3e, 0x01, 0x4f,
+ 0xc5, 0x32, 0x32, 0xf4, 0x22, 0x33, 0xf4, 0x7c,
+ 0x2a, 0x40, 0xf4, 0xbc, 0xd2, 0xb5, 0xf0, 0xcd,
+ 0x30, 0xf1, 0xc2, 0x8a, 0xf0, 0xc1, 0x79, 0x0f,
+ 0x79, 0x2a, 0x33, 0xf4, 0xda, 0xc3, 0xf0, 0xc6,
+ 0x04, 0x24, 0x24, 0x3c, 0x11, 0x80, 0x00, 0x19,
+ 0xfe, 0x35, 0xda, 0xdc, 0xf0, 0xd6, 0x34, 0xfe,
+ 0x03, 0x2a, 0x40, 0xf4, 0x11, 0x00, 0xec, 0x19,
+ 0xca, 0xdc, 0xf0, 0x24, 0xfe, 0x01, 0xc2, 0x9f,
+ 0xf0, 0x01, 0x80, 0x00, 0xcd, 0x20, 0xf0, 0x3e,
+ 0xc3, 0x32, 0x00, 0x00, 0x32, 0x05, 0x00, 0x2a,
+ 0x40, 0xf4, 0x23, 0x23, 0x23, 0x22, 0x01, 0x00,
+ 0x11, 0x03, 0xf3, 0x19, 0x22, 0x06, 0x00, 0x3a,
+ 0x04, 0x00, 0x4f, 0x11, 0xfa, 0xf7, 0x19, 0xe9,
+ 0xcd, 0x21, 0xf1, 0x3a, 0x30, 0xf4, 0x32, 0x3d,
+ 0xf4, 0xc3, 0xb6, 0xf3, 0x79, 0x32, 0x30, 0xf4,
+ 0xcd, 0x21, 0xf1, 0x3e, 0xff, 0x32, 0x27, 0xf4,
+ 0xc9, 0x3a, 0x39, 0xf4, 0x3c, 0xc8, 0xcd, 0x6f,
+ 0xf2, 0xc5, 0xcd, 0xf2, 0xf1, 0xc1, 0xc9, 0x11,
+ 0xcd, 0x6f, 0xf2, 0xcd, 0x57, 0xf3, 0xca, 0x5a,
+ 0xf1, 0x21, 0x30, 0xf4, 0x11, 0x39, 0xf4, 0xcd,
+ 0x2b, 0xf2, 0xc2, 0x4e, 0xf1, 0x1a, 0xbe, 0xc2,
+ 0x4e, 0xf1, 0xcd, 0xf2, 0xf1, 0xc0, 0x21, 0x30,
+ 0xf4, 0x11, 0x35, 0xf4, 0xcd, 0x2b, 0xf2, 0xca,
+ 0x64, 0xf1, 0x21, 0x30, 0xf4, 0xcd, 0x22, 0xf2,
+ 0xcd, 0x46, 0xf2, 0xc0, 0xcd, 0x57, 0xf3, 0xca,
+ 0x71, 0xf1, 0x3a, 0x32, 0xf4, 0x3c, 0x0f, 0xe6,
+ 0x80, 0x2a, 0x33, 0xf4, 0xeb, 0xcd, 0x9d, 0xf2,
+ 0xc8, 0xc3, 0x11, 0xcd, 0x6f, 0xf2, 0xcd, 0x57,
+ 0xf3, 0x2a, 0x33, 0xf4, 0xca, 0xb0, 0xf1, 0x21,
+ 0x30, 0xf4, 0x11, 0x39, 0xf4, 0xcd, 0x2b, 0xf2,
+ 0xc2, 0xbf, 0xf1, 0x1a, 0xbe, 0xca, 0xc3, 0xf1,
+ 0x3e, 0xff, 0x32, 0x39, 0xf4, 0x2a, 0x33, 0xf4,
+ 0xe5, 0x2a, 0x2c, 0xf4, 0x3a, 0x3b, 0xf4, 0x0f,
+ 0xda, 0xac, 0xf1, 0xe3, 0xcd, 0xf7, 0xf2, 0xe1,
+ 0xcd, 0xf7, 0xf2, 0x21, 0x30, 0xf4, 0xcd, 0x22,
+ 0xf2, 0xcd, 0x63, 0xf2, 0xc9, 0x2f, 0xfe, 0xcd,
+ 0xf2, 0xf1, 0xc0, 0x21, 0x30, 0xf4, 0x11, 0x39,
+ 0xf4, 0xcd, 0x25, 0xf2, 0x2a, 0x2c, 0xf4, 0xeb,
+ 0x2a, 0x33, 0xf4, 0xcd, 0x03, 0xf0, 0x2a, 0x40,
+ 0xf4, 0x11, 0x09, 0xf5, 0x19, 0x11, 0xf2, 0xf1,
+ 0xd5, 0x7e, 0xfe, 0x10, 0xc8, 0xfe, 0x13, 0xc8,
+ 0xfe, 0x16, 0xc8, 0xfe, 0x17, 0xc8, 0xd1, 0xaf,
+ 0xc9, 0x0e, 0x21, 0x39, 0xf4, 0x7e, 0x3c, 0xc8,
+ 0xcd, 0x22, 0xf2, 0x3e, 0xff, 0x32, 0x39, 0xf4,
+ 0xcd, 0x46, 0xf2, 0xc0, 0x3a, 0x3b, 0xf4, 0x0f,
+ 0xd2, 0x18, 0xf2, 0xcd, 0xf4, 0xf2, 0xcd, 0xb8,
+ 0xf2, 0xcd, 0x0a, 0xf3, 0xca, 0x1e, 0xf2, 0x11,
+ 0xcd, 0x0a, 0xf3, 0xcd, 0xf4, 0xf2, 0xcd, 0x63,
+ 0xf2, 0xc9, 0x11, 0x3d, 0xf4, 0x06, 0x03, 0xc3,
+ 0x05, 0xf0, 0x06, 0x1a, 0xb7, 0xf8, 0xbe, 0xc0,
+ 0x23, 0x13, 0x1a, 0xbe, 0xc0, 0x23, 0x13, 0x7e,
+ 0x3c, 0x0f, 0xe6, 0x7f, 0x4f, 0x1a, 0x3c, 0x0f,
+ 0xe6, 0x7f, 0xb9, 0xc9, 0xfe, 0x21, 0x3e, 0xff,
+ 0x32, 0x35, 0xf4, 0xaf, 0x32, 0x38, 0xf4, 0xcd,
+ 0x82, 0xf2, 0x3e, 0x01, 0xc0, 0x21, 0x3d, 0xf4,
+ 0x11, 0x35, 0xf4, 0xcd, 0x25, 0xf2, 0x78, 0xc8,
+ 0xc3, 0x7a, 0xf1, 0x3e, 0xff, 0x32, 0x35, 0xf4,
+ 0xcd, 0xcf, 0xf2, 0xc8, 0x3e, 0x01, 0xc9, 0xd1,
+ 0x21, 0x00, 0x00, 0x39, 0x31, 0x80, 0xf4, 0xe5,
+ 0x21, 0x7e, 0xf2, 0xe5, 0xeb, 0xe9, 0xe1, 0xf9,
+ 0xc9, 0x21, 0xcd, 0x28, 0xf3, 0xc2, 0x99, 0xf2,
+ 0x0e, 0x05, 0x3e, 0x03, 0xcd, 0xca, 0xf3, 0xe6,
+ 0x08, 0xc8, 0xcd, 0xd7, 0xf3, 0x0d, 0xc2, 0x8a,
+ 0xf2, 0x3e, 0x01, 0xb7, 0xc9, 0x21, 0x38, 0xf4,
+ 0xbe, 0xc4, 0xb8, 0xf2, 0x06, 0x80, 0x3e, 0x40,
+ 0xd3, 0xc0, 0xdb, 0xc0, 0x12, 0x13, 0x34, 0x05,
+ 0xc2, 0xaa, 0xf2, 0xaf, 0xd3, 0xc0, 0xc8, 0x11,
+ 0x06, 0x80, 0x21, 0x38, 0xf4, 0x3e, 0x40, 0xd3,
+ 0xc0, 0xdb, 0xc0, 0x34, 0x05, 0xc2, 0xc1, 0xf2,
+ 0x78, 0xd3, 0xc0, 0xc8, 0xcd, 0x17, 0xf2, 0xcd,
+ 0x28, 0xf3, 0xc2, 0x99, 0xf2, 0x0e, 0x05, 0x3e,
+ 0x05, 0xcd, 0xca, 0xf3, 0x3a, 0x2f, 0xf4, 0xe6,
+ 0x40, 0xc8, 0x3e, 0x07, 0xcd, 0xca, 0xf3, 0xe6,
+ 0x08, 0xc8, 0xcd, 0xd7, 0xf3, 0x0d, 0xc2, 0xd7,
+ 0xf2, 0xc3, 0x99, 0xf2, 0x2a, 0x2c, 0xf4, 0x06,
+ 0x80, 0x3e, 0x30, 0xd3, 0xc0, 0x7e, 0xd3, 0xc1,
+ 0x23, 0x05, 0xc2, 0xfd, 0xf2, 0x78, 0xd3, 0xc0,
+ 0xc8, 0x0e, 0x06, 0x80, 0x3e, 0x40, 0xd3, 0xc0,
+ 0xdb, 0xc0, 0x4f, 0xaf, 0xd3, 0xc0, 0x3e, 0x30,
+ 0xd3, 0xc0, 0x79, 0xd3, 0xc1, 0xaf, 0xd3, 0xc0,
+ 0x05, 0xc2, 0x0c, 0xf3, 0xc9, 0xcd, 0xb7, 0xf2,
+ 0x16, 0x05, 0xcd, 0x3f, 0xf3, 0xd3, 0xc1, 0x3e,
+ 0x21, 0xcd, 0xd9, 0xf3, 0xcd, 0x6b, 0xf3, 0xc8,
+ 0x15, 0xc2, 0x2a, 0xf3, 0xc3, 0x99, 0xf2, 0x2a,
+ 0x3d, 0xf4, 0x7d, 0x0f, 0x0f, 0x5f, 0xcd, 0x5a,
+ 0xf3, 0x3a, 0x3f, 0xf4, 0xca, 0x53, 0xf3, 0x3c,
+ 0x0f, 0xe6, 0x3f, 0xb3, 0xc9, 0x06, 0x0b, 0x2a,
+ 0x30, 0xf4, 0x7c, 0xb7, 0xc8, 0x3e, 0x28, 0x85,
+ 0x4f, 0x21, 0x00, 0xf4, 0x06, 0x00, 0x09, 0x7e,
+ 0xe6, 0x02, 0xc9, 0x3a, 0x3e, 0xf4, 0x21, 0x27,
+ 0xf4, 0xbe, 0xc8, 0x77, 0x5f, 0x2a, 0x3d, 0xf4,
+ 0xcd, 0x5a, 0xf3, 0xca, 0x80, 0xf3, 0x3e, 0x10,
+ 0xd3, 0xc1, 0x3e, 0x15, 0xcd, 0xd9, 0xf3, 0x7b,
+ 0xb7, 0x3e, 0x0d, 0xca, 0x98, 0xf3, 0x7b, 0xd3,
+ 0xc1, 0x3e, 0x11, 0xcd, 0xd9, 0xf3, 0x3e, 0x09,
+ 0xcd, 0xca, 0xf3, 0xe6, 0x28, 0xc8, 0xcd, 0xb1,
+ 0xf3, 0xc3, 0x99, 0xf2, 0x3e, 0xff, 0x32, 0x39,
+ 0xf4, 0xaf, 0x32, 0x3d, 0xf4, 0x3c, 0x32, 0x3f,
+ 0xf4, 0x3e, 0x81, 0xcd, 0xd9, 0xf3, 0xcd, 0x3f,
+ 0xf3, 0xd3, 0xc1, 0x3e, 0x21, 0xcd, 0xd9, 0xf3,
+ 0x3e, 0xff, 0x32, 0x27, 0xf4, 0x32, 0x35, 0xf4,
+ 0x3e, 0x0d, 0xcd, 0xd9, 0xf3, 0xdb, 0xc0, 0xe6,
+ 0x01, 0xc2, 0xcd, 0xf3, 0xdb, 0xc0, 0xc9, 0x3e,
+ 0x0b, 0xd3, 0xc0, 0xaf, 0xd3, 0xc0, 0xc9, 0x7e,
+ 0xb7, 0xc8, 0x4e, 0xe5, 0xcd, 0xec, 0xf3, 0xe1,
+ 0x23, 0xc3, 0xdf, 0xf3, 0x2a, 0x40, 0xf4, 0x2e,
+ 0x0c, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static uint8 *icom_prom = icom_3712_prom;
+
+/*
+** ICOM Registers and Interface Controls
+*/
+typedef struct {
+ uint8 status; /* Status Register */
+ uint8 track; /* Track Register */
+ uint8 sector; /* Sector Register */
+ uint8 command; /* Command Register */
+ uint8 rData; /* Read Data Register */
+ uint32 rDataBuf; /* Read buffer index */
+ uint8 wData; /* Write Data Register */
+ uint32 wDataBuf; /* Write buffer index */
+ uint8 formatMode; /* format mode */
+ uint16 bytesPerSec; /* bytes per sector */
+} ICOM_REG;
+
+/* iCOM Registers */
+#define ICOM_REG_COMMAND 0x00
+#define ICOM_REG_DATAI 0x00
+#define ICOM_REG_DATAO 0x01
+
+/* iCOM Commands */
+#define ICOM_CMD_STATUS 0x00
+#define ICOM_CMD_CMDMSK 0x01
+#define ICOM_CMD_READ 0x03
+#define ICOM_CMD_WRITE 0x05
+#define ICOM_CMD_READCRC 0x07
+#define ICOM_CMD_SEEK 0x09
+#define ICOM_CMD_CLRERRFLGS 0x0b
+#define ICOM_CMD_TRACK0 0x0d
+#define ICOM_CMD_WRITEDDM 0x0f
+#define ICOM_CMD_LDTRACK 0x11
+#define ICOM_CMD_LDUNITSEC 0x21
+#define ICOM_CMD_LDWRITEBUFNOP 0x30
+#define ICOM_CMD_LDWRITEBUF 0x31
+#define ICOM_CMD_EXREADBUF 0x40
+#define ICOM_CMD_SHREADBUF 0x41
+#define ICOM_CMD_CLEAR 0x81
+#define ICOM_CMD_LDCONF 0x15
+
+#define ICOM_STAT_BUSY 0x01
+#define ICOM_STAT_UNITMSK 0x06
+#define ICOM_STAT_CRC 0x08
+#define ICOM_STAT_WRITEPROT 0x10
+#define ICOM_STAT_DRVFAIL 0x20
+#define ICOM_STAT_MEDIASTAT 0x40
+#define ICOM_STAT_DDM 0x80
+
+#define ICOM_CONF_DD 0x10 /* Double Density */
+#define ICOM_CONF_FM 0x20 /* Format Mode */
+
+#define ICOM_TYPE_3712 0x00
+#define ICOM_TYPE_3812 0x01
+
+typedef struct {
+ uint32 mem_base; /* Memory Base Address */
+ uint32 mem_size; /* Memory Address space requirement */
+ uint32 io_base; /* I/O Base Address */
+ uint32 io_size; /* I/O Address Space requirement */
+ uint32 prom_base; /* Boot PROM Base Address */
+ uint32 prom_size; /* Boot PROM Address space requirement */
+ uint8 promEnabled; /* PROM is enabled */
+ uint8 boardType; /* Interface Board Type */
+ uint8 rwsMs; /* Read/Write Sector ms */
+ uint8 seekMs; /* Seek ms */
+ uint8 currentDrive; /* Currently selected drive */
+ uint8 currentTrack[ICOM_MAX_DRIVES];
+ uint32 msTime; /* MS time for BUSY */
+ ICOM_REG ICOM; /* ICOM Registers and Data */
+ UNIT *uptr[ICOM_MAX_DRIVES];
+} ICOM_INFO;
+
+static ICOM_INFO icom_info_data = {
+ ICOM_MEM_BASE, ICOM_MEM_SIZE, ICOM_IO_BASE, ICOM_IO_SIZE, ICOM_PROM_BASE, ICOM_PROM_SIZE,
+ TRUE, ICOM_TYPE_3812, 6, 10
+};
+
+static ICOM_INFO *icom_info = &icom_info_data;
+
+/*
+** Read and Write Data Ring Buffers
+*/
+#define DATA_MASK ICOM_DD_SECTOR_LEN-1
+
+static uint8 rdata[ICOM_DD_SECTOR_LEN];
+static uint8 wdata[ICOM_DD_SECTOR_LEN];
+
+/* Local function prototypes */
+static t_stat icom_reset(DEVICE *icom_dev);
+static t_stat icom_svc(UNIT *uptr);
+static t_stat icom_attach(UNIT *uptr, CONST char *cptr);
+static t_stat icom_detach(UNIT *uptr);
+static t_stat icom_boot(int32 unitno, DEVICE *dptr);
+static t_stat icom_set_prom(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+static t_stat icom_show_prom(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+static t_stat icom_set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+static t_stat icom_show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+static t_stat icom_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+static t_stat icom_show_type(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+static uint32 calculate_icom_sec_offset(ICOM_REG *pICOM, uint8 track, uint8 sector);
+static void icom_set_busy(uint32 msec);
+static uint8 ICOM_Read(uint32 Addr);
+static uint8 ICOM_Write(uint32 Addr, int32 data);
+static const char * ICOM_CommandString(uint8 command);
+static uint8 ICOM_Command(UNIT *uptr, ICOM_REG *pICOM, int32 data);
+static uint32 ICOM_ReadSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer);
+static uint32 ICOM_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer);
+static uint32 ICOM_FormatTrack(UNIT *uptr, uint8 track, uint8 *buffer);
+static uint8 ICOM_DriveNotReady(UNIT *uptr, ICOM_REG *pICOM);
+static const char* icom_description(DEVICE *dptr);
+static void showReadSec(void);
+static void showWriteSec(void);
+static int32 icomdev(int32 Addr, int32 rw, int32 data);
+static int32 icomprom(int32 Addr, int32 rw, int32 data);
+static int32 icommem(int32 Addr, int32 rw, int32 data);
+
+static UNIT icom_unit[ICOM_MAX_DRIVES] = {
+ { UDATA (icom_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, ICOM_DD_CAPACITY), 10000 },
+ { UDATA (icom_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, ICOM_DD_CAPACITY), 10000 },
+ { UDATA (icom_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, ICOM_DD_CAPACITY), 10000 },
+ { UDATA (icom_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, ICOM_DD_CAPACITY), 10000 }
+};
+
+static REG icom_reg[] = {
+ { DRDATAD (DRIVE, icom_info_data.currentDrive, 8, "Current drive register"), },
+ { HRDATAD (STATUS, icom_info_data.ICOM.status, 8, "Status register"), },
+ { HRDATAD (COMMAND, icom_info_data.ICOM.command, 8, "Command register"), },
+ { HRDATAD (RDATA, icom_info_data.ICOM.rData, 8, "Read Data register"), },
+ { HRDATAD (WDATA, icom_info_data.ICOM.wData, 8, "Write Data register"), },
+ { DRDATAD (TRACK, icom_info_data.ICOM.track, 8, "Track register"), },
+ { DRDATAD (SECTOR, icom_info_data.ICOM.sector, 8, "Sector register"), },
+ { DRDATAD (RBUF, icom_info_data.ICOM.rDataBuf, 16, "Read data buffer index register"), },
+ { DRDATAD (WBUF, icom_info_data.ICOM.wDataBuf, 16, "Write data buffer index register"), },
+ { DRDATAD (FORMAT, icom_info_data.ICOM.formatMode, 8, "Current format mode register"), },
+ { DRDATAD (DENSITY, icom_info_data.ICOM.bytesPerSec, 16, "Current density register"), },
+ { FLDATAD (PROM, icom_info_data.promEnabled, 0, "PROM enabled bit"), },
+ { DRDATAD (RWSMS, icom_info_data.rwsMs, 8, "Read/Write sector time (ms)"), },
+ { DRDATAD (SEEKMS, icom_info_data.seekMs, 8, "Seek track to track time (ms)"), },
+ { NULL }
+};
+
+#define ICOM_NAME "iCOM 3712/3812 Floppy Disk Interface"
+#define ICOM_SNAME "ICOM"
+
+static const char* icom_description(DEVICE *dptr) {
+ return ICOM_NAME;
+}
+
+#define UNIT_V_ICOM_WPROTECT (UNIT_V_UF + 1) /* WRTENB / WRTPROT */
+#define UNIT_ICOM_WPROTECT (1 << UNIT_V_ICOM_WPROTECT)
+
+static MTAB icom_mod[] = {
+ { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
+ &set_iobase, &show_iobase, NULL, "Sets interface board I/O base address" },
+ { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE",
+ &icom_set_membase, &icom_show_membase, NULL, "Shows interface board memory base address" },
+ { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "PROM", "PROM={ENABLE|DISABLE}",
+ &icom_set_prom, &icom_show_prom, NULL, "Set/Show PROM enabled/disabled status"},
+ { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "TYPE", "TYPE={3712|3812}",
+ &icom_set_type, &icom_show_type, NULL, "Set/Show the current controller type" },
+ { UNIT_ICOM_WPROTECT, 0, "WRTENB", "WRTENB", NULL, NULL, NULL,
+ "Enables " ICOM_SNAME "n for writing" },
+ { UNIT_ICOM_WPROTECT, UNIT_ICOM_WPROTECT, "WRTPROT", "WRTPROT", NULL, NULL, NULL,
+ "Protects " ICOM_SNAME "n from writing" },
+ { 0 }
+};
+
+/* Debug flags */
+#define VERBOSE_MSG (1 << 0)
+#define ERROR_MSG (1 << 1)
+#define RBUF_MSG (1 << 2)
+#define WBUF_MSG (1 << 3)
+#define CMD_MSG (1 << 4)
+#define RD_DATA_MSG (1 << 5)
+#define WR_DATA_MSG (1 << 6)
+#define STATUS_MSG (1 << 7)
+#define RD_DATA_DETAIL_MSG (1 << 8)
+#define WR_DATA_DETAIL_MSG (1 << 9)
+
+/* Debug Flags */
+static DEBTAB icom_dt[] = {
+ { "VERBOSE", VERBOSE_MSG, "Verbose messages" },
+ { "ERROR", ERROR_MSG, "Error messages" },
+ { "CMD", CMD_MSG, "Command messages" },
+ { "RBUF", RBUF_MSG, "Read Buffer messages" },
+ { "WBUF", WBUF_MSG, "Write Buffer messages" },
+ { "READ", RD_DATA_MSG, "Read messages" },
+ { "WRITE", WR_DATA_MSG, "Write messages" },
+ { "STATUS", STATUS_MSG, "Status messages" },
+ { "RDDETAIL", RD_DATA_DETAIL_MSG, "Read detail messages" },
+ { "WRDETAIL", WR_DATA_DETAIL_MSG, "Write detail messags" },
+ { NULL, 0 }
+};
+
+DEVICE icom_dev = {
+ ICOM_SNAME, /* name */
+ icom_unit, /* unit */
+ icom_reg, /* registers */
+ icom_mod, /* modifiers */
+ ICOM_MAX_DRIVES, /* # units */
+ 10, /* address radix */
+ 31, /* address width */
+ 1, /* addr increment */
+ ICOM_MAX_DRIVES, /* data radix */
+ ICOM_MAX_DRIVES, /* data width */
+ NULL, /* examine routine */
+ NULL, /* deposit routine */
+ &icom_reset, /* reset routine */
+ &icom_boot, /* boot routine */
+ &icom_attach, /* attach routine */
+ &icom_detach, /* detach routine */
+ &icom_info_data, /* context */
+ (DEV_DISABLE | DEV_DIS | DEV_DEBUG), /* flags */
+ ERROR_MSG, /* debug control */
+ icom_dt, /* debug flags */
+ NULL, /* mem size routine */
+ NULL, /* logical name */
+ NULL, /* help */
+ NULL, /* attach help */
+ NULL, /* context for help */
+ &icom_description /* description */
+};
+
+/* Reset routine */
+static t_stat icom_reset(DEVICE *dptr)
+{
+ uint8 i;
+
+ if (dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */
+ sim_map_resource(icom_info->prom_base, icom_info->prom_size, RESOURCE_TYPE_MEMORY, &icomprom, "icomprom", TRUE);
+ sim_map_resource(icom_info->mem_base, icom_info->mem_size, RESOURCE_TYPE_MEMORY, &icommem, "icommem", TRUE);
+ sim_map_resource(icom_info->io_base, icom_info->io_size, RESOURCE_TYPE_IO, &icomdev, "icomdev", TRUE);
+ } else {
+ if (sim_map_resource(icom_info->prom_base, icom_info->prom_size, RESOURCE_TYPE_MEMORY, &icomprom, "icomprom", FALSE) != 0) {
+ sim_debug(ERROR_MSG, &icom_dev, "Error mapping PROM resource at 0x%04x\n", icom_info->prom_base);
+ return SCPE_ARG;
+ }
+ if (sim_map_resource(icom_info->mem_base, icom_info->mem_size, RESOURCE_TYPE_MEMORY, &icommem, "icommem", FALSE) != 0) {
+ sim_debug(ERROR_MSG, &icom_dev, "Error mapping MEM resource at 0x%04x\n", icom_info->mem_base);
+ return SCPE_ARG;
+ }
+ /* Connect I/O Ports at base address */
+ if (sim_map_resource(icom_info->io_base, icom_info->io_size, RESOURCE_TYPE_IO, &icomdev, "icomdev", FALSE) != 0) {
+ sim_debug(ERROR_MSG, &icom_dev, "Error mapping I/O resource at 0x%02x\n", icom_info->io_base);
+ return SCPE_ARG;
+ }
+ }
+
+ icom_info->currentDrive = 0;
+
+ icom_info->ICOM.track = 0;
+ icom_info->ICOM.sector = 1;
+ icom_info->ICOM.command = 0;
+ icom_info->ICOM.status = 0;
+ icom_info->ICOM.rData = 0;
+ icom_info->ICOM.wData = 0;
+ icom_info->ICOM.rDataBuf = 0;
+ icom_info->ICOM.wDataBuf = 0;
+ icom_info->ICOM.bytesPerSec = ICOM_SD_SECTOR_LEN;
+ icom_info->ICOM.formatMode = 0;
+
+ /* Reset Registers and Interface Controls */
+ for (i=0; i < ICOM_MAX_DRIVES; i++) {
+ if (icom_info->uptr[i] == NULL) {
+ icom_info->uptr[i] = &icom_dev.units[i];
+ }
+
+ icom_info->currentTrack[i] = 0;
+ }
+
+ sim_debug(STATUS_MSG, &icom_dev, "reset controller.\n");
+
+ return SCPE_OK;
+}
+
+/* Service routine */
+static t_stat icom_svc(UNIT *uptr)
+{
+// if (icom_info->msTime != sim_os_msec()) {
+ icom_info->ICOM.status &= ~ICOM_STAT_BUSY;
+// }
+// else {
+// sim_activate_after_abs(icom_info->uptr[icom_info->currentDrive], 1000); /* Try another 1ms */
+// }
+
+ return SCPE_OK;
+}
+
+/* Attach routine */
+static t_stat icom_attach(UNIT *uptr, CONST char *cptr)
+{
+ t_stat r;
+ unsigned int i = 0;
+
+ r = attach_unit(uptr, cptr); /* attach unit */
+ if (r != SCPE_OK) { /* error? */
+ sim_debug(ERROR_MSG, &icom_dev, "ATTACH error=%d\n", r);
+ return r;
+ }
+
+ /* Determine length of this disk */
+ if (sim_fsize(uptr->fileref) != 0) {
+ uptr->capac = sim_fsize(uptr->fileref);
+ } else {
+ uptr->capac = ICOM_SD_CAPACITY;
+ }
+
+ for (i = 0; i < ICOM_MAX_DRIVES; i++) {
+ if (icom_dev.units[i].fileref == uptr->fileref) {
+ break;
+ }
+ }
+
+ if (i >= ICOM_MAX_DRIVES) {
+ icom_detach(uptr);
+
+ return SCPE_ARG;
+ }
+
+ /* Default for new file is DSK */
+ uptr->u3 = IMAGE_TYPE_DSK;
+
+ sim_debug(VERBOSE_MSG, uptr->dptr, "unit %d, attached to '%s' size=%d interface=%s\n",
+ i, cptr, uptr->capac, (icom_info->boardType == ICOM_TYPE_3712) ? "FD3712" : "FD3812");
+
+ return SCPE_OK;
+}
+
+
+/* Detach routine */
+static t_stat icom_detach(UNIT *uptr)
+{
+ t_stat r;
+ int8 i;
+
+ for (i = 0; i < ICOM_MAX_DRIVES; i++) {
+ if (icom_dev.units[i].fileref == uptr->fileref) {
+ break;
+ }
+ }
+
+ if (i >= ICOM_MAX_DRIVES) {
+ return SCPE_ARG;
+ }
+
+ DBG_PRINT(("Detach ICOM%d\n", i));
+
+ r = detach_unit(uptr); /* detach unit */
+
+ if (r != SCPE_OK) {
+ return r;
+ }
+
+ icom_dev.units[i].fileref = NULL;
+
+ sim_debug(VERBOSE_MSG, uptr->dptr, "unit %d detached.\n", i);
+
+ return SCPE_OK;
+}
+
+/*
+** If membase is 0, remove from system
+*/
+static t_stat icom_set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+ uint32 newba;
+ t_stat r;
+
+ if (cptr == NULL) {
+ sim_debug(ERROR_MSG, &icom_dev, "cptr=NULL\n");
+ return SCPE_ARG;
+ }
+
+ newba = get_uint(cptr, 16, 0xFFFF, &r);
+
+ if (r != SCPE_OK) {
+ sim_debug(ERROR_MSG, &icom_dev, "get_uint=%d\n", r);
+ return r;
+ }
+
+ if (newba) {
+ r = set_membase(uptr, val, cptr, desc);
+ if (r) {
+ sim_debug(ERROR_MSG, &icom_dev, "Error setting MEM resource at 0x%04x\n", icom_info->mem_base);
+ icom_info->mem_base = 0;
+ }
+ else {
+ sim_debug(VERBOSE_MSG, &icom_dev, "memory now at 0x%04x\n", icom_info->mem_base);
+ icom_info->mem_base = newba;
+ }
+ }
+ else if (icom_info->mem_base) {
+ sim_map_resource(icom_info->mem_base, icom_info->mem_size, RESOURCE_TYPE_MEMORY, &icommem, "icommem", TRUE);
+ icom_info->mem_base = 0;
+ sim_debug(VERBOSE_MSG, &icom_dev, "disabled memory at 0x%04x\n", icom_info->mem_base);
+ }
+
+ return r;
+}
+
+/* Show Base Address routine */
+t_stat icom_show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
+{
+ if (icom_info->mem_base) {
+ fprintf(st, "MEM=0x%04X-0x%04X", icom_info->mem_base, icom_info->mem_base+icom_info->mem_size-1);
+ }
+
+ if (icom_info->promEnabled) {
+ if (icom_info->mem_base) {
+ fprintf(st, ", ");
+ }
+ fprintf(st, "PROM=0x%04X-0x%04X", icom_info->prom_base, icom_info->prom_base+icom_info->prom_size-1);
+ }
+
+ return SCPE_OK;
+}
+
+static t_stat icom_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+ if (!cptr) return SCPE_IERR;
+
+ if (!strcmp(cptr, "3812")) {
+ icom_info->boardType = ICOM_TYPE_3812;
+ icom_info->ICOM.status |= ICOM_STAT_MEDIASTAT;
+ icom_prom = icom_3812_prom;
+ } else if (!strcmp(cptr, "3712")) {
+ icom_info->boardType = ICOM_TYPE_3712;
+ icom_info->ICOM.status &= ~ICOM_STAT_MEDIASTAT;
+ icom_info->ICOM.bytesPerSec = ICOM_SD_SECTOR_LEN;
+ icom_prom = icom_3712_prom;
+ } else {
+ return SCPE_ARG;
+ }
+
+ return SCPE_OK;
+}
+
+static t_stat icom_show_type(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
+{
+ fprintf(st, "TYPE=%s", (icom_info->boardType == ICOM_TYPE_3812) ? "3812" : "3712");
+
+ return SCPE_OK;
+}
+
+static t_stat icom_set_prom(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+ if (!cptr) return SCPE_IERR;
+ if (!strlen(cptr)) return SCPE_ARG;
+
+ /* this assumes that the parameter has already been upcased */
+ if (!strncmp(cptr, "ENABLE", strlen(cptr))) {
+ if (sim_map_resource(icom_info->prom_base, icom_info->prom_size, RESOURCE_TYPE_MEMORY, &icomprom, "icomprom", FALSE) != 0) {
+ sim_debug(ERROR_MSG, &icom_dev, "Error mapping MEM resource at 0x%04x\n", icom_info->prom_base);
+ return SCPE_ARG;
+ }
+ icom_info->promEnabled = TRUE;
+ } else if (!strncmp(cptr, "DISABLE", strlen(cptr))) {
+ sim_map_resource(icom_info->prom_base, icom_info->prom_size, RESOURCE_TYPE_MEMORY, &icomprom, "icomprom", TRUE);
+ icom_info->promEnabled = FALSE;
+ } else {
+ return SCPE_ARG;
+ }
+
+ return SCPE_OK;
+}
+
+static t_stat icom_show_prom(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
+{
+ fprintf(st, "%s", (icom_info->promEnabled) ? "PROM" : "NOPROM");
+
+ return SCPE_OK;
+}
+
+static t_stat icom_boot(int32 unitno, DEVICE *dptr)
+{
+ sim_debug(VERBOSE_MSG, dptr, "Booting using PROM at 0x%04x\n", icom_info->prom_base);
+
+ *((int32 *) sim_PC->loc) = icom_info->prom_base;
+
+ return SCPE_OK;
+}
+
+static void icom_set_busy(uint32 msec)
+{
+ icom_info->ICOM.status |= ICOM_STAT_BUSY;
+
+ if (!msec) {
+ msec = 1;
+ }
+
+ icom_info->msTime = sim_os_msec();
+
+ sim_activate_after_abs(icom_info->uptr[icom_info->currentDrive], msec * 1000); /* activate timer */
+}
+
+static int32 icomdev(int32 Addr, int32 rw, int32 data)
+{
+ if (rw == 0) {
+ return(ICOM_Read(Addr));
+ } else {
+ return(ICOM_Write(Addr, data));
+ }
+}
+
+static void showReadSec()
+{
+ int i;
+ ICOM_REG *pICOM;
+
+ pICOM = &icom_info->ICOM;
+
+ sim_debug(RD_DATA_DETAIL_MSG, &icom_dev, "rdata unit %d track/sector %02d/%02d:\n", icom_info->currentDrive, pICOM->track, pICOM->sector);
+
+ for (i=0; i < pICOM->bytesPerSec; i++) {
+ if (((i) & 0xf) == 0) {
+ sim_debug(RD_DATA_DETAIL_MSG, &icom_dev, "\t");
+ }
+ sim_debug(RD_DATA_DETAIL_MSG, &icom_dev, "%02X ", rdata[i]);
+ if (((i+1) & 0xf) == 0) {
+ sim_debug(RD_DATA_DETAIL_MSG, &icom_dev, "\n");
+ }
+ }
+}
+
+static void showWriteSec()
+{
+ int i;
+ ICOM_REG *pICOM;
+
+ pICOM = &icom_info->ICOM;
+
+ sim_debug(WR_DATA_DETAIL_MSG, &icom_dev, "wdata unit %d track/sector %02d/%02d:\n", icom_info->currentDrive, pICOM->track, pICOM->sector);
+
+ for (i=0; i < pICOM->bytesPerSec; i++) {
+ if (((i) & 0xf) == 0) {
+ sim_debug(WR_DATA_DETAIL_MSG, &icom_dev, "\t");
+ }
+ sim_debug(WR_DATA_DETAIL_MSG, &icom_dev, "%02X ", wdata[i]);
+ if (((i+1) & 0xf) == 0) {
+ sim_debug(WR_DATA_DETAIL_MSG, &icom_dev, "\n");
+ }
+ }
+}
+
+static uint32 calculate_icom_sec_offset(ICOM_REG *pICOM, uint8 track, uint8 sector)
+{
+ uint32 offset;
+ uint16 bps;
+
+ bps = pICOM->bytesPerSec;
+
+ /*
+ ** Calculate track offset
+ */
+ if (track==0) {
+ offset=0;
+ }
+ else {
+ offset=ICOM_SPT * ICOM_SD_SECTOR_LEN; /* Track 0 always SD */
+ offset+=(track-1) * ICOM_SPT * bps; /* Track 1-77 SD or DD */
+ }
+
+ /*
+ ** Add sector offset to track offset
+ */
+ offset += (sector-1) * bps;
+
+ DBG_PRINT(("ICOM: offset calc drive=%d bps=%d track=%d sector=%d offset=%04x\n", icom_info->currentDrive, bps, track, sector, offset));
+
+ return (offset);
+}
+
+static uint8 ICOM_Read(uint32 Addr)
+{
+ uint8 cData;
+ uint8 driveNum;
+ ICOM_REG *pICOM;
+ UNIT *uptr;
+
+ cData = 0;
+ driveNum = icom_info->currentDrive;
+ uptr = icom_info->uptr[driveNum];
+ pICOM = &icom_info->ICOM;
+
+ switch(Addr & 0x01) {
+ case ICOM_REG_DATAI:
+ if (pICOM->command & ICOM_CMD_EXREADBUF) {
+ pICOM->rData = rdata[pICOM->rDataBuf];
+ sim_debug(RBUF_MSG, &icom_dev, "read buffer[%d]=%02x\n", pICOM->rDataBuf, pICOM->rData);
+ if (icom_info->boardType == ICOM_TYPE_3812) {
+ ICOM_Command(uptr, pICOM, ICOM_CMD_SHREADBUF);
+ }
+ cData = pICOM->rData;
+ }
+ else {
+ cData = pICOM->status;
+ }
+
+ break;
+
+ default:
+ sim_debug(ERROR_MSG, &icom_dev, "READ Invalid I/O Address %02x (%02x)\n", Addr & 0xFF, Addr & 0x01);
+ cData = 0xff;
+ break;
+ }
+
+ return (cData);
+}
+
+static uint8 ICOM_Write(uint32 Addr, int32 Data)
+{
+ uint8 cData;
+ uint8 driveNum;
+ UNIT *uptr;
+ ICOM_REG *pICOM;
+
+ cData = 0;
+ driveNum = icom_info->currentDrive;
+ uptr = icom_info->uptr[driveNum];
+ pICOM = &icom_info->ICOM;
+
+ switch(Addr & 0x01) {
+ case ICOM_REG_COMMAND:
+ cData = ICOM_Command(uptr, pICOM, Data);
+ break;
+
+ case ICOM_REG_DATAO:
+ pICOM->wData = Data;
+
+ if (pICOM->command == ICOM_CMD_LDWRITEBUFNOP && icom_info->boardType == ICOM_TYPE_3812) {
+ ICOM_Command(uptr, pICOM, ICOM_CMD_LDWRITEBUF);
+ }
+ break;
+
+ default:
+ sim_debug(ERROR_MSG, &icom_dev, "WRITE Invalid I/O Address %02x (%02x)\n", Addr & 0xFF, Addr & 0x01);
+ cData = 0xff;
+ break;
+ }
+
+ return(cData);
+}
+
+static uint32 ICOM_ReadSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer)
+{
+ uint32 sec_offset;
+ uint32 rtn = 0;
+ ICOM_REG *pICOM;
+
+ pICOM = &icom_info->ICOM;
+
+ if (uptr->fileref == NULL) {
+ sim_debug(ERROR_MSG, &icom_dev, "uptr.fileref is NULL!\n");
+ return 0;
+ }
+
+ sec_offset = calculate_icom_sec_offset(pICOM, track, sector);
+
+ sim_debug(RD_DATA_MSG, &icom_dev, "track %d sector %d at offset %04X\n", track, sector, sec_offset);
+
+ if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) {
+ sim_debug(ERROR_MSG, &icom_dev, "sim_fseek error.\n");
+ return 0;
+ }
+
+ rtn = sim_fread(buffer, 1, pICOM->bytesPerSec, uptr->fileref);
+
+ sim_debug(RD_DATA_MSG, &icom_dev, "read %d bytes at offset %04X\n", rtn, sec_offset);
+
+ return rtn;
+}
+
+
+static uint32 ICOM_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer)
+{
+ uint32 sec_offset;
+ uint32 rtn = 0;
+ ICOM_REG *pICOM;
+
+ pICOM = &icom_info->ICOM;
+
+ if (uptr->fileref == NULL) {
+ sim_debug(ERROR_MSG, &icom_dev, "uptr.fileref is NULL!\n");
+ return 0;
+ }
+
+ sec_offset = calculate_icom_sec_offset(pICOM, track, sector);
+
+ sim_debug(WR_DATA_MSG, &icom_dev, "track %d sector %d bytes %d at offset %04X\n", track, sector, pICOM->bytesPerSec, sec_offset);
+
+ if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) {
+ sim_debug(ERROR_MSG, &icom_dev, "sim_fseek error.\n");
+ return 0;
+ }
+
+ rtn = sim_fwrite(buffer, 1, pICOM->bytesPerSec, uptr->fileref);
+
+ sim_debug(WR_DATA_MSG, &icom_dev, "wrote %d bytes at offset %04X\n", rtn, sec_offset);
+
+ return rtn;
+}
+
+static uint32 ICOM_FormatTrack(UNIT *uptr, uint8 track, uint8 *buffer)
+{
+ uint8 sector;
+ uint32 rtn;
+
+ for (sector = 1; sector <= ICOM_SPT; sector++) {
+ rtn = ICOM_WriteSector(uptr, track, sector, buffer);
+ sim_debug(WR_DATA_MSG, &icom_dev, "FORMAT track %d sector %d\n", track, sector);
+ }
+
+ return rtn;
+}
+
+static uint8 ICOM_DriveNotReady(UNIT *uptr, ICOM_REG *pICOM)
+{
+ pICOM->status &= ~ICOM_STAT_DRVFAIL;
+
+ if ((uptr == NULL) || (uptr->fileref == NULL)) {
+ pICOM->status |= ICOM_STAT_DRVFAIL;
+ sim_debug(STATUS_MSG, &icom_dev, "Drive: %d not attached.\n", icom_info->currentDrive);
+ }
+
+ return (pICOM->status & ICOM_STAT_DRVFAIL);
+}
+
+static const char * ICOM_CommandString(uint8 command)
+{
+ switch (command) {
+ case ICOM_CMD_STATUS:
+ return "STATUS";
+
+ case ICOM_CMD_READ:
+ return "READ";
+
+ case ICOM_CMD_WRITE:
+ return "WRITE";
+
+ case ICOM_CMD_READCRC:
+ return "READ CRC";
+
+ case ICOM_CMD_SEEK:
+ return "SEEK";
+
+ case ICOM_CMD_CLRERRFLGS:
+ return "CLR ERR FLAGS";
+
+ case ICOM_CMD_TRACK0:
+ return "TRACK 0";
+
+ case ICOM_CMD_WRITEDDM:
+ return "WRITE DDM";
+
+ case ICOM_CMD_LDTRACK:
+ return "LD TRACK";
+
+ case ICOM_CMD_LDUNITSEC:
+ return "LD UNIT/SEC";
+
+ case ICOM_CMD_LDWRITEBUFNOP:
+ return "LD WR BUF NOP";
+
+ case ICOM_CMD_LDWRITEBUF:
+ return "LD WR BUF";
+
+ case ICOM_CMD_EXREADBUF:
+ return "EX RD BUF";
+
+ case ICOM_CMD_SHREADBUF:
+ return "SHFT RD BUF";
+
+ case ICOM_CMD_CLEAR:
+ return "CLEAR";
+
+ case ICOM_CMD_LDCONF:
+ return "LD CONFIG";
+
+ default:
+ break;
+ }
+
+ return "UNRECOGNIZED COMMAND";
+}
+
+static uint8 ICOM_Command(UNIT *uptr, ICOM_REG *pICOM, int32 Data)
+{
+ uint8 cData;
+ uint8 newTrack;
+ uint8 drive;
+ int32 rtn;
+
+ cData = 0;
+
+ if (uptr == NULL) {
+ return cData;
+ }
+
+ pICOM->command = Data;
+
+ drive = icom_info->currentDrive;
+
+ switch(pICOM->command) {
+ case ICOM_CMD_STATUS:
+ pICOM->rData = pICOM->status;
+ break;
+
+ case ICOM_CMD_READ:
+ if (ICOM_DriveNotReady(uptr, pICOM)) {
+ break;
+ }
+
+ rtn = ICOM_ReadSector(uptr, pICOM->track, pICOM->sector, rdata);
+
+ if (rtn == pICOM->bytesPerSec) {
+ showReadSec();
+ icom_set_busy(icom_info->rwsMs);
+ }
+ else {
+ sim_debug(ERROR_MSG, &icom_dev, "sim_fread errno=%d\n", errno);
+
+ pICOM->status |= ICOM_STAT_DRVFAIL;
+ }
+
+ pICOM->rDataBuf = 0; // Reset read buffer address
+
+ break;
+
+ case ICOM_CMD_WRITEDDM:
+ sim_debug(VERBOSE_MSG, &icom_dev, "DDM writes not supported. Performing standard write.\n");
+
+ /* fall into ICOM_CMD_WRITE */
+
+ case ICOM_CMD_WRITE:
+ if (ICOM_DriveNotReady(uptr, pICOM)) {
+ break;
+ }
+
+ if (uptr->flags & UNIT_ICOM_WPROTECT) {
+ sim_debug(ERROR_MSG, &icom_dev, "Disk '%s' write protected.\n", uptr->filename);
+ break;
+ }
+
+ /*
+ ** If format mode, format entire track with wdata
+ */
+ if (pICOM->formatMode) {
+ rtn = ICOM_FormatTrack(uptr, pICOM->track, wdata);
+ }
+ else {
+ rtn = ICOM_WriteSector(uptr, pICOM->track, pICOM->sector, wdata);
+ }
+
+ if (rtn == pICOM->bytesPerSec) {
+ showWriteSec();
+ icom_set_busy(icom_info->rwsMs);
+ }
+ else {
+ sim_debug(ERROR_MSG, &icom_dev, "sim_fwrite errno=%d\n", errno);
+
+ pICOM->status |= ICOM_STAT_DRVFAIL;
+ }
+
+ pICOM->wDataBuf = 0; // Reset write buffer address
+ break;
+
+ case ICOM_CMD_READCRC:
+ if (ICOM_DriveNotReady(uptr, pICOM)) {
+ break;
+ }
+ icom_set_busy(icom_info->rwsMs);
+ break;
+
+ case ICOM_CMD_SEEK:
+ if (ICOM_DriveNotReady(uptr, pICOM)) {
+ break;
+ }
+
+ icom_set_busy(icom_info->seekMs * abs((int8) pICOM->track - (int8) icom_info->currentTrack[icom_info->currentDrive]));
+ icom_info->currentTrack[icom_info->currentDrive] = pICOM->track;
+
+ break;
+
+ case ICOM_CMD_CLRERRFLGS:
+ pICOM->status &= ~ICOM_STAT_BUSY;
+ pICOM->status &= ~ICOM_STAT_DDM;
+ break;
+
+ case ICOM_CMD_TRACK0:
+ if (ICOM_DriveNotReady(uptr, pICOM)) {
+ break;
+ }
+
+ pICOM->track = 0;
+ icom_set_busy(icom_info->seekMs * abs((int8) pICOM->track - (int8) icom_info->currentTrack[icom_info->currentDrive]));
+ icom_info->currentTrack[icom_info->currentDrive] = 0;
+
+ break;
+
+ case ICOM_CMD_LDTRACK:
+ newTrack = pICOM->wData;
+
+ if (newTrack < ICOM_TRACKS) {
+ pICOM->track = newTrack;
+ }
+
+ break;
+
+ case ICOM_CMD_LDUNITSEC:
+ pICOM->sector = pICOM->wData & 0x1f;
+ icom_info->currentDrive = pICOM->wData >> 6;
+ pICOM->status &= ~ICOM_STAT_UNITMSK;
+ pICOM->status |= icom_info->currentDrive << 1;
+ break;
+
+ case ICOM_CMD_LDWRITEBUFNOP:
+ sim_debug(WBUF_MSG, &icom_dev, "LOAD WRITE BUF NOP index=%04x\n", pICOM->wDataBuf);
+ break;
+
+ case ICOM_CMD_LDWRITEBUF:
+ sim_debug(WBUF_MSG, &icom_dev, "LOAD WRITE BUF %d=%02x\n", pICOM->wDataBuf, pICOM->wData);
+ wdata[pICOM->wDataBuf] = pICOM->wData;
+ pICOM->wDataBuf++;
+ pICOM->wDataBuf &= DATA_MASK;
+ break;
+
+ case ICOM_CMD_EXREADBUF:
+ sim_debug(RBUF_MSG, &icom_dev, "EXAMINE READ BUF index=%04x\n", pICOM->rDataBuf);
+ break;
+
+ case ICOM_CMD_SHREADBUF:
+ pICOM->rDataBuf++;
+ pICOM->rDataBuf &= DATA_MASK;
+ sim_debug(RBUF_MSG, &icom_dev, "SHIFT READ BUF index=%04x\n", pICOM->rDataBuf);
+ break;
+
+ case ICOM_CMD_CLEAR:
+ pICOM->status &= ~ICOM_STAT_BUSY;
+ pICOM->status &= ~ICOM_STAT_DRVFAIL;
+ pICOM->status &= ~ICOM_STAT_CRC;
+ pICOM->status &= ~ICOM_STAT_DDM;
+ pICOM->rDataBuf = 0;
+ pICOM->wDataBuf = 0;
+ break;
+
+ case ICOM_CMD_LDCONF:
+ pICOM->formatMode = (pICOM->wData & ICOM_CONF_FM);
+ pICOM->bytesPerSec = (pICOM->wData & ICOM_CONF_DD) ? ICOM_DD_SECTOR_LEN : ICOM_SD_SECTOR_LEN;
+ break;
+
+ default:
+ cData=0xFF;
+ break;
+ }
+
+ /* Set WRITE PROTECT bit */
+ pICOM->status &= ~ICOM_STAT_WRITEPROT;
+ pICOM->status |= (uptr->flags & UNIT_ICOM_WPROTECT) ? ICOM_STAT_WRITEPROT : 0;
+
+ /* Set data register to status if command bit 6 is 0 */
+ if (!(pICOM->command & 0x40)) {
+ pICOM->rData = pICOM->status;
+ }
+
+ /* Clear command bit 0 */
+ pICOM->command &= ~ICOM_CMD_CMDMSK;
+
+ sim_debug(CMD_MSG, &icom_dev,
+ "%-13.13s (%02Xh) unit=%d trk=%02d sec=%02d stat=%02Xh density=%d formatMode=%s\n",
+ ICOM_CommandString(Data),
+ Data, icom_info->currentDrive,
+ pICOM->track, pICOM->sector, pICOM->status,
+ pICOM->bytesPerSec, (pICOM->formatMode) ? "TRUE" : "FALSE");
+
+ return(cData);
+}
+
+static int32 icomprom(int32 Addr, int32 rw, int32 Data)
+{
+ /*
+ ** The iCOM controller PROM occupies 1024 bytes (1K) of RAM at
+ ** location F000H.
+ */
+ if (icom_info->promEnabled == TRUE) {
+ return(icom_prom[Addr & ICOM_PROM_MASK]);
+ }
+
+ return 0xff;
+}
+
+static int32 icommem(int32 Addr, int32 rw, int32 Data)
+{
+ if (rw) {
+ icom_mem[Addr & ICOM_MEM_MASK] = Data & 0xff;
+ }
+
+ return(icom_mem[Addr & ICOM_MEM_MASK]);
+}
+
diff --git a/AltairZ80/s100_pmmi.c b/AltairZ80/s100_pmmi.c
index 5b3bf0cd..d3c74e6e 100644
--- a/AltairZ80/s100_pmmi.c
+++ b/AltairZ80/s100_pmmi.c
@@ -259,13 +259,9 @@ static const char* pmmi_description(DEVICE *dptr)
static t_stat pmmi_reset(DEVICE *dptr)
{
- PMMI_CTX *xptr;
-
- xptr = dptr->ctxt;
-
/* Connect/Disconnect I/O Ports at base address */
- if(sim_map_resource(xptr->pnp.io_base, xptr->pnp.io_size, RESOURCE_TYPE_IO, &pmmi_io, dptr->name, dptr->flags & DEV_DIS) != 0) {
- sim_debug(ERROR_MSG, dptr, "error mapping I/O resource at 0x%02x.\n", xptr->pnp.io_base);
+ if (sim_map_resource(pmmi_ctx.pnp.io_base, pmmi_ctx.pnp.io_size, RESOURCE_TYPE_IO, &pmmi_io, dptr->name, dptr->flags & DEV_DIS) != 0) {
+ sim_debug(ERROR_MSG, dptr, "error mapping I/O resource at 0x%02x.\n", pmmi_ctx.pnp.io_base);
return SCPE_ARG;
}
@@ -273,21 +269,21 @@ static t_stat pmmi_reset(DEVICE *dptr)
dptr->units[0].dptr = dptr;
/* Enable TMXR modem control passthru */
- tmxr_set_modem_control_passthru(xptr->tmxr);
+ tmxr_set_modem_control_passthru(pmmi_ctx.tmxr);
/* Reset status registers */
- xptr->ireg0 = 0;
- xptr->ireg1 = 0;
- xptr->ireg2 = PMMI_RNG | PMMI_CTS | PMMI_DT | PMMI_AP;
- xptr->ireg3 = 0;
- xptr->oreg0 = 0;
- xptr->oreg1 = 0;
- xptr->oreg2 = 0;
- xptr->oreg3 = 0;
- xptr->txp = 0;
- xptr->intmsk = 0;
- xptr->ptimer = sim_os_msec() + 40;
- xptr->dtimer = 0;
+ pmmi_ctx.ireg0 = 0;
+ pmmi_ctx.ireg1 = 0;
+ pmmi_ctx.ireg2 = PMMI_RNG | PMMI_CTS | PMMI_DT | PMMI_AP;
+ pmmi_ctx.ireg3 = 0;
+ pmmi_ctx.oreg0 = 0;
+ pmmi_ctx.oreg1 = 0;
+ pmmi_ctx.oreg2 = 0;
+ pmmi_ctx.oreg3 = 0;
+ pmmi_ctx.txp = 0;
+ pmmi_ctx.intmsk = 0;
+ pmmi_ctx.ptimer = sim_os_msec() + 40;
+ pmmi_ctx.dtimer = 0;
if (!(dptr->flags & DEV_DIS)) {
sim_activate(&dptr->units[0], dptr->units[0].wait);
@@ -302,25 +298,22 @@ static t_stat pmmi_reset(DEVICE *dptr)
static t_stat pmmi_svc(UNIT *uptr)
{
- PMMI_CTX *xptr;
int32 c,s,ireg2;
t_stat r;
uint32 ms;
- xptr = uptr->dptr->ctxt;
-
/* Check for new incoming connection */
if (uptr->flags & UNIT_ATT) {
- if (tmxr_poll_conn(xptr->tmxr) >= 0) { /* poll connection */
+ if (tmxr_poll_conn(pmmi_ctx.tmxr) >= 0) { /* poll connection */
/* Clear DTR and RTS if serial port */
- if (xptr->tmln->serport) {
+ if (pmmi_ctx.tmln->serport) {
s = TMXR_MDM_DTR | ((pmmi_dev.units[0].flags & UNIT_PMMI_RTS) ? TMXR_MDM_RTS : 0);
- tmxr_set_get_modem_bits(xptr->tmln, 0, s, NULL);
+ tmxr_set_get_modem_bits(pmmi_ctx.tmln, 0, s, NULL);
}
- xptr->tmln->rcve = 1; /* Enable receiver */
- xptr->conn = 1; /* set connected */
+ pmmi_ctx.tmln->rcve = 1; /* Enable receiver */
+ pmmi_ctx.conn = 1; /* set connected */
sim_debug(STATUS_MSG, uptr->dptr, "new connection.\n");
}
@@ -328,104 +321,104 @@ static t_stat pmmi_svc(UNIT *uptr)
/* Update incoming modem status bits */
if (uptr->flags & UNIT_ATT) {
- tmxr_set_get_modem_bits(xptr->tmln, 0, 0, &s);
+ tmxr_set_get_modem_bits(pmmi_ctx.tmln, 0, 0, &s);
- ireg2 = xptr->ireg2;
- xptr->ireg2 &= ~PMMI_CTS;
- xptr->ireg2 |= (s & TMXR_MDM_CTS) ? 0 : PMMI_CTS; /* Active Low */
+ ireg2 = pmmi_ctx.ireg2;
+ pmmi_ctx.ireg2 &= ~PMMI_CTS;
+ pmmi_ctx.ireg2 |= (s & TMXR_MDM_CTS) ? 0 : PMMI_CTS; /* Active Low */
/* CTS status changed */
- if ((ireg2 ^ xptr->ireg2) & PMMI_CTS) {
- if (xptr->ireg2 & PMMI_CTS) { /* If no CTS, set AP bit */
- xptr->ireg2 |= PMMI_AP; /* Answer Phone Bit (active low) */
+ if ((ireg2 ^ pmmi_ctx.ireg2) & PMMI_CTS) {
+ if (pmmi_ctx.ireg2 & PMMI_CTS) { /* If no CTS, set AP bit */
+ pmmi_ctx.ireg2 |= PMMI_AP; /* Answer Phone Bit (active low) */
}
- sim_debug(STATUS_MSG, uptr->dptr, "CTS state changed to %s.\n", (xptr->ireg2 & PMMI_CTS) ? "LOW" : "HIGH");
+ sim_debug(STATUS_MSG, uptr->dptr, "CTS state changed to %s.\n", (pmmi_ctx.ireg2 & PMMI_CTS) ? "LOW" : "HIGH");
}
- xptr->ireg2 &= ~PMMI_RNG;
- xptr->ireg2 |= (s & TMXR_MDM_RNG) ? 0 : PMMI_RNG; /* Active Low */
+ pmmi_ctx.ireg2 &= ~PMMI_RNG;
+ pmmi_ctx.ireg2 |= (s & TMXR_MDM_RNG) ? 0 : PMMI_RNG; /* Active Low */
/* RNG status changed */
- if ((ireg2 ^ xptr->ireg2) & PMMI_RNG) {
+ if ((ireg2 ^ pmmi_ctx.ireg2) & PMMI_RNG) {
/* Answer Phone Bit on RI */
- if (!(xptr->ireg2 & PMMI_RNG)) {
- xptr->ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
+ if (!(pmmi_ctx.ireg2 & PMMI_RNG)) {
+ pmmi_ctx.ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
}
- sim_debug(STATUS_MSG, uptr->dptr, "RNG state changed to %s.\n", (xptr->ireg2 & PMMI_RNG) ? "LOW" : "HIGH");
+ sim_debug(STATUS_MSG, uptr->dptr, "RNG state changed to %s.\n", (pmmi_ctx.ireg2 & PMMI_RNG) ? "LOW" : "HIGH");
}
/* Enable receiver if CTS is active low */
- xptr->tmln->rcve = !(xptr->ireg2 & PMMI_CTS);
+ pmmi_ctx.tmln->rcve = !(pmmi_ctx.ireg2 & PMMI_CTS);
}
/* TX data */
- if (xptr->txp) {
+ if (pmmi_ctx.txp) {
if (uptr->flags & UNIT_ATT) {
- if (!(xptr->ireg2 & PMMI_CTS)) { /* Active low */
- r = tmxr_putc_ln(xptr->tmln, xptr->oreg1);
- xptr->txp = 0; /* Reset TX Pending */
+ if (!(pmmi_ctx.ireg2 & PMMI_CTS)) { /* Active low */
+ r = tmxr_putc_ln(pmmi_ctx.tmln, pmmi_ctx.oreg1);
+ pmmi_ctx.txp = 0; /* Reset TX Pending */
} else {
r = SCPE_STALL;
}
} else {
- r = sim_putchar(xptr->oreg1);
- xptr->txp = 0; /* Reset TX Pending */
+ r = sim_putchar(pmmi_ctx.oreg1);
+ pmmi_ctx.txp = 0; /* Reset TX Pending */
}
if (r == SCPE_LOST) {
- xptr->conn = 0; /* Connection was lost */
+ pmmi_ctx.conn = 0; /* Connection was lost */
sim_debug(STATUS_MSG, uptr->dptr, "lost connection.\n");
}
}
/* Update TBMT if not set and no character pending */
- if (!xptr->txp && !(xptr->ireg0 & PMMI_TBMT)) {
+ if (!pmmi_ctx.txp && !(pmmi_ctx.ireg0 & PMMI_TBMT)) {
if (uptr->flags & UNIT_ATT) {
- tmxr_poll_tx(xptr->tmxr);
- xptr->ireg0 |= (tmxr_txdone_ln(xptr->tmln) && xptr->conn) ? (PMMI_TBMT | PMMI_TEOC) : 0;
+ tmxr_poll_tx(pmmi_ctx.tmxr);
+ pmmi_ctx.ireg0 |= (tmxr_txdone_ln(pmmi_ctx.tmln) && pmmi_ctx.conn) ? (PMMI_TBMT | PMMI_TEOC) : 0;
} else {
- xptr->ireg0 |= (PMMI_TBMT | PMMI_TEOC);
+ pmmi_ctx.ireg0 |= (PMMI_TBMT | PMMI_TEOC);
}
}
/* Check for Data if RX buffer empty */
- if (!(xptr->ireg0 & PMMI_DAV)) {
+ if (!(pmmi_ctx.ireg0 & PMMI_DAV)) {
if (uptr->flags & UNIT_ATT) {
- tmxr_poll_rx(xptr->tmxr);
+ tmxr_poll_rx(pmmi_ctx.tmxr);
- c = tmxr_getc_ln(xptr->tmln);
+ c = tmxr_getc_ln(pmmi_ctx.tmln);
} else {
c = sim_poll_kbd();
}
if (c & (TMXR_VALID | SCPE_KFLAG)) {
- xptr->ireg1 = c & 0xff;
- xptr->ireg0 |= PMMI_DAV;
- xptr->ireg0 &= ~(PMMI_FE | PMMI_OR | PMMI_RPE);
+ pmmi_ctx.ireg1 = c & 0xff;
+ pmmi_ctx.ireg0 |= PMMI_DAV;
+ pmmi_ctx.ireg0 &= ~(PMMI_FE | PMMI_OR | PMMI_RPE);
}
}
/* Timer Pulses */
ms = sim_os_msec();
- if (ms > xptr->ptimer) {
- if (xptr->oreg2) {
- if (xptr->ireg2 & PMMI_TMR) {
- xptr->ireg2 &= ~PMMI_TMR;
- xptr->ptimer = sim_os_msec() + 600 / (PMMI_CLOCK / xptr->oreg2); /* 60% off */
+ if (ms > pmmi_ctx.ptimer) {
+ if (pmmi_ctx.oreg2) {
+ if (pmmi_ctx.ireg2 & PMMI_TMR) {
+ pmmi_ctx.ireg2 &= ~PMMI_TMR;
+ pmmi_ctx.ptimer = sim_os_msec() + 600 / (PMMI_CLOCK / pmmi_ctx.oreg2); /* 60% off */
} else {
- xptr->ireg2 |= PMMI_TMR;
- xptr->ptimer = sim_os_msec() + 400 / (PMMI_CLOCK / xptr->oreg2); /* 40% on */
+ pmmi_ctx.ireg2 |= PMMI_TMR;
+ pmmi_ctx.ptimer = sim_os_msec() + 400 / (PMMI_CLOCK / pmmi_ctx.oreg2); /* 40% on */
}
} else {
- xptr->ptimer = sim_os_msec() + 100; /* default to 100ms if timer rate is 0 */
+ pmmi_ctx.ptimer = sim_os_msec() + 100; /* default to 100ms if timer rate is 0 */
}
}
/* Emulate dial tone */
- if ((ms > xptr->dtimer) && (xptr->oreg0 & PMMI_SH) && (xptr->ireg2 & PMMI_DT)) {
- xptr->ireg2 &= ~PMMI_DT;
+ if ((ms > pmmi_ctx.dtimer) && (pmmi_ctx.oreg0 & PMMI_SH) && (pmmi_ctx.ireg2 & PMMI_DT)) {
+ pmmi_ctx.ireg2 &= ~PMMI_DT;
sim_debug(STATUS_MSG, uptr->dptr, "dial tone active.\n");
}
@@ -441,22 +434,19 @@ static t_stat pmmi_svc(UNIT *uptr)
/* Attach routine */
static t_stat pmmi_attach(UNIT *uptr, CONST char *cptr)
{
- PMMI_CTX *xptr;
t_stat r;
- xptr = uptr->dptr->ctxt;
-
sim_debug(VERBOSE_MSG, uptr->dptr, "attach (%s).\n", cptr);
- if ((r = tmxr_attach(xptr->tmxr, uptr, cptr)) == SCPE_OK) {
+ if ((r = tmxr_attach(pmmi_ctx.tmxr, uptr, cptr)) == SCPE_OK) {
- xptr->flags = uptr->flags; /* Save Flags */
+ pmmi_ctx.flags = uptr->flags; /* Save Flags */
- if (!xptr->tmln->serport) {
+ if (!pmmi_ctx.tmln->serport) {
uptr->flags |= UNIT_PMMI_RTS; /* Force following DTR on sockets */
}
- xptr->tmln->rcve = 1;
+ pmmi_ctx.tmln->rcve = 1;
sim_activate(uptr, uptr->wait);
@@ -466,22 +456,17 @@ static t_stat pmmi_attach(UNIT *uptr, CONST char *cptr)
return r;
}
-
/* Detach routine */
static t_stat pmmi_detach(UNIT *uptr)
{
- PMMI_CTX *xptr;
-
sim_debug(VERBOSE_MSG, uptr->dptr, "detach.\n");
if (uptr->flags & UNIT_ATT) {
- xptr = uptr->dptr->ctxt;
-
- uptr->flags = xptr->flags; /* Restore Flags */
+ uptr->flags = pmmi_ctx.flags; /* Restore Flags */
sim_cancel(uptr);
- return (tmxr_detach(xptr->tmxr, uptr));
+ return (tmxr_detach(pmmi_ctx.tmxr, uptr));
}
return SCPE_UNATT;
@@ -489,12 +474,9 @@ static t_stat pmmi_detach(UNIT *uptr)
static t_stat pmmi_set_baud(UNIT *uptr, int32 value, const char *cptr, void *desc)
{
- PMMI_CTX *xptr;
int32 baud;
t_stat r = SCPE_ARG;
- xptr = uptr->dptr->ctxt;
-
if (!(uptr->flags & UNIT_ATT)) {
return SCPE_UNATT;
}
@@ -502,7 +484,7 @@ static t_stat pmmi_set_baud(UNIT *uptr, int32 value, const char *cptr, void *des
if (cptr != NULL) {
if (sscanf(cptr, "%d", &baud)) {
if (baud >= 61 && baud <=600) {
- xptr->baud = baud;
+ pmmi_ctx.baud = baud;
r = pmmi_config_line(uptr);
}
}
@@ -513,12 +495,8 @@ static t_stat pmmi_set_baud(UNIT *uptr, int32 value, const char *cptr, void *des
static t_stat pmmi_show_baud(FILE *st, UNIT *uptr, int32 value, const void *desc)
{
- PMMI_CTX *xptr;
-
- xptr = uptr->dptr->ctxt;
-
if (uptr->flags & UNIT_ATT) {
- fprintf(st, "Baud rate: %d", xptr->baud);
+ fprintf(st, "Baud rate: %d", pmmi_ctx.baud);
}
return SCPE_OK;
@@ -526,84 +504,79 @@ static t_stat pmmi_show_baud(FILE *st, UNIT *uptr, int32 value, const void *desc
static t_stat pmmi_config_line(UNIT *uptr)
{
- PMMI_CTX *xptr;
char config[20];
char b,p,s;
t_stat r = SCPE_IERR;
- xptr = uptr->dptr->ctxt;
+ switch (pmmi_ctx.oreg0 & PMMI_BMSK) {
+ case PMMI_5BIT:
+ b = '5';
+ break;
- if (xptr != NULL) {
- switch (xptr->oreg0 & PMMI_BMSK) {
- case PMMI_5BIT:
- b = '5';
- break;
+ case PMMI_6BIT:
+ b = '6';
+ break;
- case PMMI_6BIT:
- b = '6';
- break;
+ case PMMI_7BIT:
+ b = '7';
+ break;
- case PMMI_7BIT:
- b = '7';
- break;
-
- case PMMI_8BIT:
- default:
- b = '8';
- break;
- }
-
- switch (xptr->oreg0 & PMMI_PMSK) {
- case PMMI_OPAR:
- p = 'O';
- break;
-
- case PMMI_EPAR:
- p = 'E';
- break;
-
- case PMMI_NPAR:
- default:
- p = 'N';
- break;
- }
-
- switch (xptr->oreg0 & PMMI_SMSK) {
- case PMMI_2SB:
- s = '2';
- break;
-
- case PMMI_1SB:
- default:
- s = '1';
- break;
- }
-
- sprintf(config, "%d-%c%c%c", xptr->baud, b,p,s);
-
- r = tmxr_set_config_line(xptr->tmln, config);
-
- sim_debug(STATUS_MSG, uptr->dptr, "port configuration set to '%s'.\n", config);
-
- /*
- ** AltairZ80 and TMXR refuse to want to play together
- ** nicely when the CLOCK register is set to anything
- ** other than 0.
- **
- ** This work-around is for those of us that may wish
- ** to run irrelevant, old software, that use TMXR and
- ** rely on some semblance of timing (Remote CP/M, BYE,
- ** RBBS, PCGET/PUT, Xmodem, MEX, Modem7, or most
- ** other communications software), on contemprary
- ** hardware.
- **
- ** Serial ports are self-limiting and sockets will run
- ** at the clocked CPU speed.
- */
- xptr->tmln->txbps = 0; /* Get TMXR's rate-limiting out of our way */
- xptr->tmln->rxbps = 0; /* Get TMXR's rate-limiting out of our way */
+ case PMMI_8BIT:
+ default:
+ b = '8';
+ break;
}
+ switch (pmmi_ctx.oreg0 & PMMI_PMSK) {
+ case PMMI_OPAR:
+ p = 'O';
+ break;
+
+ case PMMI_EPAR:
+ p = 'E';
+ break;
+
+ case PMMI_NPAR:
+ default:
+ p = 'N';
+ break;
+ }
+
+ switch (pmmi_ctx.oreg0 & PMMI_SMSK) {
+ case PMMI_2SB:
+ s = '2';
+ break;
+
+ case PMMI_1SB:
+ default:
+ s = '1';
+ break;
+ }
+
+ sprintf(config, "%d-%c%c%c", pmmi_ctx.baud, b,p,s);
+
+ r = tmxr_set_config_line(pmmi_ctx.tmln, config);
+
+ sim_debug(STATUS_MSG, uptr->dptr, "port configuration set to '%s'.\n", config);
+
+ /*
+ ** AltairZ80 and TMXR refuse to want to play together
+ ** nicely when the CLOCK register is set to anything
+ ** other than 0.
+ **
+ ** This work-around is for those of us that may wish
+ ** to run irrelevant, old software, that use TMXR and
+ ** rely on some semblance of timing (Remote CP/M, BYE,
+ ** RBBS, PCGET/PUT, Xmodem, MEX, Modem7, or most
+ ** other communications software), on contemprary
+ ** hardware.
+ **
+ ** Serial ports are self-limiting and sockets will run
+ ** at the clocked CPU speed.
+ */
+ pmmi_ctx.tmln->txbps = 0; /* Get TMXR's rate-limiting out of our way */
+ pmmi_ctx.tmln->rxbps = 0; /* Get TMXR's rate-limiting out of our way */
+
return r;
}
@@ -643,29 +616,26 @@ static int32 pmmi_io(int32 addr, int32 io, int32 data)
static int32 pmmi_reg0(int32 io, int32 data)
{
- PMMI_CTX *xptr;
int32 r;
- xptr = pmmi_dev.ctxt;
-
if (io == IO_RD) {
- r = xptr->ireg0;
- } else { xptr->oreg0 = data; /* Set UART configuration */
+ r = pmmi_ctx.ireg0;
+ } else { pmmi_ctx.oreg0 = data; /* Set UART configuration */
pmmi_config_line(&pmmi_dev.units[0]);
if (data & PMMI_SH) { /* If off-hook, clear dialtone bit (active low) */
- xptr->dtimer = sim_os_msec() + 500; /* Dialtone in 500ms */
- if (xptr->oreg0 & PMMI_SH) {
- xptr->ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
+ pmmi_ctx.dtimer = sim_os_msec() + 500; /* Dialtone in 500ms */
+ if (pmmi_ctx.oreg0 & PMMI_SH) {
+ pmmi_ctx.ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
}
- } else if (!(xptr->ireg2 & PMMI_DT)) {
- xptr->dtimer = 0;
- xptr->ireg2 |= PMMI_DT;
+ } else if (!(pmmi_ctx.ireg2 & PMMI_DT)) {
+ pmmi_ctx.dtimer = 0;
+ pmmi_ctx.ireg2 |= PMMI_DT;
sim_debug(STATUS_MSG, &pmmi_dev, "dial tone inactive.\n");
}
if (data & PMMI_RI) { /* Go off-hook in answer mode */
- xptr->ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
+ pmmi_ctx.ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
}
r = 0x00;
@@ -676,18 +646,15 @@ static int32 pmmi_reg0(int32 io, int32 data)
static int32 pmmi_reg1(int32 io, int32 data)
{
- PMMI_CTX *xptr;
int32 r;
- xptr = pmmi_dev.ctxt;
-
if (io == IO_RD) {
- r = xptr->ireg1;
- xptr->ireg0 &= ~(PMMI_DAV | PMMI_FE | PMMI_OR | PMMI_RPE);
+ r = pmmi_ctx.ireg1;
+ pmmi_ctx.ireg0 &= ~(PMMI_DAV | PMMI_FE | PMMI_OR | PMMI_RPE);
} else {
- xptr->oreg1 = data;
- xptr->ireg0 &= ~(PMMI_TBMT | PMMI_TEOC);
- xptr->txp = 1;
+ pmmi_ctx.oreg1 = data;
+ pmmi_ctx.ireg0 &= ~(PMMI_TBMT | PMMI_TEOC);
+ pmmi_ctx.txp = 1;
r = 0x00;
}
@@ -697,15 +664,12 @@ static int32 pmmi_reg1(int32 io, int32 data)
static int32 pmmi_reg2(int32 io, int32 data)
{
- PMMI_CTX *xptr;
int32 r;
- xptr = pmmi_dev.ctxt;
-
if (io == IO_RD) {
- r = xptr->ireg2;
+ r = pmmi_ctx.ireg2;
} else {
- xptr->oreg2 = data;
+ pmmi_ctx.oreg2 = data;
/*
** The actual baud rate is determined by the following:
@@ -713,7 +677,7 @@ static int32 pmmi_reg2(int32 io, int32 data)
** value loaded into the rate generator.
*/
if (data) {
- xptr->baud = 250000/(data * 16);
+ pmmi_ctx.baud = 250000/(data * 16);
pmmi_config_line(&pmmi_dev.units[0]);
}
@@ -726,24 +690,23 @@ static int32 pmmi_reg2(int32 io, int32 data)
static int32 pmmi_reg3(int32 io, int32 data)
{
- PMMI_CTX *xptr;
int32 s;
- xptr = pmmi_dev.ctxt;
+
if (io == IO_RD) {
- xptr->intmsk = xptr->oreg2; /* Load int mask from rate generator */
+ pmmi_ctx.intmsk = pmmi_ctx.oreg2; /* Load int mask from rate generator */
} else {
- xptr->oreg3 = data;
+ pmmi_ctx.oreg3 = data;
/* Set/Clear DTR */
s = TMXR_MDM_DTR | ((pmmi_dev.units[0].flags & UNIT_PMMI_RTS) ? TMXR_MDM_RTS : 0);
if (data & PMMI_DTR) {
- tmxr_set_get_modem_bits(xptr->tmln, s, 0, NULL);
- if (xptr->oreg0 & PMMI_SH) {
- xptr->ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
+ tmxr_set_get_modem_bits(pmmi_ctx.tmln, s, 0, NULL);
+ if (pmmi_ctx.oreg0 & PMMI_SH) {
+ pmmi_ctx.ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
}
sim_debug(STATUS_MSG, &pmmi_dev, "set DTR HIGH.\n");
} else {
- tmxr_set_get_modem_bits(xptr->tmln, 0, s, NULL);
- xptr->ireg2 |= PMMI_AP;
+ tmxr_set_get_modem_bits(pmmi_ctx.tmln, 0, s, NULL);
+ pmmi_ctx.ireg2 |= PMMI_AP;
sim_debug(STATUS_MSG, &pmmi_dev, "set DTR LOW.\n");
}
}
diff --git a/AltairZ80/s100_tarbell.c b/AltairZ80/s100_tarbell.c
index bb453145..3faa289c 100644
--- a/AltairZ80/s100_tarbell.c
+++ b/AltairZ80/s100_tarbell.c
@@ -707,10 +707,7 @@ static uint32 bytes_per_track(uint8 track)
static uint32 calculate_tarbell_sec_offset(uint8 track, uint8 sector)
{
uint32 offset;
- uint8 dd,ds;
-
- dd = tarbell_info->doubleDensity[tarbell_info->currentDrive];
- ds = tarbell_info->side[tarbell_info->currentDrive];
+ uint8 ds = tarbell_info->side[tarbell_info->currentDrive];
/*
** Side 0: tracks 0-76
@@ -725,8 +722,7 @@ static uint32 calculate_tarbell_sec_offset(uint8 track, uint8 sector)
*/
if (track==0) {
offset=0;
- }
- else {
+ } else {
offset=TARBELL_SPT_SD * TARBELL_SECTOR_LEN; /* Track 0 / Side 0 always SD */
offset+=(track-1) * secs_per_track(track) * TARBELL_SECTOR_LEN; /* Track 1-153 */
}
@@ -736,7 +732,7 @@ static uint32 calculate_tarbell_sec_offset(uint8 track, uint8 sector)
*/
offset += (sector-1)*TARBELL_SECTOR_LEN;
- DBG_PRINT(("TARBELL: OFFSET drive=%d side=%d den=%d track=%03d sector=%03d\n", tarbell_info->currentDrive, ds, dd, track, sector));
+ DBG_PRINT(("TARBELL: OFFSET drive=%d side=%d den=%d track=%03d sector=%03d\n", tarbell_info->currentDrive, ds, tarbell_info->doubleDensity[tarbell_info->currentDrive], track, sector));
return (offset);
}
@@ -773,7 +769,6 @@ static uint8 TARBELL_Read(uint32 Addr)
FD17XX_REG *pFD17XX;
UNIT *uptr;
- cData = 0;
driveNum = tarbell_info->currentDrive;
uptr = tarbell_info->uptr[driveNum];
pFD17XX = &tarbell_info->FD17XX;
@@ -801,29 +796,25 @@ static uint8 TARBELL_Read(uint32 Addr)
pFD17XX->dataCount = 0;
pFD17XX->status = 0x00;
pFD17XX->intrq = TRUE;
- }
- else {
+ } else {
pFD17XX->status |= FD17XX_STAT_DRQ; /* Another byte is ready */
}
TARBELL_HeadLoad(uptr, pFD17XX, TRUE);
- }
- else if (pFD17XX->readTrkActive) {
+ } else if (pFD17XX->readTrkActive) {
/* If we reached the end of the track data, terminate command and set INTRQ */
if (pFD17XX->trkCount == bytes_per_track(pFD17XX->track)) {
pFD17XX->readTrkActive = FALSE;
pFD17XX->status = 0x00;
pFD17XX->intrq = TRUE;
- }
- else {
+ } else {
pFD17XX->trkCount++;
pFD17XX->status |= FD17XX_STAT_DRQ; /* Another byte is ready */
}
TARBELL_HeadLoad(uptr, pFD17XX, TRUE);
- }
- else if (pFD17XX->addrActive) {
+ } else if (pFD17XX->addrActive) {
/* Store byte in DATA register */
pFD17XX->data = sdata[pFD17XX->dataCount++];
@@ -834,8 +825,7 @@ static uint8 TARBELL_Read(uint32 Addr)
pFD17XX->addrActive = FALSE;
pFD17XX->status = 0x00;
pFD17XX->intrq = TRUE;
- }
- else {
+ } else {
pFD17XX->status |= FD17XX_STAT_DRQ; /* Another byte is ready */
}
@@ -912,14 +902,12 @@ static uint8 TARBELL_Write(uint32 Addr, int32 Data)
pFD17XX->writeActive = FALSE;
pFD17XX->dataCount = 0;
pFD17XX->intrq = TRUE;
- }
- else {
+ } else {
pFD17XX->status |= FD17XX_STAT_DRQ; /* Ready for another byte */
}
TARBELL_HeadLoad(uptr, pFD17XX, TRUE);
- }
- else if (pFD17XX->writeTrkActive) {
+ } else if (pFD17XX->writeTrkActive) {
if (pFD17XX->dataAddrMrk) {
/* Store DATA register in Sector Buffer */
@@ -957,8 +945,7 @@ static uint8 TARBELL_Write(uint32 Addr, int32 Data)
if (pFD17XX->trkCount < bytes_per_track(pFD17XX->track)) {
pFD17XX->status |= FD17XX_STAT_DRQ; /* Ready for another byte */
- }
- else {
+ } else {
pFD17XX->status = 0x00; /* Clear Status Bits */
pFD17XX->intrq = TRUE;
pFD17XX->status &= ~FD17XX_STAT_BUSY; /* Clear BUSY Bit */
@@ -1140,8 +1127,7 @@ static uint8 TARBELL_Command(UNIT *uptr, FD17XX_REG *pFD17XX, int32 Data)
TARBELL_HeadLoad(uptr, pFD17XX, (Data & TARBELL_FLAG_H) ? TRUE : FALSE);
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": SEEK track=%03d\n", pFD17XX->track);
- }
- else {
+ } else {
pFD17XX->status |= FD17XX_STAT_SEEKERROR;
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": SEEK ERR track=%03d\n", newTrack);
}
@@ -1162,8 +1148,7 @@ static uint8 TARBELL_Command(UNIT *uptr, FD17XX_REG *pFD17XX, int32 Data)
pFD17XX->track = newTrack;
}
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEP track=%03d\n", pFD17XX->track);
- }
- else {
+ } else {
pFD17XX->status |= FD17XX_STAT_SEEKERROR;
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEP ERR track=%03d\n", newTrack);
}
@@ -1187,8 +1172,7 @@ static uint8 TARBELL_Command(UNIT *uptr, FD17XX_REG *pFD17XX, int32 Data)
TARBELL_HeadLoad(uptr, pFD17XX, (Data & TARBELL_FLAG_H) ? TRUE : FALSE);
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPIN track=%03d\n", pFD17XX->track);
- }
- else {
+ } else {
pFD17XX->status |= FD17XX_STAT_SEEKERROR;
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPIN ERR track=%03d\n", pFD17XX->track+1);
}
@@ -1211,8 +1195,7 @@ static uint8 TARBELL_Command(UNIT *uptr, FD17XX_REG *pFD17XX, int32 Data)
TARBELL_HeadLoad(uptr, pFD17XX, (Data & TARBELL_FLAG_H) ? TRUE : FALSE);
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPOUT track=%03d\n", pFD17XX->track);
- }
- else {
+ } else {
pFD17XX->status |= FD17XX_STAT_SEEKERROR;
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPOUT ERR track=%03d\n", pFD17XX->track-1);
}
@@ -1241,8 +1224,7 @@ static uint8 TARBELL_Command(UNIT *uptr, FD17XX_REG *pFD17XX, int32 Data)
pFD17XX->readActive = TRUE;
showdata(TRUE);
- }
- else {
+ } else {
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": sim_fread errno=%d\n", errno);
pFD17XX->status |= FD17XX_STAT_NOTFOUND;
@@ -1266,8 +1248,7 @@ static uint8 TARBELL_Command(UNIT *uptr, FD17XX_REG *pFD17XX, int32 Data)
if ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) {
DBG_PRINT((TARBELL_SNAME ": Disk write protected. uptr->flags=%04x writeProtect=%04x\n", uptr->flags & UNIT_TARBELL_WPROTECT, tarbell_info->writeProtect));
pFD17XX->intrq = TRUE;
- }
- else {
+ } else {
pFD17XX->writeActive = TRUE;
pFD17XX->dataCount = 0;
pFD17XX->status |= FD17XX_STAT_DRQ; /* Set DRQ */
@@ -1300,8 +1281,7 @@ static uint8 TARBELL_Command(UNIT *uptr, FD17XX_REG *pFD17XX, int32 Data)
if ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) {
DBG_PRINT((TARBELL_SNAME ": Disk write protected. uptr->flags=%04x writeProtect=%04x\n", uptr->flags & UNIT_TARBELL_WPROTECT, tarbell_info->writeProtect));
pFD17XX->intrq = TRUE;
- }
- else {
+ } else {
pFD17XX->writeTrkActive = TRUE;
pFD17XX->trkCount=0;
pFD17XX->dataCount=0;
diff --git a/Visual Studio Projects/AltairZ80.vcproj b/Visual Studio Projects/AltairZ80.vcproj
index 0abaac44..d1b279e2 100644
--- a/Visual Studio Projects/AltairZ80.vcproj
+++ b/Visual Studio Projects/AltairZ80.vcproj
@@ -331,6 +331,10 @@
RelativePath="..\AltairZ80\s100_if3.c"
>
+
+
diff --git a/doc/altairz80_doc.pdf b/doc/altairz80_doc.pdf
index 11026be2..37b91461 100644
Binary files a/doc/altairz80_doc.pdf and b/doc/altairz80_doc.pdf differ
diff --git a/makefile b/makefile
index 9fb7debc..0da33c1d 100644
--- a/makefile
+++ b/makefile
@@ -1736,6 +1736,7 @@ ALTAIRZ80 = ${ALTAIRZ80D}/altairz80_cpu.c ${ALTAIRZ80D}/altairz80_cpu_nommu.c \
${ALTAIRZ80D}/mfdc.c ${ALTAIRZ80D}/n8vem.c ${ALTAIRZ80D}/vfdhd.c \
${ALTAIRZ80D}/s100_disk1a.c ${ALTAIRZ80D}/s100_disk2.c ${ALTAIRZ80D}/s100_disk3.c \
${ALTAIRZ80D}/s100_fif.c ${ALTAIRZ80D}/s100_mdriveh.c \
+ ${ALTAIRZ80D}/s100_icom.c \
${ALTAIRZ80D}/s100_jadedd.c \
${ALTAIRZ80D}/s100_mdsa.c \
${ALTAIRZ80D}/s100_mdsad.c ${ALTAIRZ80D}/s100_selchan.c \