B5500: Initial checking of simulator for current simh

The B5500 simulator supports the following peripherals.

Two CPUs with between 4K and 32K of memory. The second CPU can be
enabled with "set cpu1 enable". "set cpu1 disable" disables the
second CPU.

Up to 4 floating IO channels. Individual channels can be enabled with
"set io# enable", or "set io# disable".

There are two card readers. The second reader is disabled by default.

There is one Card Punch.

The Card reader and Card Punch support the following options:
  set cr format=

     auto   - will automatically determine the format based on the
              text it recieves.
     text     Text based cards. Tabs are converted to the correct
              number of spaces. A record of
              ~raw octal will enter a binary card.
              ~eor will enter a 7/8/9 punch in column 1.
              ~eof will enter a 6/7/9 punch in column 1.
              ~eoi will enter a 6/7/8/9 punch in column 1.
              ~~ will enter a ~ as the first character.

     bin      Binary Card format:
              Each record 160 characters.
              First characters 6789----
              Second character 21012345
                               111
              Top 4 bits of second character are 0.
              It is unlikely that any other format could
              look like this.

     bcd      BCD Format:
              Each record variable length (80 chars or less).
              Record mark has bit 7 set.
              Bit 6 is even parity.
              Bits 5-0 are character.

    cbn       CBN Format:
              Each record 160 charaters.
              First char has bit 7 set. Rest set to 0.
              Bit 6 is odd parity.
              Bit 5-0 of first character are top 6 bits
                      of card.
              Bit 5-0 of second character are lower 6 bits
                      of card.

    For punch format of auto if the card can't be converted to text it is
    output as a raw record.

 There are two line printers, the second one is disabled by default. The LP
 supports the option "set lp# linesperpage=#" which determines when the
 printer will force out a page break.

 There are up to 16 mag tape drives, the format is controlled by the standard
 simh format control for tapes. These are 6 bit tapes, 1 character per record
 with parity. Units 8-16 are disabled by default.

 There are up to two drum units DR0 and DR1. These can either be attached
 to a file or set to AUXMEM. Setting to AUXMEM causes them to exist only
 during the given simh run. Setting back to DRUM will clear whatever was
 stored on the drum. To enable use of DRUM on XV the following options should
 be turned on "DRA,DRB,CODEOLAY,DATAOLAY". MCP will then use the drum as a
 overlay device instead of the disk system.

 Disks can be attached to the various ESU's, ESU0-9 are on DKA by default,
 ESU10-19 are on DKB. If "set dk1 dfx" is set, then ESU10-19 are not used and
 the disks are shared by both DKA and DKB. To use more then 10 ESU's in a non
 shared mode, a new version of MCP must be created. MCP must be compiled with
 DFX option set to false. For MCP XV DKBNODFX must also be set to true.  ESU units
 can be set to MODI or MODIB. MODIB will double the size of the drive.

 The DTC can be attached to a telnet port with "attach dtc #" to enable dialup
 access to the sim.

The loader card for the card reader is:
~raw0104441100204231524012004000004444550211002041317700000000000024045303040243
00050000006501004131011041310055005500000062005042310000006600304231000000720010
42310000007675610165001002310010413100040107202500440106202533554061256520252265
20251765202514655355536117650000004401062025155522610165225572610465044101160500
4131

  This card should be all in one line.
This commit is contained in:
Richard Cornwell 2016-02-06 15:51:04 -05:00
parent 4d51d63ae4
commit 0a33758e47
11 changed files with 10339 additions and 0 deletions

3903
B5500/b5500_cpu.c Normal file

File diff suppressed because it is too large Load diff

570
B5500/b5500_defs.h Normal file
View file

@ -0,0 +1,570 @@
/* b5500_defs.h: Burroughs 5500 simulator definitions
Copyright (c) 2016, Richard Cornwell
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
RICHARD CORNWELL 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.
*/
#ifndef _B5500_H_
#define _B5500_H_
#include "sim_defs.h" /* simulator defns */
/* Definitions for each supported CPU */
#define NUM_DEVS_CDR 2
#define NUM_DEVS_CDP 1
#define NUM_DEVS_LPR 2
#define NUM_DEVS_CON 1
#define NUM_DEVS_DR 2
#define NUM_DEVS_MT 16
#define NUM_DEVS_DSK 2
#define NUM_DEVS_DTC 1
#define NUM_CHAN 4
#define MAXMEMSIZE 32768
#define CHARSPERWORD 8
extern t_uint64 M[]; /* Main Memory */
extern uint16 IAR; /* Interrupt pending register */
extern uint32 iostatus; /* Active device status register */
extern uint8 loading; /* System booting flag */
/* Memory */
#define MEMSIZE (cpu_unit[0].capac) /* actual memory size */
#define MEMMASK (MEMSIZE - 1) /* Memory bits */
/* Debuging controls */
#define DEBUG_CHAN 0x0000001 /* Show channel fetchs */
#define DEBUG_TRAP 0x0000002 /* Show CPU Traps */
#define DEBUG_CMD 0x0000004 /* Show device commands */
#define DEBUG_DATA 0x0000008 /* Show data transfers */
#define DEBUG_DETAIL 0x0000010 /* Show details */
#define DEBUG_EXP 0x0000020 /* Show error conditions */
#define DEBUG_SNS 0x0000040 /* Shows sense data for 7909 devs */
#define DEBUG_CTSS 0x0000080 /* Shows CTSS specail instructions */
#define DEBUG_PROT 0x0000100 /* Protection traps */
extern DEBTAB dev_debug[];
/* Returns from device commands */
#define SCPE_BUSY (1) /* Device is active */
#define SCPE_NODEV (2) /* No device exists */
/* Symbol tables */
typedef struct _opcode
{
uint16 op;
uint8 type;
char *name;
}
t_opcode;
/* I/O Command codes */
#define IO_RDS 1 /* Read record */
#define IO_BSR 2 /* Backspace one record */
#define IO_BSF 3 /* Backspace one file */
#define IO_WRS 4 /* Write one record */
#define IO_WEF 5 /* Write eof */
#define IO_REW 6 /* Rewind */
#define IO_DRS 7 /* Set unit offline */
#define IO_SDL 8 /* Set density low */
#define IO_SDH 9 /* Set density high */
#define IO_RUN 10 /* Rewind and unload unit */
#define IO_TRS 11 /* Check it unit ready */
#define IO_CTL 12 /* Io control device specific */
#define IO_RDB 13 /* Read backwards */
#define IO_SKR 14 /* Skip record forward */
#define IO_ERG 15 /* Erase next records from tape */
t_stat chan_reset(DEVICE *);
t_stat chan_boot(t_uint64);
int find_chan();
void chan_release(int);
void start_io();
void chan_set_end(int) ;
void chan_set_parity(int) ;
void chan_set_eof(int) ;
void chan_set_read(int) ;
void chan_set_wcflg(int) ;
void chan_set_gm(int) ;
void chan_set_error(int) ;
void chan_set_notrdy(int) ;
void chan_set_bot(int) ;
void chan_set_eot(int) ;
void chan_set_wrp(int) ;
void chan_set_blank(int) ;
void chan_set_wc(int, uint16);
int chan_write_char(int, uint8 *, int) ;
int chan_read_char(int, uint8 *, int) ;
int chan_read_disk(int, uint8 *, int) ;
int chan_write_drum(int, uint8 *, int) ;
int chan_read_drum(int, uint8 *, int) ;
extern uint8 parity_table[64];
extern uint8 mem_to_ascii[64];
extern const char con_to_ascii[64];
extern const char ascii_to_con[128];
extern t_stat fprint_sym(FILE *, t_addr, t_value *, UNIT *, int32);
extern int32 tmxr_poll;
/* Generic devices common to all */
extern DEVICE cpu_dev;
extern UNIT cpu_unit[];
extern REG cpu_reg[];
extern DEVICE chan_dev;
/* Global device definitions */
#if (NUM_DEVS_CDR > 0) | (NUM_DEVS_CDP > 0)
extern DEVICE cdr_dev;
extern t_stat card_cmd(uint16, uint16, uint8, uint16 *);
#endif
#if (NUM_DEVS_CDP > 0)
extern DEVICE cdp_dev;
#endif
#if (NUM_DEVS_LPR > 0)
extern DEVICE lpr_dev;
extern t_stat lpr_cmd(uint16, uint16, uint8, uint16 *);
#endif
#if (NUM_DEVS_CON > 0)
extern DEVICE con_dev;
extern t_stat con_cmd(uint16, uint16, uint8, uint16 *);
#endif
#if (NUM_DEVS_DTC > 0)
extern DEVICE dtc_dev;
extern t_stat dtc_cmd(uint16, uint16, uint8, uint16 *);
#endif
#if (NUM_DEVS_DR > 0)
extern DEVICE drm_dev;
extern t_stat drm_cmd(uint16, uint16, uint8, uint16 *, uint8);
#endif
#if (NUM_DEVS_DSK > 0)
extern DEVICE dsk_dev;
extern t_stat dsk_cmd(uint16, uint16, uint8, uint16 *);
extern DEVICE esu_dev;
#endif
#if (NUM_DEVS_MT > 0)
extern DEVICE mt_dev;
extern t_stat mt_cmd(uint16, uint16, uint8, uint16 *);
#endif /* NUM_DEVS_MT */
/* Character codes */
#define CHR_ABLANK 000
#define CHR_MARK CHR_ABLANK
#define CHR_1 001
#define CHR_2 002
#define CHR_3 003
#define CHR_4 004
#define CHR_5 005
#define CHR_6 006
#define CHR_7 007
#define CHR_8 010
#define CHR_9 011
#define CHR_0 012
#define CHR_EQ 013
#define CHR_QUOT 014 /* Also @ */
#define CHR_COL 015
#define CHR_GT 016
#define CHR_TRM 017
#define CHR_BLANK 020
#define CHR_SLSH 021
#define CHR_S 022
#define CHR_T 023
#define CHR_U 024
#define CHR_V 025
#define CHR_W 026
#define CHR_X 027
#define CHR_Y 030
#define CHR_Z 031
#define CHR_RM 032
#define CHR_COM 033
#define CHR_RPARN 034 /* Also % */
#define CHR_WM 035
#define CHR_BSLSH 036
#define CHR_UND 037
#define CHR_MINUS 040
#define CHR_J 041
#define CHR_K 042
#define CHR_L 043
#define CHR_M 044
#define CHR_N 045
#define CHR_O 046
#define CHR_P 047
#define CHR_Q 050
#define CHR_R 051
#define CHR_EXPL 052
#define CHR_DOL 053
#define CHR_STAR 054
#define CHR_LBRK 055
#define CHR_SEMI 056
#define CHR_CART 057
#define CHR_PLUS 060
#define CHR_A 061
#define CHR_B 062
#define CHR_C 063
#define CHR_D 064
#define CHR_E 065
#define CHR_F 066
#define CHR_G 067
#define CHR_H 070
#define CHR_I 071
#define CHR_QUEST 072
#define CHR_DOT 073
#define CHR_LPARN 074 /* Also Square */
#define CHR_RBRAK 075
#define CHR_LESS 076
#define CHR_GM 077
/* Word mode opcodes */
#define WMOP_LITC 00000 /* Load literal */
#define WMOP_OPDC 00002 /* Load operand */
#define WMOP_DESC 00003 /* Load Descriptor */
#define WMOP_OPR 00001 /* Operator */
#define WMOP_DEL 00065 /* Delete top of stack */
#define WMOP_NOP 00055 /* Nop operation */
#define WMOP_XRT 00061 /* Set Variant */
#define WMOP_ADD 00101 /* Add */
#define WMOP_DLA 00105 /* Double Precision Add */
#define WMOP_PRL 00111 /* Program Release */
#define WMOP_LNG 00115 /* Logical Negate */
#define WMOP_CID 00121 /* Conditional Integer Store Destructive */
#define WMOP_GEQ 00125 /* WMOP_B greater than or equal to A */
#define WMOP_BBC 00131 /* Branch Backward Conditional */
#define WMOP_BRT 00135 /* Branch Return */
#define WMOP_INX 00141 /* Index */
#define WMOP_ITI 00211 /* Interrogate interrupt */
#define WMOP_LOR 00215 /* Logical Or */
#define WMOP_CIN 00221 /* Conditional Integer Store non-destructive */
#define WMOP_GTR 00225 /* B Greater than A */
#define WMOP_BFC 00231 /* Branch Forward Conditional */
#define WMOP_RTN 00235 /* Return normal */
#define WMOP_COC 00241 /* Construct Operand Call */
#define WMOP_SUB 00301 /* Subtract */
#define WMOP_DLS 00305 /* WMOP_Double Precision Subtract */
#define WMOP_MUL 00401 /* Multiply */
#define WMOP_DLM 00405 /* Double Precision Multiply */
#define WMOP_RTR 00411 /* Read Timer */
#define WMOP_LND 00415 /* Logical And */
#define WMOP_STD 00421 /* B Store Destructive */
#define WMOP_NEQ 00425 /* B Not equal to A */
#define WMOP_SSN 00431 /* Set Sign Bit */
#define WMOP_XIT 00435 /* Exit */
#define WMOP_MKS 00441 /* Mark Stack */
#define WMOP_DIV 01001 /* Divide */
#define WMOP_DLD 01005 /* Double Precision Divide */
#define WMOP_COM 01011 /* Communication operator */
#define WMOP_LQV 01015 /* Logical Equivalence */
#define WMOP_SND 01021 /* B Store Non-destructive */
#define WMOP_XCH 01025 /* Exchange */
#define WMOP_CHS 01031 /* Change sign bit */
#define WMOP_RTS 01235 /* Return Special */
#define WMOP_CDC 01241 /* Construct descriptor call */
#define WMOP_FTC 01425 /* Transfer F Field to Core Field */
#define WMOP_MOP 02015 /* Reset Flag bit */
#define WMOP_LOD 02021 /* Load */
#define WMOP_DUP 02025 /* Duplicate */
#define WMOP_TOP 02031 /* Test Flag Bit */
#define WMOP_IOR 02111 /* I/O Release */
#define WMOP_LBC 02131 /* Word Branch Backward Conditional */
#define WMOP_SSF 02141 /* Set or Store S or F registers */
#define WMOP_HP2 02211 /* Halt P2 */
#define WMOP_LFC 02231 /* Word Branch Forward Conditional */
#define WMOP_ZP1 02411 /* Conditional Halt */
#define WMOP_TUS 02431 /* Interrogate Peripheral Status */
#define WMOP_LLL 02541 /* Link List Look-up */
#define WMOP_IDV 03001 /* Integer Divide Integer */
#define WMOP_SFI 03011 /* Store for Interrupt */
#define WMOP_SFT 03411 /* Store for Test */
#define WMOP_FTF 03425 /* Transfer F Field to F Field */
#define WMOP_MDS 04015 /* Set Flag Bit */
#define WMOP_IP1 04111 /* Initiate P1 */
#define WMOP_ISD 04121 /* Interger Store Destructive */
#define WMOP_LEQ 04125 /* B Less Than or Equal to A */
#define WMOP_BBW 04131 /* Banch Backward Conditional */
#define WMOP_IP2 04211 /* Initiate P2 */
#define WMOP_ISN 04221 /* Integer Store Non-Destructive */
#define WMOP_LSS 04225 /* B Less Than A */
#define WMOP_BFW 04231 /* Branch Forward Unconditional */
#define WMOP_IIO 04411 /* Initiate I/O */
#define WMOP_EQL 04425 /* B Equal A */
#define WMOP_SSP 04431 /* Reset Sign Bit */
#define WMOP_CMN 04441 /* Enter Character Mode In Line */
#define WMOP_IFT 05111 /* Test Initiate */
#define WMOP_CTC 05425 /* Transfer Core Field to Core Field */
#define WMOP_LBU 06131 /* Word Branch Backward Unconditional */
#define WMOP_LFU 06231 /* Word Branch Forward Unconditional */
#define WMOP_TIO 06431 /* Interrogate I/O Channels */
#define WMOP_RDV 07001 /* Remainder Divide */
#define WMOP_FBS 07031 /* Flag Bit Search */
#define WMOP_CTF 07425 /* Transfer Core Field to F Field */
#define WMOP_ISO 00045 /* Variable Field Isolate XX */
#define WMOP_CBD 00351 /* Non-Zero Field Branch Backward Destructive Xy */
#define WMOP_CBN 00151 /* Non-Zero Field Branch Backward Non-Destructive Xy */
#define WMOP_CFD 00251 /* Non-Zero Field Branch Forward Destructive Xy */
#define WMOP_CFN 00051 /* Non-Zero Field Branch Forward Non-Destructive Xy */
#define WMOP_DIA 00055 /* Dial A XX */
#define WMOP_DIB 00061 /* Dial B XX Upper 6 not Zero */
#define WMOP_TRB 00065 /* Transfer Bits XX */
#define WMOP_FCL 00071 /* Compare Field Low XX */
#define WMOP_FCE 00075 /* Compare Field Equal XX */
/* Character Mode */
#define CMOP_EXC 00000 /* CMOP_Exit Character Mode */
#define CMOP_CMX 00100 /* Exit Character Mode In Line */
#define CMOP_BSD 00002 /* Skip Bit Destiniation */
#define CMOP_BSS 00003 /* SKip Bit Source */
#define CMOP_RDA 00004 /* Recall Destination Address */
#define CMOP_TRW 00005 /* Transfer Words */
#define CMOP_SED 00006 /* Set Destination Address */
#define CMOP_TDA 00007 /* Transfer Destination Address */
#define CMOP_TBN 00012 /* Transfer Blanks for Non-Numerics */
#define CMOP_SDA 00014 /* Store Destination Address */
#define CMOP_SSA 00015 /* Store Source Address */
#define CMOP_SFD 00016 /* Skip Forward Destination */
#define CMOP_SRD 00017 /* Skip Reverse Destination */
#define CMOP_SES 00022 /* Set Source Address */
#define CMOP_TEQ 00024 /* Test for Equal */
#define CMOP_TNE 00025 /* Test for Not-Equal */
#define CMOP_TEG 00026 /* Test for Greater Or Equal */
#define CMOP_TGR 00027 /* Test For Greater */
#define CMOP_SRS 00030 /* Skip Reverse Source */
#define CMOP_SFS 00031 /* Skip Forward Source */
#define CMOP_TEL 00034 /* Test For Equal or Less */
#define CMOP_TLS 00035 /* Test For Less */
#define CMOP_TAN 00036 /* Test for Alphanumeric */
#define CMOP_BIT 00037 /* Test Bit */
#define CMOP_INC 00040 /* Increase Tally */
#define CMOP_STC 00041 /* Store Tally */
#define CMOP_SEC 00042 /* Set Tally */
#define CMOP_CRF 00043 /* Call repeat Field */
#define CMOP_JNC 00044 /* Jump Out Of Loop Conditional */
#define CMOP_JFC 00045 /* Jump Forward Conditional */
#define CMOP_JNS 00046 /* Jump out of loop unconditional */
#define CMOP_JFW 00047 /* Jump Forward Unconditional */
#define CMOP_RCA 00050 /* Recall Control Address */
#define CMOP_ENS 00051 /* End Loop */
#define CMOP_BNS 00052 /* Begin Loop */
#define CMOP_RSA 00053 /* Recall Source Address */
#define CMOP_SCA 00054 /* Store Control Address */
#define CMOP_JRC 00055 /* Jump Reverse Conditional */
#define CMOP_TSA 00056 /* Transfer Source Address */
#define CMOP_JRV 00057 /* Jump Reverse Unconditional */
#define CMOP_CEQ 00060 /* Compare Equal */
#define CMOP_CNE 00061 /* COmpare for Not Equal */
#define CMOP_CEG 00062 /* Compare For Greater Or Equal */
#define CMOP_CGR 00063 /* Compare For Greater */
#define CMOP_BIS 00064 /* Set Bit */
#define CMOP_BIR 00065 /* Reet Bit */
#define CMOP_OCV 00066 /* Output Convert */
#define CMOP_ICV 00067 /* Input Convert */
#define CMOP_CEL 00070 /* Compare For Equal or Less */
#define CMOP_CLS 00071 /* Compare for Less */
#define CMOP_FSU 00072 /* Field Subtract */
#define CMOP_FAD 00073 /* Field Add */
#define CMOP_TRP 00074 /* Transfer Program Characters */
#define CMOP_TRN 00075 /* Transfer Numeric */
#define CMOP_TRZ 00076 /* Transfer Zones */
#define CMOP_TRS 00077 /* Transfer Source Characters */
/* Error codes for Q */ /* P1 P2 */
#define MEM_PARITY 00001 /* 060 040 */
#define INVALID_ADDR 00002 /* 061 041 */
#define STK_OVERFL 00004 /* 062 042 */
#define COM_OPR 00040 /* 064 +00 044 */
#define PROG_REL 00050 /* 065 +01 045 */
#define CONT_BIT 00060 /* 066 +02 046 */
#define PRES_BIT 00070 /* 067 +03 047 */
#define FLAG_BIT 00100 /* 070 +04 050 */
#define INDEX_ERROR 00110 /* 071 +05 051 */
#define EXPO_UNDER 00120 /* 072 +06 052 */
#define EXPO_OVER 00130 /* 073 +07 053 */
#define INT_OVER 00140 /* 074 +10 054 */
#define DIV_ZERO 00150 /* 075 +11 055 */
/* Addresses for Interrupts */
#define INTER_TIME 022
#define IO_BUSY 023
#define KEY_REQ 024
#define PRT1_FINISH 025
#define PRT2_FINISH 026
#define IO1_FINISH 027
#define IO2_FINISH 030
#define IO3_FINISH 031
#define IO4_FINISH 032
#define INQ_REQ 033
#define SPEC_IRQ1 035
#define DSK1_RDCHK 036
#define DSK2_RDCHK 037
#define PARITY_ERR 060
#define INVADR_ERR 061
#define STK_OVR_LOC 062
#define COM_OPR_LOC 064
#define PROG_REL_LOC 065
#define CONT_BIT_LOC 066
#define PRES_BIT_LOC 067
#define FLAG_BIT_LOC 070
#define INDEX_BIT_LOC 071
#define EXP_UND_LOC 072
#define EXP_OVR_LOC 073
#define INT_OVR_LOC 074
#define DIV_ZER_LOC 075
#define PARITY_ERR2 040
#define INVADR_ERR2 041
#define STK_OVR_LOC2 042
#define COM_OPR_LOC2 044
#define PROG_REL_LOC2 045
#define CONT_BIT_LOC2 046
#define PRES_BIT_LOC2 047
#define FLAG_BIT_LOC2 050
#define INDEX_BIT_LOC2 051
#define EXP_UND_LOC2 052
#define EXP_OVR_LOC2 053
#define INT_OVR_LOC2 054
#define DIV_ZER_LOC2 055
/* IAR BITS */
#define IAR6 040 /* Set if IRQ from Q */
#define IAR5 020 /* Set if IRQ from P1 */
#define IAR4 010 /* Q bit 3 */
#define IAR3 004 /* Q bit 4 */
#define IAR2 002 /* Q bit 5 */
#define IAR1 001 /* Q bit 6 or Q bit 2 */
#define IAR0 000 /* Q bit 7 or Q bit 1 */
#define IRQ_0 000001 /* Interval Timer */
#define IRQ_1 000002 /* I/O Busy */
#define IRQ_2 000004 /* Keyboard Request */
#define IRQ_3 000010 /* Printer 1 Finished */
#define IRQ_4 000020 /* Printer 2 Finished */
#define IRQ_5 000040 /* I/O Finish 1 */
#define IRQ_6 000100 /* I/O Finish 2 */
#define IRQ_7 000200 /* I/O Finish 3 */
#define IRQ_10 000400 /* I/O Finish 4 */
#define IRQ_11 001000 /* P2 Busy */
#define IRQ_12 002000 /* Inquiry Request */
#define IRQ_13 004000 /* Special IRQ 1 */
#define IRQ_14 010000 /* Disk Read Check 1 */
#define IRQ_15 020000 /* Disk Read Check 2 */
/* Masks */
#define FLAG 04000000000000000LL /* Operand Flag */
#define FWORD 03777777777777777LL /* Full word mask */
#define MSIGN 02000000000000000LL /* Operator Word */
#define ESIGN 01000000000000000LL
#define EXPO 00770000000000000LL
#define EXPO_V 39
#define MANT 00007777777777777LL
#define NORM 00007000000000000LL
#define ROUND 00004000000000000LL
#define PRESENT 01000000000000000LL /* Oprand Type */
#define DFLAG 02000000000000000LL /* Descriptor */
#define WCOUNT 00017770000000000LL
#define WCOUNT_V 30
#define INTEGR 00000002000000000LL
#define CONTIN 00000001000000000LL
#define CORE 00000000000077777LL
#define RFIELD 00077700000000000LL /* Mark Stack Control Word */
#define RFIELD_V 27 /* Shift off by 6 bits */
#define SMSFF 00000020000000000LL
#define SSALF 00000010000000000LL
#define SVARF 00000000100000000LL
#define SCWMF 00000000000100000LL
#define FFIELD 00000007777700000LL
#define FFIELD_V 15
#define REPFLD 00000770000000000LL
#define REPFLD_V 30
#define MODEF 00200000000000000LL /* Program Descriptor +FFIELD and CORE */
#define ARGF 00100000000000000LL
#define PROGF 00400000000000000LL
#define RGH 00340700000000000LL /* Return Control Word +FFIELD and CORE */
#define RGH_V 33
#define RKV 00034070000000000LL
#define RKV_V 30
#define RL 00003000000000000LL /* Save L register */
#define RL_V 36
#define LMASK 00000000007777777LL
#define HMASK 00007777770000000LL
#define DEV_DRUM_RD 01000000000000000LL
#define DEVMASK 00760000000000000LL
#define D_MASK 00777777777777777LL
#define DEV_V 40
#define DEV_WC 00017770000000000LL
#define DEV_WC_V 30
#define DEV_CMD 00000007777700000LL
#define DEV_CMD_V 15
#define DEV_INHTRF 00000004000000000LL
#define DEV_XXX 00000002000000000LL
#define DEV_XXY 00000001000000000LL
#define DEV_BIN 00000000400000000LL
#define DEV_BACK 00000000200000000LL
#define DEV_WCFLG 00000000100000000LL
#define DEV_IORD 00000000040000000LL
#define DEV_OPT 00000000007700000LL /* Print Space, Disk Segments */
#define CORE 00000000000077777LL
#define DEV_BUSY 00000000000100000LL /* D16 */
#define DEV_MEMPAR 00000000000200000LL /* D17 */
#define DEV_NOTRDY 00000000000400000LL /* D18 */
#define DEV_PARITY 00000000001000000LL /* D19 */
#define DEV_ERROR 00000000002000000LL /* D20 */
#define DEV_EOF 00000000004000000LL /* D21 */
#define DEV_MEMERR 00000000010000000LL /* D22 */
#define DEV_RESULT 00000000037700000LL
#define DEV_EOT 01000100001000000LL
#define DEV_BOT 01000200001000000LL
#define DEV_BLANK 01000400001000000LL
#define DRUM1_DEV 004 /* 00100 (4) */
#define DSK1_DEV 006 /* 00110 (6) */
#define DRUM2_DEV 010 /* 01000 (8) */
#define CARD1_DEV 012 /* 01010 (10) */
#define DSK2_DEV 014 /* 01100 (12) */
#define CARD2_DEV 016 /* 01110 (14) */
#define DTC_DEV 020 /* 10000 (16) */
#define PT1_DEV 022 /* 10010 (20) */
#define PT2_DEV 024 /* 10100 (22) */
#define PRT1_DEV 026 /* 10110 (24) */
#define PRT2_DEV 032 /* 11010 (26) */
#define SPO_DEV 036 /* 11110 (30) */
#define DRUM1_FLAG 00000000000200000LL
#define DRUM2_FLAG 00000000000400000LL
#define DSK1_FLAG 00000000001000000LL
#define DSK2_FLAG 00000000002000000LL
#define PRT1_FLAG 00000000004000000LL
#define PRT2_FLAG 00000000010000000LL
#define PUNCH_FLAG 00000000020000000LL
#define CARD1_FLAG 00000000040000000LL
#define CARD2_FLAG 00000000100000000LL
#define SPO_FLAG 00000000200000000LL
#define PTP1_FLAG 00000000400000000LL
#define PTR1_FLAG 00000001000000000LL
#define PTR2_FLAG 00000002000000000LL
#define PTP2_FLAG 00000004000000000LL
#define DTC_FLAG 00000010000000000LL
#endif /* _B5500_H_ */

578
B5500/b5500_dk.c Normal file
View file

@ -0,0 +1,578 @@
/* b5500_dk.c: Burrioughs 5500 Disk controller
Copyright (c) 2016, Richard Cornwell
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
RICHARD CORNWELL 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.
*/
#include "b5500_defs.h"
#if (NUM_DEVS_DSK > 0)
/* in u3 is device address */
/* in u4 is current buffer position */
/* in u5 Bits 30-16 of W */
#define URCSTA_SKIP 000017 /* Skip mask */
#define URCSTA_SINGLE 000020 /* Single space skip. */
#define URCSTA_DOUBLE 000040 /* Double space skip */
#define URCSTA_READ 000400 /* Read flag */
#define URCSTA_WC 001000 /* Use word count */
#define URCSTA_DIRECT 002000 /* Direction, Long line */
#define URCSTA_BINARY 004000 /* Binary transfer */
#define URCSTA_INHIBIT 040000 /* Inhibit transfer to memory */
#define DK_CHAN 0000003 /* Channel number */
#define DK_CTRL 0000004 /* Disk controller unit attached too */
#define DK_WC 0000010 /* Use word count */
#define DK_BSY 0000020 /* Drive is busy. */
#define DK_RD 0000040 /* Executing a read command */
#define DK_WR 0000100 /* Executing a write command */
#define DK_RDCK 0000200 /* Executing a read check command */
#define DK_ADDR 0000400 /* Drive has an address. */
#define DK_BIN 0001000 /* Binary mode */
#define DK_WCZERO 0002000 /* Word count Zero */
#define DK_SECMASK 0770000 /* Number of segments to transfer */
#define DK_SECT 0010000 /* One segment */
#define DK_SEC_SIZE 240 /* Sector size */
#define DK_MAXSEGS 200000 /* Max segments for MOD I ESU */
#define DK_MAXSEGS2 400000 /* Max segments for MOD IB ESU */
#define DFX_V (UNIT_V_UF + 1)
#define MODIB_V (UNIT_V_UF + 2)
#define DFX (1 << DFX_V)
#define MODIB (1 << MODIB_V)
t_stat dsk_cmd(uint16, uint16, uint8, uint16 *);
t_stat dsk_srv(UNIT *);
t_stat dsk_boot(int32, DEVICE *);
t_stat dsk_help (FILE *, DEVICE *, UNIT *, int32, const char *);
const char *dsk_description (DEVICE *);
t_stat esu_srv(UNIT *);
t_stat esu_attach(UNIT *, char *);
t_stat esu_detach(UNIT *);
t_stat esu_help (FILE *, DEVICE *, UNIT *, int32, const char *);
const char *esu_description (DEVICE *);
uint8 dsk_buffer[NUM_DEVS_DSK][DK_SEC_SIZE];
t_stat set_mod(UNIT *uptr, int32 val, char *cptr,
void *desc);
#define ESU_TYPE UDATA(&esu_srv, UNIT_ATTABLE+UNIT_DISABLE+ \
UNIT_FIX, DK_SEC_SIZE * DK_MAXSEGS)
UNIT esu_unit[] = {
{ESU_TYPE, DK_MAXSEGS}, /* 0 */
{ESU_TYPE, DK_MAXSEGS}, /* 1 */
{ESU_TYPE, DK_MAXSEGS}, /* 2 */
{ESU_TYPE, DK_MAXSEGS}, /* 3 */
{ESU_TYPE, DK_MAXSEGS}, /* 4 */
{ESU_TYPE, DK_MAXSEGS}, /* 5 */
{ESU_TYPE, DK_MAXSEGS}, /* 6 */
{ESU_TYPE, DK_MAXSEGS}, /* 7 */
{ESU_TYPE, DK_MAXSEGS}, /* 8 */
{ESU_TYPE, DK_MAXSEGS}, /* 9 */
{ESU_TYPE, DK_MAXSEGS}, /* 10 */
{ESU_TYPE, DK_MAXSEGS}, /* 11 */
{ESU_TYPE, DK_MAXSEGS}, /* 12 */
{ESU_TYPE, DK_MAXSEGS}, /* 13 */
{ESU_TYPE, DK_MAXSEGS}, /* 14 */
{ESU_TYPE, DK_MAXSEGS}, /* 15 */
{ESU_TYPE, DK_MAXSEGS}, /* 16 */
{ESU_TYPE, DK_MAXSEGS}, /* 17 */
{ESU_TYPE, DK_MAXSEGS}, /* 18 */
{ESU_TYPE, DK_MAXSEGS}, /* 19 */
};
MTAB esu_mod[] = {
{MODIB, 0, "MODI", "MODI", &set_mod, NULL, NULL,
"Sets ESU to Fast Mod I drive"},
{MODIB, MODIB, "MODIB", "MODIB", &set_mod, NULL, NULL,
"Sets ESU to Slow Mod IB drive"},
{0}
};
DEVICE esu_dev = {
"ESU", esu_unit, NULL, esu_mod,
20, 8, 15, 1, 8, 8,
NULL, NULL, NULL, NULL, &esu_attach, &esu_detach,
NULL, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
NULL, NULL, &esu_help, NULL, NULL, &esu_description
};
MTAB dsk_mod[] = {
{DFX, 0, NULL, "NODFX", NULL, NULL, NULL,
"Disables drive sharing, use only on DK1"},
{DFX, DFX, "DFX", "DFX", NULL, NULL, NULL,
"Enables drive sharing, use only on DK1"},
{0}
};
UNIT dsk_unit[] = {
{UDATA(&dsk_srv, UNIT_DISABLE, 0)}, /* DKA */
{UDATA(&dsk_srv, UNIT_DIS | UNIT_DISABLE, 0)}, /* DKB */
};
DEVICE dsk_dev = {
"DK", dsk_unit, NULL, dsk_mod,
NUM_DEVS_DSK, 8, 15, 1, 8, 8,
NULL, NULL, NULL, &dsk_boot, NULL, NULL,
NULL, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
NULL, NULL, &dsk_help, NULL, NULL, &dsk_description
};
/* Start off a disk command */
t_stat dsk_cmd(uint16 cmd, uint16 dev, uint8 chan, uint16 *wc)
{
UNIT *uptr;
int u = (dev==DSK1_DEV)? 0: 1;
uptr = &dsk_unit[u];
/* If unit disabled return error */
if (uptr->flags & UNIT_DIS)
return SCPE_NODEV;
/* Check if drive is ready to recieve a command */
if ((uptr->u5 & DK_BSY))
return SCPE_BUSY;
uptr->u5 = chan|DK_BSY;
if (dev == DSK2_DEV)
uptr->u5 |= DK_CTRL;
uptr->u5 |= (cmd & 077) << 12;
if (cmd & URCSTA_INHIBIT)
uptr->u5 |= DK_RDCK;
else if (cmd & URCSTA_READ)
uptr->u5 |= DK_RD;
else
uptr->u5 |= DK_WR;
if (cmd & URCSTA_WC) {
uptr->u5 |= DK_WC;
if (*wc == 0)
uptr->u5 |= DK_WCZERO;
}
if (cmd & URCSTA_BINARY)
uptr->u5 |= DK_BIN;
if (loading) {
uptr->u4 = 1;
uptr->u3 = 0;
} else {
uptr->u5 |= DK_ADDR;
}
sim_activate(uptr, 100);
return SCPE_OK;
}
/* Handle processing disk controller commands */
t_stat dsk_srv(UNIT * uptr)
{
int chan = uptr->u5 & DK_CHAN;
DEVICE *dptr = find_dev_from_unit(uptr);
int i;
int addr;
uint8 abuf[8]; /* x-esu-disk-track-segment */
int u = uptr - dsk_unit;
int esu;
UNIT *eptr;
if ((uptr->u5 & DK_BSY) == 0)
return SCPE_OK;
/* Read in first word, which a address. */
/* Note special read routine since address is not included
in the word count */
if (uptr->u5 & DK_ADDR) {
/* Read in 8 characters which are the address */
for (i = 0; i < 8; i++) {
if (chan_read_disk(chan, &abuf[i], 0))
break;
abuf[i] &= 017; /* Mask zone out */
if (abuf[i] == 012) /* Zero to zero */
abuf[i] = 0;
}
/* extract ESU and Address */
esu = abuf[1];
addr = 0;
for (i = 2; i < 8; i++) {
addr = (addr * 10) + abuf[i];
}
uptr->u5 &= ~DK_ADDR;
uptr->u4 = addr;
/* Map to ESU */
if (u && (dsk_unit[u].flags & DFX) == 0)
esu += 10;
sim_debug(DEBUG_DETAIL, dptr, "Disk access %d %s %02o %d,%d\n\r", u,
(uptr->u5 & DK_RDCK) ? "rcheck" :
(uptr->u5 & DK_RD) ? "read" :
(uptr->u5 & DK_WR)? "write" : "nop", (uptr->u5 >> 9) & 077,
esu, addr);
uptr->u3 = esu;
eptr = &esu_unit[uptr->u3];
/* Check if valid */
if ((eptr->flags & UNIT_DIS) || (eptr->flags & UNIT_ATT) == 0) {
/* Set not ready and end channel */
chan_set_notrdy(chan);
uptr->u5 = 0;
return SCPE_OK;
}
/* Check if Read Check or Write Check */
if ((uptr->u5 & (DK_WCZERO|DK_WC|DK_SECMASK)) == (DK_WCZERO|DK_WC)) {
if (uptr->u4 >= eptr->wait)
chan_set_eof(chan);
if (uptr->u5 & DK_WR) {
sim_debug(DEBUG_DETAIL, dptr, "Disk write int %d %d %o\n\r",
uptr->u3, uptr->u4, uptr->u5);
}
if (uptr->u5 & DK_RD) {
sim_debug(DEBUG_DETAIL, dptr, "Disk read int %d %d %o\n\r",
uptr->u3, uptr->u4, uptr->u5);
if (eptr->flags & MODIB)
chan_set_error(chan);
}
chan_set_end(chan);
uptr->u5 = 0;
return SCPE_OK;
}
sim_activate(uptr, 5000);
return SCPE_OK;
}
/* Kick off actual transfer to ESU */
if (((uptr->u5 & DK_ADDR) == 0) &&
((uptr->u5 & (DK_RDCK|DK_RD|DK_WR)) != 0)) {
eptr = &esu_unit[uptr->u3];
/* Wait until unit is ready for new access */
if ((eptr->u5 & DK_BSY) == 0) {
eptr->u3 = (uptr->u5 & DK_WR) ? 0 : DK_SEC_SIZE;
eptr->u4 = uptr->u4; /* Disk address */
eptr->u5 = uptr->u5; /* Command */
if (uptr->u5 & DK_RDCK) {
uptr->u5 = 0;
chan_set_end(chan);
} else
uptr->u5 &= ~(DK_RDCK|DK_RD|DK_WR);
sim_activate(eptr, 500);
return SCPE_OK;
}
sim_activate(uptr, 100);
}
return SCPE_OK;
}
void esu_set_end(UNIT *uptr, int err) {
int chan = uptr->u5 & DK_CHAN;
int dsk = ((uptr->u5 & DK_CTRL) != 0);
DEVICE *dptr = find_dev_from_unit(uptr);
sim_debug(DEBUG_DETAIL, dptr, "Disk done %d %d %o\n\r", uptr->u3,
uptr->u4, uptr->u5);
if (err)
chan_set_error(chan);
uptr->u5 = 0;
dsk_unit[dsk].u5 = 0;
chan_set_end(chan);
}
/* Handle processing esu controller commands */
t_stat esu_srv(UNIT * uptr)
{
int chan = uptr->u5 & DK_CHAN;
DEVICE *dptr = find_dev_from_unit(uptr);
int u = uptr - esu_unit;
int dsk = ((uptr->u5 & DK_CTRL) != 0);
int wc;
/* Process for each unit */
if (uptr->u5 & DK_RD) {
/* Check if at start of segment */
if (uptr->u3 >= DK_SEC_SIZE) {
int da = (uptr->u4 * DK_SEC_SIZE);
/* Check if end of operation */
if ((uptr->u5 & (DK_SECMASK)) == 0) {
esu_set_end(uptr, 0);
return SCPE_OK;
}
/* Check if over end of disk */
if (uptr->u4 >= uptr->wait) {
sim_debug(DEBUG_DETAIL, dptr, "Disk read over %d %d %o\n\r",
uptr->u3, uptr->u4, uptr->u5);
chan_set_eof(chan);
esu_set_end(uptr, 0);
return SCPE_OK;
}
sim_debug(DEBUG_DETAIL, dptr, "Disk read %d %d %d %o %d\n\r",
u,uptr->u3, uptr->u4, uptr->u5, da);
if (sim_fseek(uptr->fileref, da, SEEK_SET) < 0) {
esu_set_end(uptr, 1);
return SCPE_OK;
}
wc = sim_fread(&dsk_buffer[dsk][0], 1, DK_SEC_SIZE,
uptr->fileref);
for (; wc < DK_SEC_SIZE; wc++)
dsk_buffer[dsk][wc] = (uptr->u5 & DK_BIN) ? 0 :020;
uptr->u3 = 0;
uptr->u4++; /* Advance disk address */
uptr->u5 -= DK_SECT;
}
/* Transfer one Character */
if (chan_write_char(chan, &dsk_buffer[dsk][uptr->u3], 0)) {
esu_set_end(uptr, 0);
return SCPE_OK;
}
uptr->u3++;
}
if (uptr->u5 & DK_RDCK) {
if (uptr->u3 >= DK_SEC_SIZE) {
/* Check if over end of disk */
if (uptr->u4 >= uptr->wait) {
sim_debug(DEBUG_DETAIL, dptr, "Disk rdchk over %d %d %o\n\r",
uptr->u3, uptr->u4, uptr->u5);
uptr->u5 = 0;
IAR |= IRQ_14 << dsk;
return SCPE_OK;
}
sim_debug(DEBUG_DETAIL, dptr, "Disk rdchk %d %d %d %o\n\r", u,
uptr->u3, uptr->u4, uptr->u5);
uptr->u4++; /* Advance disk address */
uptr->u5 -= DK_SECT;
uptr->u3 = 0;
/* Check if end of operation */
if ((uptr->u5 & (DK_SECMASK)) == 0) {
uptr->u5 = 0;
IAR |= IRQ_14 << dsk;
return SCPE_OK;
}
}
/* Check if at end of segment */
uptr->u3++;
}
/* Process for each unit */
if (uptr->u5 & DK_WR) {
/* Check if end of operation */
if ((uptr->u5 & (DK_SECMASK)) == 0) {
esu_set_end(uptr, 0);
return SCPE_OK;
}
/* Transfer one Character */
if (chan_read_char(chan, &dsk_buffer[dsk][uptr->u3], 0)) {
if (uptr->u3 != 0) {
while (uptr->u3 < DK_SEC_SIZE)
dsk_buffer[dsk][uptr->u3++] = (uptr->u5 & DK_BIN) ? 0 :020;
}
}
uptr->u3++;
/* Check if at end of segment */
if (uptr->u3 >= DK_SEC_SIZE) {
int da = (uptr->u4 * DK_SEC_SIZE);
/* Check if over end of disk */
if (uptr->u4 >= uptr->wait) {
sim_debug(DEBUG_DETAIL, dptr, "Disk write over %d %d %o\n\r",
uptr->u3, uptr->u4, uptr->u5);
chan_set_eof(chan);
esu_set_end(uptr, 0);
return SCPE_OK;
}
sim_debug(DEBUG_DETAIL, dptr, "Disk write %d %d %d %o %d\n\r",
u, uptr->u3, uptr->u4, uptr->u5, da);
if (sim_fseek(uptr->fileref, da, SEEK_SET) < 0) {
esu_set_end(uptr, 1);
return SCPE_OK;
}
wc = sim_fwrite(&dsk_buffer[dsk][0], 1, DK_SEC_SIZE,
uptr->fileref);
if (wc != DK_SEC_SIZE) {
esu_set_end(uptr, 1);
return SCPE_OK;
}
uptr->u3 = 0;
uptr->u4++; /* Advance disk address */
uptr->u5 -= DK_SECT;
}
}
sim_activate(uptr, (uptr->flags & MODIB) ? 200 :100);
return SCPE_OK;
}
t_stat
set_mod(UNIT *uptr, int32 val, char *cptr, void *desc) {
if (uptr == NULL) return SCPE_IERR;
if (val == MODIB)
uptr->wait = DK_MAXSEGS2;
else
uptr->wait = DK_MAXSEGS;
uptr->capac = DK_SEC_SIZE * uptr->wait;
return SCPE_OK;
}
/* Boot from given device */
t_stat
dsk_boot(int32 unit_num, DEVICE * dptr)
{
int dev = (unit_num)? DSK2_DEV:DSK1_DEV;
t_uint64 desc;
int i;
for(i = 0; i < 20; i++)
esu_unit[i].u5 = 0;
desc = (((t_uint64)dev)<<DEV_V)|DEV_IORD|DEV_OPT|020LL;
return chan_boot(desc);
}
t_stat
esu_attach(UNIT * uptr, char *file)
{
t_stat r;
int u = uptr-esu_unit;
if ((r = attach_unit(uptr, file)) != SCPE_OK)
return r;
if (u < 10) {
iostatus |= DSK1_FLAG;
}
if (u >= 10 || (dsk_unit[1].flags & DFX) != 0) {
iostatus |= DSK2_FLAG;
}
return SCPE_OK;
}
t_stat
esu_detach(UNIT * uptr)
{
t_stat r;
int u = uptr-esu_unit;
int i, mask, lim;
if ((r = detach_unit(uptr)) != SCPE_OK)
return r;
/* Determine which controller */
if (u < 10) {
mask = DSK1_FLAG;
/* If DFX, then both controllers */
if ((dsk_unit[1].flags & DFX) != 0)
mask |= DSK2_FLAG;
lim = 10;
i = 0;
} else {
/* If DFX, then drive not attached */
if ((dsk_unit[1].flags & DFX) != 0)
return r;
mask = DSK2_FLAG;
lim = 20;
i = 10;
}
/* Scan to see if any disks still attached */
while (i < lim) {
if (esu_unit[i].flags & UNIT_ATT)
return r; /* Something still there */
i++;
}
/* There are no longer any drives attached to
this controller */
iostatus &= ~mask;
return r;
}
t_stat
dsk_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "B5470 Disk Controller\n\n");
fprintf (st, "By default the second disk controller is not enabled.\n\n");
fprintf (st, " sim> SET DK1 ENABLE to enable second disk controller for use\n");
fprintf (st, "The B5500 could have up to two disk controllers that could talk\n");
fprintf (st, "to up to 10 ESU. Each ESU held up to 5 storage units. By uses of\n");
fprintf (st, "a exchange unit (DFX), the second controller could talk to the\n");
fprintf (st, "same drives as the first controller. To use the second disk controller\n");
fprintf (st, "to share the same drives as the first (after enabling DK1):\n\n");
fprintf (st, " sim> SET DK1 DFX enable disk exchange\n\n");
fprintf (st, "If you want to support more then 10 ESU units you will first\n");
fprintf (st, "need to generate a new version of MCP without the DFX option\n");
fprintf (st, "for MCP XV you also need to SET DKBNODFX TRUE when building the\n");
fprintf (st, "system file.\n");
fprintf (st, "ESU units 0-9 attach to DK0, or DK1 if DFX\n");
fprintf (st, "ESU units 10-19 attach to DK1 only\n\n");
fprintf (st, "The DK unit supports the BOOT command.\n\n");
fprint_set_help (st, dptr) ;
fprint_show_help (st, dptr) ;
return SCPE_OK;
}
const char *
dsk_description (DEVICE *dptr)
{
return "B5470 disk controller module";
}
t_stat
esu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "B471 ESU with 5 B457 storage units\n\n");
fprintf (st, "Each ESU unit represents the electronics unit and 5 storage units\n");
fprintf (st, "MOD I units could handle about 48 million characters.\n");
fprintf (st, "MOD IB units could handle about 96 million characters.\n");
fprintf (st, "MOD IB units operated at half the speed of MOD I units.\n");
fprintf (st, "ESU units can be added to a system after it has been booted,\n");
fprintf (st, "however they can't be removed. The configuration of disks must\n");
fprintf (st, "be the same each time the same system is booted.\n");
fprintf (st, "To use larger slower drives do:\n");
fprintf (st, " sim> SET ESUn MODIB before the unit is attached\n");
fprintf (st, "To use smaller faster drives do (default):\n");
fprintf (st, " sim> SET ESUn MODI before the unit is attached\n\n");
fprint_set_help (st, dptr) ;
fprint_show_help (st, dptr) ;
return SCPE_OK;
}
const char *
esu_description (DEVICE *dptr)
{
return "B471 electrontics unit and 5 B457 storage units.";
}
#endif

