diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index ec7732c0..49eed930 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -106,6 +106,7 @@ #define MEMSIZE (cpu_unit.capac) #define ADDR_IS_MEM(x) (((t_addr) (x)) < cpu_memsize) /* use only in sim! */ #define DMASK 0177777 +#define BMASK 0377 /* CPU models */ @@ -633,6 +634,8 @@ typedef struct pdp_dib DIB; #define INT_V_VTCH 15 #define INT_V_VTNM 16 #define INT_V_LK 17 +#define INT_V_TDRX 18 +#define INT_V_TDTX 19 #define INT_V_PIR3 0 /* BR3 */ #define INT_V_PIR2 0 /* BR2 */ @@ -690,6 +693,8 @@ typedef struct pdp_dib DIB; #define INT_PIR3 (1u << INT_V_PIR3) #define INT_PIR2 (1u << INT_V_PIR2) #define INT_PIR1 (1u << INT_V_PIR1) +#define INT_TDRX (1u << INT_V_TDRX) +#define INT_TDTX (1u << INT_V_TDTX) #define INT_INTERNAL7 (INT_PIR7) #define INT_INTERNAL6 (INT_PIR6 | INT_CLK) @@ -744,6 +749,8 @@ typedef struct pdp_dib DIB; #define IPL_VTCH 4 #define IPL_VTNM 4 #define IPL_LK 4 /* XXX just a guess */ +#define IPL_TDRX 4 +#define IPL_TDTX 4 #define IPL_PIR7 7 #define IPL_PIR6 6 diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c index 74aac1c3..757759f1 100644 --- a/PDP11/pdp11_io_lib.c +++ b/PDP11/pdp11_io_lib.c @@ -591,7 +591,7 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */ 014240, 014250, 014260, 014270, 014300, 014310, 014320, 014330, 014340, 014350, 014360, 014370} }, /* DC11 - fx CSRs */ - { { NULL }, 1, 2, 0, 8, + { { "TDC" }, 1, 2, 0, 8, {016500, 016510, 016520, 016530, 016540, 016550, 016560, 016570, 016600, 016610, 016620, 016630, diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index c359477f..c0d851ec 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -82,6 +82,7 @@ extern DEVICE dli_dev; extern DEVICE dlo_dev; extern DEVICE dci_dev; extern DEVICE dco_dev; +extern DEVICE tdc_dev; extern DEVICE dz_dev; extern DEVICE vh_dev; extern DEVICE dt_dev; @@ -145,6 +146,7 @@ DEVICE *sim_devices[] = { &ptp_dev, &tti_dev, &tto_dev, + &tdc_dev, &cr_dev, &lpt_dev, &dli_dev, diff --git a/PDP11/pdp11_td.c b/PDP11/pdp11_td.c new file mode 100644 index 00000000..bd00bfc5 --- /dev/null +++ b/PDP11/pdp11_td.c @@ -0,0 +1,1455 @@ +/* pdp11_td.c: TU58 simulator + + Copyright (c) 2015, Mark Pizzolato + + 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 + ROBERT M SUPNIK 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 Mark Pizzolato shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Mark Pizzolato. + + td TU58 DECtape + + 26-Jun-15 MP Initial Unibus/Qbus implemention merged from + vax730_stddev.c (done by Matt Burke) and pdp11_dl.c + Added support for multiple concurrent TU58 devices + This module implements the TU58 functionality for the + VAX730 and VAX750 console devices as well as + Unibus/Qbus connected dual drive TU58s. + + PDP-11 TU58 DECtapes are represented in memory by fixed length buffer of 32b words. + + 16b 256 words per block [256 x 16b] + +Extracted from the TU58 DECtape II User's Guide - Programming Chapter: + +3.1 GENERAL PRINCIPLES + +The TU58 is controlled by a microprocessor that frees the host computer from device-related operations, +such as tape positioning and error retry. Only one high-level command to the microprocessor is necessary to +initiate a complex operation. The host and ru58 communicate via strings of one or more bytes called +packets. One brief packet can contain a message which completely describes a high-level command. The +handshaking sequences between host and TU58 as well as packet format are defined by the radial serial +protocol (RSP), or the modified radial serial protocol (MRSP), and were designed to be suitable for transmission +by asynchronous interfaces. + +3.1.1 Block Number, Byte Count, and Drive Number +The TU58 uses a drive number, block number, and byte count to write or read data. Figure 1-4 (Chapter 1) +shows the locations of blocks on the tape. If all of the desired data is contained within a single 512-byte +block, the byte count will be 512 or less. When the host asks for a particular block and a 512-or-Iess byte +count, the TU58 positions the specified drive (unit) at that block and transfers the number of bytes specified. +If the host asks for a block and also a byte count greater than that of the 512-byte boundary, the +TU58 reads as many sequential blocks as are needed to fulfill the byte count. The same process applies to +the write function. This means that the host software or an on-tape file directory need only store the number +of the first block in a file and the file's byte count to read or write all the data without having to know +the additional block numbers. + +3.1.2 Special Handler Functions +Some device-related functions are not dealt with directly in the RSP, the MRSP, or in the ru58 firmware. + 1. A short routine called Newtape (Appendix B) should be included in a TU58 handler to provide a + complete wind-rewind for new or environmentally stressed tape cartridges. This procedure + brings the tape to proper operating tension levels. + 2. A TU58 handler should check the success code (byte 3 of the RSP or MRSP end message) for + the presence of soft errors. This enables action to be taken before hard errors (permanent data + losses) occur. + +3.2 RADIAL SERIAL PROTOCOL (RSP) AND MODIFIED RSP (MRSP) + +3.2.1 Packets +All communication between the host and the TU58 is accomplished via sequences of bytes called packets. +There are two types of multi-byte packets: Control (Command) and Data. Either RSP or MRSP may be +selected using the command packet switch byte. In addition, there are three single-byte packets used to +manage protocol and control the state of the system: INIT, Continue, and XOFF. + +Control (Command) - A Control packet is sent to the TU58 to initiate all operations. The packet + contains a message completely describing the operation to be performed. In the case of a read or + write operation, for example, the message includes the function to be performed, unit (drive) number, + byte count and block number. + + A special case of the Control packet, called an End packet, is sent from the TU58 to the host after + completion of an operation or on an error. The End packet includes the status of the completed or + aborted operation. + +Data - The Data packet holds messages of between 1 and 128 bytes. This message is actually the + data transferred from or to the TU58 during a read or write operation. For transmissions of larger + than 128 bytes, the transfer is broken up and sent 128 bytes at a time. + +INIT - This single-byte packet is sent to the TU58 to cause the power-up sequence. The TU58 + returns Continue after completion, to indicate that the power-up sequence has occurred. When the + TU5S makes a protocol error or receives an invalid command, it reinitializes and sends INIT continuously + to the host. When the host recognizes INIT, it sends Break to the TU58 to restore the + protocol. + +Bootstrap - A flag byte saying Bootstrap (octal 10), followed by a byte containing a drive number, + causes the TU58 to read block 0 of the selected drive. It returns the 512 bytes without radial serial + packaging. This simplifies bootstrap operations. Bootstrap may be sent by the host instead of a + second INIT as part of the initialization process described below. + +Continue - Before the host sends a Data packet to the TU58, it must wait until the TUS8 sends + Continue. This permits the TU58 to control the rate that data packets are sent to it. + +XON - An alternate term for Continue. + +XOFF - Ordinarily, the TU58 does not have to wait between messages to the host. However, if the + host is unable to receive all of a message from the peripheral at once, it may send XOFF. The + TU58 stops transmitting immediately and waits until the host sends Continue to complete the + transfer when it is ready. (Two characters may be sent by the UART to the host after the TUS8 + receives XOFF.) + +3.2.1.1 Packet Usage - Position within the packet determines the meaning of each byte. All packets +begin with a flag byte, which announces the type of packet to follow. Flag byte numeric assignments +are as follows. + + Packet Type Flag Byte Value + Octal Binary + Data 01 00001 + Control (Command) 02 00010 + INIT 04 00100 + Bootstrap 10 01000 + Continue 20 10000 + XON 21 10001 + XOFF 23 10011 + +(Bits 5 - 7 of the nag byte are reserved.) + +Multiple-byte (Control and Data) packets also contain a byte count byte, message bytes, and two checksum +bytes. The byte count byte is the number of message bytes in the packet. The two checksum bytes +are a 16-bit checksum. The checksum is formed by summing successive byte-pairs taken as 16-bit words +while adding any carry back into the sum (end-around carry), The flag and byte count bytes are included +in the checksum. (See example in Appendix 8.) + +3.2.1 Break and Initialization +Break is a unique logic entity that can be interpreted by the TU58 and the host regardless of the state +of the protocol. This is the logical equivalent of a bus init or a master reset. Break is transmitted when +the serial line, which normally switches between two logic states called mark and space, is kept in the +space condition for at least one character time. This causes the TU58's UART to set its framing error +bit. The TU58 interprets the framing error as Break. + +If communications break· down, due to any transient problem, the host may restore order by sending +Break and IN IT as outlined above. The faulty operations are cancelled, and the TU58 reinitializes itself, +returns Continue, and waits for instructions. + +With DIGITAL serial interfaces, the initialize sequence may be sent by the following sequence of operations. +Set the Break bit in the transmit control status register, then send two null characters. When the +transmit ready flag is set again, remove the Break bit. This times Break to be one character time long. +The second character is discarded by the TU58controller. Next, send two INIT characters. The first is +discarded by the TU58. The TU58 responds to the second INIT by sending Continue. When Continue +has been received, the initialize sequence is complete and any command packet may follow. + +3.2.3 Command Packets +The command packet format is shown in Table 3-1. Bytes 0, 1, 12, and 13 are the message delivery +bytes. Their definitions follow. + + Table 3-1 Command Packet Structure + Byte Byte Contents + o Flag = 0000 0010(028) + 1 Message Byte Count = 0000 101 O( 128) + 2 Op Code + 3 Modifier + 4 Unit Number + 5 Switches + 6 Sequence Number - Low + 7 Sequence Number - High + 8 Byte Count - Low + 9 Byte Count - High + 10 Block Number - Low + 11 Block Number - High + 12 Checksum - Low + 13 Checksum - High + + 0 Flag This byte is set to 00000010 to indicate + that the packet is a Command packet. + 1 Message Byte Count Number of bytes in the packet, excluding the four message delivery + bytes. This is decimal 10 for all command packets. + 12, 13 Checksum The 16-bit checksum of bytes 0 through 11. The checksum is + formed by treating each pair of bytes as a word and summing + words with end-around carry. + + The remaining bytes are defined below. + 2 Op Code Operation being commanded. (See Table 34 and Paragraph 3.3 + for definitions.) + 3 Modifier Permits variations of commands. + 4 Unit Number Selects drive 0 or I. + 5 Switches Selects maintenance mode and specifies RSP or MRSP. + 6,7 Sequence Number Always zero for TU58. + 8,9 Byte Count Number of bytes to be transferred by a read or write command. + Ignored by other commands. + 10,11 Block Numbet The block number to be used by commands requiring tape positioning. + +3.1.3.1 Maintenance Mode - Setting bit 4 of the switches byte (byte 5) to I in a read command inhibits +retries on data errors. Instead, the incorrect data is delivered to the host followed by an end packet. +The success code in the end packet indicates a hard dt~.ta error. Since data is transmitted in 128-byte +packets, a multiple packet read progresses normally until a checksum mismatch occurs. Then the bad +data packet is transmitted, followed by the end packet, and the operation terminates. + +3.1.3.1 Special Address Mode - Setting the most significant bit of the modifier byte (byte 3) to 1 +selects special address mode. In this mode all tape positioning operations are addressed by 128-byte +records (0-2047) instead of 512-byte blocks (0-511). Zero-fill in a write operation only fills out to a 128- +byte boundary in this mode. To translate between normal addressing and special addressing, multiply +the normal address by 4. The result is the address of the first I 28-byte record of the block. Add I, 2, or +3 to get to the next three 128-byte records. + +3.1.4 Data Packets + +3.1.4.1 Radial Serial Protocol-A data transfer operation uses three or more message packets. The first +packet is the command packet from host to the TU58. Next, the data is transferred in 128-byte packets in +either direction (as required by read or write). After all data is transferred, the TU58 sends an end packet. +If the TUS8 encounters a failure before all data has been transferred, it sends the end packet as soon as the +failure occurs. + +The data packet is shown in Table 3-2. The flag byte is set to 0018. The number of data bytes may be +between 1 and 128 bytes. For data transfers larger than 128 bytes, the transaction is broken up and sent +128 bytes at a time. The host is assumed to have enough buffer capacity to accept the entire transaction, +whereas the TU58 only has 128 bytes of buffer space. For write commands, the host must wait between +message packets for the TU58 to send the Continue flag 0208 before sending the next packet. Because the +host has enough buffer space, the TU58 does not wait for a Continue flag between message packets when it +sends back read data. + +3.1.4.2 Modified Radial Serial Protocol- When the host does not have sufficient buffer space to accept +entire transactions at the hardware selected data transfer rate, modified radial serial protocol (MRSP) may +be specified using the command packet switch byte. Bit 3 of the switch byte is set to specify the MRSP. Bit +3 remains set until intentionally cleared or cleared during power up. A good practice is to set bit 3 in every +MRSP command packet. +MRSP is identical to RSP except during transmission to the host. When a command packet specifies +MRSP for the first time (that is, bit 3 of the switch byte was previously cleared or cleared during power +up), the ru58 will send one data or end packet byte (whichever occurs first). The subsequent bytes, up to +and including the last byte of the end packet, will not be transmitted until a Continue or an XON is +received from the host. To prevent a protocol error from occurring, it is necessary to transmit Continue or . +XON before transmitting any command packets. If a protocol error is detected, continuous INITs are sent +with the Continue handshake. If a bootstrap is being transmitted, however, no handshake is employed. + +3.2.5 End Packets +The end packet is sent to the host by the ru58 after completion or termination of an operation or an error. +End packets are sent using RSP or MRSP as specified by the last command packet. The end packet is +shown in Table 3-3. + + Table 3-1 Data Packets + Byte Byte Contents + 0 Flag = 0000 0001 + 1 Byte Count = M + ----------------- + 2 First Data Byte + 3 Data + + M Data + M+1 Last Data Byte + ----------------- + M+2 Checksum L + M+3 Checksum H + + Table 3-3 End Packet + Byte Byte Contents + 0 Flag = 0000 0010 + 1 Byte Count = 0000 1010 + ----------------- + 2 Op Code - 0100 0000 + 3 Success Code + 4 Unit + 5 Not Used + 6 Sequence No. L + 7 Sequence No. H + 8 Actual Byte Count L + 9 Actual Byte Count H + 10 Summary Status L + 11 Summary Status H + ----------------- + 12 Checksum L + 13 Checksum H + +The definition of bytes 0, 1, 12, and 13 are the same as for the command packet. The remaining bytes +are defined as follows. + +Byte 2 Op Code - 0100 0000 for end packet +Byte 3 Success Code + Octal Decimal + 0 0 = Normal success + 1 1 = Success but with retries + 377 -1 = Failed self test + 376 -2 = Partial operation (end of medium) + 370 -8 = Bad unit number + 367 -9 = No cartridge + 365 -11 = Write protected + 357 -17 = Data check error + 340 -32 = Seek error (block not found) + 337 -33 = Motor stopped + 320 -48 = Bad opcode + 311 -55 = Bad block number (> 511) +Byte 4 Unit Number 0 or 1 for drive number. +Byte 5 Always 0 +Bytes 6,7 Sequence number - always 0 as in command packet. +Bytes 8,9 Actual byte count - number of bytes handled in transaction. In a 511) */ + +#define TD_GETOPC 0 /* get opcode state */ +#define TD_GETLEN 1 /* get length state */ +#define TD_GETDATA 2 /* get data state */ + +#define TD_IDLE 0 /* idle state */ +#define TD_READ 1 /* read */ +#define TD_READ1 2 /* fill buffer */ +#define TD_READ2 3 /* empty buffer */ +#define TD_WRITE 4 /* write */ +#define TD_WRITE1 5 /* write */ +#define TD_WRITE2 6 /* write */ +#define TD_END 7 /* empty buffer */ +#define TD_END1 8 /* empty buffer */ +#define TD_INIT 9 /* empty buffer */ + +static char *td_states[] = { + "IDLE", "READ", "READ1", "READ2", "WRITE", "WRITE1", "WRITE2", "END", "END1", "INIT" + }; + +static char *td_ops[] = { + "NOP", "INI", "RD", "WR", "004", "POS", "006", "DIA", + "GST", "SST", "MRSP", "013", "014", "015", "016", "017", + "020", "021", "022", "023", "024", "025", "026", "027", + "030", "031", "032", "033", "034", "035", "036", "037", + "040", "041", "042", "043", "044", "045", "046", "047", + "050", "051", "052", "053", "054", "055", "056", "057", + "060", "061", "062", "063", "064", "065", "066", "067", + "070", "071", "072", "073", "074", "075", "076", "077", + "END" + }; + +static char *td_csostates[] = { + "GETOPC", "GETLEN", "GETDATA" + }; + +static int32 td_stime = 100; /* seek, per block */ +static int32 td_ctime = 150; /* command time */ +static int32 td_xtime = 180; /* tr set time */ +static int32 td_itime = 180; /* init time */ + +static int32 td_regval; /* temp location used in reg declarations */ + +static int32 td_ctrls = 1; /* number of enabled controllers */ + +static uint32 tdi_ireq = 0; +static uint32 tdo_ireq = 0; + +struct CTLR { + DEVICE *dptr; + UNIT *uptr; + uint16 rx_csr; + uint16 rx_buf; + void (*rx_set_int) (int32 ctlr_num, t_bool val); + uint16 tx_csr; + uint16 tx_buf; + void (*tx_set_int) (int32 ctlr_num, t_bool val); + uint8 ibuf[TD_NUMBY+1]; /* input buffer */ + int32 ibptr; /* input buffer pointer */ + int32 ilen; /* input length */ + uint8 obuf[TD_NUMBY+1]; /* output buffer */ + int32 obptr; /* output buffer pointer */ + int32 olen; /* output length */ + int32 block; /* current block number */ + int32 txsize; /* remaining transfer size */ + int32 offset; /* offset into current transfer */ + int32 p_state; /* protocol state */ + int32 o_state; /* output state */ + int32 unitno; /* active unit number */ + int32 ecode; /* end packet success code */ + }; + +static CTLR td_ctlr[TD_NUMCTLR+1]; /* one for each DL based TU58 plus console */ + +static t_stat td_rd (int32 *data, int32 PA, int32 access); +static t_stat td_wr (int32 data, int32 PA, int32 access); +static t_stat td_svc (UNIT *uptr); +static t_stat td_reset (DEVICE *dptr); +static t_stat td_set_ctrls (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat td_show_ctlrs (FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat td_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +static void tdi_set_int (int32 ctlr, t_bool val); +static int32 tdi_iack (void); +static void tdo_set_int (int32 ctlr, t_bool val); +static int32 tdo_iack (void); + +static const char *td_description (DEVICE *dptr); + +static void td_process_packet(CTLR *ctrl); +static t_bool td_test_xfr (UNIT *uptr, int32 state); + +/* TU58 data structures + + td_dev TD device descriptor + td_unit TD unit list + td_reg TD register list + td_mod TD modifier list +*/ + +#define IOLN_DL 010 + +static DIB td_dib = { + IOBA_AUTO, IOLN_DL, &td_rd, &td_wr, + 2, IVCL (TDRX), VEC_AUTO, { &tdi_iack, &tdo_iack }, IOLN_DL, + }; + +static UNIT td_unit[2*TD_NUMCTLR]; + +static REG td_reg[] = { + { DRDATAD (CTRLRS, td_ctrls, 4, "number of controllers"), REG_HRO }, + { HRDATAD (ECODE, td_regval, 8, "end packet success code") }, + { HRDATAD (BLOCK, td_regval, 8, "current block number") }, + { HRDATAD (RX_CSR, td_regval,16, "input control/status register") }, + { HRDATAD (RX_BUF, td_regval,16, "input buffer register") }, + { HRDATAD (TX_CSR, td_regval,16, "output control/status register") }, + { HRDATAD (TX_BUF, td_regval,16, "output buffer register") }, + { DRDATAD (P_STATE,td_regval, 4, "protocol state"), REG_RO }, + { DRDATAD (O_STATE,td_regval, 4, "output state"), REG_RO }, + { DRDATAD (IBPTR, td_regval, 9, "input buffer pointer") }, + { DRDATAD (OBPTR, td_regval, 9, "output buffer pointer") }, + { DRDATAD (ILEN, td_regval, 9, "input length") }, + { DRDATAD (OLEN, td_regval, 9, "output length") }, + { DRDATAD (TXSIZE, td_regval, 9, "remaining transfer size") }, + { DRDATAD (OFFSET, td_regval, 9, "offset into current transfer") }, + { DRDATAD (CTIME, td_regval,24, "command time"), PV_LEFT }, + { DRDATAD (STIME, td_regval,24, "seek, per block"), PV_LEFT }, + { DRDATAD (XTIME, td_regval,24, "tr set time"), PV_LEFT }, + { DRDATAD (ITIME, td_regval,24, "init time"), PV_LEFT }, + { BRDATAD (IBUF, &td_regval,16, 8, 512, "input buffer"), }, + { BRDATAD (OBUF, &td_regval,16, 8, 512, "output buffer"), }, + { NULL } + }; + +static MTAB td_mod[] = { + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL, "Write enable TU58 drive" }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL, NULL, NULL, "Write lock TU58 drive" }, + { MTAB_XTD | MTAB_VDV, 0, "CONTROLLERS", "CONTROLLERS", &td_set_ctrls, &td_show_ctlrs, NULL, "Number of Controllers" }, + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, &set_addr, &show_addr, NULL, "Bus address" }, + { MTAB_XTD|MTAB_VDV, 1, "VECTOR", NULL, &set_vec, &show_vec, NULL, "Interrupt vector" }, + { 0 } + }; + +DEVICE tdc_dev = { + "TDC", td_unit, td_reg, td_mod, + 2*TD_NUMCTLR, DEV_RDX, 20, 1, DEV_RDX, 8, + NULL, NULL, &td_reset, + NULL, NULL, NULL, + &td_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG, 0, + td_deb, NULL, NULL, &td_help, NULL, NULL, + &td_description + }; + +#define CSI_CLR_INT ctlr->rx_set_int (ctlr-td_ctlr, 0) +#define CSI_SET_INT ctlr->rx_set_int (ctlr-td_ctlr, 1) +#define CSO_CLR_INT ctlr->tx_set_int (ctlr-td_ctlr, 0) +#define CSO_SET_INT ctlr->tx_set_int (ctlr-td_ctlr, 1) + +t_stat td_rd_i_csr (CTLR *ctlr, int32 *data) +{ +*data = ctlr->rx_csr & DLICSR_RD; +sim_debug_bits_hdr(TDDEB_IRD, ctlr->dptr, "RX_CSR", rx_csr_bits, *data, *data, 1); +return SCPE_OK; +} + +t_stat td_wr_i_csr (CTLR *ctlr, int32 data) +{ +if ((data & CSR_IE) == 0) + CSI_CLR_INT; +else { + if ((ctlr->rx_csr & (CSR_DONE | CSR_IE)) == CSR_DONE) + CSI_SET_INT; + } +sim_debug_bits_hdr(TDDEB_IWR, ctlr->dptr, "RX_CSR", rx_csr_bits, ctlr->rx_csr, data, 1); +ctlr->rx_csr = (ctlr->rx_csr & ~DLICSR_WR) | (data & DLICSR_WR); +return SCPE_OK; +} + +t_stat td_rd_i_buf (CTLR *ctlr, int32 *data) +{ +int32 t = ctlr->rx_buf; + +ctlr->rx_csr &= ~CSR_DONE; /* clr done */ +ctlr->rx_buf &= BMASK; /* clr errors */ +sim_debug_bits_hdr(TDDEB_IRD, ctlr->dptr, "RX_BUF", rx_buf_bits, t, ctlr->rx_buf, 1); +CSI_CLR_INT; +*data = t; +return SCPE_OK; +} + +t_stat td_wr_i_buf (CTLR *ctlr, int32 data) +{ +sim_debug_bits_hdr(TDDEB_IWR, ctlr->dptr, "RX_BUF", rx_buf_bits, ctlr->rx_buf, ctlr->rx_buf, 1); +return SCPE_OK; +} + +t_stat td_rd_o_csr (CTLR *ctlr, int32 *data) +{ +sim_debug_bits_hdr(TDDEB_ORD, ctlr->dptr, "TX_CSR", tx_csr_bits, ctlr->tx_csr, ctlr->tx_csr, 1); +*data = ctlr->tx_csr & DLOCSR_RD; +return SCPE_OK; +} + +t_stat td_wr_o_csr (CTLR *ctlr, int32 data) +{ +sim_debug_bits_hdr(TDDEB_OWR, ctlr->dptr, "TX_CSR", tx_csr_bits, data, data, 1); +if ((ctlr->tx_csr & DLOCSR_XBR) && !(data & DLOCSR_XBR)) { + ctlr->ibptr = 0; + ctlr->ibuf[ctlr->ibptr++] = TD_OPINI; + td_process_packet(ctlr); /* check packet */ + } +if ((data & CSR_IE) == 0) + CSO_CLR_INT; +else if ((ctlr->tx_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + CSO_SET_INT; +ctlr->tx_csr = (ctlr->tx_csr & ~DLOCSR_WR) | (data & DLOCSR_WR); +return SCPE_OK; +} + +t_stat td_rd_o_buf (CTLR *ctlr, int32 *data) +{ +*data = 0; +sim_debug_bits_hdr(TDDEB_ORD, ctlr->dptr, "TX_BUF", tx_buf_bits, *data, *data, 1); +return SCPE_OK; +} + +t_stat td_wr_o_buf (CTLR *ctlr, int32 data) +{ +sim_debug (TDDEB_OWR, ctlr->dptr, "td_wr_o_buf() o_state=%s, ibptr=%d, ilen=%d\n", td_csostates[ctlr->o_state], ctlr->ibptr, ctlr->ilen); +sim_debug_bits_hdr(TDDEB_OWR, ctlr->dptr, "TX_BUF", tx_buf_bits, data, data, 1); +ctlr->tx_buf = data & BMASK; /* save data */ +ctlr->tx_csr &= ~CSR_DONE; /* clear flag */ +CSO_CLR_INT; + +switch (ctlr->o_state) { + + case TD_GETOPC: + ctlr->ibptr = 0; + ctlr->ibuf[ctlr->ibptr++] = ctlr->tx_buf & BMASK; + td_process_packet(ctlr); /* check packet */ + break; + + case TD_GETLEN: + ctlr->ibuf[ctlr->ibptr++] = ctlr->tx_buf & BMASK; + ctlr->ilen = ctlr->tx_buf + 4; /* packet length + header + checksum */ + ctlr->o_state = TD_GETDATA; + break; + + case TD_GETDATA: + ctlr->ibuf[ctlr->ibptr++] = ctlr->tx_buf & BMASK; + if (ctlr->ibptr >= ctlr->ilen) { + ctlr->o_state = TD_GETOPC; + td_process_packet(ctlr); + } + break; + } + +ctlr->tx_csr |= CSR_DONE; /* set input flag */ +if (ctlr->tx_csr & CSR_IE) + CSO_SET_INT; +return SCPE_OK; +} + + +static char *reg_access[] = {"Word", "Byte"}; + +typedef t_stat (*reg_read_routine) (CTLR *ctlr, int32 *data); + +static reg_read_routine td_rd_regs[] = { + td_rd_i_csr, + td_rd_i_buf, + td_rd_o_csr, + td_rd_o_buf + }; + +t_stat td_rd (int32 *data, int32 PA, int32 access) +{ +int32 ctlr = ((PA - td_dib.ba) >> 3); + +if (ctlr > td_ctrls) /* validate controller number */ + return SCPE_IERR; + +if (PA & 1) /* odd address reference? */ + return SCPE_OK; + +sim_debug (TDDEB_RRD, &tdc_dev, "td_rd(PA=%X(%s), access=%d-%s)\n", PA, tdc_regnam[(PA >> 1) & 03], access, reg_access[access]); + +return (td_rd_regs[(PA >> 1) & 03])(&td_ctlr[ctlr], data); +} + +typedef t_stat (*reg_write_routine) (CTLR *ctlr, int32 data); + +static reg_write_routine td_wr_regs[] = { + td_wr_i_csr, + td_wr_i_buf, + td_wr_o_csr, + td_wr_o_buf + }; + +static t_stat td_wr (int32 data, int32 PA, int32 access) +{ +int32 ctrl = ((PA - td_dib.ba) >> 3); + +if (ctrl > td_ctrls) /* validate line number */ + return SCPE_IERR; + +sim_debug (TDDEB_RWR, &tdc_dev, "td_wr(PA=%X(%s), access=%d-%s, data=%X)\n", PA, tdc_regnam[(PA >> 1) & 03], access, reg_access[access], data); + +if (PA & 1) /* odd address reference? */ + return SCPE_OK; + +sim_debug_bits_hdr (TDDEB_RWR, &tdc_dev, tdc_regnam[(PA >> 1) & 03], td_reg_bits[(PA >> 1) & 03], data, data, 1); + +return td_wr_regs[(PA >> 1) & 03](&td_ctlr[ctrl], data); +} + +static void td_process_packet(CTLR *ctlr) +{ +uint32 unit; +int32 opcode = ctlr->ibuf[0]; +char *opcode_name, *command_name; + +switch (opcode) { + case TD_OPDAT: + opcode_name = "OPDAT"; + break; + case TD_OPCMD: + opcode_name = "OPCMD"; + break; + case TD_OPINI: + opcode_name = "OPINI"; + break; + case TD_OPBOO: + opcode_name = "OPBOO"; + break; + case TD_OPCNT: + opcode_name = "OPCNT"; + break; + case TD_OPXOF: + opcode_name = "OPXOF"; + break; + default: + opcode_name = "unknown"; + } +sim_debug (TDDEB_TRC, ctlr->dptr, "td_process_packet() Opcode=%s(%d)\n", opcode_name, opcode); +switch (opcode) { + + case TD_OPDAT: + if (ctlr->p_state != TD_WRITE1) { /* expecting data? */ + sim_printf("TU58 protocol error 1\n"); + return; + } + if (ctlr->ibptr < 2) { /* whole packet read? */ + ctlr->o_state = TD_GETLEN; /* get rest of packet */ + return; + } + ctlr->p_state = TD_WRITE2; + sim_activate (ctlr->uptr+ctlr->unitno, td_ctime); /* sched command */ + break; + + case TD_OPCMD: + if (ctlr->p_state != TD_IDLE) { /* expecting command? */ + sim_printf("TU58 protocol error 2\n"); + return; + } + if (ctlr->ibptr < 2) { /* whole packet read? */ + ctlr->o_state = TD_GETLEN; /* get rest of packet */ + return; + } + if (ctlr->ibuf[2] > TD_CMDEND) + command_name = "Unknown"; + else + command_name = td_ops[ctlr->ibuf[2]]; + sim_debug (TDDEB_OPS, ctlr->dptr, "strt: fnc=%d(%s), len=%d, unit=%d, block=%d, size=%d\n", ctlr->ibuf[2], command_name, ctlr->ibuf[1], ctlr->ibuf[4], ((ctlr->ibuf[11] << 8) | ctlr->ibuf[10]), ((ctlr->ibuf[9] << 8) | ctlr->ibuf[8])); + switch (ctlr->ibuf[2]) { + case TD_CMDNOP: /* NOP */ + case TD_CMDGST: /* Get status */ + case TD_CMDSST: /* Set status */ + ctlr->unitno = ctlr->ibuf[4]; + ctlr->p_state = TD_END; /* All treated as NOP */ + ctlr->ecode = TD_STSOK; + ctlr->offset = 0; + sim_activate (ctlr->uptr+ctlr->unitno, td_ctime);/* sched command */ + break; + + case TD_CMDINI: + sim_printf("Warning: TU58 command 'INIT' not implemented\n"); + break; + + case TD_CMDRD: + ctlr->unitno = ctlr->ibuf[4]; + ctlr->block = ((ctlr->ibuf[11] << 8) | ctlr->ibuf[10]); + ctlr->txsize = ((ctlr->ibuf[9] << 8) | ctlr->ibuf[8]); + ctlr->p_state = TD_READ; + ctlr->offset = 0; + sim_activate (ctlr->uptr+ctlr->unitno, td_ctime);/* sched command */ + break; + + case TD_CMDWR: + ctlr->unitno = ctlr->ibuf[4]; + ctlr->block = ((ctlr->ibuf[11] << 8) | ctlr->ibuf[10]); + ctlr->txsize = ((ctlr->ibuf[9] << 8) | ctlr->ibuf[8]); + ctlr->p_state = TD_WRITE; + ctlr->offset = 0; + sim_activate (ctlr->uptr+ctlr->unitno, td_ctime);/* sched command */ + break; + + case TD_CMDPOS: + sim_printf("Warning: TU58 command 'Position' not implemented\n"); + break; + + case TD_CMDDIA: + sim_printf("Warning: TU58 command 'Diagnose' not implemented\n"); + break; + + case TD_CMDMRSP: + ctlr->rx_buf = TD_OPDAT; + ctlr->rx_csr |= CSR_DONE; /* set input flag */ + if (ctlr->rx_csr & CSR_IE) + CSI_SET_INT; + break; + } + break; + + case TD_OPINI: + for (unit=0; unit < ctlr->dptr->numunits; unit++) + sim_cancel (ctlr->uptr+unit); + ctlr->ibptr = 0; + ctlr->obptr = 0; + ctlr->olen = 0; + ctlr->offset = 0; + ctlr->txsize = 0; + ctlr->o_state = TD_GETOPC; + ctlr->p_state = TD_INIT; + sim_activate (ctlr->uptr, td_itime); /* sched command */ + break; + + case TD_OPBOO: + if (ctlr->p_state != TD_IDLE) { + sim_printf("TU58 protocol error 3\n"); + return; + } + if (ctlr->ibptr < 2) { /* whole packet read? */ + ctlr->ilen = 2; + ctlr->o_state = TD_GETDATA; /* get rest of packet */ + return; + } + ctlr->unitno = ctlr->ibuf[4]; + ctlr->block = 0; + ctlr->txsize = 512; + ctlr->p_state = TD_READ; + ctlr->offset = 0; + sim_activate (ctlr->uptr+ctlr->unitno, td_ctime);/* sched command */ + break; + + case TD_OPCNT: + break; + + default: + //sim_printf("TU58: Unknown opcode %d\n", opcode); + break; + } +} + +static t_stat td_svc (UNIT *uptr) +{ +int32 i, t, data_size; +uint16 c, w; +uint32 da; +int8 *fbuf = uptr->filebuf; +CTLR *ctlr = (CTLR *)uptr->up7; + +sim_debug (TDDEB_TRC, ctlr->dptr, "td_svc(%s, p_state=%s)\n", sim_uname(uptr), td_states[ctlr->p_state]); +switch (ctlr->p_state) { /* case on state */ + + case TD_IDLE: /* idle */ + return SCPE_IERR; /* done */ + + case TD_READ: case TD_WRITE: /* read, write */ + if (td_test_xfr (uptr, ctlr->p_state)) { /* transfer ok? */ + t = abs (ctlr->block - 0); /* # blocks to seek */ + if (t == 0) /* minimum 1 */ + t = 1; + ctlr->p_state++; /* set next state */ + sim_activate (uptr, td_stime * t); /* schedule seek */ + break; + } + else + ctlr->p_state = TD_END; + sim_activate (uptr, td_xtime); /* schedule next */ + break; + + case TD_READ1: /* build data packet */ + da = (ctlr->block * 512) + ctlr->offset; /* get tape address */ + if (ctlr->txsize > 128) /* Packet length */ + data_size = 128; + else + data_size = ctlr->txsize; + ctlr->txsize = ctlr->txsize - data_size; + ctlr->offset = ctlr->offset + data_size; + + ctlr->obptr = 0; + ctlr->obuf[ctlr->obptr++] = TD_OPDAT; /* Data packet */ + ctlr->obuf[ctlr->obptr++] = data_size; /* Data length */ + for (i = 0; i < data_size; i++) /* copy sector to buf */ + ctlr->obuf[ctlr->obptr++] = fbuf[da + i]; + c = 0; + for (i = 0; i < (data_size + 2); i++) { /* Calculate checksum */ + w = (ctlr->obuf[i] << ((i & 0x1) ? 8 : 0)); + c = c + w + ( (uint32)((uint32)c + (uint32)w) > 0xFFFF ? 1 : 0); + } + ctlr->obuf[ctlr->obptr++] = (c & 0xFF); /* Checksum L */ + ctlr->obuf[ctlr->obptr++] = ((c >> 8) & 0xFF); /* Checksum H */ + ctlr->olen = ctlr->obptr; + ctlr->obptr = 0; + ctlr->p_state = TD_READ2; /* go empty */ + sim_activate (uptr, td_xtime); /* schedule next */ + break; + + case TD_READ2: /* send data packet to host */ + if ((ctlr->rx_csr & CSR_DONE) == 0) { /* prev data taken? */ + ctlr->rx_buf = ctlr->obuf[ctlr->obptr++]; /* get next byte */ + ctlr->rx_csr |= CSR_DONE; /* set input flag */ + if (ctlr->rx_csr & CSR_IE) + CSI_SET_INT; + if (ctlr->obptr >= ctlr->olen) { /* buffer empty? */ + if (ctlr->txsize > 0) + ctlr->p_state = TD_READ1; + else + ctlr->p_state = TD_END; + } + } + sim_activate (uptr, td_xtime); /* schedule next */ + break; + + case TD_WRITE1: /* send continue */ + if ((ctlr->rx_csr & CSR_DONE) == 0) { /* prev data taken? */ + ctlr->rx_buf = TD_OPCNT; + ctlr->rx_csr |= CSR_DONE; /* set input flag */ + if (ctlr->rx_csr & CSR_IE) + CSI_SET_INT; + break; + } + sim_activate (uptr, td_xtime); /* schedule next */ + break; + + case TD_WRITE2: /* write data to buffer */ + da = (ctlr->block * 512) + ctlr->offset; /* get tape address */ + ctlr->olen = ctlr->ibuf[1]; + for (i = 0; i < ctlr->olen; i++) /* write data to buffer */ + fbuf[da + i] = ctlr->ibuf[i + 2]; + ctlr->offset += ctlr->olen; + ctlr->txsize -= ctlr->olen; + da = da + ctlr->olen; + if (da > uptr->hwmark) /* update hwmark */ + uptr->hwmark = da; + if (ctlr->txsize > 0) + ctlr->p_state = TD_WRITE1; + else { /* check whole number of blocks written */ + if ((ctlr->olen = (512 - (ctlr->offset % 512))) != 512) { + for (i = 0; i < ctlr->olen; i++) + fbuf[da + i] = 0; /* zero fill */ + da = da + ctlr->olen; + if (da > uptr->hwmark) /* update hwmark */ + uptr->hwmark = da; + } + ctlr->p_state = TD_END; + } + sim_activate (uptr, td_xtime); /* schedule next */ + break; + + case TD_END: /* build end packet */ + ctlr->obptr = 0; + ctlr->obuf[ctlr->obptr++] = TD_OPCMD; /* Command packet */ + ctlr->obuf[ctlr->obptr++] = 0xA; /* ** Need definition ** */ + ctlr->obuf[ctlr->obptr++] = TD_CMDEND; + ctlr->obuf[ctlr->obptr++] = ctlr->ecode; /* Success code */ + ctlr->obuf[ctlr->obptr++] = ctlr->unitno; /* Unit number */ + ctlr->obuf[ctlr->obptr++] = 0; /* Not used */ + ctlr->obuf[ctlr->obptr++] = 0; /* Sequence L (not used) */ + ctlr->obuf[ctlr->obptr++] = 0; /* Sequence H (not used) */ + ctlr->obuf[ctlr->obptr++] = (ctlr->offset & 0xFF);/* Byte count L */ + ctlr->obuf[ctlr->obptr++] = ((ctlr->offset >> 8) & 0xFF);/* Byte count H */ + ctlr->obuf[ctlr->obptr++] = 0; /* Summary status L */ + ctlr->obuf[ctlr->obptr++] = 0; /* Summary status H */ + c = 0; + for (i = 0; i < (0xA + 2); i++) { /* Calculate checksum */ + w = (ctlr->obuf[i] << ((i & 0x1) ? 8 : 0)); + c = c + w + ( (uint32)((uint32)c + (uint32)w) > 0xFFFF ? 1 : 0); + } + ctlr->obuf[ctlr->obptr++] = c & 0xFF; /* Checksum L */ + ctlr->obuf[ctlr->obptr++] = (c >> 8) & 0xFF; /* Checksum H */ + ctlr->olen = ctlr->obptr; + ctlr->obptr = 0; + ctlr->p_state = TD_END1; /* go empty */ + sim_debug(TDDEB_PKT, ctlr->dptr, "END PKT: %s Generated - Unit: %d, Success Code: %X\n", sim_uname(uptr), ctlr->unitno, ctlr->ecode); + sim_activate (uptr, td_xtime); /* schedule next */ + break; + + case TD_END1: /* send end packet to host */ + if ((ctlr->rx_csr & CSR_DONE) == 0) { /* prev data taken? */ + ctlr->rx_buf = ctlr->obuf[ctlr->obptr++]; /* get next byte */ + ctlr->rx_csr |= CSR_DONE; /* set input flag */ + if (ctlr->rx_csr & CSR_IE) + CSI_SET_INT; + if (ctlr->obptr >= ctlr->olen) { /* buffer empty? */ + sim_debug(TDDEB_PKT, ctlr->dptr, "END PKT: %s Sent. Unit=%d\n", sim_uname(uptr), ctlr->unitno); + ctlr->p_state = TD_IDLE; + break; + } + } + sim_activate (uptr, td_xtime); /* schedule next */ + break; + + case TD_INIT: + if ((ctlr->rx_csr & CSR_DONE) == 0) { /* prev data taken? */ + ctlr->rx_buf = TD_OPCNT; + ctlr->rx_csr |= CSR_DONE; /* set input flag */ + if (ctlr->rx_csr & CSR_IE) + CSI_SET_INT; + ctlr->p_state = TD_IDLE; + break; + } + sim_activate (uptr, td_xtime); /* schedule next */ + break; + } +return SCPE_OK; +} + +/* Test for data transfer okay */ + +static t_bool td_test_xfr (UNIT *uptr, int32 state) +{ +CTLR *ctlr = (CTLR *)uptr->up7; + +if ((uptr->flags & UNIT_BUF) == 0) /* not buffered? */ + ctlr->ecode = TD_STSNC; +else if (ctlr->block >= TD_NUMBLK) /* bad block? */ + ctlr->ecode = TD_STSBBN; +else if ((state == TD_WRITE) && (uptr->flags & UNIT_WPRT)) /* write and locked? */ + ctlr->ecode = TD_STSWP; +else { + ctlr->ecode = TD_STSOK; + return TRUE; + } +return FALSE; +} + +/* Interrupt routines */ + +static void tdi_set_int (int32 ctlr, t_bool val) +{ +if ((tdi_ireq & (1 << ctlr)) ^ (val << ctlr)) { + sim_debug (TDDEB_INT, &tdc_dev, "tdi_set_int(%d, %d)\n", ctlr, val); + if (val) + tdi_ireq |= (1 << ctlr); /* set rcv int */ + else + tdi_ireq &= ~(1 << ctlr); /* clear rcv int */ + if (tdi_ireq == 0) /* all clr? */ + CLR_INT (TDRX); + else + SET_INT (TDRX); /* no, set intr */ + } +} + +static int32 tdi_iack (void) +{ +int32 ctlr; + +sim_debug (TDDEB_INT, &tdc_dev, "tdi_iack()\n"); +for (ctlr = 0; ctlr < TD_NUMCTLR; ctlr++) { /* find 1st line */ + if (tdi_ireq & (1 << ctlr)) { + tdi_set_int (ctlr, 0); /* clr req */ + return (td_dib.vec + (ctlr * 010)); /* return vector */ + } + } +return 0; +} + +static void tdo_set_int (int32 ctlr, t_bool val) +{ +if ((tdo_ireq & (1 << ctlr)) ^ (val << ctlr)) { + sim_debug (TDDEB_INT, &tdc_dev, "tdo_set_int(%d, %d)\n", ctlr, val); + if (val) + tdo_ireq |= (1 << ctlr); /* set xmt int */ + else + tdo_ireq &= ~(1 << ctlr); /* clear xmt int */ + if (tdo_ireq == 0) /* all clr? */ + CLR_INT (TDTX); + else + SET_INT (TDTX); /* no, set intr */ + } +} + +static int32 tdo_iack (void) +{ +int32 ctlr; + +sim_debug (TDDEB_INT, &tdc_dev, "tdo_iack()\n"); +for (ctlr = 0; ctlr < TD_NUMCTLR; ctlr++) { /* find 1st line */ + if (tdo_ireq & (1 << ctlr)) { + tdo_set_int (ctlr, 0); /* clear intr */ + return (td_dib.vec + (ctlr * 010) + 4); /* return vector */ + } + } +return 0; +} + +static t_stat td_reset_ctlr (CTLR *ctlr) +{ +REG *reg; + +ctlr->tx_buf = 0; +ctlr->tx_csr = CSR_DONE; +CSI_CLR_INT; +ctlr->o_state = TD_GETOPC; +ctlr->ibptr = 0; +ctlr->obptr = 0; +ctlr->ilen = 0; +ctlr->olen = 0; +ctlr->offset = 0; +ctlr->txsize = 0; +ctlr->p_state = 0; +ctlr->ecode = 0; +/* fixup/connect registers to actual data */ +reg = find_reg ("ECODE", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->ecode; +reg = find_reg ("BLOCK", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->block; +reg = find_reg ("P_STATE", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->p_state; +reg = find_reg ("O_STATE", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->o_state; +reg = find_reg ("IBPTR", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->ibptr; +reg = find_reg ("ILEN", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->ilen; +reg = find_reg ("OBPTR", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->obptr; +reg = find_reg ("OLEN", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->olen; +reg = find_reg ("TXSIZE", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->txsize; +reg = find_reg ("OFFSET", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->offset; +reg = find_reg ("IBUF", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->ibuf; +reg = find_reg ("OBUF", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->obuf; +reg = find_reg ("RX_CSR", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->rx_csr; +reg = find_reg ("RX_BUF", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->rx_buf; +reg = find_reg ("TX_CSR", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->tx_csr; +reg = find_reg ("TX_BUF", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->tx_buf; +reg = find_reg ("UNIT", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&ctlr->unitno; +reg = find_reg ("CTIME", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&td_ctime; +reg = find_reg ("STIME", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&td_stime; +reg = find_reg ("XTIME", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&td_xtime; +reg = find_reg ("ITIME", NULL, ctlr->dptr); +if (reg) + reg->loc = (void *)&td_itime; +return SCPE_OK; +} + +/* Reset */ + +static t_stat td_reset (DEVICE *dptr) +{ +CTLR *ctlr; +int ctl; + +sim_debug (TDDEB_INT, dptr, "td_reset()\n"); +for (ctl=0; ctldptr = &tdc_dev; + ctlr->uptr = td_unit + 2*ctl; + ctlr->rx_set_int = tdi_set_int; + ctlr->tx_set_int = tdo_set_int; + td_unit[2*ctl+0].action = &td_svc; + td_unit[2*ctl+0].flags |= UNIT_FIX|UNIT_ATTABLE|UNIT_BUFABLE|UNIT_MUSTBUF|UNIT_DIS; + td_unit[2*ctl+0].capac = TD_SIZE; + td_unit[2*ctl+0].up7 = ctlr; + td_unit[2*ctl+1].action = &td_svc; + td_unit[2*ctl+1].flags |= UNIT_FIX|UNIT_ATTABLE|UNIT_BUFABLE|UNIT_MUSTBUF|UNIT_DIS; + td_unit[2*ctl+1].capac = TD_SIZE; + td_unit[2*ctl+1].up7 = ctlr; + td_reset_ctlr (ctlr); + sim_cancel (&td_unit[2*ctl]); + sim_cancel (&td_unit[2*ctl+1]); + } +for (ctl=0; ctldescription (dptr), dptr->name); +fprintf (st, "DECtape TU58 Cartridge .\n\n"); +fprint_set_help (st, dptr); +fprint_show_help (st, dptr); +fprint_reg_help (st, dptr); +return SCPE_OK; +} + +t_stat td_connect_console_device (DEVICE *dptr, + void (*rx_set_int) (int32 ctlr_num, t_bool val), + void (*tx_set_int) (int32 ctlr_num, t_bool val)) +{ +uint32 i; +CTLR *ctlr = &td_ctlr[TD_NUMCTLR]; + +for (i=0; inumunits; i++) { + dptr->units[i].capac = TD_SIZE; + dptr->units[i].action = td_svc; + dptr->units[i].flags |= UNIT_FIX|UNIT_ATTABLE|UNIT_BUFABLE|UNIT_MUSTBUF; + dptr->units[i].up7 = (void *)ctlr; + sim_cancel (&dptr->units[i]); + } +ctlr->dptr = dptr; +ctlr->uptr = dptr->units; +ctlr->rx_set_int = rx_set_int; +ctlr->tx_set_int = tx_set_int; +return td_reset_ctlr (ctlr); +} diff --git a/PDP11/pdp11_td.h b/PDP11/pdp11_td.h new file mode 100644 index 00000000..d0038254 --- /dev/null +++ b/PDP11/pdp11_td.h @@ -0,0 +1,85 @@ +/* pdp11_td.h: TU58 cartridge controller API + ------------------------------------------------------------------------------ + + Copyright (c) 2015, Mark Pizzolato + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------ + + Modification history: + + 20-Sep-15 MP Initial Version + + ------------------------------------------------------------------------------ +*/ + +#ifndef PDP11_TD_H +#define PDP11_TD_H + +#include "sim_defs.h" + +typedef struct CTLR CTLR; + + +t_stat td_connect_console_device (DEVICE *dptr, + void (*rx_set_int) (int32 ctlr_num, t_bool val), + void (*tx_set_int) (int32 ctlr_num, t_bool val)); + +t_stat td_rd_i_csr (CTLR *ctlr, int32 *data); +t_stat td_rd_i_buf (CTLR *ctlr, int32 *data); +t_stat td_rd_o_csr (CTLR *ctlr, int32 *data); +t_stat td_rd_o_buf (CTLR *ctlr, int32 *data); + +t_stat td_wr_i_csr (CTLR *ctlr, int32 data); +t_stat td_wr_i_buf (CTLR *ctlr, int32 data); +t_stat td_wr_o_csr (CTLR *ctlr, int32 data); +t_stat td_wr_o_buf (CTLR *ctlr, int32 data); + +/* Debug detail levels */ + +#define TDDEB_OPS 00001 /* transactions */ +#define TDDEB_IRD 00002 /* input reg reads */ +#define TDDEB_ORD 00004 /* output reg reads */ +#define TDDEB_RRD 00006 /* reg reads */ +#define TDDEB_IWR 00010 /* input reg writes */ +#define TDDEB_OWR 00020 /* output reg writes */ +#define TDDEB_RWR 00030 /* reg writes */ +#define TDDEB_TRC 00040 /* trace */ +#define TDDEB_INT 00100 /* interrupts */ +#define TDDEB_PKT 00200 /* packet */ + +static DEBTAB td_deb[] = { + { "OPS", TDDEB_OPS, "transactions" }, + { "PKT", TDDEB_PKT, "packet" }, + { "RRD", TDDEB_RRD, "reg reads"}, + { "IRD", TDDEB_IRD, "input reg reads" }, + { "ORD", TDDEB_ORD, "output reg reads" }, + { "RWR", TDDEB_RWR, "reg writes" }, + { "IWR", TDDEB_IWR, "input reg writes" }, + { "OWR", TDDEB_OWR, "output reg writes" }, + { "INT", TDDEB_INT, "interrupts" }, + { "TRC", TDDEB_TRC, "trace" }, + { NULL, 0 } + }; + +#endif /* _PDP11_TD_H */ diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index 91525afa..f3ec9c44 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -2301,6 +2301,11 @@ void xq_start_receiver(CTLR* xq) if (!xq->var->etherface) return; + /* clear read queue */ + ethq_clear(&xq->var->ReadQ); + + + /* start the read service timer or enable asynch reading as appropriate */ if (xq->var->must_poll) { if (sim_idle_enab) diff --git a/README.md b/README.md index b4586c6c..451cacd2 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ A remote console session will close when an EOF character is entered (i.e. ^D or Qbus systems 128 port limit (default of 16). DZ devices optionally support full modem control (and port speed settings when connected to serial ports). + TU58 device support for all PDP11 and VAX systems. DHU11 (device VH) on Unibus systems now has 16 ports per multiplexer. XQ devices (DEQNA, DELQA and DELQA-T) are bootable on Qbus PDP11 simulators XQ and XU devices (DEQNA, DELQA, DELQA-T, DEUNA and DELQA) devices can now diff --git a/VAX/vax610_defs.h b/VAX/vax610_defs.h index 41b18070..7476898a 100644 --- a/VAX/vax610_defs.h +++ b/VAX/vax610_defs.h @@ -242,6 +242,8 @@ typedef struct { #define INT_V_QDSS 19 /* QDSS */ #define INT_V_CR 20 #define INT_V_QVSS 21 /* QVSS */ +#define INT_V_TDRX 22 +#define INT_V_TDTX 23 #define INT_CLK (1u << INT_V_CLK) #define INT_RQ (1u << INT_V_RQ) @@ -266,6 +268,8 @@ typedef struct { #define INT_QDSS (1u << INT_V_QDSS) #define INT_CR (1u << INT_V_CR) #define INT_QVSS (1u << INT_V_QVSS) +#define INT_TDRX (1u << INT_V_TDRX) +#define INT_TDTX (1u << INT_V_TDTX) #define IPL_CLK (0x16 - IPL_HMIN) /* relative IPL */ #define IPL_RQ (0x14 - IPL_HMIN) @@ -290,6 +294,8 @@ typedef struct { #define IPL_QDSS (0x14 - IPL_HMIN) #define IPL_CR (0x14 - IPL_HMIN) #define IPL_QVSS (0x14 - IPL_HMIN) +#define IPL_TDRX (0x14 - IPL_HMIN) +#define IPL_TDTX (0x14 - IPL_HMIN) #define IPL_HMAX 0x17 /* highest hwre level */ #define IPL_HMIN 0x14 /* lowest hwre level */ diff --git a/VAX/vax610_syslist.c b/VAX/vax610_syslist.c index 13aeef4d..5a2c966c 100644 --- a/VAX/vax610_syslist.c +++ b/VAX/vax610_syslist.c @@ -44,6 +44,7 @@ extern DEVICE tlb_dev; extern DEVICE sysd_dev; extern DEVICE qba_dev; extern DEVICE tti_dev, tto_dev; +extern DEVICE tdc_dev; extern DEVICE cr_dev; extern DEVICE lpt_dev; extern DEVICE clk_dev; @@ -70,6 +71,7 @@ DEVICE *sim_devices[] = { &clk_dev, &tti_dev, &tto_dev, + &tdc_dev, &dz_dev, &vh_dev, &cr_dev, diff --git a/VAX/vax630_defs.h b/VAX/vax630_defs.h index 0898b954..0bfba8fe 100644 --- a/VAX/vax630_defs.h +++ b/VAX/vax630_defs.h @@ -294,6 +294,8 @@ typedef struct { #define INT_V_QVSS 21 /* QVSS */ #define INT_V_DMCRX 22 #define INT_V_DMCTX 23 +#define INT_V_TDRX 24 /* TU58 */ +#define INT_V_TDTX 25 #define INT_CLK (1u << INT_V_CLK) #define INT_RQ (1u << INT_V_RQ) @@ -320,6 +322,8 @@ typedef struct { #define INT_QVSS (1u << INT_V_QVSS) #define INT_DMCRX (1u << INT_V_DMCRX) #define INT_DMCTX (1u << INT_V_DMCTX) +#define INT_TDRX (1u << INT_V_TDRX) +#define INT_TDTX (1u << INT_V_TDTX) #define IPL_CLK (0x16 - IPL_HMIN) /* relative IPL */ #define IPL_RQ (0x14 - IPL_HMIN) @@ -346,6 +350,8 @@ typedef struct { #define IPL_QVSS (0x14 - IPL_HMIN) #define IPL_DMCRX (0x14 - IPL_HMIN) #define IPL_DMCTX (0x14 - IPL_HMIN) +#define IPL_TDRX (0x14 - IPL_HMIN) +#define IPL_TDTX (0x14 - IPL_HMIN) #define IPL_HMAX 0x17 /* highest hwre level */ #define IPL_HMIN 0x14 /* lowest hwre level */ diff --git a/VAX/vax630_syslist.c b/VAX/vax630_syslist.c index c5555631..497a0fe4 100644 --- a/VAX/vax630_syslist.c +++ b/VAX/vax630_syslist.c @@ -55,6 +55,7 @@ extern DEVICE wtc_dev; extern DEVICE sysd_dev; extern DEVICE qba_dev; extern DEVICE tti_dev, tto_dev; +extern DEVICE tdc_dev; extern DEVICE cr_dev; extern DEVICE lpt_dev; extern DEVICE clk_dev; @@ -84,6 +85,7 @@ DEVICE *sim_devices[] = { &clk_dev, &tti_dev, &tto_dev, + &tdc_dev, &dz_dev, &vh_dev, &cr_dev, diff --git a/VAX/vax730_defs.h b/VAX/vax730_defs.h index cac4e4a8..53531bbb 100644 --- a/VAX/vax730_defs.h +++ b/VAX/vax730_defs.h @@ -268,6 +268,8 @@ typedef struct { #define INT_V_CR 3 #define INT_V_VHRX 4 #define INT_V_VHTX 5 +#define INT_V_TDRX 6 +#define INT_V_TDTX 7 #define INT_DZRX (1u << INT_V_DZRX) #define INT_DZTX (1u << INT_V_DZTX) @@ -289,6 +291,8 @@ typedef struct { #define INT_DMCTX (1u << INT_V_DMCTX) #define INT_DUPRX (1u << INT_V_DUPRX) #define INT_DUPTX (1u << INT_V_DUPTX) +#define INT_TDRX (1u << INT_V_TDRX) +#define INT_TDTX (1u << INT_V_TDTX) #define IPL_DZRX (0x15 - IPL_HMIN) #define IPL_DZTX (0x15 - IPL_HMIN) @@ -310,6 +314,8 @@ typedef struct { #define IPL_DMCTX (0x15 - IPL_HMIN) #define IPL_DUPRX (0x15 - IPL_HMIN) #define IPL_DUPTX (0x15 - IPL_HMIN) +#define IPL_TDRX (0x14 - IPL_HMIN) +#define IPL_TDTX (0x14 - IPL_HMIN) /* Device vectors */ diff --git a/VAX/vax730_stddev.c b/VAX/vax730_stddev.c index a8ee3a87..981bc233 100644 --- a/VAX/vax730_stddev.c +++ b/VAX/vax730_stddev.c @@ -60,6 +60,8 @@ #include "vax_defs.h" #include "sim_tmxr.h" +#include "pdp11_td.h" + /* Terminal definitions */ #define RXCS_RD (CSR_DONE + CSR_IE) /* terminal input */ @@ -82,9 +84,6 @@ #define MISC_CLCS 0x4 /* clear cold start */ #define TXDB_SEL (TXDB_M_SEL << TXDB_V_SEL) /* non-terminal */ #define TXDB_GETSEL(x) (((x) >> TXDB_V_SEL) & TXDB_M_SEL) -#define CSTS_BRK 0x1 -#define CSTS_RD (CSR_DONE + CSR_IE + CSTS_BRK) /* terminal output */ -#define CSTS_WR (CSR_IE + CSTS_BRK) /* Clock definitions */ @@ -165,13 +164,8 @@ int32 tto_csr = 0; /* control/status */ int32 tto_buf = 0; /* buffer */ int32 tto_int = 0; /* interrupt */ -int32 csi_csr = 0; /* control/status */ -int32 csi_buf = 0; /* buffer */ int32 csi_int = 0; /* interrupt */ -int32 cso_csr = 0; /* control/status */ -int32 cso_buf = 0; /* buffer */ int32 cso_int = 0; /* interrupt */ -int32 cso_state = 0; /* state */ int32 tmr_iccs = 0; /* interval timer csr */ uint32 tmr_icr = 0; /* curr interval */ @@ -189,22 +183,7 @@ struct todr_battery_info { }; typedef struct todr_battery_info TOY; -int32 td_swait = 100; /* seek, per block */ -int32 td_cwait = 150; /* command time */ -int32 td_xwait = 180; /* tr set time */ -int32 td_iwait = 180; /* init time */ -uint8 td_ibuf[TD_NUMBY] = { 0 }; /* input buffer */ -int32 td_ibptr = 0; /* input buffer pointer */ -int32 td_ilen = 0; /* input length */ -uint8 td_obuf[TD_NUMBY] = { 0 }; /* output buffer */ -int32 td_obptr = 0; /* output buffer pointer */ -int32 td_olen = 0; /* output length */ -int32 td_block = 0; /* current block number */ -int32 td_txsize = 0; /* remaining transfer size */ -int32 td_offset = 0; /* offset into current transfer */ -int32 td_state = TD_IDLE; -int32 td_unitno = 0; /* active unit number */ -int32 td_ecode = 0; /* end packet success code */ +int32 td_regval; /* temp location used in reg declarations */ extern jmp_buf save_env; @@ -226,15 +205,12 @@ t_stat clk_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cpt t_stat clk_attach (UNIT *uptr, char *cptr); t_stat clk_detach (UNIT *uptr); t_stat tmr_reset (DEVICE *dptr); -t_stat td_svc (UNIT *uptr); t_stat td_reset (DEVICE *dptr); int32 icr_rd (t_bool interp); void tmr_incr (uint32 inc); void tmr_sched (void); t_stat todr_resync (void); t_stat txdb_misc_wr (int32 data); -void td_process_packet(); -t_bool td_test_xfr (UNIT *uptr, int32 state); /* TTI data structures @@ -362,19 +338,29 @@ DEVICE tmr_dev = { td_mod RX modifier list */ -UNIT td_unit[] = { - { UDATA (&td_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, TD_SIZE) }, - { UDATA (&td_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, TD_SIZE) } - }; +UNIT td_unit[2]; REG td_reg[] = { - { HRDATAD (ECODE, td_ecode, 8, "end packet success code") }, - { HRDATAD (BLK, td_block, 8, "current block number") }, - { DRDATAD (PSTATE, td_state, 4, "state"), REG_RO }, - { DRDATAD (BPTR, td_obptr, 7, "output buffer pointer") }, - { DRDATAD (CTIME, td_cwait, 24, "command time"), PV_LEFT }, - { DRDATAD (STIME, td_swait, 24, "seek, per block"), PV_LEFT }, - { DRDATAD (XTIME, td_xwait, 24, "tr set time"), PV_LEFT }, + { HRDATAD (ECODE, td_regval, 8, "end packet success code") }, + { HRDATAD (BLOCK, td_regval, 8, "current block number") }, + { HRDATAD (RX_CSR, td_regval,16, "input control/status register") }, + { HRDATAD (RX_BUF, td_regval,16, "input buffer register") }, + { HRDATAD (TX_CSR, td_regval,16, "output control/status register") }, + { HRDATAD (TX_BUF, td_regval,16, "output buffer register") }, + { DRDATAD (P_STATE,td_regval, 4, "protocol state"), REG_RO }, + { DRDATAD (O_STATE,td_regval, 4, "output state"), REG_RO }, + { DRDATAD (IBPTR, td_regval, 9, "input buffer pointer") }, + { DRDATAD (OBPTR, td_regval, 9, "output buffer pointer") }, + { DRDATAD (ILEN, td_regval, 9, "input length") }, + { DRDATAD (OLEN, td_regval, 9, "output length") }, + { DRDATAD (TXSIZE, td_regval, 9, "remaining transfer size") }, + { DRDATAD (OFFSET, td_regval, 9, "offset into current transfer") }, + { DRDATAD (CTIME, td_regval,24, "command time"), PV_LEFT }, + { DRDATAD (STIME, td_regval,24, "seek, per block"), PV_LEFT }, + { DRDATAD (XTIME, td_regval,24, "tr set time"), PV_LEFT }, + { DRDATAD (ITIME, td_regval,24, "init time"), PV_LEFT }, + { BRDATAD (IBUF, &td_regval,16, 8, 512, "input buffer"), }, + { BRDATAD (OBUF, &td_regval,16, 8, 512, "output buffer"), }, { NULL } }; @@ -389,10 +375,26 @@ DEVICE td_dev = { 2, DEV_RDX, 20, 1, DEV_RDX, 8, NULL, NULL, &td_reset, NULL, NULL, NULL, - NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, DEV_DEBUG, 0, td_deb, NULL, NULL, NULL, NULL, NULL, &td_description }; +static void set_csi_int (int ctlr, t_bool val) +{ +if (csi_int ^ val) { + csi_int = val; + sim_debug (TDDEB_INT, &td_dev, "CSI_INT(%d)\n", val); + } +} + +static void set_cso_int (int ctlr, t_bool val) +{ +if (cso_int ^ val) { + cso_int = val; + sim_debug (TDDEB_INT, &td_dev, "CSO_INT(%d)\n", val); + } +} + /* Console storage MxPR routines csrs_rd/wr input control/status @@ -401,202 +403,50 @@ DEVICE td_dev = { cstd_wr output buffer */ +#define ctlr up7 + int32 csrs_rd (void) { -return (csi_csr & RXCS_RD); +int32 data; + +sim_debug (TDDEB_IRD, &td_dev, "csrs_rd()\n"); +td_rd_i_csr ((CTLR *)td_unit[0].ctlr, &data); +return data; } void csrs_wr (int32 data) { -if ((data & CSR_IE) == 0) - cso_int = 0; -else if ((csi_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - csi_int = 1; -csi_csr = (csi_csr & ~RXCS_WR) | (data & RXCS_WR); -return; +sim_debug (TDDEB_IWR, &td_dev, "csrs_wr()\n"); +td_wr_i_csr ((CTLR *)td_unit[0].ctlr, data); } int32 csrd_rd (void) { -int32 t = csi_buf; /* char + error */ - -csi_csr = csi_csr & ~CSR_DONE; /* clr done */ -csi_buf = csi_buf & BMASK; /* clr errors */ -csi_int = 0; -return t; +int32 data; +sim_debug (TDDEB_IRD, &td_dev, "csrd_rd()\n"); +td_rd_i_buf ((CTLR *)td_unit[0].ctlr, &data); +return data; } int32 csts_rd (void) { -return (cso_csr & TXCS_RD); +int32 data; + +sim_debug (TDDEB_ORD, &td_dev, "csts_rd()\n"); +td_rd_o_csr ((CTLR *)td_unit[0].ctlr, &data); +return data; } void csts_wr (int32 data) { -if ((cso_csr & CSTS_BRK) && !(data & CSTS_BRK)) { - td_ibptr = 0; - td_ibuf[td_ibptr++] = TD_OPINI; - td_process_packet(); /* check packet */ - } -if ((data & CSR_IE) == 0) - cso_int = 0; -else if ((cso_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - cso_int = 1; -cso_csr = (cso_csr & ~CSTS_WR) | (data & CSTS_WR); -return; +sim_debug (TDDEB_OWR, &td_dev, "csts_wr()\n"); +td_wr_o_csr ((CTLR *)td_unit[0].ctlr, data); } void cstd_wr (int32 data) { -cso_buf = data & WMASK; /* save data */ -cso_csr = cso_csr & ~CSR_DONE; /* clear flag */ -cso_int = 0; /* clear int */ - -switch (cso_state) { - - case TD_GETOPC: - td_ibptr = 0; - td_ibuf[td_ibptr++] = cso_buf; - td_process_packet(); /* check packet */ - break; - - case TD_GETLEN: - td_ibuf[td_ibptr++] = cso_buf; - td_ilen = cso_buf + 4; /* packet length + header + checksum */ - cso_state = TD_GETDATA; - break; - - case TD_GETDATA: - td_ibuf[td_ibptr++] = cso_buf; - if (td_ibptr >= td_ilen) { - cso_state = TD_GETOPC; - td_process_packet(); - } - break; - } - -cso_csr = cso_csr | CSR_DONE; /* set input flag */ -if (cso_csr & CSR_IE) - cso_int = 1; -return; -} - -void td_process_packet() -{ -int32 opcode = td_ibuf[0]; - -switch (opcode) { - - case TD_OPDAT: - if (td_state != TD_WRITE1) { /* expecting data? */ - sim_printf("TU58 protocol error 1\n"); - return; - } - if (td_ibptr < 2) { /* whole packet read? */ - cso_state = TD_GETLEN; /* get rest of packet */ - return; - } - td_state = TD_WRITE2; - sim_activate (&td_dev.units[td_unitno], td_cwait); /* sched command */ - break; - - case TD_OPCMD: - if (td_state != TD_IDLE) { /* expecting command? */ - sim_printf("TU58 protocol error 2\n"); - return; - } - if (td_ibptr < 2) { /* whole packet read? */ - cso_state = TD_GETLEN; /* get rest of packet */ - return; - } - switch (td_ibuf[2]) { - case TD_CMDNOP: /* NOP */ - case TD_CMDGST: /* Get status */ - case TD_CMDSST: /* Set status */ - td_unitno = td_ibuf[4]; - td_state = TD_END; /* All treated as NOP */ - td_ecode = TD_STSOK; - td_offset = 0; - sim_activate (&td_dev.units[td_unitno], td_cwait); /* sched command */ - break; - - case TD_CMDINI: - sim_printf("Warning: TU58 command 'INIT' not implemented\n"); - break; - - case TD_CMDRD: - td_unitno = td_ibuf[4]; - td_block = ((td_ibuf[11] << 8) | td_ibuf[10]); - td_txsize = ((td_ibuf[9] << 8) | td_ibuf[8]); - td_state = TD_READ; - td_offset = 0; - sim_activate (&td_dev.units[td_unitno], td_cwait); /* sched command */ - break; - - case TD_CMDWR: - td_unitno = td_ibuf[4]; - td_block = ((td_ibuf[11] << 8) | td_ibuf[10]); - td_txsize = ((td_ibuf[9] << 8) | td_ibuf[8]); - td_state = TD_WRITE; - td_offset = 0; - sim_activate (&td_dev.units[td_unitno], td_cwait); /* sched command */ - break; - - case TD_CMDPOS: - sim_printf("Warning: TU58 command 'Position' not implemented\n"); - break; - - case TD_CMDDIA: - sim_printf("Warning: TU58 command 'Diagnose' not implemented\n"); - break; - - case TD_CMDMRSP: /* MRSP supported? */ - csi_buf = TD_OPDAT; /* TP_OPCMD = yes, TP_OPDAT = no */ - csi_csr = csi_csr | CSR_DONE; /* set input flag */ - if (csi_csr & CSR_IE) - csi_int = 1; - break; - } - break; - - case TD_OPINI: - sim_cancel (&td_dev.units[0]); - sim_cancel (&td_dev.units[1]); - td_ibptr = 0; - td_obptr = 0; - td_olen = 0; - td_offset = 0; - td_txsize = 0; - cso_state = TD_GETOPC; - td_state = TD_INIT; - sim_activate (&td_dev.units[0], td_iwait); /* sched command */ - break; - - case TD_OPBOO: - if (td_state != TD_IDLE) { - sim_printf("TU58 protocol error 3\n"); - return; - } - if (td_ibptr < 2) { /* whole packet read? */ - td_ilen = 2; - cso_state = TD_GETDATA; /* get rest of packet */ - return; - } - td_unitno = td_ibuf[1]; - td_block = 0; - td_txsize = 512; - td_state = TD_READ; - td_offset = 0; - sim_activate (&td_dev.units[td_unitno], td_cwait); /* sched command */ - break; - - case TD_OPCNT: - break; - - default: - //sim_printf("TU58: Unknown opcode %d\n", opcode); - break; - } +sim_debug (TDDEB_OWR, &td_dev, "cstd_wr()\n"); +td_wr_o_buf ((CTLR *)td_unit[0].ctlr, data); } /* Terminal MxPR routines @@ -1089,199 +939,11 @@ if (sel == TXDB_MISC) { /* misc function? */ return SCPE_OK; } -t_stat td_svc (UNIT *uptr) -{ -int32 i, t, data_size; -uint16 c, w; -uint32 da; -int8 *fbuf = uptr->filebuf; - -switch (td_state) { /* case on state */ - - case TD_IDLE: /* idle */ - return SCPE_IERR; /* done */ - - case TD_READ: case TD_WRITE: /* read, write */ - if (td_test_xfr (uptr, td_state)) { /* transfer ok? */ - t = abs (td_block - 0); /* # blocks to seek */ - if (t == 0) /* minimum 1 */ - t = 1; - td_state++; /* set next state */ - sim_activate (uptr, td_swait * t); /* schedule seek */ - break; - } - else td_state = TD_END; - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_READ1: /* build data packet */ -// da = CALC_DA (td_block); /* get tape address */ - da = (td_block * 512) + td_offset; /* get tape address */ - if (td_txsize > 128) /* Packet length */ - data_size = 128; - else data_size = td_txsize; - td_txsize = td_txsize - data_size; - td_offset = td_offset + data_size; - - td_obptr = 0; - td_obuf[td_obptr++] = TD_OPDAT; /* Data packet */ - td_obuf[td_obptr++] = data_size; /* Data length */ - for (i = 0; i < data_size; i++) /* copy sector to buf */ - td_obuf[td_obptr++] = fbuf[da + i]; - c = 0; - for (i = 0; i < (data_size + 2); i++) { /* Calculate checksum */ - w = (td_obuf[i] << ((i & 0x1) ? 8 : 0)); - c = c + w + ( (uint32)((uint32)c + (uint32)w) > 0xFFFF ? 1 : 0); - } - td_obuf[td_obptr++] = (c & 0xFF); /* Checksum L */ - td_obuf[td_obptr++] = ((c >> 8) & 0xFF); /* Checksum H */ - td_olen = td_obptr; - td_obptr = 0; - td_state = TD_READ2; /* go empty */ - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_READ2: /* send data packet to host */ - if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ - csi_buf = td_obuf[td_obptr++]; /* get next byte */ - csi_csr = csi_csr | CSR_DONE; /* set input flag */ - if (csi_csr & CSR_IE) - csi_int = 1; - if (td_obptr >= td_olen) { /* buffer empty? */ - if (td_txsize > 0) - td_state = TD_READ1; - else - td_state = TD_END; - } - } - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_WRITE1: /* send continue */ - if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ - csi_buf = TD_OPCNT; - csi_csr = csi_csr | CSR_DONE; /* set input flag */ - if (csi_csr & CSR_IE) - csi_int = 1; - break; - } - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_WRITE2: /* write data to buffer */ - da = (td_block * 512) + td_offset; /* get tape address */ - td_olen = td_ibuf[1]; - for (i = 0; i < td_olen; i++) /* write data to buffer */ - fbuf[da + i] = td_ibuf[i + 2]; - td_offset += td_olen; - td_txsize -= td_olen; - da = da + td_olen; - if (da > uptr->hwmark) /* update hwmark */ - uptr->hwmark = da; - if (td_txsize > 0) - td_state = TD_WRITE1; - else { /* check whole number of blocks written */ - if ((td_olen = (512 - (td_offset % 512)) != 512)) { - for (i = 0; i < td_olen; i++) - fbuf[da + i] = 0; /* zero fill */ - da = da + td_olen; - if (da > uptr->hwmark) /* update hwmark */ - uptr->hwmark = da; - } - td_state = TD_END; - } - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_END: /* build end packet */ - td_obptr = 0; - td_obuf[td_obptr++] = TD_OPCMD; /* Command packet */ - td_obuf[td_obptr++] = 0xA; /* ** Need definition ** */ - td_obuf[td_obptr++] = TD_CMDEND; - td_obuf[td_obptr++] = td_ecode; /* Success code */ - td_obuf[td_obptr++] = td_unitno; /* Unit number */ - td_obuf[td_obptr++] = 0; /* Not used */ - td_obuf[td_obptr++] = 0; /* Sequence L (not used) */ - td_obuf[td_obptr++] = 0; /* Sequence H (not used) */ - td_obuf[td_obptr++] = (td_offset & 0xFF); /* Byte count L */ - td_obuf[td_obptr++] = ((td_offset >> 8) & 0xFF);/* Byte count H */ - td_obuf[td_obptr++] = 0; /* Summary status L */ - td_obuf[td_obptr++] = 0; /* Summary status H */ - c = 0; - for (i = 0; i < (0xA + 2); i++) { /* Calculate checksum */ - w = (td_obuf[i] << ((i & 0x1) ? 8 : 0)); - c = c + w + ( (uint32)((uint32)c + (uint32)w) > 0xFFFF ? 1 : 0); - } - td_obuf[td_obptr++] = c & 0xFF; /* Checksum L */ - td_obuf[td_obptr++] = (c >> 8) & 0xFF; /* Checksum H */ - td_olen = td_obptr; - td_obptr = 0; - td_state = TD_END1; /* go empty */ - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_END1: /* send end packet to host */ - if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ - csi_buf = td_obuf[td_obptr++]; /* get next byte */ - csi_csr = csi_csr | CSR_DONE; /* set input flag */ - if (csi_csr & CSR_IE) - csi_int = 1; - if (td_obptr >= td_olen) { /* buffer empty? */ - td_state = TD_IDLE; - break; - } - } - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_INIT: - if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ - csi_buf = TD_OPCNT; - csi_csr = csi_csr | CSR_DONE; /* set input flag */ - if (csi_csr & CSR_IE) - csi_int = 1; - td_state = TD_IDLE; - break; - } - sim_activate (uptr, td_xwait); /* schedule next */ - break; - } -return SCPE_OK; -} - -/* Test for data transfer okay */ - -t_bool td_test_xfr (UNIT *uptr, int32 state) -{ -if ((uptr->flags & UNIT_BUF) == 0) /* not buffered? */ - td_ecode = TD_STSNC; -else if (td_block >= TD_NUMBLK) /* bad block? */ - td_ecode = TD_STSBBN; -else if ((state == TD_WRITE) && (uptr->flags & UNIT_WPRT)) /* write and locked? */ - td_ecode = TD_STSWP; -else { - td_ecode = TD_STSOK; - return TRUE; - } -return FALSE; -} - /* Reset */ t_stat td_reset (DEVICE *dptr) { -cso_buf = 0; -cso_csr = CSR_DONE; -cso_int = 0; -cso_state = TD_GETOPC; -td_ibptr = 0; -td_obptr = 0; -td_olen = 0; -td_offset = 0; -td_txsize = 0; -sim_cancel (&td_dev.units[0]); -sim_cancel (&td_dev.units[1]); -return SCPE_OK; +return td_connect_console_device (&td_dev, set_csi_int, set_cso_int); } const char *td_description (DEVICE *dptr) diff --git a/VAX/vax730_syslist.c b/VAX/vax730_syslist.c index 5e7cf395..3f1d2085 100644 --- a/VAX/vax730_syslist.c +++ b/VAX/vax730_syslist.c @@ -40,6 +40,7 @@ extern DEVICE clk_dev; extern DEVICE tmr_dev; extern DEVICE tti_dev, tto_dev; extern DEVICE td_dev; +extern DEVICE tdc_dev; extern DEVICE cr_dev; extern DEVICE lpt_dev; extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; @@ -68,6 +69,7 @@ DEVICE *sim_devices[] = { &tti_dev, &tto_dev, &td_dev, + &tdc_dev, &dz_dev, &vh_dev, &cr_dev, diff --git a/VAX/vax750_defs.h b/VAX/vax750_defs.h index c47cc56c..cf45e9bc 100644 --- a/VAX/vax750_defs.h +++ b/VAX/vax750_defs.h @@ -309,6 +309,8 @@ typedef struct { #define INT_V_CR 3 #define INT_V_VHRX 4 #define INT_V_VHTX 5 +#define INT_V_TDRX 6 +#define INT_V_TDTX 7 #define INT_DZRX (1u << INT_V_DZRX) #define INT_DZTX (1u << INT_V_DZTX) @@ -329,6 +331,8 @@ typedef struct { #define INT_DMCTX (1u << INT_V_DMCTX) #define INT_DUPRX (1u << INT_V_DUPRX) #define INT_DUPTX (1u << INT_V_DUPTX) +#define INT_TDRX (1u << INT_V_TDRX) +#define INT_TDTX (1u << INT_V_TDTX) #define IPL_DZRX (0x15 - IPL_HMIN) #define IPL_DZTX (0x15 - IPL_HMIN) @@ -349,6 +353,8 @@ typedef struct { #define IPL_DMCTX (0x15 - IPL_HMIN) #define IPL_DUPRX (0x15 - IPL_HMIN) #define IPL_DUPTX (0x15 - IPL_HMIN) +#define IPL_TDRX (0x14 - IPL_HMIN) +#define IPL_TDTX (0x14 - IPL_HMIN) /* Device vectors */ diff --git a/VAX/vax750_stddev.c b/VAX/vax750_stddev.c index b93beb2e..f3be77fd 100644 --- a/VAX/vax750_stddev.c +++ b/VAX/vax750_stddev.c @@ -62,6 +62,8 @@ #include "sim_tmxr.h" #include +#include "pdp11_td.h" + /* Terminal definitions */ #define RXCS_RD (CSR_DONE + CSR_IE) /* terminal input */ @@ -81,9 +83,6 @@ #define MISC_CLCS 0x4 /* clear cold start */ #define TXDB_SEL (TXDB_M_SEL << TXDB_V_SEL) /* non-terminal */ #define TXDB_GETSEL(x) (((x) >> TXDB_V_SEL) & TXDB_M_SEL) -#define CSTS_BRK 0x1 -#define CSTS_RD (CSR_DONE + CSR_IE + CSTS_BRK) /* terminal output */ -#define CSTS_WR (CSR_IE + CSTS_BRK) static BITFIELD rx_csr_bits[] = { BITNCF(6), /* unused */ @@ -145,63 +144,7 @@ static BITFIELD tx_buf_bits[] = { #define TD_NUMBY 512 /* bytes/block */ #define TD_SIZE (TD_NUMBLK * TD_NUMBY) /* bytes/tape */ -#define TD_OPDAT 001 /* Data */ -#define TD_OPCMD 002 /* Command */ -#define TD_OPINI 004 /* INIT */ -#define TD_OPBOO 010 /* Bootstrap */ -#define TD_OPCNT 020 /* Continue */ -#define TD_OPXOF 023 /* XOFF */ -#define TD_CMDNOP 0000 /* NOP */ -#define TD_CMDINI 0001 /* INIT */ -#define TD_CMDRD 0002 /* Read */ -#define TD_CMDWR 0003 /* Write */ -#define TD_CMDPOS 0005 /* Position */ -#define TD_CMDDIA 0007 /* Diagnose */ -#define TD_CMDGST 0010 /* Get Status */ -#define TD_CMDSST 0011 /* Set Status */ -#define TD_CMDMRSP 0012 /* MRSP Request */ -#define TD_CMDEND 0100 /* END */ - -#define TD_STSOK 0000 /* Normal success */ -#define TD_STSRTY 0001 /* Success with retries */ -#define TD_STSFAIL 0377 /* Failed selftest */ -#define TD_STSPO 0376 /* Partial operation (end of medium) */ -#define TD_STSBUN 0370 /* Bad unit number */ -#define TD_STSNC 0367 /* No cartridge */ -#define TD_STSWP 0365 /* Write protected */ -#define TD_STSDCE 0357 /* Data check error */ -#define TD_STSSE 0340 /* Seek error (block not found) */ -#define TD_STSMS 0337 /* Motor stopped */ -#define TD_STSBOP 0320 /* Bad opcode */ -#define TD_STSBBN 0311 /* Bad block number (>511) */ - -#define TD_GETOPC 0 /* get opcode state */ -#define TD_GETLEN 1 /* get length state */ -#define TD_GETDATA 2 /* get data state */ - -#define TD_IDLE 0 /* idle state */ -#define TD_READ 1 /* read */ -#define TD_READ1 2 /* fill buffer */ -#define TD_READ2 3 /* empty buffer */ -#define TD_WRITE 4 /* write */ -#define TD_WRITE1 5 /* write */ -#define TD_WRITE2 6 /* write */ -#define TD_END 7 /* empty buffer */ -#define TD_END1 8 /* empty buffer */ -#define TD_INIT 9 /* empty buffer */ - -static char *td_states[] = { - "IDLE", "READ", "READ1", "READ2", "WRITE", "WRITE1", "WRITE2", "END", "END1", "INIT" - }; - -static char *td_ops[] = { - "NOP", "INI", "RD", "WR", "POS", "DIA", "GST", "SST", "MRSP" - }; - -static char *td_csostates[] = { - "GETOPC", "GETLEN", "GETDATA" - }; int32 tti_csr = 0; /* control/status */ uint32 tti_buftime; /* time input character arrived */ @@ -211,13 +154,8 @@ int32 tto_csr = 0; /* control/status */ int32 tto_buf = 0; /* buffer */ int32 tto_int = 0; /* interrupt */ -int32 csi_csr = 0; /* control/status */ -int32 csi_buf = 0; /* buffer */ int32 csi_int = 0; /* interrupt */ -int32 cso_csr = 0; /* control/status */ -int32 cso_buf = 0; /* buffer */ int32 cso_int = 0; /* interrupt */ -int32 cso_state = 0; /* state */ int32 tmr_iccs = 0; /* interval timer csr */ uint32 tmr_icr = 0; /* curr interval */ @@ -235,21 +173,7 @@ struct todr_battery_info { }; typedef struct todr_battery_info TOY; -int32 td_swait = 100; /* seek, per block */ -int32 td_cwait = 150; /* command time */ -int32 td_xwait = 180; /* tr set time */ -int32 td_iwait = 180; /* init time */ -uint8 td_ibuf[TD_NUMBY] = { 0 }; /* input buffer */ -int32 td_ibptr = 0; /* input buffer pointer */ -int32 td_ilen = 0; /* input length */ -uint8 td_obuf[TD_NUMBY] = { 0 }; /* output buffer */ -int32 td_obptr = 0; /* output buffer pointer */ -int32 td_olen = 0; /* output length */ -int32 td_block = 0; /* current block number */ -int32 td_txsize = 0; /* remaining transfer size */ -int32 td_offset = 0; /* offset into current transfer */ -int32 td_state = TD_IDLE; -int32 td_ecode = 0; /* end packet success code */ +int32 td_regval; /* temp location used in reg declarations */ extern jmp_buf save_env; @@ -270,7 +194,6 @@ t_stat clk_attach (UNIT *uptr, char *cptr); t_stat clk_detach (UNIT *uptr); t_stat tmr_reset (DEVICE *dptr); const char *tmr_description (DEVICE *dptr); -t_stat td_svc (UNIT *uptr); t_stat td_reset (DEVICE *dptr); const char *td_description (DEVICE *dptr); int32 icr_rd (t_bool interp); @@ -278,8 +201,6 @@ void tmr_incr (uint32 inc); void tmr_sched (void); t_stat todr_resync (void); t_stat txdb_misc_wr (int32 data); -void td_process_packet(); -t_bool td_test_xfr (UNIT *uptr, int32 state); extern int32 con_halt (int32 code, int32 cc); @@ -409,17 +330,29 @@ DEVICE tmr_dev = { td_mod RX modifier list */ -UNIT td_unit = { UDATA (&td_svc, - UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, TD_SIZE) }; +UNIT td_unit; REG td_reg[] = { - { HRDATAD (ECODE, td_ecode, 8, "end packet success code") }, - { HRDATAD (BLK, td_block, 8, "current block number") }, - { DRDATAD (PSTATE, td_state, 4, "state"), REG_RO }, - { DRDATAD (BPTR, td_obptr, 7, "output buffer pointer") }, - { DRDATAD (CTIME, td_cwait, 24, "command time"), PV_LEFT }, - { DRDATAD (STIME, td_swait, 24, "seek, per block"), PV_LEFT }, - { DRDATAD (XTIME, td_xwait, 24, "tr set time"), PV_LEFT }, + { HRDATAD (ECODE, td_regval, 8, "end packet success code") }, + { HRDATAD (BLOCK, td_regval, 8, "current block number") }, + { HRDATAD (RX_CSR, td_regval,16, "input control/status register") }, + { HRDATAD (RX_BUF, td_regval,16, "input buffer register") }, + { HRDATAD (TX_CSR, td_regval,16, "output control/status register") }, + { HRDATAD (TX_BUF, td_regval,16, "output buffer register") }, + { DRDATAD (P_STATE,td_regval, 4, "protocol state"), REG_RO }, + { DRDATAD (O_STATE,td_regval, 4, "output state"), REG_RO }, + { DRDATAD (IBPTR, td_regval, 9, "input buffer pointer") }, + { DRDATAD (OBPTR, td_regval, 9, "output buffer pointer") }, + { DRDATAD (ILEN, td_regval, 9, "input length") }, + { DRDATAD (OLEN, td_regval, 9, "output length") }, + { DRDATAD (TXSIZE, td_regval, 9, "remaining transfer size") }, + { DRDATAD (OFFSET, td_regval, 9, "offset into current transfer") }, + { DRDATAD (CTIME, td_regval,24, "command time"), PV_LEFT }, + { DRDATAD (STIME, td_regval,24, "seek, per block"), PV_LEFT }, + { DRDATAD (XTIME, td_regval,24, "tr set time"), PV_LEFT }, + { DRDATAD (ITIME, td_regval,24, "init time"), PV_LEFT }, + { BRDATAD (IBUF, &td_regval,16, 8, 512, "input buffer"), }, + { BRDATAD (OBUF, &td_regval,16, 8, 512, "output buffer"), }, { NULL } }; @@ -429,33 +362,6 @@ MTAB td_mod[] = { { 0 } }; -/* Debug detail levels */ - -#define TDDEB_OPS 00001 /* transactions */ -#define TDDEB_IRD 00002 /* input reg reads */ -#define TDDEB_ORD 00004 /* output reg reads */ -#define TDDEB_RRD 00006 /* reg reads */ -#define TDDEB_IWR 00010 /* input reg writes */ -#define TDDEB_OWR 00020 /* output reg writes */ -#define TDDEB_RWR 00030 /* reg writes */ -#define TDDEB_TRC 00040 /* trace */ -#define TDDEB_INT 00100 /* interrupts */ -#define TDDEB_PKT 00200 /* packet */ - -DEBTAB td_deb[] = { - { "OPS", TDDEB_OPS, "transactions" }, - { "PKT", TDDEB_PKT, "packet" }, - { "RRD", TDDEB_RRD, "reg reads"}, - { "IRD", TDDEB_IRD, "input reg reads" }, - { "ORD", TDDEB_ORD, "output reg reads" }, - { "RWR", TDDEB_RWR, "reg writes" }, - { "IWR", TDDEB_IWR, "input reg writes" }, - { "OWR", TDDEB_OWR, "output reg writes" }, - { "INT", TDDEB_INT, "interrupts" }, - { "TRC", TDDEB_TRC, "trace" }, - { NULL, 0 } - }; - DEVICE td_dev = { "TD", &td_unit, td_reg, td_mod, 1, DEV_RDX, 20, 1, DEV_RDX, 8, @@ -465,6 +371,23 @@ DEVICE td_dev = { &td_description }; +static void set_csi_int (int ctlr, t_bool val) +{ +if (csi_int ^ val) { + csi_int = val; + sim_debug (TDDEB_INT, &td_dev, "CSI_INT(%d)\n", val); + } +} + +static void set_cso_int (int ctlr, t_bool val) +{ +if (cso_int ^ val) { + cso_int = val; + sim_debug (TDDEB_INT, &td_dev, "CSO_INT(%d)\n", val); + } +} + + /* Console storage MxPR routines csrs_rd/wr input control/status @@ -473,260 +396,50 @@ DEVICE td_dev = { cstd_wr output buffer */ +#define ctlr up7 + int32 csrs_rd (void) { -sim_debug(TDDEB_IRD, &td_dev, "csrs_rd()\n"); -sim_debug_bits_hdr(TDDEB_IRD, &td_dev, "RX_CSR", rx_csr_bits, csi_csr, csi_csr, 1); -return (csi_csr & RXCS_RD); +int32 data; + +sim_debug (TDDEB_IRD, &td_dev, "csrs_rd()\n"); +td_rd_i_csr ((CTLR *)td_unit.ctlr, &data); +return data; } void csrs_wr (int32 data) { -sim_debug(TDDEB_IWR, &td_dev, "csrs_wr()\n"); -sim_debug_bits_hdr(TDDEB_IWR, &td_dev, "RX_CSR", rx_csr_bits, data, data, 1); -if ((data & CSR_IE) == 0) { - csi_int = 0; - sim_debug (TDDEB_INT, &td_dev, "CSI_INT(0)\n"); - } -else if ((csi_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) { - csi_int = 1; - sim_debug (TDDEB_INT, &td_dev, "CSI_INT(1)\n"); - } -csi_csr = (csi_csr & ~RXCS_WR) | (data & RXCS_WR); -return; +sim_debug (TDDEB_IWR, &td_dev, "csrs_wr()\n"); +td_wr_i_csr ((CTLR *)td_unit.ctlr, data); } int32 csrd_rd (void) { -int32 t = csi_buf; /* char + error */ - -sim_debug(TDDEB_IRD, &td_dev, "csrd_rd()\n"); -sim_debug_bits_hdr(TDDEB_IRD, &td_dev, "RX_BUF", rx_buf_bits, t, t, 1); -csi_csr = csi_csr & ~CSR_DONE; /* clr done */ -csi_buf = csi_buf & BMASK; /* clr errors */ -if (csi_int) { - csi_int = 0; - sim_debug (TDDEB_INT, &td_dev, "CSI_INT(0)\n"); - } -return t; +int32 data; +sim_debug (TDDEB_IRD, &td_dev, "csrd_rd()\n"); +td_rd_i_buf ((CTLR *)td_unit.ctlr, &data); +return data; } int32 csts_rd (void) { -sim_debug(TDDEB_ORD, &td_dev, "csts_rd()\n"); -sim_debug_bits_hdr(TDDEB_ORD, &td_dev, "TX_CSR", tx_csr_bits, cso_csr, cso_csr, 1); -return (cso_csr & TXCS_RD); +int32 data; + +sim_debug (TDDEB_ORD, &td_dev, "csts_rd()\n"); +td_rd_o_csr ((CTLR *)td_unit.ctlr, &data); +return data; } void csts_wr (int32 data) { -sim_debug(TDDEB_OWR, &td_dev, "csts_wr()\n"); -sim_debug_bits_hdr(TDDEB_OWR, &td_dev, "TX_CSR", tx_csr_bits, data, data, 1); -if ((cso_csr & CSTS_BRK) && !(data & CSTS_BRK)) { - td_ibptr = 0; - td_ibuf[td_ibptr++] = TD_OPINI; - td_process_packet(); /* check packet */ - } -if ((data & CSR_IE) == 0) { - if (cso_int) { - cso_int = 0; - sim_debug (TDDEB_INT, &td_dev, "CSO_INT(0)\n"); - } - } -else if ((cso_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) { - cso_int = 1; - sim_debug (TDDEB_INT, &td_dev, "CSO_INT(1)\n"); - } -cso_csr = (cso_csr & ~CSTS_WR) | (data & CSTS_WR); -return; +sim_debug (TDDEB_OWR, &td_dev, "csts_wr()\n"); +td_wr_o_csr ((CTLR *)td_unit.ctlr, data); } void cstd_wr (int32 data) { -sim_debug(TDDEB_OWR, &td_dev, "cstd_wr() state=%s, ibptr=%d, ilen=%d\n", td_csostates[cso_state], td_ibptr, td_ilen); -sim_debug_bits_hdr(TDDEB_OWR, &td_dev, "TX_BUF", tx_buf_bits, data, data, 1); -cso_buf = data & BMASK; /* save data */ -cso_csr = cso_csr & ~CSR_DONE; /* clear flag */ -if (cso_int) { - cso_int = 0; /* clear int */ - sim_debug (TDDEB_INT, &td_dev, "CSO_INT(0)\n"); - } - -switch (cso_state) { - - case TD_GETOPC: - td_ibptr = 0; - td_ibuf[td_ibptr++] = cso_buf; - td_process_packet(); /* check packet */ - break; - - case TD_GETLEN: - td_ibuf[td_ibptr++] = cso_buf; - td_ilen = cso_buf + 4; /* packet length + header + checksum */ - cso_state = TD_GETDATA; - break; - - case TD_GETDATA: - td_ibuf[td_ibptr++] = cso_buf; - if (td_ibptr >= td_ilen) { - cso_state = TD_GETOPC; - td_process_packet(); - } - break; - } - -cso_csr = cso_csr | CSR_DONE; /* set input flag */ -if (cso_csr & CSR_IE) { - cso_int = 1; - sim_debug (TDDEB_INT, &td_dev, "CSO_INT(1)\n"); - } -return; -} - -void td_process_packet() -{ -int32 opcode = td_ibuf[0]; -char *opcode_name, *command_name; - -switch (opcode) { - case TD_OPDAT: - opcode_name = "OPDAT"; - break; - case TD_OPCMD: - opcode_name = "OPCMD"; - break; - case TD_OPINI: - opcode_name = "OPINI"; - break; - case TD_OPBOO: - opcode_name = "OPBOO"; - break; - case TD_OPCNT: - opcode_name = "OPCNT"; - break; - case TD_OPXOF: - opcode_name = "OPXOF"; - break; - default: - opcode_name = "unknown"; - } -sim_debug (TDDEB_TRC, &td_dev, "td_process_packet() Opcode=%s(%d)\n", opcode_name, opcode); -switch (opcode) { - - case TD_OPDAT: - if (td_state != TD_WRITE1) { /* expecting data? */ - sim_printf("TU58 protocol error 1\n"); - return; - } - if (td_ibptr < 2) { /* whole packet read? */ - cso_state = TD_GETLEN; /* get rest of packet */ - return; - } - td_state = TD_WRITE2; - sim_activate (&td_unit, td_cwait); /* sched command */ - break; - - case TD_OPCMD: - if (td_state != TD_IDLE) { /* expecting command? */ - sim_printf("TU58 protocol error 2\n"); - return; - } - if (td_ibptr < 2) { /* whole packet read? */ - cso_state = TD_GETLEN; /* get rest of packet */ - return; - } - if (td_ibuf[2] == TD_CMDEND) - command_name = "END"; - else - command_name = td_ops[td_ibuf[2]]; - sim_debug (TDDEB_OPS, &td_dev, "strt: fnc=%d(%s), block=%d, size=%d\n", td_ibuf[2], command_name, ((td_ibuf[11] << 8) | td_ibuf[10]), ((td_ibuf[9] << 8) | td_ibuf[8])); - switch (td_ibuf[2]) { - case TD_CMDNOP: /* NOP */ - case TD_CMDGST: /* Get status */ - case TD_CMDSST: /* Set status */ - td_state = TD_END; /* All treated as NOP */ - td_ecode = TD_STSOK; - td_offset = 0; - sim_activate (&td_unit, td_cwait); /* sched command */ - break; - - case TD_CMDINI: - sim_printf("Warning: TU58 command 'INIT' not implemented\n"); - break; - - case TD_CMDRD: - td_block = ((td_ibuf[11] << 8) | td_ibuf[10]); - td_txsize = ((td_ibuf[9] << 8) | td_ibuf[8]); - td_state = TD_READ; - td_offset = 0; - if (td_block == 0) - td_block = td_block; - sim_activate (&td_unit, td_cwait); /* sched command */ - break; - - case TD_CMDWR: - td_block = ((td_ibuf[11] << 8) | td_ibuf[10]); - td_txsize = ((td_ibuf[9] << 8) | td_ibuf[8]); - td_state = TD_WRITE; - td_offset = 0; - sim_activate (&td_unit, td_cwait); /* sched command */ - break; - - case TD_CMDPOS: - sim_printf("Warning: TU58 command 'Position' not implemented\n"); - break; - - case TD_CMDDIA: - sim_printf("Warning: TU58 command 'Diagnose' not implemented\n"); - break; - - case TD_CMDMRSP: - csi_buf = TD_OPDAT; - csi_csr = csi_csr | CSR_DONE; /* set input flag */ - if (csi_csr & CSR_IE) { - csi_int = 1; - sim_debug (TDDEB_INT, &td_dev, "CSI_INT(1)\n"); - } - break; - } - break; - - case TD_OPINI: - sim_cancel (&td_unit); - td_ibptr = 0; - td_obptr = 0; - td_olen = 0; - td_offset = 0; - td_txsize = 0; - cso_state = TD_GETOPC; - td_state = TD_INIT; - sim_activate (&td_unit, td_iwait); /* sched command */ - break; - - case TD_OPBOO: - if (td_state != TD_IDLE) { - sim_printf("TU58 protocol error 3\n"); - return; - } - if (td_ibptr < 2) { /* whole packet read? */ - td_ilen = 2; - cso_state = TD_GETDATA; /* get rest of packet */ - return; - } - td_block = 0; - td_txsize = 512; - td_state = TD_READ; - td_offset = 0; - sim_activate (&td_unit, td_cwait); /* sched command */ - break; - - case TD_OPCNT: - break; - - default: - //sim_printf("TU58: Unknown opcode %d\n", opcode); - break; - } +sim_debug (TDDEB_OWR, &td_dev, "cstd_wr()\n"); +td_wr_o_buf ((CTLR *)td_unit.ctlr, data); } /* Terminal MxPR routines @@ -824,10 +537,6 @@ tti_buf = 0; tti_csr = 0; tti_int = 0; sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); -csi_buf = 0; -csi_csr = 0; -csi_int = 0; -sim_debug (TDDEB_INT, &td_dev, "CSI_INT(0)\n"); return SCPE_OK; } @@ -1224,209 +933,11 @@ if (sel == TXDB_MISC) { /* misc function? */ return SCPE_OK; } -t_stat td_svc (UNIT *uptr) -{ -int32 i, t, data_size; -uint16 c, w; -uint32 da; -int8 *fbuf = uptr->filebuf; - -sim_debug (TDDEB_TRC, &td_dev, "td_svc(state=%s)\n", td_states[td_state]); -switch (td_state) { /* case on state */ - - case TD_IDLE: /* idle */ - return SCPE_IERR; /* done */ - - case TD_READ: case TD_WRITE: /* read, write */ - if (td_test_xfr (uptr, td_state)) { /* transfer ok? */ - t = abs (td_block - 0); /* # blocks to seek */ - if (t == 0) /* minimum 1 */ - t = 1; - td_state++; /* set next state */ - sim_activate (uptr, td_swait * t); /* schedule seek */ - break; - } - else td_state = TD_END; - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_READ1: /* build data packet */ - da = (td_block * 512) + td_offset; /* get tape address */ - if (td_txsize > 128) /* Packet length */ - data_size = 128; - else data_size = td_txsize; - td_txsize = td_txsize - data_size; - td_offset = td_offset + data_size; - - td_obptr = 0; - td_obuf[td_obptr++] = TD_OPDAT; /* Data packet */ - td_obuf[td_obptr++] = data_size; /* Data length */ - for (i = 0; i < data_size; i++) /* copy sector to buf */ - td_obuf[td_obptr++] = fbuf[da + i]; - c = 0; - for (i = 0; i < (data_size + 2); i++) { /* Calculate checksum */ - w = (td_obuf[i] << ((i & 0x1) ? 8 : 0)); - c = c + w + ( (uint32)((uint32)c + (uint32)w) > 0xFFFF ? 1 : 0); - } - td_obuf[td_obptr++] = (c & 0xFF); /* Checksum L */ - td_obuf[td_obptr++] = ((c >> 8) & 0xFF); /* Checksum H */ - td_olen = td_obptr; - td_obptr = 0; - td_state = TD_READ2; /* go empty */ - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_READ2: /* send data packet to host */ - if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ - csi_buf = td_obuf[td_obptr++]; /* get next byte */ - csi_csr = csi_csr | CSR_DONE; /* set input flag */ - if (csi_csr & CSR_IE) { - csi_int = 1; - sim_debug (TDDEB_INT, &td_dev, "CSI_INT(1)\n"); - } - if (td_obptr >= td_olen) { /* buffer empty? */ - if (td_txsize > 0) - td_state = TD_READ1; - else - td_state = TD_END; - } - } - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_WRITE1: /* send continue */ - if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ - csi_buf = TD_OPCNT; - csi_csr = csi_csr | CSR_DONE; /* set input flag */ - if (csi_csr & CSR_IE) { - csi_int = 1; - sim_debug (TDDEB_INT, &td_dev, "CSI_INT(1)\n"); - } - break; - } - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_WRITE2: /* write data to buffer */ - da = (td_block * 512) + td_offset; /* get tape address */ - td_olen = td_ibuf[1]; - for (i = 0; i < td_olen; i++) /* write data to buffer */ - fbuf[da + i] = td_ibuf[i + 2]; - td_offset += td_olen; - td_txsize -= td_olen; - da = da + td_olen; - if (da > uptr->hwmark) /* update hwmark */ - uptr->hwmark = da; - if (td_txsize > 0) - td_state = TD_WRITE1; - else { /* check whole number of blocks written */ - if ((td_olen = (512 - (td_offset % 512))) != 512) { - for (i = 0; i < td_olen; i++) - fbuf[da + i] = 0; /* zero fill */ - da = da + td_olen; - if (da > uptr->hwmark) /* update hwmark */ - uptr->hwmark = da; - } - td_state = TD_END; - } - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_END: /* build end packet */ - td_obptr = 0; - td_obuf[td_obptr++] = TD_OPCMD; /* Command packet */ - td_obuf[td_obptr++] = 0xA; /* ** Need definition ** */ - td_obuf[td_obptr++] = TD_CMDEND; - td_obuf[td_obptr++] = td_ecode; /* Success code */ - td_obuf[td_obptr++] = 0; /* Unit number */ - td_obuf[td_obptr++] = 0; /* Not used */ - td_obuf[td_obptr++] = 0; /* Sequence L (not used) */ - td_obuf[td_obptr++] = 0; /* Sequence H (not used) */ - td_obuf[td_obptr++] = (td_offset & 0xFF); /* Byte count L */ - td_obuf[td_obptr++] = ((td_offset >> 8) & 0xFF);/* Byte count H */ - td_obuf[td_obptr++] = 0; /* Summary status L */ - td_obuf[td_obptr++] = 0; /* Summary status H */ - c = 0; - for (i = 0; i < (0xA + 2); i++) { /* Calculate checksum */ - w = (td_obuf[i] << ((i & 0x1) ? 8 : 0)); - c = c + w + ( (uint32)((uint32)c + (uint32)w) > 0xFFFF ? 1 : 0); - } - td_obuf[td_obptr++] = c & 0xFF; /* Checksum L */ - td_obuf[td_obptr++] = (c >> 8) & 0xFF; /* Checksum H */ - td_olen = td_obptr; - td_obptr = 0; - td_state = TD_END1; /* go empty */ - sim_debug(TDDEB_PKT, &td_dev, "END PKT: Generated - Success Code: %X\n", td_ecode); - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_END1: /* send end packet to host */ - if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ - csi_buf = td_obuf[td_obptr++]; /* get next byte */ - csi_csr = csi_csr | CSR_DONE; /* set input flag */ - if (csi_csr & CSR_IE) { - csi_int = 1; - sim_debug (TDDEB_INT, &td_dev, "CSI_INT(1)\n"); - } - if (td_obptr >= td_olen) { /* buffer empty? */ - sim_debug(TDDEB_PKT, &td_dev, "END PKT: Sent\n"); - td_state = TD_IDLE; - break; - } - } - sim_activate (uptr, td_xwait); /* schedule next */ - break; - - case TD_INIT: - if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ - csi_buf = TD_OPCNT; - csi_csr = csi_csr | CSR_DONE; /* set input flag */ - if (csi_csr & CSR_IE) { - csi_int = 1; - sim_debug (TDDEB_INT, &td_dev, "CSI_INT(1)\n"); - } - td_state = TD_IDLE; - break; - } - sim_activate (uptr, td_xwait); /* schedule next */ - break; - } -return SCPE_OK; -} - -/* Test for data transfer okay */ - -t_bool td_test_xfr (UNIT *uptr, int32 state) -{ -if ((uptr->flags & UNIT_BUF) == 0) /* not buffered? */ - td_ecode = TD_STSNC; -else if (td_block >= TD_NUMBLK) /* bad block? */ - td_ecode = TD_STSBBN; -else if ((state == TD_WRITE) && (uptr->flags & UNIT_WPRT)) /* write and locked? */ - td_ecode = TD_STSWP; -else { - td_ecode = TD_STSOK; - return TRUE; - } -return FALSE; -} - /* Reset */ t_stat td_reset (DEVICE *dptr) { -cso_buf = 0; -cso_csr = CSR_DONE; -cso_int = 0; -sim_debug (TDDEB_INT, &td_dev, "CSO_INT(0)\n"); -cso_state = TD_GETOPC; -td_ibptr = 0; -td_obptr = 0; -td_olen = 0; -td_offset = 0; -td_txsize = 0; -sim_cancel (&td_unit); -return SCPE_OK; +return td_connect_console_device (&td_dev, set_csi_int, set_cso_int); } const char *td_description (DEVICE *dptr) diff --git a/VAX/vax750_syslist.c b/VAX/vax750_syslist.c index 7ba663f5..e4c600fa 100644 --- a/VAX/vax750_syslist.c +++ b/VAX/vax750_syslist.c @@ -41,6 +41,7 @@ extern DEVICE clk_dev; extern DEVICE tmr_dev; extern DEVICE tti_dev, tto_dev; extern DEVICE td_dev; +extern DEVICE tdc_dev; extern DEVICE cr_dev; extern DEVICE lpt_dev; extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; @@ -73,6 +74,7 @@ DEVICE *sim_devices[] = { &tti_dev, &tto_dev, &td_dev, + &tdc_dev, &dz_dev, &vh_dev, &cr_dev, diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index 959e145a..5bb9b253 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -323,6 +323,8 @@ typedef struct { #define INT_V_CR 3 #define INT_V_VHRX 4 #define INT_V_VHTX 5 +#define INT_V_TDRX 6 +#define INT_V_TDTX 7 #define INT_DZRX (1u << INT_V_DZRX) #define INT_DZTX (1u << INT_V_DZTX) @@ -343,6 +345,8 @@ typedef struct { #define INT_DMCTX (1u << INT_V_DMCTX) #define INT_DUPRX (1u << INT_V_DUPRX) #define INT_DUPTX (1u << INT_V_DUPTX) +#define INT_TDRX (1u << INT_V_TDRX) +#define INT_TDTX (1u << INT_V_TDTX) #define IPL_DZRX (0x15 - IPL_HMIN) #define IPL_DZTX (0x15 - IPL_HMIN) @@ -363,6 +367,8 @@ typedef struct { #define IPL_DMCTX (0x15 - IPL_HMIN) #define IPL_DUPRX (0x15 - IPL_HMIN) #define IPL_DUPTX (0x15 - IPL_HMIN) +#define IPL_TDRX (0x14 - IPL_HMIN) +#define IPL_TDTX (0x14 - IPL_HMIN) /* Device vectors */ diff --git a/VAX/vax780_syslist.c b/VAX/vax780_syslist.c index 44bdf301..52e124f7 100644 --- a/VAX/vax780_syslist.c +++ b/VAX/vax780_syslist.c @@ -48,6 +48,7 @@ extern DEVICE clk_dev; extern DEVICE tmr_dev; extern DEVICE tti_dev, tto_dev; extern DEVICE fl_dev; +extern DEVICE tdc_dev; extern DEVICE cr_dev; extern DEVICE lpt_dev; extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; @@ -81,6 +82,7 @@ DEVICE *sim_devices[] = { &tti_dev, &tto_dev, &fl_dev, + &tdc_dev, &dz_dev, &vh_dev, &cr_dev, diff --git a/VAX/vax860_defs.h b/VAX/vax860_defs.h index 4bc6f156..209c8838 100644 --- a/VAX/vax860_defs.h +++ b/VAX/vax860_defs.h @@ -353,6 +353,8 @@ typedef struct { #define INT_V_CR 3 #define INT_V_VHRX 4 #define INT_V_VHTX 5 +#define INT_V_TDRX 6 +#define INT_V_TDTX 7 #define INT_DZRX (1u << INT_V_DZRX) #define INT_DZTX (1u << INT_V_DZTX) @@ -373,6 +375,8 @@ typedef struct { #define INT_DMCTX (1u << INT_V_DMCTX) #define INT_DUPRX (1u << INT_V_DUPRX) #define INT_DUPTX (1u << INT_V_DUPTX) +#define INT_TDRX (1u << INT_V_TDRX) +#define INT_TDTX (1u << INT_V_TDTX) #define IPL_DZRX (0x15 - IPL_HMIN) #define IPL_DZTX (0x15 - IPL_HMIN) @@ -393,6 +397,8 @@ typedef struct { #define IPL_DMCTX (0x15 - IPL_HMIN) #define IPL_DUPRX (0x15 - IPL_HMIN) #define IPL_DUPTX (0x15 - IPL_HMIN) +#define IPL_TDRX (0x14 - IPL_HMIN) +#define IPL_TDTX (0x14 - IPL_HMIN) /* Device vectors */ diff --git a/VAX/vax860_syslist.c b/VAX/vax860_syslist.c index 243fa314..ab2f8069 100644 --- a/VAX/vax860_syslist.c +++ b/VAX/vax860_syslist.c @@ -48,6 +48,7 @@ extern DEVICE clk_dev; extern DEVICE tmr_dev; extern DEVICE tti_dev, tto_dev; extern DEVICE rlcs_dev; +extern DEVICE tdc_dev; extern DEVICE cr_dev; extern DEVICE lpt_dev; extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; @@ -79,6 +80,7 @@ DEVICE *sim_devices[] = { &tti_dev, &tto_dev, &rlcs_dev, + &tdc_dev, &dz_dev, &vh_dev, &cr_dev, diff --git a/VAX/vax_syslist.c b/VAX/vax_syslist.c index 635619e5..3d5f158f 100644 --- a/VAX/vax_syslist.c +++ b/VAX/vax_syslist.c @@ -46,6 +46,7 @@ extern DEVICE nvr_dev; extern DEVICE sysd_dev; extern DEVICE qba_dev; extern DEVICE tti_dev, tto_dev; +extern DEVICE tdc_dev; extern DEVICE cr_dev; extern DEVICE lpt_dev; extern DEVICE clk_dev; @@ -77,6 +78,7 @@ DEVICE *sim_devices[] = { &tto_dev, &csi_dev, &cso_dev, + &tdc_dev, &dz_dev, &vh_dev, &cr_dev, diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index d78cb99b..4bf1239b 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -344,6 +344,8 @@ typedef struct { #define INT_V_QVSS 21 /* QVSS */ #define INT_V_DMCRX 22 /* DMC11 */ #define INT_V_DMCTX 23 +#define INT_V_TDRX 24 /* TU58 */ +#define INT_V_TDTX 25 #define INT_CLK (1u << INT_V_CLK) #define INT_RQ (1u << INT_V_RQ) @@ -370,6 +372,8 @@ typedef struct { #define INT_QVSS (1u << INT_V_QVSS) #define INT_DMCRX (1u << INT_V_DMCRX) #define INT_DMCTX (1u << INT_V_DMCTX) +#define INT_TDRX (1u << INT_V_TDRX) +#define INT_TDTX (1u << INT_V_TDTX) #define IPL_CLK (0x16 - IPL_HMIN) /* relative IPL */ #define IPL_RQ (0x14 - IPL_HMIN) @@ -396,6 +400,8 @@ typedef struct { #define IPL_QVSS (0x14 - IPL_HMIN) #define IPL_DMCRX (0x14 - IPL_HMIN) #define IPL_DMCTX (0x14 - IPL_HMIN) +#define IPL_TDRX (0x14 - IPL_HMIN) +#define IPL_TDTX (0x14 - IPL_HMIN) #define IPL_HMAX 0x17 /* highest hwre level */ #define IPL_HMIN 0x14 /* lowest hwre level */ diff --git a/Visual Studio Projects/MicroVAX1.vcproj b/Visual Studio Projects/MicroVAX1.vcproj index 670a57de..b813e99b 100644 --- a/Visual Studio Projects/MicroVAX1.vcproj +++ b/Visual Studio Projects/MicroVAX1.vcproj @@ -220,6 +220,10 @@ RelativePath="..\PDP11\pdp11_rq.c" > + + @@ -390,6 +394,10 @@ RelativePath="..\PDP11\pdp11_mscp.h" > + + diff --git a/Visual Studio Projects/MicroVAX2.vcproj b/Visual Studio Projects/MicroVAX2.vcproj index 488e8e18..e3470838 100644 --- a/Visual Studio Projects/MicroVAX2.vcproj +++ b/Visual Studio Projects/MicroVAX2.vcproj @@ -220,6 +220,10 @@ RelativePath="..\PDP11\pdp11_rq.c" > + + @@ -390,6 +394,10 @@ RelativePath="..\PDP11\pdp11_mscp.h" > + + diff --git a/Visual Studio Projects/PDP11.vcproj b/Visual Studio Projects/PDP11.vcproj index 99ca255c..126cd96d 100644 --- a/Visual Studio Projects/PDP11.vcproj +++ b/Visual Studio Projects/PDP11.vcproj @@ -326,6 +326,10 @@ RelativePath="..\PDP11\pdp11_tc.c" > + + @@ -463,6 +467,10 @@ RelativePath="..\PDP11\pdp11_mscp.h" > + + diff --git a/Visual Studio Projects/VAX.vcproj b/Visual Studio Projects/VAX.vcproj index 1336d643..a6f34fb1 100644 --- a/Visual Studio Projects/VAX.vcproj +++ b/Visual Studio Projects/VAX.vcproj @@ -224,6 +224,10 @@ RelativePath="..\PDP11\pdp11_rq.c" > + + @@ -390,6 +394,10 @@ RelativePath="..\PDP11\pdp11_mscp.h" > + + diff --git a/Visual Studio Projects/VAX730.vcproj b/Visual Studio Projects/VAX730.vcproj index 4c8b95a2..a1a87f3b 100644 --- a/Visual Studio Projects/VAX730.vcproj +++ b/Visual Studio Projects/VAX730.vcproj @@ -229,6 +229,10 @@ RelativePath="..\PDP11\pdp11_ry.c" > + + @@ -390,6 +394,10 @@ RelativePath="..\PDP11\pdp11_mscp.h" > + + diff --git a/Visual Studio Projects/VAX750.vcproj b/Visual Studio Projects/VAX750.vcproj index 742bcbee..0f61eee7 100644 --- a/Visual Studio Projects/VAX750.vcproj +++ b/Visual Studio Projects/VAX750.vcproj @@ -233,6 +233,10 @@ RelativePath="..\PDP11\pdp11_ry.c" > + + @@ -398,6 +402,10 @@ RelativePath="..\PDP11\pdp11_mscp.h" > + + diff --git a/Visual Studio Projects/VAX780.vcproj b/Visual Studio Projects/VAX780.vcproj index 1beac2a8..5920979a 100644 --- a/Visual Studio Projects/VAX780.vcproj +++ b/Visual Studio Projects/VAX780.vcproj @@ -238,6 +238,10 @@ RelativePath="..\PDP11\pdp11_ry.c" > + + @@ -408,6 +412,10 @@ RelativePath="..\PDP11\pdp11_mscp.h" > + + diff --git a/Visual Studio Projects/VAX8600.vcproj b/Visual Studio Projects/VAX8600.vcproj index fe7f8eca..a9d7b0bd 100644 --- a/Visual Studio Projects/VAX8600.vcproj +++ b/Visual Studio Projects/VAX8600.vcproj @@ -238,6 +238,10 @@ RelativePath="..\PDP11\pdp11_ry.c" > + + @@ -400,6 +404,10 @@ RelativePath="..\PDP11\pdp11_mscp.h" > + + diff --git a/Visual Studio Projects/rtVAX1000.vcproj b/Visual Studio Projects/rtVAX1000.vcproj index 7a97c9d0..096cd937 100644 --- a/Visual Studio Projects/rtVAX1000.vcproj +++ b/Visual Studio Projects/rtVAX1000.vcproj @@ -220,6 +220,10 @@ RelativePath="..\PDP11\pdp11_rq.c" > + + @@ -390,6 +394,10 @@ RelativePath="..\PDP11\pdp11_mscp.h" > + + diff --git a/descrip.mms b/descrip.mms index d5b9d972..41f67d47 100644 --- a/descrip.mms +++ b/descrip.mms @@ -548,7 +548,7 @@ PDP11_SOURCE1 = $(PDP11_DIR)PDP11_FP.C,$(PDP11_DIR)PDP11_CPU.C,\ PDP11_LIB2 = $(LIB_DIR)PDP11L2-$(ARCH).OLB PDP11_SOURCE2 = $(PDP11_DIR)PDP11_TM.C,$(PDP11_DIR)PDP11_TS.C,\ $(PDP11_DIR)PDP11_IO.C,$(PDP11_DIR)PDP11_RQ.C,\ - $(PDP11_DIR)PDP11_TQ.C,$(PDP11_DIR)PDP11_PCLK.C,\ + $(PDP11_DIR)PDP11_TD.C,$(PDP11_DIR)PDP11_TQ.C,$(PDP11_DIR)PDP11_PCLK.C,\ $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_PT.C,\ $(PDP11_DIR)PDP11_HK.C,$(PDP11_DIR)PDP11_XQ.C,\ $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_RH.C,\ @@ -657,7 +657,7 @@ VAX_SOURCE1 = $(VAX_DIR)VAX_CIS.C,$(VAX_DIR)VAX_CMODE.C,\ VAX_SOURCE2 = $(PDP11_DIR)PDP11_IO_LIB.C,\ $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ - $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TD.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_XQ.C,$(PDP11_DIR)PDP11_VH.C,\ $(PDP11_DIR)PDP11_CR.C,\ $(VAX_DIR)VAX_VC.C,$(VAX_DIR)VAX_LK.C,\ @@ -687,7 +687,7 @@ VAX610_LIB2 = $(LIB_DIR)VAX610L2-$(ARCH).OLB VAX610_SOURCE2 = $(PDP11_DIR)PDP11_IO_LIB.C,\ $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ - $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TD.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_XQ.C,$(PDP11_DIR)PDP11_VH.C,\ $(PDP11_DIR)PDP11_CR.C,$(VAX610_DIR)VAX_VC.C,\ $(VAX610_DIR)VAX_LK.C,$(VAX610_DIR)VAX_VS.C,\ @@ -717,7 +717,7 @@ VAX630_LIB2 = $(LIB_DIR)VAX630L2-$(ARCH).OLB VAX630_SOURCE2 = $(PDP11_DIR)PDP11_IO_LIB.C,\ $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ - $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TD.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_XQ.C,$(PDP11_DIR)PDP11_VH.C,\ $(PDP11_DIR)PDP11_CR.C,$(VAX630_DIR)VAX_VC.C,\ $(VAX630_DIR)VAX_LK.C,$(VAX630_DIR)VAX_VS.C,\ @@ -747,7 +747,7 @@ VAX620_LIB2 = $(LIB_DIR)VAX620L2-$(ARCH).OLB VAX620_SOURCE2 = $(PDP11_DIR)PDP11_IO_LIB.C,\ $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ - $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TD.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_XQ.C,$(PDP11_DIR)PDP11_VH.C,\ $(PDP11_DIR)PDP11_CR.C,$(VAX620_DIR)VAX_VC.C,\ $(VAX620_DIR)VAX_LK.C,$(VAX620_DIR)VAX_VS.C,\ @@ -777,7 +777,7 @@ VAX730_SOURCE1 = $(VAX730_DIR)VAX_CPU.C,$(VAX730_DIR)VAX_CPU1.C,\ VAX730_LIB2 = $(LIB_DIR)VAX730L2-$(ARCH).OLB VAX730_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ - $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TD.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_RY.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_HK.C,\ $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_DMC.C,\ @@ -807,7 +807,7 @@ VAX750_SOURCE1 = $(VAX750_DIR)VAX_CPU.C,$(VAX750_DIR)VAX_CPU1.C,\ VAX750_LIB2 = $(LIB_DIR)VAX750L2-$(ARCH).OLB VAX750_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ - $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TD.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_RY.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_HK.C,\ $(PDP11_DIR)PDP11_RP.C,$(PDP11_DIR)PDP11_TU.C,\ @@ -838,7 +838,7 @@ VAX780_SOURCE1 = $(VAX780_DIR)VAX_CPU.C,$(VAX780_DIR)VAX_CPU1.C,\ VAX780_LIB2 = $(LIB_DIR)VAX780L2-$(ARCH).OLB VAX780_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ - $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TD.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_RY.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_RP.C,\ $(PDP11_DIR)PDP11_TU.C,$(PDP11_DIR)PDP11_HK.C,\ @@ -869,7 +869,7 @@ VAX8600_SOURCE1 = $(VAX8600_DIR)VAX_CPU.C,$(VAX8600_DIR)VAX_CPU1.C,\ VAX8600_LIB2 = $(LIB_DIR)VAX860L2-$(ARCH).OLB VAX8600_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ - $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TD.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_RY.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_RP.C,\ $(PDP11_DIR)PDP11_TU.C,$(PDP11_DIR)PDP11_HK.C,\ diff --git a/makefile b/makefile index 9bf3e339..2066a55e 100644 --- a/makefile +++ b/makefile @@ -947,7 +947,7 @@ PDP11 = ${PDP11D}/pdp11_fp.c ${PDP11D}/pdp11_cpu.c ${PDP11D}/pdp11_dz.c \ ${PDP11D}/pdp11_ta.c ${PDP11D}/pdp11_rc.c ${PDP11D}/pdp11_kg.c \ ${PDP11D}/pdp11_ke.c ${PDP11D}/pdp11_dc.c ${PDP11D}/pdp11_dmc.c \ ${PDP11D}/pdp11_kmc.c ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_rs.c \ - ${PDP11D}/pdp11_vt.c ${PDP11D}/pdp11_io_lib.c $(DISPLAYL) $(DISPLAYVT) + ${PDP11D}/pdp11_vt.c ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c $(DISPLAYL) $(DISPLAYVT) PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} $(DISPLAY_OPT) @@ -960,7 +960,7 @@ VAX = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c ${VAXD}/vax_io.c \ ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ - ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c VAX_OPT = -DVM_VAX -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} @@ -973,7 +973,7 @@ VAX610 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ - ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c VAX610_OPT = -DVM_VAX -DVAX_610 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} VAX630 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -985,7 +985,7 @@ VAX630 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ - ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c VAX620_OPT = -DVM_VAX -DVAX_620 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} VAX630_OPT = -DVM_VAX -DVAX_630 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} @@ -1000,7 +1000,7 @@ VAX730 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_hk.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c \ - ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_io_lib.c VAX730_OPT = -DVM_VAX -DVAX_730 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} @@ -1015,7 +1015,7 @@ VAX750 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_hk.c ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c \ ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_dup.c \ - ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c VAX750_OPT = -DVM_VAX -DVAX_750 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} @@ -1030,7 +1030,7 @@ VAX780 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_hk.c \ ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_dup.c \ - ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c VAX780_OPT = -DVM_VAX -DVAX_780 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} @@ -1045,7 +1045,7 @@ VAX8600 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_hk.c \ ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_dup.c \ - ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c VAX8600_OPT = -DVM_VAX -DVAX_860 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT}