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 \