258
B5500/b5500_dr.c Normal file
View file

@ -0,0 +1,258 @@
/* b5500_dr.c: Burrioughs 5500 Drum controller
Copyright (c) 2015, Richard Cornwell
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
RICHARD CORNWELL 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.
*/
#include "b5500_defs.h"
#if (NUM_DEVS_DR > 0)
#define UNIT_DR UNIT_ATTABLE | UNIT_DISABLE | UNIT_FIX | \
UNIT_BUFABLE | UNIT_MUSTBUF
/* in u3 is device address */
/* in u4 is current address */
/* in u5 Bits 30-16 of W */
#define DR_CHAN 000003 /* Channel number */
#define DR_RD 000004 /* Executing a read command */
#define DR_WR 000010 /* Executing a write command */
#define DR_RDY 000040 /* Device Ready */
#define AUXMEM (1 << UNIT_V_UF)
t_stat drm_srv(UNIT *);
t_stat drm_boot(int32, DEVICE *);
t_stat drm_attach(UNIT *, char *);
t_stat drm_detach(UNIT *);
t_stat set_drum(UNIT * uptr, int32 val, char *cptr,
void *desc);
t_stat set_auxmem(UNIT * uptr, int32 val, char *cptr,
void *desc);
t_stat drm_help (FILE *, DEVICE *, UNIT *, int32, const char *);
const char *drm_description (DEVICE *);
MTAB drm_mod[] = {
{AUXMEM, 0, "DRUM", "DRUM", &set_drum, NULL, "Device is drum"},
{AUXMEM, AUXMEM, "AUXMEM", "AUXMEM", &set_auxmem, NULL, "Device is memory unit"},
{0}
};
UNIT drm_unit[] = {
{UDATA(&drm_srv, UNIT_DR, 32*1024)}, /* DRA */
{UDATA(&drm_srv, UNIT_DR, 32*1024)}, /* DRB */
};
DEVICE drm_dev = {
"DR", drm_unit, NULL, drm_mod,
NUM_DEVS_DR, 8, 15, 1, 8, 64,
NULL, NULL, NULL, &drm_boot, &drm_attach, &drm_detach,
NULL, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
NULL, NULL, &drm_help, NULL, NULL,
&drm_description
};
/* Start off a disk command */
t_stat drm_cmd(uint16 cmd, uint16 dev, uint8 chan, uint16 *wc, uint8 rd_flg)
{
UNIT *uptr;
int u = (dev==DRUM1_DEV)? 0: 1;
uptr = &drm_unit[u];
/* If unit disabled return error */
if (uptr->flags & UNIT_DIS) {
return SCPE_NODEV;
}
if ((uptr->flags & (UNIT_BUF)) == 0) {
sim_debug(DEBUG_CMD, &drm_dev, "Drum not buffered\n\r");
return SCPE_UNATT;
}
/* Check if drive is ready to recieve a command */
if ((uptr->u5 & DR_RDY) == 0)
return SCPE_BUSY;
uptr->u5 = chan;
if (rd_flg)
uptr->u5 |= DR_RD;
else
uptr->u5 |= DR_WR;
uptr->u4 = cmd << 3;
sim_debug(DEBUG_CMD, &drm_dev, "Drum access %s %06o\n\r",
(uptr->u5 & DR_RD) ? "read" : "write", uptr->u4);
sim_activate(uptr, 100);
return SCPE_OK;
}
/* Handle processing disk controller commands */
t_stat drm_srv(UNIT * uptr)
{
int chan = uptr->u5 & DR_CHAN;
uint8 *ch = &(((uint8 *)uptr->filebuf)[uptr->u4]);
/* Process for each unit */
if (uptr->u5 & DR_RD) {
/* Transfer one Character */
if (chan_write_drum(chan, ch, 0)) {
uptr->u5 = DR_RDY;
chan_set_end(chan);
return SCPE_OK;
}
uptr->u4++;
if (uptr->u4 > ((int32)uptr->capac << 3)) {
sim_debug(DEBUG_CMD, &drm_dev, "Drum overrun\n\r");
uptr->u5 = DR_RDY;
chan_set_error(chan);
chan_set_end(chan);
return SCPE_OK;
}
sim_activate(uptr, 40);
}
/* Process for each unit */
if (uptr->u5 & DR_WR) {
/* Transfer one Character */
if (chan_read_drum(chan, ch, 0)) {
uptr->u5 = DR_RDY;
chan_set_end(chan);
return SCPE_OK;
}
uptr->u4++;
if (uptr->u4 > ((int32)uptr->capac << 3)) {
sim_debug(DEBUG_CMD, &drm_dev, "Drum overrun\n\r");
uptr->u5 = DR_RDY;
chan_set_error(chan);
chan_set_end(chan);
return SCPE_OK;
}
sim_activate(uptr, 40);
}
return SCPE_OK;
}
/* Boot from given device */
t_stat
drm_boot(int32 unit_num, DEVICE * dptr)
{
int dev = (unit_num)? DRUM2_DEV:DRUM1_DEV;
t_uint64 desc;
desc = (((t_uint64)dev)<<DEV_V)|DEV_IORD|DEV_OPT|020LL;
return chan_boot(desc);
}
t_stat
drm_attach(UNIT * uptr, char *file)
{
t_stat r;
int u = uptr - drm_unit;
if ((r = attach_unit(uptr, file)) != SCPE_OK)
return r;
uptr->u5 |= DR_RDY;
uptr->hwmark = uptr->capac;
if (u)
iostatus |= DRUM2_FLAG;
else
iostatus |= DRUM1_FLAG;
return SCPE_OK;
}
t_stat
drm_detach(UNIT * uptr)
{
t_stat r;
int u = uptr - drm_unit;
if ((r = detach_unit(uptr)) != SCPE_OK)
return r;
uptr->u5 = 0;
if (u)
iostatus &= ~DRUM2_FLAG;
else
iostatus &= ~DRUM1_FLAG;
return SCPE_OK;
}
t_stat
set_drum(UNIT * uptr, int32 val, char *cptr, void *desc) {
if ((uptr->flags & AUXMEM) == 0)
return SCPE_OK;
if (uptr->flags & UNIT_ATT)
drm_detach(uptr);
uptr->flags |= UNIT_ATTABLE;
return SCPE_OK;
}
t_stat
set_auxmem(UNIT * uptr, int32 val, char *cptr, void *desc) {
int u = uptr - drm_unit;
if (uptr->flags & AUXMEM)
return SCPE_OK;
if (uptr->flags & UNIT_ATT)
detach_unit(uptr);
uptr->flags &= ~UNIT_ATTABLE;
if (uptr->filebuf == 0) {
uptr->filebuf = calloc(uptr->capac, 8);
uptr->flags |= UNIT_BUF;
}
uptr->u5 = DR_RDY;
if (u)
iostatus |= DRUM2_FLAG;
else
iostatus |= DRUM1_FLAG;
return SCPE_OK;
}
t_stat
drm_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "B430 Magnetic Drum or B6500 memory module\n\n");
fprintf (st, "There are up to two drum units DR0 and DR1. These can either\n");
fprintf (st, "be attached to a file or set to AUXMEM. Setting to AUXMEM causes\n");
fprintf (st, "them to exist only during the given sim run. Setting back to DRUM\n");
fprintf (st, "will clear whatever was stored on the drum. If the device is set\n");
fprintf (st, "to DRUM it must be attached to a file which it will buffer until\n");
fprintf (st, "the unit is detached, or the sim exits. MCP must be configured to\n");
fprintf (st, "the drum\n\n");
fprint_set_help (st, dptr) ;
fprint_show_help (st, dptr) ;
return SCPE_OK;
}
const char *
drm_description (DEVICE *dptr)
{
return "B430 Magnetic Drum or B6500 memory module";
}
#endif

895
B5500/b5500_dtc.c Normal file
View file

