AltairZ80: New iCOM device, PTP port command, code cleanup

This commit is contained in:
Peter Schorn 2020-11-28 14:02:01 +01:00
parent 26f9c7a748
commit 5211c1134a
13 changed files with 2021 additions and 483 deletions

View file

@ -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);
}

View file

@ -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)

View file

@ -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,

View file

@ -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;

View file

@ -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,

View file

@ -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;

View file

@ -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,15 +440,11 @@ 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;
if (xptr != NULL) {
switch (xptr->oreg1 & HAYES_BMSK) {
switch (hayes_ctx.oreg1 & HAYES_BMSK) {
case HAYES_5BIT:
b = '5';
break;
@ -481,7 +463,7 @@ static t_stat hayes_config_line(UNIT *uptr)
break;
}
switch (xptr->oreg1 & HAYES_PMSK) {
switch (hayes_ctx.oreg1 & HAYES_PMSK) {
case HAYES_OPAR:
p = 'O';
break;
@ -495,7 +477,7 @@ static t_stat hayes_config_line(UNIT *uptr)
break;
}
switch (xptr->oreg1 & HAYES_SMSK) {
switch (hayes_ctx.oreg1 & HAYES_SMSK) {
case HAYES_2SB:
s = '2';
break;
@ -506,9 +488,9 @@ static t_stat hayes_config_line(UNIT *uptr)
break;
}
sprintf(config, "%d-%c%c%c", xptr->baud, b,p,s);
sprintf(config, "%d-%c%c%c", hayes_ctx.baud, b,p,s);
r = tmxr_set_config_line(xptr->tmln, config);
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);
@ -531,35 +513,29 @@ static t_stat hayes_config_line(UNIT *uptr)
** 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 */
}
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);
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 (!xptr->dtr && flag) {
r = tmxr_set_get_modem_bits(xptr->tmln, TMXR_MDM_DTR, 0, NULL);
} 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");
}
xptr->dtr = flag;
}
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);

1462
AltairZ80/s100_icom.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -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,15 +504,11 @@ 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;
if (xptr != NULL) {
switch (xptr->oreg0 & PMMI_BMSK) {
switch (pmmi_ctx.oreg0 & PMMI_BMSK) {
case PMMI_5BIT:
b = '5';
break;
@ -553,7 +527,7 @@ static t_stat pmmi_config_line(UNIT *uptr)
break;
}
switch (xptr->oreg0 & PMMI_PMSK) {
switch (pmmi_ctx.oreg0 & PMMI_PMSK) {
case PMMI_OPAR:
p = 'O';
break;
@ -568,7 +542,7 @@ static t_stat pmmi_config_line(UNIT *uptr)
break;
}
switch (xptr->oreg0 & PMMI_SMSK) {
switch (pmmi_ctx.oreg0 & PMMI_SMSK) {
case PMMI_2SB:
s = '2';
break;
@ -579,9 +553,9 @@ static t_stat pmmi_config_line(UNIT *uptr)
break;
}
sprintf(config, "%d-%c%c%c", xptr->baud, b,p,s);
sprintf(config, "%d-%c%c%c", pmmi_ctx.baud, b,p,s);
r = tmxr_set_config_line(xptr->tmln, config);
r = tmxr_set_config_line(pmmi_ctx.tmln, config);
sim_debug(STATUS_MSG, uptr->dptr, "port configuration set to '%s'.\n", config);
@ -600,9 +574,8 @@ static t_stat pmmi_config_line(UNIT *uptr)
** 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 */
}
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");
}
}

View file

@ -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;

View file

@ -331,6 +331,10 @@
RelativePath="..\AltairZ80\s100_if3.c"
>
</File>
<File
RelativePath="..\AltairZ80\s100_icom.c"
>
</File>
<File
RelativePath="..\AltairZ80\s100_jadedd.c"
>

Binary file not shown.

View file

@ -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 \