mirror of
https://github.com/rcornwell/sims.git
synced 2026-01-16 08:23:21 +00:00
IBM360: Initial commit
This commit is contained in:
parent
39ee29e66a
commit
eb4320e2e4
68
IBM360/Makefile
Normal file
68
IBM360/Makefile
Normal file
@ -0,0 +1,68 @@
|
||||
# CC Command
|
||||
#
|
||||
# Note: -O2 is sometimes broken in GCC when setjump/longjump is being
|
||||
# used. Try -O2 only with released simulators.
|
||||
#
|
||||
#ifeq ($(WIN32),)
|
||||
#Unix Environments
|
||||
#ifeq ($(OSTYPE),solaris)
|
||||
#OS_CCDEFS = -lsocket -lnsl -lpthread -D_GNU_SOURCE
|
||||
#else
|
||||
#OS_CCDEFS = -D_GNU_SOURCE -I .
|
||||
#endif
|
||||
#CC = gcc -std=c99 -O2 -U__STRICT_ANSI__ -g -lm $(OS_CCDEFS) -I .
|
||||
#ifeq ($(USE_NETWORK),)
|
||||
#else
|
||||
#NETWORK_OPT = -DUSE_NETWORK -isystem /usr/local/include /usr/local/lib/libpcap.a
|
||||
#endif
|
||||
#else
|
||||
##Win32 Environments
|
||||
LDFLAGS = -lm -lwsock32
|
||||
#CC = gcc -std=c99 -U__STRICT_ANSI__ -O0 -I.
|
||||
#EXE = .exe
|
||||
#ifeq ($(USE_NETWORK),)
|
||||
#else
|
||||
#NETWORK_OPT = -DUSE_NETWORK -lwpcap -lpacket
|
||||
#endif
|
||||
#endif
|
||||
CC=gcc -g -std=c99 -U__STRICT_ANSI__ -D_GNU_SOURCE -I. -DUSE_SIM_CARD
|
||||
LDFLAGS = -lm -lrt
|
||||
|
||||
|
||||
#
|
||||
# Common Libraries
|
||||
#
|
||||
BIN = ./
|
||||
SIM = ../scp.c ../sim_console.c ../sim_fio.c ../sim_timer.c ../sim_tape.c \
|
||||
../sim_sock.c ../sim_tmxr.c ../sim_ether.c ../sim_video.c ../sim_serial.c \
|
||||
../sim_disk.c ../sim_card.c
|
||||
|
||||
|
||||
#
|
||||
# Emulator source files and compile time options
|
||||
#
|
||||
IBM360D = ./
|
||||
IBM360 = ${IBM360D}ibm360_cpu.c ${IBM360D}ibm360_sys.c ${IBM360D}ibm360_con.c \
|
||||
${IBM360D}ibm360_chan.c ${IBM360D}ibm360_cdr.c ${IBM360D}ibm360_cdp.c \
|
||||
${IBM360D}ibm360_mt.c ${IBM360D}ibm360_lpr.c ${IBM360D}ibm360_dasd.c \
|
||||
${IBM360D}ibm360_com.c
|
||||
IBM360_OPT = -I.. -DIBM360
|
||||
|
||||
#
|
||||
# Build everything
|
||||
#
|
||||
all : ${BIN}ibm360${EXE}
|
||||
|
||||
clean :
|
||||
ifeq ($(WIN32),)
|
||||
${RM} ${ALL}
|
||||
else
|
||||
if exist BIN\*.exe del /q BIN\*.exe
|
||||
endif
|
||||
#
|
||||
# Individual builds
|
||||
#
|
||||
${BIN}ibm360${EXE} : ${IBM360} ${SIM}
|
||||
${CC} ${IBM360} ${SIM} ${IBM360_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
40
IBM360/STATUS.txt
Normal file
40
IBM360/STATUS.txt
Normal file
@ -0,0 +1,40 @@
|
||||
Current status:
|
||||
|
||||
Operating Systems:
|
||||
TOS/360: Will IPL, and read IPL deck. Will not run any test jobs.
|
||||
|
||||
DOS/360: Will IPL disk init job.
|
||||
|
||||
OS/360: Will IPL disk init job.
|
||||
|
||||
ibm360_cpu.c:
|
||||
Need to complete floating point and decimal instructions.
|
||||
|
||||
ibm360_chan.c
|
||||
Need to move fprintf's to sim_debug functions.
|
||||
Add number of Channels and subchannels as option.
|
||||
|
||||
ibm360_cdp.c:
|
||||
Add support for binary mode.
|
||||
|
||||
ibm360_cdr.c:
|
||||
Add support for binary mode.
|
||||
|
||||
ibm360_com.c:
|
||||
Not implemented.
|
||||
|
||||
ibm360_con.c:
|
||||
Appears to be working.
|
||||
|
||||
ibm360_dasd.c:
|
||||
Need to complete.
|
||||
|
||||
ibm360_lpr.c:
|
||||
Need to add in support for line skip and skip control.
|
||||
|
||||
ibm360_mt.c:
|
||||
Appears to be working.
|
||||
|
||||
ibm360_sys.c:
|
||||
Need to add in deposit function.
|
||||
|
||||
229
IBM360/ibm360_cdp.c
Normal file
229
IBM360/ibm360_cdp.c
Normal file
@ -0,0 +1,229 @@
|
||||
/* ibm360_urec.c: IBM 360 Unit record devices.
|
||||
|
||||
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.
|
||||
|
||||
This is the standard card reader.
|
||||
This is the standard card punch.
|
||||
This is the standard line printer.
|
||||
This is the standard inquiry or console interface.
|
||||
|
||||
These units each buffer one record in local memory and signal
|
||||
ready when the buffer is full or empty. The channel must be
|
||||
ready to recieve/transmit data when they are activated since
|
||||
they will transfer their block during chan_cmd. All data is
|
||||
transmitted as BCD characters.
|
||||
|
||||
*/
|
||||
|
||||
#include "ibm360_defs.h"
|
||||
#include "sim_defs.h"
|
||||
#include "sim_card.h"
|
||||
|
||||
#ifdef NUM_DEVS_CDP
|
||||
#define UNIT_CDP UNIT_ATTABLE | UNIT_DISABLE
|
||||
|
||||
|
||||
#define CHN_SNS 0x04 /* Sense command */
|
||||
|
||||
/* Device status information stored in u3 */
|
||||
#define CDR_RD 0x02 /* Read command */
|
||||
#define CDR_FEED 0x03 /* Feed next card */
|
||||
#define CDP_CMDMSK 0x27 /* Mask command part. */
|
||||
#define CDR_MODE 0x20 /* Mode operation */
|
||||
#define CDR_STKMSK 0xC0 /* Mask for stacker */
|
||||
#define CDP_WR 0x09 /* Punch command */
|
||||
#define CDP_CARD 0x80 /* Unit has card in buffer */
|
||||
|
||||
|
||||
/* in u5 packs sense byte 0,1 and 3 */
|
||||
/* Sense byte 0 */
|
||||
#define SNS_CMDREJ 0x80 /* Command reject */
|
||||
#define SNS_INTVENT 0x40 /* Unit intervention required */
|
||||
#define SNS_BUSCHK 0x20 /* Parity error on bus */
|
||||
#define SNS_EQUCHK 0x10 /* Equipment check */
|
||||
#define SNS_DATCHK 0x08 /* Data Check */
|
||||
#define SNS_OVRRUN 0x04 /* Data overrun */
|
||||
#define SNS_SEQUENCE 0x02 /* Unusual sequence */
|
||||
#define SNS_CHN9 0x01 /* Channel 9 on printer */
|
||||
|
||||
|
||||
|
||||
/* std devices. data structures
|
||||
|
||||
cdp_dev Card Punch device descriptor
|
||||
cdp_unit Card Punch unit descriptor
|
||||
cdp_reg Card Punch register list
|
||||
cdp_mod Card Punch modifiers list
|
||||
*/
|
||||
|
||||
uint8 cdp_startcmd(UNIT *, uint16, uint8);
|
||||
void cdp_ini(UNIT *, t_bool);
|
||||
t_stat cdp_srv(UNIT *);
|
||||
t_stat cdp_reset(DEVICE *);
|
||||
t_stat cdp_attach(UNIT *, CONST char *);
|
||||
t_stat cdp_detach(UNIT *);
|
||||
|
||||
UNIT cdp_unit[] = {
|
||||
{UDATA(cdp_srv, UNIT_CDP, 0), 600, UNIT_ADDR(0x00D) }, /* A */
|
||||
#if NUM_DEVS_CDP > 1
|
||||
{UDATA(cdp_srv, UNIT_CDP, 0), 600, UNIT_ADDR(0x01D)}, /* A */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
MTAB cdp_mod[] = {
|
||||
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||
&sim_card_set_fmt, &sim_card_show_fmt, NULL},
|
||||
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr,
|
||||
&show_dev_addr, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct dib cdp_dib = { 0xFF, 1, NULL, cdp_startcmd, NULL, cdp_unit, NULL};
|
||||
|
||||
DEVICE cdp_dev = {
|
||||
"CDP", cdp_unit, NULL, cdp_mod,
|
||||
NUM_DEVS_CDP, 8, 15, 1, 8, 8,
|
||||
NULL, NULL, NULL, NULL, &cdp_attach, &cdp_detach,
|
||||
&cdp_dib, DEV_UADDR | DEV_DISABLE | DEV_DEBUG, 0, crd_debug
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* Card punch routine
|
||||
|
||||
Modifiers have been checked by the caller
|
||||
C modifier is recognized (column binary is implemented)
|
||||
*/
|
||||
|
||||
|
||||
uint8 cdp_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
|
||||
|
||||
uint8 ch;
|
||||
|
||||
if ((uptr->u3 & (CDP_CARD|CDP_CMDMSK)) != 0) {
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
return SNS_BSY;
|
||||
return SNS_DEVEND|SNS_UNITCHK;
|
||||
}
|
||||
|
||||
switch (cmd & 0x7) {
|
||||
case 1: /* Write command */
|
||||
uptr->u3 &= ~(CDP_CMDMSK);
|
||||
uptr->u3 |= (cmd & CDP_CMDMSK);
|
||||
sim_activate(uptr, 1000); /* Start unit off */
|
||||
uptr->u4 = 0;
|
||||
uptr->u5 = 0;
|
||||
return 0;
|
||||
|
||||
case 3:
|
||||
if (cmd != 0x3) {
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
}
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
|
||||
case 0: /* Status */
|
||||
break;
|
||||
case 4: /* Sense */
|
||||
ch = uptr->u5;
|
||||
chan_write_byte(GET_UADDR(uptr->u3), &ch);
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
|
||||
default: /* invalid command */
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
break;
|
||||
}
|
||||
if (uptr->u5 & 0xff)
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
}
|
||||
|
||||
/* Handle transfer of data for card punch */
|
||||
t_stat
|
||||
cdp_srv(UNIT *uptr) {
|
||||
uint16 addr = GET_UADDR(uptr->u3);
|
||||
/* Waiting for disconnect */
|
||||
|
||||
if (uptr->u5 & CDP_CARD) {
|
||||
/* Done waiting, punch card */
|
||||
uptr->u5 &= ~CDP_CARD;
|
||||
switch(sim_punch_card(uptr, NULL)) {
|
||||
/* If we get here, something is wrong */
|
||||
case SCPE_IOERR:
|
||||
chan_end(addr, SNS_DEVEND|SNS_UNITCHK);
|
||||
default:
|
||||
chan_end(addr, SNS_DEVEND);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy next column over */
|
||||
if (uptr->u4 < 80) {
|
||||
struct _card_data *data;
|
||||
int u = uptr-cdp_unit;
|
||||
uint8 ch = 0;
|
||||
|
||||
data = (struct _card_data *)uptr->up7;
|
||||
|
||||
if (chan_read_byte(addr, &ch)) {
|
||||
uptr->u3 |= CDP_CARD;
|
||||
} else {
|
||||
sim_debug(DEBUG_DATA, &cdp_dev, "%d: Char < %02o\n", u, ch);
|
||||
data->image[uptr->u4++] = sim_ebcdic_to_hol(ch);
|
||||
if (uptr->u4 == 80) {
|
||||
uptr->u3 |= CDP_CARD;
|
||||
}
|
||||
}
|
||||
if (uptr->u3 & CDP_CARD) {
|
||||
uptr->u3 &= ~(CDP_CMDMSK);
|
||||
chan_end(addr, SNS_CHNEND);
|
||||
sim_activate(uptr, 1000);
|
||||
} else
|
||||
sim_activate(uptr, 10);
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cdp_ini(UNIT *uptr, t_bool f) {
|
||||
}
|
||||
|
||||
t_stat
|
||||
cdp_attach(UNIT * uptr, CONST char *file)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
if ((r = sim_card_attach(uptr, file)) != SCPE_OK)
|
||||
return r;
|
||||
uptr->u5 = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
cdp_detach(UNIT * uptr)
|
||||
{
|
||||
if (uptr->u5 & CDP_CARD)
|
||||
sim_punch_card(uptr, NULL);
|
||||
return sim_card_detach(uptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
252
IBM360/ibm360_cdr.c
Normal file
252
IBM360/ibm360_cdr.c
Normal file
@ -0,0 +1,252 @@
|
||||
/* ibm360_urec.c: IBM 360 Card Reader.
|
||||
|
||||
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.
|
||||
|
||||
This is the standard card reader.
|
||||
|
||||
These units each buffer one record in local memory and signal
|
||||
ready when the buffer is full or empty. The channel must be
|
||||
ready to recieve/transmit data when they are activated since
|
||||
they will transfer their block during chan_cmd. All data is
|
||||
transmitted as BCD characters.
|
||||
|
||||
*/
|
||||
|
||||
#include "ibm360_defs.h"
|
||||
#include "sim_defs.h"
|
||||
#include "sim_card.h"
|
||||
|
||||
#ifdef NUM_DEVS_CDR
|
||||
#define UNIT_CDR UNIT_ATTABLE | UNIT_RO | UNIT_DISABLE | UNIT_ROABLE | MODE_029
|
||||
|
||||
|
||||
#define CHN_SNS 0x04 /* Sense command */
|
||||
|
||||
/* Device status information stored in u3 */
|
||||
#define CDR_RD 0x02 /* Read command */
|
||||
#define CDR_FEED 0x03 /* Feed next card */
|
||||
#define CDR_CMDMSK 0x27 /* Mask command part. */
|
||||
#define CDR_MODE 0x20 /* Mode operation */
|
||||
#define CDR_STKMSK 0xC0 /* Mask for stacker */
|
||||
#define CDP_WR 0x09 /* Punch command */
|
||||
#define CDR_CARD 0x80 /* Unit has card in buffer */
|
||||
|
||||
|
||||
/* in u5 packs sense byte 0,1 and 3 */
|
||||
/* Sense byte 0 */
|
||||
#define SNS_CMDREJ 0x80 /* Command reject */
|
||||
#define SNS_INTVENT 0x40 /* Unit intervention required */
|
||||
#define SNS_BUSCHK 0x20 /* Parity error on bus */
|
||||
#define SNS_EQUCHK 0x10 /* Equipment check */
|
||||
#define SNS_DATCHK 0x08 /* Data Check */
|
||||
#define SNS_OVRRUN 0x04 /* Data overrun */
|
||||
#define SNS_SEQUENCE 0x02 /* Unusual sequence */
|
||||
#define SNS_CHN9 0x01 /* Channel 9 on printer */
|
||||
|
||||
|
||||
|
||||
/* std devices. data structures
|
||||
|
||||
cdr_dev Card Reader device descriptor
|
||||
cdr_unit Card Reader unit descriptor
|
||||
cdr_reg Card Reader register list
|
||||
cdr_mod Card Reader modifiers list
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
uint8 cdr_startcmd(UNIT *, uint16, uint8);
|
||||
t_stat cdr_boot(int32, DEVICE *);
|
||||
t_stat cdr_srv(UNIT *);
|
||||
t_stat cdr_reset(DEVICE *);
|
||||
t_stat cdr_attach(UNIT *, CONST char *);
|
||||
t_stat cdr_detach(UNIT *);
|
||||
|
||||
|
||||
|
||||
UNIT cdr_unit[] = {
|
||||
{UDATA(cdr_srv, UNIT_CDR, 0), 300, UNIT_ADDR(0x0C)}, /* A */
|
||||
#if NUM_DEVS_CDR > 1
|
||||
{UDATA(cdr_srv, UNIT_CDR, 0), 300, UNIT_ADDR(0x1C)}, /* B */
|
||||
#endif
|
||||
};
|
||||
|
||||
MTAB cdr_mod[] = {
|
||||
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||
&sim_card_set_fmt, &sim_card_show_fmt, NULL},
|
||||
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr,
|
||||
&show_dev_addr, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct dib cdr_dib = { 0xFF, 1, NULL, cdr_startcmd, NULL, cdr_unit};
|
||||
|
||||
DEVICE cdr_dev = {
|
||||
"CDR", cdr_unit, NULL, cdr_mod,
|
||||
NUM_DEVS_CDR, 8, 15, 1, 8, 8,
|
||||
NULL, NULL, NULL, &cdr_boot, &cdr_attach, &sim_card_detach,
|
||||
&cdr_dib, DEV_UADDR | DEV_DISABLE | DEV_DEBUG, 0, crd_debug
|
||||
};
|
||||
|
||||
|
||||
uint8 cdr_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
|
||||
DEVICE *dptr = find_dev_from_unit(uptr);
|
||||
int unit = (uptr - dptr->units);
|
||||
uint8 ch;
|
||||
|
||||
if ((uptr->u3 & CDR_CMDMSK) != 0) {
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
return SNS_BSY;
|
||||
return SNS_DEVEND;
|
||||
}
|
||||
|
||||
sim_debug(DEBUG_CMD, dptr, "CMD unit=%d %x", unit, cmd);
|
||||
switch (cmd & 0x7) {
|
||||
case 2: /* Read command */
|
||||
if ((cmd & 0xc0) != 0xc0)
|
||||
uptr->u3 &= ~CDR_CARD;
|
||||
uptr->u3 &= ~(CDR_CMDMSK);
|
||||
uptr->u3 |= (cmd & CDR_CMDMSK);
|
||||
sim_activate(uptr, 1000); /* Start unit off */
|
||||
uptr->u4 = 0;
|
||||
uptr->u5 = 0;
|
||||
return 0;
|
||||
|
||||
case 3: /* Control */
|
||||
uptr->u5 = 0;
|
||||
uptr->u3 &= ~(CDR_CMDMSK|CDR_CARD);
|
||||
if (cmd == 0x3)
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
if ((cmd & 0x30) != 0x20 || (cmd & 0xc0) == 0xc0) {
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
}
|
||||
uptr->u3 |= (cmd & CDR_CMDMSK);
|
||||
uptr->u4 = 0;
|
||||
sim_activate(uptr, 1000); /* Start unit off */
|
||||
return 0;
|
||||
|
||||
case 0: /* Status */
|
||||
break;
|
||||
|
||||
case 4: /* Sense */
|
||||
ch = uptr->u5;
|
||||
chan_write_byte(GET_UADDR(uptr->u3), &ch);
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
|
||||
default: /* invalid command */
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
break;
|
||||
}
|
||||
|
||||
if (uptr->u5)
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
}
|
||||
|
||||
/* Handle transfer of data for card reader */
|
||||
t_stat
|
||||
cdr_srv(UNIT *uptr) {
|
||||
int addr = GET_UADDR(uptr->u3);
|
||||
|
||||
/* Check if new card requested. */
|
||||
if ((uptr->u3 & CDR_CARD) == 0) {
|
||||
switch(sim_read_card(uptr)) {
|
||||
case SCPE_EOF:
|
||||
case SCPE_UNATT:
|
||||
chan_end(addr, SNS_DEVEND|SNS_UNITEXP);
|
||||
uptr->u5 = SNS_INTVENT;
|
||||
uptr->u3 &= ~CDR_CMDMSK;
|
||||
return SCPE_OK;
|
||||
case SCPE_IOERR:
|
||||
chan_end(addr, SNS_DEVEND|SNS_UNITCHK);
|
||||
uptr->u5 = SNS_INTVENT;
|
||||
uptr->u3 &= ~CDR_CMDMSK;
|
||||
return SCPE_OK;
|
||||
case SCPE_OK:
|
||||
uptr->u3 |= CDR_CARD;
|
||||
if ((uptr->u3 & CDR_CMDMSK) == CDR_FEED) {
|
||||
chan_end(addr, SNS_DEVEND);
|
||||
uptr->u3 &= ~(CDR_CMDMSK);
|
||||
return SCPE_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy next column over */
|
||||
if ((uptr->u3 & CDR_CMDMSK) == CDR_RD) {
|
||||
struct _card_data *data;
|
||||
int u = uptr-cdr_unit;
|
||||
uint8 ch = 0;
|
||||
|
||||
data = (struct _card_data *)uptr->up7;
|
||||
ch = sim_hol_to_ebcdic(data->image[uptr->u4]);
|
||||
|
||||
if (ch == 0x100) {
|
||||
uptr->u5 |= SNS_DATCHK;
|
||||
ch = 0x00;
|
||||
}
|
||||
if (chan_write_byte(addr, &ch)) {
|
||||
uptr->u3 &= ~(CDR_CMDMSK);
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND|(uptr->u5 ? SNS_UNITCHK:0));
|
||||
return SCPE_OK;
|
||||
} else {
|
||||
uptr->u4++;
|
||||
sim_debug(DEBUG_DATA, &cdr_dev, "%d: Char > %02o\n", u, ch);
|
||||
}
|
||||
if (uptr->u4 == 80) {
|
||||
uptr->u3 &= ~(CDR_CMDMSK);
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND|(uptr->u5 ? SNS_UNITCHK:0));
|
||||
}
|
||||
sim_activate(uptr, 10);
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Boot from given device */
|
||||
t_stat
|
||||
cdr_boot(int32 unit_num, DEVICE * dptr)
|
||||
{
|
||||
UNIT *uptr = &dptr->units[unit_num];
|
||||
t_stat r;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
return SCPE_UNATT; /* attached? */
|
||||
return chan_boot(GET_UADDR(uptr->u3), dptr);
|
||||
}
|
||||
|
||||
t_stat
|
||||
cdr_attach(UNIT * uptr, CONST char *file)
|
||||
{
|
||||
int addr = GET_UADDR(uptr->u3);
|
||||
t_stat r;
|
||||
|
||||
if ((r = sim_card_attach(uptr, file)) != SCPE_OK)
|
||||
return r;
|
||||
set_devattn(addr, SNS_DEVEND);
|
||||
uptr->u3 &= ~(CDR_CARD);
|
||||
uptr->u4 = 0;
|
||||
uptr->u6 = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
799
IBM360/ibm360_chan.c
Normal file
799
IBM360/ibm360_chan.c
Normal file
@ -0,0 +1,799 @@
|
||||
/* ibm360_chan.c: IBM 360 Channel functions.
|
||||
|
||||
Copyright (c) 2007, 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 "ibm360_defs.h"
|
||||
#include "sim_defs.h"
|
||||
|
||||
|
||||
#define CCMDMSK 0xff000000 /* Mask for command */
|
||||
#define CDADRMSK 0x00ffffff /* Mask for data address */
|
||||
#define CCNTMSK 0x0000ffff /* Mask for data count */
|
||||
#define CD 0x80000000 /* Chain data */
|
||||
#define CC 0x40000000 /* Chain command */
|
||||
#define SLI 0x20000000 /* Suppress length indication */
|
||||
#define SKIP 0x10000000 /* Skip flag */
|
||||
#define PCI 0x08000000 /* Program controlled interuption */
|
||||
|
||||
/* Command masks */
|
||||
#define CMD_TYPE 0x3 /* Type mask */
|
||||
#define CMD_CHAN 0x0 /* Channel command */
|
||||
#define CMD_WRITE 0x1 /* Write command */
|
||||
#define CMD_READ 0x2 /* Read command */
|
||||
#define CMD_CTL 0x3 /* Control command */
|
||||
#define CMD_SENSE 0x4 /* Sense channel command */
|
||||
#define CMD_TIC 0x8 /* Transfer in channel */
|
||||
#define CMD_RDBWD 0xc /* Read backward */
|
||||
|
||||
#define STATUS_ATTN 0x8000 /* Device raised attention */
|
||||
#define STATUS_MOD 0x4000 /* Status modifier */
|
||||
#define STATUS_CTLEND 0x2000 /* Control end */
|
||||
#define STATUS_BUSY 0x1000 /* Device busy */
|
||||
#define STATUS_CEND 0x0800 /* Channel end */
|
||||
#define STATUS_DEND 0x0400 /* Device end */
|
||||
#define STATUS_CHECK 0x0200 /* Unit check */
|
||||
#define STATUS_EXPT 0x0100 /* Unit excpetion */
|
||||
#define STATUS_PCI 0x0080 /* Program interupt */
|
||||
#define STATUS_LENGTH 0x0040 /* Incorrect lenght */
|
||||
#define STATUS_PCHK 0x0020 /* Program check */
|
||||
#define STATUS_PROT 0x0010 /* Protection check */
|
||||
#define STATUS_CDATA 0x0008 /* Channel data check */
|
||||
#define STATUS_CCNTL 0x0004 /* Channel control check */
|
||||
#define STATUS_INTER 0x0002 /* Channel interface check */
|
||||
#define STATUS_CHAIN 0x0001 /* Channel chain check */
|
||||
|
||||
#define FLAG_CD 0x8000 /* Chain data */
|
||||
#define FLAG_CC 0x4000 /* Chain command */
|
||||
#define FLAG_SLI 0x2000 /* Suppress length indicator */
|
||||
#define FLAG_SKIP 0x1000 /* Suppress memory write */
|
||||
#define FLAG_PCI 0x0800 /* Program controled interrupt */
|
||||
|
||||
#define BUFF_EMPTY 0x4 /* Buffer is empty */
|
||||
#define BUFF_DIRTY 0x8 /* Buffer is dirty flag */
|
||||
#define BUFF_NEWCMD 0x10 /* Channel ready for new command */
|
||||
#define BUFF_CHNEND 0x20 /* Channel end */
|
||||
|
||||
#define AMASK 0x00ffffff
|
||||
#define PMASK 0xf0000000 /* Storage protection mask */
|
||||
extern uint32 *M;
|
||||
extern uint8 key[MAXMEMSIZE / 2048];
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
#define MAX_DEV (MAX_CHAN * 256)
|
||||
int subchannels = SUB_CHANS; /* Number of subchannels */
|
||||
int irq_pend = 0;
|
||||
uint32 caw[256]; /* Channel command address word */
|
||||
uint32 ccw_addr[256]; /* Channel address */
|
||||
uint16 ccw_count[256]; /* Channel count */
|
||||
uint8 ccw_cmd[256]; /* Channel command and flags */
|
||||
uint16 ccw_flags[256]; /* Channel flags */
|
||||
uint16 chan_status[256]; /* Channel status */
|
||||
uint16 chan_dev[256]; /* Device on channel */
|
||||
uint32 chan_buf[256]; /* Channel data buffer */
|
||||
uint8 chan_byte[256]; /* Current byte, dirty/full */
|
||||
DIB *dev_unit[MAX_DEV]; /* Pointer to Device info block */
|
||||
uint8 dev_status[MAX_DEV]; /* last device status flags */
|
||||
|
||||
/* Find unit pointer for given device */
|
||||
UNIT *
|
||||
find_chan_dev(uint16 addr) {
|
||||
struct dib *dibp;
|
||||
UNIT *uptr;
|
||||
int i;
|
||||
|
||||
dibp = dev_unit[addr];
|
||||
if (dibp == 0)
|
||||
return NULL;
|
||||
uptr = dibp->units;
|
||||
if (dibp->mask == 0) {
|
||||
for (i = 0; i < dibp->numunits; i++) {
|
||||
if (addr == GET_UADDR(uptr->u3))
|
||||
return uptr;
|
||||
uptr++;
|
||||
}
|
||||
} else {
|
||||
return uptr + (addr & ~dibp->mask & 0xff);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* channel:
|
||||
subchannels = 128
|
||||
0 - 7 0x80-0xff
|
||||
8 - 127 0x00-0x7f
|
||||
128 - +6 0x1xx - 0x6xx
|
||||
*/
|
||||
|
||||
/* look up device to find subchannel device is on */
|
||||
int
|
||||
find_subchan(uint16 device) {
|
||||
int chan;
|
||||
if (device > MAX_DEV)
|
||||
return -1;
|
||||
if (device > 0xff) {
|
||||
chan = (device >> 8) & 0x7;
|
||||
if (chan > MAX_CHAN)
|
||||
return -1;
|
||||
return subchannels + chan;
|
||||
}
|
||||
if (device < subchannels)
|
||||
return device;
|
||||
return ((device - subchannels)>>4) & 0xf;
|
||||
}
|
||||
|
||||
int
|
||||
readfull(int chan, uint32 addr, uint32 *word) {
|
||||
int sk, k;
|
||||
if ((addr & AMASK) > MEMSIZE) {
|
||||
chan_status[chan] |= STATUS_PCHK;
|
||||
return 1;
|
||||
}
|
||||
sk = (addr >> 24) & 0xff;
|
||||
if (sk != 0) {
|
||||
if ((cpu_dev.flags & PROTECT) == 0) {
|
||||
chan_status[chan] |= STATUS_PROT;
|
||||
return 1;
|
||||
}
|
||||
k = key[(addr & 0xfffc00) >> 10];
|
||||
if ((k & 0x8) != 0 && (k & 0xf0) != sk) {
|
||||
chan_status[chan] |= STATUS_PROT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
addr &= AMASK;
|
||||
addr >>= 2;
|
||||
*word = M[addr];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int writefull(int chan, uint32 addr, uint32 *word) {
|
||||
int sk, k;
|
||||
if ((addr & AMASK) > MEMSIZE) {
|
||||
chan_status[chan] |= STATUS_PCHK;
|
||||
return 1;
|
||||
}
|
||||
sk = (addr >> 24) & 0xff;
|
||||
if (sk != 0) {
|
||||
if ((cpu_dev.flags & PROTECT) == 0) {
|
||||
chan_status[chan] |= STATUS_PROT;
|
||||
return 1;
|
||||
}
|
||||
k = key[(addr & 0xfffc00) >> 10];
|
||||
if ((k & 0x8) != 0 && (k & 0xf0) != sk) {
|
||||
chan_status[chan] |= STATUS_PROT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Channel write %02x %06x %08x %08x '", chan, addr, *word, ccw_count[chan]);
|
||||
addr &= AMASK;
|
||||
addr >>= 2;
|
||||
M[addr] = *word;
|
||||
for(k = 24; k >= 0; k -= 8) {
|
||||
char ch = ebcdic_to_ascii[(*word >> k) & 0xFF];
|
||||
if (ch < 0x20 || ch == 0xff)
|
||||
ch = '.';
|
||||
fprintf(stderr, "%c", ch);
|
||||
}
|
||||
|
||||
fprintf(stderr, "'\n\r");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
load_ccw(uint16 chan, int tic_ok) {
|
||||
uint32 word;
|
||||
int cmd = 0;
|
||||
UNIT *uptr;
|
||||
|
||||
loop:
|
||||
if ((caw[chan] & 0x7) != 0) {
|
||||
chan_status[chan] |= STATUS_PCHK;
|
||||
return 1;
|
||||
}
|
||||
/* Check if we have status modifier set */
|
||||
if (chan_status[chan] & STATUS_MOD) {
|
||||
caw[chan]+=8;
|
||||
caw[chan] &= PMASK|AMASK; /* Mask overflow bits */
|
||||
chan_status[chan] &= ~STATUS_MOD;
|
||||
}
|
||||
readfull(chan, caw[chan], &word);
|
||||
fprintf(stderr, "Channel read ccw %02x %06x %08x\n\r", chan, caw[chan], word);
|
||||
if (((word >> 24) & 0xf) == CMD_TIC) {
|
||||
if (tic_ok) {
|
||||
caw[chan] = (caw[chan] & PMASK) | (word & AMASK);
|
||||
tic_ok = 0;
|
||||
goto loop;
|
||||
}
|
||||
chan_status[chan] |= STATUS_PCHK;
|
||||
irq_pend = 1;
|
||||
return 1;
|
||||
}
|
||||
caw[chan] += 4;
|
||||
caw[chan] &= PMASK|AMASK; /* Mask overflow bits */
|
||||
/* Check if fetch ok */
|
||||
if ((ccw_flags[chan] & FLAG_CD) == 0) {
|
||||
ccw_cmd[chan] = (word >> 24) & 0xff;
|
||||
cmd = 1;
|
||||
}
|
||||
ccw_addr[chan] = word & AMASK;
|
||||
ccw_addr[chan] |= caw[chan] & PMASK; /* Copy key */
|
||||
readfull(chan, caw[chan], &word);
|
||||
fprintf(stderr, "Channel read ccw2 %02x %06x %08x\n\r", chan, caw[chan], word);
|
||||
caw[chan]+=4;
|
||||
caw[chan] &= PMASK|AMASK; /* Mask overflow bits */
|
||||
ccw_count[chan] = word & 0xffff;
|
||||
ccw_flags[chan] = (word >> 16) & 0xffff;
|
||||
chan_byte[chan] = BUFF_EMPTY;
|
||||
if (ccw_flags[chan] & FLAG_PCI) {
|
||||
chan_status[chan] |= STATUS_PCI;
|
||||
irq_pend = 1;
|
||||
}
|
||||
/* Check invalid count */
|
||||
if (ccw_count[chan] == 0) {
|
||||
chan_status[chan] |= STATUS_PCHK;
|
||||
irq_pend = 1;
|
||||
return 1;
|
||||
}
|
||||
if (cmd) {
|
||||
DIB *dibp = dev_unit[chan_dev[chan]];
|
||||
/* Check if invalid command */
|
||||
if ((ccw_cmd[chan] & 0xF) == 0) {
|
||||
chan_status[chan] |= STATUS_PCHK;
|
||||
irq_pend = 1;
|
||||
return 1;
|
||||
}
|
||||
uptr = find_chan_dev(chan_dev[chan]);
|
||||
if (uptr == 0)
|
||||
return 1;
|
||||
chan_status[chan] &= 0xff;
|
||||
chan_status[chan] |= dibp->start_cmd(uptr, chan, ccw_cmd[chan]) << 8;
|
||||
if (chan_status[chan] & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) {
|
||||
chan_status[chan] |= STATUS_CEND;
|
||||
ccw_flags[chan] = 0;
|
||||
ccw_cmd[chan] = 0;
|
||||
irq_pend = 1;
|
||||
return 1;
|
||||
}
|
||||
if (chan_status[chan] & (STATUS_DEND|STATUS_CEND)) {
|
||||
chan_status[chan] |= STATUS_CEND;
|
||||
chan_byte[chan] = BUFF_NEWCMD;
|
||||
ccw_cmd[chan] = 0;
|
||||
irq_pend = 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* read byte from memory */
|
||||
int
|
||||
chan_read_byte(uint16 addr, uint8 *data) {
|
||||
int chan = find_subchan(addr);
|
||||
int byte;
|
||||
int k;
|
||||
|
||||
if ((ccw_cmd[chan] & 0x1) == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (chan_byte[chan] == BUFF_CHNEND)
|
||||
return 1;
|
||||
if (chan_byte[chan] == BUFF_EMPTY) {
|
||||
if (readfull(chan, ccw_addr[chan], &chan_buf[chan])) {
|
||||
chan_byte[chan] = BUFF_CHNEND;
|
||||
irq_pend = 1;
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "Channel read %02x %06x %08x %08x '", chan, ccw_addr[chan], chan_buf[chan], ccw_count[chan]);
|
||||
for(k = 24; k >= 0; k -= 8) {
|
||||
char ch = ebcdic_to_ascii[(chan_buf[chan] >> k) & 0xFF];
|
||||
if (ch < 0x20 || ch == 0xff)
|
||||
ch = '.';
|
||||
fprintf(stderr, "%c", ch);
|
||||
}
|
||||
|
||||
fprintf(stderr, "'\n\r");
|
||||
chan_byte[chan] = ccw_addr[chan] & 0x3;
|
||||
ccw_addr[chan] += 4 - chan_byte[chan];
|
||||
}
|
||||
ccw_count[chan]--;
|
||||
byte = (chan_buf[chan] >> (8 * (3 - (chan_byte[chan] & 0x3)))) & 0xff;
|
||||
chan_byte[chan]++;
|
||||
*data = byte;
|
||||
if (ccw_count[chan] == 0) {
|
||||
if (ccw_flags[chan] & FLAG_CD)
|
||||
return load_ccw(chan, 1);
|
||||
else {
|
||||
chan_status[chan] |= STATUS_CEND;
|
||||
chan_byte[chan] = BUFF_CHNEND;
|
||||
}
|
||||
fprintf(stderr, "chan_read_end\n\r");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write byte to memory */
|
||||
int
|
||||
chan_write_byte(uint16 addr, uint8 *data) {
|
||||
int chan = find_subchan(addr);
|
||||
int byte;
|
||||
int offset;
|
||||
uint32 mask;
|
||||
|
||||
if ((ccw_cmd[chan] & 0x1) != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (chan_byte[chan] == BUFF_CHNEND) {
|
||||
if ((ccw_flags[chan] & FLAG_SLI) == 0) {
|
||||
chan_status[chan] |= STATUS_LENGTH;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (ccw_flags[chan] & FLAG_SKIP) {
|
||||
ccw_count[chan]--;
|
||||
if ((ccw_cmd[chan] & 0xf) == CMD_RDBWD)
|
||||
ccw_addr[chan]--;
|
||||
else
|
||||
ccw_addr[chan]++;
|
||||
if (ccw_count[chan] == 0) {
|
||||
if (ccw_flags[chan] & FLAG_CD)
|
||||
return load_ccw(chan, 1);
|
||||
else
|
||||
chan_byte[chan] = BUFF_CHNEND;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (chan_byte[chan] == (BUFF_EMPTY|BUFF_DIRTY)) {
|
||||
if (writefull(chan, ccw_addr[chan], &chan_buf[chan])) {
|
||||
chan_byte[chan] = BUFF_CHNEND;
|
||||
irq_pend = 1;
|
||||
return 1;
|
||||
}
|
||||
if ((ccw_cmd[chan] & 0xf) == CMD_RDBWD)
|
||||
ccw_addr[chan] -= 1 + (ccw_addr[chan] & 0x3);
|
||||
else
|
||||
ccw_addr[chan] += 4 - (ccw_addr[chan] & 0x3);
|
||||
chan_byte[chan] = BUFF_EMPTY;
|
||||
}
|
||||
if (chan_byte[chan] == BUFF_EMPTY) {
|
||||
if (readfull(chan, ccw_addr[chan], &chan_buf[chan])) {
|
||||
chan_byte[chan] = BUFF_CHNEND;
|
||||
irq_pend = 1;
|
||||
return 1;
|
||||
}
|
||||
chan_byte[chan] = ccw_addr[chan] & 0x3;
|
||||
}
|
||||
ccw_count[chan]--;
|
||||
offset = 8 * (chan_byte[chan] & 0x3);
|
||||
mask = 0xff000000 >> offset;
|
||||
chan_buf[chan] &= ~mask;
|
||||
chan_buf[chan] |= ((uint32)(*data)) << (24 - offset);
|
||||
if ((ccw_cmd[chan] & 0xf) == CMD_RDBWD) {
|
||||
if (chan_byte[chan] & 0x3)
|
||||
chan_byte[chan]--;
|
||||
else
|
||||
chan_byte[chan] = BUFF_EMPTY;
|
||||
} else
|
||||
chan_byte[chan]++;
|
||||
chan_byte[chan] |= BUFF_DIRTY;
|
||||
if (ccw_count[chan] == 0) {
|
||||
if (writefull(chan, ccw_addr[chan], &chan_buf[chan])) {
|
||||
chan_byte[chan] = BUFF_CHNEND;
|
||||
return 1;
|
||||
}
|
||||
if (ccw_flags[chan] & FLAG_CD)
|
||||
return load_ccw(chan, 1);
|
||||
chan_byte[chan] = BUFF_CHNEND;
|
||||
fprintf(stderr, "chan_write_end\n\r");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
set_devattn(uint16 addr, uint8 flags) {
|
||||
int chan = find_subchan(addr);
|
||||
|
||||
if (chan_dev[chan] == addr && (chan_status[chan] & STATUS_CEND) != 0 &&
|
||||
(flags & SNS_DEVEND) != 0) {
|
||||
chan_status[chan] |= ((uint16)flags) << 8;
|
||||
} else
|
||||
dev_status[addr] = flags;
|
||||
fprintf(stderr, "set_devattn(%x, %x) %x\n\r", addr, flags, chan_dev[chan]);
|
||||
irq_pend = 1;
|
||||
}
|
||||
|
||||
void
|
||||
chan_end(uint16 addr, uint8 flags) {
|
||||
int chan = find_subchan(addr);
|
||||
|
||||
fprintf(stderr, "chan_end(%x, %x)\n\r", addr, flags);
|
||||
if (chan_byte[chan] & BUFF_DIRTY) {
|
||||
writefull(chan, ccw_addr[chan], &chan_buf[chan]);
|
||||
chan_byte[chan] = BUFF_EMPTY;
|
||||
}
|
||||
chan_status[chan] |= STATUS_CEND;
|
||||
chan_status[chan] |= ((uint16)flags) << 8;
|
||||
ccw_cmd[chan] = 0;
|
||||
if (ccw_count[chan] != 0 && (ccw_flags[chan] & FLAG_SLI) == 0) {
|
||||
chan_status[chan] |= STATUS_LENGTH;
|
||||
ccw_flags[chan] = 0;
|
||||
}
|
||||
if (flags & (SNS_ATTN|SNS_UNITCHK|SNS_UNITEXP)) {
|
||||
ccw_flags[chan] = 0;
|
||||
}
|
||||
|
||||
if (chan_status[chan] & (STATUS_DEND|STATUS_CEND)) {
|
||||
chan_byte[chan] = BUFF_NEWCMD;
|
||||
}
|
||||
|
||||
irq_pend = 1;
|
||||
}
|
||||
|
||||
int
|
||||
store_csw(uint16 chan) {
|
||||
M[0x40 >> 2] = caw[chan];
|
||||
M[0x44 >> 2] = (((uint32)ccw_count[chan])) | ((uint32)chan_status[chan]<<16);
|
||||
fprintf(stderr, "Channel store csw %02x %06x %08x\n\r", chan, M[0x40>>2], M[0x44 >> 2]);
|
||||
return chan_dev[chan];
|
||||
}
|
||||
|
||||
|
||||
int startio(uint16 addr) {
|
||||
int chan = find_subchan(addr);
|
||||
DIB *dibp = dev_unit[addr];
|
||||
UNIT *uptr;
|
||||
uint8 status;
|
||||
|
||||
fprintf(stderr, "SIO %x %x %x %x\n\r", addr, chan, ccw_cmd[chan], ccw_flags[chan]);
|
||||
if (chan < 0 || dibp == 0)
|
||||
return 3;
|
||||
uptr = find_chan_dev(addr);
|
||||
if (uptr == 0)
|
||||
return 3;
|
||||
if (ccw_cmd[chan] != 0 || (ccw_flags[chan] & (FLAG_CD|FLAG_CC)) != 0)
|
||||
return 2;
|
||||
chan_status[chan] = 0;
|
||||
dev_status[addr] = 0;
|
||||
caw[chan] = M[0x48>>2];
|
||||
chan_dev[chan] = addr;
|
||||
if (dibp->start_io != NULL) {
|
||||
chan_status[chan] = dibp->start_io(uptr, chan) << 8;
|
||||
if (chan_status[chan] != 0) {
|
||||
M[0x44 >> 2] = ((uint32)chan_status[chan]<<16) | M[0x44 >> 2] & 0xffff;
|
||||
fprintf(stderr, "Channel store csw %02x %08x\n\r", chan, M[0x44 >> 2]);
|
||||
chan_status[chan] = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (load_ccw(chan, 0) || (chan_status[chan] & (STATUS_PCI))) {
|
||||
M[0x44 >> 2] = ((uint32)chan_status[chan]<<16) | M[0x44 >> 2] & 0xffff;
|
||||
fprintf(stderr, "Channel store csw %02x %08x\n\r", chan, M[0x44 >> 2]);
|
||||
chan_status[chan] &= ~STATUS_PCI;
|
||||
dev_status[addr] = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testio(uint16 addr) {
|
||||
int chan = find_subchan(addr);
|
||||
DIB *dibp = dev_unit[addr];
|
||||
UNIT *uptr;
|
||||
uint8 status;
|
||||
|
||||
if (chan < 0 || dibp == 0)
|
||||
return 3;
|
||||
uptr = find_chan_dev(addr);
|
||||
if (uptr == 0)
|
||||
return 3;
|
||||
if (ccw_cmd[chan] != 0 || (ccw_flags[chan] & (FLAG_CD|FLAG_CC)) != 0)
|
||||
return 2;
|
||||
if (chan_dev[chan] != addr)
|
||||
return 2;
|
||||
if (ccw_cmd[chan] == 0 && chan_status[chan] != 0) {
|
||||
store_csw(chan);
|
||||
chan_status[chan] = 0;
|
||||
dev_status[addr] = 0;
|
||||
return 1;
|
||||
}
|
||||
if (dev_status[addr] & (SNS_ATTN|SNS_UNITCHK|SNS_UNITEXP)) {
|
||||
M[0x40 >> 2] = 0;
|
||||
M[0x44 >> 2] = ((uint32)dev_status[addr]) << 24;
|
||||
dev_status[addr] = 0;
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "Testio %x %x\n\r", addr, chan_status[chan]);
|
||||
chan_status[chan] = dibp->start_cmd(uptr, chan, 0) << 8;
|
||||
if (chan_status[chan] & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) {
|
||||
M[0x44 >> 2] = ((uint32)chan_status[chan]<<16) | M[0x44 >> 2] & 0xffff;
|
||||
chan_status[chan] = 0;
|
||||
dev_status[addr] = 0;
|
||||
return 1;
|
||||
}
|
||||
chan_status[chan] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int haltio(uint16 addr) {
|
||||
int chan = find_subchan(addr);
|
||||
DIB *dibp = dev_unit[addr];
|
||||
UNIT *uptr;
|
||||
uint8 status;
|
||||
|
||||
if (chan < 0 || dibp == 0)
|
||||
return 3;
|
||||
uptr = find_chan_dev(chan_dev[chan]);
|
||||
if (uptr == 0)
|
||||
return 3;
|
||||
if (ccw_cmd[chan]) {
|
||||
chan_byte[chan] = BUFF_CHNEND;
|
||||
return 2;
|
||||
}
|
||||
if (dibp->halt_io != NULL)
|
||||
chan_status[chan] = dibp->halt_io(uptr) << 8;
|
||||
if (chan_status[chan] & (STATUS_ATTN|STATUS_PCI|STATUS_EXPT|STATUS_CHECK|
|
||||
STATUS_PROT|STATUS_CDATA|STATUS_CCNTL|STATUS_INTER|
|
||||
STATUS_CHAIN))
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testchan(uint16 channel) {
|
||||
uint16 st = 0;
|
||||
channel >>= 8;
|
||||
if (channel = 0)
|
||||
return 0;
|
||||
st = chan_status[subchannels + channel];
|
||||
if (st & STATUS_BUSY)
|
||||
return 2;
|
||||
if (st & (STATUS_ATTN|STATUS_PCI|STATUS_EXPT|STATUS_CHECK|
|
||||
STATUS_PROT|STATUS_CDATA|STATUS_CCNTL|STATUS_INTER|
|
||||
STATUS_CHAIN))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_stat chan_boot(uint16 addr, DEVICE *dptyr) {
|
||||
int chan = find_subchan(addr);
|
||||
DIB *dibp = dev_unit[addr];
|
||||
UNIT *uptr;
|
||||
uint8 status;
|
||||
int i;
|
||||
|
||||
if (chan < 0 || dibp == 0)
|
||||
return SCPE_IOERR;
|
||||
for (i = 0; i < MAX_DEV; i++) {
|
||||
dev_status[i] = 0;
|
||||
}
|
||||
for (i = 0; i < 256; i++) {
|
||||
ccw_cmd[i] = 0;
|
||||
ccw_flags[i] = 0;
|
||||
}
|
||||
uptr = find_chan_dev(addr);
|
||||
chan_status[chan] = 0;
|
||||
dev_status[addr] = 0;
|
||||
caw[chan] = 0x8;
|
||||
chan_dev[chan] = addr;
|
||||
ccw_count[chan] = 24;
|
||||
ccw_flags[chan] = FLAG_CC|FLAG_SLI;
|
||||
chan_byte[chan] = BUFF_EMPTY;
|
||||
ccw_cmd[chan] = 0x2;
|
||||
chan_status[chan] &= 0xff;
|
||||
chan_status[chan] |= dibp->start_cmd(uptr, chan, ccw_cmd[chan]) << 8;
|
||||
if (chan_status[chan] & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) {
|
||||
ccw_flags[chan] = 0;
|
||||
return SCPE_IOERR;
|
||||
}
|
||||
loading = addr;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Scan all channels and see if one is ready to start or has
|
||||
interrupt pending.
|
||||
*/
|
||||
uint16 scan_chan(uint8 mask) {
|
||||
int i;
|
||||
int pend = 0; /* No device */
|
||||
int imask = 0x80;
|
||||
|
||||
if (irq_pend == 0)
|
||||
return 0;
|
||||
irq_pend = 0;
|
||||
for (i = 0; i < subchannels + MAX_CHAN; i++) {
|
||||
if (i >= subchannels)
|
||||
imask = imask / 2;
|
||||
|
||||
/* If channel end, check if we should continue */
|
||||
if (chan_status[i] & STATUS_CEND) {
|
||||
if (ccw_flags[i] & FLAG_CC) {
|
||||
//fprintf(stderr, "Scan(%x %x) CC\n\r", i, chan_status[i]);
|
||||
if (chan_status[i] & STATUS_DEND)
|
||||
(void)load_ccw(i, 1);
|
||||
else
|
||||
irq_pend = 1;
|
||||
} else {
|
||||
fprintf(stderr, "Scan(%x %x %x %x) end\n\r", i, chan_status[i], imask, mask);
|
||||
if ((imask & mask) != 0 || loading != 0) {
|
||||
pend = chan_dev[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pend) {
|
||||
irq_pend = 1;
|
||||
i = find_subchan(pend);
|
||||
fprintf(stderr, "Scan end (%x %x)\n\r", chan_dev[i], pend);
|
||||
store_csw(i);
|
||||
chan_status[i] = 0;
|
||||
chan_dev[i] = 0;
|
||||
dev_status[pend] = 0;
|
||||
} else {
|
||||
for (i = 0; i < MAX_DEV; i++) {
|
||||
if (dev_status[i] != 0) {
|
||||
pend = find_subchan(i);
|
||||
if (ccw_cmd[pend] == 0 && mask & (0x80 >> (i >> 8))) {
|
||||
irq_pend = 1;
|
||||
fprintf(stderr, "Set atten %03x %02x\n\r", i, dev_status[i]);
|
||||
// M[0x40 >> 2] = 0;
|
||||
M[0x44 >> 2] = (((uint32)dev_status[i]) << 24) |
|
||||
(M[0x44>>2] & 0xffff);
|
||||
dev_status[i] = 0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
pend = 0;
|
||||
}
|
||||
return pend;
|
||||
}
|
||||
|
||||
|
||||
t_stat
|
||||
chan_set_devs()
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for(i = 0; i < MAX_DEV; i++) {
|
||||
dev_unit[i] = NULL; /* Device pointer */
|
||||
}
|
||||
/* Build channel array */
|
||||
for (i = 0; sim_devices[i] != NULL; i++) {
|
||||
DEVICE *dptr = sim_devices[i];
|
||||
UNIT *uptr = dptr->units;
|
||||
DIB *dibp = (DIB *) dptr->ctxt;
|
||||
int addr;
|
||||
int chan;
|
||||
|
||||
/* If no DIB, not channel device */
|
||||
if (dibp == NULL)
|
||||
continue;
|
||||
/* Skip disabled devices */
|
||||
if (dptr->flags & DEV_DIS)
|
||||
continue;
|
||||
/* Check if address is in unit or dev entry */
|
||||
for (j = 0; j < dptr->numunits; j++) {
|
||||
addr = GET_UADDR(uptr->u3);
|
||||
if ((uptr->flags & UNIT_DIS) == 0)
|
||||
dev_unit[addr] = dibp;
|
||||
if (dibp->dev_ini != NULL)
|
||||
dibp->dev_ini(uptr, 1);
|
||||
uptr++;
|
||||
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Sets the device onto a given channel */
|
||||
t_stat
|
||||
set_dev_addr(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
DEVICE *dptr;
|
||||
DIB *dibp;
|
||||
t_value newdev;
|
||||
t_stat r;
|
||||
int num;
|
||||
int type;
|
||||
int i;
|
||||
int devaddr;
|
||||
|
||||
if (cptr == NULL)
|
||||
return SCPE_ARG;
|
||||
if (uptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dptr = find_dev_from_unit(uptr);
|
||||
if (dptr == NULL)
|
||||
return SCPE_IERR;
|
||||
|
||||
dibp = (DIB *) dptr->ctxt;
|
||||
if (dibp == NULL)
|
||||
return SCPE_IERR;
|
||||
|
||||
newdev = get_uint (cptr, 16, 0xfff, &r);
|
||||
|
||||
if (r != SCPE_OK)
|
||||
return r;
|
||||
|
||||
devaddr = GET_UADDR(uptr->u3);
|
||||
if (newdev > MAX_DEV)
|
||||
return SCPE_ARG;
|
||||
|
||||
/* Clear out existing entry */
|
||||
if (dptr->flags & DEV_UADDR) {
|
||||
dev_unit[devaddr] = NULL;
|
||||
} else {
|
||||
devaddr &= dibp->mask | 0x700;
|
||||
for (i = 0; i < dibp->numunits; i++)
|
||||
dev_unit[devaddr + i] = NULL;
|
||||
}
|
||||
|
||||
/* Check if device already at newdev */
|
||||
if (dptr->flags & DEV_UADDR) {
|
||||
if (dev_unit[newdev] != NULL)
|
||||
r = SCPE_ARG;
|
||||
} else {
|
||||
newdev &= dibp->mask | 0x700;
|
||||
for (i = 0; i < dibp->numunits; i++) {
|
||||
if (dev_unit[newdev + i] != NULL)
|
||||
r = SCPE_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
/* If not, point to new dev, else restore old */
|
||||
if (r == SCPE_OK)
|
||||
devaddr = newdev;
|
||||
|
||||
/* Update device entry */
|
||||
if (dptr->flags & DEV_UADDR) {
|
||||
dev_unit[devaddr] = dibp;
|
||||
fprintf(stderr, "Set dev %x\n\r", devaddr);
|
||||
} else {
|
||||
for (i = 0; i < dibp->numunits; i++) {
|
||||
dev_unit[devaddr + i] = dibp;
|
||||
fprintf(stderr, "Set dev %x\n\r", devaddr + i);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
t_stat
|
||||
show_dev_addr(FILE * st, UNIT * uptr, int32 v, CONST void *desc)
|
||||
{
|
||||
DEVICE *dptr;
|
||||
DIB *dibp;
|
||||
int addr;
|
||||
|
||||
|
||||
if (uptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dptr = find_dev_from_unit(uptr);
|
||||
if (dptr == NULL)
|
||||
return SCPE_IERR;
|
||||
addr = GET_UADDR(uptr->u3);
|
||||
fprintf(st, "%03x", addr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
304
IBM360/ibm360_com.c
Normal file
304
IBM360/ibm360_com.c
Normal file
@ -0,0 +1,304 @@
|
||||
/* ibm360_com.c: IBM 360 2703 communications 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 "ibm360_defs.h"
|
||||
|
||||
#ifdef NUM_DEVS_COM
|
||||
#define UNIT_COM UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE
|
||||
|
||||
|
||||
/* u3 */
|
||||
#define DK_NOP 0x03 /* Nop operation */
|
||||
#define DK_RELEASE 0x17 /* Release from channel */
|
||||
#define DK_RESTORE 0x13 /* Restore */
|
||||
#define DK_SEEK 0x07 /* Seek */
|
||||
#define DK_SEEKCYL 0x0B /* Seek Cylinder */
|
||||
#define DK_SEEKHD 0x09 /* Seek Head */
|
||||
#define DK_SETMSK 0x1f /* Set file mask */
|
||||
#define DK_SPACE 0x0f /* Space record */
|
||||
#define DK_SRCH_HAEQ 0x39 /* Search HA equal */
|
||||
#define DK_SRCH_IDEQ 0x31 /* Search ID equal */
|
||||
#define DK_SRCH_IDGT 0x51 /* Search ID greater */
|
||||
#define DK_SRCH_IDGE 0x71 /* Search ID greater or equal */
|
||||
#define DK_SRCH_KYEQ 0x29 /* Search Key equal */
|
||||
#define DK_SRCH_KYGT 0x49 /* Search Key greater */
|
||||
#define DK_SRCH_KYGE 0x69 /* Search Key greater or equal */
|
||||
#define DK_RD_IPL 0x02 /* Read IPL record */
|
||||
#define DK_RD_HA 0x1A /* Read home address */
|
||||
#define DK_RD_CNT 0x12 /* Read count */
|
||||
#define DK_RD_R0 0x16 /* Read R0 */
|
||||
#define DK_RD_D 0x06 /* Read Data */
|
||||
#define DK_RD_KD 0x0e /* Read key and data */
|
||||
#define DK_RD_CKD 0x1e /* Read count, key and data */
|
||||
#define DK_WR_HA 0x19 /* Write home address */
|
||||
#define DK_WR_R0 0x15 /* Write R0 */
|
||||
#define DK_WR_D 0x05 /* Write Data */
|
||||
#define DK_WR_KD 0x0d /* Write key and data */
|
||||
#define DK_WR_CKD 0x1d /* Write count, key and data */
|
||||
#define DK_WR_SCKD 0x01 /* Write special count, key and data */
|
||||
#define DK_ERASE 0x11 /* Erase to end of track */
|
||||
#define DK_MT 0x80 /* Multi track flag */
|
||||
|
||||
#define DK_CYL_DIRTY 0x100 /* Current cylinder dirty */
|
||||
|
||||
#define DK_MSK_INHWR0 0x00 /* Inhbit writing of HA/R0 */
|
||||
#define DK_MSK_INHWRT 0x40 /* Inhbit all writes */
|
||||
#define DK_MSK_ALLWRU 0x80 /* Allow all updates */
|
||||
#define DK_MSK_ALLWRT 0xc0 /* Allow all writes */
|
||||
#define DK_MSK_WRT 0xc0 /* Write mask */
|
||||
|
||||
#define DK_MSK_SKALLSKR 0x00 /* Allow all seek/recal */
|
||||
#define DK_MSK_SKALLCLY 0x01 /* Allow cyl/head only */
|
||||
#define DK_MSK_SKALLHD 0x02 /* Allow head only */
|
||||
#define DK_MSK_SKNONE 0x03 /* Allow no seeks */
|
||||
#define DK_MSK_SK 0x03 /* Seek mask */
|
||||
|
||||
|
||||
/* u4 */
|
||||
/* Position around disk */
|
||||
|
||||
/* u5 */
|
||||
/* Sense byte 0 */
|
||||
#define SNS_CMDREJ 0x01 /* Command reject */
|
||||
#define SNS_INTVENT 0x02 /* Unit intervention required */
|
||||
#define SNS_BUSCHK 0x04 /* Parity error on bus */
|
||||
#define SNS_EQUCHK 0x08 /* Equipment check */
|
||||
#define SNS_DATCHK 0x10 /* Data Check */
|
||||
#define SNS_OVRRUN 0x20 /* Data overrun */
|
||||
#define SNS_TRKCND 0x40 /* Track Condition */
|
||||
#define SNS_SEEKCK 0x80 /* Seek Check */
|
||||
|
||||
/* Sense byte 1 */
|
||||
#define SNS_DCCNT 0x01 /* Data Check Count */
|
||||
#define SNS_TRKOVR 0x02 /* Track Overrun */
|
||||
#define SNS_ENDCYL 0x04 /* End of Cylinder */
|
||||
#define SNS_INVSEQ 0x08 /* Invalid Sequence */
|
||||
#define SNS_NOREC 0x10 /* No record found */
|
||||
#define SNS_WRP 0x20 /* Write Protect */
|
||||
#define SNS_ADDR 0x40 /* Missing Address Mark */
|
||||
#define SNS_OVRINC 0x80 /* Overflow Incomplete */
|
||||
|
||||
/* Sense byte 2 */
|
||||
#define SNS_BYTE2 0x00 /* Diags Use */
|
||||
/* Sense byte 3 */
|
||||
#define SNS_BYTE3 0x00 /* Diags Use */
|
||||
|
||||
/* u6 */
|
||||
|
||||
uint8 com_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) ;
|
||||
uint8 com_haltio(uint16 addr);
|
||||
t_stat com_srv(UNIT *);
|
||||
void com_ini(UNIT *, t_bool);
|
||||
t_stat com_reset(DEVICE *);
|
||||
t_stat com_attach(UNIT *, CONST char *);
|
||||
t_stat com_detach(UNIT *);
|
||||
t_stat com_boot(int32, DEVICE *);
|
||||
|
||||
|
||||
|
||||
MTAB com_mod[] = {
|
||||
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr,
|
||||
&show_dev_addr, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
UNIT com_unit[] = {
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x030)}, /* 0 */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x031)}, /* 1 */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x032)}, /* 2 */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x033)}, /* 3 */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x034)}, /* 4 */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x035)}, /* 5 */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x036)}, /* 6 */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x037)}, /* 7 */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x038)}, /* 8 */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x039)}, /* 9 */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x03A)}, /* A */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x03B)}, /* B */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x03C)}, /* C */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x03D)}, /* D */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x03E)}, /* E */
|
||||
{UDATA(&com_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x03F)}, /* F */
|
||||
};
|
||||
|
||||
struct dib com_dib = { 0xF0, NUM_UNITS_MT, NULL, com_startcmd, NULL, com_unit, NULL};
|
||||
|
||||
DEVICE com_dev = {
|
||||
"COM", com_unit, NULL, com_mod,
|
||||
NUM_UNITS_COM, 8, 15, 1, 8, 8,
|
||||
NULL, NULL, &com_reset, NULL, &com_attach, &com_detach,
|
||||
&com_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug
|
||||
};
|
||||
|
||||
|
||||
|
||||
uint8 com_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
|
||||
uint16 addr = GET_UADDR(uptr->u3);
|
||||
DEVICE *dptr = find_dev_from_unit(uptr);
|
||||
int unit = (uptr - dptr->units);
|
||||
uint8 ch;
|
||||
|
||||
if ((uptr->u3 & 0xff) != 0) {
|
||||
return SNS_BSY;
|
||||
}
|
||||
|
||||
sim_debug(DEBUG_CMD, dptr, "CMD unit=%d %x", unit, cmd);
|
||||
|
||||
switch (cmd & 0x3) {
|
||||
case 0x3: /* Control */
|
||||
if ((cmd & 0xfc) == 0)
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
case 0x1: /* Write command */
|
||||
case 0x2: /* Read command */
|
||||
uptr->u3 |= cmd;
|
||||
return 0;
|
||||
|
||||
case 0x0: /* Status */
|
||||
if (cmd == 0x4) { /* Sense */
|
||||
uptr->u3 |= cmd;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (uptr->u5 & 0xff)
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
}
|
||||
|
||||
/* Handle processing of disk requests. */
|
||||
t_stat com_srv(UNIT * uptr)
|
||||
{
|
||||
uint16 addr = GET_UADDR(uptr->u3);
|
||||
DEVICE *dptr = find_dev_from_unit(uptr);
|
||||
struct com_t *data = (struct com_t *)(uptr->up7);
|
||||
int unit = (uptr - dptr->units);
|
||||
int cmd = uptr->u3 & 0xff;
|
||||
uint8 ch;
|
||||
|
||||
|
||||
switch (cmd) {
|
||||
case 0: /* No command, stop tape */
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Idle unit=%d\n", unit);
|
||||
break;
|
||||
|
||||
case 0x4:
|
||||
ch = uptr->u5 & 0xff;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 1 %x\n", unit, ch);
|
||||
chan_write_byte(addr, &ch) ;
|
||||
ch = (uptr->u5 >> 8) & 0xff;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 2 %x\n", unit, ch);
|
||||
chan_write_byte(addr, &ch) ;
|
||||
ch = 0xc0;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 3 %x\n", unit, ch);
|
||||
chan_write_byte(addr, &ch) ;
|
||||
ch = (uptr->u5 >> 16) & 0xff;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 4 %x\n", unit, ch);
|
||||
chan_write_byte(addr, &ch) ;
|
||||
ch = 0;
|
||||
chan_write_byte(addr, &ch) ;
|
||||
chan_write_byte(addr, &ch);
|
||||
uptr->u3 &= ~0xff;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
break;
|
||||
|
||||
case DK_RELEASE: /* Release from channel */
|
||||
case DK_RESTORE: /* Restore */
|
||||
case DK_SEEK: /* Seek */
|
||||
case DK_SEEKCYL: /* Seek Cylinder */
|
||||
case DK_SEEKHD: /* Seek Head */
|
||||
case DK_SETMSK: /* Set file mask */
|
||||
case DK_SPACE: /* Space record */
|
||||
case DK_SRCH_HAEQ: /* Search HA equal */
|
||||
case DK_SRCH_IDEQ: /* Search ID equal */
|
||||
case DK_SRCH_IDGT: /* Search ID greater */
|
||||
case DK_SRCH_IDGE: /* Search ID greater or equal */
|
||||
case DK_SRCH_KYEQ: /* Search Key equal */
|
||||
case DK_SRCH_KYGT: /* Search Key greater */
|
||||
case DK_SRCH_KYGE: /* Search Key greater or equal */
|
||||
case DK_RD_IPL: /* Read IPL record */
|
||||
case DK_RD_HA: /* Read home address */
|
||||
case DK_RD_CNT: /* Read count */
|
||||
case DK_RD_R0: /* Read R0 */
|
||||
case DK_RD_D: /* Read Data */
|
||||
case DK_RD_KD: /* Read key and data */
|
||||
case DK_RD_CKD: /* Read count, key and data */
|
||||
case DK_WR_HA: /* Write home address */
|
||||
case DK_WR_R0: /* Write R0 */
|
||||
case DK_WR_D: /* Write Data */
|
||||
case DK_WR_KD: /* Write key and data */
|
||||
case DK_WR_CKD: /* Write count, key and data */
|
||||
case DK_WR_SCKD: /* Write special count, key and data */
|
||||
case DK_ERASE: /* Erase to end of track */
|
||||
break;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
void
|
||||
com_ini(UNIT * uptr, t_bool f)
|
||||
{
|
||||
DEVICE *dptr = find_dev_from_unit(uptr);
|
||||
}
|
||||
|
||||
t_stat
|
||||
com_reset(DEVICE * dptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
com_attach(UNIT * uptr, CONST char *file)
|
||||
{
|
||||
uint16 addr = GET_UADDR(uptr->u3);
|
||||
t_stat r;
|
||||
|
||||
if ((r = attach_unit(uptr, file)) != SCPE_OK)
|
||||
return r;
|
||||
|
||||
set_devattn(addr, SNS_DEVEND);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
com_detach(UNIT * uptr)
|
||||
{
|
||||
uptr->u3 = 0;
|
||||
return detach_unit(uptr);
|
||||
}
|
||||
|
||||
t_stat com_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||||
const char *cptr)
|
||||
{
|
||||
int i;
|
||||
fprint_set_help (st, dptr);
|
||||
fprint_show_help (st, dptr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
const char *com_description (DEVICE *dptr)
|
||||
{
|
||||
return "IBM 2703 communications controller";
|
||||
}
|
||||
|
||||
#endif
|
||||
333
IBM360/ibm360_con.c
Normal file
333
IBM360/ibm360_con.c
Normal file
@ -0,0 +1,333 @@
|
||||
/* ibm360_urec.c: IBM 360 Unit record devices.
|
||||
|
||||
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.
|
||||
|
||||
This is the standard card reader.
|
||||
This is the standard card punch.
|
||||
This is the standard line printer.
|
||||
This is the standard inquiry or console interface.
|
||||
|
||||
These units each buffer one record in local memory and signal
|
||||
ready when the buffer is full or empty. The channel must be
|
||||
ready to recieve/transmit data when they are activated since
|
||||
they will transfer their block during chan_cmd. All data is
|
||||
transmitted as BCD characters.
|
||||
|
||||
*/
|
||||
|
||||
#include "ibm360_defs.h"
|
||||
#include "sim_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef NUM_DEVS_CON
|
||||
|
||||
/* Held in u3 */
|
||||
#define CHN_SNS 0x04 /* Sense command */
|
||||
#define CON_WR 0x01 /* Write console */
|
||||
#define CON_ACR 0x09 /* Auto carrage return */
|
||||
#define CON_RD 0x0a /* Read console */
|
||||
#define CON_NOP 0x03 /* No op command */
|
||||
#define CON_MSK 0x0f /* Command mask */
|
||||
|
||||
/* Status held in u3 */
|
||||
#define CON_INPUT 0x100 /* Input ready for unit */
|
||||
#define CON_CR 0x200 /* Output at beginning of line */
|
||||
#define CON_REQ 0x400 /* Request key pressed */
|
||||
|
||||
/* Input buffer pointer held in u4 */
|
||||
|
||||
/* in u5 packs sense byte 0,1 and 3 */
|
||||
/* Sense byte 0 */
|
||||
#define SNS_CMDREJ 0x80 /* Command reject */
|
||||
#define SNS_INTVENT 0x40 /* Unit intervention required */
|
||||
|
||||
|
||||
|
||||
/* std devices. data structures
|
||||
|
||||
con_dev Console device descriptor
|
||||
con_unit Console unit descriptor
|
||||
con_reg Console register list
|
||||
con_mod Console modifiers list
|
||||
*/
|
||||
|
||||
|
||||
struct _con_data
|
||||
{
|
||||
uint8 ibuff[145]; /* Input line buffer */
|
||||
uint8 inptr;
|
||||
}
|
||||
con_data[NUM_DEVS_CON];
|
||||
|
||||
uint8 con_startcmd(UNIT *, uint16, uint8);
|
||||
void con_ini(UNIT *, t_bool);
|
||||
t_stat con_srv(UNIT *);
|
||||
t_stat con_reset(DEVICE *);
|
||||
t_stat con_attach(UNIT *, char *);
|
||||
t_stat con_detach(UNIT *);
|
||||
|
||||
|
||||
UNIT con_unit[] = {
|
||||
{UDATA(con_srv, 0, 0), 0, UNIT_ADDR(0x1F)}, /* A */
|
||||
};
|
||||
|
||||
struct dib con_dib = { 0xFF, 1, NULL, con_startcmd, NULL, con_unit, con_ini};
|
||||
|
||||
DEVICE con_dev = {
|
||||
"INQ", con_unit, NULL, NULL,
|
||||
NUM_DEVS_CON, 8, 15, 1, 8, 8,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
&con_dib, DEV_UADDR | DEV_DISABLE | DEV_DEBUG, 0, dev_debug
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Console printer routines.
|
||||
*/
|
||||
void
|
||||
con_ini(UNIT *uptr, t_bool f) {
|
||||
int u = (uptr - con_unit);
|
||||
con_data[u].inptr = 0;
|
||||
uptr->u5 = 0;
|
||||
sim_activate(uptr, 1000);
|
||||
}
|
||||
|
||||
uint8 con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
|
||||
int u = (uptr - con_unit);
|
||||
uint8 ch;
|
||||
|
||||
if ((uptr->u3 & CON_MSK) != 0)
|
||||
return SNS_BSY;
|
||||
|
||||
if ((cmd & 0xf0) != 0) {
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
}
|
||||
|
||||
switch (cmd & 0x7) {
|
||||
case 2: /* Read command */
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: Cmd RD\n", u);
|
||||
if (uptr->u3 & CON_REQ) {
|
||||
return SNS_ATTN|SNS_BSY;
|
||||
}
|
||||
|
||||
if ((uptr->u3 & CON_INPUT) == 0 &&
|
||||
(con_data[u].inptr == 0 || uptr->u3 & CON_CR)) {
|
||||
/* Activate input so we can get response */
|
||||
sim_putchar('I');
|
||||
sim_putchar(' ');
|
||||
uptr->u5 &= ~CON_CR;
|
||||
}
|
||||
uptr->u4 = 0;
|
||||
uptr->u3 |= cmd & CON_MSK;
|
||||
uptr->u5 = 0;
|
||||
return 0;
|
||||
|
||||
case 1: /* Write command */
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: Cmd WR\n", u);
|
||||
if (uptr->u3 & CON_REQ) {
|
||||
return SNS_ATTN|SNS_BSY;
|
||||
}
|
||||
uptr->u3 |= cmd & CON_MSK;
|
||||
uptr->u5 = 0;
|
||||
if (uptr->u3 & CON_CR) {
|
||||
sim_putchar('R');
|
||||
sim_putchar(' ');
|
||||
uptr->u3 &= ~CON_CR;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 3: /* Control */
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: Cmd NOP\n", u);
|
||||
if (uptr->u3 & CON_REQ) {
|
||||
return SNS_ATTN|SNS_BSY;
|
||||
}
|
||||
uptr->u5 = 0;
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
|
||||
case 0: /* Status */
|
||||
break;
|
||||
|
||||
case 4: /* Sense */
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: Cmd SNS %02x\n", u, uptr->u5);
|
||||
/* Check if request pending */
|
||||
ch = uptr->u5;
|
||||
chan_write_byte(GET_UADDR(uptr->u3), &ch);
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
|
||||
default: /* invalid command */
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
break;
|
||||
}
|
||||
|
||||
if (uptr->u5)
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
}
|
||||
|
||||
/* Handle transfer of data for printer */
|
||||
t_stat
|
||||
con_srv(UNIT *uptr) {
|
||||
uint16 addr = GET_UADDR(uptr->u3);
|
||||
int u = (uptr - con_unit);
|
||||
int cmd = uptr->u3 & CON_MSK;
|
||||
t_stat r = SCPE_ARG; /* Force error if not set */
|
||||
uint8 ch;
|
||||
int i;
|
||||
|
||||
|
||||
switch (cmd) {
|
||||
case CON_WR:
|
||||
case CON_ACR:
|
||||
if (chan_read_byte(addr, &ch)) {
|
||||
if (cmd == CON_ACR) {
|
||||
sim_putchar('\r');
|
||||
sim_putchar('\n');
|
||||
uptr->u3 |= CON_CR;
|
||||
}
|
||||
uptr->u3 &= ~CON_MSK;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
} else {
|
||||
ch = ebcdic_to_ascii[ch];
|
||||
if (!isprint(ch))
|
||||
ch = '_';
|
||||
sim_putchar(ch);
|
||||
}
|
||||
break;
|
||||
|
||||
case CON_RD:
|
||||
if (uptr->u3 & CON_INPUT) {
|
||||
uptr->u3 &= ~CON_REQ;
|
||||
if (con_data[u].inptr == 0) {
|
||||
uptr->u3 &= ~CON_INPUT;
|
||||
con_data[u].inptr = 0;
|
||||
cmd = 0;
|
||||
uptr->u3 &= ~(CON_MSK);
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: devend\n", u);
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
break;
|
||||
}
|
||||
|
||||
ch = con_data[u].ibuff[uptr->u4++];
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: rd %02x\n", u, ch);
|
||||
if (chan_write_byte(addr, &ch)) {
|
||||
uptr->u3 &= ~CON_INPUT;
|
||||
con_data[u].inptr = 0;
|
||||
cmd = 0;
|
||||
uptr->u3 &= ~(CON_MSK);
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: devend input\n", u);
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
} else {
|
||||
if (uptr->u4 == con_data[u].inptr) {
|
||||
uptr->u3 &= ~CON_INPUT;
|
||||
con_data[u].inptr = 0;
|
||||
cmd = 0;
|
||||
uptr->u3 &= ~(CON_MSK);
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: devend\n", u);
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
r = sim_poll_kbd();
|
||||
if (r & SCPE_KFLAG) {
|
||||
ch = r & 0377;
|
||||
if ((uptr->u3 & CON_INPUT) == 0) {
|
||||
/* Handle end of buffer */
|
||||
switch (ch) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: ent\n", u);
|
||||
// if (con_data[u].inptr != 0)
|
||||
uptr->u3 |= CON_INPUT;
|
||||
uptr->u3 |= CON_CR;
|
||||
sim_putchar('\r');
|
||||
sim_putchar('\n');
|
||||
/* Fall through */
|
||||
|
||||
case 033: /* request key */
|
||||
if (cmd != CON_RD) {
|
||||
uptr->u3 |= CON_REQ;
|
||||
}
|
||||
break;
|
||||
case 0177:
|
||||
case '\b':
|
||||
if (con_data[u].inptr != 0) {
|
||||
con_data[u].inptr--;
|
||||
sim_putchar('\b');
|
||||
sim_putchar(' ');
|
||||
sim_putchar('\b');
|
||||
}
|
||||
break;
|
||||
case 030: /* ^X Post external interrupt */
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: ext\n", u);
|
||||
post_extirq();
|
||||
break;
|
||||
case 03: /* ^C */
|
||||
case 025: /* ^U clear line */
|
||||
for (i = con_data[u].inptr; i> 0; i--) {
|
||||
sim_putchar('\b');
|
||||
sim_putchar(' ');
|
||||
sim_putchar('\b');
|
||||
}
|
||||
con_data[u].inptr = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: key '%c'\n", u, ch);
|
||||
if (con_data[u].inptr < sizeof(con_data[u].ibuff)) {
|
||||
ch = ascii_to_ebcdic[ch];
|
||||
if (ch == 0xff) {
|
||||
sim_putchar('\007');
|
||||
break;
|
||||
}
|
||||
sim_putchar(ebcdic_to_ascii[ch]);
|
||||
con_data[u].ibuff[con_data[u].inptr++] = ch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (cmd == CON_RD && ch == 03) { /* Cancel */
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP);
|
||||
uptr->u3 &= ~CON_INPUT;
|
||||
con_data[u].inptr = 0;
|
||||
cmd = 0;
|
||||
} else {
|
||||
sim_putchar('\007');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == 0 && uptr->u3 & CON_REQ) {
|
||||
sim_debug(DEBUG_CMD, &con_dev, "%d: setattn %x\n", u, addr);
|
||||
set_devattn(addr, SNS_ATTN);
|
||||
uptr->u3 &= ~CON_REQ;
|
||||
}
|
||||
sim_activate(uptr, 500);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
2152
IBM360/ibm360_cpu.c
Normal file
2152
IBM360/ibm360_cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
1295
IBM360/ibm360_dasd.c
Normal file
1295
IBM360/ibm360_dasd.c
Normal file
File diff suppressed because it is too large
Load Diff
372
IBM360/ibm360_defs.h
Normal file
372
IBM360/ibm360_defs.h
Normal file
@ -0,0 +1,372 @@
|
||||
/* ibm360_defs.h: IBM 360 simulator definitions
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator defns */
|
||||
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_IONRDY 1 /* I/O dev not ready */
|
||||
#define STOP_HALT 2 /* HALT */
|
||||
#define STOP_IBKPT 3 /* breakpoint */
|
||||
#define STOP_UUO 4 /* invalid opcode */
|
||||
#define STOP_INVINS 5 /* invalid instr */
|
||||
#define STOP_INVIOP 6 /* invalid I/O op */
|
||||
#define STOP_INDLIM 7 /* indirect limit */
|
||||
#define STOP_XECLIM 8 /* XEC limit */
|
||||
#define STOP_IOCHECK 9 /* IOCHECK */
|
||||
#define STOP_MMTRP 10 /* mm in trap */
|
||||
#define STOP_TRPINS 11 /* trap inst not BRM */
|
||||
#define STOP_RTCINS 12 /* rtc inst not MIN/SKR */
|
||||
#define STOP_ILLVEC 13 /* zero vector */
|
||||
#define STOP_CCT 14 /* runaway CCT */
|
||||
|
||||
/* Conditional error returns */
|
||||
|
||||
/* Memory */
|
||||
|
||||
#define MAXMEMSIZE (16*1024*1024) /* max memory size */
|
||||
#define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */
|
||||
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
|
||||
#define MEM_ADDR_OK(x) (((x)) < MEMSIZE)
|
||||
|
||||
/* Device information block */
|
||||
typedef struct dib {
|
||||
uint8 mask; /* Device mask */
|
||||
uint8 numunits; /* Number of units */
|
||||
/* Start I/O */
|
||||
uint8 (*start_io)(UNIT *uptr, uint16 chan);
|
||||
/* Start a command */
|
||||
uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd);
|
||||
/* Stop I/O */
|
||||
uint8 (*halt_io)(UNIT *uptr);
|
||||
UNIT *units; /* Pointer to units structure */
|
||||
void (*dev_ini)(UNIT *, t_bool);
|
||||
|
||||
} DIB;
|
||||
|
||||
#define DEV_V_ADDR DEV_V_UF /* Pointer to device address */
|
||||
#define DEV_ADDR_MASK (0x7ff << DEV_V_ADDR)
|
||||
#define DEV_V_UADDR (DEV_V_UF + 12) /* Device address in Unit */
|
||||
#define DEV_UADDR (1 << DEV_V_UADDR)
|
||||
#define GET_DADDR(x) (0x7ff & ((x) >> DEV_V_ADDR))
|
||||
#define DEV_ADDR(x) ((x) << DEV_V_ADDR)
|
||||
|
||||
#define UNIT_V_ADDR 21
|
||||
#define UNIT_ADDR_MASK (0x7ff << UNIT_V_ADDR)
|
||||
#define GET_UADDR(x) ((UNIT_ADDR_MASK & x) >> UNIT_V_ADDR)
|
||||
#define UNIT_ADDR(x) ((x) << UNIT_V_ADDR)
|
||||
|
||||
#define PROTECT_V UNIT_V_UF+12
|
||||
#define PROTECT (1 << PROTECT_V)
|
||||
|
||||
/* Arithmetic */
|
||||
|
||||
/* Instruction format */
|
||||
|
||||
/* Globally visible flags */
|
||||
|
||||
/* I/O routine functions */
|
||||
|
||||
|
||||
/* low addresses */
|
||||
#define IPSW 0x00 /* IPSW */
|
||||
#define ICCW1 0x08 /* ICCW1 */
|
||||
#define ICCW2 0x10 /* ICCW2 */
|
||||
#define OEPSW 0x18 /* Exteranl old PSW */
|
||||
#define OSPSW 0x20 /* Supervisior call old PSW */
|
||||
#define OPPSW 0x28 /* Program old PSW */
|
||||
#define OMPSW 0x30 /* Machine check PSW */
|
||||
#define OIOPSW 0x38 /* IO old PSW */
|
||||
#define CSW 0x40 /* CSW */
|
||||
#define CAW 0x48 /* CAW */
|
||||
#define TIMER 0x50 /* timer */
|
||||
#define NEPSW 0x58 /* External new PSW */
|
||||
#define NSPSW 0x60 /* SVC new PSW */
|
||||
#define NPPSW 0x68 /* Program new PSW */
|
||||
#define NMPSW 0x70 /* Machine Check PSW */
|
||||
#define NIOPSW 0x78 /* IOPSW */
|
||||
#define DIAGAREA 0x80 /* Diag scan area. */
|
||||
|
||||
/* Opcode definitions */
|
||||
#define OP_SPM 0x04
|
||||
#define OP_BALR 0x05
|
||||
#define OP_BCTR 0x06
|
||||
#define OP_BCR 0x07
|
||||
#define OP_SSK 0x08
|
||||
#define OP_ISK 0x09
|
||||
#define OP_SVC 0x0A
|
||||
#define OP_LPR 0x10
|
||||
#define OP_LNR 0x11
|
||||
#define OP_LTR 0x12
|
||||
#define OP_LCR 0x13
|
||||
#define OP_NR 0x14
|
||||
#define OP_CLR 0x15
|
||||
#define OP_OR 0x16
|
||||
#define OP_XR 0x17
|
||||
#define OP_CR 0x19
|
||||
#define OP_LR 0x18
|
||||
#define OP_AR 0x1A
|
||||
#define OP_SR 0x1B
|
||||
#define OP_MR 0x1C
|
||||
#define OP_DR 0x1D
|
||||
#define OP_ALR 0x1E
|
||||
#define OP_SLR 0x1F
|
||||
#define OP_LPDR 0x20
|
||||
#define OP_LNDR 0x21
|
||||
#define OP_LTDR 0x22
|
||||
#define OP_LCDR 0x23
|
||||
#define OP_HDR 0x24
|
||||
#define OP_LRDR 0x25
|
||||
#define OP_MXR 0x26
|
||||
#define OP_MXDR 0x27
|
||||
#define OP_LDR 0x28
|
||||
#define OP_CDR 0x29
|
||||
#define OP_ADR 0x2A
|
||||
#define OP_SDR 0x2B
|
||||
#define OP_MDR 0x2C
|
||||
#define OP_DDR 0x2D
|
||||
#define OP_AWR 0x2E
|
||||
#define OP_SWR 0x2F
|
||||
#define OP_LPER 0x30
|
||||
#define OP_LNER 0x31
|
||||
#define OP_LTER 0x32
|
||||
#define OP_LCER 0x33
|
||||
#define OP_HER 0x34
|
||||
#define OP_LRER 0x35
|
||||
#define OP_AXR 0x36
|
||||
#define OP_SXR 0x37
|
||||
#define OP_LER 0x38
|
||||
#define OP_CER 0x39
|
||||
#define OP_AER 0x3A
|
||||
#define OP_SER 0x3B
|
||||
#define OP_MER 0x3C
|
||||
#define OP_DER 0x3D
|
||||
#define OP_AUR 0x3E
|
||||
#define OP_SUR 0x3F
|
||||
#define OP_STH 0x40
|
||||
#define OP_LA 0x41
|
||||
#define OP_STC 0x42
|
||||
#define OP_IC 0x43
|
||||
#define OP_EX 0x44
|
||||
#define OP_BAL 0x45
|
||||
#define OP_BCT 0x46
|
||||
#define OP_BC 0x47
|
||||
#define OP_LH 0x48
|
||||
#define OP_CH 0x49
|
||||
#define OP_AH 0x4A
|
||||
#define OP_SH 0x4B
|
||||
#define OP_MH 0x4C
|
||||
#define OP_CVD 0x4E
|
||||
#define OP_CVB 0x4F
|
||||
#define OP_ST 0x50
|
||||
#define OP_N 0x54
|
||||
#define OP_CL 0x55
|
||||
#define OP_O 0x56
|
||||
#define OP_X 0x57
|
||||
#define OP_L 0x58
|
||||
#define OP_C 0x59
|
||||
#define OP_A 0x5A
|
||||
#define OP_S 0x5B
|
||||
#define OP_M 0x5C
|
||||
#define OP_D 0x5D
|
||||
#define OP_AL 0x5E
|
||||
#define OP_SL 0x5F
|
||||
#define OP_STD 0x60
|
||||
#define OP_MXD 0x67
|
||||
#define OP_LD 0x68
|
||||
#define OP_CD 0x69
|
||||
#define OP_AD 0x6A
|
||||
#define OP_SD 0x6B
|
||||
#define OP_MD 0x6C
|
||||
#define OP_DD 0x6D
|
||||
#define OP_AW 0x6E
|
||||
#define OP_SW 0x6F
|
||||
#define OP_STE 0x70
|
||||
#define OP_LE 0x78
|
||||
#define OP_CE 0x79
|
||||
#define OP_AE 0x7A
|
||||
#define OP_SE 0x7B
|
||||
#define OP_ME 0x7C
|
||||
#define OP_DE 0x7D
|
||||
#define OP_AU 0x7E
|
||||
#define OP_SU 0x7F
|
||||
#define OP_SSM 0x80
|
||||
#define OP_LPSW 0x82
|
||||
#define OP_DIAG 0x83
|
||||
#define OP_BXH 0x86
|
||||
#define OP_BXLE 0x87
|
||||
#define OP_SRL 0x88
|
||||
#define OP_SLL 0x89
|
||||
#define OP_SRA 0x8A
|
||||
#define OP_SLA 0x8B
|
||||
#define OP_SRDL 0x8C
|
||||
#define OP_SLDL 0x8D
|
||||
#define OP_SRDA 0x8E
|
||||
#define OP_SLDA 0x8F
|
||||
#define OP_STM 0x90
|
||||
#define OP_TM 0x91
|
||||
#define OP_MVI 0x92
|
||||
#define OP_TS 0x93
|
||||
#define OP_NI 0x94
|
||||
#define OP_CLI 0x95
|
||||
#define OP_OI 0x96
|
||||
#define OP_XI 0x97
|
||||
#define OP_LM 0x98
|
||||
#define OP_SIO 0x9C
|
||||
#define OP_TIO 0x9D
|
||||
#define OP_HIO 0x9E
|
||||
#define OP_TCH 0x9F
|
||||
#define OP_MVN 0xD1
|
||||
#define OP_MVC 0xD2
|
||||
#define OP_MVZ 0xD3
|
||||
#define OP_NC 0xD4
|
||||
#define OP_CLC 0xD5
|
||||
#define OP_OC 0xD6
|
||||
#define OP_XC 0xD7
|
||||
#define OP_TR 0xDC
|
||||
#define OP_TRT 0xDD
|
||||
#define OP_ED 0xDE
|
||||
#define OP_EDMK 0xDF
|
||||
#define OP_MVO 0xF1
|
||||
#define OP_PACK 0xF2
|
||||
#define OP_UNPK 0xF3
|
||||
#define OP_ZAP 0xF8
|
||||
#define OP_CP 0xF9
|
||||
#define OP_AP 0xFA
|
||||
#define OP_SP 0xFB
|
||||
#define OP_MP 0xFC
|
||||
#define OP_DP 0xFD
|
||||
|
||||
/* Channel sense bytes */
|
||||
#define SNS_ATTN 0x80 /* Unit attention */
|
||||
#define SNS_SMS 0x40 /* Status modifier */
|
||||
#define SNS_CTLEND 0x20 /* Control unit end */
|
||||
#define SNS_BSY 0x10 /* Unit Busy */
|
||||
#define SNS_CHNEND 0x08 /* Channel end */
|
||||
#define SNS_DEVEND 0x04 /* Device end */
|
||||
#define SNS_UNITCHK 0x02 /* Unit check */
|
||||
#define SNS_UNITEXP 0x01 /* Unit exception */
|
||||
|
||||
/* Command masks */
|
||||
#define CMD_TYPE 0x3 /* Type mask */
|
||||
#define CMD_CHAN 0x0 /* Channel command */
|
||||
#define CMD_WRITE 0x1 /* Write command */
|
||||
#define CMD_READ 0x2 /* Read command */
|
||||
#define CMD_CTL 0x3 /* Control command */
|
||||
#define CMD_SENSE 0x4 /* Sense channel command */
|
||||
#define CMD_TIC 0x8 /* Transfer in channel */
|
||||
#define CMD_RDBWD 0xc /* Read backward */
|
||||
|
||||
#define STATUS_ATTN 0x8000 /* Device raised attention */
|
||||
#define STATUS_MOD 0x4000 /* Status modifier */
|
||||
#define STATUS_CTLEND 0x2000 /* Control end */
|
||||
#define STATUS_BUSY 0x1000 /* Device busy */
|
||||
#define STATUS_CEND 0x0800 /* Channel end */
|
||||
#define STATUS_DEND 0x0400 /* Device end */
|
||||
#define STATUS_CHECK 0x0200 /* Unit check */
|
||||
#define STATUS_EXPT 0x0100 /* Unit excpetion */
|
||||
#define STATUS_PCI 0x0080 /* Program interupt */
|
||||
#define STATUS_LENGTH 0x0040 /* Incorrect lenght */
|
||||
#define STATUS_PCHK 0x0020 /* Program check */
|
||||
#define STATUS_PROT 0x0010 /* Protection check */
|
||||
#define STATUS_CDATA 0x0008 /* Channel data check */
|
||||
#define STATUS_CCNTL 0x0004 /* Channel control check */
|
||||
#define STATUS_INTER 0x0002 /* Channel interface check */
|
||||
#define STATUS_CHAIN 0x0001 /* Channel chain check */
|
||||
|
||||
/* channel:
|
||||
subchannels = 128
|
||||
0 - 7 0x80-0xff
|
||||
8 - 127 0x00-0x7f
|
||||
128 - +6 0x1xx - 0x6xx
|
||||
|
||||
Devices on channel 0 below number of subchannels have there own
|
||||
virtual channel.
|
||||
Devices on channel 0 above the number of subchannels are mapped in
|
||||
groups of 16 into channels 0 to n.
|
||||
|
||||
Channels 1-n run on channels virtual channels above subchannels.
|
||||
*/
|
||||
|
||||
#define MAX_CHAN 3
|
||||
#define SUB_CHANS 128
|
||||
|
||||
void post_extirq();
|
||||
|
||||
/* look up device to find subchannel device is on */
|
||||
int find_subchan(uint16 device);
|
||||
int chan_read_byte(uint16 chan, uint8 *data);
|
||||
int chan_write_byte(uint16 chan, uint8 *data);
|
||||
void set_devattn(uint16 addr, uint8 flags);
|
||||
void chan_end(uint16 chan, uint8 flags);
|
||||
int startio(uint16 addr) ;
|
||||
int testio(uint16 addr);
|
||||
int haltio(uint16 addr);
|
||||
int testchan(uint16 channel);
|
||||
uint16 scan_chan(uint8 mask);
|
||||
t_stat chan_boot(uint16 addr, DEVICE *dptr);
|
||||
t_stat chan_set_devs();
|
||||
t_stat set_dev_addr(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
|
||||
t_stat show_dev_addr(FILE * st, UNIT * uptr, int32 v, CONST void *desc);
|
||||
uint16 loading;
|
||||
int irq_pend;
|
||||
|
||||
const char ascii_to_ebcdic[128];
|
||||
const char ebcdic_to_ascii[256];
|
||||
|
||||
/* Debuging controls */
|
||||
#define DEBUG_CMD 0x0000001 /* Show device commands */
|
||||
#define DEBUG_DATA 0x0000002 /* Show data transfers */
|
||||
#define DEBUG_DETAIL 0x0000004 /* Show details */
|
||||
#define DEBUG_EXP 0x0000008 /* Show error conditions */
|
||||
#define DEBUG_CONI 0x0000020 /* Show CONI instructions */
|
||||
#define DEBUG_CONO 0x0000040 /* Show CONO instructions */
|
||||
#define DEBUG_DATAIO 0x0000080 /* Show DATAI/O instructions */
|
||||
#define DEBUG_IRQ 0x0000100 /* Show IRQ requests */
|
||||
|
||||
extern DEBTAB dev_debug[];
|
||||
extern DEBTAB crd_debug[];
|
||||
|
||||
extern DEVICE cdp_dev;
|
||||
extern DEVICE cdr_dev;
|
||||
extern DEVICE lpr_dev;
|
||||
extern DEVICE con_dev;
|
||||
extern DEVICE mta_dev;
|
||||
extern DEVICE mtb_dev;
|
||||
extern DEVICE dda_dev;
|
||||
extern DEVICE ddb_dev;
|
||||
extern DEVICE com_dev;
|
||||
|
||||
#define NUM_DEVS_CDP 1
|
||||
#define NUM_DEVS_CDR 1
|
||||
#define NUM_DEVS_CON 1
|
||||
#define NUM_DEVS_LPR 1
|
||||
#define NUM_DEVS_MT 1
|
||||
#define NUM_UNITS_MT 8
|
||||
#define NUM_DEVS_DASD 2
|
||||
#define NUM_UNITS_DASD 8
|
||||
#define NUM_DEVS_COM 1
|
||||
#define NUM_UNITS_COM 16
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern void fprint_inst(FILE *, uint16 *);
|
||||
288
IBM360/ibm360_lpr.c
Normal file
288
IBM360/ibm360_lpr.c
Normal file
@ -0,0 +1,288 @@
|
||||
/* ibm360_urec.c: IBM 360 Line Printer
|
||||
|
||||
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.
|
||||
|
||||
This is the standard line printer.
|
||||
This is the standard inquiry or console interface.
|
||||
|
||||
These units each buffer one record in local memory and signal
|
||||
ready when the buffer is full or empty. The channel must be
|
||||
ready to recieve/transmit data when they are activated since
|
||||
they will transfer their block during chan_cmd. All data is
|
||||
transmitted as BCD characters.
|
||||
|
||||
*/
|
||||
|
||||
#include "ibm360_defs.h"
|
||||
#include "sim_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef NUM_DEVS_LPR
|
||||
#define UNIT_LPR UNIT_ATTABLE | UNIT_DISABLE
|
||||
|
||||
|
||||
/* u3 hold command and status information */
|
||||
#define CHN_SNS 0x04 /* Sense command */
|
||||
|
||||
#define LPR_WR 0x01 /* Write command */
|
||||
#define LPR_SPKCMD 0x03 /* Skip command */
|
||||
#define LPR_SPCMSK 0x18 /* Space after printing */
|
||||
#define LPR_SKIP 0x80 /* Skip Flag */
|
||||
#define LPR_SKPCHN 0x78 /* Skip Channel */
|
||||
#define LPR_CMDMSK 0xff /* Mask command part. */
|
||||
#define LPR_FULL 0x100 /* Buffer full */
|
||||
|
||||
/* u4 holds current line */
|
||||
/* in u5 packs sense byte 0,1 and 3 */
|
||||
/* Sense byte 0 */
|
||||
#define SNS_CMDREJ 0x80 /* Command reject */
|
||||
#define SNS_INTVENT 0x40 /* Unit intervention required */
|
||||
#define SNS_BUSCHK 0x20 /* Parity error on bus */
|
||||
#define SNS_EQUCHK 0x10 /* Equipment check */
|
||||
#define SNS_DATCHK 0x08 /* Data Check */
|
||||
#define SNS_OVRRUN 0x04 /* Data overrun */
|
||||
#define SNS_SEQUENCE 0x02 /* Unusual sequence */
|
||||
#define SNS_CHN9 0x01 /* Channel 9 on printer */
|
||||
/* u6 hold buffer position */
|
||||
|
||||
|
||||
/* std devices. data structures
|
||||
|
||||
lpr_dev Line Printer device descriptor
|
||||
lpr_unit Line Printer unit descriptor
|
||||
lpr_reg Line Printer register list
|
||||
lpr_mod Line Printer modifiers list
|
||||
*/
|
||||
|
||||
|
||||
struct _lpr_data
|
||||
{
|
||||
uint8 lbuff[145]; /* Output line buffer */
|
||||
uint8 fcs[256]; /* Form control buffer */
|
||||
}
|
||||
lpr_data[NUM_DEVS_LPR];
|
||||
|
||||
uint8 lpr_startcmd(UNIT *, uint16, uint8);
|
||||
void lpr_ini(UNIT *, t_bool);
|
||||
t_stat lpr_srv(UNIT *);
|
||||
t_stat lpr_reset(DEVICE *);
|
||||
t_stat lpr_attach(UNIT *, CONST char *);
|
||||
t_stat lpr_detach(UNIT *);
|
||||
t_stat lpr_setlpp(UNIT *, int32, CONST char *, void *);
|
||||
t_stat lpr_getlpp(FILE *, UNIT *, int32, CONST void *);
|
||||
|
||||
UNIT lpr_unit[] = {
|
||||
{UDATA(lpr_srv, UNIT_LPR, 55), 300, UNIT_ADDR(0x0E)}, /* A */
|
||||
#if NUM_DEVS_LPR > 1
|
||||
{UDATA(lpr_srv, UNIT_LPR, 55), 300, UNIT_ADDR(0x1E)}, /* B */
|
||||
#endif
|
||||
};
|
||||
|
||||
MTAB lpr_mod[] = {
|
||||
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LINESPERPAGE", "LINESPERPAGE",
|
||||
&lpr_setlpp, &lpr_getlpp, NULL, "Number of lines per page"},
|
||||
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr,
|
||||
&show_dev_addr, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct dib lpr_dib = { 0xFF, 1, NULL, lpr_startcmd, NULL, lpr_unit};
|
||||
|
||||
DEVICE lpr_dev = {
|
||||
"LPR", lpr_unit, NULL, lpr_mod,
|
||||
NUM_DEVS_LPR, 8, 15, 1, 8, 8,
|
||||
NULL, NULL, NULL, NULL, &lpr_attach, &lpr_detach,
|
||||
&lpr_dib, DEV_UADDR | DEV_DISABLE | DEV_DEBUG, 0, dev_debug
|
||||
};
|
||||
|
||||
|
||||
/* Line printer routines
|
||||
*/
|
||||
|
||||
t_stat
|
||||
lpr_setlpp(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
int i;
|
||||
if (cptr == NULL)
|
||||
return SCPE_ARG;
|
||||
if (uptr == NULL)
|
||||
return SCPE_IERR;
|
||||
i = 0;
|
||||
while(*cptr != '\0') {
|
||||
if (*cptr < '0' || *cptr > '9')
|
||||
return SCPE_ARG;
|
||||
i = (i * 10) + (*cptr++) - '0';
|
||||
}
|
||||
if (i < 20 || i > 100)
|
||||
return SCPE_ARG;
|
||||
uptr->capac = i;
|
||||
uptr->u4 = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
lpr_getlpp(FILE *st, UNIT *uptr, int32 v, CONST void *desc)
|
||||
{
|
||||
if (uptr == NULL)
|
||||
return SCPE_IERR;
|
||||
fprintf(st, "linesperpage=%d", uptr->capac);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
void
|
||||
print_line(UNIT * uptr)
|
||||
{
|
||||
|
||||
char out[150]; /* Temp conversion buffer */
|
||||
int i;
|
||||
int u = (uptr - lpr_unit);
|
||||
|
||||
/* Try to convert to text */
|
||||
memset(out, ' ', sizeof(out));
|
||||
|
||||
/* Scan each column */
|
||||
for (i = 0; i < uptr->u6; i++) {
|
||||
int ch = lpr_data[u].lbuff[i];
|
||||
|
||||
ch = ebcdic_to_ascii[ch];
|
||||
if (!isprint(ch))
|
||||
ch = '.';
|
||||
out[i] = ch;
|
||||
}
|
||||
|
||||
/* Trim trailing spaces */
|
||||
for (--i; i > 0 && out[i] == ' '; i--) ;
|
||||
out[++i] = '\n';
|
||||
out[++i] = '\r';
|
||||
out[++i] = '\0';
|
||||
|
||||
/* Print out buffer */
|
||||
sim_fwrite(&out, 1, i, uptr->fileref);
|
||||
fprintf(stderr, "%s", out);
|
||||
uptr->u4++;
|
||||
if (uptr->u4 > uptr->capac) {
|
||||
uptr->u4 = 1;
|
||||
}
|
||||
|
||||
memset(&lpr_data[u].lbuff[0], 0, 144);
|
||||
}
|
||||
|
||||
|
||||
uint8 lpr_startcmd(UNIT * uptr, uint16 chan, uint8 cmd)
|
||||
{
|
||||
uint8 ch;
|
||||
|
||||
if ((uptr->u3 & LPR_CMDMSK) != 0) {
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
return SNS_BSY;
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
}
|
||||
|
||||
switch (cmd & 0x7) {
|
||||
case 1: /* Write command */
|
||||
case 3:
|
||||
uptr->u3 &= ~(LPR_CMDMSK);
|
||||
uptr->u3 |= (cmd & LPR_CMDMSK);
|
||||
sim_activate(uptr, 10); /* Start unit off */
|
||||
uptr->u5 = 0;
|
||||
uptr->u6 = 0;
|
||||
return 0;
|
||||
|
||||
case 0: /* Status */
|
||||
break;
|
||||
|
||||
case 4: /* Sense */
|
||||
uptr->u3 &= ~(LPR_CMDMSK);
|
||||
uptr->u3 |= (cmd & LPR_CMDMSK);
|
||||
sim_activate(uptr, 10); /* Start unit off */
|
||||
return 0;
|
||||
|
||||
default: /* invalid command */
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
break;
|
||||
}
|
||||
if (uptr->u5 & 0xff)
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
}
|
||||
|
||||
/* Handle transfer of data for printer */
|
||||
t_stat
|
||||
lpr_srv(UNIT *uptr) {
|
||||
int addr = GET_UADDR(uptr->u3);
|
||||
int u = (uptr - lpr_unit);
|
||||
|
||||
if ((uptr->u3 & 0xFF) == 4) {
|
||||
uint8 ch = uptr->u5;
|
||||
chan_write_byte(GET_UADDR(uptr->u3), &ch);
|
||||
chan_end(addr, SNS_DEVEND|SNS_CHNEND);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if ((uptr->u3 & LPR_FULL) || (uptr->u3 & 0x7) == 0x3) {
|
||||
print_line(uptr);
|
||||
uptr->u3 &= ~(LPR_FULL|LPR_CMDMSK);
|
||||
uptr->u6 = 0;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
// set_devattn(addr, SNS_DEVEND);
|
||||
}
|
||||
|
||||
/* Copy next column over */
|
||||
if ((uptr->u3 & 0x7) == 1 && uptr->u6 < 144) {
|
||||
if(chan_read_byte(addr, &lpr_data[u].lbuff[uptr->u6++])) {
|
||||
uptr->u3 |= LPR_FULL;
|
||||
} else {
|
||||
sim_activate(uptr, 10);
|
||||
}
|
||||
if (uptr->u3 & LPR_FULL || uptr->u6 >= 144) {
|
||||
uptr->u3 |= LPR_FULL;
|
||||
// chan_end(addr, SNS_CHNEND);
|
||||
sim_activate(uptr, 1000);
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
void
|
||||
lpr_ini(UNIT *uptr, t_bool f) {
|
||||
}
|
||||
|
||||
t_stat
|
||||
lpr_attach(UNIT * uptr, CONST char *file)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
if ((r = attach_unit(uptr, file)) != SCPE_OK)
|
||||
return r;
|
||||
uptr->u3 &= ~(LPR_FULL|LPR_CMDMSK);
|
||||
uptr->u4 = 0;
|
||||
uptr->u5 = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
lpr_detach(UNIT * uptr)
|
||||
{
|
||||
if (uptr->u3 & LPR_FULL)
|
||||
print_line(uptr);
|
||||
return detach_unit(uptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
891
IBM360/ibm360_mt.c
Normal file
891
IBM360/ibm360_mt.c
Normal file
@ -0,0 +1,891 @@
|
||||
/* ibm360_mt.c: IBM 360 2400 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 "ibm360_defs.h"
|
||||
#include "sim_tape.h"
|
||||
|
||||
#ifdef NUM_DEVS_MT
|
||||
#define BUFFSIZE (64 * 1024)
|
||||
#define MTUF_9TR (1 << MTUF_V_UF)
|
||||
#define UNIT_MT UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | MTUF_9TR
|
||||
#define DEV_BUF_NUM(x) (((x) & 07) << DEV_V_UF)
|
||||
#define GET_DEV_BUF(x) (((x) >> DEV_V_UF) & 07)
|
||||
|
||||
|
||||
|
||||
#define MT_WRITE 0x01 /* Write command */
|
||||
#define MT_READ 0x02 /* Read command */
|
||||
#define MT_RDBK 0x0c /* Read Backward */
|
||||
#define MT_SENSE 0x04 /* Sense command */
|
||||
#define MT_REW 0x07 /* Rewind command */
|
||||
#define MT_RUN 0x0f /* Rewind and unload */
|
||||
#define MT_ERG 0x17 /* Erase Gap */
|
||||
#define MT_WTM 0x1f /* Write Tape Mark */
|
||||
#define MT_BSR 0x27 /* Back space record */
|
||||
#define MT_BSF 0x2f /* Back space file */
|
||||
#define MT_FSR 0x37 /* Forward space record */
|
||||
#define MT_FSF 0x3f /* Forward space file */
|
||||
#define MT_MODE 0x03 /* Mode command */
|
||||
#define MT_MODEMSK 0x07 /* Mode Mask */
|
||||
|
||||
#define MT_MDEN_200 0x00 /* 200 BPI mode 7 track only */
|
||||
#define MT_MDEN_556 0x40 /* 556 BPI mode 7 track only */
|
||||
#define MT_MDEN_800 0x80 /* 800 BPI mode 7 track only */
|
||||
#define MT_MDEN_1600 0xc0 /* 1600 BPI mode 9 track only */
|
||||
#define MT_MDEN_MSK 0xc0 /* Density mask */
|
||||
|
||||
#define MT_CTL_MSK 0x38 /* Mask for control flags */
|
||||
#define MT_CTL_NOP 0x00 /* Nop control mode */
|
||||
#define MT_CTL_NRZI 0x08 /* 9 track 800 bpi mode */
|
||||
#define MT_CTL_RST 0x10 /* Set density, odd, convert on, trans off */
|
||||
#define MT_CTL_NOP2 0x18 /* 9 track 1600 NRZI mode */
|
||||
#define MT_CTL_MD0 0x20 /* Set density, even, convert off, trans off */
|
||||
#define MT_CTL_MD1 0x28 /* Set density, even, convert off, trans on */
|
||||
#define MT_CTL_MD2 0x30 /* Set density, odd, convert off, trans off */
|
||||
#define MT_CTL_MD3 0x38 /* Set density, odd, convert off, trans on */
|
||||
|
||||
/* in u3 is device command code and status */
|
||||
#define MT_CMDMSK 0x003f /* Command being run */
|
||||
#define MT_READDONE 0x0400 /* Read finished, end channel */
|
||||
#define MT_MARK 0x0800 /* Sensed tape mark in move command */
|
||||
#define MT_ODD 0x1000 /* Odd parity */
|
||||
#define MT_TRANS 0x2000 /* Translation turned on ignored 9 track */
|
||||
#define MT_CONV 0x4000 /* Data converter on ignored 9 track */
|
||||
#define MT_BUSY 0x8000 /* Flag to send a CUE */
|
||||
#define MT_CHAN_MSK 0xff0000 /* Channel mask */
|
||||
#define MT_CHAN_V 16 /* Channel shift */
|
||||
|
||||
/* in u4 is current buffer position */
|
||||
|
||||
/* in u5 packs sense byte 0,1 and 3 */
|
||||
/* Sense byte 0 */
|
||||
#define SNS_CMDREJ 0x80 /* Command reject */
|
||||
#define SNS_INTVENT 0x40 /* Unit intervention required */
|
||||
#define SNS_BUSCHK 0x20 /* Parity error on bus */
|
||||
#define SNS_EQUCHK 0x10 /* Equipment check */
|
||||
#define SNS_DATCHK 0x08 /* Data Check */
|
||||
#define SNS_OVRRUN 0x04 /* Data overrun */
|
||||
#define SNS_WCZERO 0x02 /* Write with no data */
|
||||
#define SNS_CVTCHK 0x01 /* Data conversion error */
|
||||
|
||||
/* Sense byte 1 */
|
||||
#define SNS_NOISE 0x80 /* Noise record */
|
||||
#define SNS_TUASTA 0x40 /* Selected and ready */
|
||||
#define SNS_TUBSTA 0x20 /* Not ready, rewinding. */
|
||||
#define SNS_7TRACK 0x10 /* Seven track unit */
|
||||
#define SNS_LOAD 0x08 /* Load Point */
|
||||
#define SNS_WR 0x04 /* Unit write */
|
||||
#define SNS_WRP 0x02 /* No write ring */
|
||||
#define SNS_DENS 0x01 /* Density error 9tr only */
|
||||
|
||||
/* Sense byte 2 */
|
||||
#define SNS_BYTE2 0xc0 /* Not supported feature */
|
||||
|
||||
/* Sense byte 3 */
|
||||
#define SNS_VRC 0x80 /* Veritical parity error */
|
||||
#define SNS_LRCR 0x40 /* Logituntial parity error */
|
||||
#define SNS_SKEW 0x20 /* Skew */
|
||||
#define SNS_CRC 0x10 /* CRC error. 9t only */
|
||||
#define SNS_SKEWVRC 0x08 /* VRC Skew */
|
||||
#define SNS_PE 0x04 /* Phase encoding */
|
||||
#define SNS_BACK 0x01 /* tape in backward status */
|
||||
|
||||
#define SNS_BYTE4 0x00 /* Hardware errors not supported */
|
||||
#define SNS_BYTE5 0x00 /* Hardware errors not supported */
|
||||
|
||||
#define MT_CONV1 0x40
|
||||
#define MT_CONV2 0x80
|
||||
#define MT_CONV3 0xc0
|
||||
|
||||
/* u6 holds the packed characters and unpack counter */
|
||||
#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF)
|
||||
#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF
|
||||
|
||||
uint8 mt_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) ;
|
||||
t_stat mt_srv(UNIT *);
|
||||
t_stat mt_boot(int32, DEVICE *);
|
||||
void mt_ini(UNIT *, t_bool);
|
||||
t_stat mt_reset(DEVICE *);
|
||||
t_stat mt_attach(UNIT *, CONST char *);
|
||||
t_stat mt_detach(UNIT *);
|
||||
t_stat mt_boot(int32, DEVICE *);
|
||||
|
||||
|
||||
/* One buffer per channel */
|
||||
uint8 mt_buffer[NUM_DEVS_MT][BUFFSIZE];
|
||||
uint8 mt_busy[NUM_DEVS_MT];
|
||||
|
||||
MTAB mt_mod[] = {
|
||||
{MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL},
|
||||
{MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL},
|
||||
{MTUF_9TR, 0, "7 track", "7T", NULL},
|
||||
{MTUF_9TR, MTUF_9TR, "9 track", "9T", NULL},
|
||||
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL},
|
||||
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr,
|
||||
&show_dev_addr, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
UNIT mta_unit[] = {
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x180)}, /* 0 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x181)}, /* 1 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x182)}, /* 2 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x183)}, /* 3 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x184)}, /* 4 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x185)}, /* 5 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x186)}, /* 6 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x187)}, /* 7 */
|
||||
};
|
||||
|
||||
struct dib mta_dib = { 0xF8, NUM_UNITS_MT, NULL, mt_startcmd, NULL, mta_unit, NULL};
|
||||
|
||||
DEVICE mta_dev = {
|
||||
"MTA", mta_unit, NULL, mt_mod,
|
||||
NUM_UNITS_MT, 8, 15, 1, 8, 8,
|
||||
NULL, NULL, &mt_reset, &mt_boot, &mt_attach, &mt_detach,
|
||||
&mta_dib, DEV_BUF_NUM(0) | DEV_DISABLE | DEV_DEBUG, 0, dev_debug
|
||||
};
|
||||
|
||||
#if NUM_DEVS_MT > 1
|
||||
UNIT mtb_unit[] = {
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x280)}, /* 0 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x281)}, /* 1 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x282)}, /* 2 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x283)}, /* 3 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x284)}, /* 4 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x285)}, /* 5 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x286)}, /* 6 */
|
||||
{UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x287)}, /* 7 */
|
||||
};
|
||||
|
||||
struct dib mtb_dib = { 0xF8, NUM_UNITS_MT, NULL, mt_startcmd, NULL, mtb_unit, NULL};
|
||||
|
||||
DEVICE mtb_dev = {
|
||||
"MTB", mtb_unit, NULL, mt_mod,
|
||||
NUM_UNITS_MT, 8, 15, 1, 8, 8,
|
||||
NULL, NULL, &mt_reset, &mt_boot, &mt_attach, &mt_detach,
|
||||
&mtb_dib, DEV_BUF_NUM(1) | DEV_DISABLE | DEV_DEBUG, 0, dev_debug
|
||||
};
|
||||
#endif
|
||||
|
||||
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 bcd_to_ebcdic[64] = {
|
||||
0x40, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xf0, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x7a, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xe0, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x60, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xd0, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x50, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xc0, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f};
|
||||
|
||||
|
||||
uint8 mt_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
|
||||
uint16 addr = GET_UADDR(uptr->u3);
|
||||
DEVICE *dptr = find_dev_from_unit(uptr);
|
||||
int unit = (uptr - dptr->units);
|
||||
uint8 ch;
|
||||
|
||||
if (mt_busy[GET_DEV_BUF(dptr->flags)] != 0 || (uptr->u3 & MT_CMDMSK) != 0) {
|
||||
sim_debug(DEBUG_CMD, dptr, "CMD busy unit=%d %x", unit, cmd);
|
||||
uptr->flags |= MT_BUSY; /* Flag we need to send CUE */
|
||||
mt_busy[GET_DEV_BUF(dptr->flags)] |= 2;
|
||||
return SNS_BSY;
|
||||
}
|
||||
|
||||
sim_debug(DEBUG_CMD, dptr, "CMD unit=%d %x", unit, cmd);
|
||||
|
||||
switch (cmd & 0xF) {
|
||||
case 0x7: /* Tape motion */
|
||||
case 0xf: /* Tape motion */
|
||||
case 0x1: /* Write command */
|
||||
case 0x2: /* Read command */
|
||||
case 0xc: /* Read backward */
|
||||
uptr->u5 = 0;
|
||||
uptr->u5 |= SNS_TUASTA << 8;
|
||||
if ((uptr->flags & MTUF_9TR) == 0)
|
||||
uptr->u5 |= (SNS_7TRACK << 8);
|
||||
if (sim_tape_wrp(uptr))
|
||||
uptr->u5 |= (SNS_WRP << 8);
|
||||
if (sim_tape_bot(uptr))
|
||||
uptr->u5 |= (SNS_LOAD << 8);
|
||||
/* Fall through */
|
||||
|
||||
case 0x4: /* Sense */
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
uptr->u3 |= cmd & MT_CMDMSK;
|
||||
sim_activate(uptr, 1000); /* Start unit off */
|
||||
CLR_BUF(uptr);
|
||||
uptr->u4 = 0;
|
||||
uptr->u6 = 0;
|
||||
mt_busy[GET_DEV_BUF(dptr->flags)] = 1;
|
||||
if ((cmd & 0x7) == 0x7) /* Quick end channel on control */
|
||||
return SNS_CHNEND;
|
||||
return 0;
|
||||
|
||||
case 0x3: /* Control */
|
||||
case 0xb: /* Control */
|
||||
if ((uptr->flags & MTUF_9TR) == 0) {
|
||||
uptr->u5 |= (SNS_7TRACK << 8);
|
||||
if ((cmd & 0x30) == 0)
|
||||
return SNS_DEVEND;
|
||||
if ((cmd & 0x38) == 0x18)
|
||||
return SNS_DEVEND;
|
||||
if ((cmd & 0xc0) != 0xc0) {
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
} else {
|
||||
uptr->u3 &= ~MT_MDEN_MSK;
|
||||
uptr->u3 |= (cmd & MT_MDEN_MSK);
|
||||
}
|
||||
uptr->u3 &= ~(MT_ODD|MT_TRANS);
|
||||
uptr->u3 |= MT_CONV;
|
||||
if (cmd & 0x10)
|
||||
uptr->u3 |= MT_ODD;
|
||||
if (cmd & 0x20)
|
||||
uptr->u3 &= ~MT_CONV;
|
||||
if (cmd & 0x08)
|
||||
uptr->u3 |= MT_TRANS;
|
||||
} else {
|
||||
if ((cmd & 0xf0) != 0xc0) {
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
}
|
||||
uptr->u3 &= ~MT_MDEN_MSK;
|
||||
if (cmd & 0x8)
|
||||
uptr->u3 |= MT_MDEN_800;
|
||||
else
|
||||
uptr->u3 |= MT_MDEN_1600;
|
||||
}
|
||||
uptr->u5 = 0;
|
||||
break;
|
||||
|
||||
case 0x0: /* Status */
|
||||
break;
|
||||
|
||||
default: /* invalid command */
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
break;
|
||||
}
|
||||
if (uptr->u5 & 0xff)
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
return SNS_CHNEND|SNS_DEVEND;
|
||||
}
|
||||
|
||||
/* Map simH errors into machine errors */
|
||||
t_stat mt_error(UNIT * uptr, uint16 addr, t_stat r, DEVICE * dptr)
|
||||
{
|
||||
mt_busy[GET_DEV_BUF(dptr->flags)] &= ~1;
|
||||
switch (r) {
|
||||
case MTSE_OK: /* no error */
|
||||
break;
|
||||
|
||||
case MTSE_TMK: /* tape mark */
|
||||
sim_debug(DEBUG_EXP, dptr, "MARK ");
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP);
|
||||
return SCPE_OK;
|
||||
|
||||
case MTSE_WRP: /* write protected */
|
||||
case MTSE_UNATT: /* unattached */
|
||||
sim_debug(DEBUG_EXP, dptr, "ATTENTION %d ", r);
|
||||
break;
|
||||
|
||||
case MTSE_IOERR: /* IO error */
|
||||
case MTSE_FMT: /* invalid format */
|
||||
case MTSE_RECE: /* error in record */
|
||||
sim_debug(DEBUG_EXP, dptr, "ERROR %d ", r);
|
||||
break;
|
||||
case MTSE_BOT: /* beginning of tape */
|
||||
sim_debug(DEBUG_EXP, dptr, "BOT ");
|
||||
break;
|
||||
case MTSE_INVRL: /* invalid rec lnt */
|
||||
case MTSE_EOM: /* end of medium */
|
||||
sim_debug(DEBUG_EXP, dptr, "EOT ");
|
||||
break;
|
||||
}
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Handle processing of tape requests. */
|
||||
t_stat mt_srv(UNIT * uptr)
|
||||
{
|
||||
uint16 addr = GET_UADDR(uptr->u3);
|
||||
DEVICE *dptr = find_dev_from_unit(uptr);
|
||||
int unit = (uptr - dptr->units);
|
||||
int cmd = uptr->u3 & MT_CMDMSK;
|
||||
int bufnum = GET_DEV_BUF(dptr->flags);
|
||||
t_mtrlnt reclen;
|
||||
t_stat r = SCPE_ARG; /* Force error if not set */
|
||||
uint8 ch;
|
||||
int mode = 0;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||
uptr->u5 |= SNS_INTVENT;
|
||||
if (cmd != MT_SENSE)
|
||||
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case 0: /* No command, stop tape */
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Idle unit=%d\n", unit);
|
||||
break;
|
||||
|
||||
case MT_SENSE:
|
||||
ch = uptr->u5 & 0xff;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 1 %x\n", unit, ch);
|
||||
chan_write_byte(addr, &ch) ;
|
||||
ch = (uptr->u5 >> 8) & 0xff;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 2 %x\n", unit, ch);
|
||||
chan_write_byte(addr, &ch) ;
|
||||
ch = 0xc0;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 3 %x\n", unit, ch);
|
||||
chan_write_byte(addr, &ch) ;
|
||||
ch = (uptr->u5 >> 16) & 0xff;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 4 %x\n", unit, ch);
|
||||
chan_write_byte(addr, &ch) ;
|
||||
ch = 0;
|
||||
chan_write_byte(addr, &ch) ;
|
||||
chan_write_byte(addr, &ch);
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[bufnum] &= ~1;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
break;
|
||||
|
||||
case MT_READ:
|
||||
|
||||
if (uptr->u3 & MT_READDONE) {
|
||||
uptr->u3 &= ~(MT_CMDMSK|MT_READDONE);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
break;
|
||||
}
|
||||
|
||||
/* If empty buffer, fill */
|
||||
if (BUF_EMPTY(uptr)) {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d ", unit);
|
||||
if ((r = sim_tape_rdrecf(uptr, &mt_buffer[bufnum][0], &reclen,
|
||||
BUFFSIZE)) != MTSE_OK) {
|
||||
uptr->u3 &= ~(MT_CMDMSK|MT_READDONE);
|
||||
return mt_error(uptr, addr, r, dptr);
|
||||
}
|
||||
uptr->u4 = 0;
|
||||
uptr->hwmark = reclen;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Block %d chars\n", reclen);
|
||||
}
|
||||
|
||||
ch = mt_buffer[bufnum][uptr->u4++];
|
||||
/* if we are a 7track tape, handle conversion */
|
||||
if ((uptr->flags & MTUF_9TR) == 0) {
|
||||
mode = (uptr->u3 & MT_ODD) ? 0100 : 0;
|
||||
if ((parity_table[ch & 077] ^ (ch & 0100) ^ mode) == 0) {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Parity error unit=%d %d %03o\n",
|
||||
unit, uptr->u4-1, ch);
|
||||
uptr->u5 |= (SNS_VRC << 16) | SNS_DATCHK;
|
||||
}
|
||||
ch &= 077;
|
||||
if (uptr->u3 & MT_TRANS)
|
||||
ch = bcd_to_ebcdic[ch];
|
||||
if (uptr->u3 & MT_CONV) {
|
||||
sim_debug(DEBUG_DATA, dptr, "Read raw data unit=%d %d %02x %02x\n",
|
||||
unit, uptr->u4, ch, uptr->u6);
|
||||
if (uptr->u6 == 0 && uptr->u4 < uptr->hwmark) {
|
||||
uptr->u6 = MT_CONV1 | ch;
|
||||
sim_activate(uptr, 20);
|
||||
return SCPE_OK;
|
||||
} else if ((uptr->u6 & 0xc0) == MT_CONV1) {
|
||||
int t = uptr->u6 & 0x3F;
|
||||
uptr->u6 = MT_CONV2 | ch;
|
||||
ch = (t << 2) | ((ch >> 4) & 03);
|
||||
} else if ((uptr->u6 & 0xc0) == MT_CONV2) {
|
||||
int t = uptr->u6 & 0xf;
|
||||
uptr->u6 = MT_CONV3 | ch;
|
||||
ch = (t << 4) | ((ch >> 2) & 0xf);
|
||||
} else if ((uptr->u6 & 0xc0) == MT_CONV3) {
|
||||
ch |= ((uptr->u6 & 0x3) << 6);
|
||||
uptr->u6 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Send character over to channel */
|
||||
if (chan_write_byte(addr, &ch)) {
|
||||
sim_debug(DEBUG_DATA, dptr, "Read unit=%d EOR\n\r", unit);
|
||||
/* If not read whole record, skip till end */
|
||||
if (uptr->u4 < uptr->hwmark) {
|
||||
/* Send dummy character to force SLI */
|
||||
chan_write_byte(addr, &ch);
|
||||
sim_activate(uptr, (uptr->hwmark-uptr->u4) * 20);
|
||||
uptr->u3 |= MT_READDONE;
|
||||
break;
|
||||
}
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[bufnum] &= ~1;
|
||||
chan_end(addr, SNS_DEVEND);
|
||||
} else {
|
||||
sim_debug(DEBUG_DATA, dptr, "Read data unit=%d %d %02x\n\r",
|
||||
unit, uptr->u4, ch);
|
||||
if (uptr->u4 >= uptr->hwmark) { /* In IRG */
|
||||
/* Handle end of record */
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[bufnum] &= ~1;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
} else
|
||||
sim_activate(uptr, 20);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case MT_WRITE:
|
||||
/* Check if write protected */
|
||||
if (sim_tape_wrp(uptr)) {
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[bufnum] &= ~1;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Grab data until channel has no more */
|
||||
if (chan_read_byte(addr, &ch)) {
|
||||
if (uptr->u4 > 0) { /* Only if data in record */
|
||||
reclen = uptr->hwmark;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Write unit=%d Block %d chars\n",
|
||||
unit, reclen);
|
||||
r = sim_tape_wrrecf(uptr, &mt_buffer[bufnum][0], reclen);
|
||||
uptr->u4 = 0;
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_error(uptr, addr, r, dptr); /* Record errors */
|
||||
} else {
|
||||
uptr->u5 |= SNS_WCZERO; /* Write with no data */
|
||||
}
|
||||
} else {
|
||||
if ((uptr->flags & MTUF_9TR) == 0) {
|
||||
mode = (uptr->u3 & MT_ODD) ? 0100 : 0;
|
||||
if (uptr->u3 & MT_TRANS)
|
||||
ch = (ch & 0xf) | ((ch & 0x30) ^ 0x30);
|
||||
if (uptr->u3 & MT_CONV) {
|
||||
if (uptr->u6 == 0) {
|
||||
uptr->u6 = MT_CONV1 | (ch & 0x3);
|
||||
ch >>= 2;
|
||||
} else if ((uptr->u6 & 0xc0) == MT_CONV1) {
|
||||
int t = uptr->u6 & 0x3;
|
||||
uptr->u6 = MT_CONV2 | (ch & 0xf);
|
||||
ch = (t << 4) | ((ch >> 4) & 0xf);
|
||||
} else if ((uptr->u6 & 0xc0) == MT_CONV2) {
|
||||
int t = uptr->u6 & 0xf;
|
||||
ch = (t << 2) | ((ch >> 6) & 0x3);
|
||||
ch ^= parity_table[ch & 077] ^ mode;
|
||||
mt_buffer[bufnum][uptr->u4++] = ch;
|
||||
uptr->u6 = 0;
|
||||
}
|
||||
}
|
||||
ch &= 077;
|
||||
ch |= parity_table[ch] ^ mode;
|
||||
}
|
||||
mt_buffer[bufnum][uptr->u4++] = ch;
|
||||
sim_debug(DEBUG_DATA, dptr, "Write data unit=%d %d %02o\n\r",
|
||||
unit, uptr->u4, ch);
|
||||
uptr->hwmark = uptr->u4;
|
||||
break;
|
||||
}
|
||||
sim_activate(uptr, 20);
|
||||
break;
|
||||
|
||||
case MT_RDBK:
|
||||
if (uptr->u3 & MT_READDONE) {
|
||||
uptr->u3 &= ~(MT_CMDMSK|MT_READDONE);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* If at end of record, fill buffer */
|
||||
if (BUF_EMPTY(uptr)) {
|
||||
if (sim_tape_bot(uptr)) {
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[GET_DEV_BUF(dptr->flags)] &= ~1;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
||||
return SCPE_OK;
|
||||
}
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Read backward unit=%d ", unit);
|
||||
if ((r = sim_tape_rdrecr(uptr, &mt_buffer[bufnum][0], &reclen,
|
||||
BUFFSIZE)) != MTSE_OK) {
|
||||
uptr->u3 &= ~(MT_CMDMSK|MT_READDONE);
|
||||
return mt_error(uptr, addr, r, dptr);
|
||||
}
|
||||
uptr->u4 = reclen;
|
||||
uptr->hwmark = reclen;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Binary Block %d chars\n", reclen);
|
||||
}
|
||||
|
||||
ch = mt_buffer[bufnum][--uptr->u4];
|
||||
if ((uptr->flags & MTUF_9TR) == 0) {
|
||||
mode = (uptr->u3 & MT_ODD) ? 0100 : 0;
|
||||
ch &= 077;
|
||||
if ((parity_table[ch & 077] ^ (ch & 0100) ^ mode) == 0) {
|
||||
uptr->u5 |= (SNS_VRC << 16) | SNS_DATCHK;
|
||||
}
|
||||
if (uptr->u3 & MT_TRANS)
|
||||
ch = bcd_to_ebcdic[ch];
|
||||
if (uptr->u3 & MT_CONV) {
|
||||
if (uptr->u6 == 0 && uptr->u4 < uptr->hwmark) {
|
||||
uptr->u6 = MT_CONV1 | ch;
|
||||
sim_activate(uptr, 20);
|
||||
return SCPE_OK;
|
||||
} else if ((uptr->u6 & 0xc0) == MT_CONV1) {
|
||||
int t = uptr->u6 & 0x3F;
|
||||
uptr->u6 = MT_CONV2 | ch;
|
||||
ch = t | ((ch << 6) & 0xc0);
|
||||
} else if ((uptr->u6 & 0xc0) == MT_CONV2) {
|
||||
int t = uptr->u6 & 0x3C;
|
||||
uptr->u6 = MT_CONV3 | ch;
|
||||
ch = (t >> 2) | ((ch << 4) & 0xf0);
|
||||
} else if ((uptr->u6 & 0xc0) == MT_CONV3) {
|
||||
ch |= ((uptr->u6 & 0x30) >> 4);
|
||||
uptr->u6 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chan_write_byte(addr, &ch)) {
|
||||
sim_debug(DEBUG_DATA, dptr, "Read unit=%d EOR\n\r", unit);
|
||||
/* If not read whole record, skip till end */
|
||||
if (uptr->u4 >= 0) {
|
||||
sim_activate(uptr, (uptr->u4) * 20);
|
||||
uptr->u3 |= MT_READDONE;
|
||||
return SCPE_OK;
|
||||
}
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[bufnum] &= ~1;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
} else {
|
||||
sim_debug(DEBUG_DATA, dptr, "Read data unit=%d %d %02o\n\r",
|
||||
unit, uptr->u4, ch);
|
||||
if (uptr->u4 == 0) { /* In IRG */
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[bufnum] &= ~1;
|
||||
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
|
||||
} else
|
||||
sim_activate(uptr, 20);
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_WTM:
|
||||
if (uptr->u4 == 0) {
|
||||
if (sim_tape_wrp(uptr)) {
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[GET_DEV_BUF(dptr->flags)] &= ~1;
|
||||
set_devattn(addr, SNS_DEVEND|SNS_UNITCHK);
|
||||
return SCPE_OK;
|
||||
}
|
||||
uptr->u4 ++;
|
||||
sim_activate(uptr, 500);
|
||||
} else {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Write Mark unit=%d\n", unit);
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
r = sim_tape_wrtmk(uptr);
|
||||
set_devattn(addr, SNS_DEVEND);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_BSR:
|
||||
switch (uptr->u4 ) {
|
||||
case 0:
|
||||
if (sim_tape_bot(uptr)) {
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[GET_DEV_BUF(dptr->flags)] &= ~1;
|
||||
set_devattn(addr, SNS_DEVEND|SNS_UNITCHK);
|
||||
return SCPE_OK;
|
||||
}
|
||||
uptr->u4 ++;
|
||||
sim_activate(uptr, 500);
|
||||
break;
|
||||
case 1:
|
||||
uptr->u4++;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Backspace rec unit=%d ", unit);
|
||||
r = sim_tape_sprecr(uptr, &reclen);
|
||||
/* We don't set EOF on BSR */
|
||||
if (r == MTSE_TMK) {
|
||||
uptr->u4++;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "MARK\n");
|
||||
sim_activate(uptr, 50);
|
||||
} else {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "%d \n", reclen);
|
||||
sim_activate(uptr, 10 + (10 * reclen));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
set_devattn(addr, SNS_DEVEND);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
break;
|
||||
case 3:
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
set_devattn(addr, SNS_DEVEND|SNS_UNITEXP);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_BSF:
|
||||
switch(uptr->u4) {
|
||||
case 0:
|
||||
if (sim_tape_bot(uptr)) {
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[bufnum] &= ~1;
|
||||
set_devattn(addr, SNS_DEVEND|SNS_UNITCHK);
|
||||
break;
|
||||
}
|
||||
uptr->u4 ++;
|
||||
sim_activate(uptr, 500);
|
||||
break;
|
||||
case 1:
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Backspace file unit=%d\n", unit);
|
||||
r = sim_tape_sprecr(uptr, &reclen);
|
||||
if (r == MTSE_TMK) {
|
||||
uptr->u4++;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "MARK\n");
|
||||
sim_activate(uptr, 50);
|
||||
} else if (r == MTSE_BOT) {
|
||||
uptr->u4+= 2;
|
||||
sim_activate(uptr, 50);
|
||||
} else {
|
||||
sim_activate(uptr, 10 + (10 * reclen));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
set_devattn(addr, SNS_DEVEND|SNS_UNITEXP);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
break;
|
||||
case 3:
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
set_devattn(addr, SNS_DEVEND|SNS_UNITCHK);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_FSR:
|
||||
switch(uptr->u4) {
|
||||
case 0:
|
||||
uptr->u4 ++;
|
||||
sim_activate(uptr, 500);
|
||||
break;
|
||||
case 1:
|
||||
uptr->u4++;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Skip rec unit=%d ", unit);
|
||||
r = sim_tape_sprecf(uptr, &reclen);
|
||||
if (r == MTSE_TMK) {
|
||||
uptr->u4 = 3;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "MARK\n");
|
||||
sim_activate(uptr, 50);
|
||||
} else if (r == MTSE_EOM) {
|
||||
uptr->u4 = 4;
|
||||
sim_activate(uptr, 50);
|
||||
} else {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "%d\n", reclen);
|
||||
sim_activate(uptr, 10 + (10 * reclen));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
set_devattn(addr, SNS_DEVEND);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
break;
|
||||
case 3:
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
set_devattn(addr, SNS_DEVEND|SNS_UNITEXP);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
break;
|
||||
case 4:
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
set_devattn(addr, SNS_DEVEND|SNS_UNITCHK);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_FSF:
|
||||
switch(uptr->u4) {
|
||||
case 0:
|
||||
uptr->u4 ++;
|
||||
sim_activate(uptr, 500);
|
||||
break;
|
||||
case 1:
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Skip rec unit=%d ", unit);
|
||||
r = sim_tape_sprecf(uptr, &reclen);
|
||||
if (r == MTSE_TMK) {
|
||||
uptr->u4++;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "MARK\n");
|
||||
sim_activate(uptr, 50);
|
||||
} else if (r == MTSE_EOM) {
|
||||
uptr->u4+= 2;
|
||||
sim_activate(uptr, 50);
|
||||
} else {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "%d\n", reclen);
|
||||
sim_activate(uptr, 10 + (10 * reclen));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
set_devattn(addr, SNS_DEVEND);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Skip done unit=%d\n", unit);
|
||||
break;
|
||||
case 3:
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
set_devattn(addr, SNS_DEVEND|SNS_UNITCHK);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case MT_ERG:
|
||||
switch (uptr->u4) {
|
||||
case 0:
|
||||
if (sim_tape_wrp(uptr)) {
|
||||
uptr->u5 |= SNS_CMDREJ;
|
||||
uptr->u3 &= ~MT_CMDMSK;
|
||||
mt_busy[bufnum] &= ~1;
|
||||
set_devattn(addr, SNS_DEVEND|SNS_UNITCHK);
|
||||
} else {
|
||||
uptr->u4 ++;
|
||||
sim_activate(uptr, 500);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Erase unit=%d\n", unit);
|
||||
r = sim_tape_wrgap(uptr, 35);
|
||||
sim_activate(uptr, 5000);
|
||||
uptr->u4++;
|
||||
break;
|
||||
case 2:
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
set_devattn(addr, SNS_DEVEND);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_REW:
|
||||
if (uptr->u4 == 0) {
|
||||
uptr->u4 ++;
|
||||
sim_activate(uptr, 30000);
|
||||
} else {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Rewind unit=%d\n", unit);
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
r = sim_tape_rewind(uptr);
|
||||
set_devattn(addr, SNS_DEVEND);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_RUN:
|
||||
if (uptr->u4 == 0) {
|
||||
uptr->u4 ++;
|
||||
sim_activate(uptr, 30000);
|
||||
} else {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Unload unit=%d\n", unit);
|
||||
uptr->u3 &= ~(MT_CMDMSK);
|
||||
r = sim_tape_detach(uptr);
|
||||
mt_busy[bufnum] &= ~1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
void
|
||||
mt_ini(UNIT * uptr, t_bool f)
|
||||
{
|
||||
DEVICE *dptr = find_dev_from_unit(uptr);
|
||||
|
||||
uptr->u3 = MT_ODD|MT_DENS_800;
|
||||
mt_busy[GET_DEV_BUF(dptr->flags)] = 0;
|
||||
}
|
||||
|
||||
t_stat
|
||||
mt_reset(DEVICE * dptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
mt_attach(UNIT * uptr, CONST char *file)
|
||||
{
|
||||
uint16 addr = GET_UADDR(uptr->u3);
|
||||
t_stat r;
|
||||
|
||||
if ((r = sim_tape_attach(uptr, file)) != SCPE_OK)
|
||||
return r;
|
||||
set_devattn(addr, SNS_DEVEND);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
mt_detach(UNIT * uptr)
|
||||
{
|
||||
uptr->u3 = 0;
|
||||
return sim_tape_detach(uptr);
|
||||
}
|
||||
|
||||
t_stat
|
||||
mt_boot(int32 unit_num, DEVICE * dptr)
|
||||
{
|
||||
UNIT *uptr = &dptr->units[unit_num];
|
||||
t_stat r;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
return SCPE_UNATT; /* attached? */
|
||||
uptr->u3 |= MT_CONV;
|
||||
return chan_boot(GET_UADDR(uptr->u3), dptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
647
IBM360/ibm360_sys.c
Normal file
647
IBM360/ibm360_sys.c
Normal file
@ -0,0 +1,647 @@
|
||||
/* ibm360_sys.c: IBM 360 Simulator system interface.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#include "ibm360_defs.h"
|
||||
#include <ctype.h>
|
||||
#include "sim_card.h"
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern uint32 M[MAXMEMSIZE];
|
||||
|
||||
/* 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[] = "IBM 360";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 16;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
#ifdef NUM_DEVS_CON
|
||||
&con_dev,
|
||||
#endif
|
||||
#ifdef NUM_DEVS_CDR
|
||||
&cdr_dev,
|
||||
#endif
|
||||
#ifdef NUM_DEVS_CDP
|
||||
&cdp_dev,
|
||||
#endif
|
||||
#ifdef NUM_DEVS_LPR
|
||||
&lpr_dev,
|
||||
#endif
|
||||
#ifdef NUM_DEVS_MT
|
||||
&mta_dev,
|
||||
#if NUM_DEVS_MT > 1
|
||||
&mtb_dev,
|
||||
#endif
|
||||
#endif
|
||||
#ifdef NUM_DEVS_DASD
|
||||
&dda_dev,
|
||||
#if NUM_DEVS_DASD > 1
|
||||
&ddb_dev,
|
||||
#endif
|
||||
#endif
|
||||
#ifdef NUM_DEVS_COM
|
||||
&com_dev,
|
||||
#endif
|
||||
NULL };
|
||||
|
||||
|
||||
/* 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"},
|
||||
{"CONI", DEBUG_CONI, "Show coni instructions"},
|
||||
{"CONO", DEBUG_CONO, "Show coni instructions"},
|
||||
{"DATAIO", DEBUG_DATAIO, "Show datai and datao instructions"},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
/* Simulator debug controls */
|
||||
DEBTAB crd_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"},
|
||||
{"CONI", DEBUG_CONI, "Show coni instructions"},
|
||||
{"CONO", DEBUG_CONO, "Show coni instructions"},
|
||||
{"DATAIO", DEBUG_DATAIO, "Show datai and datao instructions"},
|
||||
{"CARD", DEBUG_CARD, "Show Card read/punches"},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"IO device not ready",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Unknown Opcode",
|
||||
"Invalid instruction",
|
||||
"Invalid I/O operation",
|
||||
"Nested indirects exceed limit",
|
||||
"Nested XEC's exceed limit",
|
||||
"I/O Check opcode",
|
||||
"Memory management trap during trap",
|
||||
"Trap instruction not BRM",
|
||||
"RTC instruction not MIN or SKR",
|
||||
"Interrupt vector zero",
|
||||
"Runaway carriage control tape" };
|
||||
|
||||
const char ascii_to_ebcdic[128] = {
|
||||
/* Control */
|
||||
0x01,0x02,0x03,0xFF,0x00,0x00,0x00,0x00, /*0-37*/
|
||||
/*Control*/
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
/*Control*/
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
/*Control*/
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
/* sp ! " # $ % & ' */
|
||||
0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, /* 40 - 77 */
|
||||
/* ( ) * + , - . / */
|
||||
0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
/* 8 9 : ; < = > ? */
|
||||
0xf8, 0xf9, 0x7a, 0x6e, 0x4c, 0x7e, 0x6e, 0x6f,
|
||||
/* @ A B C D E F G */
|
||||
0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 100 - 137 */
|
||||
/* H I J K L M N O */
|
||||
0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
|
||||
/* P Q R S T U V W */
|
||||
0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
|
||||
/* X Y Z [ \ ] ^ _ */
|
||||
0xe7, 0xe8, 0xe9, 0x4a, 0xff, 0x5a, 0x5f, 0x6d,
|
||||
/* ` a b c d e f g */
|
||||
0x7c, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 140 - 177 */
|
||||
/* h i j k l m n o */
|
||||
0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
|
||||
/* p q r s t u v w */
|
||||
0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
|
||||
/* x y z { | } ~ del */
|
||||
0xa7, 0xa8, 0xa9, 0xff, 0x47, 0xff, 0xff, 0x6d,
|
||||
};
|
||||
|
||||
const char ebcdic_to_ascii[256] = {
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
0x00, 0x01, 0x02, 0x03, 0xFF, 0x09, 0xff, 0x7f, /* 0x */
|
||||
0xff, 0xff, 0xff, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x19, 0x0a, 0x08, 0x08, 0xff, /* 1x */
|
||||
0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x1c, 0xff, 0xff, 0x0a, 0xff, 0xff, /* 2x */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x06, 0x07,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xff, 0xff, /* 3x */
|
||||
0xff, 0xff, 0xff, 0xff, 0x14, 0x15, 0xff, 0xff,
|
||||
' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 4x */
|
||||
0xff, 0xff, '[', '.', '<', '(', '+', '|',
|
||||
'&', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 5x */
|
||||
0xff, 0xff, ']', '$', '*', ')', ';', '^',
|
||||
'-', '/', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 6x */
|
||||
0xff, 0xff, 0xff, ',', '%', '_', '>', '?',
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 7x */
|
||||
0xff, 0xff, ':', '#', '@', '\'', '=', '"',
|
||||
0xff, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 8x */
|
||||
'h', 'i', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 'j', 'k', 'l', 'm', 'n', 'o', 'p', /* 9x */
|
||||
'q', 'r', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 's', 't', 'u', 'v', 'w', 'x', /* Ax */
|
||||
'y', 'z', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Bx */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* Cx */
|
||||
'H', 'I', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* Dx */
|
||||
'Q', 'R', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 'S', 'T', 'U', 'V', 'W', 'X', /* Ex */
|
||||
'Y', 'Z', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', /* Fx */
|
||||
'8', '9', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
|
||||
/* Load a card image file into memory. */
|
||||
|
||||
t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag)
|
||||
{
|
||||
return SCPE_NOFNC;
|
||||
}
|
||||
|
||||
/* Symbol tables */
|
||||
typedef struct _opcode {
|
||||
uint8 opbase;
|
||||
char *name;
|
||||
uint8 type;
|
||||
} t_opcode;
|
||||
|
||||
#define RR 01
|
||||
#define RX 02
|
||||
#define RS 03
|
||||
#define SI 04
|
||||
#define SS 05
|
||||
#define LNMSK 07
|
||||
#define ONEOP 010
|
||||
#define IMDOP 020
|
||||
#define TWOOP 030
|
||||
#define ZEROOP 040
|
||||
#define OPMSK 070
|
||||
|
||||
t_opcode optab[] = {
|
||||
{ OP_SPM, "SPM", RR|ONEOP },
|
||||
{ OP_BALR, "BALR", RR },
|
||||
{ OP_BCTR, "BCTR", RR },
|
||||
{ OP_BCR, "BCR", RR },
|
||||
{ OP_SSK, "SSK", RR },
|
||||
{ OP_ISK, "ISK", RR },
|
||||
{ OP_SVC, "SVC", RR|IMDOP },
|
||||
{ OP_LPR, "LPR", RR },
|
||||
{ OP_LNR, "LNR", RR },
|
||||
{ OP_LTR, "LTR", RR },
|
||||
{ OP_LCR, "LCR", RR },
|
||||
{ OP_NR, "NR", RR },
|
||||
{ OP_OR, "OR", RR },
|
||||
{ OP_XR, "XR", RR },
|
||||
{ OP_CLR, "CLR", RR },
|
||||
{ OP_CR, "CR", RR },
|
||||
{ OP_LR, "LR", RR },
|
||||
{ OP_AR, "AR", RR },
|
||||
{ OP_SR, "SR", RR },
|
||||
{ OP_MR, "MR", RR },
|
||||
{ OP_DR, "DR", RR },
|
||||
{ OP_ALR, "ALR", RR },
|
||||
{ OP_SLR, "SLR", RR },
|
||||
{ OP_LPDR, "LPDR", RR },
|
||||
{ OP_LNDR, "LNDR", RR },
|
||||
{ OP_LTDR, "LTDR", RR },
|
||||
{ OP_LCDR, "LCDR", RR },
|
||||
{ OP_HDR, "HDR", RR },
|
||||
{ OP_LRDR, "LRDR", RR },
|
||||
{ OP_MXR, "MXR", RR },
|
||||
{ OP_MXDR, "MXDR", RR },
|
||||
{ OP_LDR, "LDR", RR },
|
||||
{ OP_CDR, "CDR", RR },
|
||||
{ OP_ADR, "ADR", RR },
|
||||
{ OP_SDR, "SDR", RR },
|
||||
{ OP_MDR, "MDR", RR },
|
||||
{ OP_DDR, "DDR", RR },
|
||||
{ OP_AWR, "AWR", RR },
|
||||
{ OP_SWR, "SWR", RR },
|
||||
{ OP_LPER, "LPER", RR },
|
||||
{ OP_LNER, "LNER", RR },
|
||||
{ OP_LTER, "LTER", RR },
|
||||
{ OP_LCER, "LCER", RR },
|
||||
{ OP_HER, "HER", RR },
|
||||
{ OP_LRER, "LRER", RR },
|
||||
{ OP_AXR, "AXR", RR },
|
||||
{ OP_SXR, "SXR", RR },
|
||||
{ OP_LER, "LER", RR },
|
||||
{ OP_CER, "CER", RR },
|
||||
{ OP_AER, "AER", RR },
|
||||
{ OP_SER, "SER", RR },
|
||||
{ OP_MER, "MER", RR },
|
||||
{ OP_DER, "DER", RR },
|
||||
{ OP_AUR, "AUR", RR },
|
||||
{ OP_SUR, "SUR", RR },
|
||||
{ OP_STH, "STH", RX },
|
||||
{ OP_LA, "LA", RX },
|
||||
{ OP_STC, "STC", RX },
|
||||
{ OP_IC, "IC", RX },
|
||||
{ OP_EX, "EX", RX },
|
||||
{ OP_BAL, "BAL", RX },
|
||||
{ OP_BCT, "BCT", RX },
|
||||
{ OP_BC, "BC", RX },
|
||||
{ OP_LH, "LH", RX },
|
||||
{ OP_CH, "CH", RX },
|
||||
{ OP_AH, "AH", RX },
|
||||
{ OP_SH, "SH", RX },
|
||||
{ OP_MH, "MH", RX },
|
||||
{ OP_CVD, "CVD", RX },
|
||||
{ OP_CVB, "CVB", RX },
|
||||
{ OP_ST, "ST", RX },
|
||||
{ OP_N, "N", RX },
|
||||
{ OP_CL, "CL", RX },
|
||||
{ OP_O, "O", RX },
|
||||
{ OP_X, "X", RX },
|
||||
{ OP_L, "L", RX },
|
||||
{ OP_C, "C", RX },
|
||||
{ OP_A, "A", RX },
|
||||
{ OP_S, "S", RX },
|
||||
{ OP_M, "M", RX },
|
||||
{ OP_D, "D", RX },
|
||||
{ OP_AL, "AL", RX },
|
||||
{ OP_SL, "SL", RX },
|
||||
{ OP_STD, "STD", RX },
|
||||
{ OP_MXD, "MXD", RX },
|
||||
{ OP_LD, "LD", RX },
|
||||
{ OP_CD, "CD", RX },
|
||||
{ OP_AD, "AD", RX },
|
||||
{ OP_SD, "SD", RX },
|
||||
{ OP_MD, "MD", RX },
|
||||
{ OP_DD, "DD", RX },
|
||||
{ OP_AW, "AW", RX },
|
||||
{ OP_SW, "SW", RX },
|
||||
{ OP_STE, "STE", RX },
|
||||
{ OP_LE, "LE", RX },
|
||||
{ OP_CE, "CE", RX },
|
||||
{ OP_AE, "AE", RX },
|
||||
{ OP_SE, "SE", RX },
|
||||
{ OP_ME, "ME", RX },
|
||||
{ OP_DE, "DE", RX },
|
||||
{ OP_AU, "AU", RX },
|
||||
{ OP_SU, "SU", RX },
|
||||
{ OP_SSM, "SSM", SI|ZEROOP },
|
||||
{ OP_LPSW, "LPSW", SI|ZEROOP },
|
||||
{ OP_DIAG, "DIAG", SI },
|
||||
{ OP_BXH, "BXH", RS },
|
||||
{ OP_BXLE, "BXLE", RS },
|
||||
{ OP_SRL, "SRL", RS|ZEROOP },
|
||||
{ OP_SLL, "SLL", RS|ZEROOP },
|
||||
{ OP_SRA, "SRA", RS|ZEROOP },
|
||||
{ OP_SLA, "SLA", RS|ZEROOP },
|
||||
{ OP_SRDL, "SRDL", RS|ZEROOP },
|
||||
{ OP_SLDL, "SLDL", RS|ZEROOP },
|
||||
{ OP_SRDA, "SRDA", RS|ZEROOP },
|
||||
{ OP_SLDA, "SLDA", RS|ZEROOP },
|
||||
{ OP_STM, "STM", RS|TWOOP },
|
||||
{ OP_TM, "TM", SI },
|
||||
{ OP_MVI, "MVI", SI },
|
||||
{ OP_TS, "TS", SI|ZEROOP },
|
||||
{ OP_NI, "NI", SI },
|
||||
{ OP_CLI, "CLI", SI },
|
||||
{ OP_OI, "OI", SI },
|
||||
{ OP_XI, "XI", SI },
|
||||
{ OP_LM, "LM", RS|TWOOP },
|
||||
{ OP_SIO, "SIO", SI|ZEROOP },
|
||||
{ OP_TIO, "TIO", SI|ZEROOP },
|
||||
{ OP_HIO, "HIO", SI|ZEROOP },
|
||||
{ OP_TCH, "TCH", SI|ZEROOP },
|
||||
{ OP_MVN, "MVN", SS },
|
||||
{ OP_MVC, "MVC", SS },
|
||||
{ OP_MVZ, "MVZ", SS },
|
||||
{ OP_NC, "NC", SS },
|
||||
{ OP_CLC, "CLC", SS },
|
||||
{ OP_OC, "OC", SS },
|
||||
{ OP_XC, "XC", SS },
|
||||
{ OP_TR, "TR", SS },
|
||||
{ OP_TRT, "TRT", SS },
|
||||
{ OP_ED, "ED", SS },
|
||||
{ OP_EDMK, "EDMK", SS },
|
||||
{ OP_MVO, "MVO", SS|TWOOP },
|
||||
{ OP_PACK, "PACK", SS|TWOOP },
|
||||
{ OP_UNPK, "UNPK", SS|TWOOP },
|
||||
{ OP_ZAP, "ZAP", SS|TWOOP },
|
||||
{ OP_CP, "CP", SS|TWOOP },
|
||||
{ OP_AP, "AP", SS|TWOOP },
|
||||
{ OP_SP, "SP", SS|TWOOP },
|
||||
{ OP_MP, "MP", SS|TWOOP },
|
||||
{ OP_DP, "DP", SS|TWOOP },
|
||||
{ 0, NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
/* Register change decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
inst = mask bits
|
||||
*/
|
||||
|
||||
//void fprint_reg (FILE *of, int32 inst)
|
||||
//{
|
||||
//int32 i, j, sp;
|
||||
#if 0
|
||||
inst = inst & ~(I_M_OP << I_V_OP); /* clear opcode */
|
||||
for (i = sp = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
|
||||
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
|
||||
if ((j == I_V_REG) && (opc_val[i] & inst)) { /* reg class? */
|
||||
inst = inst & ~opc_val[i]; /* mask bit set? */
|
||||
fprintf (of, (sp? " %s": "%s"), opcode[i]);
|
||||
sp = 1; } }
|
||||
#endif
|
||||
//return;
|
||||
//}
|
||||
|
||||
void fprint_inst(FILE *of, uint16 *val) {
|
||||
uint8 inst = (val[0] >> 8) & 0xff;
|
||||
int i;
|
||||
int l = 1;
|
||||
t_opcode *tab;
|
||||
|
||||
for (tab = optab; tab->name != NULL; tab++) {
|
||||
if (tab->opbase == inst) {
|
||||
fputs(tab->name, of);
|
||||
fputc(' ', of);
|
||||
switch (tab->type & LNMSK) {
|
||||
case RR:
|
||||
if (tab->type & IMDOP) {
|
||||
fprint_val(of, val[0] & 0xff, 16, 8, PV_RZRO);
|
||||
} else {
|
||||
if (tab->type & ONEOP)
|
||||
fprintf(of, "%d", (val[0] >> 4) & 0xf);
|
||||
else
|
||||
fprintf(of, "%d,%d", (val[0] >> 4) & 0xf, val[0] & 0xf);
|
||||
}
|
||||
break;
|
||||
case RX:
|
||||
fprintf(of, "%d,", (val[0] >> 4) & 0xf);
|
||||
fprint_val(of, val[1] & 0xfff, 16, 12, PV_RZRO);
|
||||
fprintf(of, "(%d,%d)", val[0] & 0xf, (val[1] >> 12) & 0xf);
|
||||
break;
|
||||
case RS:
|
||||
fprintf(of, "%d,", (val[0] >> 4) & 0xf);
|
||||
if ((tab->type & ZEROOP) == 0)
|
||||
fprintf(of, "%d,", val[0] & 0xf);
|
||||
fprint_val(of, val[1] & 0xfff, 16, 12, PV_RZRO);
|
||||
if (val[1] & 0xf000)
|
||||
fprintf(of, "(%d)", (val[1] >> 12) & 0xf);
|
||||
break;
|
||||
case SI:
|
||||
fprint_val(of, val[1] & 0xfff, 16, 12, PV_RZRO);
|
||||
if (val[1] & 0xf000)
|
||||
fprintf(of, "(%d)", (val[1] >> 12) & 0xf);
|
||||
if ((tab->type & ZEROOP) == 0)
|
||||
fprintf(of, ",%02x", val[0] & 0xff);
|
||||
break;
|
||||
case SS:
|
||||
fprint_val(of, val[1] & 0xfff, 16, 12, PV_RZRO);
|
||||
if (tab->type & TWOOP) {
|
||||
fprintf(of, "(%d", (val[0] >> 4) & 0xf);
|
||||
} else {
|
||||
fprintf(of, "(%d", val[0] & 0xff);
|
||||
}
|
||||
if (val[1] & 0xf000)
|
||||
fprintf(of, ",%d", (val[1] >> 12) & 0xf);
|
||||
fprintf(of, "),");
|
||||
fprint_val(of, val[2] & 0xfff, 16, 12, PV_RZRO);
|
||||
if (tab->type & TWOOP) {
|
||||
fprintf(of, "(%d,", val[0] & 0xf);
|
||||
} else {
|
||||
fprintf(of, "(");
|
||||
}
|
||||
fprintf(of, "%d)", (val[2] >> 12) & 0xf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
uint8 inst = *val;
|
||||
int i;
|
||||
int l = 1;
|
||||
t_opcode *tab;
|
||||
|
||||
if (sw & SWMASK ('M')) {
|
||||
for (tab = optab; tab->name != NULL; tab++) {
|
||||
if (tab->opbase == inst) {
|
||||
switch (tab->type & LNMSK) {
|
||||
case RR:
|
||||
l = 2;
|
||||
break;
|
||||
case RX:
|
||||
case RS:
|
||||
case SI:
|
||||
l = 4;
|
||||
break;
|
||||
case SS:
|
||||
l = 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
sw &= ~ SWMASK('F'); /* Can't do F and M at same time */
|
||||
} else if (sw & SWMASK('F')) {
|
||||
l = 4;
|
||||
} else if (sw & SWMASK('W')) {
|
||||
l = 2;
|
||||
}
|
||||
|
||||
for(i = 0; i < l; i++) {
|
||||
fprintf(of, "%02x ", val[i] & 0xFF);
|
||||
}
|
||||
|
||||
if (sw & SWMASK ('C')) {
|
||||
fputc('\'', of);
|
||||
for(i = 0; i < l; i++) {
|
||||
char ch = ebcdic_to_ascii[val[i] & 0xff];
|
||||
if (ch >= 0x20 && ch <= 0x7f)
|
||||
fprintf(of, "%c", ch);
|
||||
else
|
||||
fputc('_', of);
|
||||
}
|
||||
fputc('\'', of);
|
||||
}
|
||||
if (sw & SWMASK ('W')) {
|
||||
if (sw & SWMASK('M')) {
|
||||
for(i = l; i <= 6; i++) {
|
||||
fputs(" ", of);
|
||||
if (sw & SWMASK('C'))
|
||||
fputs(" ", of);
|
||||
}
|
||||
if (sw & SWMASK('C'))
|
||||
fputs(" ", of);
|
||||
}
|
||||
for(i = 0; i < l; i+=2)
|
||||
fprintf(of, "%02x%02x ", val[i] & 0xff, val[i+1] & 0xff);
|
||||
if (sw & SWMASK('M')) {
|
||||
for(i = l; i <= 6; i+=2) {
|
||||
fputs(" ", of);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sw & SWMASK ('F')) {
|
||||
fprintf(of, "%02x%02x%02x%02x ", val[0] & 0xff, val[1] & 0xff, val[2] & 0xff, val[3] & 0xff);
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (sw & SWMASK ('M')) {
|
||||
fputs(" ", of);
|
||||
if ((sw & SWMASK('W')) == 0) {
|
||||
if (sw & SWMASK('M')) {
|
||||
for(i = l; i <= 6; i++) {
|
||||
fputs(" ", of);
|
||||
if (sw & SWMASK('C'))
|
||||
fputs(" ", of);
|
||||
}
|
||||
if (sw & SWMASK('C'))
|
||||
fputs(" ", of);
|
||||
}
|
||||
}
|
||||
for (tab = optab; tab->name != NULL; tab++) {
|
||||
if (tab->opbase == inst) {
|
||||
fputs(tab->name, of);
|
||||
fputc(' ', of);
|
||||
switch (tab->type & LNMSK) {
|
||||
case RR:
|
||||
if (tab->type & IMDOP) {
|
||||
fprint_val(of, val[1], 16, 8, PV_RZRO);
|
||||
} else {
|
||||
if (tab->type & ONEOP)
|
||||
fprintf(of, "%d", (val[1] >> 4) & 0xf);
|
||||
else
|
||||
fprintf(of, "%d,%d", (val[1] >> 4) & 0xf, val[1] & 0xf);
|
||||
}
|
||||
break;
|
||||
case RX:
|
||||
fprintf(of, "%d, %x(", (val[1] >> 4) & 0xf, ((val[2] << 8) & 0xf00) | val[3]);
|
||||
fprintf(of, "%d,%d)", val[1] & 0xf, (val[2] >> 4) & 0xf);
|
||||
break;
|
||||
case RS:
|
||||
fprintf(of, "%d,", (val[1] >> 4) & 0xf);
|
||||
if ((tab->type & ZEROOP) == 0)
|
||||
fprintf(of, "%d,", val[1] & 0xf);
|
||||
fprintf(of, "%x", ((val[2] << 8) & 0xf00) | val[3]);
|
||||
if (val[2] & 0xf0)
|
||||
fprintf(of, "(%d)", (val[2] >> 4) & 0xf);
|
||||
break;
|
||||
case SI:
|
||||
fprintf(of, "%x", ((val[2] << 8) & 0xf00) | val[3]);
|
||||
if (val[2] & 0xf0)
|
||||
fprintf(of, "(%d)", (val[2] >> 4) & 0xf);
|
||||
if ((tab->type & ZEROOP) == 0)
|
||||
fprintf(of, ",%2x", val[1]);
|
||||
break;
|
||||
case SS:
|
||||
fprintf(of, "%x", ((val[2] << 8) & 0xf00) | val[3]);
|
||||
if (tab->type & TWOOP) {
|
||||
fprintf(of, "(%d", (val[1] >> 4) & 0xf);
|
||||
} else {
|
||||
fprintf(of, "(%d", val[1] & 0xff);
|
||||
}
|
||||
if (val[2] & 0xf0)
|
||||
fprintf(of, ",%d", (val[1] >> 4) & 0xf);
|
||||
fprintf(of, "),");
|
||||
fprintf(of, "%x", ((val[4] << 8) & 0xf00) | val[5]);
|
||||
if (tab->type & TWOOP) {
|
||||
fprintf(of, "(%d,", val[1] & 0xf);
|
||||
} else {
|
||||
fprintf(of, "(");
|
||||
}
|
||||
fprintf(of, "%d)", (val[4] >> 4) & 0xf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//fprint_val (of, inst, 16, 8, PV_RZRO);
|
||||
return -(l-1);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* 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 (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
int32 i, j, k;
|
||||
t_value d, tag;
|
||||
t_stat r;
|
||||
|
||||
while (isspace (*cptr)) cptr++;
|
||||
return SCPE_OK;
|
||||
|
||||
/* Symbolic input, continued */
|
||||
|
||||
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user