@ -0,0 +1,895 @@
/* b5500_dtc.c: Burrioughs 5500 Data Communications
Copyright (c) 2016, Richard Cornwell
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
RICHARD CORNWELL 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.
*/
#include "b5500_defs.h"
#include "sim_timer.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#if (NUM_DEVS_DTC > 0)
#define UNIT_DTC UNIT_ATTABLE | UNIT_DISABLE | UNIT_IDLE
#define DTC_MLINES 32 /* mux lines */
#define DTC_TLINES 8
#define DTC_BUFSIZ 112 /* max chan transfer */
#define DTCSTA_READ 000400 /* Read flag */
#define DTCSTA_BINARY 004000 /* Bypass translation */
#define DTCSTA_INHIBIT 040000 /* Interrogate or Read/Write */
/* Flags in WC Field */
#define DTCSTA_TTU 0740 /* TTU number */
#define DTCSTA_GM 0020 /* Ignore GM on transfer */
#define DTCSTA_BUF 0017 /* Buffer Number */
/* Interrogate
D28 - Busy DEV_ERROR
D27 - Write Ready DEV_EOF
D24 - Read Ready DEV_IORD */
/* Abnormal flag = DEV_WCFLG */
/* Buffer full/GM flag = D25 */
/* Buffer wrong state = DEV_EOF D27 */
/* Buffer Busy = DEV_ERROR D28 */
/* DTC not ready or buffer, DEV_NOTRDY D30 */
/* in u3 is device address */
/* in u4 is current address */
/* in u5 Line number */
#define DTC_CHAN 000003 /* Channel number */
#define DTC_RD 000004 /* Executing a read command */
#define DTC_WR 000010 /* Executing a write command */
#define DTC_INQ 000020 /* Executing an interragte command */
#define DTC_RDY 000040 /* Device Ready */
#define DTC_BIN 000100 /* Transfer in Binary mode */
#define DTC_IGNGM 000200 /* Ignore GM on transfer */
#define BufNotReady 0 /* Device not connected */
#define BufIdle 1 /* Buffer in Idle state */
#define BufInputBusy 2 /* Buffer being filled */
#define BufReadRdy 3 /* Buffer ready to read */
#define BufWrite 4 /* Buffer writing */
#define BufWriteRdy 5 /* Buffer ready for write */
#define BufOutBusy 6 /* Buffer outputing */
#define BufRead 7 /* Buffer reading */
#define BufSMASK 7 /* Buffer state mask */
#define BufAbnormal 010 /* Abnornmal flag */
#define BufGM 020 /* Buffer term with GM */
#define BufIRQ 040 /* Buffer ready */
/* Not connected line:
BufNotReady.
Write:
BufNotReady -> 0x34 (EOF,ERROR,NR)
BufIdle -> BufWrite (set GM if set.)
BufReadReady -> 0x20 (EOF).
BufInputBusy, BufWrite -> 0x30
-> 0x34 (EOF,ERROR)
BufWriteRdy -> BufWrite.
Write Done:
BufOutBusy.
Read:
BufNotReady -> 0x34 (EOF,ERROR,NR)
BufIdle -> 0x34 (EOF,ERROR,NR)
BufInputBusy, BufOutBusy -> 0x30 (EOF,ERROR)
BufReadRdy -> return buffer. -> BufIdle
Interogate:
return BufWriteRdy/BufWriteFull
return BufReadRdy.
Recieve Char:
Connect:
State BufWriteRdy.
Output Done:
BufGM -> BufIdle
-> BufWriteRdy
*/
/* Translate chars
output:
! -> LF.
< -> RO.
> -> X-OFF
} -> Disconnect line
~ -> End of message.
input:
~/_/CR -> End of message.
BufReadRdy, IRQ.
</BS -> Back up one char.
!/ -> Disconnect insert }
BufReadRdy, IRQ.
^B -> Clear input.
BufIdle
^E -> set abnormal, buffer to BufWriteRdy.
^L -> Clear input.
BufIdle
? -> Set abnormal
Char: Buf to BufInputBsy. Insert char.
if Fullbuff, BufReadRdy, IRQ,
*/
t_stat dtc_srv(UNIT *);
t_stat dtco_srv(UNIT *);
t_stat dtc_attach(UNIT *, char *);
t_stat dtc_detach(UNIT *);
t_stat dtc_reset(DEVICE *);
t_stat dtc_setnl (UNIT *, int32, char *, void *);
t_stat dtc_set_log (UNIT *, int32, char *, void *);
t_stat dtc_set_nolog (UNIT *, int32, char *, void *);
t_stat dtc_show_log (FILE *, UNIT *, int32, void *);
t_stat dtc_help(FILE *, DEVICE *, UNIT *, int32, const char *);
t_stat dtc_help_attach (FILE *, DEVICE *, UNIT *, int32, const char *);
const char *dtc_description(DEVICE *);
int32 tmxr_poll;
uint8 dtc_buf[DTC_MLINES][DTC_BUFSIZ];
TMLN dtc_ldsc[DTC_MLINES]; /* line descriptors */
TMXR dtc_desc = { DTC_TLINES, 0, 0, dtc_ldsc }; /* mux descriptor */
uint8 dtc_lstatus[DTC_MLINES]; /* Line status */
uint16 dtc_bufptr[DTC_MLINES]; /* Buffer pointer */
uint16 dtc_bsize[DTC_MLINES]; /* Buffer size */
uint16 dtc_blimit[DTC_MLINES]; /* Buffer size */
MTAB dtc_mod[] = {
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &dtc_desc, "Disconnect a specific line" },
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
NULL, &tmxr_show_summ, (void *) &dtc_desc, "Display a summary of line states" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &tmxr_show_cstat, (void *) &dtc_desc, "Display current connections" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &tmxr_show_cstat, (void *) &dtc_desc, "Display multiplexer statistics" },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "LINES", "LINES=n",
&dtc_setnl, &tmxr_show_lines, (void *) &dtc_desc, "Display number of lines" },
{ MTAB_XTD|MTAB_VDV|MTAB_NC, 0, NULL, "LOG=n=file",
&dtc_set_log, NULL, &dtc_desc },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, NULL, "NOLOG",
&dtc_set_nolog, NULL, &dtc_desc, "Disable logging on designated line" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "LOG", NULL,
NULL, &dtc_show_log, &dtc_desc, "Display logging for all lines" },
{0}
};
UNIT dtc_unit[] = {
{UDATA(&dtc_srv, UNIT_DTC, 0)}, /* DTC */
{UDATA(&dtco_srv, UNIT_DIS, 0)}, /* DTC server process */
};
DEVICE dtc_dev = {
"DTC", dtc_unit, NULL, dtc_mod,
2, 8, 15, 1, 8, 64,
NULL, NULL, &dtc_reset, NULL, &dtc_attach, &dtc_detach,
NULL, DEV_DISABLE | DEV_DEBUG | DEV_MUX, 0, dev_debug,
NULL, NULL, &dtc_help, &dtc_help_attach, (void *)&dtc_desc,
&dtc_description
};
/* Start off a terminal controller command */
t_stat dtc_cmd(uint16 cmd, uint16 dev, uint8 chan, uint16 *wc)
{
UNIT *uptr;
int ttu;
int buf;
uptr = &dtc_unit[0];
/* If unit disabled return error */
if (uptr->flags & UNIT_DIS)
return SCPE_NODEV;
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_UNATT;
/* Check if drive is ready to recieve a command */
if ((uptr->u5 & DTC_RDY) == 0)
return SCPE_BUSY;
uptr->u5 = chan;
ttu = (*wc & DTCSTA_TTU) >> 5;
buf = (*wc & DTCSTA_BUF);
/* Set the Terminal unit. */
if (ttu == 0)
uptr->u4 = -1;
else {
uptr->u4 = buf + ((ttu-1) * 15);
}
if (*wc & DTCSTA_GM)
uptr->u5 |= DTC_IGNGM;
if (cmd & DTCSTA_READ)
uptr->u5 |= DTC_RD;
else if (cmd & DTCSTA_INHIBIT)
uptr->u5 |= DTC_INQ;
else
uptr->u5 |= DTC_WR;
if (cmd & DTCSTA_BINARY)
uptr->u5 |= DTC_BIN;
sim_debug(DEBUG_CMD, &dtc_dev, "Datacomm access %s %06o %d %04o\n",
(uptr->u5 & DTC_RD) ? "read" : ((uptr->u5 & DTC_INQ) ? "inq" :
((uptr->u5 & DTC_WR) ? "write" : "unknown")),
uptr->u5, uptr->u4, *wc);
sim_activate(uptr, 5000);
return SCPE_OK;
}
/* Handle processing terminal controller commands */
t_stat dtc_srv(UNIT * uptr)
{
int chan = uptr->u5 & DTC_CHAN;
uint8 ch;
int ttu;
int buf;
int i;
int line = uptr->u4;
/* Process interrage command */
if (uptr->u5 & DTC_INQ) {
if (line == -1) {
buf = -1;
for(i = 0; i < DTC_MLINES; i++) {
if (dtc_lstatus[i]& BufIRQ) {
if ((dtc_lstatus[i] & BufSMASK) == BufReadRdy)
buf = i;
if ((dtc_lstatus[i] & BufSMASK) == BufWriteRdy ||
(dtc_lstatus[i] & BufSMASK) == BufIdle) {
line = i;
break;
}
}
}
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm inqury found %d %d ",
line, buf);
if (line != -1) {
chan_set_eof(chan);
sim_debug(DEBUG_DETAIL, &dtc_dev, " writerdy ");
} else if (buf != -1) {
chan_set_read(chan);
sim_debug(DEBUG_DETAIL, &dtc_dev, " readrdy ");
line = buf;
}
if (line != -1) {
if (dtc_lstatus[line] & BufAbnormal) {
chan_set_wcflg(chan);
sim_debug(DEBUG_DETAIL, &dtc_dev, " abnormal ");
}
dtc_lstatus[line] &= ~BufIRQ;
}
sim_debug(DEBUG_DETAIL, &dtc_dev, " %03o ", dtc_lstatus[i]);
} else {
if (line > dtc_desc.lines) {
chan_set_notrdy(chan);
} else {
switch(dtc_lstatus[line] & BufSMASK) {
case BufReadRdy:
chan_set_read(chan);
sim_debug(DEBUG_DETAIL, &dtc_dev, " readrdy ");
break;
case BufWriteRdy:
chan_set_eof(chan);
sim_debug(DEBUG_DETAIL, &dtc_dev, " writerdy ");
break;
default:
chan_set_error(chan);
sim_debug(DEBUG_DETAIL, &dtc_dev, " busy ");
break;
}
}
if (dtc_lstatus[line] & BufAbnormal) {
chan_set_wcflg(chan);
sim_debug(DEBUG_DETAIL, &dtc_dev, " abnormal ");
}
dtc_lstatus[line] &= ~BufIRQ;
chan_set_wc(uptr->u4, 0);
chan_set_end(chan);
sim_debug(DEBUG_DETAIL, &dtc_dev, " %03o ", dtc_lstatus[line]);
}
if (line != -1) {
for (ttu = 1; line > 15; ttu++)
line -= 15;
} else {
ttu = line = 0;
}
chan_set_wc(chan, (ttu << 5) | line);
chan_set_end(chan);
uptr->u5 = DTC_RDY;
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm inqury %d %d\n",
ttu, line);
}
/* Process for each unit */
if (uptr->u5 & DTC_WR) {
if (line > dtc_desc.lines || line == -1) {
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm write invalid %d\n",
line);
chan_set_notrdy(chan);
chan_set_end(chan);
uptr->u5 = DTC_RDY;
return SCPE_OK;
}
/* Validate that we can send data to buffer */
i = dtc_lstatus[line] & BufSMASK;
switch(i) {
case BufNotReady:
chan_set_notrdy(chan);
case BufInputBusy:
case BufRead:
case BufReadRdy:
chan_set_error(chan);
case BufOutBusy:
chan_set_eof(chan);
chan_set_end(chan);
uptr->u5 = DTC_RDY;
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm write busy %d %d\n",
line, i);
return SCPE_OK;
/* Ok to start filling */
case BufIdle:
case BufWriteRdy:
dtc_lstatus[line] = BufWrite;
dtc_bufptr[line] = 0;
dtc_bsize[line] = 0;
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm write start %d\n",
line);
break;
/* Continue filling */
case BufWrite:
break;
}
if (chan_read_char(chan, &ch, dtc_bufptr[line] >= dtc_blimit[line])) {
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm write done %d %d ",
line, dtc_bufptr[line]);
if (dtc_lstatus[line] & BufAbnormal) {
chan_set_wcflg(chan);
}
dtc_lstatus[line] = BufOutBusy;
/* Check if we filled up buffer */
if (dtc_bufptr[line] >= dtc_blimit[line]) {
chan_set_gm(chan);
sim_debug(DEBUG_DETAIL, &dtc_dev, "full ");
} else {
dtc_lstatus[line] |= BufGM;
sim_debug(DEBUG_DETAIL, &dtc_dev, "gm ");
}
sim_debug(DEBUG_DETAIL, &dtc_dev, "\n");
dtc_bsize[line] = dtc_bufptr[line];
dtc_bufptr[line] = 0;
chan_set_end(chan);
uptr->u5 = DTC_RDY;
return SCPE_OK;
} else {
dtc_buf[line][dtc_bufptr[line]++] = ch & 077;
sim_debug(DEBUG_DATA, &dtc_dev, "Datacomm write data %d %02o %d\n",
line, ch&077, dtc_bufptr[line]);
}
sim_activate(uptr, 5000);
}
if (uptr->u5 & DTC_RD) {
if (line > dtc_desc.lines || line == -1) {
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm read nothing %d\n",
line);
chan_set_notrdy(chan);
chan_set_end(chan);
uptr->u5 = DTC_RDY;
return SCPE_OK;
}
/* Validate that we can send data to buffer */
i = dtc_lstatus[line] & BufSMASK;
switch(i) {
case BufNotReady:
chan_set_notrdy(chan);
case BufInputBusy:
chan_set_error(chan);
case BufWriteRdy:
case BufOutBusy:
case BufIdle:
case BufWrite:
chan_set_eof(chan);
chan_set_end(chan);
uptr->u5 = DTC_RDY;
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm read busy %d %d\n",
line, i);
return SCPE_OK;
/* Ok to start filling */
case BufReadRdy:
dtc_lstatus[line] = (dtc_lstatus[line] & 030) | BufRead;
dtc_bufptr[line] = 0;
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm read starting %d\n",
line);
break;
/* Continue filling */
case BufRead:
break;
}
ch = dtc_buf[line][dtc_bufptr[line]++];
/* If no buffer, error out */
if (chan_write_char(chan, &ch, dtc_bufptr[line] >= dtc_bsize[line])) {
/* Check if we filled up buffer */
if (dtc_lstatus[line] & BufGM) {
chan_set_gm(chan);
sim_debug(DEBUG_DETAIL, &dtc_dev, "gm ");
}
if (dtc_lstatus[line] & BufAbnormal)
chan_set_wcflg(chan);
if (dtc_ldsc[line].conn == 0) /* connected? */
dtc_lstatus[line] = BufNotReady;
else
dtc_lstatus[line] = BufIdle;
dtc_bsize[line] = 0;
chan_set_end(chan);
uptr->u5 = DTC_RDY;
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm read done %d\n",
line);
return SCPE_OK;
} else {
sim_debug(DEBUG_DATA, &dtc_dev, "Datacomm read data %d %02o %d\n",
line, ch & 077, dtc_bufptr[line]);
}
sim_activate(uptr, 5000);
}
return SCPE_OK;
}
/* Unit service - receive side
Poll all active lines for input
Poll for new connections */
t_stat
dtco_srv(UNIT * uptr)
{
int c, ln, t, c1;
sim_clock_coschedule(uptr, tmxr_poll);
ln = tmxr_poll_conn(&dtc_desc); /* look for connect */
if (ln >= 0) { /* got one? */
dtc_blimit[ln] = DTC_BUFSIZ-1;
dtc_lstatus[ln] = BufIRQ|BufAbnormal|BufWriteRdy;
IAR |= IRQ_12;
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm connect %d\n", ln);
}
/* For each line that is in idle state enable recieve */
for (ln = 0; ln < dtc_desc.lines; ln++) {
if (dtc_ldsc[ln].conn &&
(dtc_lstatus[ln] & BufSMASK) == BufIdle) {
dtc_ldsc[ln].rcve = 1;
}
}
tmxr_poll_rx(&dtc_desc); /* poll for input */
for (ln = 0; ln < DTC_MLINES; ln++) { /* loop thru mux */
/* Check for disconnect */
if (dtc_ldsc[ln].conn == 0) { /* connected? */
switch(dtc_lstatus[ln] & BufSMASK) {
case BufIdle: /* Idle, throw in EOT */
case BufWriteRdy: /* Awaiting output, terminate */
dtc_bufptr[ln] = 0;
case BufInputBusy: /* reading, terminate with EOT */
dtc_buf[ln][dtc_bufptr[ln]++] = 017;
dtc_bsize[ln] = dtc_bufptr[ln];
dtc_lstatus[ln] = BufIRQ|BufAbnormal|BufReadRdy;
IAR |= IRQ_12;
break;
case BufOutBusy: /* Terminate Output */
dtc_lstatus[ln] = BufIRQ|BufIdle;
dtc_bsize[ln] = 0;
IAR |= IRQ_12;
break;
default: /* Other cases, ignore until
in better state */
break;
break;
}
continue; /* Skip if not connected */
}
switch(dtc_lstatus[ln] & BufSMASK) {
case BufIdle:
/* If we have any data to receive */
if (tmxr_rqln(&dtc_ldsc[ln]) > 0)
dtc_lstatus[ln] = BufInputBusy;
else
break; /* Nothing to do */
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm recieve %d idle\n",
ln);
dtc_bufptr[ln] = 0;
dtc_bsize[ln] = 0;
case BufInputBusy:
t = 1;
while (t && tmxr_rqln(&dtc_ldsc[ln]) != 0) {
c = tmxr_getc_ln(&dtc_ldsc[ln]) & 0x7f; /* get char */
c1 = ascii_to_con[c];
switch(c) {
case '\005': /* ^E ENQ who-are-you */
dtc_lstatus[ln] &= ~(BufSMASK);
dtc_lstatus[ln] |= BufIRQ|BufAbnormal|BufWriteRdy;
IAR |= IRQ_12;
sim_debug(DEBUG_DETAIL, &dtc_dev,
"Datacomm recieve ENQ %d\n", ln);
t = 0;
break;
case '}':
dtc_buf[ln][dtc_bufptr[ln]++] = 017;
dtc_lstatus[ln] |= BufAbnormal;
/* Fall through to next */
case '\r':
case '\n':
case '~':
dtc_lstatus[ln] &= ~BufSMASK;
dtc_lstatus[ln] |= BufIRQ|BufReadRdy;
/* Force at least one character for GM */
dtc_buf[ln][dtc_bufptr[ln]++] = 077;
dtc_bsize[ln] = dtc_bufptr[ln];
IAR |= IRQ_12;
t = 0;
sim_debug(DEBUG_DETAIL, &dtc_dev,
"Datacomm recieve %d return\n", ln);
break;
case '\025': /* Control U clear input buffer. */
dtc_bsize[ln] = 0;
c1 = 0;
break;
case '\b':
case 0x7f:
if (dtc_bufptr[ln] > 0) {
tmxr_putc_ln(&dtc_ldsc[ln], '\b');
tmxr_putc_ln(&dtc_ldsc[ln], ' ');
tmxr_putc_ln(&dtc_ldsc[ln], '\b');
dtc_bufptr[ln]--;
} else {
tmxr_putc_ln(&dtc_ldsc[ln], '\007');
}
c1 = 0;
sim_debug(DEBUG_DATA, &dtc_dev,
"Datacomm recieve %d backspace\n", ln);
break;
case '?':
sim_debug(DEBUG_DATA, &dtc_dev,
"Datacomm recieve %d ?\n", ln);
dtc_lstatus[ln] |= BufAbnormal;
c1 = 0;
break;
default:
sim_debug(DEBUG_DATA, &dtc_dev,
"Datacomm recieve %d %02x %c %02o\n", ln, c, c, c1);
}
if (t && c1) {
tmxr_putc_ln(&dtc_ldsc[ln], con_to_ascii[c1]);
dtc_buf[ln][dtc_bufptr[ln]++] = c1;
}
if (dtc_bufptr[ln] >= dtc_blimit[ln]) {
sim_debug(DEBUG_DETAIL, &dtc_dev,
"Datacomm recieve %d full\n", ln);
dtc_lstatus[ln] &= ~(BufSMASK);
dtc_lstatus[ln] |= BufGM|BufIRQ|BufReadRdy;
dtc_bsize[ln] = dtc_bufptr[ln];
IAR |= IRQ_12;
t = 0;
break;
}
}
break;
case BufOutBusy:
/* Get next char and send to output */
t = 1;
while(t && dtc_bufptr[ln] < dtc_bsize[ln] && dtc_ldsc[ln].xmte) {
c = dtc_buf[ln][dtc_bufptr[ln]++];
c1 = con_to_ascii[c];
switch(c) {
case 057: /* { */
c1 = '\r'; /* CR */
break;
case 032: /* ! */
c1 = '\n'; /* LF */
break;
case 076: /* < */
c1 = 0; /* X-ON */
break;
case 016: /* > */
c1 = 0; /* DEL */
break;
case 017: /* } */
/* Disconnect line */
tmxr_reset_ln(&dtc_ldsc[ln]);
sim_debug(DEBUG_DETAIL, &dtc_dev,
"Datacomm disconnect %d\n", ln);
t = 0;
continue; /* On to next line */
}
sim_debug(DEBUG_DATA, &dtc_dev,
"Datacomm transmit %d %02o %c\n", ln, c&077, c1);
tmxr_putc_ln(&dtc_ldsc[ln], c1);
if (c1 == '\n') {
tmxr_putc_ln(&dtc_ldsc[ln], '\r');
}
}
if (dtc_bufptr[ln] >= dtc_bsize[ln]) {
if (dtc_lstatus[ln] & BufGM) {
sim_debug(DEBUG_DETAIL, &dtc_dev,
"Datacomm idle %d\n", ln);
dtc_lstatus[ln] = BufIRQ|BufIdle;
} else {
sim_debug(DEBUG_DETAIL, &dtc_dev, "Datacomm writerdy %d\n",
ln);
dtc_lstatus[ln] = BufIRQ|BufWriteRdy;
}
IAR |= IRQ_12;
}
break;
default:
/* Other states are an ignore */
break;
}
} /* end for */
tmxr_poll_tx(&dtc_desc); /* poll xmt */
return SCPE_OK;
}
t_stat
dtc_reset(DEVICE *dptr) {
if (dtc_unit[0].flags & UNIT_ATT) {
sim_activate(&dtc_unit[1], 100); /* quick poll */
iostatus |= DTC_FLAG;
} else {
sim_cancel(&dtc_unit[1]);
iostatus &= ~DTC_FLAG;
}
return SCPE_OK;
}
/* Attach master unit */
t_stat
dtc_attach(UNIT * uptr, char *cptr)
{
int i;
t_stat r;
r = tmxr_attach(&dtc_desc, uptr, cptr); /* attach */
if (r != SCPE_OK)
return r; /* error */
sim_activate(&dtc_unit[1], 100); /* quick poll */
for (i = 0; i < DTC_MLINES; i++) {
dtc_lstatus[i] = BufNotReady; /* Device not connected */
}
uptr->u5 = DTC_RDY;
iostatus |= DTC_FLAG;
return SCPE_OK;
}
/* Detach master unit */
t_stat
dtc_detach(UNIT * uptr)
{
int i;
t_stat r;
r = tmxr_detach(&dtc_desc, uptr); /* detach */
for (i = 0; i < dtc_desc.lines; i++)
dtc_ldsc[i].rcve = 0; /* disable rcv */
sim_cancel(uptr); /* stop poll */
uptr->u5 = 0;
iostatus &= ~DTC_FLAG;
return r;
}
/* SET LINES processor */
t_stat dtc_setnl (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 newln, i, t;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
newln = (int32) get_uint (cptr, 10, DTC_MLINES, &r);
if ((r != SCPE_OK) || (newln == dtc_desc.lines))
return r;
if ((newln == 0) || (newln > DTC_MLINES))
return SCPE_ARG;
if (newln < dtc_desc.lines) {
for (i = newln, t = 0; i < dtc_desc.lines; i++)
t = t | dtc_ldsc[i].conn;
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
return SCPE_OK;
for (i = newln; i < dtc_desc.lines; i++) {
if (dtc_ldsc[i].conn) {
tmxr_linemsg (&dtc_ldsc[i], "\r\nOperator disconnected line\r\n");
tmxr_send_buffered_data (&dtc_ldsc[i]);
}
tmxr_detach_ln (&dtc_ldsc[i]); /* completely reset line */
}
}
if (dtc_desc.lines < newln)
memset (dtc_ldsc + dtc_desc.lines, 0, sizeof(*dtc_ldsc)*(newln-dtc_desc.lines));
dtc_desc.lines = newln;
return dtc_reset (&dtc_dev); /* setup lines and auto config */
}
/* SET LOG processor */
t_stat dtc_set_log (UNIT *uptr, int32 val, char *cptr, void *desc)
{
char *tptr;
t_stat r;
int32 ln;
if (cptr == NULL)
return SCPE_ARG;
tptr = strchr (cptr, '=');
if ((tptr == NULL) || (*tptr == 0))
return SCPE_ARG;
*tptr++ = 0;
ln = (int32) get_uint (cptr, 10, dtc_desc.lines, &r);
if ((r != SCPE_OK) || (ln >= dtc_desc.lines))
return SCPE_ARG;
return tmxr_set_log (NULL, ln, tptr, desc);
}
/* SET NOLOG processor */
t_stat dtc_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc)
{
t_stat r;
int32 ln;
if (cptr == NULL)
return SCPE_ARG;
ln = (int32) get_uint (cptr, 10, dtc_desc.lines, &r);
if ((r != SCPE_OK) || (ln >= dtc_desc.lines))
return SCPE_ARG;
return tmxr_set_nolog (NULL, ln, NULL, desc);
}
/* SHOW LOG processor */
t_stat dtc_show_log (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i;
for (i = 0; i < dtc_desc.lines; i++) {
fprintf (st, "line %d: ", i);
tmxr_show_log (st, NULL, i, desc);
fprintf (st, "\n");
}
return SCPE_OK;
}
/* Show summary processor */
t_stat
dtc_summ(FILE * st, UNIT * uptr, int32 val, void *desc)
{
uint32 i, t;
t = 0;
for (i = 0; i < DTC_MLINES; i++)
t = t + (dtc_ldsc[i].conn != 0);
if (t == 1)
fprintf(st, "1 connection");
else
fprintf(st, "%d connections", t);
return SCPE_OK;
}
/* SHOW CONN/STAT processor */
t_stat
dtc_show(FILE * st, UNIT * uptr, int32 val, void *desc)
{
int32 i, cc;
for (cc = 0; (cc < DTC_MLINES) && dtc_ldsc[cc].conn; cc++) ;
if (cc) {
for (i = 0; i < DTC_MLINES; i++) {
if (dtc_ldsc[i].conn) {
if (val)
tmxr_fconns(st, &dtc_ldsc[i], i);
else
tmxr_fstats(st, &dtc_ldsc[i], i);
}
}
} else
fprintf(st, "all disconnected\n");
return SCPE_OK;
}
t_stat dtc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "B249 Terminal Control Unit\n\n");
fprintf (st, "The B249 is a terminal multiplexor. Up to %d lines are supported.\n", DTC_MLINES);
fprintf (st, "The default number of lines is %d. The number of lines can\n", DTC_MLINES);
fprintf (st, "be changed with the command\n\n");
fprintf (st, " sim> SET %s LINES=n set line count to n\n\n", dptr->name);
fprintf (st, "The B249 supports logging on a per-line basis. The command\n\n");
fprintf (st, " sim> SET %s LOG=n=filename\n\n", dptr->name);
fprintf (st, "enables logging for the specified line(n) to the indicated file. The command\n\n");
fprintf (st, " sim> SET %s NOLOG=line\n\n", dptr->name);
fprintf (st, "disables logging for the specified line and closes any open log file. Finally,\n");
fprintf (st, "the command:\n\n");
fprintf (st, " sim> SHOW %s LOG\n\n", dptr->name);
fprintf (st, "displays logging information for all %s lines.\n\n", dptr->name);
fprintf (st, "Once the B249 is attached and the simulator is running, the B249 will listen for\n");
fprintf (st, "connections on the specified port. It assumes that the incoming connections\n");
fprintf (st, "are Telnet connections. The connection remains open until disconnected by the\n");
fprintf (st, "simulated program, the Telnet client, a SET %s DISCONNECT command, or a\n", dptr->name);
fprintf (st, "DETACH %s command.\n\n", dptr->name);
fprintf (st, "Other special %s commands:\n\n", dptr->name);
fprintf (st, " sim> SHOW %s CONNECTIONS show current connections\n", dptr->name);
fprintf (st, " sim> SHOW %s STATISTICS show statistics for active connections\n", dptr->name);
fprintf (st, " sim> SET %s DISCONNECT=linenumber disconnects the specified line.\n\n\n", dptr->name);
fprintf (st, "All open connections are lost when the simulator shuts down or the %s is\n", dptr->name);
fprintf (st, "detached.\n\n");
dtc_help_attach (st, dptr, uptr, flag, cptr);
return SCPE_OK;
}
t_stat dtc_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
tmxr_attach_help (st, dptr, uptr, flag, cptr);
fprintf (st, "The terminal lines perform input and output through Telnet sessions connected\n");
fprintf (st, "to a user-specified port. The ATTACH command specifies the port to be used:\n\n");
fprintf (st, " sim> ATTACH %s {interface:}port set up listening port\n\n", dptr->name);
fprintf (st, "where port is a decimal number between 1 and 65535 that is not being used for\n");
fprintf (st, "other TCP/IP activities. All terminals are considered Dialup to the B249.\n");
return SCPE_OK;
}
const char *dtc_description (DEVICE *dptr)
{
return "B249 Terminal Control Unit";
}
#endif

795
B5500/b5500_io.c Normal file
View file

@ -0,0 +1,795 @@
/* B5500_io.c: Burroughs 5500 I/O System.
Copyright (c) 2016, Richard Cornwell
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
RICHARD CORNWELL 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.
*/
#include "b5500_defs.h"
#define EOR 1
#define USEGM 2
t_stat chan_reset(DEVICE * dptr);
/* Channel data structures
chan_dev Channel device descriptor
chan_unit Channel unit descriptor
chan_reg Channel register list
chan_mod Channel modifiers list
*/
t_uint64 D[NUM_CHAN]; /* Current I/O instruction */
uint8 CC[NUM_CHAN]; /* Channel character count */
t_uint64 W[NUM_CHAN]; /* Assembly register */
uint8 status[NUM_CHAN]; /* Channel status */
uint8 cstatus; /* Active status */
#define WC(x) (uint16)(((x) & DEV_WC) >> DEV_WC_V)
#define toWC(x) (((t_uint64)(x) << DEV_WC_V) & DEV_WC)
UNIT chan_unit[] = {
/* Normal channels */
{UDATA(NULL,UNIT_DISABLE,0)},/* A */
{UDATA(NULL,UNIT_DISABLE,0)},/* B */
{UDATA(NULL,UNIT_DISABLE,0)},/* C */
{UDATA(NULL,UNIT_DISABLE,0)},/* D */
};
REG chan_reg[] = {
{BRDATA(D, D, 8, 48, NUM_CHAN), REG_RO},
{BRDATA(CC, CC, 7, 6, NUM_CHAN), REG_RO},
{BRDATA(W, W, 8, 48, NUM_CHAN), REG_RO},
{NULL}
};
/* Simulator debug controls */
DEBTAB chn_debug[] = {
{"CHANNEL", DEBUG_CHAN},
{"DETAIL", DEBUG_DETAIL},
{"DATA", DEBUG_DATA},
{"CH0", 0x0100 << 0},
{"CH1", 0x0100 << 1},
{"CH2", 0x0100 << 2},
{"CH3", 0x0100 << 3},
{0, 0}
};
DEVICE chan_dev = {
"IO", chan_unit, chan_reg, NULL,
NUM_CHAN, 10, 18, 1, 10, 44,
NULL, NULL, &chan_reset, NULL, NULL, NULL,
NULL, DEV_DEBUG, 0, chn_debug
};
t_stat
chan_reset(DEVICE * dptr)
{
int i;
int j = 1;
cstatus = 0;
/* Clear channel assignment */
for (i = 0; i < NUM_CHAN; i++) {
status[i] = 0;
D[i] = 0;
W[i] = 0;
CC[i] = 0;
if (chan_unit[i].flags & UNIT_DIS)
cstatus |= j;
j <<= 1;
}
return SCPE_OK;
}
/* Boot from given device */
t_stat
chan_boot(t_uint64 desc)
{
M[020] = desc;
M[010] = 020;
loading = 1;
start_io();
return SCPE_OK;
}
int
find_chan() {
int i;
int chan;
i = 1;
for(chan = 0; chan < NUM_CHAN; chan++) {
if ((cstatus & i) == 0)
break;
i <<= 1;
}
if (chan == NUM_CHAN) {
return 0;
}
return chan + 1;
}
void
chan_release(int chan) {
cstatus &= ~(1 << chan);
}
int
chan_advance(int chan) {
uint16 addr = (uint16)(D[chan] & CORE);
if (D[chan] & DEV_WCFLG) {
uint16 wc = WC(D[chan]);
if (wc == 0) {
status[chan] |= EOR;
return 1;
}
D[chan] &= ~DEV_WC;
D[chan] |= toWC(wc-1);
}
if (addr > MEMSIZE) {
D[chan] |= DEV_MEMERR;
status[chan] |= EOR;
return 1;
}
W[chan] = M[addr];
D[chan] &= ~CORE;
if (D[chan] & DEV_BACK)
D[chan] |= (t_uint64)((addr - 1) & CORE);
else
D[chan] |= (t_uint64)((addr + 1) & CORE);
CC[chan] = 0;
return 0;
}
void
start_io() {
int i;
int chan;
t_stat r;
uint16 dev;
uint16 cmd;
uint16 wc;
int addr;
chan = find_chan();
addr = M[010] & CORE;
if (chan == 0) {
IAR |= IRQ_1;
return;
}
chan--;
i = 1 << chan;
sim_debug(DEBUG_DETAIL, &chan_dev, "strtio(%016llo %d)\n", M[addr], chan);
D[chan] = M[addr] & D_MASK;
CC[chan] = 0;
W[chan] = 0;
dev = (uint16)((D[chan] & DEVMASK) >> DEV_V);
cmd = (uint16)((D[chan] & DEV_CMD) >> DEV_CMD_V);
wc = WC(D[chan]);
D[chan] &= ~DEV_RESULT;
status[chan] = 0;
if (dev & 1) {
#if (NUM_DEVS_MT > 0)
status[chan] = USEGM;
r = mt_cmd(cmd, dev, chan, &wc);
#else
r = SCPE_UNATT;
#endif
} else {
switch(dev) {
#if (NUM_DEVS_DR > 0)
case DRUM1_DEV:
case DRUM2_DEV:
r = drm_cmd(cmd, dev, chan, &wc, (uint8)((M[addr] & PRESENT)!=0));
break;
#endif
#if (NUM_DEVS_CDR > 0) | (NUM_DEVS_CDP > 0)
case CARD1_DEV:
case CARD2_DEV:
r = card_cmd(cmd, dev, chan, &wc);
break;
#endif
#if (NUM_DEVS_DSK > 0)
case DSK1_DEV:
case DSK2_DEV:
/* Need to pass word count to identify interrogates */
r = dsk_cmd(cmd, dev, chan, &wc);
break;
#endif
#if (NUM_DEVS_DTC > 0)
case DTC_DEV:
status[chan] = USEGM;
/* Word count is TTU and BUF number */
r = dtc_cmd(cmd, dev, chan, &wc);
if (r == SCPE_OK)
D[chan] &= ~DEV_WC;
D[chan] &= ~(DEV_BIN|DEV_WCFLG);
wc = 0;
break;
#endif
#if (NUM_DEVS_LPR > 0)
case PRT1_DEV:
case PRT2_DEV:
r = lpr_cmd(cmd, dev, chan, &wc);
if (r == SCPE_OK)
D[chan] &= ~DEV_BACK; /* Clear this bit, since printer
uses this to determine 120/132
char line */
break;
#endif
#if (NUM_DEVS_CON > 0)
case SPO_DEV:
status[chan] = USEGM;
r = con_cmd(cmd, dev, chan, &wc);
break;
#endif
default:
r = SCPE_UNATT;
break;
}
}
if (wc != 0) {
D[chan] &= ~DEV_WC;
D[chan] |= toWC(wc) | DEV_WCFLG;
}
switch(r) {
case SCPE_OK:
cstatus |= i;
return;
case SCPE_NXDEV:
case SCPE_UNATT:
D[chan] |= DEV_NOTRDY;
break;
case SCPE_BUSY:
D[chan] |= DEV_BUSY;
break;
case SCPE_EOF:
D[chan] |= DEV_EOF;
break;
}
chan_set_end(chan);
}
void
chan_set_end(int chan) {
uint16 dev;
dev = (uint16)((D[chan] & DEVMASK) >> DEV_V);
/* Set character count if reading and tape */
if ((dev & 1) && (D[chan] & DEV_IORD)) {
D[chan] &= ~((7LL)<<DEV_WC_V);
/* If not data transfered, return zero code */
if ((D[chan] & DEV_BACK) != 0 &&
(status[chan] & EOR) != 0)
D[chan] |= ((t_uint64)((7-CC[chan]) & 07)) << DEV_WC_V;
else
D[chan] |= ((t_uint64)(CC[chan] & 07)) << DEV_WC_V;
}
/* Flush last buffer if short write */
if ((D[chan] & DEV_IORD) && CC[chan] != 0) {
uint16 addr = (uint16)(D[chan] & CORE);
if ((D[chan] & (DEV_BIN|DEV_WCFLG)) == 0) {
/* Insert group mark */
if (D[chan] & DEV_BACK) {
W[chan] |= (t_uint64)037LL << ((CC[chan]) * 6);
CC[chan]++;
} else {
while(CC[chan] != 8) {
W[chan] |= 037LL << ((7 - CC[chan]) * 6);
CC[chan]++;
}
}
}
M[addr] = W[chan];
sim_debug(DEBUG_DATA, &chan_dev, "write(%d, %05o, %016llo)f\n",
chan, addr, W[chan]);
(void)chan_advance(chan);
}
M[014+chan] = D[chan];
if (loading == 0)
IAR |= IRQ_5 << chan;
else
loading = 0;
sim_debug(DEBUG_DETAIL, &chan_dev, "endio (%016llo %o)\n", D[chan], chan);
}
void
chan_set_eof(int chan) {
D[chan] |= DEV_EOF;
}
void
chan_set_parity(int chan) {
D[chan] |= DEV_PARITY;
}
void
chan_set_error(int chan) {
D[chan] |= DEV_ERROR;
}
void
chan_set_wcflg(int chan) {
D[chan] |= DEV_WCFLG;
}
void
chan_set_read(int chan) {
D[chan] |= DEV_IORD;
}
void
chan_set_gm(int chan) {
D[chan] |= DEV_BACK;
}
void
chan_set_notrdy(int chan) {
D[chan] |= DEV_NOTRDY;
chan_set_end(chan);
}
void
chan_set_eot(int chan) {
D[chan] &= ~DEV_WC;
D[chan] |= DEV_EOT;
}
void
chan_set_bot(int chan) {
D[chan] &= ~DEV_WC;
D[chan] |= DEV_BOT;
}
void
chan_set_blank(int chan) {
D[chan] &= ~DEV_WC;
D[chan] |= DEV_BLANK;
}
void
chan_set_wrp(int chan) {
D[chan] |= DEV_ERROR|DEV_MEMERR;
}
void
chan_set_wc(int chan, uint16 wc) {
D[chan] &= ~DEV_WC;
D[chan] |= toWC(wc);
}
/*
Internal BCD
00 0000 00 1010 0000 -> 1010
00 0001 00 0001
00 0010 00 0010
00 0011 00 0011
00 0100 00 0100
00 0101 00 0101
00 0110 00 0110
00 0111 00 0111
00 1000 00 1000
00 1001 00 1001
00 1010 00 1011 1010 -> 1011
00 1011 00 1100 1011 -> 1100
00 1100 00 0000 1100 -> 0000
00 1101 00 1101
00 1110 00 1110
00 1111 00 1111
01 0000 11 1010 0000 -> 1010 10
01 0001 11 0001 1
01 0010 11 0010 2
01 0011 11 0011 3
01 0100 11 0100
01 0101 11 0101
01 0110 11 0110
01 0111 11 0111
01 1000 11 1000 8
01 1001 11 1001 9
01 1010 11 1011 1010 -> 1011 10
01 1011 11 1100 1011 -> 1100 11
01 1100 11 0000 1100 -> 0000 12
01 1101 11 1101 13
01 1110 11 1110 14
01 1111 11 1111 15
10 0000 10 1010 0000 -> 1010
10 0001 10 0001
10 0010 10 0010
10 0011 10 0011
10 0100 10 0100
10 0101 10 0101
10 0110 10 0110
10 0111 10 0111
10 1000 10 1000
10 1001 10 1001
10 1010 10 1011 1010 -> 1011
10 1011 10 1100 1011 -> 1100
10 1100 10 0000 1100 -> 0000
10 1101 10 1101
10 1110 10 1110
10 1111 10 1111
11 0000 01 0000
11 0001 01 0001
11 0010 01 0010
11 0011 01 0011
11 0100 01 0100
11 0101 01 0101
11 0110 01 0110
11 0111 01 0111
11 1000 01 1000
11 1001 01 1001
11 1010 01 1011 1010 -> 1011
11 1011 01 1100 1011 -> 1100
11 1100 01 1010 1100 -> 1010
11 1101 01 1101
11 1110 01 1110
11 1111 01 1111 */
/* returns 1 when channel can take no more characters.
A return of 1 indicates that the character was not
processed.
*/
int chan_write_char(int chan, uint8 *ch, int flags) {
uint8 c;
if (status[chan] & EOR)
return 1;
if (D[chan] & DEV_INHTRF) {
status[chan] |= EOR;
return 1;
}
/* Check if first word */
if (CC[chan] == 0) {
uint16 wc = WC(D[chan]);
if (D[chan] & DEV_WCFLG && wc == 0) {
sim_debug(DEBUG_DATA, &chan_dev, "zerowc(%d)\n", chan);
status[chan] |= EOR;
return 1;
}
W[chan] = 0;
}
c = *ch & 077;
if ((D[chan] & DEV_BIN) == 0) {
/* Translate BCL to BCD */
uint8 cx = c & 060;
c &= 017;
switch(c) {
case 0:
/* 11-0 -> 01 C */
/* 10-0 -> 10 C */
/* 01-0 -> 11 0 */
/* 00-0 -> 00 C */
if (cx != 020)
c = 0xc;
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 0xd:
case 0xe:
case 0xf:
break;
case 0xa:
/* 11-A -> 01 0 */
/* 10-A -> 10 0 */
/* 01-A -> 11 C */
/* 00-A -> 00 0 */
if (cx == 020)
c = 0xc;
else
c = 0;
break;
case 0xb:
c = 0xa;
break;
case 0xc:
c = 0xb;
break;
}
c |= cx ^ ((cx & 020)<<1);
}
if (D[chan] & DEV_BACK)
W[chan] |= ((t_uint64)c) << ((CC[chan]) * 6);
else
W[chan] |= ((t_uint64)c) << ((7 - CC[chan]) * 6);
CC[chan]++;
if (CC[chan] == 8) {
uint16 addr = (uint16)(D[chan] & CORE);
M[addr] = W[chan];
sim_debug(DEBUG_DATA, &chan_dev, "write(%d, %05o, %016llo)\n",
chan, addr, W[chan]);
if (chan_advance(chan))
return 1;
}
if (flags) {
if ((D[chan] & (DEV_BIN|DEV_WCFLG)) == 0) {
/* Insert group mark */
if (D[chan] & DEV_BACK) {
int i = CC[chan];
W[chan] |= (t_uint64)037LL << ((CC[chan]) * 6);
while(i < 8) {
W[chan] |= (t_uint64)014LL << (i * 6);
i++;
}
} else {
W[chan] |= 037LL << ((7 - CC[chan]) * 6);
}
CC[chan]++;
}
/* Flush last word */
if (CC[chan] != 0) {
uint16 addr = (uint16)(D[chan] & CORE);
M[addr] = W[chan];
sim_debug(DEBUG_DATA, &chan_dev, "write(%d, %05o, %016llo)\n",
chan, addr, W[chan]);
(void)chan_advance(chan);
}
status[chan] |= EOR;
return 1;
}
return 0;
}
/* Returns 1 on last character. If it returns 1, the
character in ch is not valid. If flag is set to 1, then
this is the last character the device will request.
*/
int chan_read_char(int chan, uint8 *ch, int flags) {
uint8 c;
int gm;
if (status[chan] & EOR)
return 1;
if (D[chan] & DEV_INHTRF) {
status[chan] |= EOR;
return 1;
}
if (CC[chan] == 0) {
uint16 addr = (uint16)(D[chan] & CORE);
if (chan_advance(chan))
return 1;
sim_debug(DEBUG_DATA, &chan_dev, "read(%d, %05o, %016llo)\n", chan,
addr, W[chan]);
}
if (D[chan] & DEV_BACK)
c = 077 & (W[chan] >> ((CC[chan]) * 6));
else
c = 077 & (W[chan] >> ((7 - CC[chan]) * 6));
gm = (c == 037);
CC[chan]++;
if (CC[chan] == 8) {
CC[chan] = 0;
}
if ((D[chan] & DEV_BIN) == 0) {
/* Translate BCD to BCL */
uint8 cx = c & 060;
c &= 017;
switch(c) {
case 0:
if (cx != 060)
c = 0xa;
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 0xd:
case 0xe:
case 0xf:
break;
case 0xa:
c = 0xb;
break;
case 0xb:
c = 0xc;
break;
case 0xc:
if (cx == 060)
c = 0xa;
else
c = 0;
break;
}
c |= cx ^ ((cx & 020)<<1);
}
*ch = c;
if ((status[chan] & USEGM) != 0 && (D[chan] & DEV_WCFLG) == 0 && gm) {
status[chan] |= EOR;
return 1;
}
if (flags) {
status[chan] |= EOR;
}
return 0;
}
/* Same as chan_read_char, however we do not check word count
nor do we advance it.
*/
int chan_read_disk(int chan, uint8 *ch, int flags) {
uint8 c;
if (CC[chan] == 0) {
uint16 addr = (uint16)(D[chan] & CORE);
if (addr > MEMSIZE) {
D[chan] |= DEV_MEMERR;
return 1;
}
W[chan] = M[addr];
D[chan] &= ~CORE;
D[chan] |= (addr + 1) & CORE;
}
c = 077 & (W[chan] >> ((7 - CC[chan]) * 6));
CC[chan]++;
*ch = c;
if (CC[chan] == 8) {
CC[chan] = 0;
return 1;
}
return 0;
}
int
chan_advance_drum(int chan) {
uint16 addr = (uint16)(D[chan] & CORE);
uint16 wc = WC(D[chan]);
if (wc == 0) {
status[chan] |= EOR;
return 1;
}
D[chan] &= ~DEV_WC;
D[chan] |= toWC(wc-1);
if (addr > MEMSIZE) {
D[chan] |= DEV_MEMERR;
status[chan] |= EOR;
return 1;
}
W[chan] = M[addr];
D[chan] &= ~CORE;
D[chan] |= (addr + 1) & CORE;
CC[chan] = 0;
return 0;
}
/* returns 1 when channel can take no more characters.
A return of 1 indicates that the character was not
processed.
*/
int chan_write_drum(int chan, uint8 *ch, int flags) {
uint8 c;
if (status[chan] & EOR)
return 1;
/* Check if first word */
if (CC[chan] == 0) {
uint16 wc = WC(D[chan]);
if (wc == 0) {
status[chan] |= EOR;
return 1;
}
W[chan] = 0;
}
c = *ch;
c &= 077;
W[chan] |= (t_uint64)c << ((7 - CC[chan]) * 6);
CC[chan]++;
if (CC[chan] == 8) {
uint16 addr = (uint16)(D[chan] & CORE);
M[addr] = W[chan];
if (chan_advance_drum(chan))
return 1;
}
if (flags) {
/* Flush last word */
if (CC[chan] != 0) {
uint16 addr = (uint16)(D[chan] & CORE);
M[addr] = W[chan];
(void)chan_advance_drum(chan);
}
status[chan] |= EOR;
return 1;
}
return 0;
}
/* Returns 1 on last character. If it returns 1, the
character in ch is not valid. If flag is set to 1, then
this is the last character the device will request.
*/
int chan_read_drum(int chan, uint8 *ch, int flags) {
uint8 c;
if (status[chan] & EOR)
return 1;
if (CC[chan] == 0) {
if (chan_advance_drum(chan))
return 1;
}
c = 077 & (W[chan] >> ((7 - CC[chan]) * 6));
CC[chan]++;
if (CC[chan] == 8) {
CC[chan] = 0;
}
*ch = c;
if (flags) {
status[chan] |= EOR;
}
return 0;
}

629
B5500/b5500_mt.c Normal file
View file

@ -0,0 +1,629 @@
/* b5500_mt.c: Burrioughs 5500 Magnetic tape controller
Copyright (c) 2016, Richard Cornwell
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
RICHARD CORNWELL 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.
Magnetic tapes are represented as a series of variable records
of the form:
32b byte count
byte 0
byte 1
:
byte n-2
byte n-1
32b byte count
If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a byte count of 0.
*/
#include "b5500_defs.h"
#include "sim_tape.h"
#if (NUM_DEVS_MT > 0)
#define BUFFSIZE 10240
#define UNIT_MT UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE
#define HT 500 /* Time per char high density */
/* in u3 is device address */
/* in u4 is current buffer position */
/* in u5 Bits 30-16 of W */
#define URCSTA_SKIP 000017 /* Skip mask */
#define URCSTA_SINGLE 000020 /* Single space skip. */
#define URCSTA_DOUBLE 000040 /* Double space skip */
#define URCSTA_READ 000400 /* Read flag */
#define URCSTA_WC 001000 /* Use word count */
#define URCSTA_DIRECT 002000 /* Direction, Long line */
#define URCSTA_BINARY 004000 /* Binary transfer */
#define URCSTA_INHIBIT 040000 /* Inhibit transfer to memory */
#define MT_CHAN 0000003 /* Channel active on */
#define MT_BIN 0000004 /* Binary/BCD */
#define MT_BACK 0000010 /* Backwards */
#define MT_CMD 0000070 /* Command to tape drive */
#define MT_INT 0000010 /* Interrogate */
#define MT_RD 0000020 /* Reading */
#define MT_RDBK 0000030 /* Reading Backwards */
#define MT_WR 0000040 /* Writing */
#define MT_REW 0000050 /* Rewind */
#define MT_FSR 0000060 /* Space Forward */
#define MT_BSR 0000070 /* Space Backward record */
#define MT_RDY 0000100 /* Device is ready for command */
#define MT_IDLE 0000200 /* Tape still in motion */
#define MT_MARK 0001000 /* Hit tape mark */
#define MT_EOT 0002000 /* At End Of Tape */
#define MT_BOT 0004000 /* At Beginning Of Tape */
#define MT_EOR 0010000 /* Set EOR on next record */
#define MT_BSY 0020000 /* Tape busy after operation */
#define MT_LOADED 0040000 /* Tape loaded, return ready */
t_stat mt_srv(UNIT *);
t_stat mt_attach(UNIT *, char *);
t_stat mt_detach(UNIT *);
t_stat mt_reset(DEVICE *);
t_stat mt_help(FILE *, DEVICE *, UNIT *, int32, const char *);
const char *mt_description(DEVICE *dptr);
/* Channel level activity */
uint8 mt_chan[NUM_CHAN];
uint16 mt_busy = 0; /* Busy bits */
/* One buffer per channel */
uint8 mt_buffer[NUM_CHAN][BUFFSIZE];
UNIT mt_unit[] = {
/* Controller 1 */
#if (NUM_DEVS_MT > 0)
{UDATA(&mt_srv, UNIT_MT, 0), 0}, /* 0 */
{UDATA(&mt_srv, UNIT_MT, 0), 0}, /* 1 */
{UDATA(&mt_srv, UNIT_MT, 0), 0}, /* 2 */
{UDATA(&mt_srv, UNIT_MT, 0), 0}, /* 3 */
#if (NUM_DEVS_MT > 3)
{UDATA(&mt_srv, UNIT_MT, 0), 0}, /* 4 */
{UDATA(&mt_srv, UNIT_MT, 0), 0}, /* 5 */
{UDATA(&mt_srv, UNIT_MT, 0), 0}, /* 6 */
{UDATA(&mt_srv, UNIT_MT, 0), 0}, /* 7 */
#if (NUM_DEVS_MT > 7)
{UDATA(&mt_srv, UNIT_MT|UNIT_DIS, 0), 0}, /* 8 */
{UDATA(&mt_srv, UNIT_MT|UNIT_DIS, 0), 0}, /* 9 */
{UDATA(&mt_srv, UNIT_MT|UNIT_DIS, 0), 0}, /* 10 */
{UDATA(&mt_srv, UNIT_MT|UNIT_DIS, 0), 0}, /* 11 */
#if (NUM_DEVS_MT > 11)
{UDATA(&mt_srv, UNIT_MT|UNIT_DIS, 0), 0}, /* 12 */
{UDATA(&mt_srv, UNIT_MT|UNIT_DIS, 0), 0}, /* 13 */
{UDATA(&mt_srv, UNIT_MT|UNIT_DIS, 0), 0}, /* 14 */
{UDATA(&mt_srv, UNIT_MT|UNIT_DIS, 0), 0}, /* 15 */
#endif
#endif
#endif
#endif
};
MTAB mt_mod[] = {
{MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL,
"Write ring in place"},
{MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL, NULL,
"no Write ring in place"},
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL,
"Set/Display tape format (SIMH, E11, TPC, P7B)" },
{MTAB_XTD | MTAB_VUN, 0, "LENGTH", "LENGTH",
&sim_tape_set_capac, &sim_tape_show_capac, NULL,
"Set unit n capacity to arg MB (0 = unlimited)" },
{MTAB_XTD | MTAB_VUN, 0, "DENSITY", "DENSITY",
NULL, &sim_tape_show_dens, NULL},
{0}
};
DEVICE mt_dev = {
"MT", mt_unit, NULL, mt_mod,
NUM_DEVS_MT, 8, 15, 1, 8, 8,
NULL, NULL, &mt_reset, NULL, &mt_attach, &mt_detach,
NULL, DEV_DISABLE | DEV_DEBUG | DEV_TAPE, 0, dev_debug,
NULL, NULL, &mt_help, NULL, NULL,
&mt_description
};
/* Start off a mag tape command */
t_stat
mt_cmd(uint16 cmd, uint16 dev, uint8 chan, uint16 *wc)
{
UNIT *uptr;
int unit = dev >> 1;
/* Make sure valid drive number */
if (unit > NUM_DEVS_MT || unit < 0)
return SCPE_NODEV;
uptr = &mt_unit[unit];
/* If unit disabled return error */
if (uptr->flags & UNIT_DIS)
return SCPE_NODEV;
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_UNATT;
/* Not there until loading done */
if ((uptr->u5 & MT_LOADED))
return SCPE_UNATT;
/* Check if drive is ready to recieve a command */
if ((uptr->u5 & MT_BSY) != 0)
return SCPE_BUSY;
/* Determine actual command */
uptr->u5 &= ~(MT_RDY|MT_CHAN|MT_CMD|MT_BIN);
uptr->u5 |= chan;
if (cmd & URCSTA_BINARY)
uptr->u5 |= MT_BIN;
if (cmd & URCSTA_READ) {
if ((cmd & URCSTA_WC) && *wc == 0)
uptr->u5 |= MT_FSR;
else
uptr->u5 |= MT_RD;
} else {
/* Erase gap not supported on sim, treat as
write of null record */
if ((cmd & URCSTA_WC) && *wc == 0)
uptr->u5 |= MT_INT;
else
uptr->u5 |= MT_WR;
}
*wc = 0; /* So no overide occurs */
/* Convert command to correct type */
if (cmd & URCSTA_DIRECT)
uptr->u5 |= MT_BACK;
uptr->u6 = 0;
uptr->hwmark = -1;
sim_debug(DEBUG_CMD, &mt_dev, "Command %d %o %o\n\r", unit, uptr->u5, cmd);
if ((uptr->u5 & MT_IDLE) == 0) {
sim_activate(uptr,50000);
}
return SCPE_OK;
}
/* Map simH errors into machine errors */
t_stat mt_error(UNIT * uptr, int chan, t_stat r, DEVICE * dptr)
{
switch (r) {
case MTSE_OK: /* no error */
sim_debug(DEBUG_EXP, dptr, "OK ");
break;
case MTSE_EOM: /* end of medium */
sim_debug(DEBUG_EXP, dptr, "EOT ");
if (uptr->u5 & MT_BOT) {
chan_set_blank(chan);
} else {
uptr->u5 &= ~MT_BOT;
uptr->u5 |= MT_EOT;
chan_set_eot(chan);
}
break;
case MTSE_TMK: /* tape mark */
sim_debug(DEBUG_EXP, dptr, "MARK ");
uptr->u5 &= ~(MT_BOT|MT_EOT);
chan_set_eof(chan);
break;
case MTSE_WRP: /* write protected */
sim_debug(DEBUG_EXP, dptr, "WriteLocked ");
chan_set_wrp(chan);
break;
case MTSE_INVRL: /* invalid rec lnt */
case MTSE_IOERR: /* IO error */
case MTSE_FMT: /* invalid format */
case MTSE_RECE: /* error in record */
chan_set_error(chan); /* Force redundency error */
sim_debug(DEBUG_EXP, dptr, "ERROR %d ", r);
break;
case MTSE_BOT: /* beginning of tape */
uptr->u5 &= ~MT_EOT;
uptr->u5 |= MT_BOT;
chan_set_bot(chan); /* Set flag */
sim_debug(DEBUG_EXP, dptr, "BOT ");
break;
case MTSE_UNATT: /* unattached */
default:
sim_debug(DEBUG_EXP, dptr, "%d ", r);
}
uptr->u5 &= ~(MT_CMD|MT_BIN);
uptr->u5 |= MT_RDY|MT_IDLE;
chan_set_end(chan);
return SCPE_OK;
}
/* Handle processing of tape requests. */
t_stat mt_srv(UNIT * uptr)
{
int chan = uptr->u5 & MT_CHAN;
int unit = uptr - mt_unit;
int cmd = uptr->u5 & MT_CMD;
DEVICE *dptr = find_dev_from_unit(uptr);
t_mtrlnt reclen;
t_stat r = SCPE_ARG; /* Force error if not set */
uint8 ch;
int mode;
t_mtrlnt loc;
/* Simulate tape load delay */
if (uptr->u5 & MT_LOADED) {
uptr->u5 &= ~MT_LOADED;
uptr->u5 |= MT_BSY|MT_RDY;
sim_debug(DEBUG_DETAIL, dptr, "Unit=%d Loaded\n\r", unit);
sim_activate(uptr, 50000);
return SCPE_OK;
}
if (uptr->u5 & MT_BSY) {
uptr->u5 &= ~MT_BSY;
sim_debug(DEBUG_DETAIL, dptr, "Unit=%d Online\n\r", unit);
iostatus |= 1 << (uptr - mt_unit);
if (uptr->u5 & MT_IDLE)
sim_activate(uptr, 50000);
return SCPE_OK;
}
if (uptr->u5 & MT_IDLE) {
uptr->u5 &= ~MT_IDLE;
if (uptr->u5 & MT_RDY) {
sim_debug(DEBUG_DETAIL, dptr, "Unit=%d idling\n\r", unit);
return SCPE_OK;
}
sim_debug(DEBUG_DETAIL, dptr, "Unit=%d start %02o\n\r", unit, cmd);
}
switch (cmd) {
/* Handle interrogate */
case MT_INT:
if (sim_tape_wrp(uptr))
chan_set_wrp(chan);
uptr->u5 &= ~(MT_CMD|MT_BIN);
uptr->u5 |= MT_RDY;
chan_set_end(chan);
sim_debug(DEBUG_DETAIL, dptr, "Status\n\r");
return SCPE_OK;
case MT_RD: /* Read */
/* If at end of record, fill buffer */
if (uptr->hwmark == -1) {
sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d %s ", unit,
(uptr->u5 & MT_BIN)? "bin": "bcd");
if (sim_tape_eot(uptr)) {
sim_activate(uptr, 4000);
return mt_error(uptr, chan, MTSE_EOM, dptr);
}
r = sim_tape_rdrecf(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE);
if (r != MTSE_OK) {
if (r == MTSE_TMK) {
sim_debug(DEBUG_DETAIL, dptr, "TM\n\r");
ch = 017;
(void)chan_write_char(chan, &ch, 1);
sim_activate(uptr, 4000);
} else {
sim_debug(DEBUG_DETAIL, dptr, "r=%d\n\r", r);
sim_activate(uptr, 5000);
}
return mt_error(uptr, chan, r, dptr);
} else {
uptr->u5 &= ~(MT_BOT|MT_EOT);
uptr->hwmark = reclen;
}
sim_debug(DEBUG_DETAIL, dptr, "%d chars\n\r", uptr->hwmark);
uptr->u6 = 0;
if ((uptr->u5 & MT_BIN) == 0)
mode = 0100;
else
mode = 0;
for (loc = 0; loc < reclen; loc++) {
ch = mt_buffer[chan][loc] & 0177;
if (((parity_table[ch & 077]) ^ (ch & 0100) ^ mode) == 0) {
chan_set_error(chan);
break;
}
}
}
ch = mt_buffer[chan][uptr->u6++] & 0177;
/* 00 characters are not transfered in BCD mode */
if (ch == 0) {
if (((uint32)uptr->u6) >= uptr->hwmark) {
sim_activate(uptr, 4000);
return mt_error(uptr, chan, MTSE_OK, dptr);
} else {
sim_activate(uptr, HT);
return SCPE_OK;
}
}
if (chan_write_char(chan, &ch,
(((uint32)uptr->u6) >= uptr->hwmark) ? 1 : 0)) {
sim_debug(DEBUG_DATA, dptr, "Read unit=%d %d EOR\n\r", unit,
uptr->hwmark-uptr->u6);
sim_activate(uptr, 4000);
return mt_error(uptr, chan, MTSE_OK, dptr);
} else {
sim_debug(DEBUG_DATA, dptr, "Read data unit=%d %d %03o\n\r",
unit, uptr->u6, ch);
sim_activate(uptr, HT);
}
return SCPE_OK;
case MT_RDBK: /* Read Backword */
/* If at end of record, fill buffer */
if (uptr->hwmark == -1) {
sim_debug(DEBUG_DETAIL, dptr, "Read back unit=%d %s ", unit,
(uptr->u5 & MT_BIN)? "bin": "bcd");
if (sim_tape_bot(uptr)) {
sim_activate(uptr, 4000);
return mt_error(uptr, chan, MTSE_BOT, dptr);
}
r = sim_tape_rdrecr(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE);
if (r != MTSE_OK) {
if (r == MTSE_TMK) {
sim_debug(DEBUG_DETAIL, dptr, "TM\n\r");
ch = 017;
(void)chan_write_char(chan, &ch, 1);
sim_activate(uptr, 4000);
} else {
uptr->u5 |= MT_BSY;
sim_debug(DEBUG_DETAIL, dptr, "r=%d\n\r", r);
sim_activate(uptr, 100);
}
return mt_error(uptr, chan, r, dptr);
} else {
uptr->u5 &= ~(MT_BOT|MT_EOT);
uptr->hwmark = reclen;
}
sim_debug(DEBUG_DETAIL, dptr, "%d chars\n\r", uptr->hwmark);
uptr->u6 = uptr->hwmark;
if ((uptr->u5 & MT_BIN) == 0)
mode = 0100;
else
mode = 0;
for (loc = 0; loc < reclen; loc++) {
ch = mt_buffer[chan][loc] & 0177;
if (((parity_table[ch & 077]) ^ (ch & 0100) ^ mode) == 0) {
chan_set_error(chan);
break;
}
}
}
ch = mt_buffer[chan][--uptr->u6] & 0177;
/* 00 characters are not transfered in BCD mode */
if (ch == 0) {
if (uptr->u6 <= 0) {
sim_activate(uptr, 4000);
return mt_error(uptr, chan, MTSE_OK, dptr);
} else {
sim_activate(uptr, HT);
return SCPE_OK;
}
}
if (chan_write_char(chan, &ch, (uptr->u6 > 0) ? 0 : 1)) {
sim_debug(DEBUG_DATA, dptr, "Read back unit=%d %d EOR\n\r",
unit, uptr->hwmark-uptr->u6);
sim_activate(uptr, 100);
return mt_error(uptr, chan, MTSE_OK, dptr);
} else {
sim_debug(DEBUG_DATA, dptr, "Read back data unit=%d %d %03o\n\r",
unit, uptr->u6, ch);
sim_activate(uptr, HT);
}
return SCPE_OK;
case MT_WR: /* Write */
/* Check if write protected */
if (uptr->u6 == 0 && sim_tape_wrp(uptr)) {
sim_activate(uptr, 100);
return mt_error(uptr, chan, MTSE_WRP, dptr);
}
if (chan_read_char(chan, &ch,
(uptr->u6 > BUFFSIZE) ? 1 : 0)) {
reclen = uptr->u6;
/* If no transfer, then either erase */
if (reclen == 0) {
sim_debug(DEBUG_DETAIL, dptr, "Erase\n\r");
r = MTSE_OK;
} else if ((reclen == 1) && (cmd & MT_BIN) == 0 &&
(mt_buffer[chan][0] == 017)) {
/* Check if write rtape mark */
sim_debug(DEBUG_DETAIL, dptr, "Write Mark unit=%d\n\r", unit);
r = sim_tape_wrtmk(uptr);
} else {
sim_debug(DEBUG_DETAIL, dptr,
"Write unit=%d Block %d %s chars\n\r", unit, reclen,
(uptr->u5 & MT_BIN)? "bin": "bcd");
r = sim_tape_wrrecf(uptr, &mt_buffer[chan][0], reclen);
}
uptr->u5 &= ~(MT_BOT|MT_EOT);
sim_activate(uptr, 4000);
return mt_error(uptr, chan, r, dptr); /* Record errors */
} else {
/* Copy data to buffer */
ch &= 077;
ch |= parity_table[ch];
if ((uptr->u5 & MT_BIN))
ch ^= 0100;
/* Don't write out even parity zeros */
if (ch != 0)
mt_buffer[chan][uptr->u6++] = ch;
sim_debug(DEBUG_DATA, dptr, "Write data unit=%d %d %03o\n\r",
unit, uptr->u6, ch);
uptr->hwmark = uptr->u6;
}
sim_activate(uptr, HT);
return SCPE_OK;
case MT_FSR: /* Space forward one record */
if (uptr->hwmark == -1) {
/* If at end of record, fill buffer */
sim_debug(DEBUG_DETAIL, dptr, "Space unit=%d ", unit);
if (sim_tape_eot(uptr)) {
uptr->u5 &= ~MT_BOT;
sim_debug(DEBUG_DETAIL, dptr, "EOT\r\n");
sim_activate(uptr, 4000);
return mt_error(uptr, chan, MTSE_EOM, dptr);
}
r = sim_tape_rdrecf(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE);
if (r != MTSE_OK) {
if (r == MTSE_TMK) {
sim_debug(DEBUG_DETAIL, dptr, "TM ");
reclen = 1;
chan_set_eof(chan);
} else {
sim_debug(DEBUG_DETAIL, dptr, "r=%d ", r);
reclen = 10;
}
}
uptr->u5 &= ~(MT_BOT|MT_EOT);
uptr->hwmark = reclen;
sim_debug(DEBUG_DETAIL, dptr, "%d chars\n\r", uptr->hwmark);
sim_activate(uptr, uptr->hwmark * HT);
return SCPE_OK;
}
sim_activate(uptr, 4000);
return mt_error(uptr, chan, MTSE_OK, dptr);
case MT_BSR: /* Backspace record */
if (uptr->hwmark == -1) {
/* If at end of record, fill buffer */
sim_debug(DEBUG_DETAIL, dptr, "backspace unit=%d ", unit);
if (sim_tape_bot(uptr)) {
sim_debug(DEBUG_DETAIL, dptr, "BOT\n\r");
sim_activate(uptr, 100);
return mt_error(uptr, chan, MTSE_BOT, dptr);
}
r = sim_tape_rdrecr(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE);
if (r != MTSE_OK) {
if (r == MTSE_TMK) {
sim_debug(DEBUG_DETAIL, dptr, "TM ");
reclen = 1;
chan_set_eof(chan);
} else {
reclen = 10;
sim_debug(DEBUG_DETAIL, dptr, "r=%d ", r);
}
}
uptr->u5 &= ~(MT_BOT|MT_EOT);
uptr->hwmark = reclen;
sim_debug(DEBUG_DETAIL, dptr, "%d chars\n\r", uptr->hwmark);
sim_activate(uptr, uptr->hwmark * HT);
return SCPE_OK;
}
sim_activate(uptr, 4000);
return mt_error(uptr, chan, MTSE_OK, dptr);
case MT_REW: /* Rewind */
sim_debug(DEBUG_DETAIL, dptr, "Rewind unit=%d pos=%d\n\r", unit,
uptr->pos);
uptr->u5 &= ~(MT_CMD | MT_BIN | MT_IDLE | MT_RDY);
uptr->u5 |= MT_BSY|MT_RDY;
iostatus &= ~(1 << (uptr - mt_unit));
sim_activate(uptr, (uptr->pos/100) + 100);
r = sim_tape_rewind(uptr);
uptr->u5 &= ~MT_EOT;
uptr->u5 |= MT_BOT;
chan_set_end(chan);
return r;
}
return mt_error(uptr, chan, r, dptr);
}
t_stat
mt_attach(UNIT * uptr, char *file)
{
t_stat r;
if ((r = sim_tape_attach(uptr, file)) != SCPE_OK)
return r;
uptr->u5 |= MT_LOADED|MT_BOT;
sim_activate(uptr, 50000);
return SCPE_OK;
}
t_stat
mt_detach(UNIT * uptr)
{
uptr->u5 = 0;
iostatus &= ~(1 << (uptr - mt_unit));
return sim_tape_detach(uptr);
}
t_stat
mt_reset(DEVICE *dptr)
{
int i;
/* Scan all devices and enable those that
are loaded. This is to allow tapes that
are mounted prior to boot to be recognized
at later. Also disconnect all devices no
longer connected. */
for ( i = 0; i < NUM_DEVS_MT; i++) {
mt_unit[i].dynflags = MT_DENS_556 << UNIT_V_DF_TAPE;
if ((mt_unit[i].flags & UNIT_ATT) == 0)
iostatus &= ~(1 << i);
else if (mt_unit[i].u5 & (MT_LOADED|MT_RDY)) {
iostatus |= 1 << i;
mt_unit[i].u5 &= ~(MT_LOADED);
mt_unit[i].u5 |= MT_RDY;
}
}
return SCPE_OK;
}
t_stat
mt_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "B422/B423 Magnetic tape unit\n\n");
fprintf (st, "The magnetic tape controller assumes that all tapes are 7 track\n");
fprintf (st, "with valid parity. Tapes are assumed to be 555.5 characters per\n");
fprintf (st, "inch. To simulate a standard 2400foot tape, do:\n");
fprintf (st, " sim> SET MTn LENGTH 15\n\n");
fprintf (st, "By default only 8 drives are enabled, additional units up to 15 supported.\n");
fprint_set_help(st, dptr);
fprint_show_help(st, dptr);
return SCPE_OK;
}
const char *
mt_description(DEVICE *dptr)
{
return "B422/B423 Magnetic tape unit";
}
#endif

541
B5500/b5500_sys.c Normal file
View file

@ -0,0 +1,541 @@
/* b5500_sys.c: Burroughs 5500 Simulator system interface.
Copyright (c) 2016, Richard Cornwell
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
RICHARD CORNWELL 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.
*/
#include "sim_defs.h"
#include "b5500_defs.h"
#include "sim_card.h"
#include <ctype.h>
t_stat parse_sym(char *cptr, t_addr addr, UNIT * uptr, t_value * val, int32 sw);
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "B5500";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 1;
DEVICE *sim_devices[] = {
&cpu_dev,
&chan_dev,
#if NUM_DEVS_CDR > 0
&cdr_dev,
#endif
#if NUM_DEVS_CDP > 0
&cdp_dev,
#endif
#if NUM_DEVS_LPR > 0
&lpr_dev,
#endif
#if NUM_DEVS_CON > 0
&con_dev,
#endif
#if NUM_DEVS_MT > 0
&mt_dev,
#endif
#if NUM_DEVS_DR > 0
&drm_dev,
#endif
#if NUM_DEVS_DSK > 0
&esu_dev,
&dsk_dev,
#endif
#if NUM_DEVS_DTC > 0
&dtc_dev,
#endif
NULL
};
/* Simulator stop codes */
const char *sim_stop_messages[] = {
0,
};
/* Simulator debug controls */
DEBTAB dev_debug[] = {
{"CMD", DEBUG_CMD, "Show command execution to devices"},
{"DATA", DEBUG_DATA, "Show data transfers"},
{"DETAIL", DEBUG_DETAIL, "Show details about device"},
{"EXP", DEBUG_EXP, "Show exception information"},
{0, 0}
};
uint8 parity_table[64] = {
/* 0 1 2 3 4 5 6 7 */
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000
};
uint8 mem_to_ascii[64] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 */
'0', '1', '2', '3', '4', '5', '6', '7', /* 0x */
'8', '9', '#', '@', '?', ':', '>', '}', /* 1x */
'+', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 2x */
'H', 'I', '.', '[', '&', '(', '<', '~', /* 3x */
'|', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 4x */
'Q', 'R', '$', '*', '-', ')', ';', '{', /* 5x */
' ', '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 6x */
'Y', 'Z', ',', '%', '!', '=', ']', '"' /* 7x */
};
const char con_to_ascii[64] = {
'?', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '0', '#', '@', ':', '>', '}', /* 17 = box */
' ', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '!', ',', '%', '=', ']', '"',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '|', '$', '*', ')', ';', '{', /* 57 = triangle */
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '+', '.', '[', '(', '<', '~', /* 37 = stop code */
}; /* 72 = rec mark */
/* 75 = squiggle, 77 = del */
const char ascii_to_con[128] = {
/* Control */
-1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 37 */
/* Control */
-1, -1, -1, -1, -1, -1, -1, -1,
/* Control */
-1, -1, -1, -1, -1, -1, -1, -1,
/* Control */
-1, -1, -1, -1, -1, -1, -1, -1,
/*sp ! " # $ % & ' */
020, 032, 037, 013, 053, 017, 060, 014, /* 40 - 77 */
/* ( ) * + , - . / */
075, 055, 054, 072, 033, 040, 073, 021,
/* 0 1 2 3 4 5 6 7 */
012, 001, 002, 003, 004, 005, 006, 007,
/* 8 9 : ; < = > ? */
010, 011, 015, 056, 076, 035, 016, 000,
/* @ A B C D E F G */
014, 061, 062, 063, 064, 065, 066, 067, /* 100 - 137 */
/* H I J K L M N O */
070, 071, 041, 042, 043, 044, 045, 046,
/* P Q R S T U V W */
047, 050, 051, 022, 023, 024, 025, 026,
/* X Y Z [ \ ] ^ _ */
027, 030, 031, 075, 036, 055, 057, 000,
/* ` a b c d e f g */
035, 061, 062, 063, 064, 065, 066, 067, /* 140 - 177 */
/* h i j k l m n o */
070, 071, 041, 042, 043, 044, 045, 046,
/* p q r s t u v w */
047, 050, 051, 022, 023, 024, 025, 026,
/* x y z { | } ~ del*/
027, 030, 031, 057, 077, 017, -1, -1
};
/* Load a card image file into memory. */
t_stat
sim_load(FILE * fileref, char *cptr, char *fnam, int flag)
{
/* Currently not implimented until I know format of load files */
return SCPE_NOFNC;
}
#define TYPE_A 1 /* Full 12 bit opcode */
#define TYPE_B 2 /* 6 Bit Opcode with 6 bit field */
#define TYPE_C 3 /* 8 Bit opcode with 4 bit field */
#define TYPE_D 4 /* 2 bit opcode, 10 bit field */
/* Opcodes */
t_opcode word_ops[] = {
/* Word mode opcodes */
WMOP_LITC, TYPE_D, "LITC", /* Load literal */
WMOP_OPDC, TYPE_D, "OPDC", /* Load operand */
WMOP_DESC, TYPE_D, "DESC", /* Load Descriptor */
WMOP_DEL, TYPE_A, "DEL", /* Delete top of stack */
WMOP_NOP, TYPE_A, "NOP", /* Nop operation */
WMOP_XRT, TYPE_A, "XRT", /* Set Variant */
WMOP_ADD, TYPE_A, "ADD", /* Add */
WMOP_DLA, TYPE_A, "DLA", /* Double Precision Add */
WMOP_PRL, TYPE_A, "PRL", /* Program Release */
WMOP_LNG, TYPE_A, "LNG", /* Logical Negate */
WMOP_CID, TYPE_A, "CID", /* Conditional Integer Store Destructive */
WMOP_GEQ, TYPE_A, "GEQ", /* B greater than or equal to A */
WMOP_BBC, TYPE_A, "BBC", /* Branch Backward Conditional */
WMOP_BRT, TYPE_A, "BRT", /* Branch Return */
WMOP_INX, TYPE_A, "INX", /* Index */
WMOP_ITI, TYPE_A, "ITI", /* Interrogate interrupt */
WMOP_LOR, TYPE_A, "LOR", /* Logical Or */
WMOP_CIN, TYPE_A, "CIN", /* Conditional Integer Store non-destructive */
WMOP_GTR, TYPE_A, "GTR", /* B Greater than A */
WMOP_BFC, TYPE_A, "BFC", /* Branch Forward Conditional */
WMOP_RTN, TYPE_A, "RTN", /* Return normal */
WMOP_COC, TYPE_A, "COC", /* Construct Operand Call */
WMOP_SUB, TYPE_A, "SUB", /* Subtract */
WMOP_DLS, TYPE_A, "DLS", /* Double Precision Subtract */
WMOP_MUL, TYPE_A, "MUL", /* Multiply */
WMOP_DLM, TYPE_A, "DLM", /* Double Precision Multiply */
WMOP_RTR, TYPE_A, "RTR", /* Read Timer */
WMOP_LND, TYPE_A, "LND", /* Logical And */
WMOP_STD, TYPE_A, "STD", /* B Store Destructive */
WMOP_NEQ, TYPE_A, "NEQ", /* B Not equal to A */
WMOP_SSN, TYPE_A, "SSN", /* Set Sign Bit */
WMOP_XIT, TYPE_A, "XIT", /* Exit */
WMOP_MKS, TYPE_A, "MKS", /* Mark Stack */
WMOP_DIV, TYPE_A, "DIV", /* Divide */
WMOP_DLD, TYPE_A, "DLD", /* Double Precision Divide */
WMOP_COM, TYPE_A, "COM", /* Communication operator */
WMOP_LQV, TYPE_A, "LQV", /* Logical Equivalence */
WMOP_SND, TYPE_A, "SND", /* B Store Non-destructive */
WMOP_XCH, TYPE_A, "XCH", /* Exchange */
WMOP_CHS, TYPE_A, "CHS", /* Change sign bit */
WMOP_RTS, TYPE_A, "RTS", /* Return Special */
WMOP_CDC, TYPE_A, "CDC", /* Construct descriptor call */
WMOP_FTC, TYPE_A, "FTC", /* Transfer F Field to Core Field */
WMOP_MOP, TYPE_A, "MOP", /* Reset Flag bit */
WMOP_LOD, TYPE_A, "LOD", /* Load */
WMOP_DUP, TYPE_A, "DUP", /* Duplicate */
WMOP_TOP, TYPE_A, "TOP", /* Test Flag Bit */
WMOP_IOR, TYPE_A, "IOR", /* I/O Release */
WMOP_LBC, TYPE_A, "LBC", /* Word Branch Backward Conditional */
WMOP_SSF, TYPE_A, "SSF", /* Set or Store S or F registers */
WMOP_HP2, TYPE_A, "HP2", /* Halt P2 */
WMOP_LFC, TYPE_A, "LFC", /* Word Branch Forward Conditional */
WMOP_ZP1, TYPE_A, "ZP1", /* Conditional Halt */
WMOP_TUS, TYPE_A, "TUS", /* Interrogate Peripheral Status */
WMOP_LLL, TYPE_A, "LLL", /* Link List Look-up */
WMOP_IDV, TYPE_A, "IDV", /* Integer Divide Integer */
WMOP_SFI, TYPE_A, "SFI", /* Store for Interrupt */
WMOP_SFT, TYPE_A, "SFT", /* Store for Test */
WMOP_FTF, TYPE_A, "FTF", /* Transfer F Field to F Field */
WMOP_MDS, TYPE_A, "MDS", /* Set Flag Bit */
WMOP_IP1, TYPE_A, "IP1", /* Initiate P1 */
WMOP_ISD, TYPE_A, "ISD", /* Interger Store Destructive */
WMOP_LEQ, TYPE_A, "LEQ", /* B Less Than or Equal to A */
WMOP_BBW, TYPE_A, "BBW", /* Banch Backward Conditional */
WMOP_IP2, TYPE_A, "IP2", /* Initiate P2 */
WMOP_ISN, TYPE_A, "ISN", /* Integer Store Non-Destructive */
WMOP_LSS, TYPE_A, "LSS", /* B Less Than A */
WMOP_BFW, TYPE_A, "BFW", /* Branch Forward Unconditional */
WMOP_IIO, TYPE_A, "IIO", /* Initiate I/O */
WMOP_EQL, TYPE_A, "EQL", /* B Equal A */
WMOP_SSP, TYPE_A, "SSP", /* Reset Sign Bit */
WMOP_CMN, TYPE_A, "CMN", /* Enter Character Mode In Line */
WMOP_IFT, TYPE_A, "IFT", /* Test Initiate */
WMOP_CTC, TYPE_A, "CTC", /* Transfer Core Field to Core Field */
WMOP_LBU, TYPE_A, "LBU", /* Word Branch Backward Unconditional */
WMOP_LFU, TYPE_A, "LFU", /* Word Branch Forward Unconditional */
WMOP_TIO, TYPE_A, "TIO", /* Interrogate I/O Channels */
WMOP_RDV, TYPE_A, "RDV", /* Remainder Divide */
WMOP_FBS, TYPE_A, "FBS", /* Flag Bit Search */
WMOP_CTF, TYPE_A, "CTF", /* Transfer Core Field to F Field */
WMOP_ISO, TYPE_B, "ISO", /* Variable Field Isolate XX */
WMOP_CBD, TYPE_C, "CBD", /* Non-Zero Field Branch Backward Destructive Xy */
WMOP_CBN, TYPE_C, "CBN", /* Non-Zero Field Branch Backward Non-Destructive Xy */
WMOP_CFD, TYPE_C, "CFD", /* Non-Zero Field Branch Forward Destructive Xy */
WMOP_CFN, TYPE_B, "CFN", /* Non-Zero Field Branch Forward Non-Destructive Xy */
WMOP_DIA, TYPE_B, "DIA", /* Dial A XX */
WMOP_DIB, TYPE_B, "DIB", /* Dial B XX Upper 6 not Zero */
WMOP_TRB, TYPE_B, "TRB", /* Transfer Bits XX */
WMOP_FCL, TYPE_B, "FCL", /* Compare Field Low XX */
WMOP_FCE, TYPE_B, "FCE", /* Compare Field Equal XX */
{0, 0, NULL},
};
t_opcode char_ops[] = {
/* Character Mode */
CMOP_EXC, TYPE_A, "EXC", /* Exit Character Mode */
CMOP_CMX, TYPE_A, "CMX", /* Exit Character Mode In Line */
CMOP_BSD, TYPE_B, "BSD", /* Skip Bit Destiniation */
CMOP_BSS, TYPE_B, "BSS", /* SKip Bit Source */
CMOP_RDA, TYPE_B, "RDA", /* Recall Destination Address */
CMOP_TRW, TYPE_B, "TRW", /* Transfer Words */
CMOP_SED, TYPE_B, "SED", /* Set Destination Address */
CMOP_TDA, TYPE_B, "TDA", /* Transfer Destination Address */
CMOP_TBN, TYPE_B, "TBN", /* Transfer Blanks for Non-Numerics */
WMOP_ITI, TYPE_A, "ITI", /* Interrogate interrupt */
WMOP_SFI, TYPE_A, "SFI", /* Store for Interrupt */
WMOP_SFT, TYPE_A, "SFT", /* Store for Test */
WMOP_ZP1, TYPE_A, "ZP1", /* Conditional Halt */
WMOP_HP2, TYPE_A, "HP2", /* Halt P2 */
CMOP_SDA, TYPE_B, "SDA", /* Store Destination Address */
CMOP_SSA, TYPE_B, "SSA", /* Store Source Address */
CMOP_SFD, TYPE_B, "SFD", /* Skip Forward Destination */
CMOP_SRD, TYPE_B, "SRD", /* Skip Reverse Destination */
CMOP_SES, TYPE_B, "SES", /* Set Source Address */
CMOP_TEQ, TYPE_B, "TEQ", /* Test for Equal */
CMOP_TNE, TYPE_B, "TNE", /* Test for Not-Equal */
CMOP_TEG, TYPE_B, "TEG", /* Test for Greater Or Equal */
CMOP_TGR, TYPE_B, "TGR", /* Test For Greater */
CMOP_SRS, TYPE_B, "SRS", /* Skip Reverse Source */
CMOP_SFS, TYPE_B, "SFS", /* Skip Forward Source */
CMOP_TEL, TYPE_B, "TEL", /* Test For Equal or Less */
CMOP_TLS, TYPE_B, "TLS", /* Test For Less */
CMOP_TAN, TYPE_B, "TAN", /* Test for Alphanumeric */
CMOP_BIT, TYPE_B, "BIT", /* Test Bit */
CMOP_INC, TYPE_B, "INC", /* Increase Tally */
CMOP_STC, TYPE_B, "STC", /* Store Tally */
CMOP_SEC, TYPE_B, "SEC", /* Set Tally */
CMOP_CRF, TYPE_B, "CRF", /* Call repeat Field */
CMOP_JNC, TYPE_B, "JNC", /* Jump Out Of Loop Conditional */
CMOP_JFC, TYPE_B, "JFC", /* Jump Forward Conditional */
CMOP_JNS, TYPE_B, "JNS", /* Jump out of loop unconditional */
CMOP_JFW, TYPE_B, "JFW", /* Jump Forward Unconditional */
CMOP_RCA, TYPE_B, "RCA", /* Recall Control Address */
CMOP_ENS, TYPE_B, "ENS", /* End Loop */
CMOP_BNS, TYPE_B, "BNS", /* Begin Loop */
CMOP_RSA, TYPE_B, "RSA", /* Recall Source Address */
CMOP_SCA, TYPE_B, "SCA", /* Store Control Address */
CMOP_JRC, TYPE_B, "JRC", /* Jump Reverse Conditional */
CMOP_TSA, TYPE_B, "TSA", /* Transfer Source Address */
CMOP_JRV, TYPE_B, "JRV", /* Jump Reverse Unconditional */
CMOP_CEQ, TYPE_B, "CEQ", /* Compare Equal */
CMOP_CNE, TYPE_B, "CNE", /* COmpare for Not Equal */
CMOP_CEG, TYPE_B, "CEG", /* Compare For Greater Or Equal */
CMOP_CGR, TYPE_B, "CGR", /* Compare For Greater */
CMOP_BIS, TYPE_B, "BIS", /* Set Bit */
CMOP_BIR, TYPE_B, "BIR", /* Reet Bit */
CMOP_OCV, TYPE_B, "OCV", /* Output Convert */
CMOP_ICV, TYPE_B, "ICV", /* Input Convert */
CMOP_CEL, TYPE_B, "CEL", /* Compare For Equal or Less */
CMOP_CLS, TYPE_B, "CLS", /* Compare for Less */
CMOP_FSU, TYPE_B, "FSU", /* Field Subtract */
CMOP_FAD, TYPE_B, "FAD", /* Field Add */
CMOP_TRP, TYPE_B, "TRP", /* Transfer Program Characters */
CMOP_TRN, TYPE_B, "TRN", /* Transfer Numeric */
CMOP_TRZ, TYPE_B, "TRZ", /* Transfer Zones */
CMOP_TRS, TYPE_B, "TRS", /* Transfer Source Characters */
{0, 0, NULL},
};
/* Print out an instruction */
void
print_opcode(FILE * of, t_value val, t_opcode * tab)
{
uint16 op;
op = val;
while (tab->name != NULL) {
switch(tab->type) {
case TYPE_A:
if (op != tab->op)
break;
fputs(tab->name, of);
fputs(" ",of);
return;
case TYPE_B:
if ((op & 077) != tab->op)
break;
fputs(tab->name, of);
fputc(' ',of);
fputc(' ',of);
fprint_val(of, (val >> 6), 8, 6, 0);
fputs(" ",of);
return;
case TYPE_C:
if ((op & 0377) != tab->op)
break;
fputs(tab->name, of);
fputc(' ',of);
fprint_val(of, (val >> 8), 8, 4, 0);
fputs(" ",of);
return;
case TYPE_D:
if ((op & 03) != tab->op)
break;
fputs(tab->name, of);
fputc(' ',of);
fprint_val(of, (val >> 2), 8, 10, 0);
fputc(' ',of);
return;
}
tab++;
}
fprintf(of, "*%04o uuo ", op);
}
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
Outputs:
return = status code
*/
t_stat
fprint_sym(FILE * of, t_addr addr, t_value * val, UNIT * uptr, int32 sw)
{
t_value inst = *val;
int i;
fputc(' ', of);
fprint_val(of, inst, 8, 48, PV_RZRO);
if (sw & SWMASK('W')) { /* Word mode opcodes */
fputs(" ", of);
for (i = 36; i >= 0; i-=12) {
int op = (int)(inst >> i) & 07777;
print_opcode(of, op, word_ops);
}
}
if (sw & SWMASK('C')) { /* Char mode opcodes */
fputs(" ", of);
for (i = 36; i >= 0; i-=12) {
int op = (int)(inst >> i) & 07777;
print_opcode(of, op, char_ops);
}
}
if (sw & SWMASK('B')) { /* BCD mode */
fputs(" '", of);
for (i = 42; i >= 0; i-=6) {
int ch;
ch = (int)(inst >> i) & 077;
fputc(mem_to_ascii[ch], of);
}
fputc('\'', of);
}
if (sw & SWMASK('F')) { /* Floating point/Descriptor */
}
return SCPE_OK;
}
t_opcode *
find_opcode(char *op, t_opcode * tab)
{
while (tab->name != NULL) {
if (*tab->name != '\0' && strcmp(op, tab->name) == 0)
return tab;
tab++;
}
return NULL;
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
*/
t_stat
parse_sym(char *cptr, t_addr addr, UNIT * uptr, t_value * val, int32 sw)
{
int i;
t_value d;
int opr;
char opcode[100];
while (isspace(*cptr))
cptr++;
d = 0;
if (sw & (SWMASK('W')|SWMASK('C'))) {
t_opcode *op;
/* Grab opcode */
cptr = get_glyph(cptr, opcode, 0);
op = 0;
opr = -1;
if((op = find_opcode(opcode,
(SWMASK('W') ? word_ops : char_ops))) == 0) {
return SCPE_UNK;
}
while (*cptr == ' ' || *cptr == '\t')
cptr++;
/* Collect first argument if there is one */
while (*cptr >= '0' && *cptr <= '7')
opr = (opr << 3) + (*cptr++ - '0');
/* Skip blanks */
while (*cptr == ' ' || *cptr == '\t')
cptr++;
switch (op->type) {
case TYPE_A:
if (opr >= 0)
return SCPE_2MARG;
*val = op->op;
return SCPE_OK;
case TYPE_B:
if (opr < 0 || opr > 64)
return SCPE_ARG;
*val = (opr << 6) | op->op;
return SCPE_OK;
case TYPE_C:
if (opr < 0 || opr > 16)
return SCPE_ARG;
*val = (opr << 8) | op->op;
return SCPE_OK;
case TYPE_D:
if (opr < 0 || opr > 1024)
return SCPE_ARG;
*val = (opr << 2) | op->op;
return SCPE_OK;
}
} else if (sw & SWMASK('B')) {
i = 0;
while (*cptr != '\0' && i < 8) {
d <<= 6;
d |= (int)sim_ascii_to_six[0177 & *cptr];
cptr++;
i++;
}
d <<= 6 * (8 - i);
} else {
while (*cptr >= '0' && *cptr <= '7') {
d <<= 3;
d |= *cptr++ - '0';
}
}
*val = d;
return SCPE_OK;
/* Symbolic input, continued */
if (*cptr != 0)
return SCPE_ARG; /* junk at end? */
return SCPE_OK;
}

1007
B5500/b5500_urec.c Normal file

File diff suppressed because it is too large Load diff

1050
B5500/sim_card.c Normal file

File diff suppressed because it is too large Load diff

113
B5500/sim_card.h Normal file
View file

@ -0,0 +1,113 @@
/* Card read/punch routines for 7000 simulators.
Copyright (c) 2005, Richard Cornwell
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.
This is the standard card reader.
This is the standard card punch.
Input formats are accepted in a variaty of formats:
Standard ASCII: one record per line.
returns are ignored.
tabs are expanded to modules 8 characters.
~ in first column is treated as a EOF.
Binary Card format:
Each record 160 characters.
First character 21012345
111
Second characters 6789----
Top 4 bits of second character are 0.
It is unlikely that ascii text or BCD format
text could produce similar profile.
BCD Format:
Each record variable length (80 chars or less).
Record mark has bit 7 set.
Bit 6 is even parity.
Bits 5-0 are character.
CBN Format:
Each record 160 charaters.
First char has bit 7 set. Rest set to 0.
Bit 6 is odd parity.
Bit 5-0 of first character are top 6 bits
of card.
Bit 5-0 of second character are lower 6 bits
of card.
For autodetection of BCD card format, there can be no parity errors.
All undeterminate formats are treated as ASCII.
Auto output format is ASCII if card has only printable characters
or card format binary.
*/
#define DEBUG_CARD 0x0000010 /* Show details */
/* Flags for punch and reader. */
#define UNIT_V_MODE (UNIT_V_UF + 0)
#define UNIT_MODE (7 << UNIT_V_MODE)
#define MODE_AUTO (0 << UNIT_V_MODE)
#define MODE_BIN (1 << UNIT_V_MODE)
#define MODE_TEXT (2 << UNIT_V_MODE)
#define MODE_BCD (3 << UNIT_V_MODE)
#define MODE_CBN (4 << UNIT_V_MODE)
/* Allow lower case letters */
#define MODE_LOWER (8 << UNIT_V_MODE)
#define MODE_026 (0x10 << UNIT_V_MODE)
#define MODE_029 (0x20 << UNIT_V_MODE)
#define MODE_EBCDIC (0x30 << UNIT_V_MODE)
#define MODE_CHAR (0x30 << UNIT_V_MODE)
struct _card_data
{
int ptr; /* Pointer in buffer */
int len; /* Length of buffer */
char cbuff[1024]; /* Read in buffer for cards */
uint16 image[80]; /* Image */
uint8 hol_to_ascii[4096]; /* Back conversion table */
};
/* Generic routines. */
t_stat sim_read_card(UNIT * uptr);
int sim_card_eof(UNIT * uptr);
t_stat sim_punch_card(UNIT * uptr, UNIT *stkptr);
t_stat sim_card_attach(UNIT * uptr, char *file);
t_stat sim_card_detach(UNIT *uptr);
/* Conversion routines to save code */
uint16 sim_bcd_to_hol(uint8 bcd);
uint16 sim_ebcdic_to_hol(uint8 ebcdic);
uint8 sim_hol_to_bcd(uint16 hol);
uint8 sim_hol_to_ebbcd(uint16 hol);
/* Format control routines. */
t_stat sim_card_set_fmt (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat sim_card_show_fmt (FILE *st, UNIT *uptr, int32 val, void *desc);
/* Help information */
t_stat sim_card_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
/* Translation tables */
const char sim_six_to_ascii[64];
const char sim_ascii_to_six[128];
const uint8 sim_parity_table[64];