Merge changes from v3.9-0 rc1

This commit is contained in:
Mark Pizzolato 2012-03-19 16:05:24 -07:00
parent e04a987353
commit fffad7c20e
145 changed files with 29917 additions and 15649 deletions

View file

@ -1,80 +0,0 @@
Notes For V3.8
The makefile now works for Linux and most Unix's. However, for Solaris
and MacOS, you must first export the OSTYPE environment variable:
> export OSTYPE
> make
Otherwise, you will get build errors.
1. New Features
1.1 3.8-0
1.1.1 SCP and Libraries
- BREAK, NOBREAK, and SHOW BREAK with no argument will set, clear, and
show (respectively) a breakpoint at the current PC.
1.1.2 GRI
- Added support for the GRI-99 processor.
1.1.3 HP2100
- Added support for the BACI terminal interface.
- Added support for RTE OS/VMA/EMA, SIGNAL, VIS firmware extensions.
1.1.4 Nova
- Added support for 64KW memory (implemented in third-party CPU's).
1.1.5 PDP-11
- Added support for DC11, RC11, KE11A, KG11A.
- Added modem control support for DL11.
- Added ASCII character support for all 8b devices.
1.2 3.8-1
1.2.1 SCP and libraries
- Added capability to set line connection order for terminal multiplexers.
1.2.2 HP2100
- Added support for 12620A/12936A privileged interrupt fence.
- Added support for 12792C eight-channel asynchronous multiplexer.
1.3 3.8-2
1.3.1 SCP and libraries
- Added line history capability for *nix hosts.
- Added "SHOW SHOW" and "SHOW <dev> SHOW" commands.
1.3.2 1401
- Added "no rewind" option to magtape boot.
1.3.3 PDP-11
- Added RD32 support to RQ
- Added debug support to RL
1.3.4 PDP-8
- Added FPP support (many thanks to Rick Murphy for debugging the code)
1.3.5 VAX-11/780
- Added AUTORESTART switch support, and VMS REBOOT command support
2. Bugs Fixed
Please see the revision history on http://simh.trailing-edge.com or
in the source module sim_rev.h.

184
0readme_39.txt Normal file
View file

@ -0,0 +1,184 @@
Notes For V3.9
The makefile now works for Linux and most Unix's. However, for Solaris
and MacOS, you must first export the OSTYPE environment variable:
> export OSTYPE
> make
Otherwise, you will get build errors.
1. New Features
1.1 3.9-0
1.1.1 SCP and libraries
- added *nix READLINE support (Mark Pizzolato)
- added "SHOW SHOW" and "SHOW <dev> SHOW" commands (Mark Pizzolato)
- added support for BREAK key on Windows (Mark Pizzolato)
1.1.2 PDP-8
- floating point processor is now enabled
2. Bugs Fixed
Please see the revision history on http://simh.trailing-edge.com or
in the source module sim_rev.h.
3. Status Report
This is the last release of SimH for which I will be sole editor. After this
release, the source is moving to a public repository:
under the general editorship of Dave Hittner and Mark Pizzolato. The status
of the individual simulators is as follows:
3.1 PDP-1
Stable and working; runs available software.
3.2 PDP-4/7/9/15
Stable and working; runs available software.
3.3 PDP-8
Stable and working; runs available software.
3.4 PDP-10 [KS-10 only]
Stable and working; runs available software.
3.5 PDP-11
Stable and working; runs available system software. The emulation of individual
models has numerous errors of detail, which prevents many diagnostics from
running correctly.
3.6 VAX-11/780
Stable and working; runs available software.
3.7 MicroVAX 3900 (VAX)
Stable and working; runs available software. Thanks to the kind generosity of
Camiel Vanderhoeven, this simulator has been verified with AXE, the VAX
architectural exerciser.
3.8 Nova
Stable and working; runs available software.
3.9 Eclipse
Stable and working, but not really supported. There is no Eclipse-specific
software available under a hobbyist license.
3.10 Interdata 16b
Stable and working, but no software for it has been found, other than
diagnostics.
3.11 Interdata 32b
Stable and working; runs 32b UNIX and diagnostics.
3.12 IBM 1401
Stable and working; runs available software.
3.13 IBM 1620
Hand debug only. No software for it has been found or tested.
3.14 IBM 7094
Stable and working as a stock system; runs IBSYS. The CTSS extensions
have not been debugged.
3.15 IBM S/3
Stable and working, but not really supported. Runs available software.
3.16 IBM 1130
Stable and working; runs available software. Supported and edited by
Brian Knittel.
3.17 HP 2100/1000
Stable and working; runs available software. Supported and edited by
Dave Bryan.
3.18 Honeywell 316/516
Stable and working; runs available software.
3.19 GRI-909/99
Hand debug only. No software for it has been found or tested.
3.20 SDS-940
Hand debug only, and a few diagnostics.
3.21 LGP-30
Unfinished; hand debug only. Does not run available software, probably
due to my misunderstanding of the LGP-30 operational procedures.
3.22 Altair (original 8080 version)
Stable and working, but not really supported. Runs available software.
3.23 AltairZ80 (Z80 version)
Stable and working; runs available software. Supported and edited by
Peter Schorn.
3.24 SWTP 6800
Stable and working; runs available software. Supported and edited by
Bill Beech
3.25 Sigma 32b
Incomplete; more work is needed on the peripherals for accuracy.
3.26 Alpha
Incomplete; essentially just an EV-5 (21164) chip emulator.
4. Suggestions for Future Work
4.1 General Structure
- Multi-threading, to allow true concurrency between SCP and the simulator
- Graphics device support, particularly for the PDP-1 and PDP-11
4.2 Current Simulators
- PDP-1 graphics, to run Space War
- PDP-11 GT40 graphics, to run Lunar Lander
- PDP-15 MUMPS-15
- Interdata native OS debug, both 16b and 32b
- SDS 940 timesharing operating system debug
- IBM 7094 CTSS feature debug and operating system debug
- IBM 1620 debug and software
- GRI-909 software
- Sigma 32b completion and debug
- LGP-30 debug
4.3 Possible Future Simulators
- Data General MV8000 (if a hobbyist license can be obtained for AOS)
- Alpha simulator
- HP 3000 (16b) simulator with MPE

View file

@ -1,6 +1,6 @@
/* altairz80_cpu.c: MITS Altair CPU (8080 and Z80)
Copyright (c) 2002-2010, Peter Schorn
Copyright (c) 2002-2011, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -191,6 +191,8 @@ uint8 GetByteDMA(const uint32 Addr);
void PutByteDMA(const uint32 Addr, const uint32 Value);
int32 getBankSelect(void);
void setBankSelect(const int32 b);
uint32 getClockFrequency(void);
void setClockFrequency(const uint32 Value);
uint32 getCommon(void);
t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag);
uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
@ -1867,6 +1869,17 @@ t_stat sim_instr (void) {
return result;
}
static int32 clockHasChanged = FALSE;
uint32 getClockFrequency(void) {
return clockFrequency;
}
void setClockFrequency(const uint32 Value) {
clockFrequency = Value;
clockHasChanged = TRUE;
}
static t_stat sim_instr_mmu (void) {
extern int32 sim_interval;
extern t_bool sim_brk_pend[SIM_BKPT_N_SPC];
@ -1916,22 +1929,29 @@ static t_stat sim_instr_mmu (void) {
startTime = sim_os_msec();
tStatesInSlice = sliceLength*clockFrequency;
}
else { /* make sure that sim_os_msec() is not called later */
else /* make sure that sim_os_msec() is not called later */
clockFrequency = startTime = tStatesInSlice = 0;
}
/* main instruction fetch/decode loop */
while (switch_cpu_now == TRUE) { /* loop until halted */
if (sim_interval <= 0) { /* check clock queue */
#if !UNIX_PLATFORM
if ((reason = sim_os_poll_kbd()) == SCPE_STOP) { /* poll on platforms without reliable signalling */
if ((reason = sim_os_poll_kbd()) == SCPE_STOP) /* poll on platforms without reliable signalling */
break;
}
#endif
if ( (reason = sim_process_event()) )
if ((reason = sim_process_event()))
break;
else
specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ;
if (clockHasChanged) {
clockHasChanged = FALSE;
tStates = 0;
if (rtc_avail) {
startTime = sim_os_msec();
tStatesInSlice = sliceLength*clockFrequency;
}
else /* make sure that sim_os_msec() is not called later */
clockFrequency = startTime = tStatesInSlice = 0;
}
specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ;
}
if (specialProcessing) { /* quick check for special processing */
@ -6442,6 +6462,7 @@ static void cpu_clear(void) {
mmu_table[i] = EMPTY_PAGE;
if (cpu_unit.flags & UNIT_CPU_ALTAIRROM)
install_ALTAIRbootROM();
clockHasChanged = FALSE;
}
static t_stat cpu_clear_command(UNIT *uptr, int32 value, char *cptr, void *desc) {

View file

@ -1,6 +1,6 @@
/* altairz80_cpu_opt.c: MITS Altair CPU (8080 and Z80)
Copyright (c) 2002-2010, Peter Schorn
Copyright (c) 2002-2011, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -1,6 +1,6 @@
/* altairz80_defs.h: MITS Altair simulator definitions
Copyright (c) 2002-2010, Peter Schorn
Copyright (c) 2002-2011, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -43,7 +43,7 @@
#define RESOURCE_TYPE_MEMORY 1
#define RESOURCE_TYPE_IO 2
#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */
#define NUM_OF_DSK 16 /* NUM_OF_DSK must be power of two */
#define LDA_INSTRUCTION 0x3e /* op-code for LD A,<8-bit value> instruction */
#define UNIT_NO_OFFSET_1 0x37 /* LD A,<unitno> */
#define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | <unitno> */

Binary file not shown.

View file

@ -1,6 +1,6 @@
/* altairz80_dsk.c: MITS Altair 88-DISK Simulator
Copyright (c) 2002-2010, Peter Schorn
Copyright (c) 2002-2011, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -152,18 +152,20 @@ void install_ALTAIRbootROM(void);
/* currently selected drive (values are 0 .. NUM_OF_DSK)
current_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */
static int32 current_disk = NUM_OF_DSK;
static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS };
static int32 in9_count = 0;
static int32 in9_message = FALSE;
static int32 dirty = FALSE; /* TRUE when buffer has unwritten data in it */
static int32 warnLevelDSK = 3;
static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static int32 warnDSK10 = 0;
static int32 warnDSK11 = 0;
static int32 warnDSK12 = 0;
@ -215,7 +217,15 @@ static UNIT dsk_unit[] = {
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
};
static REG dsk_reg[] = {
@ -244,10 +254,6 @@ static MTAB dsk_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if (dsk_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB dsk_dt[] = {
{ "IN", IN_MSG },
@ -262,7 +268,7 @@ static DEBTAB dsk_dt[] = {
DEVICE dsk_dev = {
"DSK", dsk_unit, dsk_reg, dsk_mod,
8, 10, 31, 1, 8, 8,
NUM_OF_DSK, 10, 31, 1, 8, 8,
NULL, NULL, &dsk_reset,
&dsk_boot, NULL, NULL,
NULL, (DEV_DISABLE | DEV_DEBUG), 0,
@ -281,6 +287,11 @@ static t_stat dsk_reset(DEVICE *dptr) {
for (i = 0; i < NUM_OF_DSK; i++) {
warnLock[i] = 0;
warnAttached[i] = 0;
current_track[i] = 0;
current_sector[i] = 0;
current_byte[i] = 0;
current_flag[i] = 0;
tracks[i] = MAX_TRACKS;
}
warnDSK10 = 0;
warnDSK11 = 0;
@ -332,23 +343,30 @@ static void writebuf(void) {
dskbuf[i++] = 0;
uptr = dsk_dev.units + current_disk;
if (((uptr -> flags) & UNIT_DSK_WLK) == 0) { /* write enabled */
TRACE_PRINT(WRITE_MSG, ("DSK%i: " ADDRESS_FORMAT " OUT 0x0a (WRITE) D%d T%d S%d" NLP, current_disk, PCX,
current_disk, current_track[current_disk], current_sector[current_disk]));
sim_debug(WRITE_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT " OUT 0x0a (WRITE) D%d T%d S%d\n",
current_disk, PCX, current_disk,
current_track[current_disk], current_sector[current_disk]);
if (dskseek(uptr)) {
printf("DSK%i: " ADDRESS_FORMAT " fseek failed D%d T%d S%d" NLP, current_disk,
PCX, current_disk, current_track[current_disk], current_sector[current_disk]);
sim_debug(VERBOSE_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT " fseek failed D%d T%d S%d\n",
current_disk, PCX, current_disk,
current_track[current_disk], current_sector[current_disk]);
}
rtn = sim_fwrite(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref);
if (rtn != DSK_SECTSIZE) {
printf("DSK%i: " ADDRESS_FORMAT " sim_fwrite failed T%d S%d Return=%d" NLP, current_disk,
PCX, current_track[current_disk], current_sector[current_disk], rtn);
sim_debug(VERBOSE_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT " sim_fwrite failed T%d S%d Return=%d\n",
current_disk, PCX, current_track[current_disk],
current_sector[current_disk], rtn);
}
}
else if ( (dsk_dev.dctrl & VERBOSE_MSG) && (warnLock[current_disk] < warnLevelDSK) ) {
/* write locked - print warning message if required */
warnLock[current_disk]++;
/*05*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt to write to locked DSK%d - ignored." NLP,
current_disk, PCX, current_disk);
sim_debug(VERBOSE_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT " Attempt to write to locked DSK%d - ignored.\n",
current_disk, PCX, current_disk);
}
current_flag[current_disk] &= 0xfe; /* ENWD off */
current_byte[current_disk] = 0xff;
@ -381,8 +399,10 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) {
if (current_disk >= NUM_OF_DSK) {
if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK10 < warnLevelDSK)) {
warnDSK10++;
/*01*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt of IN 0x08 on unattached disk - ignored." NLP,
current_disk, PCX);
sim_debug(VERBOSE_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT
" Attempt of IN 0x08 on unattached disk - ignored.\n",
current_disk, PCX);
}
return 0xff; /* no drive selected - can do nothing */
}
@ -392,14 +412,16 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) {
/* OUT: Controller set/reset/enable/disable */
if (dirty) /* implies that current_disk < NUM_OF_DSK */
writebuf();
TRACE_PRINT(OUT_MSG, ("DSK%i: " ADDRESS_FORMAT " OUT 0x08: %x" NLP, current_disk, PCX, data));
sim_debug(OUT_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " OUT 0x08: %x\n", current_disk, PCX, data);
current_disk = data & NUM_OF_DSK_MASK; /* 0 <= current_disk < NUM_OF_DSK */
current_disk_flags = (dsk_dev.units + current_disk) -> flags;
if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */
if ( (dsk_dev.dctrl & VERBOSE_MSG) && (warnAttached[current_disk] < warnLevelDSK) ) {
warnAttached[current_disk]++;
/*02*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt to select unattached DSK%d - ignored." NLP,
current_disk, PCX, current_disk);
sim_debug(VERBOSE_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT
" Attempt to select unattached DSK%d - ignored.\n",
current_disk, PCX, current_disk);
}
current_disk = NUM_OF_DSK;
}
@ -407,8 +429,8 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) {
current_sector[current_disk] = 0xff; /* reset internal counters */
current_byte[current_disk] = 0xff;
current_flag[current_disk] = data & 0x80 ? 0 /* disable drive */ :
(current_track[current_disk] == 0 ? 0x5a /* enable: head move true, track 0 if there */ :
0x1a); /* enable: head move true */
(current_track[current_disk] == 0 ? 0x5a /* enable: head move true, track 0 if there */ :
0x1a); /* enable: head move true */
}
return 0; /* ignored since OUT */
}
@ -419,8 +441,10 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
if (current_disk >= NUM_OF_DSK) {
if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK11 < warnLevelDSK)) {
warnDSK11++;
/*03*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt of %s 0x09 on unattached disk - ignored." NLP,
current_disk, PCX, selectInOut(io));
sim_debug(VERBOSE_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT
" Attempt of %s 0x09 on unattached disk - ignored.\n",
current_disk, PCX, selectInOut(io));
}
return 0; /* no drive selected - can do nothing */
}
@ -430,10 +454,11 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
in9_count++;
if ((dsk_dev.dctrl & SECTOR_STUCK_MSG) && (in9_count > 2 * DSK_SECT) && (!in9_message)) {
in9_message = TRUE;
printf("DSK%i: " ADDRESS_FORMAT " Looping on sector find." NLP,
current_disk, PCX);
sim_debug(SECTOR_STUCK_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT " Looping on sector find.\n",
current_disk, PCX);
}
TRACE_PRINT(IN_MSG, ("DSK%i: " ADDRESS_FORMAT " IN 0x09" NLP, current_disk, PCX));
sim_debug(IN_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " IN 0x09\n", current_disk, PCX);
if (dirty) /* implies that current_disk < NUM_OF_DSK */
writebuf();
if (current_flag[current_disk] & 0x04) { /* head loaded? */
@ -442,7 +467,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
current_sector[current_disk] = 0;
current_byte[current_disk] = 0xff;
return (((current_sector[current_disk] << 1) & 0x3e) /* return 'sector true' bit = 0 (true) */
| 0xc0); /* set on 'unused' bits */
| 0xc0); /* set on 'unused' bits */
} else
return 0; /* head not loaded - return 0 */
}
@ -450,12 +475,12 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
in9_count = 0;
/* drive functions */
TRACE_PRINT(OUT_MSG, ("DSK%i: " ADDRESS_FORMAT " OUT 0x09: %x" NLP, current_disk, PCX, data));
sim_debug(OUT_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " OUT 0x09: %x\n", current_disk, PCX, data);
if (data & 0x01) { /* step head in */
if ((dsk_dev.dctrl & TRACK_STUCK_MSG) && (current_track[current_disk] == (tracks[current_disk] - 1))) {
printf("DSK%i: " ADDRESS_FORMAT " Unnecessary step in." NLP,
current_disk, PCX);
}
if (current_track[current_disk] == (tracks[current_disk] - 1))
sim_debug(TRACK_STUCK_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT " Unnecessary step in.\n",
current_disk, PCX);
current_track[current_disk]++;
if (current_track[current_disk] > (tracks[current_disk] - 1))
current_track[current_disk] = (tracks[current_disk] - 1);
@ -466,9 +491,10 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
}
if (data & 0x02) { /* step head out */
if ((dsk_dev.dctrl & TRACK_STUCK_MSG) && (current_track[current_disk] == 0)) {
printf("DSK%i: " ADDRESS_FORMAT " Unnecessary step out." NLP, current_disk, PCX);
}
if (current_track[current_disk] == 0)
sim_debug(TRACK_STUCK_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT " Unnecessary step out.\n",
current_disk, PCX);
current_track[current_disk]--;
if (current_track[current_disk] < 0) {
current_track[current_disk] = 0;
@ -513,8 +539,10 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) {
if (current_disk >= NUM_OF_DSK) {
if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) {
warnDSK12++;
/*04*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt of %s 0x0a on unattached disk - ignored." NLP,
current_disk, PCX, selectInOut(io));
sim_debug(VERBOSE_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT
" Attempt of %s 0x0a on unattached disk - ignored.\n",
current_disk, PCX, selectInOut(io));
}
return 0;
}
@ -525,24 +553,29 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) {
if (io == 0) {
if (current_byte[current_disk] >= DSK_SECTSIZE) {
/* physically read the sector */
TRACE_PRINT(READ_MSG,
("DSK%i: " ADDRESS_FORMAT " IN 0x0a (READ) D%d T%d S%d" NLP, current_disk,
PCX, current_disk, current_track[current_disk], current_sector[current_disk]));
sim_debug(READ_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT " IN 0x0a (READ) D%d T%d S%d\n",
current_disk, PCX, current_disk,
current_track[current_disk], current_sector[current_disk]);
for (i = 0; i < DSK_SECTSIZE; i++)
dskbuf[i] = 0;
if (dskseek(uptr)) {
if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) {
warnDSK12++;
printf("DSK%i: " ADDRESS_FORMAT " fseek error D%d T%d S%d" NLP, current_disk,
PCX, current_disk, current_track[current_disk], current_sector[current_disk]);
sim_debug(VERBOSE_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT " fseek error D%d T%d S%d\n",
current_disk, PCX, current_disk,
current_track[current_disk], current_sector[current_disk]);
}
}
rtn = sim_fread(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref);
if (rtn != DSK_SECTSIZE) {
if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) {
warnDSK12++;
printf("DSK%i: " ADDRESS_FORMAT " sim_fread error D%d T%d S%d" NLP, current_disk,
PCX, current_disk, current_track[current_disk], current_sector[current_disk]);
sim_debug(VERBOSE_MSG, &dsk_dev,
"DSK%i: " ADDRESS_FORMAT " sim_fread error D%d T%d S%d\n",
current_disk, PCX, current_disk,
current_track[current_disk], current_sector[current_disk]);
}
}
current_byte[current_disk] = 0;

View file

@ -1,6 +1,6 @@
/* altairz80_hdsk.c: simulated hard disk device to increase capacity
Copyright (c) 2002-2010, Peter Schorn
Copyright (c) 2002-2011, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -248,10 +248,6 @@ static MTAB hdsk_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if (hdsk_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB hdsk_dt[] = {
{ "READ", READ_MSG },
@ -552,32 +548,37 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) {
static int32 checkParameters(void) {
UNIT *uptr;
if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Disk %i does not exist, will use HDSK0 instead." NLP,
selectedDisk, PCX, selectedDisk));
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
" Disk %i does not exist, will use HDSK0 instead.\n",
selectedDisk, PCX, selectedDisk);
selectedDisk = 0;
}
uptr = &hdsk_dev.units[selectedDisk];
if ((hdsk_dev.units[selectedDisk].flags & UNIT_ATT) == 0) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Disk %i is not attached." NLP,
selectedDisk, PCX, selectedDisk));
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
" Disk %i is not attached.\n", selectedDisk, PCX, selectedDisk);
return FALSE; /* cannot read or write */
}
if ((selectedSector < 0) || (selectedSector >= uptr -> HDSK_SECTORS_PER_TRACK)) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Constraint violation 0 <= Sector=%02d < %d, will use sector 0 instead." NLP,
selectedDisk, PCX, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK));
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
" Constraint violation 0 <= Sector=%02d < %d, will use sector 0 instead.\n",
selectedDisk, PCX, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK);
selectedSector = 0;
}
if ((selectedTrack < 0) || (selectedTrack >= uptr -> HDSK_NUMBER_OF_TRACKS)) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Constraint violation 0 <= Track=%04d < %04d, will use track 0 instead." NLP,
selectedDisk, PCX, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS));
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
" Constraint violation 0 <= Track=%04d < %04d, will use track 0 instead.\n",
selectedDisk, PCX, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS);
selectedTrack = 0;
}
selectedDMA &= ADDRMASK;
if ((hdsk_dev.dctrl & READ_MSG) && (hdskLastCommand == HDSK_READ))
printf("HDSK%d " ADDRESS_FORMAT " Read Track=%04d Sector=%02d Len=%04d DMA=%04x" NLP,
if (hdskLastCommand == HDSK_READ)
sim_debug(READ_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT
" Read Track=%04d Sector=%02d Len=%04d DMA=%04x\n",
selectedDisk, PCX, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA);
if ((hdsk_dev.dctrl & WRITE_MSG) && (hdskLastCommand == HDSK_WRITE))
printf("HDSK%d " ADDRESS_FORMAT " Write Track=%04d Sector=%02d Len=%04d DMA=%04x" NLP,
if (hdskLastCommand == HDSK_WRITE)
sim_debug(WRITE_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT
" Write Track=%04d Sector=%02d Len=%04d DMA=%04x\n",
selectedDisk, PCX, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA);
return TRUE;
}
@ -592,8 +593,9 @@ static int32 doSeek(void) {
if (sim_fseek(uptr -> fileref,
sectorSize * (uptr -> HDSK_SECTORS_PER_TRACK * selectedTrack + hostSector) +
dpb[uptr -> HDSK_FORMAT_TYPE].offset, SEEK_SET)) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not access Sector=%02d[=%02d] Track=%04d." NLP,
selectedDisk, PCX, selectedSector, hostSector, selectedTrack));
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
" Could not access Sector=%02d[=%02d] Track=%04d.\n",
selectedDisk, PCX, selectedSector, hostSector, selectedTrack);
return CPM_ERROR;
}
return CPM_OK;
@ -611,8 +613,9 @@ static int32 doRead(void) {
if (sim_fread(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref) != (size_t)(uptr -> HDSK_SECTOR_SIZE)) {
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
hdskbuf[i] = CPM_EMPTY;
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not read Sector=%02d Track=%04d." NLP,
selectedDisk, PCX, selectedSector, selectedTrack));
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
" Could not read Sector=%02d Track=%04d.\n",
selectedDisk, PCX, selectedSector, selectedTrack);
return CPM_OK; /* allows the creation of empty hard disks */
}
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
@ -632,14 +635,16 @@ static int32 doWrite(void) {
hdskbuf[i] = GetBYTEWrapper(selectedDMA + i);
rtn = sim_fwrite(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref);
if (rtn != (size_t)(uptr -> HDSK_SECTOR_SIZE)) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write Sector=%02d Track=%04d Result=%d." NLP,
selectedDisk, PCX, selectedSector, selectedTrack, (int)rtn));
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
" Could not write Sector=%02d Track=%04d Result=%zd.\n",
selectedDisk, PCX, selectedSector, selectedTrack, rtn);
return CPM_ERROR;
}
}
else {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write to locked disk Sector=%02d Track=%04d." NLP,
selectedDisk, PCX, selectedSector, selectedTrack));
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
" Could not write to locked disk Sector=%02d Track=%04d.\n",
selectedDisk, PCX, selectedSector, selectedTrack);
return CPM_ERROR;
}
return CPM_OK;
@ -660,8 +665,9 @@ static int32 hdsk_in(const int32 port) {
hdskLastCommand = HDSK_NONE;
return parameterBlock[parameterCount - 1];
}
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Illegal IN command detected (port=%03xh, cmd=%d, pos=%d)." NLP,
selectedDisk, PCX, port, hdskLastCommand, hdskCommandPosition));
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
" Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).\n",
selectedDisk, PCX, port, hdskLastCommand, hdskCommandPosition);
return CPM_OK;
}
@ -745,8 +751,9 @@ static int32 hdsk_out(const int32 port, const int32 data) {
if ((HDSK_RESET <= data) && (data <= HDSK_PARAM))
hdskLastCommand = data;
else {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Illegal OUT command detected (port=%03xh, cmd=%d)." NLP,
selectedDisk, PCX, port, data));
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
" Illegal OUT command detected (port=%03xh, cmd=%d).\n",
selectedDisk, PCX, port, data);
hdskLastCommand = HDSK_RESET;
}
hdskCommandPosition = 0;

View file

@ -1,6 +1,6 @@
/* altairz80_net.c: networking capability
Copyright (c) 2002-2010, Peter Schorn
Copyright (c) 2002-2011, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -96,10 +96,6 @@ static MTAB net_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if (net_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB net_dt[] = {
{ "ACCEPT", ACCEPT_MSG },
@ -215,7 +211,7 @@ static t_stat net_svc(UNIT *uptr) {
s = sim_accept_conn(serviceDescriptor[1].masterSocket, NULL);
if (s != INVALID_SOCKET) {
serviceDescriptor[i].ioSocket = s;
TRACE_PRINT(ACCEPT_MSG, ("NET: " ADDRESS_FORMAT " Accepted connection %i with socket %i." NLP, PCX, i, s));
sim_debug(ACCEPT_MSG, &net_dev, "NET: " ADDRESS_FORMAT " Accepted connection %i with socket %i.\n", PCX, i, s);
}
}
}
@ -232,8 +228,7 @@ static t_stat net_svc(UNIT *uptr) {
r = sim_read_sock(serviceDescriptor[i].ioSocket, svcBuffer,
BUFFER_LENGTH - serviceDescriptor[i].inputSize);
if (r == -1) {
TRACE_PRINT(DROP_MSG, ("NET: " ADDRESS_FORMAT " Drop connection %i with socket %i." NLP,
PCX, i, serviceDescriptor[i].ioSocket));
sim_debug(DROP_MSG, &net_dev, "NET: " ADDRESS_FORMAT " Drop connection %i with socket %i.\n", PCX, i, serviceDescriptor[i].ioSocket);
sim_close_sock(serviceDescriptor[i].ioSocket, FALSE);
serviceDescriptor[i].ioSocket = 0;
serviceDescriptor_reset(i);
@ -303,8 +298,7 @@ int32 netData(const int32 port, const int32 io, const int32 data) {
serviceDescriptor[i].inputPosRead = 0;
serviceDescriptor[i].inputSize--;
}
TRACE_PRINT(IN_MSG, ("NET: " ADDRESS_FORMAT " IN(%i)=%03xh (%c)" NLP, PCX, port, (result & 0xff),
(32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?'));
sim_debug(IN_MSG, &net_dev, "NET: " ADDRESS_FORMAT " IN(%i)=%03xh (%c)\n", PCX, port, (result & 0xff), (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?');
return result;
}
else { /* OUT */
@ -319,8 +313,7 @@ int32 netData(const int32 port, const int32 io, const int32 data) {
serviceDescriptor[i].outputPosWrite = 0;
serviceDescriptor[i].outputSize++;
}
TRACE_PRINT(OUT_MSG, ("NET: " ADDRESS_FORMAT " OUT(%i)=%03xh (%c)" NLP, PCX, port, data,
(32 <= data) && (data <= 127) ? data : '?'));
sim_debug(OUT_MSG, &net_dev, "NET: " ADDRESS_FORMAT " OUT(%i)=%03xh (%c)\n", PCX, port, data, (32 <= data) && (data <= 127) ? data : '?');
return 0;
}
}

View file

@ -1,6 +1,6 @@
/* altairz80_sio.c: MITS Altair serial I/O card
Copyright (c) 2002-2010, Peter Schorn
Copyright (c) 2002-2011, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -62,6 +62,23 @@
#include <windows.h>
#endif
uint8 *URLContents(const char *URL, uint32 *length);
#ifndef URL_READER_SUPPORT
#define RESULT_BUFFER_LENGTH 1024
#define RESULT_LEAD_IN "URL is not supported on this platform. START URL \""
#define RESULT_LEAD_OUT "\" URL END."
uint8 *URLContents(const char *URL, uint32 *length) {
char str[RESULT_BUFFER_LENGTH] = RESULT_LEAD_IN;
char *result;
strncat(str, URL, RESULT_BUFFER_LENGTH - strlen(RESULT_LEAD_IN) - strlen(RESULT_LEAD_OUT) - 1);
strcat(str, RESULT_LEAD_OUT);
result = malloc(strlen(str));
strcpy(result, str);
*length = strlen(str);
return (uint8*)result;
}
#endif
/* Debug flags */
#define IN_MSG (1 << 0)
#define OUT_MSG (1 << 1)
@ -143,6 +160,8 @@ extern uint32 getCommon(void);
extern uint8 GetBYTEWrapper(const uint32 Addr);
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
extern uint32 getClockFrequency(void);
extern void setClockFrequency(const uint32 Value);
extern int32 chiptype;
extern const t_bool rtc_avail;
@ -154,10 +173,6 @@ extern UNIT cpu_unit;
extern volatile int32 stop_cpu;
extern int32 sim_interval;
#define TRACE_PRINT(device, level, args) if (device.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB generic_dt[] = {
{ "IN", IN_MSG },
@ -213,6 +228,11 @@ static int32 lastCPMStatus = 0; /* result of last attachCPM comm
static int32 lastCommand = 0; /* most recent command processed on port 0xfeh */
static int32 getCommonPos = 0; /* determines state for sending the 'common' register */
/* CPU Clock Frequency related */
static uint32 newClockFrequency;
static int32 setClockFrequencyPos = 0; /* determines state for sending the clock frequency */
static int32 getClockFrequencyPos = 0; /* determines state for receiving the clock frequency */
/* support for wild card expansion */
#if UNIX_PLATFORM
static glob_t globS;
@ -437,7 +457,7 @@ static void pollConnection(void) {
/* reset routines */
static t_stat sio_reset(DEVICE *dptr) {
int32 i;
TRACE_PRINT(sio_dev, VERBOSE_MSG, ("SIO: " ADDRESS_FORMAT " Reset" NLP, PCX));
sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT " Reset\n", PCX);
sio_unit.u3 = FALSE; /* no character in terminal input buffer */
sio_unit.buf = 0;
resetSIOWarningFlags();
@ -452,7 +472,7 @@ static t_stat sio_reset(DEVICE *dptr) {
}
static t_stat ptr_reset(DEVICE *dptr) {
TRACE_PRINT(ptr_dev, VERBOSE_MSG, ("PTR: " ADDRESS_FORMAT " Reset" NLP, PCX));
sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT " Reset\n", PCX);
resetSIOWarningFlags();
ptr_unit.u3 = FALSE; /* End Of File not yet reached */
ptr_unit.buf = 0;
@ -464,7 +484,7 @@ static t_stat ptr_reset(DEVICE *dptr) {
}
static t_stat ptp_reset(DEVICE *dptr) {
TRACE_PRINT(ptp_dev, VERBOSE_MSG, ("PTP: " ADDRESS_FORMAT " Reset" NLP, PCX));
sim_debug(VERBOSE_MSG, &ptp_dev, "PTP: " ADDRESS_FORMAT " Reset\n", PCX);
resetSIOWarningFlags();
sim_map_resource(0x12, 1, RESOURCE_TYPE_IO, &sio1s, dptr->flags & DEV_DIS);
sim_map_resource(0x13, 1, RESOURCE_TYPE_IO, &sio1d, dptr->flags & DEV_DIS);
@ -506,10 +526,10 @@ typedef struct {
int32 sio_can_read; /* bit mask to indicate that one can read from this port */
int32 sio_cannot_read; /* bit mask to indicate that one cannot read from this port */
int32 sio_can_write; /* bit mask to indicate that one can write to this port */
t_bool hasReset; /* TRUE iff SIO has reset command */
int32 hasReset; /* TRUE iff SIO has reset command */
int32 sio_reset; /* reset command */
t_bool hasOUT; /* TRUE iff port supports OUT command */
t_bool isBuiltin; /* TRUE iff mapping is built in */
int32 hasOUT; /* TRUE iff port supports OUT command */
int32 isBuiltin; /* TRUE iff mapping is built in */
} SIO_PORT_INFO;
static SIO_PORT_INFO port_table[PORT_TABLE_SIZE] = {
@ -677,18 +697,20 @@ static int32 sio0sCore(const int32 port, const int32 io, const int32 data) {
if (spi.hasReset && (data == spi.sio_reset)) { /* reset command */
if (!sio_unit.u4) /* only reset for regular console I/O */
sio_unit.u3 = FALSE; /* indicate that no character is available */
TRACE_PRINT(sio_dev, CMD_MSG,
("\tSIO_S: " ADDRESS_FORMAT " Command OUT(0x%03x) = 0x%02x" NLP, PCX, port, data));
sim_debug(CMD_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT
" Command OUT(0x%03x) = 0x%02x\n", PCX, port, data);
}
return 0x00; /* ignored since OUT */
}
int32 sio0s(const int32 port, const int32 io, const int32 data) {
const int32 result = sio0sCore(port, io, data);
if ((io == 0) && (sio_dev.dctrl & IN_MSG))
printf("\tSIO_S: " ADDRESS_FORMAT " IN(0x%03x) = 0x%02x" NLP, PCX, port, result);
else if ((io) && (sio_dev.dctrl & OUT_MSG))
printf("\tSIO_S: " ADDRESS_FORMAT " OUT(0x%03x) = 0x%02x" NLP, PCX, port, data);
if (io == 0)
sim_debug(IN_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT
" IN(0x%03x) = 0x%02x\n", PCX, port, result);
else if (io)
sim_debug(OUT_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT
" OUT(0x%03x) = 0x%02x\n", PCX, port, data);
return result;
}
@ -701,8 +723,9 @@ static int32 sio0dCore(const int32 port, const int32 io, const int32 data) {
if (io == 0) { /* IN */
if ((sio_unit.flags & UNIT_ATT) && (!sio_unit.u4))
return mapCharacter(tmxr_getc_ln(&TerminalLines[spi.terminalLine]));
if ((!sio_unit.u3) && (sio_dev.dctrl & BUFFER_EMPTY_MSG))
printf("\tSIO_D: " ADDRESS_FORMAT " IN(0x%03x) for empty character buffer" NLP, PCX, port);
if (!sio_unit.u3)
sim_debug(BUFFER_EMPTY_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT
" IN(0x%03x) for empty character buffer\n", PCX, port);
sio_unit.u3 = FALSE; /* no character is available any more */
return mapCharacter(sio_unit.buf); /* return previous character */
} /* OUT follows, no fall-through from IN */
@ -730,10 +753,12 @@ static char* printable(char* result, int32 data, const int32 isIn) {
int32 sio0d(const int32 port, const int32 io, const int32 data) {
char buffer[8];
const int32 result = sio0dCore(port, io, data);
if ((io == 0) && (sio_dev.dctrl & IN_MSG))
printf("\tSIO_D: " ADDRESS_FORMAT " IN(0x%03x) = 0x%02x%s" NLP, PCX, port, result, printable(buffer, result, TRUE));
else if ((io) && (sio_dev.dctrl & OUT_MSG))
printf("\tSIO_D: " ADDRESS_FORMAT " OUT(0x%03x) = 0x%02x%s" NLP, PCX, port, data, printable(buffer, data, FALSE));
if (io == 0)
sim_debug(IN_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT
" IN(0x%03x) = 0x%02x%s\n", PCX, port, result, printable(buffer, result, TRUE));
else if (io)
sim_debug(OUT_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT
" OUT(0x%03x) = 0x%02x%s\n", PCX, port, data, printable(buffer, data, FALSE));
return result;
}
@ -746,7 +771,8 @@ static int32 sio1sCore(const int32 port, const int32 io, const int32 data) {
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* PTR is not attached */
if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTR < warnLevelSIO)) {
warnUnattachedPTR++;
/*06*/ printf("PTR: " ADDRESS_FORMAT " Attempt to test status of unattached PTR[0x%02x]. 0x02 returned." NLP, PCX, port);
/*06*/ sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT
" Attempt to test status of unattached PTR[0x%02x]. 0x02 returned.\n", PCX, port);
}
return SIO_CAN_WRITE;
}
@ -756,18 +782,26 @@ static int32 sio1sCore(const int32 port, const int32 io, const int32 data) {
} /* OUT follows */
if (data == SIO_RESET) {
ptr_unit.u3 = FALSE; /* reset EOF indicator */
TRACE_PRINT(ptr_dev, CMD_MSG,
("PTR: " ADDRESS_FORMAT " Command OUT(0x%03x) = 0x%02x" NLP, PCX, port, data));
sim_debug(CMD_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT
" Command OUT(0x%03x) = 0x%02x\n", PCX, port, data);
}
return 0x00; /* ignored since OUT */
}
int32 sio1s(const int32 port, const int32 io, const int32 data) {
const int32 result = sio1sCore(port, io, data);
if ((io == 0) && ((ptr_dev.dctrl & IN_MSG) || (ptp_dev.dctrl & IN_MSG)))
printf("PTP/PTR_S: " ADDRESS_FORMAT " IN(0x%02x) = 0x%02x" NLP, PCX, port, result);
else if ((io) && ((ptr_dev.dctrl & OUT_MSG) || (ptp_dev.dctrl & OUT_MSG)))
printf("PTP/PTR_S: " ADDRESS_FORMAT " OUT(0x%02x) = 0x%02x" NLP, PCX, port, data);
if (io == 0) {
sim_debug(IN_MSG, &ptr_dev, "PTR_S: " ADDRESS_FORMAT
" IN(0x%02x) = 0x%02x\n", PCX, port, result);
sim_debug(IN_MSG, &ptp_dev, "PTP_S: " ADDRESS_FORMAT
" IN(0x%02x) = 0x%02x\n", PCX, port, result);
}
else if (io) {
sim_debug(OUT_MSG, &ptr_dev, "PTR_S: " ADDRESS_FORMAT
" OUT(0x%02x) = 0x%02x\n", PCX, port, data);
sim_debug(OUT_MSG, &ptp_dev, "PTP_S: " ADDRESS_FORMAT
" OUT(0x%02x) = 0x%02x\n", PCX, port, data);
}
return result;
}
@ -778,14 +812,16 @@ static int32 sio1dCore(const int32 port, const int32 io, const int32 data) {
if (ptr_unit.u3) { /* EOF reached, no more data available */
if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnPTREOF < warnLevelSIO)) {
warnPTREOF++;
/*07*/ printf("PTR: " ADDRESS_FORMAT " PTR[0x%02x] attempted to read past EOF. 0x00 returned." NLP, PCX, port);
/*07*/ sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT
" PTR[0x%02x] attempted to read past EOF. 0x00 returned.\n", PCX, port);
}
return 0x00;
}
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* not attached */
if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTR < warnLevelSIO)) {
warnUnattachedPTR++;
/*08*/ printf("PTR: " ADDRESS_FORMAT " Attempt to read from unattached PTR[0x%02x]. 0x00 returned." NLP, PCX, port);
/*08*/ sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT
" Attempt to read from unattached PTR[0x%02x]. 0x00 returned.\n", PCX, port);
}
return 0x00;
}
@ -800,17 +836,26 @@ static int32 sio1dCore(const int32 port, const int32 io, const int32 data) {
/* else ignore data */
else if ((ptp_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTP < warnLevelSIO)) {
warnUnattachedPTP++;
/*09*/ printf("PTP: " ADDRESS_FORMAT " Attempt to output '0x%02x' to unattached PTP[0x%02x] - ignored." NLP, PCX, data, port);
/*09*/ sim_debug(VERBOSE_MSG, &ptp_dev, "PTP: " ADDRESS_FORMAT
" Attempt to output '0x%02x' to unattached PTP[0x%02x] - ignored.\n", PCX, data, port);
}
return 0x00; /* ignored since OUT */
}
int32 sio1d(const int32 port, const int32 io, const int32 data) {
const int32 result = sio1dCore(port, io, data);
if ((io == 0) && ((ptr_dev.dctrl & IN_MSG) || (ptp_dev.dctrl & IN_MSG)))
printf("PTP/PTR_D: " ADDRESS_FORMAT " IN(0x%02x) = 0x%02x" NLP, PCX, port, result);
else if ((io) && ((ptr_dev.dctrl & OUT_MSG) || (ptp_dev.dctrl & OUT_MSG)))
printf("PTP/PTR_D: " ADDRESS_FORMAT " OUT(0x%02x) = 0x%02x" NLP, PCX, port, data);
if (io == 0) {
sim_debug(IN_MSG, &ptr_dev, "PTR_D: " ADDRESS_FORMAT
" IN(0x%02x) = 0x%02x\n", PCX, port, result);
sim_debug(IN_MSG, &ptp_dev, "PTP_D: " ADDRESS_FORMAT
" IN(0x%02x) = 0x%02x\n", PCX, port, result);
}
else if (io) {
sim_debug(OUT_MSG, &ptr_dev, "PTR_D: " ADDRESS_FORMAT
" OUT(0x%02x) = 0x%02x\n", PCX, port, data);
sim_debug(OUT_MSG, &ptp_dev, "PTP_D: " ADDRESS_FORMAT
" OUT(0x%02x) = 0x%02x\n", PCX, port, data);
}
return result;
}
@ -962,9 +1007,13 @@ int32 nulldev(const int32 port, const int32 io, const int32 data) {
if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnassignedPort < warnLevelSIO)) {
warnUnassignedPort++;
if (io == 0)
printf("SIO: " ADDRESS_FORMAT " Attempt to input from unassigned port 0x%04x - ignored." NLP, PCX, port);
sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT
" Attempt to input from unassigned port 0x%04x - ignored.\n",
PCX, port);
else
printf("SIO: " ADDRESS_FORMAT " Attempt to output 0x%02x to unassigned port 0x%04x - ignored." NLP, PCX, data, port);
sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT
" Attempt to output 0x%02x to unassigned port 0x%04x - ignored.\n",
PCX, data, port);
}
return io == 0 ? 0xff : 0;
}
@ -1010,7 +1059,17 @@ static int32 fromBCD(const int32 x) {
Note: The calling program must request all bytes of the result. Otherwise
the pseudo device is left in an undefined state.
4) Commands requiring parameters and returning results do not exist currently.
4) For commands that do require parameters and return results
ld a,<cmd>
out (0feh),a
ld a,<p1>
out (0feh),a
ld a,<p2>
out (0feh),a
... ; send all parameters
in a,(0feh) ; <A> contains first byte of result
in a,(0feh) ; <A> contains second byte of result
...
*/
@ -1044,12 +1103,14 @@ enum simhPseudoDeviceCommands { /* do not change order or remove commands, add o
readStopWatchCmd, /* 26 read the millisecond stop watch */
SIMHSleepCmd, /* 27 let SIMH sleep for SIMHSleep microseconds */
getHostOSPathSeparatorCmd, /* 28 obtain the file path separator of the OS under which SIMH runs */
getHostFilenamesCmd /* 29 perform wildcard expansion and obtain list of file names */
getHostFilenamesCmd, /* 29 perform wildcard expansion and obtain list of file names */
readURLCmd, /* 30 read the contents of an URL */
getCPUClockFrequency, /* 31 get the clock frequency of the CPU */
setCPUClockFrequency, /* 32 set the clock frequency of the CPU */
kSimhPseudoDeviceCommands
};
static int32 lastSIMHCommand = getHostFilenamesCmd;
static char *cmdNames[] = {
static char *cmdNames[kSimhPseudoDeviceCommands] = {
"printTime",
"startTimer",
"stopTimer",
@ -1079,7 +1140,10 @@ static char *cmdNames[] = {
"readStopWatch",
"SIMHSleep",
"getHostOSPathSeparator",
"getHostFilenames"
"getHostFilenames",
"readURL",
"getCPUClockFrequency",
"setCPUClockFrequency",
};
#define CPM_COMMAND_LINE_LENGTH 128
@ -1087,7 +1151,16 @@ static char *cmdNames[] = {
static uint32 markTime[TIMER_STACK_LIMIT]; /* timer stack */
static struct tm currentTime;
static int32 currentTimeValid = FALSE;
static char version[] = "SIMH003";
static char version[] = "SIMH004";
#define URL_MAX_LENGTH 1024
static uint32 urlPointer;
static char urlStore[URL_MAX_LENGTH];
static uint8 *urlResult = NULL;
static uint32 resultLength;
static uint32 resultPointer;
static int32 showAvailability;
static int32 isInReadPhase;
static t_stat simh_dev_reset(DEVICE *dptr) {
sim_map_resource(0xfe, 1, RESOURCE_TYPE_IO, &simh_dev, dptr->flags & DEV_DIS);
@ -1107,14 +1180,21 @@ static t_stat simh_dev_reset(DEVICE *dptr) {
lastCommand = 0;
lastCPMStatus = SCPE_OK;
timerInterrupt = FALSE;
urlPointer = 0;
getClockFrequencyPos = 0;
setClockFrequencyPos = 0;
if (urlResult != NULL) {
free(urlResult);
urlResult = NULL;
}
if (simh_unit.flags & UNIT_SIMH_TIMERON)
simh_dev_set_timeron(NULL, 0, NULL, NULL);
return SCPE_OK;
}
static void warnNoRealTimeClock(void) {
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Sorry - no real time clock available." NLP, PCX));
sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" Sorry - no real time clock available.\n", PCX);
}
static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *desc) {
@ -1142,11 +1222,11 @@ static t_stat simh_svc(UNIT *uptr) {
else {
uint32 newTimeOfNextInterrupt = now + timerDelta - (now - timeOfNextInterrupt) % timerDelta;
if (newTimeOfNextInterrupt != timeOfNextInterrupt + timerDelta) {
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Timer interrupts skipped %i. Delta %i. Expect %i. Got %i." NLP, PCX,
(newTimeOfNextInterrupt - timeOfNextInterrupt) / timerDelta - 1,
timerDelta,
timeOfNextInterrupt + timerDelta - now, newTimeOfNextInterrupt - now));
sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" Timer interrupts skipped %i. Delta %i. Expect %i. Got %i.\n",
PCX, (newTimeOfNextInterrupt - timeOfNextInterrupt) / timerDelta - 1,
timerDelta, timeOfNextInterrupt + timerDelta - now,
newTimeOfNextInterrupt - now);
}
timeOfNextInterrupt = newTimeOfNextInterrupt;
}
@ -1187,8 +1267,10 @@ static void attachCPM(UNIT *uptr) {
/* 'C' option makes sure that file is properly truncated if it had existed before */
sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */
lastCPMStatus = attach_unit(uptr, cpmCommandLine);
if ((lastCPMStatus != SCPE_OK) && (simh_device.dctrl & VERBOSE_MSG))
printf("SIMH: " ADDRESS_FORMAT " Cannot open '%s' (%s)." NLP, PCX, cpmCommandLine, sim_error_text(lastCPMStatus));
if (lastCPMStatus != SCPE_OK)
sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" Cannot open '%s' (%s).\n", PCX, cpmCommandLine,
sim_error_text(lastCPMStatus));
}
/* setClockZSDOSAdr points to 6 byte block in M: YY MM DD HH MM SS in BCD notation */
@ -1234,6 +1316,25 @@ static void setClockCPM3(void) {
static int32 simh_in(const int32 port) {
int32 result = 0;
switch(lastCommand) {
case readURLCmd:
if (isInReadPhase) {
if (showAvailability) {
if (resultPointer < resultLength)
result = 1;
else {
if (urlResult != NULL)
free(urlResult);
urlResult = NULL;
lastCommand = 0;
}
}
else if (resultPointer < resultLength)
result = urlResult[resultPointer++];
showAvailability = 1 - showAvailability;
}
else
lastCommand = 0;
break;
case getHostFilenamesCmd:
#if UNIX_PLATFORM
@ -1358,8 +1459,8 @@ static int32 simh_in(const int32 port) {
result = getBankSelect();
else {
result = 0;
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Get selected bank ignored for non-banked memory." NLP, PCX));
sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" Get selected bank ignored for non-banked memory.\n", PCX);
}
lastCommand = 0;
break;
@ -1375,6 +1476,17 @@ static int32 simh_in(const int32 port) {
}
break;
case getCPUClockFrequency:
if (getClockFrequencyPos == 0) {
result = getClockFrequency() & 0xff;
getClockFrequencyPos = 1;
}
else {
result = (getClockFrequency() >> 8) & 0xff;
getClockFrequencyPos = lastCommand = 0;
}
break;
case hasBankedMemoryCmd:
result = cpu_unit.flags & UNIT_CPU_BANKED ? MAXBANKS : 0;
lastCommand = 0;
@ -1402,9 +1514,9 @@ static int32 simh_in(const int32 port) {
break;
default:
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Undefined IN from SIMH pseudo device on port %03xh ignored." NLP,
PCX, port));
sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" Undefined IN from SIMH pseudo device on port %03xh ignored.\n",
PCX, port);
result = lastCommand = 0;
}
return result;
@ -1427,7 +1539,26 @@ void do_SIMH_sleep(void) {
static int32 simh_out(const int32 port, const int32 data) {
time_t now;
switch(lastCommand) {
case readURLCmd:
if (isInReadPhase)
lastCommand = 0;
else {
if (data) {
if (urlPointer < URL_MAX_LENGTH - 1)
urlStore[urlPointer++] = data & 0xff;
}
else {
if (urlResult != NULL)
free(urlResult);
urlStore[urlPointer] = 0;
urlResult = URLContents(urlStore, &resultLength);
urlPointer = resultPointer = 0;
showAvailability = 1;
isInReadPhase = TRUE;
}
}
break;
case setClockZSDOSCmd:
if (setClockZSDOSPos == 0) {
setClockZSDOSAdr = data;
@ -1439,7 +1570,7 @@ static int32 simh_out(const int32 port, const int32 data) {
setClockZSDOSPos = lastCommand = 0;
}
break;
case setClockCPM3Cmd:
if (setClockCPM3Pos == 0) {
setClockCPM3Adr = data;
@ -1451,18 +1582,28 @@ static int32 simh_out(const int32 port, const int32 data) {
setClockCPM3Pos = lastCommand = 0;
}
break;
case setCPUClockFrequency:
if (setClockFrequencyPos == 0) {
newClockFrequency = data;
setClockFrequencyPos = 1;
}
else {
setClockFrequency((data << 8) | newClockFrequency);
setClockFrequencyPos = lastCommand = 0;
}
break;
case setBankSelectCmd:
if (cpu_unit.flags & UNIT_CPU_BANKED)
setBankSelect(data & BANKMASK);
else {
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Set selected bank to %i ignored for non-banked memory."
NLP, PCX, data & 3));
}
else
sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" Set selected bank to %i ignored for non-banked memory.\n",
PCX, data & 3);
lastCommand = 0;
break;
case setTimerDeltaCmd:
if (setTimerDeltaPos == 0) {
timerDelta = data;
@ -1473,13 +1614,13 @@ static int32 simh_out(const int32 port, const int32 data) {
setTimerDeltaPos = lastCommand = 0;
if (timerDelta == 0) {
timerDelta = DEFAULT_TIMER_DELTA;
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Timer delta set to 0 ms ignored. Using %i ms instead."
NLP, PCX, DEFAULT_TIMER_DELTA));
sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" Timer delta set to 0 ms ignored. Using %i ms instead.\n",
PCX, DEFAULT_TIMER_DELTA);
}
}
break;
case setTimerInterruptAdrCmd:
if (setTimerInterruptAdrPos == 0) {
timerInterruptHandler = data;
@ -1490,15 +1631,21 @@ static int32 simh_out(const int32 port, const int32 data) {
setTimerInterruptAdrPos = lastCommand = 0;
}
break;
default:
TRACE_PRINT(simh_device, CMD_MSG,
("SIMH: " ADDRESS_FORMAT " CMD(0x%02x) <- %i (0x%02x, '%s')" NLP, PCX, port, data, data,
(0 <= data) && (data <= lastSIMHCommand) ? cmdNames[data] : "Unknown command"));
default: /* lastCommand not yet set */
sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" CMD(0x%02x) <- %i (0x%02x, '%s')\n",
PCX, port, data, data,
(0 <= data) && (data < kSimhPseudoDeviceCommands) ?
cmdNames[data] : "Unknown command");
lastCommand = data;
switch(data) {
case readURLCmd:
urlPointer = 0;
isInReadPhase = FALSE;
break;
case getHostFilenamesCmd:
#if UNIX_PLATFORM
if (!globValid) {
@ -1507,9 +1654,10 @@ static int32 simh_out(const int32 port, const int32 data) {
createCPMCommandLine();
globError = glob(cpmCommandLine, GLOB_ERR, NULL, &globS);
if (globError) {
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Cannot expand '%s'. Error is %i."
NLP, PCX, cpmCommandLine, globError));
sim_debug(VERBOSE_MSG, &simh_device,
"SIMH: " ADDRESS_FORMAT
" Cannot expand '%s'. Error is %i.\n",
PCX, cpmCommandLine, globError);
globfree(&globS);
globValid = FALSE;
}
@ -1523,36 +1671,37 @@ static int32 simh_out(const int32 port, const int32 data) {
setLastPathSeparator();
hFind = FindFirstFile(cpmCommandLine, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE) {
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Cannot expand '%s'. Error is %lu."
NLP, PCX, cpmCommandLine, GetLastError()));
sim_debug(VERBOSE_MSG, &simh_device,
"SIMH: " ADDRESS_FORMAT
" Cannot expand '%s'. Error is %lu.\n",
PCX, cpmCommandLine, GetLastError());
globValid = FALSE;
}
}
#endif
break;
case SIMHSleepCmd:
do_SIMH_sleep();
break;
case printTimeCmd: /* print time */
if (rtc_avail)
printf("SIMH: " ADDRESS_FORMAT " Current time in milliseconds = %d." NLP, PCX, sim_os_msec());
else
warnNoRealTimeClock();
break;
case startTimerCmd: /* create a new timer on top of stack */
if (rtc_avail)
if (markTimeSP < TIMER_STACK_LIMIT)
markTime[markTimeSP++] = sim_os_msec();
else
printf("SIMH: " ADDRESS_FORMAT " Timer stack overflow." NLP, PCX);
else
warnNoRealTimeClock();
else
warnNoRealTimeClock();
break;
case stopTimerCmd: /* stop timer on top of stack and show time difference */
if (rtc_avail)
if (markTimeSP > 0) {
@ -1561,26 +1710,26 @@ static int32 simh_out(const int32 port, const int32 data) {
}
else
printf("SIMH: " ADDRESS_FORMAT " No timer active." NLP, PCX);
else
warnNoRealTimeClock();
else
warnNoRealTimeClock();
break;
case resetPTRCmd: /* reset ptr device */
ptr_reset(&ptr_dev);
break;
case attachPTRCmd: /* attach ptr to the file with name at beginning of CP/M command line */
attachCPM(&ptr_unit);
break;
case detachPTRCmd: /* detach ptr */
detach_unit(&ptr_unit);
break;
case getSIMHVersionCmd:
versionPos = 0;
break;
case getClockZSDOSCmd:
time(&now);
now += ClockZSDOSDelta;
@ -1588,11 +1737,11 @@ static int32 simh_out(const int32 port, const int32 data) {
currentTimeValid = TRUE;
getClockZSDOSPos = 0;
break;
case setClockZSDOSCmd:
setClockZSDOSPos = 0;
break;
case getClockCPM3Cmd:
time(&now);
now += ClockCPM3Delta;
@ -1601,18 +1750,29 @@ static int32 simh_out(const int32 port, const int32 data) {
daysCPM3SinceOrg = (int32) ((now - mkCPM3Origin()) / SECONDS_PER_DAY);
getClockCPM3Pos = 0;
break;
case setClockCPM3Cmd:
setClockCPM3Pos = 0;
break;
case getCommonCmd:
getCommonPos = 0;
break;
case getCPUClockFrequency:
getClockFrequencyPos = 0;
break;
case setCPUClockFrequency:
setClockFrequencyPos = 0;
break;
case getBankSelectCmd:
case setBankSelectCmd:
case getCommonCmd:
case hasBankedMemoryCmd:
case getHostOSPathSeparatorCmd:
break;
case resetSIMHInterfaceCmd:
markTimeSP = 0;
lastCommand = 0;
@ -1630,7 +1790,7 @@ static int32 simh_out(const int32 port, const int32 data) {
}
#endif
break;
case showTimerCmd: /* show time difference to timer on top of stack */
if (rtc_avail)
if (markTimeSP > 0) {
@ -1639,60 +1799,60 @@ static int32 simh_out(const int32 port, const int32 data) {
}
else
printf("SIMH: " ADDRESS_FORMAT " No timer active." NLP, PCX);
else
warnNoRealTimeClock();
else
warnNoRealTimeClock();
break;
case attachPTPCmd: /* attach ptp to the file with name at beginning of CP/M command line */
attachCPM(&ptp_unit);
break;
case detachPTPCmd: /* detach ptp */
detach_unit(&ptp_unit);
break;
case setZ80CPUCmd:
chiptype = CHIP_TYPE_Z80;
break;
case set8080CPUCmd:
chiptype = CHIP_TYPE_8080;
break;
case startTimerInterruptsCmd:
if (simh_dev_set_timeron(NULL, 0, NULL, NULL) == SCPE_OK) {
timerInterrupt = FALSE;
simh_unit.flags |= UNIT_SIMH_TIMERON;
}
break;
case stopTimerInterruptsCmd:
simh_unit.flags &= ~UNIT_SIMH_TIMERON;
simh_dev_set_timeroff(NULL, 0, NULL, NULL);
break;
case setTimerDeltaCmd:
setTimerDeltaPos = 0;
break;
case setTimerInterruptAdrCmd:
setTimerInterruptAdrPos = 0;
break;
case resetStopWatchCmd:
stopWatchNow = rtc_avail ? sim_os_msec() : 0;
break;
case readStopWatchCmd:
getStopWatchDeltaPos = 0;
stopWatchDelta = rtc_avail ? sim_os_msec() - stopWatchNow : 0;
break;
default:
TRACE_PRINT(simh_device, CMD_MSG,
("SIMH: " ADDRESS_FORMAT " Unknown command (%i) to SIMH pseudo device on port %03xh ignored."
NLP, PCX, data, port));
}
sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" Unknown command (%i) to SIMH pseudo device on port %03xh ignored.\n",
PCX, data, port);
}
}
return 0x00; /* ignored, since OUT */
}
@ -1702,15 +1862,17 @@ int32 simh_dev(const int32 port, const int32 io, const int32 data) {
int32 result = 0;
if (io == 0) {
result = simh_in(port);
TRACE_PRINT(simh_device, IN_MSG,
("SIMH: " ADDRESS_FORMAT " IN(0x%02x) -> %i (0x%02x, '%c')" NLP, PCX, port, result, result,
(32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?'));
sim_debug(IN_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" IN(0x%02x) -> %i (0x%02x, '%c')\n", PCX,
port, result, result,
(32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?');
}
else {
TRACE_PRINT(simh_device, OUT_MSG,
("SIMH: " ADDRESS_FORMAT " OUT(0x%02x) <- %i (0x%02x, '%c')" NLP, PCX, port, data, data,
(32 <= (data & 0xff)) && ((data & 0xff) <= 127) ? (data & 0xff) : '?'));
sim_debug(OUT_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
" OUT(0x%02x) <- %i (0x%02x, '%c')\n", PCX,
port, data, data,
(32 <= (data & 0xff)) && ((data & 0xff) <= 127) ? (data & 0xff) : '?');
simh_out(port, data);
}
return result;

View file

@ -1,6 +1,6 @@
/* altairz80_sys.c: MITS Altair system interface
Copyright (c) 2002-2010, Peter Schorn
Copyright (c) 2002-2011, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -202,11 +202,6 @@ static MTAB i8272_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(i8272_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB i8272_dt[] = {
{ "ERROR", ERROR_MSG },
@ -427,26 +422,32 @@ uint8 I8272_Read(const uint32 Addr)
cData |= ~I8272_MSR_FDC_BUSY;
}
#endif /* 0 hharte */
TRACE_PRINT(STATUS_MSG, ("I8272: " ADDRESS_FORMAT " RD FDC MSR = 0x%02x" NLP, PCX, cData));
sim_debug(STATUS_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" RD FDC MSR = 0x%02x\n", PCX, cData);
break;
case I8272_FDC_DATA:
if(i8272_info->fdc_phase == DATA_PHASE) {
cData = i8272_info->result[i8272_info->result_index];
TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " RD Data, phase=%d, [%d]=0x%02x" NLP, PCX, i8272_info->fdc_phase, i8272_info->result_index, cData));
sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" RD Data, phase=%d, [%d]=0x%02x\n",
PCX, i8272_info->fdc_phase, i8272_info->result_index, cData);
i8272_irq = 0;
i8272_info->result_index ++;
if(i8272_info->result_index == i8272_info->result_len) {
TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " result phase complete." NLP, PCX));
sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" result phase complete.\n", PCX);
i8272_info->fdc_phase = CMD_PHASE;
}
} else {
cData = i8272_info->result[0]; /* hack, in theory any value should be ok but this makes "format" work */
TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " error, reading data register when not in data phase. "
"Returning 0x%02x" NLP, PCX, cData));
sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" error, reading data register when not in data phase. "
"Returning 0x%02x\n", PCX, cData);
}
break;
default:
TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " Cannot read register %x" NLP, PCX, Addr));
sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Cannot read register %x\n", PCX, Addr);
cData = 0xFF;
}
@ -475,8 +476,8 @@ static char *messages[0x20] = {
uint8 I8272_Write(const uint32 Addr, uint8 cData)
{
I8272_DRIVE_INFO *pDrive;
uint32 flags = 0;
uint32 readlen;
unsigned int flags = 0;
unsigned int readlen;
uint8 disk_read = 0;
int32 i;
@ -488,19 +489,20 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
switch(Addr & 0x3) {
case I8272_FDC_MSR:
TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " WR Drive Select Reg=%02x" NLP,
PCX, cData));
sim_debug(WR_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" WR Drive Select Reg=%02x\n", PCX, cData);
break;
case I8272_FDC_DATA:
i8272_info->fdc_msr &= 0xF0;
TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " WR Data, phase=%d, index=%d" NLP,
PCX, i8272_info->fdc_phase, i8272_info->cmd_index));
sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" WR Data, phase=%d, index=%d\n",
PCX, i8272_info->fdc_phase, i8272_info->cmd_index);
if(i8272_info->fdc_phase == CMD_PHASE) {
i8272_info->cmd[i8272_info->cmd_index] = cData;
if(i8272_info->cmd_index == 0) {
TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " CMD=0x%02x[%s]" NLP,
PCX, cData & 0x1F, messages[cData & 0x1F]));
sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" CMD=0x%02x[%s]\n", PCX, cData & 0x1F, messages[cData & 0x1F]);
I8272_Setup_Cmd(cData & 0x1F);
}
i8272_info->cmd_index ++;
@ -537,14 +539,12 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
i8272_info->fdc_seek_end = 0;
}
if(pDrive->track != i8272_info->cmd[2]) {
TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT
" ERROR: CMD=0x%02x[%s]: Drive: %d, Command wants track %d, but positioner is on track %d." NLP,
PCX,
i8272_info->cmd[0] & 0x1F,
messages[i8272_info->cmd[0] & 0x1F],
i8272_info->sel_drive,
i8272_info->cmd[2],
pDrive->track));
sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" ERROR: CMD=0x%02x[%s]: Drive: %d, Command wants track %d, "
"but positioner is on track %d.\n",
PCX, i8272_info->cmd[0] & 0x1F,
messages[i8272_info->cmd[0] & 0x1F],
i8272_info->sel_drive, i8272_info->cmd[2], pDrive->track);
}
pDrive->track = i8272_info->cmd[2];
@ -552,30 +552,31 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
i8272_info->fdc_sector = i8272_info->cmd[4];
i8272_info->fdc_sec_len = i8272_info->cmd[5];
if(i8272_info->fdc_sec_len > I8272_MAX_N) {
TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector size %d [N=%d]. Reset to %d [N=%d]." NLP,
PCX, 128 << i8272_info->fdc_sec_len, i8272_info->fdc_sec_len,
128 << I8272_MAX_N, I8272_MAX_N));
sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Illegal sector size %d [N=%d]. Reset to %d [N=%d].\n",
PCX, 128 << i8272_info->fdc_sec_len,
i8272_info->fdc_sec_len, 128 << I8272_MAX_N, I8272_MAX_N);
i8272_info->fdc_sec_len = I8272_MAX_N;
}
i8272_info->fdc_eot = i8272_info->cmd[6];
i8272_info->fdc_gpl = i8272_info->cmd[7];
i8272_info->fdc_dtl = i8272_info->cmd[8];
TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT
" CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, EOT=%02x, GPL=%02x, DTL=%02x" NLP,
PCX,
i8272_info->cmd[0] & 0x1F,
messages[i8272_info->cmd[0] & 0x1F],
i8272_info->sel_drive,
i8272_info->fdc_mt ? "Multi" : "Single",
i8272_info->fdc_mfm ? "MFM" : "FM",
pDrive->track,
i8272_info->fdc_head,
i8272_info->fdc_sector,
i8272_info->fdc_sec_len,
i8272_info->fdc_eot,
i8272_info->fdc_gpl,
i8272_info->fdc_dtl));
sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, "
"EOT=%02x, GPL=%02x, DTL=%02x\n", PCX,
i8272_info->cmd[0] & 0x1F,
messages[i8272_info->cmd[0] & 0x1F],
i8272_info->sel_drive,
i8272_info->fdc_mt ? "Multi" : "Single",
i8272_info->fdc_mfm ? "MFM" : "FM",
pDrive->track,
i8272_info->fdc_head,
i8272_info->fdc_sector,
i8272_info->fdc_sec_len,
i8272_info->fdc_eot,
i8272_info->fdc_gpl,
i8272_info->fdc_dtl);
i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2;
i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 0x03);
@ -613,8 +614,9 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
/* READID to detect non-standard disk formats. */
i8272_info->fdc_sector = pDrive->imd->track[pDrive->track][i8272_info->fdc_hds].start_sector;
if((i8272_info->fdc_sec_len == 0xF8) || (i8272_info->fdc_sec_len > I8272_MAX_N)) { /* Error calculating N or N too large */
TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector size N=%d. Reset to 0." NLP,
PCX, i8272_info->fdc_sec_len));
sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Illegal sector size N=%d. Reset to 0.\n",
PCX, i8272_info->fdc_sec_len);
i8272_info->fdc_sec_len = 0;
return 0xFF;
}
@ -642,8 +644,9 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
pDrive->track = 0;
i8272_info->fdc_phase = CMD_PHASE; /* No result phase */
i8272_info->fdc_seek_end = 1;
TRACE_PRINT(SEEK_MSG, ("I8272: " ADDRESS_FORMAT " Recalibrate: Drive 0x%02x" NLP,
PCX, i8272_info->sel_drive));
sim_debug(SEEK_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Recalibrate: Drive 0x%02x\n",
PCX, i8272_info->sel_drive);
break;
case I8272_FORMAT_TRACK: /* FORMAT A TRACK */
i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6;
@ -662,25 +665,27 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
}
i8272_info->fdc_sec_len = i8272_info->cmd[2];
if(i8272_info->fdc_sec_len > I8272_MAX_N) {
TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector size %d [N=%d]. Reset to %d [N=%d]." NLP,
PCX, 128 << i8272_info->fdc_sec_len, i8272_info->fdc_sec_len,
128 << I8272_MAX_N, I8272_MAX_N));
sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Illegal sector size %d [N=%d]. Reset to %d [N=%d].\n",
PCX, 128 << i8272_info->fdc_sec_len,
i8272_info->fdc_sec_len, 128 << I8272_MAX_N, I8272_MAX_N);
i8272_info->fdc_sec_len = I8272_MAX_N;
}
i8272_info->fdc_sc = i8272_info->cmd[3];
i8272_info->fdc_gpl = i8272_info->cmd[4];
i8272_info->fdc_fillbyte = i8272_info->cmd[5];
TRACE_PRINT(FMT_MSG, ("I8272: " ADDRESS_FORMAT " Format Drive: %d, %s, C=%d. H=%d. N=%d, SC=%d, GPL=%02x, FILL=%02x" NLP,
PCX,
i8272_info->sel_drive,
i8272_info->fdc_mfm ? "MFM" : "FM",
pDrive->track,
i8272_info->fdc_head,
i8272_info->fdc_sec_len,
i8272_info->fdc_sc,
i8272_info->fdc_gpl,
i8272_info->fdc_fillbyte));
sim_debug(FMT_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Format Drive: %d, %s, C=%d. H=%d. N=%d, SC=%d, GPL=%02x, FILL=%02x\n",
PCX,
i8272_info->sel_drive,
i8272_info->fdc_mfm ? "MFM" : "FM",
pDrive->track,
i8272_info->fdc_head,
i8272_info->fdc_sec_len,
i8272_info->fdc_sc,
i8272_info->fdc_gpl,
i8272_info->fdc_fillbyte);
i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2;
i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 0x03);
@ -698,7 +703,8 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
i8272_info->result[6] = i8272_info->fdc_sec_len;
break;
case I8272_SENSE_INTR_STATUS: /* SENSE INTERRUPT STATUS */
TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Sense Interrupt Status" NLP, PCX));
sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Sense Interrupt Status\n", PCX);
i8272_info->result[0] = i8272_info->fdc_seek_end ? 0x20 : 0x00; /* SEEK_END */
i8272_info->result[0] |= i8272_info->sel_drive;
i8272_info->result[1] = pDrive->track;
@ -710,12 +716,12 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
i8272_info->fdc_hlt = ((i8272_info->cmd[2] & 0xFE) >> 1) * 2;
i8272_info->fdc_nd = (i8272_info->cmd[2] & 0x01);
i8272_info->fdc_phase = CMD_PHASE; /* No result phase */
TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s" NLP,
PCX,
i8272_info->fdc_srt,
i8272_info->fdc_hut,
i8272_info->fdc_hlt,
i8272_info->fdc_nd ? "NON-DMA" : "DMA"));
sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s\n",
PCX, i8272_info->fdc_srt,
i8272_info->fdc_hut,
i8272_info->fdc_hlt,
i8272_info->fdc_nd ? "NON-DMA" : "DMA");
break;
case I8272_SENSE_DRIVE_STATUS: /* Setup Status3 Byte */
i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2;
@ -735,8 +741,8 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
i8272_info->result[0] |= (i8272_info->fdc_hds & 1) << 2;
i8272_info->result[0] |= (i8272_info->sel_drive & 0x03);
i8272_info->result[0] |= (pDrive->track == 0) ? DRIVE_STATUS_TRACK0 : 0x00; /* Track 0 */
TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Sense Drive Status = 0x%02x" NLP,
PCX, i8272_info->result[0]));
sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Sense Drive Status = 0x%02x\n", PCX, i8272_info->result[0]);
break;
case I8272_SEEK: /* SEEK */
i8272_info->fdc_mt = (i8272_info->cmd[0] & 0x80) >> 7;
@ -752,15 +758,15 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
pDrive->track = i8272_info->cmd[2];
i8272_info->fdc_head = i8272_info->fdc_hds; /*AGN seek should save the head */
i8272_info->fdc_seek_end = 1;
TRACE_PRINT(SEEK_MSG, ("I8272: " ADDRESS_FORMAT
" Seek Drive: %d, %s %s, C=%d. Skip Deleted Data=%s Head Select=%s" NLP,
PCX,
i8272_info->sel_drive,
i8272_info->fdc_mt ? "Multi" : "Single",
i8272_info->fdc_mfm ? "MFM" : "FM",
i8272_info->cmd[2],
i8272_info->fdc_sk ? "True" : "False",
i8272_info->fdc_hds ? "True" : "False"));
sim_debug(SEEK_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Seek Drive: %d, %s %s, C=%d. Skip Deleted Data=%s Head Select=%s\n",
PCX,
i8272_info->sel_drive,
i8272_info->fdc_mt ? "Multi" : "Single",
i8272_info->fdc_mfm ? "MFM" : "FM",
i8272_info->cmd[2],
i8272_info->fdc_sk ? "True" : "False",
i8272_info->fdc_hds ? "True" : "False");
break;
default: /* INVALID */
break;
@ -777,10 +783,11 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
case I8272_WRITE_DATA:
case I8272_WRITE_DELETED_DATA:
for(;i8272_info->fdc_sector<=i8272_info->fdc_eot;i8272_info->fdc_sector++) {
TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " %s Data, sector: %d sector len=%d" NLP,
PCX, disk_read ? "RD" : "WR",
i8272_info->fdc_sector,
128 << i8272_info->fdc_sec_len));
sim_debug(RD_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" %s Data, sector: %d sector len=%d\n",
PCX, disk_read ? "RD" : "WR",
i8272_info->fdc_sector,
128 << i8272_info->fdc_sec_len);
if(pDrive->imd == NULL) {
printf(".imd is NULL!" NLP);
@ -799,20 +806,21 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
PutByteDMA(i8272_info->fdc_dma_addr, sdata.raw[i]);
i8272_info->fdc_dma_addr++;
}
TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " T:%d/H:%d/S:%d/L:%4d: Data transferred to RAM at 0x%06x" NLP,
PCX,
pDrive->track,
i8272_info->fdc_head,
i8272_info->fdc_sector,
128 << i8272_info->fdc_sec_len,
i8272_info->fdc_dma_addr - i));
sim_debug(RD_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" T:%d/H:%d/S:%d/L:%4d: Data transferred to RAM at 0x%06x\n",
PCX, pDrive->track,
i8272_info->fdc_head,
i8272_info->fdc_sector,
128 << i8272_info->fdc_sec_len,
i8272_info->fdc_dma_addr - i);
} else { /* Write */
for(i=0;i<(128 << i8272_info->fdc_sec_len);i++) {
sdata.raw[i] = GetByteDMA(i8272_info->fdc_dma_addr);
i8272_info->fdc_dma_addr++;
}
TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " Data transferred from RAM at 0x%06x" NLP,
PCX, i8272_info->fdc_dma_addr));
sim_debug(WR_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Data transferred from RAM at 0x%06x\n",
PCX, i8272_info->fdc_dma_addr);
sectWrite(pDrive->imd,
pDrive->track,
i8272_info->fdc_head,
@ -829,14 +837,12 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
break;
case I8272_FORMAT_TRACK: /* FORMAT A TRACK */
for(i8272_info->fdc_sector = 1;i8272_info->fdc_sector<=i8272_info->fdc_sc;i8272_info->fdc_sector++) {
TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Format Track %d, Sector=%d, len=%d" NLP,
PCX,
pDrive->track,
i8272_info->fdc_sector,
128 << i8272_info->fdc_sec_len));
sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Format Track %d, Sector=%d, len=%d\n", PCX, pDrive->track, i8272_info->fdc_sector, 128 << i8272_info->fdc_sec_len);
if(i8272_info->fdc_sectorcount >= I8272_MAX_SECTOR) {
TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector count" NLP, PCX));
sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Illegal sector count\n", PCX);
i8272_info->fdc_sectorcount = 0;
}
i8272_info->fdc_sectormap[i8272_info->fdc_sectorcount] = i8272_info->fdc_sector;
@ -862,16 +868,20 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData)
case I8272_SCAN_LOW_EQUAL: /* SCAN LOW OR EQUAL */
case I8272_SCAN_HIGH_EQUAL: /* SCAN HIGH OR EQUAL */
case I8272_SCAN_EQUAL: /* SCAN EQUAL */
TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Scan Data" NLP,
PCX));
TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " ERROR: Scan not implemented." NLP, PCX));
sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" Scan Data\n", PCX);
sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" ERROR: Scan not implemented.\n", PCX);
break;
case I8272_READ_ID: /* READ ID */
TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT
" READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x C=%d H=%d R=%02x N=%d"
NLP, PCX, i8272_info->sel_drive, i8272_info->result[0],
i8272_info->result[1],i8272_info->result[2],i8272_info->result[3],
i8272_info->result[4],i8272_info->result[5],i8272_info->result[6]));
sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT
" READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x "
"C=%d H=%d R=%02x N=%d\n", PCX,
i8272_info->sel_drive,
i8272_info->result[0], i8272_info->result[1],
i8272_info->result[2], i8272_info->result[3],
i8272_info->result[4], i8272_info->result[5],
i8272_info->result[6]);
break;
default:
@ -956,7 +966,7 @@ extern void raise_disk1a_interrupt(void);
static void raise_i8272_interrupt(void)
{
TRACE_PRINT(IRQ_MSG, ("I8272: " ADDRESS_FORMAT " FDC Interrupt" NLP, PCX));
sim_debug(IRQ_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " FDC Interrupt\n", PCX);
i8272_irq = 1;
raise_disk1a_interrupt();
}

File diff suppressed because it is too large Load diff

View file

@ -161,10 +161,6 @@ static MTAB mfdc_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(mfdc_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB mfdc_dt[] = {
{ "ERROR", ERROR_MSG },
@ -402,7 +398,7 @@ static uint8 MFDC_Read(const uint32 Addr)
cData |= (1 << 7); /* Sector Flag */
mfdc_info->xfr_flag = 1; /* Drive has data */
mfdc_info->datacount = 0;
TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Sector Register = 0x%02x" NLP, PCX, cData));
sim_debug(STATUS_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Sector Register = 0x%02x\n", PCX, cData);
break;
case 1:
cData = (mfdc_info->sel_drive & 0x3); /* [1:0] selected drive */
@ -414,15 +410,15 @@ static uint8 MFDC_Read(const uint32 Addr)
cData |= (0 << 6); /* [6] PINTE from S-100 Bus */
cData |= (mfdc_info->xfr_flag << 7); /* [7] Transfer Flag */
TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Status = 0x%02x" NLP, PCX, cData));
sim_debug(STATUS_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Status = 0x%02x\n", PCX, cData);
break;
case 2:
case 3:
if(mfdc_info->datacount == 0) {
unsigned int i, checksum;
unsigned long sec_offset;
uint32 flags;
uint32 readlen;
unsigned int flags;
unsigned int readlen;
/* Clear out unused portion of sector. */
memset(&sdata.u.unused[0], 0x00, 10);
@ -431,10 +427,7 @@ static uint8 MFDC_Read(const uint32 Addr)
sdata.u.header[0] = pDrive->track;
sdata.u.header[1] = pDrive->sector;
TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " RD Data T:%d S:[%d]" NLP,
PCX,
pDrive->track,
pDrive->sector));
sim_debug(RD_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Data T:%d S:[%d]\n", PCX, pDrive->track, pDrive->sector);
#ifdef USE_VGI
sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \
@ -509,8 +502,7 @@ static uint8 MFDC_Read(const uint32 Addr)
mfdc_info->datacount++;
if(mfdc_info->datacount == 270) {
TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " Read sector [%d] complete" NLP,
PCX, pDrive->sector));
sim_debug(RD_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Read sector [%d] complete\n", PCX, pDrive->sector);
mfdc_info->read_in_progress = FALSE;
}
@ -524,8 +516,8 @@ static uint8 MFDC_Read(const uint32 Addr)
static uint8 MFDC_Write(const uint32 Addr, uint8 cData)
{
unsigned int sec_offset;
uint32 flags = 0;
uint32 writelen;
unsigned int flags = 0;
unsigned int writelen;
MFDC_DRIVE_INFO *pDrive;
pDrive = &mfdc_info->drive[mfdc_info->sel_drive];
@ -564,10 +556,7 @@ static uint8 MFDC_Write(const uint32 Addr, uint8 cData)
mfdc_info->datacount ++;
if(mfdc_info->datacount == 270) {
TRACE_PRINT(WR_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " WR Data T:%d S:[%d]" NLP,
PCX,
pDrive->track,
pDrive->sector));
sim_debug(WR_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " WR Data T:%d S:[%d]\n", PCX, pDrive->track, pDrive->sector);
if (!(pDrive->uptr->flags & UNIT_ATT)) {
if (pDrive->uptr->flags & UNIT_MFDC_VERBOSE)
@ -641,7 +630,7 @@ static void MFDC_Command(uint8 cData)
switch(cCommand) {
case MFDC_CMD_NOP:
TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " No Op." NLP, PCX));
sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " No Op.\n", PCX);
break;
case MFDC_CMD_SELECT:
mfdc_info->sel_drive = cModifier & 0x03;
@ -654,13 +643,11 @@ static void MFDC_Command(uint8 cData)
pDrive->ready = 0;
}
TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Select Drive: %d, Head: %s" NLP,
PCX, mfdc_info->sel_drive, (mfdc_info->head) ? "Upper" : "Lower"));
sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Select Drive: %d, Head: %s\n", PCX, mfdc_info->sel_drive, (mfdc_info->head) ? "Upper" : "Lower");
break;
case MFDC_CMD_INTR:
mfdc_info->int_enable = cModifier & 1; /* 0=int disable, 1=enable */
TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Interrupts %s." NLP,
PCX, mfdc_info->int_enable ? "Enabled" : "Disabled"));
sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Interrupts %s.\n", PCX, mfdc_info->int_enable ? "Enabled" : "Disabled");
break;
case MFDC_CMD_STEP:
if(cModifier & 1) { /* Step IN */
@ -672,23 +659,22 @@ static void MFDC_Command(uint8 cData)
}
}
TRACE_PRINT(SEEK_MSG, ("MFDC: " ADDRESS_FORMAT " Step %s, Track=%d." NLP,
PCX, (cModifier & 1) ? "IN" : "OUT", pDrive->track));
sim_debug(SEEK_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Step %s, Track=%d.\n", PCX, (cModifier & 1) ? "IN" : "OUT", pDrive->track);
break;
case MFDC_CMD_SET_WRITE:
TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Set WRITE." NLP, PCX));
sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Set WRITE.\n", PCX);
mfdc_info->wr_latch = 1; /* Allow writes for the current sector */
mfdc_info->datacount = 0; /* reset the byte counter */
break;
case MFDC_CMD_RESET:
TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Reset Controller." NLP, PCX));
sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Reset Controller.\n", PCX);
mfdc_info->selected = 0; /* de-select the drive */
mfdc_info->wr_latch = 0; /* Disable the write latch */
mfdc_info->datacount = 0; /* reset the byte counter */
break;
default:
TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Unsupported command." NLP, PCX));
sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Unsupported command.\n", PCX);
break;
}
}

View file

@ -136,10 +136,6 @@ static MTAB n8vem_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(n8vem_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB n8vem_dt[] = {
{ "ERROR", ERROR_MSG },
@ -165,7 +161,7 @@ static t_stat n8vem_reset(DEVICE *dptr)
{
PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reset.\n"));
sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Reset.\n");
if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */
sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &n8vemdev, TRUE);
@ -196,7 +192,7 @@ static t_stat n8vem_reset(DEVICE *dptr)
static t_stat n8vem_boot(int32 unitno, DEVICE *dptr)
{
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Boot.\n"));
sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Boot.\n");
/* Clear the RAM and ROM mapping registers */
n8vem_info->mpcl_ram = 0;
@ -226,7 +222,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr)
/* Determine length of this disk */
uptr->capac = sim_fsize(uptr->fileref);
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Attach %s.\n", i == 0 ? "ROM" : "RAM"));
sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Attach %s.\n", i == 0 ? "ROM" : "RAM");
if(i == 0) { /* Attaching ROM */
n8vem_info->rom_attached = TRUE;
@ -240,9 +236,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr)
uptr->capac = N8VEM_ROM_SIZE;
rtn = fread((void *)(n8vem_info->rom), uptr->capac, 1, uptr->fileref);
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into ROM."
" Result = %ssuccessful.\n",
uptr->capac, rtn == 1 ? "" : "not "));
sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Reading %d bytes into ROM." " Result = %ssuccessful.\n", uptr->capac, rtn == 1 ? "" : "not ");
}
} else { /* attaching RAM */
/* Erase RAM */
@ -254,9 +248,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr)
uptr->capac = N8VEM_RAM_SIZE;
rtn = fread((void *)(n8vem_info->ram), uptr->capac, 1, uptr->fileref);
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into RAM."
" Result = %ssuccessful.\n",
uptr->capac, rtn == 1 ? "" : "not "));
sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Reading %d bytes into RAM." " Result = %ssuccessful.\n", uptr->capac, rtn == 1 ? "" : "not ");
}
}
return r;
@ -274,7 +266,7 @@ static t_stat n8vem_detach(UNIT *uptr)
return (SCPE_IERR);
}
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Detach %s.\n", i == 0 ? "ROM" : "RAM"));
sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Detach %s.\n", i == 0 ? "ROM" : "RAM");
/* rewind to the beginning of the file. */
sim_fseek(uptr->fileref, 0, SEEK_SET);
@ -282,13 +274,13 @@ static t_stat n8vem_detach(UNIT *uptr)
if(i == 0) { /* ROM */
/* Save the ROM back to disk if SAVEROM is set. */
if(save_rom == 1) {
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Writing %d bytes into ROM image.\n", N8VEM_ROM_SIZE));
sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Writing %d bytes into ROM image.\n", N8VEM_ROM_SIZE);
fwrite((void *)(n8vem_info->rom), N8VEM_ROM_SIZE, 1, uptr->fileref);
}
} else { /* RAM */
/* Save the RAM back to disk if SAVERAM is set. */
if(save_ram == 1) {
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Writing %d bytes into RAM image.\n", N8VEM_RAM_SIZE));
sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Writing %d bytes into RAM image.\n", N8VEM_RAM_SIZE);
fwrite((void *)(n8vem_info->ram), N8VEM_RAM_SIZE, 1, uptr->fileref);
}
}
@ -334,7 +326,7 @@ static t_stat n8vem_detach(UNIT *uptr)
if(save_rom == 1) {
n8vem_info->rom[((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK)] = data;
} else {
TRACE_PRINT(ROM_MSG, ("N8VEM: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM." NLP, PCX, ((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK)));
sim_debug(ROM_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM.\n", PCX, ((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK));
}
}
return 0;
@ -391,19 +383,19 @@ static uint8 N8VEM_Read(const uint32 Addr)
switch(Addr & 0x1F) {
case N8VEM_PIO1A:
TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1A" NLP, PCX));
sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1A\n", PCX);
cData = n8vem_pio1a;
break;
case N8VEM_PIO1B:
TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1B" NLP, PCX));
sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1B\n", PCX);
cData = n8vem_pio1b;
break;
case N8VEM_PIO1C:
TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1C" NLP, PCX));
sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1C\n", PCX);
cData = n8vem_pio1c;
break;
case N8VEM_PIO1CONT:
TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1CTRL" NLP, PCX));
sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1CTRL\n", PCX);
cData = n8vem_pio1ctrl;
break;
case N8VEM_UART_LCR:
@ -415,7 +407,7 @@ static uint8 N8VEM_Read(const uint32 Addr)
case N8VEM_UART_INTR:
case N8VEM_UART_MCR:
case N8VEM_UART_MSR:
TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " RD[%02x]: UART not Implemented." NLP, PCX, Addr));
sim_debug(UART_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD[%02x]: UART not Implemented.\n", PCX, Addr);
break;
case N8VEM_UART_SCR: /* 16550 Scratchpad, implemented so software can detect UART is present */
cData = n8vem_info->uart_scr;
@ -424,16 +416,16 @@ static uint8 N8VEM_Read(const uint32 Addr)
case N8VEM_MPCL_RAM1:
case N8VEM_MPCL_RAM2:
case N8VEM_MPCL_RAM3:
TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: MPCL_RAM not Implemented." NLP, PCX));
sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: MPCL_RAM not Implemented.\n", PCX);
break;
case N8VEM_MPCL_ROM:
case N8VEM_MPCL_ROM1:
case N8VEM_MPCL_ROM2:
case N8VEM_MPCL_ROM3:
TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: MPCL_ROM not Implemented." NLP, PCX));
sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: MPCL_ROM not Implemented.\n", PCX);
break;
default:
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: " ADDRESS_FORMAT " RD[%02x]: not Implemented." NLP, PCX, Addr));
sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD[%02x]: not Implemented.\n", PCX, Addr);
break;
}
@ -446,23 +438,23 @@ static uint8 N8VEM_Write(const uint32 Addr, uint8 cData)
switch(Addr & 0x1F) {
case N8VEM_PIO1A:
TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1A=0x%02x" NLP, PCX, cData));
sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1A=0x%02x\n", PCX, cData);
n8vem_pio1a = cData;
break;
case N8VEM_PIO1B:
TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1B=0x%02x" NLP, PCX, cData));
sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1B=0x%02x\n", PCX, cData);
n8vem_pio1b = cData;
break;
case N8VEM_PIO1C:
TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1C=0x%02x" NLP, PCX, cData));
sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1C=0x%02x\n", PCX, cData);
n8vem_pio1c = cData;
break;
case N8VEM_PIO1CONT:
TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1_CTRL=0x%02x" NLP, PCX, cData));
sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1_CTRL=0x%02x\n", PCX, cData);
n8vem_pio1ctrl = cData;
break;
case N8VEM_UART_LCR:
TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: UART LCR=%02x." NLP, PCX, cData));
sim_debug(UART_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: UART LCR=%02x.\n", PCX, cData);
n8vem_info->uart_lcr = cData;
break;
case N8VEM_UART_DATA:
@ -471,7 +463,7 @@ static uint8 N8VEM_Write(const uint32 Addr, uint8 cData)
case N8VEM_UART_MCR:
case N8VEM_UART_LSR:
case N8VEM_UART_MSR:
TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " WR[%02x]: UART not Implemented." NLP, PCX, Addr));
sim_debug(UART_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR[%02x]: UART not Implemented.\n", PCX, Addr);
break;
case N8VEM_UART_SCR: /* 16550 Scratchpad, implemented so software can detect UART is present */
n8vem_info->uart_scr = cData;
@ -480,18 +472,18 @@ static uint8 N8VEM_Write(const uint32 Addr, uint8 cData)
case N8VEM_MPCL_RAM1:
case N8VEM_MPCL_RAM2:
case N8VEM_MPCL_RAM3:
TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: MPCL_RAM=0x%02x" NLP, PCX, cData));
sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: MPCL_RAM=0x%02x\n", PCX, cData);
n8vem_info->mpcl_ram = cData;
break;
case N8VEM_MPCL_ROM:
case N8VEM_MPCL_ROM1:
case N8VEM_MPCL_ROM2:
case N8VEM_MPCL_ROM3:
TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: MPCL_ROM=0x%02x" NLP, PCX, cData));
sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: MPCL_ROM=0x%02x\n", PCX, cData);
n8vem_info->mpcl_rom = cData;
break;
default:
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented." NLP, PCX, Addr, cData));
sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented.\n", PCX, Addr, cData);
break;
}

View file

@ -86,7 +86,7 @@ typedef struct {
uint8 ipend; /* Interrupt Pending Register */
} CROMFDC_INFO;
extern WD179X_INFO_PUB *wd179x_info;
extern WD179X_INFO_PUB *wd179x_infop;
static CROMFDC_INFO cromfdc_info_data = { { 0xC000, CROMFDC_ROM_SIZE, 0x3, 2 } };
static CROMFDC_INFO *cromfdc_info = &cromfdc_info_data;
@ -248,10 +248,6 @@ static MTAB cromfdc_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(cromfdc_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB cromfdc_dt[] = {
{ "ERROR", ERROR_MSG },
@ -1463,13 +1459,13 @@ static t_stat cromfdc_svc (UNIT *uptr)
motor_timeout ++;
if(motor_timeout == MOTOR_TO_LIMIT) {
cromfdc_info->motor_on = 0;
TRACE_PRINT(DRIVE_MSG, ("CROMFDC: Motor OFF" NLP))
sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: Motor OFF\n");
}
}
cromfdc_info->rtc ++;
TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: " ADDRESS_FORMAT " Timer IRQ" NLP, PCX));
sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " Timer IRQ\n", PCX);
cromfdc_info->ipend |= CROMFDC_IRQ_TIMER3;
/* sim_activate (cromfdc_unit, cromfdc_unit->wait); */ /* requeue! */
@ -1498,14 +1494,13 @@ static t_stat cromfdc_reset(DEVICE *dptr)
} else {
/* Connect CROMFDC ROM at base address */
if (cromfdc_hasProperty(UNIT_CROMFDC_ROM)) {
TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: ROM Enabled." NLP));
sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: ROM Enabled.\n");
if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &cromfdcrom, FALSE) != 0) {
printf("%s: error mapping MEM resource at 0x%04x" NLP, __FUNCTION__, pnp->io_base);
return SCPE_ARG;
}
} else {
TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: ROM Disabled." NLP))
}
} else
sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: ROM Disabled.\n");
/* Connect CROMFDC Interrupt, and Aux Disk Registers */
if(sim_map_resource(0x03, 0x02, RESOURCE_TYPE_IO, &cromfdc_ext, FALSE) != 0) {
printf("%s: error mapping I/O resource at 0x%04x" NLP, __FUNCTION__, pnp->io_base);
@ -1535,7 +1530,7 @@ static t_stat cromfdc_reset(DEVICE *dptr)
printf("%s: error mapping I/O resource at 0x%04x" NLP, __FUNCTION__, pnp->io_base);
return SCPE_ARG;
} else {
TRACE_PRINT(VERBOSE_MSG, ("Mapped CCS2810 UART Status at 0x26" NLP));
sim_debug(VERBOSE_MSG, &cromfdc_dev, "Mapped CCS2810 UART Status at 0x26\n");
}
}
@ -1585,29 +1580,28 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data)
if(io) { /* I/O Write */
switch(data & 0x0F) {
case 0:
wd179x_info->sel_drive = 0xFF;
wd179x_infop->sel_drive = 0xFF;
break;
case CROMFDC_CTRL_DS1:
wd179x_info->sel_drive = 0;
wd179x_infop->sel_drive = 0;
break;
case CROMFDC_CTRL_DS2:
wd179x_info->sel_drive = 1;
wd179x_infop->sel_drive = 1;
break;
case CROMFDC_CTRL_DS3:
wd179x_info->sel_drive = 2;
wd179x_infop->sel_drive = 2;
break;
case CROMFDC_CTRL_DS4:
wd179x_info->sel_drive = 3;
wd179x_infop->sel_drive = 3;
break;
default:
TRACE_PRINT(STATUS_MSG,
("CROMFDC: " ADDRESS_FORMAT " WR CTRL = 0x%02x: Invalid drive selected." NLP, PCX, data & 0xFF));
sim_debug(STATUS_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL = 0x%02x: Invalid drive selected.\n", PCX, data & 0xFF);
break;
}
if(data & CROMFDC_CTRL_MAXI) {
wd179x_info->drivetype = 8;
wd179x_infop->drivetype = 8;
} else {
wd179x_info->drivetype = 5;
wd179x_infop->drivetype = 5;
}
if(data & CROMFDC_CTRL_MTRON) {
@ -1617,13 +1611,12 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data)
if(data & CROMFDC_CTRL_DDENS) {
if(crofdc_type == 4) { /* 4FDC */
TRACE_PRINT(DRIVE_MSG,
("CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set double density on 4FDC" NLP, PCX));
sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set double density on 4FDC\n", PCX);
} else {
wd179x_info->ddens = 1;
wd179x_infop->ddens = 1;
}
} else {
wd179x_info->ddens = 0;
wd179x_infop->ddens = 0;
}
if(data & CROMFDC_CTRL_AUTOWAIT) {
cromfdc_info->autowait = 1;
@ -1631,13 +1624,11 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data)
cromfdc_info->autowait = 0;
}
TRACE_PRINT(DRIVE_MSG,
("CROMFDC: " ADDRESS_FORMAT " WR CTRL: sel_drive=%d, drivetype=%d, motor=%d, dens=%d, aw=%d" NLP, PCX,
wd179x_info->sel_drive, wd179x_info->drivetype, cromfdc_info->motor_on, wd179x_info->ddens, cromfdc_info->autowait));
sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL: sel_drive=%d, drivetype=%d, motor=%d, dens=%d, aw=%d\n", PCX, wd179x_infop->sel_drive, wd179x_infop->drivetype, cromfdc_info->motor_on, wd179x_infop->ddens, cromfdc_info->autowait);
} else { /* I/O Read */
result = (crofdc_boot) ? 0 : CROMFDC_FLAG_BOOT;
result |= (wd179x_info->intrq) ? CROMFDC_FLAG_EOJ : 0;
result |= (wd179x_info->drq) ? CROMFDC_FLAG_DRQ : 0;
result |= (wd179x_infop->intrq) ? CROMFDC_FLAG_EOJ : 0;
result |= (wd179x_infop->drq) ? CROMFDC_FLAG_DRQ : 0;
if(crofdc_type != 50) { /* Cromemco Controller */
result |= (motor_timeout < MOTOR_TO_LIMIT) ? CROMFDC_FLAG_SEL_REQ : 0;
if(crofdc_type > 4) { /* 16, 64FDC */
@ -1648,7 +1639,7 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data)
result |= 0x1E; /* Make unused bits '1' on 4FDC */
}
} else { /* CCS 2422 Controller */
switch(wd179x_info->sel_drive) {
switch(wd179x_infop->sel_drive) {
case 1:
result |= 0x02;
break;
@ -1665,8 +1656,8 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data)
/* printf("CCS2422FDC: " ADDRESS_FORMAT " Read STATUS1=0x%02x" NLP, PCX, result); */
}
TRACE_PRINT(STATUS_MSG,
("CROMFDC: " ADDRESS_FORMAT " Read DISK FLAGS, Port 0x%02x Result 0x%02x" NLP, PCX, port, result))
sim_debug(STATUS_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT
" Read DISK FLAGS, Port 0x%02x Result 0x%02x\n", PCX, port, result);
}
return result;
@ -1684,13 +1675,12 @@ static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data)
if(crofdc_type != 50) { /* Cromemco Controller */
if((data & CROMFDC_AUX_CMD_SIDE) == 0) {
if(crofdc_type == 4) { /* 4FDC */
TRACE_PRINT(DRIVE_MSG,
("CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set side 1 on 4FDC" NLP, PCX));
sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set side 1 on 4FDC\n", PCX);
} else {
wd179x_info->fdc_head = 1;
wd179x_infop->fdc_head = 1;
}
} else {
wd179x_info->fdc_head = 0;
wd179x_infop->fdc_head = 0;
}
#if 0 /* hharte - nothing implemented for these */
if((data & CROMFDC_AUX_EJECT) == 0) {
@ -1710,21 +1700,20 @@ static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data)
}
} else { /* CCS 2422 Controller */
if((data & CCSFDC_CMD_SIDE) == 0) {
wd179x_info->fdc_head = 1;
wd179x_infop->fdc_head = 1;
} else {
wd179x_info->fdc_head = 0;
wd179x_infop->fdc_head = 0;
}
}
} else if (port == 0x3) { /* Interrupt Address */
TRACE_PRINT(IRQ_MSG,
("CROMFDC: " ADDRESS_FORMAT " IRQ Mask=0x%02x" NLP, PCX, data));
sim_debug(IRQ_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " IRQ Mask=0x%02x\n", PCX, data);
cromfdc_info->imask = data;
} else {
}
TRACE_PRINT(DRIVE_MSG,
("CROMFDC: " ADDRESS_FORMAT " AUX OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data))
sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT
" AUX OUT, Port 0x%02x Data 0x%02x\n", PCX, port, data);
result = 0;
} else { /* I/O Read */
if(port == 0x4) {
@ -1732,20 +1721,18 @@ static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data)
result |= 0x00; /* Bit 6 is Seek in Progress for Persci drives. */
result |= (cromfdc_info->rtc & 1) ? 0x80 : 0;
if(crofdc_type == 50) {
TRACE_PRINT(STATUS_MSG,
("CCS2422FDC: " ADDRESS_FORMAT " Read STATUS2=0x%02x" NLP, PCX, result));
sim_debug(STATUS_MSG, &cromfdc_dev, "CCS2422FDC: " ADDRESS_FORMAT " Read STATUS2=0x%02x\n", PCX, result);
}
} else if (port == 0x3) { /* Interrupt Address */
result = ipend_to_rst_opcode(cromfdc_info->ipend);
if(result != 0) {
TRACE_PRINT(IRQ_MSG,
("CROMFDC: " ADDRESS_FORMAT " RST Opcode=%x, Vector=%04x" NLP, PCX, result, RST_OPCODE_TO_VECTOR(result)));
sim_debug(IRQ_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " RST Opcode=%x, Vector=%04x\n", PCX, result, RST_OPCODE_TO_VECTOR(result));
}
} else {
result = 0xFF;
}
TRACE_PRINT(STATUS_MSG,
("CROMFDC: " ADDRESS_FORMAT " AUX IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result))
sim_debug(STATUS_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT
" AUX IN, Port 0x%02x Result 0x%02x\n", PCX, port, result);
}
return result;
}
@ -1755,14 +1742,14 @@ static int32 cromfdc_timer(const int32 port, const int32 io, const int32 data)
{
static int32 result = 0;
if(io) {
TRACE_PRINT(VERBOSE_MSG,
("CROMFDC: " ADDRESS_FORMAT " TIMER%d OUT, Port 0x%02x Data 0x%02x" NLP, PCX, (port-4), port, data))
sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT
" TIMER%d OUT, Port 0x%02x Data 0x%02x\n", PCX, (port-4), port, data);
result = 0;
sim_activate(cromfdc_unit, (CROMFDC_SIM_64US * data));
} else {
result++;
TRACE_PRINT(VERBOSE_MSG,
("CROMFDC: " ADDRESS_FORMAT " TIMER%d IN, Port 0x%02x Result 0x%02x" NLP, PCX, (port-4), port, result))
sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT
" TIMER%d IN, Port 0x%02x Result 0x%02x\n", PCX, (port-4), port, result);
}
return result;
}
@ -1772,15 +1759,15 @@ static int32 cromfdc_banksel(const int32 port, const int32 io, const int32 data)
{
int32 result;
if(io) {
TRACE_PRINT(VERBOSE_MSG,
("CROMFDC: " ADDRESS_FORMAT " BANKSEL OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data))
sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT
" BANKSEL OUT, Port 0x%02x Data 0x%02x\n", PCX, port, data);
/* Unmap Boot ROM */
cromfdc_info->rom_disabled = TRUE;
result = 0;
} else {
result = 0xFF;
TRACE_PRINT(VERBOSE_MSG,
("CROMFDC: " ADDRESS_FORMAT " BANKSEL IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result))
sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT
" BANKSEL IN, Port 0x%02x Result 0x%02x\n", PCX, port, result);
}
return result;
}

View file

@ -88,7 +88,7 @@ typedef struct {
uint8 s100_addr_u; /* A23:16 of S-100 bus */
} ADCS6_INFO;
extern WD179X_INFO_PUB *wd179x_info;
extern WD179X_INFO_PUB *wd179x_infop;
static ADCS6_INFO adcs6_info_data = { { 0xF000, ADCS6_ROM_SIZE, 0x3, 2 } };
static ADCS6_INFO *adcs6_info = &adcs6_info_data;
@ -207,10 +207,6 @@ static MTAB adcs6_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(adcs6_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB adcs6_dt[] = {
{ "ERROR", ERROR_MSG },
@ -398,7 +394,7 @@ static t_stat adcs6_svc (UNIT *uptr)
motor_timeout ++;
if(motor_timeout == MOTOR_TO_LIMIT) {
adcs6_info->head_sel = 0;
TRACE_PRINT(DRIVE_MSG, ("ADCS6: Motor OFF" NLP))
sim_debug(DRIVE_MSG, &adcs6_dev, "ADCS6: Motor OFF\n");
}
}
@ -430,14 +426,14 @@ static t_stat adcs6_reset(DEVICE *dptr)
} else {
/* Connect ADCS6 ROM at base address */
if (adcs6_hasProperty(UNIT_ADCS6_ROM)) {
TRACE_PRINT(VERBOSE_MSG, ("ADCS6: ROM Enabled." NLP))
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: ROM Enabled.\n");
if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &adcs6rom, FALSE) != 0) {
printf("%s: error mapping MEM resource at 0x%04x\n", __FUNCTION__, pnp->io_base);
return SCPE_ARG;
}
adcs6_info->rom_disabled = FALSE;
} else {
TRACE_PRINT(VERBOSE_MSG, ("ADCS6: ROM Disabled." NLP))
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: ROM Disabled.\n");
adcs6_info->rom_disabled = TRUE;
}
@ -508,8 +504,8 @@ static int32 adcs6rom(const int32 Addr, const int32 write, const int32 data)
/* DBG_PRINT(("ADCS6: ROM %s, Addr %04x" NLP, write ? "WR" : "RD", Addr)); */
if(write) {
if(adcs6_info->rom_disabled == FALSE) {
TRACE_PRINT(ERROR_MSG,
("ADCS6: " ADDRESS_FORMAT " Cannot write to ROM." NLP, PCX));
sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" Cannot write to ROM.\n", PCX);
} else {
adcs6ram[Addr & ADCS6_ADDR_MASK] = data;
}
@ -528,26 +524,26 @@ static int32 adcs6_control(const int32 port, const int32 io, const int32 data)
{
int32 result = 0;
if(io) { /* I/O Write */
wd179x_info->sel_drive = data & 0x03;
wd179x_infop->sel_drive = data & 0x03;
if(data & ADCS6_CTRL_MINI) {
wd179x_info->drivetype = 5;
wd179x_infop->drivetype = 5;
} else {
wd179x_info->drivetype = 8;
wd179x_infop->drivetype = 8;
}
if(data & ADCS6_CTRL_HDS) {
adcs6_info->head_sel = 1;
wd179x_info->fdc_head = 1;
wd179x_infop->fdc_head = 1;
} else {
adcs6_info->head_sel = 0;
wd179x_info->fdc_head = 0;
wd179x_infop->fdc_head = 0;
}
if(data & ADCS6_CTRL_DDENS) {
wd179x_info->ddens = 1;
wd179x_infop->ddens = 1;
} else {
wd179x_info->ddens = 0;
wd179x_infop->ddens = 0;
}
if(data & ADCS6_CTRL_AUTOWAIT) {
adcs6_info->autowait = 1;
@ -555,16 +551,15 @@ static int32 adcs6_control(const int32 port, const int32 io, const int32 data)
adcs6_info->autowait = 0;
}
TRACE_PRINT(DRIVE_MSG,
("ADCS6: " ADDRESS_FORMAT " WR CTRL: sel_drive=%d, drivetype=%d, head_sel=%d, dens=%d, aw=%d" NLP, PCX,
wd179x_info->sel_drive, wd179x_info->drivetype, adcs6_info->head_sel, wd179x_info->ddens, adcs6_info->autowait));
sim_debug(DRIVE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR CTRL: sel_drive=%d, drivetype=%d, head_sel=%d, dens=%d, aw=%d\n",
PCX, wd179x_infop->sel_drive,
wd179x_infop->drivetype, adcs6_info->head_sel,
wd179x_infop->ddens, adcs6_info->autowait);
} else { /* I/O Read */
result = wd179x_info->drq ? 0xFF : 0;
if (wd179x_info->intrq)
result = wd179x_infop->drq ? 0xFF : 0;
if (wd179x_infop->intrq)
result &= 0x7F;
/* TRACE_PRINT(VERBOSE_MSG, */
/* ("ADCS6: " ADDRESS_FORMAT " Read DISK FLAGS, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) */
}
return result;
@ -575,12 +570,12 @@ static int32 adcs6_dma(const int32 port, const int32 io, const int32 data)
{
int32 result = 0xff;
if(io) { /* I/O Write */
TRACE_PRINT(DMA_MSG,
("ADCS6: " ADDRESS_FORMAT " WR DMA: 0x%02x" NLP, PCX, data & 0xFF));
sim_debug(DMA_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR DMA: 0x%02x\n", PCX, data & 0xFF);
} else { /* I/O Read */
result = 0xFF;
TRACE_PRINT(DMA_MSG,
("ADCS6: " ADDRESS_FORMAT " RD DMA: 0x%02x" NLP, PCX, result));
sim_debug(DMA_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" RD DMA: 0x%02x\n", PCX, result);
}
return result;
}
@ -592,62 +587,62 @@ static int32 adcs6_timer(const int32 port, const int32 io, const int32 data)
if(io) { /* Write */
switch(port) {
case 0x04:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " WR PIOA DATA=0x%02x" NLP, PCX, data));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR PIOA DATA=0x%02x\n", PCX, data);
break;
case 0x05:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " WR PIOB DATA=0x%02x" NLP, PCX, data));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR PIOB DATA=0x%02x\n", PCX, data);
break;
case 0x06:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " WR PIOA CTRL=0x%02x" NLP, PCX, data));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR PIOA CTRL=0x%02x\n", PCX, data);
break;
case 0x07:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " WR PIOB CTRL=0x%02x" NLP, PCX, data));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR PIOB CTRL=0x%02x\n", PCX, data);
break;
case 0x08:
case 0x09:
case 0x0A:
case 0x0B:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " WR CTC%d: 0x%02x" NLP, PCX, port - 8, data));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR CTC%d: 0x%02x\n", PCX, port - 8, data);
break;
default:
TRACE_PRINT(ERROR_MSG,
("ADCS6: " ADDRESS_FORMAT " WR Unhandled Port: 0x%02x=0x%02x" NLP, PCX, port, data));
sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR Unhandled Port: 0x%02x=0x%02x\n", PCX, port, data);
break;
}
} else { /* Read */
result = 0xFF;
switch(port) {
case 0x04:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " RD PIOA DATA=0x%02x" NLP, PCX, result));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" RD PIOA DATA=0x%02x\n", PCX, result);
break;
case 0x05:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " RD PIOB DATA=0x%02x" NLP, PCX, result));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" RD PIOB DATA=0x%02x\n", PCX, result);
break;
case 0x06:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " RD PIOA CTRL=0x%02x" NLP, PCX, result));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" RD PIOA CTRL=0x%02x\n", PCX, result);
break;
case 0x07:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " RD PIOB CTRL=0x%02x" NLP, PCX, result));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" RD PIOB CTRL=0x%02x\n", PCX, result);
break;
case 0x08:
case 0x09:
case 0x0A:
case 0x0B:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " RD CTC%d: 0x%02x" NLP, PCX, port - 8, data));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" RD CTC%d: 0x%02x\n", PCX, port - 8, data);
break;
default:
TRACE_PRINT(ERROR_MSG,
("ADCS6: " ADDRESS_FORMAT " RD Unhandled Port: 0x%02x=0x%02x" NLP, PCX, port, data));
sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" RD Unhandled Port: 0x%02x=0x%02x\n", PCX, port, data);
break;
}
}
@ -662,28 +657,28 @@ static int32 adcs6_banksel(const int32 port, const int32 io, const int32 data)
switch(port) {
case 0x15:
adcs6_info->s100_addr_u = data & 0xFF;
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " WR S100 A[23:16]=0x%02x" NLP, PCX, data));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR S100 A[23:16]=0x%02x\n", PCX, data);
break;
case 0x16:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " WR MCTRL0: 0x%02x" NLP, PCX, data));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR MCTRL0: 0x%02x\n", PCX, data);
adcs6_info->rom_disabled = (data & 0x20) ? TRUE : FALSE; /* Unmap Boot ROM */
break;
case 0x17:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " WR MCTRL1: 0x%02x" NLP, PCX, data));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR MCTRL1: 0x%02x\n", PCX, data);
break;
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " WR BAUD RATE=0x%02x" NLP, PCX, data));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR BAUD RATE=0x%02x\n", PCX, data);
break;
default:
TRACE_PRINT(ERROR_MSG,
("ADCS6: " ADDRESS_FORMAT " WR Unhandled Port: 0x%02x=0x%02x" NLP, PCX, port, data));
sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" WR Unhandled Port: 0x%02x=0x%02x\n", PCX, port, data);
break;
}
result = 0;
@ -697,8 +692,8 @@ static int32 adcs6_banksel(const int32 port, const int32 io, const int32 data)
* Bit 5:0 = "Baud Rate"
*/
result = dipswitch;
TRACE_PRINT(VERBOSE_MSG,
("ADCS6: " ADDRESS_FORMAT " RD BAUD RATE=0x%02x" NLP, PCX, result));
sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" RD BAUD RATE=0x%02x\n", PCX, result);
break;
case 0x16:
case 0x17:
@ -707,8 +702,8 @@ static int32 adcs6_banksel(const int32 port, const int32 io, const int32 data)
case 0x1A:
case 0x1B:
default:
TRACE_PRINT(ERROR_MSG,
("ADCS6: " ADDRESS_FORMAT " RD attempt from write-only 0x%02x=0x%02x" NLP, PCX, port, result));
sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT
" RD attempt from write-only 0x%02x=0x%02x\n", PCX, port, result);
break;
}
}

View file

@ -145,10 +145,6 @@ static MTAB disk1a_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(disk1a_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB disk1a_dt[] = {
{ "ERROR", ERROR_MSG },
@ -805,14 +801,13 @@ static int32 disk1adev(const int32 port, const int32 io, const int32 data)
{
int32 result;
if(io) {
TRACE_PRINT(VERBOSE_MSG,
("DISK1A: " ADDRESS_FORMAT " OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data))
sim_debug(VERBOSE_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT
" OUT, Port 0x%02x Data 0x%02x\n", PCX, port, data);
DISK1A_Write(port, data);
result = 0;
} else {
result = DISK1A_Read(port);
TRACE_PRINT(VERBOSE_MSG,
("DISK1A: " ADDRESS_FORMAT " IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result))
sim_debug(VERBOSE_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " IN, Port 0x%02x Result 0x%02x\n", PCX, port, result);
}
return result;
}
@ -835,12 +830,10 @@ static uint8 DISK1A_Read(const uint32 Addr)
break;
case DISK1A_DRIVE_STATUS:
cData = i8272_irq ? 0x81 : 0x01; /* Ready */
TRACE_PRINT(STATUS_MSG,
("DISK1A: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData))
sim_debug(STATUS_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " RD STATUS = 0x%02x\n", PCX, cData);
break;
case DISK1A_MOTOR:
TRACE_PRINT(VERBOSE_MSG,
("DISK1A: " ADDRESS_FORMAT " Error, can't read from MOTOR register." NLP, PCX))
sim_debug(VERBOSE_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " Error, can't read from MOTOR register.\n", PCX);
cData = 0xFF; /* Return High-Z data */
break;
}
@ -862,24 +855,24 @@ static uint8 DISK1A_Write(const uint32 Addr, uint8 cData)
disk1a_info->dma_addr <<= 8;
disk1a_info->dma_addr &= 0x00FFFF00;
disk1a_info->dma_addr |= cData;
TRACE_PRINT(RD_DATA_MSG, ("DISK1A: " ADDRESS_FORMAT " DMA Address=%06x" NLP,
PCX, disk1a_info->dma_addr))
sim_debug(RD_DATA_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT
" DMA Address=%06x\n", PCX, disk1a_info->dma_addr);
I8272_Set_DMA(disk1a_info->dma_addr);
break;
case DISK1A_MOTOR:
TRACE_PRINT(CMD_MSG,
("DISK1A: " ADDRESS_FORMAT " write Motor Reg=0x%02x" NLP, PCX, cData))
sim_debug(CMD_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT
" write Motor Reg=0x%02x\n", PCX, cData);
if((cData & BOOT_PROM_DISABLE) == 0) {
TRACE_PRINT(CMD_MSG,
("DISK1A: " ADDRESS_FORMAT " Boot ROM disabled" NLP, PCX))
sim_debug(CMD_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT
" Boot ROM disabled\n", PCX);
/* Unmap Boot ROM */
disk1a_info->rom_disabled = TRUE;
}
TRACE_PRINT(CMD_MSG, ("DISK1A: " ADDRESS_FORMAT " Motors = %x" NLP,
PCX, (cData & FLOPPY_MOTORS) >> 4))
sim_debug(CMD_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT
" Motors = %x\n", PCX, (cData & FLOPPY_MOTORS) >> 4);
break;
}
@ -890,7 +883,7 @@ static uint8 DISK1A_Write(const uint32 Addr, uint8 cData)
void raise_disk1a_interrupt(void)
{
TRACE_PRINT(IRQ_MSG, ("DISK1A: " ADDRESS_FORMAT " Interrupt" NLP, PCX));
sim_debug(IRQ_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " Interrupt\n", PCX);
raise_ss1_interrupt(SS1_VI4_INT);

View file

@ -174,10 +174,6 @@ static MTAB disk2_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(disk2_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB disk2_dt[] = {
{ "ERROR", ERROR_MSG },
@ -313,7 +309,7 @@ t_stat disk2_detach(UNIT *uptr)
static int32 disk2dev(const int32 port, const int32 io, const int32 data)
{
/* TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); */
/* sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT " IO %s, Port %02x\n", PCX, io ? "WR" : "RD", port); */
if(io) {
DISK2_Write(port, data);
return 0;
@ -343,7 +339,8 @@ static uint8 DISK2_Read(const uint32 Addr)
cData |= (disk2_info->seek_complete == 0) ? 0x04 : 0x00;
cData |= (disk2_info->write_fault) << 1;
cData |= ((pDrive->track != 0) || (disk2_info->seek_complete == 0)) ? 0x01 : 0x00;
TRACE_PRINT(STATUS_MSG, ("DISK2: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData));
sim_debug(STATUS_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" RD STATUS = 0x%02x\n", PCX, cData);
disk2_info->seek_complete = 1;
break;
@ -357,8 +354,9 @@ static uint8 DISK2_Read(const uint32 Addr)
pDrive->track --;
}
}
TRACE_PRINT(SEEK_MSG, ("DISK2: " ADDRESS_FORMAT " Step %s, Track=%d" NLP,
PCX, disk2_info->ctl_op & 0x04 ? "IN" : "OUT", pDrive->track));
sim_debug(SEEK_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" Step %s, Track=%d\n", PCX,
disk2_info->ctl_op & 0x04 ? "IN" : "OUT", pDrive->track);
disk2_info->seek_complete = 0;
cData = 0xFF; /* Return High-Z data */
break;
@ -399,13 +397,11 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
disk2_info->timeout = 0;
}
disk2_info->ctl_us = (cData & 0x03);
TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " ATTN*=%d, RUN=%d, OP=%d, FAULT_CLR=%d, US=%d" NLP,
PCX,
disk2_info->ctl_attn,
disk2_info->ctl_run,
disk2_info->ctl_op,
disk2_info->ctl_fault_clr,
disk2_info->ctl_us));
sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" ATTN*=%d, RUN=%d, OP=%d, FAULT_CLR=%d, US=%d\n",
PCX, disk2_info->ctl_attn, disk2_info->ctl_run,
disk2_info->ctl_op, disk2_info->ctl_fault_clr,
disk2_info->ctl_us);
/* FIXME: seek_complete = 1 is needed by CP/M, but why? Also, maybe related,
* there appears to be a bug in the seeking logic. For some reason, the
@ -428,21 +424,20 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
switch(disk2_info->ctl_op) {
case DISK2_CMD_NULL:
TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " NULL Command" NLP, PCX));
sim_debug(CMD_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" NULL Command\n", PCX);
break;
case DISK2_CMD_READ_DATA:
TRACE_PRINT(RD_DATA_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: (C:%d/H:%d/S:%d)" NLP,
PCX,
disk2_info->cyl,
disk2_info->head,
disk2_info->sector));
sim_debug(RD_DATA_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" READ_DATA: (C:%d/H:%d/S:%d)\n", PCX, disk2_info->cyl, disk2_info->head, disk2_info->sector);
if(disk2_info->head_sel != disk2_info->head) {
printf("DISK2: " ADDRESS_FORMAT " READ_DATA: head_sel != head" NLP, PCX);
printf("DISK2: " ADDRESS_FORMAT
" READ_DATA: head_sel != head" NLP, PCX);
}
/* See FIXME above... that might be why this does not work properly... */
if(disk2_info->cyl != pDrive->track) { /* problem, should not happen, see above */
TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: cyl=%d, track=%d" NLP,
PCX, disk2_info->cyl, pDrive->track));
sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" READ_DATA: cyl=%d, track=%d\n", PCX, disk2_info->cyl, pDrive->track);
pDrive->track = disk2_info->cyl; /* update track */
}
sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET);
@ -450,15 +445,18 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
/* Read sector */
rtn = sim_fread(sdata.raw, 1, (pDrive->sectsize + 3), (pDrive->uptr)->fileref);
if (rtn != (size_t)(pDrive->sectsize + 3)) {
TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: sim_fread error." NLP, PCX));
sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" READ_DATA: sim_fread error.\n", PCX);
}
if(sdata.u.header[2] == disk2_info->sector) {
if(sdata.u.header[0] != disk2_info->cyl) { /*pDrive->track) { */
printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: track" NLP, PCX);
printf("DISK2: " ADDRESS_FORMAT
" READ_DATA Incorrect header: track" NLP, PCX);
disk2_info->timeout = 1;
}
if(sdata.u.header[1] != disk2_info->head) {
printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: head" NLP, PCX);
printf("DISK2: " ADDRESS_FORMAT
" READ_DATA Incorrect header: head" NLP, PCX);
disk2_info->timeout = 1;
}
@ -466,24 +464,22 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
break;
}
if(i == pDrive->nsectors) {
printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX);
printf("DISK2: " ADDRESS_FORMAT
" Sector not found" NLP, PCX);
disk2_info->timeout = 1;
}
}
break;
case DISK2_CMD_WRITE_DATA:
TRACE_PRINT(WR_DATA_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: (C:%d/H:%d/S:%d)" NLP,
PCX,
disk2_info->cyl,
disk2_info->head,
disk2_info->sector));
sim_debug(WR_DATA_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" WRITE_DATA: (C:%d/H:%d/S:%d)\n", PCX, disk2_info->cyl, disk2_info->head, disk2_info->sector);
if(disk2_info->head_sel != disk2_info->head) {
printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA: head_sel != head" NLP, PCX);
}
if(disk2_info->cyl != pDrive->track) { /* problem, should not happen, see above */
TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA = 0x%02x, cyl=%d, track=%d" NLP,
PCX, cData, disk2_info->cyl, pDrive->track));
sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" WRITE_DATA = 0x%02x, cyl=%d, track=%d\n", PCX, cData, disk2_info->cyl, pDrive->track);
pDrive->track = disk2_info->cyl; /* update track */
}
@ -493,15 +489,18 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
file_offset = ftell((pDrive->uptr)->fileref);
rtn = sim_fread(sdata.raw, 1, 3, (pDrive->uptr)->fileref);
if (rtn != 3) {
TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: sim_fread error." NLP, PCX));
sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" WRITE_DATA: sim_fread error.\n", PCX);
}
if(sdata.u.header[2] == disk2_info->sector) {
if(sdata.u.header[0] != disk2_info->cyl) {
printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: track" NLP, PCX);
printf("DISK2: " ADDRESS_FORMAT
" WRITE_DATA Incorrect header: track" NLP, PCX);
disk2_info->timeout = 1;
}
if(sdata.u.header[1] != disk2_info->head) {
printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: head" NLP, PCX);
printf("DISK2: " ADDRESS_FORMAT
" WRITE_DATA Incorrect header: head" NLP, PCX);
disk2_info->timeout = 1;
}
@ -512,7 +511,8 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
}
rtn = sim_fread(sdata.raw, 1, pDrive->sectsize, (pDrive->uptr)->fileref);
if (rtn != (size_t)(pDrive->sectsize)) {
TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: sim_fread error." NLP, PCX));
sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" WRITE_DATA: sim_fread error.\n", PCX);
}
if(i == pDrive->nsectors) {
printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX);
@ -522,12 +522,10 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
break;
case DISK2_CMD_WRITE_HEADER:
track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3);
TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_HEADER Command: track=%d (%d), Head=%d, Sector=%d" NLP,
PCX,
pDrive->track,
disk2_info->cyl,
disk2_info->head_sel,
disk2_info->hdr_sector));
sim_debug(CMD_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" WRITE_HEADER Command: track=%d (%d), Head=%d, Sector=%d\n",
PCX, pDrive->track, disk2_info->cyl,
disk2_info->head_sel, disk2_info->hdr_sector);
i = disk2_info->hdr_sector;
selchan_dma(sdata.raw, 3);
@ -542,11 +540,13 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
break;
case DISK2_CMD_READ_HEADER:
track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3);
TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER Command" NLP, PCX));
sim_debug(CMD_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" READ_HEADER Command\n", PCX);
sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET);
rtn = sim_fread(sdata.raw, 1, 3, (pDrive->uptr)->fileref);
if (rtn != 3) {
TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER: sim_fread error." NLP, PCX));
sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" READ_HEADER: sim_fread error.\n", PCX);
}
selchan_dma(sdata.raw, 3);
@ -578,33 +578,36 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
disk2_info->sel_drive = 3;
break;
default:
printf("DISK2: " ADDRESS_FORMAT " Error, invalid drive select=0x%x" NLP, PCX, cData >> 4);
printf("DISK2: " ADDRESS_FORMAT
" Error, invalid drive select=0x%x" NLP, PCX, cData >> 4);
break;
}
disk2_info->head_sel = cData & 0x0F;
TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [DRIVE]=%d, Head=%d" NLP,
PCX, disk2_info->sel_drive, disk2_info->head));
sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" Write DATA [DRIVE]=%d, Head=%d\n",
PCX, disk2_info->sel_drive, disk2_info->head);
break;
case DISK2_OP_CYL:
disk2_info->cyl = cData;
TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [CYL] = %02x" NLP,
PCX, cData));
sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" Write DATA [CYL] = %02x\n", PCX, cData);
break;
case DISK2_OP_HEAD:
disk2_info->head = cData;
TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [HEAD] = %02x" NLP,
PCX, cData));
sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" Write DATA [HEAD] = %02x\n", PCX, cData);
break;
case DISK2_OP_SECTOR:
disk2_info->sector = cData;
TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write Register [SECTOR] = %02x" NLP,
PCX, cData));
sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" Write Register [SECTOR] = %02x\n", PCX, cData);
break;
default:
TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write Register unknown op [%d] = %02x" NLP,
PCX, disk2_info->ctl_op, cData));
sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" Write Register unknown op [%d] = %02x\n",
PCX, disk2_info->ctl_op, cData);
break;
}
}
@ -616,7 +619,8 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
static void raise_disk2_interrupt(void)
{
TRACE_PRINT(IRQ_MSG, ("DISK2: " ADDRESS_FORMAT " Interrupt" NLP, PCX));
sim_debug(IRQ_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT
" Interrupt\n", PCX);
raise_ss1_interrupt(SS1_VI1_INT);

View file

@ -237,10 +237,6 @@ static MTAB disk3_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(disk3_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB disk3_dt[] = {
{ "ERROR", ERROR_MSG },
@ -384,7 +380,8 @@ t_stat disk3_detach(UNIT *uptr)
static int32 disk3dev(const int32 port, const int32 io, const int32 data)
{
TRACE_PRINT(VERBOSE_MSG, ("DISK3: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port));
sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3: " ADDRESS_FORMAT
" IO %s, Port %02x\n", PCX, io ? "WR" : "RD", port);
if(io) {
DISK3_Write(port, data);
return 0;
@ -417,13 +414,13 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
next_link |= disk3_info->iopb[DISK3_IOPB_LINK+1] << 8;
next_link |= disk3_info->iopb[DISK3_IOPB_LINK+2] << 16;
TRACE_PRINT(VERBOSE_MSG, ("DISK3[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, %s DMA@0x%05x\n",
disk3_info->sel_drive,
disk3_info->link_addr,
next_link,
disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_CMD_MASK,
(disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_REQUEST_IRQ) ? "IRQ" : "POLL",
disk3_info->dma_addr));
sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, %s DMA@0x%05x\n",
disk3_info->sel_drive,
disk3_info->link_addr,
next_link,
disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_CMD_MASK,
(disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_REQUEST_IRQ) ? "IRQ" : "POLL",
disk3_info->dma_addr);
pDrive = &disk3_info->drive[disk3_info->sel_drive];
@ -432,30 +429,33 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
/* Perform command */
switch(cmd & DISK3_CMD_MASK) {
case DISK3_CODE_NOOP:
TRACE_PRINT(VERBOSE_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " NOOP" NLP, disk3_info->sel_drive, PCX));
sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" NOOP\n", disk3_info->sel_drive, PCX);
break;
case DISK3_CODE_VERSION:
break;
case DISK3_CODE_GLOBAL:
TRACE_PRINT(CMD_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " GLOBAL" NLP, disk3_info->sel_drive, PCX));
sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" GLOBAL\n", disk3_info->sel_drive, PCX);
disk3_info->mode = disk3_info->iopb[DISK3_IOPB_ARG1];
disk3_info->retries = disk3_info->iopb[DISK3_IOPB_ARG2];
disk3_info->ndrives = disk3_info->iopb[DISK3_IOPB_ARG3];
TRACE_PRINT(SPECIFY_MSG, (" Mode: 0x%02x" NLP, disk3_info->mode));
TRACE_PRINT(SPECIFY_MSG, (" # Retries: 0x%02x" NLP, disk3_info->retries));
TRACE_PRINT(SPECIFY_MSG, (" # Drives: 0x%02x" NLP, disk3_info->ndrives));
sim_debug(SPECIFY_MSG, &disk3_dev, " Mode: 0x%02x\n", disk3_info->mode);
sim_debug(SPECIFY_MSG, &disk3_dev, " # Retries: 0x%02x\n", disk3_info->retries);
sim_debug(SPECIFY_MSG, &disk3_dev, " # Drives: 0x%02x\n", disk3_info->ndrives);
if(disk3_info->mode == DISK3_MODE_ABS) {
TRACE_PRINT(ERROR_MSG, ("DISK3: Absolute addressing not supported." NLP));
sim_debug(ERROR_MSG, &disk3_dev, "DISK3: Absolute addressing not supported.\n");
}
break;
case DISK3_CODE_SPECIFY:
{
uint8 specify_data[22];
TRACE_PRINT(CMD_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " SPECIFY" NLP, disk3_info->sel_drive, PCX));
sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" SPECIFY\n", disk3_info->sel_drive, PCX);
for(i = 0; i < 22; i++) {
specify_data[i] = GetByteDMA(disk3_info->dma_addr + i);
@ -467,32 +467,36 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
pDrive->ntracks = specify_data[10] | (specify_data[11] << 8);
pDrive->res_tracks = specify_data[18] | (specify_data[19] << 8);
TRACE_PRINT(SPECIFY_MSG, (" Sectsize: %d" NLP, pDrive->sectsize));
TRACE_PRINT(SPECIFY_MSG, (" Sectors: %d" NLP, pDrive->nsectors));
TRACE_PRINT(SPECIFY_MSG, (" Heads: %d" NLP, pDrive->nheads));
TRACE_PRINT(SPECIFY_MSG, (" Tracks: %d" NLP, pDrive->ntracks));
TRACE_PRINT(SPECIFY_MSG, (" Reserved: %d" NLP, pDrive->res_tracks));
sim_debug(SPECIFY_MSG, &disk3_dev, " Sectsize: %d\n", pDrive->sectsize);
sim_debug(SPECIFY_MSG, &disk3_dev, " Sectors: %d\n", pDrive->nsectors);
sim_debug(SPECIFY_MSG, &disk3_dev, " Heads: %d\n", pDrive->nheads);
sim_debug(SPECIFY_MSG, &disk3_dev, " Tracks: %d\n", pDrive->ntracks);
sim_debug(SPECIFY_MSG, &disk3_dev, " Reserved: %d\n", pDrive->res_tracks);
break;
}
case DISK3_CODE_HOME:
pDrive->track = 0;
TRACE_PRINT(SEEK_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " HOME" NLP, disk3_info->sel_drive, PCX));
sim_debug(SEEK_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" HOME\n", disk3_info->sel_drive, PCX);
break;
case DISK3_CODE_SEEK:
pDrive->track = disk3_info->iopb[DISK3_IOPB_ARG1];
pDrive->track |= (disk3_info->iopb[DISK3_IOPB_ARG2] << 8);
if(pDrive->track > pDrive->ntracks) {
TRACE_PRINT(ERROR_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " SEEK ERROR %d not found" NLP, disk3_info->sel_drive, PCX, pDrive->track));
sim_debug(ERROR_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" SEEK ERROR %d not found\n", disk3_info->sel_drive, PCX, pDrive->track);
pDrive->track = pDrive->ntracks - 1;
result = DISK3_STATUS_TIMEOUT;
} else {
TRACE_PRINT(SEEK_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " SEEK %d" NLP, disk3_info->sel_drive, PCX, pDrive->track));
sim_debug(SEEK_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" SEEK %d\n", disk3_info->sel_drive, PCX, pDrive->track);
}
break;
case DISK3_CODE_READ_HDR:
{
TRACE_PRINT(CMD_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " READ HEADER: %d" NLP, pDrive->track, PCX, pDrive->track >> 8));
sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" READ HEADER: %d\n", pDrive->track, PCX, pDrive->track >> 8);
PutByteDMA(disk3_info->dma_addr + 0, pDrive->track & 0xFF);
PutByteDMA(disk3_info->dma_addr + 1, (pDrive->track >> 8) & 0xFF);
PutByteDMA(disk3_info->dma_addr + 2, 0);
@ -510,7 +514,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
size_t rtn;
if(disk3_info->mode == DISK3_MODE_ABS) {
TRACE_PRINT(ERROR_MSG, ("DISK3: Absolute addressing not supported." NLP));
sim_debug(ERROR_MSG, &disk3_dev, "DISK3: Absolute addressing not supported.\n");
break;
}
@ -532,16 +536,15 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
if(disk3_info->iopb[DISK3_IOPB_ARG1] == 1) { /* Read */
rtn = sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref);
TRACE_PRINT(RD_DATA_MSG,
("DISK3[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d %s" NLP,
disk3_info->sel_drive,
PCX,
disk3_info->dma_addr,
pDrive->cur_track,
pDrive->cur_sect,
pDrive->xfr_nsects,
rtn == (size_t)xfr_len ? "OK" : "NOK"
));
sim_debug(RD_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" READ @0x%05x T:%04d/S:%04d/#:%d %s\n",
disk3_info->sel_drive,
PCX,
disk3_info->dma_addr,
pDrive->cur_track,
pDrive->cur_sect,
pDrive->xfr_nsects,
rtn == (size_t)xfr_len ? "OK" : "NOK" );
/* Perform DMA Transfer */
@ -549,14 +552,8 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
PutByteDMA(disk3_info->dma_addr + xfr_count, dataBuffer[xfr_count]);
}
} else { /* Write */
TRACE_PRINT(WR_DATA_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " WRITE @0x%05x T:%04d/S:%04d/#:%d" NLP,
disk3_info->sel_drive,
PCX,
disk3_info->dma_addr,
pDrive->cur_track,
pDrive->cur_sect,
pDrive->xfr_nsects
));
sim_debug(WR_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" WRITE @0x%05x T:%04d/S:%04d/#:%d\n", disk3_info->sel_drive, PCX, disk3_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects );
/* Perform DMA Transfer */
for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) {
@ -596,14 +593,14 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
data_len = pDrive->nsectors * pDrive->sectsize;
TRACE_PRINT(WR_DATA_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d" NLP,
disk3_info->sel_drive,
PCX,
pDrive->track,
disk3_info->iopb[DISK3_IOPB_ARG3],
disk3_info->iopb[DISK3_IOPB_ARG2],
data_len
));
sim_debug(WR_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d\n",
disk3_info->sel_drive,
PCX,
pDrive->track,
disk3_info->iopb[DISK3_IOPB_ARG3],
disk3_info->iopb[DISK3_IOPB_ARG2],
data_len);
file_offset = (pDrive->track * (pDrive->nheads) * data_len); /* Calculate offset based on current track */
file_offset += (disk3_info->iopb[DISK3_IOPB_ARG3] * data_len);
@ -627,7 +624,11 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
case DISK3_CODE_EXAMINE:
case DISK3_CODE_MODIFY:
default:
TRACE_PRINT(ERROR_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " CMD=%x Unsupported" NLP, disk3_info->sel_drive, PCX, cmd & DISK3_CMD_MASK));
sim_debug(ERROR_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT
" CMD=%x Unsupported\n",
disk3_info->sel_drive,
PCX,
cmd & DISK3_CMD_MASK);
break;
}
} else { /* Drive not ready */
@ -654,7 +655,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
static void raise_disk3_interrupt(void)
{
TRACE_PRINT(IRQ_MSG, ("DISK3: " ADDRESS_FORMAT " Interrupt" NLP, PCX));
sim_debug(IRQ_MSG, &disk3_dev, "DISK3: " ADDRESS_FORMAT " Interrupt\n", PCX);
raise_ss1_interrupt(SS1_VI1_INT);

View file

@ -2,7 +2,7 @@
IMSAI FIF Disk Controller by Ernie Price
Based on altairz80_dsk.c, Copyright (c) 2002-2010, Peter Schorn
Based on altairz80_dsk.c, Copyright (c) 2002-2011, Peter Schorn
Plug-n-Play added by Howard M. Harte

View file

@ -144,10 +144,6 @@ static MTAB hdc1001_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(hdc1001_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB hdc1001_dt[] = {
{ "ERROR", ERROR_MSG },
@ -289,7 +285,7 @@ t_stat hdc1001_detach(UNIT *uptr)
static int32 hdc1001dev(const int32 port, const int32 io, const int32 data)
{
/* TRACE_PRINT(VERBOSE_MSG, ("HDC1001: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); */
/* sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001: " ADDRESS_FORMAT " IO %s, Port %02x\n", PCX, io ? "WR" : "RD", port); */
if(io) {
HDC1001_Write(port, data);
return 0;
@ -369,19 +365,18 @@ static uint8 HDC1001_Write(const uint32 Addr, uint8 cData)
case TF_CYLLO:
case TF_CYLHI:
hdc1001_info->taskfile[Addr & 0x07] = cData;
TRACE_PRINT(VERBOSE_MSG, ("HDC1001: " ADDRESS_FORMAT " WR TF[%d]=0x%02x" NLP, PCX, Addr & 7, cData));
sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001: " ADDRESS_FORMAT
" WR TF[%d]=0x%02x\n", PCX, Addr & 7, cData);
break;
case TF_CMD:
pDrive->track = hdc1001_info->taskfile[TF_CYLLO] | (hdc1001_info->taskfile[TF_CYLHI] << 8);
pDrive->xfr_nsects = hdc1001_info->taskfile[TF_SECNT];
TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: Command=%d, T:%d/H:%d/S:%d N=%d" NLP,
hdc1001_info->sel_drive,
hdc1001_info->taskfile[TF_CMD],
pDrive->track,
hdc1001_info->taskfile[TF_SDH] & 0x07,
hdc1001_info->taskfile[TF_SECNO],
pDrive->xfr_nsects));
sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: Command=%d, T:%d/H:%d/S:%d N=%d\n",
hdc1001_info->sel_drive,
hdc1001_info->taskfile[TF_CMD],
pDrive->track, hdc1001_info->taskfile[TF_SDH] & 0x07,
hdc1001_info->taskfile[TF_SECNO], pDrive->xfr_nsects);
break;
default:
break;
@ -394,7 +389,8 @@ static uint8 HDC1001_Read(const uint32 Addr)
uint8 cData;
cData = hdc1001_info->taskfile[Addr & 0x07];
TRACE_PRINT(VERBOSE_MSG, ("HDC1001: " ADDRESS_FORMAT " RD TF[%d]=0x%02x" NLP, PCX, Addr & 7, cData));
sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001: " ADDRESS_FORMAT
" RD TF[%d]=0x%02x\n", PCX, Addr & 7, cData);
return (cData);
}
@ -415,12 +411,7 @@ static uint8 HDC1001_Read(const uint32 Addr)
next_link |= hdc1001_info->iopb[0x0E] << 8;
next_link |= hdc1001_info->iopb[0x0F] << 16;
TRACE_PRINT(VERBOSE_MSG, ("HDC1001[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, DMA@0x%05x\n",
hdc1001_info->sel_drive,
hdc1001_info->link_addr,
next_link,
hdc1001_info->iopb[0],
hdc1001_info->dma_addr));
sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, DMA@0x%05x\n", hdc1001_info->sel_drive, hdc1001_info->link_addr, next_link, hdc1001_info->iopb[0], hdc1001_info->dma_addr);
@ -429,26 +420,26 @@ static uint8 HDC1001_Read(const uint32 Addr)
/* Perform command */
switch(cmd) {
case HDC1001_CODE_NOOP:
TRACE_PRINT(VERBOSE_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " NOOP" NLP, hdc1001_info->sel_drive, PCX));
sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " NOOP\n", hdc1001_info->sel_drive, PCX);
break;
case HDC1001_CODE_VERSION:
break;
case HDC1001_CODE_GLOBAL:
TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " GLOBAL" NLP, hdc1001_info->sel_drive, PCX));
sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " GLOBAL\n", hdc1001_info->sel_drive, PCX);
hdc1001_info->mode = hdc1001_info->iopb[3];
hdc1001_info->retries = hdc1001_info->iopb[4];
hdc1001_info->ndrives = hdc1001_info->iopb[5];
TRACE_PRINT(VERBOSE_MSG, (" Mode: 0x%02x" NLP, hdc1001_info->mode));
TRACE_PRINT(VERBOSE_MSG, (" # Retries: 0x%02x" NLP, hdc1001_info->retries));
TRACE_PRINT(VERBOSE_MSG, (" # Drives: 0x%02x" NLP, hdc1001_info->ndrives));
sim_debug(VERBOSE_MSG, &hdc1001_dev, " Mode: 0x%02x\n", hdc1001_info->mode);
sim_debug(VERBOSE_MSG, &hdc1001_dev, " # Retries: 0x%02x\n", hdc1001_info->retries);
sim_debug(VERBOSE_MSG, &hdc1001_dev, " # Drives: 0x%02x\n", hdc1001_info->ndrives);
break;
case HDC1001_CODE_SPECIFY:
{
uint8 specify_data[22];
TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " SPECIFY" NLP, hdc1001_info->sel_drive, PCX));
sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " SPECIFY\n", hdc1001_info->sel_drive, PCX);
for(i = 0; i < 22; i++) {
specify_data[i] = GetBYTEWrapper(hdc1001_info->dma_addr + i);
@ -460,32 +451,32 @@ static uint8 HDC1001_Read(const uint32 Addr)
pDrive->ntracks = specify_data[10] | (specify_data[11] << 8);
pDrive->res_tracks = specify_data[18] | (specify_data[19] << 8);
TRACE_PRINT(VERBOSE_MSG, (" Sectsize: %d" NLP, pDrive->sectsize));
TRACE_PRINT(VERBOSE_MSG, (" Sectors: %d" NLP, pDrive->nsectors));
TRACE_PRINT(VERBOSE_MSG, (" Heads: %d" NLP, pDrive->nheads));
TRACE_PRINT(VERBOSE_MSG, (" Tracks: %d" NLP, pDrive->ntracks));
TRACE_PRINT(VERBOSE_MSG, (" Reserved: %d" NLP, pDrive->res_tracks));
sim_debug(VERBOSE_MSG, &hdc1001_dev, " Sectsize: %d\n", pDrive->sectsize);
sim_debug(VERBOSE_MSG, &hdc1001_dev, " Sectors: %d\n", pDrive->nsectors);
sim_debug(VERBOSE_MSG, &hdc1001_dev, " Heads: %d\n", pDrive->nheads);
sim_debug(VERBOSE_MSG, &hdc1001_dev, " Tracks: %d\n", pDrive->ntracks);
sim_debug(VERBOSE_MSG, &hdc1001_dev, " Reserved: %d\n", pDrive->res_tracks);
break;
}
case HDC1001_CODE_HOME:
pDrive->track = 0;
TRACE_PRINT(SEEK_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " HOME" NLP, hdc1001_info->sel_drive, PCX));
sim_debug(SEEK_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " HOME\n", hdc1001_info->sel_drive, PCX);
break;
case HDC1001_CODE_SEEK:
pDrive->track = hdc1001_info->iopb[3];
pDrive->track |= (hdc1001_info->iopb[4] << 8);
if(pDrive->track > pDrive->ntracks) {
TRACE_PRINT(ERROR_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " SEEK ERROR %d not found" NLP, hdc1001_info->sel_drive, PCX, pDrive->track));
sim_debug(ERROR_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " SEEK ERROR %d not found\n", hdc1001_info->sel_drive, PCX, pDrive->track);
pDrive->track = pDrive->ntracks - 1;
result = HDC1001_STATUS_TIMEOUT;
} else {
TRACE_PRINT(SEEK_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " SEEK %d" NLP, hdc1001_info->sel_drive, PCX, pDrive->track));
sim_debug(SEEK_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " SEEK %d\n", hdc1001_info->sel_drive, PCX, pDrive->track);
}
break;
case HDC1001_CODE_READ_HDR:
{
TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " READ HEADER: %d" NLP, pDrive->track, PCX));
sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " READ HEADER: %d\n", pDrive->track, PCX);
PutBYTEWrapper(hdc1001_info->dma_addr + 0, pDrive->track & 0xFF);
PutBYTEWrapper(hdc1001_info->dma_addr + 1, (pDrive->track >> 8) & 0xFF);
PutBYTEWrapper(hdc1001_info->dma_addr + 2, 0);
@ -517,14 +508,7 @@ static uint8 HDC1001_Read(const uint32 Addr)
sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET);
if(hdc1001_info->iopb[3] == 1) { /* Read */
TRACE_PRINT(RD_DATA_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d" NLP,
hdc1001_info->sel_drive,
PCX,
hdc1001_info->dma_addr,
pDrive->cur_track,
pDrive->cur_sect,
pDrive->xfr_nsects
));
sim_debug(RD_DATA_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d\n", hdc1001_info->sel_drive, PCX, hdc1001_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects );
sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref);
@ -533,14 +517,7 @@ static uint8 HDC1001_Read(const uint32 Addr)
PutBYTEWrapper(hdc1001_info->dma_addr + xfr_count, dataBuffer[xfr_count]);
}
} else { /* Write */
TRACE_PRINT(WR_DATA_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " WRITE @0x%05x T:%04d/S:%04d/#:%d" NLP,
hdc1001_info->sel_drive,
PCX,
hdc1001_info->dma_addr,
pDrive->cur_track,
pDrive->cur_sect,
pDrive->xfr_nsects
));
sim_debug(WR_DATA_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " WRITE @0x%05x T:%04d/S:%04d/#:%d\n", hdc1001_info->sel_drive, PCX, hdc1001_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects );
/* Perform DMA Transfer */
for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) {
@ -562,14 +539,7 @@ static uint8 HDC1001_Read(const uint32 Addr)
data_len = pDrive->nsectors * pDrive->sectsize;
TRACE_PRINT(WR_DATA_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d" NLP,
hdc1001_info->sel_drive,
PCX,
pDrive->track,
hdc1001_info->iopb[5],
hdc1001_info->iopb[4],
data_len
));
sim_debug(WR_DATA_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d\n", hdc1001_info->sel_drive, PCX, pDrive->track, hdc1001_info->iopb[5], hdc1001_info->iopb[4], data_len );
file_offset = (pDrive->track * (pDrive->nheads) * data_len); /* Calculate offset based on current track */
file_offset += (hdc1001_info->iopb[5] * data_len);
@ -592,7 +562,7 @@ static uint8 HDC1001_Read(const uint32 Addr)
case HDC1001_CODE_EXAMINE:
case HDC1001_CODE_MODIFY:
default:
TRACE_PRINT(ERROR_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " CMD=%x Unsupported" NLP, hdc1001_info->sel_drive, PCX, cmd));
sim_debug(ERROR_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " CMD=%x Unsupported\n", hdc1001_info->sel_drive, PCX, cmd);
break;
}
} else { /* Drive not ready */

View file

@ -126,10 +126,6 @@ static MTAB if3_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(if3_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB if3_dt[] = {
{ "ERROR", ERROR_MSG },
@ -153,15 +149,15 @@ DEVICE if3_dev = {
static t_stat set_if3_connect(UNIT *uptr, int32 val, char *cptr, void *desc)
{
if(uptr->flags & UNIT_DISABLE) {
TRACE_PRINT(ERROR_MSG, ("IF3[%d]: not enabled." NLP, uptr->u3));
sim_debug(ERROR_MSG, &if3_dev, "IF3[%d]: not enabled.\n", uptr->u3);
return SCPE_OK;
}
if(val & UNIT_IF3_CONNECT) {
TRACE_PRINT((RXIRQ_MSG|TXIRQ_MSG), ("IF3[%d]: IRQ polling started..." NLP, uptr->u3));
sim_debug((RXIRQ_MSG|TXIRQ_MSG), &if3_dev, "IF3[%d]: IRQ polling started...\n", uptr->u3);
sim_activate(uptr, 100000);
} else {
TRACE_PRINT((RXIRQ_MSG|TXIRQ_MSG), ("IF3[%d]: IRQ polling stopped." NLP, uptr->u3));
sim_debug((RXIRQ_MSG|TXIRQ_MSG), &if3_dev, "IF3[%d]: IRQ polling stopped.\n", uptr->u3);
sim_cancel(uptr);
}
return (SCPE_OK);
@ -189,7 +185,7 @@ static t_stat if3_reset(DEVICE *dptr)
for(i=0;i<IF3_MAX_BOARDS;i++) {
if3_unit[i].u3 = i; /* Store unit board ID in u3. Also guarantees that u3 < IF3_MAX_BOARDS */
if(if3_unit[i].flags & UNIT_IF3_CONNECT) {
TRACE_PRINT((RXIRQ_MSG|TXIRQ_MSG), ("IF3[%d]: IRQ polling started..." NLP, i));
sim_debug((RXIRQ_MSG|TXIRQ_MSG), &if3_dev, "IF3[%d]: IRQ polling started...\n", i);
sim_activate(&if3_unit[i], 200000); /* start Rx/Tx interrupt polling routine */
}
@ -224,43 +220,40 @@ static uint8 IF3_Read(const uint32 Addr)
/* Check if board is connected */
if(!(if3_unit[if3_board].flags & UNIT_IF3_CONNECT)) {
TRACE_PRINT(ERROR_MSG, ("IF3[%d]: " ADDRESS_FORMAT " RD UART[%d] Board not connected DATA=0x%02x" NLP,
if3_board, PCX, if3_user, cData));
sim_debug(ERROR_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " RD UART[%d] Board not connected DATA=0x%02x\n", if3_board, PCX, if3_user, cData);
return cData;
}
switch(Addr & 0x07) {
case IF3_UART_DATA:
cData = sio0d(IF3_PORT_BASE+(if3_board*0x10)+(if3_user*2), 0, 0);
TRACE_PRINT(UART_MSG, ("IF3[%d]: " ADDRESS_FORMAT " RD UART[%d] DATA=0x%02x Port=0x%03x" NLP,
if3_board, PCX, if3_user, cData, IF3_PORT_BASE+(if3_board*0x10)+(if3_user*2)));
sim_debug(UART_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " RD UART[%d] DATA=0x%02x Port=0x%03x\n", if3_board, PCX, if3_user, cData, IF3_PORT_BASE+(if3_board*0x10)+(if3_user*2));
break;
case IF3_UART_STAT:
cData = sio0s(IF3_PORT_BASE+(if3_board*0x10)+1+(if3_user*2), 0, 0);
TRACE_PRINT(UART_MSG, ("IF3[%d]: " ADDRESS_FORMAT " RD UART[%d] STAT=0x%02x Port=0x%03x" NLP,
if3_board, PCX, if3_user, cData, IF3_PORT_BASE+(if3_board*0x10)+1+(if3_user*2)));
sim_debug(UART_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " RD UART[%d] STAT=0x%02x Port=0x%03x\n", if3_board, PCX, if3_user, cData, IF3_PORT_BASE+(if3_board*0x10)+1+(if3_user*2));
break;
case IF3_UART_MODE:
TRACE_PRINT(ERROR_MSG, ("IF3[%d]: " ADDRESS_FORMAT " RD UART MODE cannot read 0x%02x" NLP, if3_board, PCX, Addr));
sim_debug(ERROR_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " RD UART MODE cannot read 0x%02x\n", if3_board, PCX, Addr);
break;
case IF3_UART_CMD:
TRACE_PRINT(ERROR_MSG, ("IF3[%d]: " ADDRESS_FORMAT " RD UART CMD cannot read 0x%02x" NLP, if3_board, PCX, Addr));
sim_debug(ERROR_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " RD UART CMD cannot read 0x%02x\n", if3_board, PCX, Addr);
break;
case IF3_TISR:
update_rx_tx_isr (&if3_unit[if3_board]);
cData = if3_tisr[if3_board];
TRACE_PRINT(TXIRQ_MSG, ("IF3[%d]: " ADDRESS_FORMAT " RD UART TISR=0x%02x" NLP, if3_board, PCX, cData));
sim_debug(TXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " RD UART TISR=0x%02x\n", if3_board, PCX, cData);
break;
case IF3_RISR:
update_rx_tx_isr (&if3_unit[if3_board]);
cData = if3_risr[if3_board];
TRACE_PRINT(RXIRQ_MSG, ("IF3[%d]: " ADDRESS_FORMAT " RD UART RISR=0x%02x" NLP, if3_board, PCX, cData));
sim_debug(RXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " RD UART RISR=0x%02x\n", if3_board, PCX, cData);
break;
case IF3_RESERVED:
TRACE_PRINT(ERROR_MSG, ("IF3[%d]: " ADDRESS_FORMAT " RD UART RESERVED cannot read 0x%02x" NLP, if3_board, PCX, Addr));
sim_debug(ERROR_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " RD UART RESERVED cannot read 0x%02x\n", if3_board, PCX, Addr);
break;
case IF3_USER_SEL:
TRACE_PRINT(USER_MSG, ("IF3[%d]: " ADDRESS_FORMAT " Cannot read UART_SEL" NLP, if3_board, PCX));
sim_debug(USER_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " Cannot read UART_SEL\n", if3_board, PCX);
break;
}
@ -273,8 +266,7 @@ static uint8 IF3_Write(const uint32 Addr, uint8 cData)
/* Check if board is connected for all ports except "user select" */
if((Addr & 0x7) != IF3_USER_SEL) {
if(!(if3_unit[if3_board].flags & UNIT_IF3_CONNECT)) {
TRACE_PRINT(ERROR_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] Board not connected DATA=0x%02x" NLP,
if3_board, PCX, if3_user, cData));
sim_debug(ERROR_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] Board not connected DATA=0x%02x\n", if3_board, PCX, if3_user, cData);
return cData;
}
}
@ -282,34 +274,32 @@ static uint8 IF3_Write(const uint32 Addr, uint8 cData)
switch(Addr & 0x07) {
case IF3_UART_DATA:
sio0d(IF3_PORT_BASE+(if3_board*0x10)+(if3_user*2), 1, cData);
TRACE_PRINT(UART_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] DATA=0x%02x Port=0x%03x" NLP,
if3_board, PCX, if3_user, cData, IF3_PORT_BASE+(if3_board*0x10)+(if3_user*2)));
sim_debug(UART_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] DATA=0x%02x Port=0x%03x\n", if3_board, PCX, if3_user, cData, IF3_PORT_BASE+(if3_board*0x10)+(if3_user*2));
break;
case IF3_UART_STAT:
TRACE_PRINT(UART_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] STAT=0x%02x" NLP, if3_board, PCX, if3_user, cData));
sim_debug(UART_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] STAT=0x%02x\n", if3_board, PCX, if3_user, cData);
break;
case IF3_UART_MODE:
TRACE_PRINT(UART_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] MODE=0x%02x" NLP, if3_board, PCX, if3_user, cData));
sim_debug(UART_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] MODE=0x%02x\n", if3_board, PCX, if3_user, cData);
break;
case IF3_UART_CMD:
TRACE_PRINT(UART_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] CMD=0x%02x" NLP, if3_board, PCX, if3_user, cData));
sim_debug(UART_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] CMD=0x%02x\n", if3_board, PCX, if3_user, cData);
break;
case IF3_TISR:
TRACE_PRINT(TXIRQ_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART TIMR=0x%02x" NLP, if3_board, PCX, cData));
sim_debug(TXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART TIMR=0x%02x\n", if3_board, PCX, cData);
if3_timr[if3_board] = cData;
break;
case IF3_RISR:
TRACE_PRINT(RXIRQ_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART RIMR=0x%02x" NLP, if3_board, PCX, cData));
sim_debug(RXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART RIMR=0x%02x\n", if3_board, PCX, cData);
if3_rimr[if3_board] = cData;
break;
case IF3_RESERVED:
TRACE_PRINT(UART_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] RESERVED=0x%02x" NLP, if3_board, PCX, if3_user, cData));
sim_debug(UART_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART[%d] RESERVED=0x%02x\n", if3_board, PCX, if3_user, cData);
break;
case IF3_USER_SEL:
if3_board = (cData & 0x18) >> 3; /* guarantees that if3_board < IF3_MAX_BOARDS */
if3_user = cData & 0x7;
TRACE_PRINT(USER_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART_SEL=0x%02x (Board=%d, Rel_User=%d, User=%d)" NLP,
if3_board, PCX, cData, if3_board, if3_user, cData));
sim_debug(USER_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART_SEL=0x%02x (Board=%d, Rel_User=%d, User=%d)\n", if3_board, PCX, cData, if3_board, if3_user, cData);
break;
}
@ -334,13 +324,13 @@ static t_stat if3_svc (UNIT *uptr)
pending_rx_irqs = if3_risr[board] & if3_rimr[board];
if(pending_rx_irqs) {
TRACE_PRINT(RXIRQ_MSG, ("IF3[%d]: " ADDRESS_FORMAT " Rx IRQ Pending: 0x%02x" NLP, board, PCX, pending_rx_irqs));
sim_debug(RXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " Rx IRQ Pending: 0x%02x\n", board, PCX, pending_rx_irqs);
raise_ss1_interrupt(SS1_VI2_INT);
}
pending_tx_irqs = if3_tisr[board] & if3_timr[board];
if(pending_tx_irqs) {
TRACE_PRINT(TXIRQ_MSG, ("IF3[%d]: " ADDRESS_FORMAT " Tx IRQ Pending: 0x%02x" NLP, board, PCX, pending_tx_irqs));
sim_debug(TXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " Tx IRQ Pending: 0x%02x\n", board, PCX, pending_tx_irqs);
raise_ss1_interrupt(SS1_VI3_INT);
}

View file

@ -118,10 +118,6 @@ static MTAB mdriveh_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(mdriveh_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB mdriveh_dt[] = {
{ "ERROR", ERROR_MSG },
@ -207,8 +203,7 @@ static uint8 MDRIVEH_Read(const uint32 Addr)
switch(Addr & 0x1) {
case MDRIVEH_ADDR:
TRACE_PRINT(VERBOSE_MSG, ("MDRIVEH: " ADDRESS_FORMAT " RD Addr = 0x%02x" NLP,
PCX, cData));
sim_debug(VERBOSE_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " RD Addr = 0x%02x\n", PCX, cData);
break;
case MDRIVEH_DATA:
unit = (mdriveh_info->dma_addr & 0x380000) >> 19;
@ -218,8 +213,7 @@ static uint8 MDRIVEH_Read(const uint32 Addr)
cData = mdriveh_info->storage[unit][offset];
}
TRACE_PRINT(RD_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " RD Data [%x:%05x] = 0x%02x" NLP,
PCX, unit, offset, cData));
sim_debug(RD_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " RD Data [%x:%05x] = 0x%02x\n", PCX, unit, offset, cData);
/* Increment M-DRIVE/H Data Address */
mdriveh_info->dma_addr++;
@ -241,8 +235,7 @@ static uint8 MDRIVEH_Write(const uint32 Addr, uint8 cData)
mdriveh_info->dma_addr <<= 8;
mdriveh_info->dma_addr &= 0x003FFF00;
mdriveh_info->dma_addr |= cData;
TRACE_PRINT(SEEK_MSG, ("MDRIVEH: " ADDRESS_FORMAT " DMA Address=%06x" NLP,
PCX, mdriveh_info->dma_addr));
sim_debug(SEEK_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " DMA Address=%06x\n", PCX, mdriveh_info->dma_addr);
break;
case MDRIVEH_DATA:
unit = (mdriveh_info->dma_addr & 0x380000) >> 19;
@ -250,16 +243,13 @@ static uint8 MDRIVEH_Write(const uint32 Addr, uint8 cData)
if(mdriveh_info->storage[unit] != NULL) {
if(mdriveh_info->uptr[unit].flags & UNIT_MDRIVEH_WLK) {
TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit Write Locked" NLP,
PCX, unit, offset));
sim_debug(WR_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit Write Locked\n", PCX, unit, offset);
} else {
TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = 0x%02x" NLP,
PCX, unit, offset, cData));
sim_debug(WR_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = 0x%02x\n", PCX, unit, offset, cData);
mdriveh_info->storage[unit][offset] = cData;
}
} else {
TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit OFFLINE" NLP,
PCX, unit, offset));
sim_debug(WR_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit OFFLINE\n", PCX, unit, offset);
}
/* Increment M-DRIVE/H Data Address */

View file

@ -243,10 +243,6 @@ static MTAB mdsad_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(mdsad_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB mdsad_dt[] = {
{ "ERROR", ERROR_MSG },
@ -462,13 +458,10 @@ static uint8 MDSAD_Read(const uint32 Addr)
case MDSAD_WRITE_DATA:
{
if(mdsad_info->datacount == 0) {
TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT
" WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d" NLP,
PCX,
mdsad_info->orders.ds,
pDrive->track,
mdsad_info->orders.ss,
pDrive->sector));
sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d\n",
PCX, mdsad_info->orders.ds, pDrive->track,
mdsad_info->orders.ss, pDrive->sector);
sec_offset = calculate_mdsad_sec_offset(pDrive->track,
mdsad_info->orders.ss,
@ -484,13 +477,12 @@ static uint8 MDSAD_Read(const uint32 Addr)
sdata.raw[mdsad_info->datacount] = Addr & 0xFF;
if(mdsad_info->datacount == (MDSAD_RAW_LEN - 1)) {
TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT
" Write Complete" NLP, PCX));
sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" Write Complete\n", PCX);
if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) {
TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT
" Drive: %d not attached - write ignored." NLP,
PCX, mdsad_info->orders.ds));
sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" Drive: %d not attached - write ignored.\n", PCX, mdsad_info->orders.ds);
return 0x00;
}
if(mdsad_dev.dctrl & WR_DATA_DETAIL_MSG)
@ -541,34 +533,29 @@ static uint8 MDSAD_Read(const uint32 Addr)
}
if(mdsad_info->orders.ds != (mdsad_info->orders.ds & 0x03)) {
TRACE_PRINT(ERROR_MSG, ("MDSAD: " ADDRESS_FORMAT
" Controller Orders update drive %x" NLP, PCX, mdsad_info->orders.ds));
sim_debug(ERROR_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" Controller Orders update drive %x\n", PCX, mdsad_info->orders.ds);
mdsad_info->orders.ds &= 0x03;
}
TRACE_PRINT(ORDERS_MSG, ("MDSAD: " ADDRESS_FORMAT
" Controller Orders: Drive=%x[%x], DD=%d, SS=%d, DP=%d, ST=%d" NLP,
PCX,
mdsad_info->orders.ds, ds,
mdsad_info->orders.dd,
mdsad_info->orders.ss,
mdsad_info->orders.dp,
mdsad_info->orders.st));
sim_debug(ORDERS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" Controller Orders: Drive=%x[%x], DD=%d, SS=%d, DP=%d, ST=%d\n",
PCX, mdsad_info->orders.ds, ds, mdsad_info->orders.dd,
mdsad_info->orders.ss, mdsad_info->orders.dp, mdsad_info->orders.st);
/* use latest selected drive */
pDrive = &mdsad_info->drive[mdsad_info->orders.ds];
if(mdsad_info->orders.st == 1) {
if(mdsad_info->orders.dp == 0) {
TRACE_PRINT(SEEK_MSG, ("MDSAD: " ADDRESS_FORMAT
" Step out: Track=%d%s" NLP, PCX, pDrive->track,
pDrive->track == 0 ? "[Warn: already at 0]" : ""));
sim_debug(SEEK_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" Step out: Track=%d%s\n", PCX, pDrive->track,
pDrive->track == 0 ? "[Warn: already at 0]" : "");
if(pDrive->track > 0) /* anything to do? */
pDrive->track--;
} else {
TRACE_PRINT(SEEK_MSG, ("MDSAD: " ADDRESS_FORMAT
" Step in: Track=%d%s" NLP, PCX, pDrive->track,
pDrive->track == (MDSAD_TRACKS - 1) ?
"[Warn: already at highest track]" : ""));
sim_debug(SEEK_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" Step in: Track=%d%s\n", PCX, pDrive->track,
pDrive->track == (MDSAD_TRACKS - 1) ? "[Warn: already at highest track]" : "");
if(pDrive->track < (MDSAD_TRACKS - 1)) /* anything to do? */
pDrive->track++;
}
@ -577,11 +564,11 @@ static uint8 MDSAD_Read(const uint32 Addr)
mdsad_info->b_status.t0 = (pDrive->track == 0);
break;
case MDSAD_CTLR_COMMAND:
/* TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT " DM=%x" NLP, PCX, (Addr & 0xF0) >> 4)); */
/* sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " DM=%x\n", PCX, (Addr & 0xF0) >> 4); */
switch(Addr & 0x0F) {
case MDSAD_CMD_MOTORS_ON:
TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT
" CMD=Motors On" NLP, PCX));
sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" CMD=Motors On\n", PCX);
mdsad_info->com_status.mo = 1; /* Turn motors on */
break;
@ -616,37 +603,37 @@ static uint8 MDSAD_Read(const uint32 Addr)
}
break;
case MDSAD_CMD_RESET_SF:
TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT
" CMD=Reset Sector Flag" NLP, PCX));
sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" CMD=Reset Sector Flag\n", PCX);
mdsad_info->com_status.sf = 0;
mdsad_info->datacount = 0;
break;
case MDSAD_CMD_INTR_DIS:
TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT
" CMD=Disarm Interrupt" NLP, PCX));
sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" CMD=Disarm Interrupt\n", PCX);
mdsad_info->int_enable = 0;
break;
case MDSAD_CMD_INTR_ARM:
TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT
" CMD=Arm Interrupt" NLP, PCX));
sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" CMD=Arm Interrupt\n", PCX);
mdsad_info->int_enable = 1;
break;
case MDSAD_CMD_SET_BODY:
TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT
" CMD=Set Body (Diagnostic)" NLP, PCX));
sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" CMD=Set Body (Diagnostic)\n", PCX);
break;
case MDSAD_CMD_BEGIN_WR:
TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT
" CMD=Begin Write" NLP, PCX));
sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" CMD=Begin Write\n", PCX);
break;
case MDSAD_CMD_RESET:
TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT
" CMD=Reset Controller" NLP, PCX));
sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" CMD=Reset Controller\n", PCX);
mdsad_info->com_status.mo = 0; /* Turn motors off */
break;
default:
TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT
" Unsupported CMD=0x%x" NLP, PCX, Addr & 0x0F));
sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" Unsupported CMD=0x%x\n", PCX, Addr & 0x0F);
break;
}
@ -666,52 +653,56 @@ static uint8 MDSAD_Read(const uint32 Addr)
cData |= (mdsad_info->a_status.re & 1) << 2;
cData |= (mdsad_info->a_status.sp & 1) << 1;
cData |= (mdsad_info->a_status.bd & 1);
TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT
" A-Status = <%s %s %s %s %s %s %s %s>" NLP, PCX,
cData & MDSAD_A_SF ? "SF" : " ",
cData & MDSAD_A_IX ? "IX" : " ",
cData & MDSAD_A_DD ? "DD" : " ",
cData & MDSAD_A_MO ? "MO" : " ",
cData & MDSAD_A_WI ? "WI" : " ",
cData & MDSAD_A_RE ? "RE" : " ",
cData & MDSAD_A_SP ? "SP" : " ",
cData & MDSAD_A_BD ? "BD" : " "));
sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" A-Status = <%s %s %s %s %s %s %s %s>\n",
PCX,
cData & MDSAD_A_SF ? "SF" : " ",
cData & MDSAD_A_IX ? "IX" : " ",
cData & MDSAD_A_DD ? "DD" : " ",
cData & MDSAD_A_MO ? "MO" : " ",
cData & MDSAD_A_WI ? "WI" : " ",
cData & MDSAD_A_RE ? "RE" : " ",
cData & MDSAD_A_SP ? "SP" : " ",
cData & MDSAD_A_BD ? "BD" : " ");
break;
case MDSAD_B_STATUS: /* B-STATUS */
cData |= (mdsad_info->b_status.wr & 1) << 3;
cData |= (mdsad_info->b_status.sp & 1) << 2;
cData |= (mdsad_info->b_status.wp & 1) << 1;
cData |= (mdsad_info->b_status.t0 & 1);
TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT
" B-Status = <%s %s %s %s %s %s %s %s>" NLP, PCX,
cData & MDSAD_B_SF ? "SF" : " ",
cData & MDSAD_B_IX ? "IX" : " ",
cData & MDSAD_B_DD ? "DD" : " ",
cData & MDSAD_B_MO ? "MO" : " ",
cData & MDSAD_B_WR ? "WR" : " ",
cData & MDSAD_B_SP ? "SP" : " ",
cData & MDSAD_B_WP ? "WP" : " ",
cData & MDSAD_B_T0 ? "T0" : " "));
sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" B-Status = <%s %s %s %s %s %s %s %s>\n",
PCX,
cData & MDSAD_B_SF ? "SF" : " ",
cData & MDSAD_B_IX ? "IX" : " ",
cData & MDSAD_B_DD ? "DD" : " ",
cData & MDSAD_B_MO ? "MO" : " ",
cData & MDSAD_B_WR ? "WR" : " ",
cData & MDSAD_B_SP ? "SP" : " ",
cData & MDSAD_B_WP ? "WP" : " ",
cData & MDSAD_B_T0 ? "T0" : " ");
break;
case MDSAD_C_STATUS: /* C-STATUS */
cData |= (mdsad_info->c_status.sc & 0xF);
TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT
" C-Status = <%s %s %s %s %i>" NLP, PCX,
cData & MDSAD_C_SF ? "SF" : " ",
cData & MDSAD_C_IX ? "IX" : " ",
cData & MDSAD_C_DD ? "DD" : " ",
cData & MDSAD_C_MO ? "MO" : " ", cData & MDSAD_C_SC));
sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" C-Status = <%s %s %s %s %i>\n",
PCX,
cData & MDSAD_C_SF ? "SF" : " ",
cData & MDSAD_C_IX ? "IX" : " ",
cData & MDSAD_C_DD ? "DD" : " ",
cData & MDSAD_C_MO ? "MO" : " ",
cData & MDSAD_C_SC);
break;
case MDSAD_READ_DATA: /* READ DATA */
{
if(mdsad_info->datacount == 0) {
TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT
" READ Start: Drive: %d, Track=%d, Head=%d, Sector=%d" NLP,
PCX,
mdsad_info->orders.ds,
pDrive->track,
mdsad_info->orders.ss,
pDrive->sector));
sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" READ Start: Drive: %d, Track=%d, Head=%d, Sector=%d\n",
PCX,
mdsad_info->orders.ds,
pDrive->track,
mdsad_info->orders.ss,
pDrive->sector);
checksum = 0;
@ -721,9 +712,9 @@ static uint8 MDSAD_Read(const uint32 Addr)
if ((pDrive->uptr == NULL) ||
(pDrive->uptr->fileref == NULL)) {
TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT
" Drive: %d not attached - read ignored." NLP,
PCX, mdsad_info->orders.ds));
sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" Drive: %d not attached - read ignored.\n",
PCX, mdsad_info->orders.ds);
return 0xe5;
}
@ -738,7 +729,8 @@ static uint8 MDSAD_Read(const uint32 Addr)
rtn = sim_fread(&sdata.u.data[0], 1, MDSAD_SECTOR_LEN,
(pDrive->uptr)->fileref);
if (rtn != MDSAD_SECTOR_LEN) {
TRACE_PRINT(ERROR_MSG, ("MDSAD: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX));
sim_debug(ERROR_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" READ: sim_fread error.\n", PCX);
}
}
break;
@ -768,9 +760,9 @@ static uint8 MDSAD_Read(const uint32 Addr)
PCX, sec_offset, mdsad_info->datacount, cData));
} else { /* checksum */
cData = checksum;
TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT
" READ-DATA: Checksum is: 0x%02x" NLP,
PCX, cData));
sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" READ-DATA: Checksum is: 0x%02x\n",
PCX, cData);
}
mdsad_info->datacount++;

View file

@ -120,10 +120,6 @@ static MTAB scp300f_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(scp300f_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB scp300f_dt[] = {
{ "ERROR", ERROR_MSG },
@ -151,7 +147,7 @@ static t_stat scp300f_reset(DEVICE *dptr)
{
PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
TRACE_PRINT(VERBOSE_MSG, ("SCP300F: Reset." NLP));
sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: Reset.\n");
if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */
sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &scp300fdev, TRUE);
@ -321,7 +317,7 @@ static uint8 scp300f_rom[SCP300F_ROM_SIZE] = {
if(write) {
if(scp300f_info->rom_enabled)
{
TRACE_PRINT(ROM_MSG, ("SCP300F: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM." NLP, PCX, Addr));
sim_debug(ROM_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM.\n", PCX, Addr);
} else {
}
return 0;
@ -370,38 +366,38 @@ static uint8 SCP300F_Read(const uint32 Addr)
switch(Addr & SCP300F_IO_MASK) {
case SCP300F_MPIC_0:
case SCP300F_MPIC_1:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Master 8259 DATA RD[%02x]: not implemented." NLP, PCX, Addr));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Master 8259 DATA RD[%02x]: not implemented.\n", PCX, Addr);
break;
case SCP300F_SPIC_0:
case SCP300F_SPIC_1:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA RD[%02x]: not implemented." NLP, PCX, Addr));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA RD[%02x]: not implemented.\n", PCX, Addr);
break;
case SCP300F_9513_DATA:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 DATA RD[%02x]: not implemented." NLP, PCX, Addr));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 DATA RD[%02x]: not implemented.\n", PCX, Addr);
break;
case SCP300F_9513_STATUS:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 STAT RD[%02x]: not implemented." NLP, PCX, Addr));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 STAT RD[%02x]: not implemented.\n", PCX, Addr);
break;
case SCP300F_UART_DATA: /* UART is handled by the 2SIO, if this gets called, then the 2SIO was not */
case SCP300F_UART_STATUS: /* configured properly. */
TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD[%02x]: UART not configured properly." NLP, PCX, Addr));
sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " RD[%02x]: UART not configured properly.\n", PCX, Addr);
break;
case SCP300F_PIO_DATA:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO DATA RD[%02x]: not implemented." NLP, PCX, Addr));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " PIO DATA RD[%02x]: not implemented.\n", PCX, Addr);
break;
case SCP300F_PIO_STATUS:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO STATUS RD[%02x]: not implemented." NLP, PCX, Addr));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " PIO STATUS RD[%02x]: not implemented.\n", PCX, Addr);
break;
case SCP300F_EPROM_DIS:
TRACE_PRINT(ROM_MSG, ("SCP300F: " ADDRESS_FORMAT " EPROM DIS RD: EPROM Disabled." NLP, PCX));
sim_debug(ROM_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " EPROM DIS RD: EPROM Disabled.\n", PCX);
scp300f_info->rom_enabled = 0;
break;
case SCP300F_SENSE_SW: /* Sense Switch */
cData = scp300f_sr;
TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD: Sense Switch=0x%02x" NLP, PCX, cData));
sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " RD: Sense Switch=0x%02x\n", PCX, cData);
break;
default:
TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD[%02x]: not Implemented." NLP, PCX, Addr));
sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " RD[%02x]: not Implemented.\n", PCX, Addr);
break;
}
@ -415,37 +411,37 @@ static uint8 SCP300F_Write(const uint32 Addr, uint8 cData)
switch(Addr & SCP300F_IO_MASK) {
case SCP300F_MPIC_0:
case SCP300F_MPIC_1:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Master 8259 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Master 8259 DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData);
break;
case SCP300F_SPIC_0:
case SCP300F_SPIC_1:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData);
break;
case SCP300F_9513_DATA:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData);
break;
case SCP300F_9513_STATUS:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 STAT WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 STAT WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData);
break;
case SCP300F_UART_DATA: /* UART is handled by the 2SIO, if this gets called, then the 2SIO was not */
case SCP300F_UART_STATUS: /* configured properly. */
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: UART not configured properly." NLP, PCX, Addr));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[%02x]: UART not configured properly.\n", PCX, Addr);
break;
case SCP300F_PIO_DATA:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " PIO DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData);
break;
case SCP300F_PIO_STATUS:
TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to PIO STATUS." NLP, PCX, Addr));
sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to PIO STATUS.\n", PCX, Addr);
break;
case SCP300F_EPROM_DIS:
TRACE_PRINT(ROM_MSG, ("SCP300F: " ADDRESS_FORMAT " EPROM DIS WR: EPROM Disabled." NLP, PCX));
sim_debug(ROM_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " EPROM DIS WR: EPROM Disabled.\n", PCX);
scp300f_info->rom_enabled = 0;
break;
case SCP300F_SENSE_SW:
TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to SR." NLP, PCX, Addr));
sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to SR.\n", PCX, Addr);
break;
default:
TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented." NLP, PCX, Addr, cData));
sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented.\n", PCX, Addr, cData);
break;
}

View file

@ -109,10 +109,6 @@ static MTAB selchan_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(selchan_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB selchan_dt[] = {
{ "ERROR", ERROR_MSG },
@ -167,18 +163,12 @@ static int32 selchandev(const int32 port, const int32 io, const int32 data)
selchan_info->reg_cnt ++;
if(selchan_info->reg_cnt == 4) {
TRACE_PRINT(VERBOSE_MSG, ("SELCHAN: " ADDRESS_FORMAT " DMA=0x%06x, Mode=0x%02x (%s, %s, %s)" NLP,
PCX,
selchan_info->dma_addr,
selchan_info->dma_mode,
selchan_info->dma_mode & SELCHAN_MODE_WRITE ? "WR" : "RD",
selchan_info->dma_mode & SELCHAN_MODE_IO ? "I/O" : "MEM",
selchan_info->dma_mode & SELCHAN_MODE_IO ? "FIX" : selchan_info->dma_mode & SELCHAN_MODE_CNT_UP ? "INC" : "DEC"));
sim_debug(VERBOSE_MSG, &selchan_dev, "SELCHAN: " ADDRESS_FORMAT " DMA=0x%06x, Mode=0x%02x (%s, %s, %s)\n", PCX, selchan_info->dma_addr, selchan_info->dma_mode, selchan_info->dma_mode & SELCHAN_MODE_WRITE ? "WR" : "RD", selchan_info->dma_mode & SELCHAN_MODE_IO ? "I/O" : "MEM", selchan_info->dma_mode & SELCHAN_MODE_IO ? "FIX" : selchan_info->dma_mode & SELCHAN_MODE_CNT_UP ? "INC" : "DEC");
}
return 0;
} else {
TRACE_PRINT(VERBOSE_MSG, ("SELCHAN: " ADDRESS_FORMAT " Reset" NLP, PCX));
sim_debug(VERBOSE_MSG, &selchan_dev, "SELCHAN: " ADDRESS_FORMAT " Reset\n", PCX);
selchan_info->reg_cnt = 0;
return(0xFF);
}
@ -199,9 +189,7 @@ int32 selchan_dma(uint8 *buf, uint32 len)
printf("SELCHAN: " ADDRESS_FORMAT " I/O Not supported" NLP, PCX);
return (-1);
} else {
TRACE_PRINT(DMA_MSG, ("SELCHAN: " ADDRESS_FORMAT " DMA %s Transfer, len=%d" NLP,
PCX,
(selchan_info->dma_mode & SELCHAN_MODE_WRITE) ? "WR" : "RD", len));
sim_debug(DMA_MSG, &selchan_dev, "SELCHAN: " ADDRESS_FORMAT " DMA %s Transfer, len=%d\n", PCX, (selchan_info->dma_mode & SELCHAN_MODE_WRITE) ? "WR" : "RD", len);
for(i=0;i<len;i++) {
if(selchan_info->dma_mode & SELCHAN_MODE_WRITE) {
PutByteDMA(selchan_info->dma_addr + i, buf[i]);

View file

@ -207,10 +207,6 @@ static MTAB ss1_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(ss1_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB ss1_dt[] = {
{ "ERROR", ERROR_MSG },
@ -306,10 +302,12 @@ static uint8 SS1_Read(const uint32 Addr)
case SS1_M8259_L:
if((ss1_pic[sel_pic].OCW3 & 0x03) == 0x03) {
cData = ss1_pic[sel_pic].ISR;
TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " RD: %s PIC ISR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData));
sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: %s PIC ISR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
} else if((ss1_pic[sel_pic].OCW3 & 0x03) == 0x02) {
cData = ss1_pic[sel_pic].IRR;
TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " RD: %s PIC IRR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData));
sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: %s PIC IRR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
} else {
cData = 0xFF;
}
@ -318,27 +316,32 @@ static uint8 SS1_Read(const uint32 Addr)
sel_pic = SLAVE_PIC;
case SS1_M8259_H:
cData = ss1_pic[sel_pic].IMR;
TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " RD: %s PIC IMR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData));
sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: %s PIC IMR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
ss1_pic[sel_pic].IMR = cData;
break;
case SS1_8253_CTL:
cData = ss1_tc[0].CTL;
TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " RD: TC CTL=0x%02x." NLP, PCX, cData));
sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: TC CTL=0x%02x.\n", PCX, cData);
break;
case SS1_8253_TC2:
sel_tc++;
case SS1_8253_TC1:
sel_tc++;
case SS1_8253_TC0:
TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " RD: TC [%d]=0x%02x." NLP, PCX, sel_tc, cData));
sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: TC [%d]=0x%02x.\n", PCX, sel_tc, cData);
break;
case SS1_9511A_DATA:
case SS1_9511A_CMD:
TRACE_PRINT(MATH_MSG, ("SS1: " ADDRESS_FORMAT " RD: Math Coprocessor not Implemented." NLP, PCX));
sim_debug(MATH_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: Math Coprocessor not Implemented.\n", PCX);
break;
case SS1_RTC_CMD:
cData = 0xFF;
TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " RD: RTC Cmd=0x%02x." NLP, PCX, cData));
sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: RTC Cmd=0x%02x.\n", PCX, cData);
break;
case SS1_RTC_DATA:
time(&now);
@ -389,20 +392,24 @@ static uint8 SS1_Read(const uint32 Addr)
cData = 0;
break;
}
TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " RD: RTC Data[%x]=0x%02x." NLP, PCX, ss1_rtc[0].digit_sel, cData));
sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: RTC Data[%x]=0x%02x.\n", PCX, ss1_rtc[0].digit_sel, cData);
break;
case SS1_UART_DATA:
cData = sio0d(Addr, 0, 0);
TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " RD: UART Data=0x%02x." NLP, PCX, cData));
sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: UART Data=0x%02x.\n", PCX, cData);
break;
case SS1_UART_STAT:
cData = sio0s(Addr, 0, 0);
TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " RD: UART Stat=0x%02x." NLP, PCX, cData));
sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: UART Stat=0x%02x.\n", PCX, cData);
break;
case SS1_UART_MODE:
case SS1_UART_CMD:
TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " RD: UART not Implemented." NLP, PCX));
sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" RD: UART not Implemented.\n", PCX);
break;
}
@ -427,15 +434,18 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData)
sel_pic = SLAVE_PIC;
case SS1_M8259_L:
if(cData & 0x10) {
TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC ICW1=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData));
sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: %s PIC ICW1=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
ss1_pic[sel_pic].ICW[1] = cData;
ss1_pic[sel_pic].config_cnt=1;
} else {
if(cData & 0x08) { /* OCW3 */
TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC OCW3=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData));
sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: %s PIC OCW3=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
ss1_pic[sel_pic].OCW3 = cData;
} else { /* OCW2 */
TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC OCW2=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData));
sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: %s PIC OCW2=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
ss1_pic[sel_pic].OCW2 = cData;
}
}
@ -444,12 +454,12 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData)
sel_pic = SLAVE_PIC;
case SS1_M8259_H:
if(ss1_pic[sel_pic].config_cnt == 0) {
TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC IMR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData));
sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC IMR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
ss1_pic[sel_pic].IMR = cData;
generate_ss1_interrupt();
} else {
ss1_pic[sel_pic].config_cnt++;
TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC ICW%d=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), ss1_pic[sel_pic].config_cnt, cData));
sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC ICW%d=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), ss1_pic[sel_pic].config_cnt, cData);
ss1_pic[sel_pic].ICW[ss1_pic[sel_pic].config_cnt] = cData;
ss1_unit[0].u3 = ss1_pic[SLAVE_PIC].ICW[2]+TC0_IRQ_OFFSET;
@ -464,15 +474,22 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData)
case SS1_8253_CTL:
ss1_tc[0].CTL = cData;
sel_timer = (ss1_tc[0].CTL & I8253_CTL_SC_MASK) >> 6;
TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " WR: TC CTL=0x%02x." NLP, PCX, ss1_tc[0].CTL));
sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: TC CTL=0x%02x.\n",
PCX, ss1_tc[0].CTL);
if(ss1_tc[0].CTL & I8253_CTL_BCD) {
TRACE_PRINT(ERROR_MSG, ("SS1: " ADDRESS_FORMAT " Timer %d: BCD Mode not supported: TC CTL=0x%02x." NLP, PCX, sel_timer, ss1_tc[0].CTL));
sim_debug(ERROR_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" Timer %d: BCD Mode not supported: TC CTL=0x%02x.\n",
PCX, sel_timer, ss1_tc[0].CTL);
}
ss1_tc[0].bcd[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_BCD);
ss1_tc[0].mode[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_MODE_MASK) >> 1;
ss1_tc[0].rl[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_RL_MASK) >> 4;
TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " Timer %d: Mode: %d, RL=%d, %s." NLP, PCX,
sel_timer, ss1_tc[0].mode[sel_timer], ss1_tc[0].rl[sel_timer], ss1_tc[0].bcd[sel_timer] ? "BCD" : "Binary"));
sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" Timer %d: Mode: %d, RL=%d, %s.\n",
PCX, sel_timer, ss1_tc[0].mode[sel_timer],
ss1_tc[0].rl[sel_timer],
ss1_tc[0].bcd[sel_timer] ? "BCD" : "Binary");
newcount = 0;
bc=0;
break;
@ -497,38 +514,45 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData)
sim_activate(&ss1_unit[sel_tc], newcount);
}
TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " WR: TC [%d]=0x%02x." NLP, PCX, sel_tc, cData));
sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: TC [%d]=0x%02x.\n", PCX, sel_tc, cData);
if(sel_tc == 0) {
}
break;
case SS1_9511A_DATA:
case SS1_9511A_CMD:
TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: Math Coprocessor not Implemented." NLP, PCX));
sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: Math Coprocessor not Implemented.\n", PCX);
break;
case SS1_RTC_CMD:
ss1_rtc[0].digit_sel = cData & 0x0F;
ss1_rtc[0].flags = (cData >> 4) & 0x0F;
TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " WR: RTC Cmd=0x%02x (%s%s%s SEL=%x)" NLP,
PCX, cData,
ss1_rtc[0].flags & 0x4 ? "HOLD " :"",
ss1_rtc[0].flags & 0x2 ? "WR" :"",
ss1_rtc[0].flags & 0x1 ? "RD" :"",
ss1_rtc[0].digit_sel))
sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: RTC Cmd=0x%02x (%s%s%s SEL=%x)\n",
PCX, cData,
ss1_rtc[0].flags & 0x4 ? "HOLD " :"",
ss1_rtc[0].flags & 0x2 ? "WR" :"",
ss1_rtc[0].flags & 0x1 ? "RD" :"",
ss1_rtc[0].digit_sel);
break;
case SS1_RTC_DATA:
TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " WR: RTC Data=0x%02x" NLP, PCX, cData));
sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: RTC Data=0x%02x\n", PCX, cData);
break;
case SS1_UART_DATA:
TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " WR: UART Data=0x%02x." NLP, PCX, cData));
sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: UART Data=0x%02x.\n", PCX, cData);
sio0d(Addr, 1, cData);
break;
case SS1_UART_STAT:
TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " WR: UART Stat=0x%02x." NLP, PCX, cData));
sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: UART Stat=0x%02x.\n", PCX, cData);
sio0s(Addr, 1, cData);
break;
case SS1_UART_MODE:
case SS1_UART_CMD:
TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: UART not Implemented." NLP, PCX));
sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
" WR: UART not Implemented.\n", PCX);
break;
}
@ -564,22 +588,12 @@ static void generate_ss1_interrupt(void)
if(irq_bit) {
ss1_pic[pic].IRR |= (irq_bit << irq_index);
irq = ss1_pic[pic].ICW[2]+irq_index;
TRACE_PRINT(IRQ_MSG, ("Handling interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d" NLP,
pic ? "SLAVE" : "MASTER",
ss1_pic[pic].IMR,
ss1_pic[pic].ISR,
ss1_pic[pic].IRR,
irq_index));
sim_debug(IRQ_MSG, &ss1_dev, "Handling interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d\n", pic ? "SLAVE" : "MASTER", ss1_pic[pic].IMR, ss1_pic[pic].ISR, ss1_pic[pic].IRR, irq_index);
cpu_raise_interrupt(irq);
ss1_pic[pic].IRR &= ~(irq_bit << irq_index);
ss1_pic[pic].ISR &= ~(irq_bit << irq_index);
if(irq_pend & 0x7E) {
/* TRACE_PRINT(IRQ_MSG, ("Requeue interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d" NLP,
pic ? "SLAVE" : "MASTER",
ss1_pic[pic].IMR,
ss1_pic[pic].ISR,
ss1_pic[pic].IRR,
irq_index));
/* sim_debug(IRQ_MSG, &ss1_dev, "Requeue interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d\n", pic ? "SLAVE" : "MASTER", ss1_pic[pic].IMR, ss1_pic[pic].ISR, ss1_pic[pic].IRR, irq_index);
*/
sim_activate(&ss1_unit[3], 1000); /* requeue, because more interrupts are pending. */
}
@ -607,7 +621,7 @@ static t_stat ss1_svc (UNIT *uptr)
generate_ss1_interrupt();
sim_activate(uptr, 1000); /* requeue, because we still need to handle the timer interrupt. */
} else if((cData & 1) && ((ss1_pic[SLAVE_PIC].IMR & 0x40) == 0)) {
TRACE_PRINT(IRQ_MSG, ("SS1: " ADDRESS_FORMAT " Calling UART Tx ISR." NLP, PCX));
sim_debug(IRQ_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling UART Tx ISR.\n", PCX);
ss1_pic[SLAVE_PIC].ISR |= 0x40;
generate_ss1_interrupt();
sim_activate(uptr, 1000); /* requeue, because we still need to handle the timer interrupt. */
@ -626,15 +640,15 @@ static t_stat ss1_svc (UNIT *uptr)
break;
}
if(ss1_tc[0].mode[uptr->u4] == 0x0) {
TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " Calling Timer%d ISR." NLP, PCX, uptr->u4));
sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling Timer%d ISR.\n", PCX, uptr->u4);
ss1_pic[SLAVE_PIC].ISR |= irq_bit;
generate_ss1_interrupt();
}
if(ss1_tc[0].mode[uptr->u4] == 0x3) {
TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " Calling Timer%d ISR." NLP, PCX, uptr->u4));
sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling Timer%d ISR.\n", PCX, uptr->u4);
ss1_pic[SLAVE_PIC].ISR |= irq_bit;
generate_ss1_interrupt();
TRACE_PRINT(TC_MSG, ("Timer %d, mode %d, reloading\n", uptr->u4, ss1_tc[0].mode[uptr->u4]));
sim_debug(TC_MSG, &ss1_dev, "Timer %d, mode %d, reloading\n", uptr->u4, ss1_tc[0].mode[uptr->u4]);
sim_activate(uptr, 33280);
}
}

View file

@ -361,6 +361,7 @@ t_stat diskCreate(FILE *fileref, char *ctlr_comment)
DISK_INFO *myDisk = NULL;
char *comment;
char *curptr;
char *result;
uint8 answer;
int32 len, remaining;
@ -387,8 +388,8 @@ t_stat diskCreate(FILE *fileref, char *ctlr_comment)
remaining = MAX_COMMENT_LEN;
do {
printf("IMD> ");
fgets(curptr, remaining - 3, stdin);
if (strcmp(curptr, ".\n") == 0) {
result = fgets(curptr, remaining - 3, stdin);
if ((result == NULL) || (strcmp(curptr, ".\n") == 0)) {
remaining = 0;
} else {
len = strlen(curptr) - 1;
@ -409,7 +410,10 @@ t_stat diskCreate(FILE *fileref, char *ctlr_comment)
#ifdef _WIN32 /* This might work under UNIX and/or VMS since this POSIX, but I haven't tried it. */
_chsize(_fileno(fileref), ftell (fileref));
#else
ftruncate(fileno(fileref), ftell (fileref));
if (ftruncate(fileno(fileref), ftell (fileref)) == -1) {
printf("SIM_IMD: Error overwriting disk image.\n");
return(SCPE_OPENERR);
}
#endif
fprintf(fileref, "IMD SIMH %s %s\n", __DATE__, __TIME__);
@ -722,7 +726,11 @@ t_stat trackWrite(DISK_INFO *myDisk,
#ifdef _WIN32 /* This might work under UNIX and/or VMS since this POSIX, but I haven't tried it. */
_chsize(_fileno(fileref), ftell (fileref));
#else
ftruncate(fileno(fileref), ftell (fileref));
if (ftruncate(fileno(fileref), ftell (fileref)) == -1) {
printf("Disk truncation failed." NLP);
*flags |= IMD_DISK_IO_ERROR_GENERAL;
return(SCPE_IOERR);
}
#endif
/* Flush and re-parse the IMD file. */
fflush(fileref);

View file

@ -181,10 +181,6 @@ static MTAB vfdhd_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(vfdhd_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB vfdhd_dt[] = {
{ "ERROR", ERROR_MSG },
@ -392,7 +388,7 @@ static uint8 VFDHD_Read(const uint32 Addr)
cData |= (pDrive->seek_complete & 1) << 4; /* [4] Seek Complete (HD) */
cData |= (pDrive->sync_lost & 1) << 5; /* [5] Loss of Sync (HD) */
cData |= 0xC0; /* [7:6] Reserved (pulled up) */
TRACE_PRINT(STATUS_MSG, ("VFDHD: " ADDRESS_FORMAT " RD S0 = 0x%02x" NLP, PCX, cData));
sim_debug(STATUS_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD S0 = 0x%02x\n", PCX, cData);
break;
case FDHD_CTRL_STATUS1:
vfdhd_info->floppy_sel = (vfdhd_info->sel_drive == 0) ? 0 : 1;
@ -407,12 +403,12 @@ static uint8 VFDHD_Read(const uint32 Addr)
vfdhd_info->controller_busy = 0;
TRACE_PRINT(STATUS_MSG, ("VFDHD: " ADDRESS_FORMAT " RD S1 = 0x%02x" NLP, PCX, cData));
sim_debug(STATUS_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD S1 = 0x%02x\n", PCX, cData);
break;
case FDHD_DATA:
/* DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " RD Data" NLP, PCX)); */
if(vfdhd_info->datacount+40 >= VFDHD_RAW_LEN) {
TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount));
sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount);
vfdhd_info->datacount = 0;
}
cData = sdata.raw[vfdhd_info->datacount+40];
@ -422,7 +418,7 @@ static uint8 VFDHD_Read(const uint32 Addr)
/* DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " RD Data Sector %d[%03d]: 0x%02x" NLP, PCX, pDrive->sector, vfdhd_info->datacount, cData)); */
break;
case FDHD_RESET_START: /* Reset */
TRACE_PRINT(CMD_MSG, ("VFDHD: " ADDRESS_FORMAT " Reset" NLP, PCX));
sim_debug(CMD_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Reset\n", PCX);
vfdhd_info->datacount = 0;
cData = 0xFF; /* Return High-Z data */
break;
@ -445,14 +441,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData)
vfdhd_info->direction = (cData >> 6) & 1;
vfdhd_info->rwc = (cData >> 7) & 1;
TRACE_PRINT(WR_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " WR C0=%02x: sel_drive=%d, head=%d, step=%d, dir=%d, rwc=%d" NLP,
PCX,
cData,
vfdhd_info->sel_drive,
vfdhd_info->head,
vfdhd_info->step,
vfdhd_info->direction,
vfdhd_info->rwc));
sim_debug(WR_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " WR C0=%02x: sel_drive=%d, head=%d, step=%d, dir=%d, rwc=%d\n", PCX, cData, vfdhd_info->sel_drive, vfdhd_info->head, vfdhd_info->step, vfdhd_info->direction, vfdhd_info->rwc);
if(vfdhd_info->step == 1) {
if(vfdhd_info->direction == 1) { /* Step IN */
@ -462,8 +451,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData)
pDrive->track--;
}
}
TRACE_PRINT(SEEK_MSG, ("VFDHD: " ADDRESS_FORMAT " Drive %d on track %d" NLP,
PCX, vfdhd_info->sel_drive, pDrive->track));
sim_debug(SEEK_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Drive %d on track %d\n", PCX, vfdhd_info->sel_drive, pDrive->track);
}
break;
@ -473,8 +461,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData)
vfdhd_info->ecc_enable = (cData >> 6) & 1;
vfdhd_info->precomp = (cData >> 7) & 1;
if(cData == 0xFF) {
TRACE_PRINT(SEEK_MSG, ("VFDHD: " ADDRESS_FORMAT " Home Disk %d" NLP,
PCX, vfdhd_info->sel_drive));
sim_debug(SEEK_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Home Disk %d\n", PCX, vfdhd_info->sel_drive);
pDrive->track = 0;
}
DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " WR C1=%02x: sector=%d, read=%d, ecc_en=%d, precomp=%d" NLP,
@ -490,20 +477,20 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData)
#ifdef USE_VGI
if(vfdhd_info->sel_drive > 0) { /* Floppy */
if(vfdhd_info->datacount >= VFDHD_RAW_LEN) {
TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount));
sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount);
vfdhd_info->datacount = 0;
}
sdata.raw[vfdhd_info->datacount] = cData;
} else { /* Hard */
if(vfdhd_info->datacount+10 >= VFDHD_RAW_LEN) {
TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount));
sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount);
vfdhd_info->datacount = 0;
}
sdata.raw[vfdhd_info->datacount+10] = cData;
}
#else
if((vfdhd_info->datacount-13 >= VFDHD_RAW_LEN) || (vfdhd_info->datacount < 13)) {
TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount));
sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount);
vfdhd_info->datacount = 13;
}
sdata.u.data[vfdhd_info->datacount-13] = cData;
@ -513,7 +500,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData)
break;
case FDHD_RESET_START:
TRACE_PRINT(CMD_MSG, ("VFDHD: " ADDRESS_FORMAT " Start Command" NLP, PCX));
sim_debug(CMD_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Start Command\n", PCX);
VFDHD_Command();
break;
}
@ -547,14 +534,9 @@ static void VFDHD_Command(void)
if(vfdhd_info->read == 1) { /* Perform a Read operation */
unsigned int i, checksum;
uint32 readlen;
unsigned int readlen;
TRACE_PRINT(RD_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " RD: Drive=%d, Track=%d, Head=%d, Sector=%d" NLP,
PCX,
vfdhd_info->sel_drive,
pDrive->track,
vfdhd_info->head,
vfdhd_info->sector));
sim_debug(RD_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD: Drive=%d, Track=%d, Head=%d, Sector=%d\n", PCX, vfdhd_info->sel_drive, pDrive->track, vfdhd_info->head, vfdhd_info->sector);
/* Clear out unused portion of sector. */
memset(&sdata.u.unused[0], 0x00, 10);
@ -597,7 +579,7 @@ static void VFDHD_Command(void)
sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);
rtn = sim_fread(&sdata.u.sync, 1, 274, /*VFDHD_SECTOR_LEN,*/ (pDrive->uptr)->fileref);
if (rtn != 274) {
TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX));
sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " READ: sim_fread error.\n", PCX);
}
memset(&sdata.u.preamble, 0, 40);
@ -619,14 +601,9 @@ static void VFDHD_Command(void)
}
} else { /* Perform a Write operation */
uint32 writelen;
unsigned int writelen;
TRACE_PRINT(WR_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " WR: Drive=%d, Track=%d, Head=%d, Sector=%d" NLP,
PCX,
vfdhd_info->sel_drive,
pDrive->track,
vfdhd_info->head,
vfdhd_info->sector));
sim_debug(WR_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " WR: Drive=%d, Track=%d, Head=%d, Sector=%d\n", PCX, vfdhd_info->sel_drive, pDrive->track, vfdhd_info->head, vfdhd_info->sector);
#ifdef USE_VGI
#else

View file

@ -199,6 +199,7 @@ uint8 floorlog2(unsigned int n);
WD179X_INFO wd179x_info_data = { { 0x0, 0, 0x30, 4 } };
WD179X_INFO *wd179x_info = &wd179x_info_data;
WD179X_INFO_PUB *wd179x_infop = (WD179X_INFO_PUB *)&wd179x_info_data;
static UNIT wd179x_unit[] = {
{ UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 },
@ -218,10 +219,6 @@ static MTAB wd179x_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if(wd179x_dev.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB wd179x_dt[] = {
{ "ERROR", ERROR_MSG },
@ -280,19 +277,21 @@ void wd179x_external_restore(void)
WD179X_DRIVE_INFO *pDrive;
if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
TRACE_PRINT(ERROR_MSG, ("WD179X: " ADDRESS_FORMAT " Illegal drive selected, cannot restore." NLP, PCX))
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" Illegal drive selected, cannot restore.\n", PCX);
return;
}
pDrive = &wd179x_info->drive[wd179x_info->sel_drive];
if(pDrive->uptr == NULL) {
TRACE_PRINT(ERROR_MSG, ("WD179X: " ADDRESS_FORMAT " No drive selected, cannot restore." NLP, PCX))
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" No drive selected, cannot restore.\n", PCX);
return;
}
TRACE_PRINT(SEEK_MSG,
("WD179X[%d]: " ADDRESS_FORMAT " External Restore drive to track 0" NLP, wd179x_info->sel_drive, PCX))
sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" External Restore drive to track 0\n", wd179x_info->sel_drive, PCX);
pDrive->track = 0;
@ -445,8 +444,8 @@ uint8 WD179X_Read(const uint32 Addr)
{
uint8 cData;
WD179X_DRIVE_INFO *pDrive;
uint32 flags = 0;
uint32 readlen;
unsigned int flags = 0;
unsigned int readlen;
int status;
if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
@ -476,19 +475,19 @@ uint8 WD179X_Read(const uint32 Addr)
}
cData = (pDrive->ready == 0) ? WD179X_STAT_NOT_READY : 0;
cData |= wd179x_info->fdc_status; /* Status Register */
TRACE_PRINT(STATUS_MSG,
("WD179X: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData))
sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" RD STATUS = 0x%02x\n", PCX, cData);
wd179x_info->intrq = 0;
break;
case WD179X_TRACK:
cData = pDrive->track;
TRACE_PRINT(STATUS_MSG,
("WD179X: " ADDRESS_FORMAT " RD TRACK = 0x%02x" NLP, PCX, cData))
sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" RD TRACK = 0x%02x\n", PCX, cData);
break;
case WD179X_SECTOR:
cData = wd179x_info->fdc_sector;
TRACE_PRINT(STATUS_MSG,
("WD179X: " ADDRESS_FORMAT " RD SECT = 0x%02x" NLP, PCX, cData))
sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" RD SECT = 0x%02x\n", PCX, cData);
break;
case WD179X_DATA:
cData = 0xFF; /* Return High-Z data */
@ -496,8 +495,10 @@ uint8 WD179X_Read(const uint32 Addr)
if(wd179x_info->fdc_dataindex < wd179x_info->fdc_datacount) {
cData = sdata.raw[wd179x_info->fdc_dataindex];
if(wd179x_info->fdc_read_addr == TRUE) {
TRACE_PRINT(STATUS_MSG,
("WD179X[%d]: " ADDRESS_FORMAT " READ_ADDR[%d] = 0x%02x" NLP, wd179x_info->sel_drive, PCX, wd179x_info->fdc_dataindex, cData))
sim_debug(STATUS_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" READ_ADDR[%d] = 0x%02x\n",
wd179x_info->sel_drive, PCX,
wd179x_info->fdc_dataindex, cData);
}
wd179x_info->fdc_dataindex++;
@ -514,21 +515,13 @@ uint8 WD179X_Read(const uint32 Addr)
wd179x_info->fdc_sec_len = floorlog2(
pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7;
if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP,
wd179x_info->sel_drive, PCX));
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
wd179x_info->fdc_sec_len = 0;
return cData;
}
wd179x_info->fdc_sector ++;
TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " MULTI_READ_REC, T:%d/S:%d/N:%d, %s, len=%d" NLP,
wd179x_info->sel_drive,
PCX,
pDrive->track,
wd179x_info->fdc_head,
wd179x_info->fdc_sector,
wd179x_info->ddens ? "DD" : "SD",
128 << wd179x_info->fdc_sec_len));
sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " MULTI_READ_REC, T:%d/S:%d/N:%d, %s, len=%d\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, wd179x_info->ddens ? "DD" : "SD", 128 << wd179x_info->fdc_sec_len);
status = sectRead(pDrive->imd,
pDrive->track,
@ -578,8 +571,8 @@ static uint8 Do1793Command(uint8 cCommand)
{
uint8 result = 0;
WD179X_DRIVE_INFO *pDrive;
uint32 flags = 0;
uint32 readlen;
unsigned int flags = 0;
unsigned int readlen;
int status;
if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
@ -594,8 +587,9 @@ static uint8 Do1793Command(uint8 cCommand)
if(wd179x_info->fdc_status & WD179X_STAT_BUSY) {
if(((cCommand & 0xF0) != WD179X_FORCE_INTR)) { /* && ((cCommand & 0xF0) != WD179X_RESTORE)) { */
TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " ERROR: Command 0x%02x ignored because controller is BUSY\n" NLP,
wd179x_info->sel_drive, PCX, cCommand));
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" ERROR: Command 0x%02x ignored because controller is BUSY\n\n",
wd179x_info->sel_drive, PCX, cCommand);
}
return 0xFF;
}
@ -617,7 +611,7 @@ static uint8 Do1793Command(uint8 cCommand)
wd179x_info->fdc_status |= WD179X_STAT_BUSY; /* Set BUSY */
wd179x_info->fdc_status &= ~(WD179X_STAT_CRC_ERROR | WD179X_STAT_SEEK_ERROR | WD179X_STAT_DRQ);
wd179x_info->intrq = 0;
wd179x_info->hld = cCommand && 0x08;
wd179x_info->hld = cCommand & 0x08;
wd179x_info->verify = cCommand & 0x04;
break;
/* Type II Commands */
@ -648,19 +642,26 @@ static uint8 Do1793Command(uint8 cCommand)
switch(cCommand & 0xF0) {
/* Type I Commands */
case WD179X_RESTORE:
TRACE_PRINT(CMD_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=RESTORE %s" NLP, wd179x_info->sel_drive, PCX, wd179x_info->verify ? "[VERIFY]" : ""));
sim_debug(CMD_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=RESTORE %s\n", wd179x_info->sel_drive, PCX,
wd179x_info->verify ? "[VERIFY]" : "");
pDrive->track = 0;
wd179x_info->intrq = 1;
break;
case WD179X_SEEK:
TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=SEEK, track=%d, new=%d" NLP, wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_data));
sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=SEEK, track=%d, new=%d\n", wd179x_info->sel_drive,
PCX, pDrive->track, wd179x_info->fdc_data);
pDrive->track = wd179x_info->fdc_data;
break;
case WD179X_STEP:
TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP" NLP, wd179x_info->sel_drive, PCX));
sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP\n", wd179x_info->sel_drive, PCX);
break;
case WD179X_STEP_U:
TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_U dir=%d" NLP, wd179x_info->sel_drive, PCX, wd179x_info->step_dir));
sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP_U dir=%d\n", wd179x_info->sel_drive,
PCX, wd179x_info->step_dir);
if(wd179x_info->step_dir == 1) {
if (pDrive->track < 255)
pDrive->track++;
@ -668,26 +669,30 @@ static uint8 Do1793Command(uint8 cCommand)
if (pDrive->track > 0)
pDrive->track--;
} else {
TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " ERROR: undefined direction for STEP" NLP, wd179x_info->sel_drive, PCX));
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" ERROR: undefined direction for STEP\n",
wd179x_info->sel_drive, PCX);
}
break;
case WD179X_STEP_IN:
TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_IN" NLP, wd179x_info->sel_drive, PCX));
sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP_IN\n", wd179x_info->sel_drive, PCX);
break;
case WD179X_STEP_IN_U:
if (pDrive->track < 255)
pDrive->track++;
wd179x_info->step_dir = 1;
TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_IN_U, Track=%d" NLP,
wd179x_info->sel_drive, PCX, pDrive->track));
sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP_IN_U, Track=%d\n", wd179x_info->sel_drive,
PCX, pDrive->track);
break;
case WD179X_STEP_OUT:
TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_OUT" NLP,
wd179x_info->sel_drive, PCX));
sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP_OUT\n", wd179x_info->sel_drive, PCX);
break;
case WD179X_STEP_OUT_U:
TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_OUT_U" NLP,
wd179x_info->sel_drive, PCX));
sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP_OUT_U\n", wd179x_info->sel_drive, PCX);
if (pDrive->track > 0)
pDrive->track--;
wd179x_info->step_dir = -1;
@ -699,8 +704,8 @@ static uint8 Do1793Command(uint8 cCommand)
wd179x_info->fdc_sec_len = floorlog2(
pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7;
if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP,
wd179x_info->sel_drive, PCX));
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" Invalid sector size!\n", wd179x_info->sel_drive, PCX);
wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */
wd179x_info->fdc_status &= ~WD179X_STAT_BUSY;
wd179x_info->intrq = 1;
@ -710,14 +715,12 @@ static uint8 Do1793Command(uint8 cCommand)
}
wd179x_info->fdc_multiple = (cCommand & 0x10) ? TRUE : FALSE;
TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_REC, T:%d/S:%d/N:%d, %s, %s len=%d" NLP,
wd179x_info->sel_drive,
PCX, pDrive->track,
wd179x_info->fdc_head,
wd179x_info->fdc_sector,
wd179x_info->fdc_multiple ? "Multiple" : "Single",
wd179x_info->ddens ? "DD" : "SD",
128 << wd179x_info->fdc_sec_len));
sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=READ_REC, T:%d/S:%d/N:%d, %s, %s len=%d\n",
wd179x_info->sel_drive, PCX, pDrive->track,
wd179x_info->fdc_head, wd179x_info->fdc_sector,
wd179x_info->fdc_multiple ? "Multiple" : "Single",
wd179x_info->ddens ? "DD" : "SD", 128 << wd179x_info->fdc_sec_len);
if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) {
wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */
@ -756,26 +759,21 @@ static uint8 Do1793Command(uint8 cCommand)
}
break;
case WD179X_WRITE_RECS:
TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Error: WRITE_RECS not implemented." NLP,
wd179x_info->sel_drive, PCX));
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" Error: WRITE_RECS not implemented.\n", wd179x_info->sel_drive, PCX);
break;
case WD179X_WRITE_REC:
/* Compute Sector Size */
wd179x_info->fdc_sec_len = floorlog2(
pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7;
if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP,
wd179x_info->sel_drive, PCX));
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" Invalid sector size!\n", wd179x_info->sel_drive, PCX);
wd179x_info->fdc_sec_len = 0;
}
TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_REC, T:%d/S:%d/N:%d, %s." NLP,
wd179x_info->sel_drive,
PCX,
pDrive->track,
wd179x_info->fdc_head,
wd179x_info->fdc_sector,
(cCommand & 0x10) ? "Multiple" : "Single"));
sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=WRITE_REC, T:%d/S:%d/N:%d, %s.\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, (cCommand & 0x10) ? "Multiple" : "Single");
wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */
wd179x_info->drq = 1;
wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len;
@ -789,12 +787,9 @@ static uint8 Do1793Command(uint8 cCommand)
break;
/* Type III Commands */
case WD179X_READ_ADDR:
TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_ADDR, T:%d/S:%d, %s" NLP,
wd179x_info->sel_drive,
PCX,
pDrive->track,
wd179x_info->fdc_head,
wd179x_info->ddens ? "DD" : "SD"));
sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=READ_ADDR, T:%d/S:%d, %s\n", wd179x_info->sel_drive,
PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->ddens ? "DD" : "SD");
/* For some reason 86-DOS tries to use this track, force it to 0. Need to investigate this more. */
if (pDrive->track == 0xFF)
@ -804,8 +799,8 @@ static uint8 Do1793Command(uint8 cCommand)
wd179x_info->fdc_sec_len = floorlog2(
pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7;
if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP,
wd179x_info->sel_drive, PCX));
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" Invalid sector size!\n", wd179x_info->sel_drive, PCX);
wd179x_info->fdc_sec_len = 0;
}
@ -833,17 +828,17 @@ static uint8 Do1793Command(uint8 cCommand)
}
break;
case WD179X_READ_TRACK:
TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_TRACK" NLP, wd179x_info->sel_drive, PCX));
TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Error: READ_TRACK not implemented." NLP,
wd179x_info->sel_drive, PCX));
sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=READ_TRACK\n", wd179x_info->sel_drive, PCX);
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" Error: READ_TRACK not implemented.\n", wd179x_info->sel_drive, PCX);
break;
case WD179X_WRITE_TRACK:
TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_TRACK" NLP, wd179x_info->sel_drive, PCX));
TRACE_PRINT(FMT_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_TRACK, T:%d/S:%d." NLP,
wd179x_info->sel_drive,
PCX,
pDrive->track,
wd179x_info->fdc_head));
sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=WRITE_TRACK\n", wd179x_info->sel_drive, PCX);
sim_debug(FMT_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=WRITE_TRACK, T:%d/S:%d.\n", wd179x_info->sel_drive,
PCX, pDrive->track, wd179x_info->fdc_head);
wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */
wd179x_info->drq = 1;
wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len;
@ -858,7 +853,8 @@ static uint8 Do1793Command(uint8 cCommand)
break;
/* Type IV Commands */
case WD179X_FORCE_INTR:
TRACE_PRINT(CMD_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=FORCE_INTR" NLP, wd179x_info->sel_drive, PCX));
sim_debug(CMD_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" CMD=FORCE_INTR\n", wd179x_info->sel_drive, PCX);
if((cCommand & 0x0F) == 0) { /* I0-I3 == 0, no intr, but clear BUSY and terminate command */
wd179x_info->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */
wd179x_info->drq = 0;
@ -887,8 +883,8 @@ static uint8 Do1793Command(uint8 cCommand)
}
break;
default:
TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " ERROR: Unknown command 0x%02x.\n" NLP,
wd179x_info->sel_drive, PCX, cCommand));
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" ERROR: Unknown command 0x%02x.\n\n", wd179x_info->sel_drive, PCX, cCommand);
break;
}
@ -904,15 +900,16 @@ static uint8 Do1793Command(uint8 cCommand)
case WD179X_STEP_OUT:
case WD179X_STEP_OUT_U:
if(wd179x_info->verify) { /* Verify the selected track/head is ok. */
TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Verify ", wd179x_info->sel_drive, PCX));
sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" Verify ", wd179x_info->sel_drive, PCX);
if(sectSeek(pDrive->imd, pDrive->track, wd179x_info->fdc_head) != SCPE_OK) {
TRACE_PRINT(SEEK_MSG, ("FAILED" NLP));
sim_debug(SEEK_MSG, &wd179x_dev, "FAILED\n");
wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND;
} else if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) {
wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */
TRACE_PRINT(SEEK_MSG, ("NOT FOUND" NLP));
sim_debug(SEEK_MSG, &wd179x_dev, "NOT FOUND\n");
} else {
TRACE_PRINT(SEEK_MSG, ("Ok" NLP));
sim_debug(SEEK_MSG, &wd179x_dev, "Ok\n");
}
}
@ -955,8 +952,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData)
{
WD179X_DRIVE_INFO *pDrive;
/* uint8 disk_read = 0; */
uint32 flags = 0;
uint32 writelen;
unsigned int flags = 0;
unsigned int writelen;
if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
return 0xFF;
@ -970,8 +967,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData)
switch(Addr & 0x3) {
case WD179X_STATUS:
TRACE_PRINT(STATUS_MSG,
("WD179X: " ADDRESS_FORMAT " WR CMD = 0x%02x" NLP, PCX, cData))
sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" WR CMD = 0x%02x\n", PCX, cData);
wd179x_info->fdc_read = FALSE;
wd179x_info->fdc_write = FALSE;
wd179x_info->fdc_write_track = FALSE;
@ -981,18 +978,18 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData)
Do1793Command(cData);
break;
case WD179X_TRACK:
TRACE_PRINT(STATUS_MSG,
("WD179X: " ADDRESS_FORMAT " WR TRACK = 0x%02x" NLP, PCX, cData))
sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" WR TRACK = 0x%02x\n", PCX, cData);
pDrive->track = cData;
break;
case WD179X_SECTOR: /* Sector Register */
TRACE_PRINT(STATUS_MSG,
("WD179X: " ADDRESS_FORMAT " WR SECT = 0x%02x" NLP, PCX, cData))
sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" WR SECT = 0x%02x\n", PCX, cData);
wd179x_info->fdc_sector = cData;
break;
case WD179X_DATA:
TRACE_PRINT(STATUS_MSG,
("WD179X: " ADDRESS_FORMAT " WR DATA = 0x%02x" NLP, PCX, cData))
sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" WR DATA = 0x%02x\n", PCX, cData);
if(wd179x_info->fdc_write == TRUE) {
if(wd179x_info->fdc_dataindex < wd179x_info->fdc_datacount) {
sdata.raw[wd179x_info->fdc_dataindex] = cData;
@ -1003,13 +1000,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData)
wd179x_info->drq = 0;
wd179x_info->intrq = 1;
TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Writing sector, T:%d/S:%d/N:%d, Len=%d" NLP,
wd179x_info->sel_drive,
PCX,
pDrive->track,
wd179x_info->fdc_head,
wd179x_info->fdc_sector,
128 << wd179x_info->fdc_sec_len));
sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" Writing sector, T:%d/S:%d/N:%d, Len=%d\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, 128 << wd179x_info->fdc_sec_len);
sectWrite(pDrive->imd,
pDrive->track,
@ -1026,15 +1018,12 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData)
}
if(wd179x_info->fdc_write_track == TRUE) {
/* TRACE_PRINT(FMT_MSG, */
/* ("WD179X: " ADDRESS_FORMAT " FMT DATA[%d] = 0x%02x" NLP, PCX, wd179x_info->fdc_fmt_state, cData)); */
if(wd179x_info->fdc_fmt_state == FMT_GAP1) {
if(cData != 0xFC) {
wd179x_info->fdc_gap[0]++;
} else {
TRACE_PRINT(VERBOSE_MSG,
("WD179X: " ADDRESS_FORMAT " FMT GAP1 Length = %d" NLP, PCX, wd179x_info->fdc_gap[0]));
sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" FMT GAP1 Length = %d\n", PCX, wd179x_info->fdc_gap[0]);
wd179x_info->fdc_gap[1] = 0;
wd179x_info->fdc_fmt_state = FMT_GAP2;
}
@ -1042,8 +1031,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData)
if(cData != 0xFE) {
wd179x_info->fdc_gap[1]++;
} else {
TRACE_PRINT(VERBOSE_MSG,
("WD179X: " ADDRESS_FORMAT " FMT GAP2 Length = %d" NLP, PCX, wd179x_info->fdc_gap[1]));
sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" FMT GAP2 Length = %d\n", PCX, wd179x_info->fdc_gap[1]);
wd179x_info->fdc_gap[2] = 0;
wd179x_info->fdc_fmt_state = FMT_HEADER;
wd179x_info->fdc_header_index = 0;
@ -1053,8 +1042,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData)
wd179x_info->fdc_gap[2] = 0;
wd179x_info->fdc_fmt_state = FMT_GAP3;
} else {
TRACE_PRINT(VERBOSE_MSG,
("WD179X: " ADDRESS_FORMAT " HEADER[%d]=%02x" NLP, PCX, wd179x_info->fdc_header_index, cData));
sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" HEADER[%d]=%02x\n", PCX, wd179x_info->fdc_header_index, cData);
switch(wd179x_info->fdc_header_index) {
case 0:
pDrive->track = cData;
@ -1080,8 +1069,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData)
if(cData != 0xFB) {
wd179x_info->fdc_gap[2]++;
} else {
TRACE_PRINT(VERBOSE_MSG,
("WD179X: " ADDRESS_FORMAT " FMT GAP3 Length = %d" NLP, PCX, wd179x_info->fdc_gap[2]));
sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" FMT GAP3 Length = %d\n", PCX, wd179x_info->fdc_gap[2]);
wd179x_info->fdc_fmt_state = FMT_DATA;
wd179x_info->fdc_dataindex = 0;
}
@ -1092,28 +1081,26 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData)
} else {
wd179x_info->fdc_sec_len = floorlog2(wd179x_info->fdc_dataindex) - 7;
if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP,
wd179x_info->sel_drive, PCX));
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
" Invalid sector size!\n", wd179x_info->sel_drive, PCX);
wd179x_info->fdc_sec_len = 0;
}
if(wd179x_info->fdc_fmt_sector_count >= WD179X_MAX_SECTOR) {
TRACE_PRINT(ERROR_MSG, ("WD179X: " ADDRESS_FORMAT " Illegal sector count" NLP, PCX));
sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" Illegal sector count\n", PCX);
wd179x_info->fdc_fmt_sector_count = 0;
}
wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count] = wd179x_info->fdc_sector;
wd179x_info->fdc_fmt_sector_count++;
TRACE_PRINT(VERBOSE_MSG,
("WD179X: " ADDRESS_FORMAT " FMT Data Length = %d" NLP, PCX, wd179x_info->fdc_dataindex));
sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" FMT Data Length = %d\n", PCX, wd179x_info->fdc_dataindex);
TRACE_PRINT(FMT_MSG,
("WD179X: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/N:%d=%d/L=%d[%d] Fill=0x%02x" NLP, PCX,
pDrive->track,
wd179x_info->fdc_head,
wd179x_info->fdc_fmt_sector_count,
wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count],
wd179x_info->fdc_dataindex,
wd179x_info->fdc_sec_len,
sdata.raw[0]));
sim_debug(FMT_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
" FORMAT T:%d/H:%d/N:%d=%d/L=%d[%d] Fill=0x%02x\n", PCX,
pDrive->track, wd179x_info->fdc_head,
wd179x_info->fdc_fmt_sector_count,
wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count],
wd179x_info->fdc_dataindex, wd179x_info->fdc_sec_len, sdata.raw[0]);
wd179x_info->fdc_gap[1] = 0;
wd179x_info->fdc_fmt_state = FMT_GAP2;

View file

@ -1,6 +1,6 @@
/* hp2100_baci.c: HP 12966A buffered asynchronous communications interface simulator
Copyright (c) 2007-2008, J. David Bryan
Copyright (c) 2007-2011, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
BACI 12966A BACI card
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
25-Nov-08 JDB Revised for new multiplexer library SHOW routines
11-Sep-08 JDB Fixed STC,C losing interrupt request on BREAK
07-Sep-08 JDB Fixed IN_LOOPBACK conflict with netinet/in.h
@ -320,11 +322,13 @@
/* BACI state variables */
FLIP_FLOP baci_control = CLEAR; /* control flip-flop */
FLIP_FLOP baci_flag = CLEAR; /* flag flip-flop */
FLIP_FLOP baci_flagbuf = CLEAR; /* flag buffer flip-flop */
FLIP_FLOP baci_srq = CLEAR; /* SRQ flip-flop */
FLIP_FLOP baci_lockout = CLEAR; /* interrupt lockout flip-flop */
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
FLIP_FLOP srq; /* SRQ flip-flop */
FLIP_FLOP lockout; /* interrupt lockout flip-flop */
} baci = { CLEAR, CLEAR, CLEAR, CLEAR, CLEAR };
uint16 baci_ibuf = 0; /* status/data in */
uint16 baci_obuf = 0; /* command/data out */
@ -372,7 +376,8 @@ static void clock_uart (void);
/* BACI global routines */
uint32 baci_io (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER baci_io;
t_stat baci_term_svc (UNIT *uptr);
t_stat baci_poll_svc (UNIT *uptr);
t_stat baci_reset (DEVICE *dptr);
@ -400,13 +405,14 @@ t_stat baci_detach (UNIT *uptr);
ten millisecond period.
*/
DIB baci_dib = { BACI, &baci_io };
DIB baci_dib = { &baci_io, BACI, 0 };
DEVICE baci_dev;
UNIT baci_unit[] =
{ { UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */
{ UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } }; /* Telnet poll unit */
UNIT baci_unit[] = {
{ UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */
{ UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } /* Telnet poll unit */
};
REG baci_reg[] = {
{ ORDATA (IBUF, baci_ibuf, 16), REG_FIT },
@ -438,12 +444,12 @@ REG baci_reg[] = {
{ FLDATA (ENQFLAG, baci_enq_seen, 0), REG_HRO },
{ DRDATA (ENQCNTR, baci_enq_cntr, 16), REG_HRO },
{ FLDATA (LKO, baci_lockout, 0) },
{ FLDATA (CTL, baci_control, 0) },
{ FLDATA (FLG, baci_flag, 0) },
{ FLDATA (FBF, baci_flagbuf, 0) },
{ FLDATA (SRQ, baci_srq, 0) },
{ ORDATA (DEVNO, baci_dib.devno, 6), REG_HRO },
{ FLDATA (LKO, baci.lockout, 0) },
{ FLDATA (CTL, baci.control, 0) },
{ FLDATA (FLG, baci.flag, 0) },
{ FLDATA (FBF, baci.flagbuf, 0) },
{ FLDATA (SRQ, baci.srq, 0) },
{ ORDATA (DEVNO, baci_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -526,232 +532,233 @@ DEVICE baci_dev = {
would be cleared, and the interrupt would be lost.
*/
uint32 baci_io (uint32 select_code, IOSIG signal, uint32 data)
uint32 baci_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const char *hold_or_clear = (signal > ioCLF ? ",C" : "");
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
const char *hold_or_clear = (signal_set & ioCLF ? ",C" : "");
uint8 ch;
uint16 data;
uint32 mask;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
baci_flag = baci_flagbuf = CLEAR; /* clear flag and flag buffer */
baci_srq = CLEAR; /* clear SRQ */
switch (signal) { /* dispatch I/O signal */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: [CLF] Flag and SRQ cleared\n", sim_deb);
update_status (); /* FLG might set when SRQ clears */
break;
case ioSTF: /* set flag flip-flop */
baci_flag = baci_flagbuf = SET; /* set flag and flag buffer */
baci_lockout = SET; /* set lockout */
baci_srq = SET; /* set SRQ */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: [STF] Flag, SRQ, and lockout set\n", sim_deb);
break;
case ioENF: /* enable flag */
baci_flag = baci_flagbuf = SET; /* set device flag and flag buffer */
baci_lockout = SET; /* set lockout */
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (baci);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (baci);
break;
case ioIOI: /* I/O data input */
if (baci_control) { /* control set? */
baci_ibuf = TO_CHARCNT (baci_fcount); /* get FIFO count */
if (IO_MODE == RECV) /* receiving? */
baci_ibuf = baci_ibuf | fifo_get (); /* add char and validity flag */
data = baci_ibuf; /* return received data */
if (DEBUG_PRI (baci_dev, DEB_CPU))
fprintf (sim_deb, ">>BACI cpu: [LIx%s] Received data = %06o\n", hold_or_clear, data);
}
else { /* control clear? */
data = baci_status; /* return status */
if (DEBUG_PRI (baci_dev, DEB_CPU))
fprintf (sim_deb, ">>BACI cpu: [LIx%s] Status = %06o\n", hold_or_clear, data);
}
break;
case ioIOO: /* I/O data output */
if (DEBUG_PRI (baci_dev, DEB_CPU))
fprintf (sim_deb, ">>BACI cpu: [OTx%s] Command = %06o\n", hold_or_clear, data);
baci_obuf = data;
if (baci_obuf & OUT_MR) { /* master reset? */
master_reset (); /* do before processing */
baci_io (select_code, ioSIR, 0); /* set interrupt request */
case ioCLF: /* clear flag flip-flop */
baci.flag = baci.flagbuf = CLEAR; /* clear flag and flag buffer */
baci.srq = CLEAR; /* clear SRQ */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Master reset\n", hold_or_clear);
}
fputs (">>BACI cmds: [CLF] Flag and SRQ cleared\n", sim_deb);
switch (GET_ID (baci_obuf)) { /* isolate ID code */
update_status (); /* FLG might set when SRQ clears */
break;
case 0: /* transmit data */
if (IO_MODE == XMIT) { /* transmitting? */
ch = baci_obuf & OUT_DATA; /* mask to character */
fifo_put (ch); /* queue character */
if (baci_term.flags & UNIT_ATT) { /* attached to network? */
if (DEBUG_PRI (baci_dev, DEB_CMDS) && /* debugging? */
(sim_is_active (&baci_term) == 0)) /* service stopped? */
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, "
"time = %d\n", hold_or_clear, baci_term.wait);
case ioSTF: /* set flag flip-flop */
baci.flag = baci.flagbuf = SET; /* set flag and flag buffer */
baci.lockout = SET; /* set lockout */
baci.srq = SET; /* set SRQ */
if (baci_fcount == 1) /* first char to xmit? */
sim_activate_abs (&baci_term, /* start service with full char time */
baci_term.wait);
else
sim_activate (&baci_term, /* start service if not running */
baci_term.wait);
}
}
break;
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: [STF] Flag, SRQ, and lockout set\n", sim_deb);
break;
case 1: /* enable device status interrupt */
baci_edsiw = baci_obuf; /* load new enable word */
update_status (); /* may have enabled an interrupt */
break;
case 2: /* device status reference */
if ((baci_term.flags & UNIT_DIAG) && /* diagnostic mode? */
(baci_dsrw & OUT_DIAG) && /* and last DIAG was high? */
!(baci_obuf & OUT_DIAG) && /* and new DIAG is low? */
!(baci_icw & OUT_BAUDRATE)) /* and clock is external? */
clock_uart (); /* pulse UART clock */
case ioENF: /* enable flag */
baci.flag = baci.flagbuf = SET; /* set device flag and flag buffer */
baci.lockout = SET; /* set lockout */
break;
baci_dsrw = baci_obuf; /* load new reference word */
update_status (); /* clocking UART may interrupt */
break;
case 3: /* character frame control */
baci_cfcw = baci_obuf; /* load new frame word */
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (baci);
break;
case 4: /* interface control */
if ((baci_icw ^ baci_obuf) & OUT_BAUDRATE) { /* baud rate change? */
baci_term.wait = service_time (baci_obuf); /* set service time to match rate */
if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */
if (baci_obuf & OUT_BAUDRATE) { /* internal baud rate requested? */
sim_activate (&baci_term, /* activate I/O service */
baci_term.wait);
case ioSFS: /* skip if flag is set */
setstdSKF (baci);
break;
if (DEBUG_PRI (baci_dev, DEB_CMDS))
case ioIOI: /* I/O data input */
if (baci.control) { /* control set? */
baci_ibuf = TO_CHARCNT (baci_fcount); /* get FIFO count */
if (IO_MODE == RECV) /* receiving? */
baci_ibuf = baci_ibuf | fifo_get (); /* add char and validity flag */
data = baci_ibuf; /* return received data */
if (DEBUG_PRI (baci_dev, DEB_CPU))
fprintf (sim_deb, ">>BACI cpu: [LIx%s] Received data = %06o\n", hold_or_clear, baci_ibuf);
}
else { /* control clear? */
data = baci_status; /* return status */
if (DEBUG_PRI (baci_dev, DEB_CPU))
fprintf (sim_deb, ">>BACI cpu: [LIx%s] Status = %06o\n", hold_or_clear, baci_status);
}
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
break;
case ioIOO: /* I/O data output */
baci_obuf = IODATA (stat_data); /* get data value */
if (DEBUG_PRI (baci_dev, DEB_CPU))
fprintf (sim_deb, ">>BACI cpu: [OTx%s] Command = %06o\n", hold_or_clear, baci_obuf);
if (baci_obuf & OUT_MR) { /* master reset? */
master_reset (); /* do before processing */
baci_io (&baci_dib, ioSIR, 0); /* set interrupt request */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Master reset\n", hold_or_clear);
}
switch (GET_ID (baci_obuf)) { /* isolate ID code */
case 0: /* transmit data */
if (IO_MODE == XMIT) { /* transmitting? */
ch = baci_obuf & OUT_DATA; /* mask to character */
fifo_put (ch); /* queue character */
if (baci_term.flags & UNIT_ATT) { /* attached to network? */
if (DEBUG_PRI (baci_dev, DEB_CMDS) && /* debugging? */
(sim_is_active (&baci_term) == 0)) /* service stopped? */
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, "
"time = %d\n", hold_or_clear, baci_term.wait);
if (baci_fcount == 1) /* first char to xmit? */
sim_activate_abs (&baci_term, /* start service with full char time */
baci_term.wait);
else
sim_activate (&baci_term, /* start service if not running */
baci_term.wait);
}
}
break;
else { /* external rate */
sim_cancel (&baci_term); /* stop I/O service */
case 1: /* enable device status interrupt */
baci_edsiw = baci_obuf; /* load new enable word */
update_status (); /* may have enabled an interrupt */
break;
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service stopped\n",
hold_or_clear);
}
}
case 2: /* device status reference */
if ((baci_term.flags & UNIT_DIAG) && /* diagnostic mode? */
(baci_dsrw & OUT_DIAG) && /* and last DIAG was high? */
!(baci_obuf & OUT_DIAG) && /* and new DIAG is low? */
!(baci_icw & OUT_BAUDRATE)) /* and clock is external? */
clock_uart (); /* pulse UART clock */
baci_icw = baci_obuf; /* load new reference word */
update_status (); /* loopback may change status */
break;
baci_dsrw = baci_obuf; /* load new reference word */
update_status (); /* clocking UART may interrupt */
break;
case 5: /* interrupt status reset */
baci_isrw = baci_obuf; /* load new reset word */
case 3: /* character frame control */
baci_cfcw = baci_obuf; /* load new frame word */
break;
mask = (baci_isrw & OUT_IRQCLR) << /* form reset mask */
IN_V_IRQCLR; /* for common irqs */
case 4: /* interface control */
if ((baci_icw ^ baci_obuf) & OUT_BAUDRATE) { /* baud rate change? */
baci_term.wait = service_time (baci_obuf); /* set service time to match rate */
if (baci_isrw & OUT_CSC) /* add special char mask bit */
mask = mask | IN_SPCHAR; /* if requested */
if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */
if (baci_obuf & OUT_BAUDRATE) { /* internal baud rate requested? */
sim_activate (&baci_term, /* activate I/O service */
baci_term.wait);
baci_status = baci_status & ~mask; /* clear specified status bits */
break;
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, "
"time = %d\n", hold_or_clear, baci_term.wait);
}
case 6: /* special character */
baci_spchar [baci_obuf & OUT_SPCHAR] = /* set special character entry */
((baci_obuf & OUT_SPFLAG) != 0);
break;
}
break;
else { /* external rate */
sim_cancel (&baci_term); /* stop I/O service */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service stopped\n",
hold_or_clear);
}
}
baci_icw = baci_obuf; /* load new reference word */
update_status (); /* loopback may change status */
break;
case 5: /* interrupt status reset */
baci_isrw = baci_obuf; /* load new reset word */
mask = (baci_isrw & OUT_IRQCLR) << /* form reset mask */
IN_V_IRQCLR; /* for common irqs */
if (baci_isrw & OUT_CSC) /* add special char mask bit */
mask = mask | IN_SPCHAR; /* if requested */
baci_status = baci_status & ~mask; /* clear specified status bits */
break;
case 6: /* special character */
baci_spchar [baci_obuf & OUT_SPCHAR] = /* set special character entry */
((baci_obuf & OUT_SPFLAG) != 0);
break;
}
break;
case ioPOPIO: /* power-on preset to I/O */
/* fall into CRS handler */
case ioCRS: /* control reset */
master_reset (); /* issue master reset */
case ioCRS: /* control reset */
master_reset (); /* issue master reset */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: [CRS] Master reset\n", sim_deb);
break;
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: [CRS] Master reset\n", sim_deb);
break;
case ioCLC: /* clear control flip-flop */
baci_control = CLEAR; /* clear control */
case ioCLC: /* clear control flip-flop */
baci.control = CLEAR; /* clear control */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [CLC%s] Control cleared\n", hold_or_clear);
break;
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [CLC%s] Control cleared\n", hold_or_clear);
break;
case ioSTC: /* set control flip-flop */
baci_control = SET; /* set control */
baci_lockout = CLEAR; /* clear lockout */
case ioSTC: /* set control flip-flop */
baci.control = SET; /* set control */
baci.lockout = CLEAR; /* clear lockout */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [STC%s] Control set and lockout cleared\n", hold_or_clear);
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [STC%s] Control set and lockout cleared\n", hold_or_clear);
if (signal == ioSTC) /* STC without ,C ? */
update_status (); /* clearing lockout might interrupt */
break;
if (!(signal_set & ioCLF)) /* STC without ,C ? */
update_status (); /* clearing lockout might interrupt */
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, baci); /* set standard PRL signal */
setstdIRQ (select_code, baci); /* set standard IRQ signal */
setSRQ (select_code, baci_srq); /* set SRQ signal */
break;
case ioSIR: /* set interrupt request */
setstdPRL (baci); /* set standard PRL signal */
setstdIRQ (baci); /* set standard IRQ signal */
setSRQ (dibptr->select_code, baci.srq); /* set SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
baci_flagbuf = CLEAR;
break;
case ioIAK: /* interrupt acknowledge */
baci.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
baci_io (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
baci_io (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -931,7 +938,7 @@ while (recv_loop && /* OK to process? */
baci_uart_rhr = CLEAR_HR; /* clear RHR */
update_status (); /* update FIFO status (may set flag) */
recv_loop = fast_timing && !IRQ (baci_dib.devno); /* loop if fast mode and no IRQ */
recv_loop = fast_timing && !IRQ (baci_dib.select_code); /* loop if fast mode and no IRQ */
}
else { /* xmit or ENQ/ACK, leave char in RHR */
@ -1002,7 +1009,7 @@ return SCPE_OK;
t_stat baci_reset (DEVICE *dptr)
{
baci_io (baci_dib.devno, ioPOPIO, 0); /* send POPIO signal */
IOPRESET (&baci_dib); /* PRESET device (does not use PON) */
baci_ibuf = 0; /* clear input buffer */
baci_obuf = 0; /* clear output buffer */
@ -1083,10 +1090,10 @@ baci_uart_rr = CLEAR_R; /* clear receiver regist
baci_uart_clk = 0; /* clear UART clock */
baci_bcount = 0; /* clear break counter */
baci_control = CLEAR; /* clear control */
baci_flag = baci_flagbuf = SET; /* set flag and flag buffer */
baci_srq = SET; /* set SRQ */
baci_lockout = SET; /* set lockout flip-flop */
baci.control = CLEAR; /* clear control */
baci.flag = baci.flagbuf = SET; /* set flag and flag buffer */
baci.srq = SET; /* set SRQ */
baci.lockout = SET; /* set lockout flip-flop */
baci_edsiw = 0; /* clear interrupt enables */
baci_dsrw = 0; /* clear status reference */
@ -1150,18 +1157,18 @@ if ((baci_status & IN_STDIRQ) || /* standard interrupt? *
(baci_edsiw & OUT_ENCM) && /* and char mode */
(baci_fget != baci_fput)) { /* and FIFO not empty? */
if (baci_lockout) { /* interrupt lockout? */
if (baci.lockout) { /* interrupt lockout? */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: Lockout prevents flag set", sim_deb);
}
else if (baci_srq) { /* SRQ set? */
else if (baci.srq) { /* SRQ set? */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: SRQ prevents flag set", sim_deb);
}
else {
baci_io (baci_dib.devno, ioENF, 0); /* set flag */
baci_io (&baci_dib, ioENF, 0); /* set flag */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: Flag and lockout set", sim_deb);
@ -1175,14 +1182,14 @@ if ((baci_icw & OUT_DCPC) && /* DCPC enabled? */
((IO_MODE == XMIT) && (baci_fcount < 128) || /* and xmit and room in FIFO */
(IO_MODE == RECV) && (baci_fcount > 0))) { /* or recv and data in FIFO? */
if (baci_lockout) { /* interrupt lockout? */
if (baci.lockout) { /* interrupt lockout? */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: Lockout prevents SRQ set", sim_deb);
}
else {
baci_srq = SET; /* set SRQ */
baci_io (baci_dib.devno, ioSIR, 0); /* set interrupt request */
baci.srq = SET; /* set SRQ */
baci_io (&baci_dib, ioSIR, 0); /* set interrupt request */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: SRQ set", sim_deb);

View file

@ -1,6 +1,6 @@
HP 2100 SIMULATOR BUG FIX WRITEUPS
==================================
Last update: 2008-09-30
Last update: 2011-06-21
1. PROBLEM: Booting from magnetic tape reports "HALT instruction, P: 77756
@ -138,8 +138,8 @@
the "ex -u" and "ex -s" commands reveals the same data in both sets of
locations. The "ex" command isn't using the DMS maps properly.
CAUSE: String constants are used instead of character constants, preventing
the DMS map switches from being recognized.
CAUSE: String constants are used instead of character constants,
preventing the DMS map switches from being recognized.
RESOLUTION: Modify "hp2100_cpu.c" to use character constants rather than
string constants in "dms_cons" so that DMS map switches work correctly.
@ -151,14 +151,14 @@
program. The EXEC target is below the MP fence, and the expected action is
an MP violation interrupt that is recognized and processed by the system as
a legal call to the system executive. However, the MP violation isn't
occurring, so the SJP instruction at the actual EXEC entry point (present to
catch EXEC calls made with the interrupt system off) is attempted, and that
causes the DM violation, due to execution of a protected instruction from
the user map.
occurring, so the SJP instruction at the actual EXEC entry point (present
to catch EXEC calls made with the interrupt system off) is attempted, and
that causes the DM violation, due to execution of a protected instruction
from the user map.
CAUSE: Memory writes aren't being checked for an MP violation if DMS is
enabled, i.e., if DMS is enabled, and the page is writable, then whether the
target is below the MP fence is not checked.
enabled, i.e., if DMS is enabled, and the page is writable, then whether
the target is below the MP fence is not checked.
RESOLUTION: Modify "hp2100_cpu.c" to do MP check on all writes after DMS
translation and violation checks are done (so, to pass, the page must be
@ -430,7 +430,7 @@
RESOLUTION: Alter "ptr_svc" (hp2100_stddev.c) to fail if STOP_IOE is set,
or to supply feed frames upon encountering the end of the attached file.
"SET PTR TRLLIM" sets the maximum number of feed frames to supply. Note
that RTE needs at least 30 feed frames before signalling EOT.
that RTE needs at least 30 feed frames before signaling EOT.
STATUS: Fixed in version 3.2-1.
@ -706,8 +706,8 @@
the simulator doesn't supply it explicitly in this case.
The HP "7900A Disc Drive Operating and Service Manual" (07900-90002) says,
in section 4-67, "Attention is set high everytime a seek has been completed
and Access Ready comes high."
in section 4-67, "Attention is set high every time a seek has been
completed and Access Ready comes high."
TSB code loads the "drive attention" word from the command channel to create
a "request status" command. The code assumes that either bit 0 or bit 1
@ -848,9 +848,9 @@
from issuing a WRITE command until the first data is requested). Most of
these are reported as diagnostic failures.
CAUSE: I/O time modelling is not done properly. In some cases, the times
CAUSE: I/O time modeling is not done properly. In some cases, the times
indicated are incorrect. In others, certain characteristics (e.g., that
operations from BOT take longer, due to the initial gap) aren't modelled at
operations from BOT take longer, due to the initial gap) aren't modeled at
all.
RESOLUTION: Revise "mscio" and "msc_svc" (hp2100_ms.c) to model actual I/O
@ -1200,12 +1200,13 @@
ready (i.e., when the unit is attached).
CAUSE: Section 4-67 of the "7900A Disc Drive Operating and Service Manual"
(HP 07900-90002) says, "Attention is set high everytime a seek has completed
and Access Ready comes high." This includes the initial head-loading seek
when the drive becomes ready. The "Troubleshooting Diagrams (Sheet 2 of 4)"
on page 5-17 show that after the heads load, Drive Ready, First Status,
Access Ready (a.k.a. not Busy), and Attention are asserted. The
corresponding code in "dpc_attach" sets First Status but not Attention.
(HP 07900-90002) says, "Attention is set high every time a seek has
completed and Access Ready comes high." This includes the initial
head-loading seek when the drive becomes ready. The "Troubleshooting
Diagrams (Sheet 2 of 4)" on page 5-17 show that after the heads load, Drive
Ready, First Status, Access Ready (a.k.a. not Busy), and Attention are
asserted. The corresponding code in "dpc_attach" sets First Status but not
Attention.
In addition, the last diagnostic command prior to the loop is a STATUS
CHECK. This leaves the 13210A interface polling for attention bits, and
@ -1332,7 +1333,7 @@
51. PROBLEM: The diagnostic configurator mis-identifies the host CPU.
51. PROBLEM: The diagnostic configurator misidentifies the host CPU.
VERSION: 3.2-3
@ -1509,7 +1510,7 @@
missing the option to indicate that commas are glyph separators.
RESOLUTION: Modify the appropriate calls to "get_glyph" (scp.c,
sim_console.c) to specify ',' as the the "optional end of glyph character"
sim_console.c) to specify ',' as the "optional end of glyph character"
parameter.
STATUS: Fixed in version 3.3-0.
@ -2154,7 +2155,7 @@
conclusion of writes when using the 12606 interface. This is an artifact of
the interface design.
CAUSE: The status return from the 12606 interface is not modelled properly.
CAUSE: The status return from the 12606 interface is not modeled properly.
RESOLUTION: Modify "drv_svc" (hp2100_dr.c) to return DRS_PER at the
conclusion of writes when configured as a 2770/2771 disk.
@ -2542,7 +2543,7 @@
Section I, Paragraph 4-17, "Store Field", of the "HP 1000 M/E/F-Series
Computers Engineering and Reference Documentation" (HP 92851-90001) says:
"The A and B addressable flip-slops (ABFF) [38A] can be clocked at the
"The A and B addressable flip-flops (ABFF) [38A] can be clocked at the
end of every microcycle. Addresses 0 and 1 are detected on the M-bus and
the flip-flops are set accordingly. When DCPC uses the M-bus the ABFFST
signal is suppressed."
@ -3867,7 +3868,7 @@
the terminal multiplexer.
RESOLUTION: Modify the "ioEDT" handler in "iplio" (hp2100_ipl.c) to sleep
for one millisecond before signalling a DMA completion interrupt for an
for one millisecond before signaling a DMA completion interrupt for an
output transfer. This allows the SP time to pulse the IPL before the IOP
processes the DMA completion interrupt. Modify "dma_cycle" (hp2100_cpu.c)
to pass the DMA channel number and I/O direction flag in the "dat"
@ -4711,7 +4712,7 @@
191. PROBLEM: The action of certain I/O cards (e.g., the 12936A Privileged
Interrupt Fence) cannot be modelled by SIMH.
Interrupt Fence) cannot be modeled by SIMH.
VERSION: 3.8-0
@ -4722,7 +4723,7 @@
CAUSE: The hardware has I/O signals for interrupt request (IRQ) and
interrupt priority to lower-priority devices (PRL). These signals are not
modelled directly in SIMH. Rather, they are implied by control, flag, and
modeled directly in SIMH. Rather, they are implied by control, flag, and
flag buffer set (for IRQ) and control and flag set (for PRL). If an I/O
card does not follow these conventions, then the proper action cannot be
simulated.
@ -5065,7 +5066,7 @@
VERSION: 3.8-0
OBSERVATION: The A and B register values are stored in two places: as
"uint16 ABREG[2]" duing execution, and as "uint32 saved_AR" and "uint32
"uint16 ABREG[2]" during execution, and as "uint32 saved_AR" and "uint32
saved_BR" between executions. The latter was to accommodate the
requirement that register variables must be 32 bits in size. That
requirement was removed in version 3.5-2 for registers declared with the
@ -5208,10 +5209,10 @@
VERSION: 3.8-0
OBSERVATION: Page 2-6 of the 12559A 9-Track Magnetic Tape Unit Interface
Kit Operating and Service Manual says that the CLR command channel flag
flip-flop when the command completes. The MT simulator does not, so the
command channel does not interrupt.
OBSERVATION: Page 2-5 of the 12559A 9-Track Magnetic Tape Unit Interface
Kit Operating and Service Manual says that the command channel flag
flip-flop sets when the CLR command completes. The MT simulator does not
do this, so the command channel does not interrupt.
CAUSE: Coding error.
@ -5319,7 +5320,7 @@
This second interrupt would normally be allowed, as the STC sc,C
instruction clears the "interrupt lockout" flag that was set when the first
interupt was generated. However, the STC signal handler checks for
interrupt was generated. However, the STC signal handler checks for
interrupt status between the STC and the succeeding CLF, rather than after
the CLF. The result is that the STC clears lockout, then the FIFO status
sets the flag and lockout, and then the CLF clears the flag, leaving
@ -5351,3 +5352,554 @@
to the "interrupt trap cell" execution path.
STATUS: Fixed in version 3.8-1.
213. PROBLEM: A DO command without a filename prints the wrong error message.
VERSION: 3.8-1
OBSERVATION: The DO command requires a file argument and zero or more
parameter arguments. Entering DO without the file argument should print
"Too few arguments," as other commands that require arguments do (e.g.,
ATTACH, BOOT, etc.). Instead, it prints "File open error."
CAUSE: A test in "do_cmd" attempts to detect when no arguments are passed
and return SCPE_2FARG in response, but the test always fails. As a result,
"fopen" is called with a NULL filename parameter. The call fails,
resulting in the "File open error" message.
The test follows the initialization of the "do_arg" array and depends on
initialization stopping when a null argument is encountered. The bug fix
of 25-Jul-2008 ("DO cmd missing params now default to null string")
modified "do_arg" initialization to cover the entire array. Therefore, the
test to determine if "do_arg" was not initialized (which implies that the
file argument was not passed) never trips.
RESOLUTION: Modify "do_arg" (scp.c) to test "do_arg[0]" for NULL and to
return SCPE_2FARG if so.
STATUS: Fixed in version 3.8-2.
214. PROBLEM: DMA/DCPC cannot steal consecutive I/O cycles.
VERSION: 3.8-1
OBSERVATION: All DMA and DCPC cards are capable of stealing consecutive
I/O cycles, presuming that SRQ is asserted at the proper time before each
cycle. The current SIMH implementation of DMA/DCPC is capable of stealing
only every other cycle, even if SRQ is asserted continuously. The 12821A
Disc Interface diagnostic checks for consecutive cycle-steal capability and
fails when run.
CAUSE: Each pass through the instruction simulation loop does a device
timeout check, then a potential DMA cycle, and then an instruction cycle.
The device timeout calls the card unit service routine, which sets SRQ and
schedules the next service. The SRQ is then processed with the DMA cycle,
which dispatches ioIOI/IOO and ioCLF to the device. At the end of the DMA
cycle, the next instruction is executed.
A device capable of transferring data continuously would leave SRQ asserted
after the I/O cycle. But because SRQ is not checked after the DMA cycle,
the next instruction execution is performed unconditionally. Therefore,
even with continuous SRQ assertion, the simulator will interleave DMA
cycles and instructions.
RESOLUTION: Modify the instruction execution loop (hp2100_cpu.c) to
recalculate SRQ requests after each DMA cycle, and if a request is still
pending, skip instruction execution. This allows consecutive DMA cycles
without intervening instruction executions if SRQ is asserted continuously.
STATUS: Fixed in version 3.8-2.
215. PROBLEM: DMA/DCPC does not give priority to channel 1 during contention.
VERSION: 3.8-1
OBSERVATION: Dual-channel DMA/DCPC cards give priority to channel 1 if
both channels are requesting a DMA cycle. If channel 1 SRQ is asserted
continuously, then no channel 2 cycles will occur until channel 1
completes.
Under simulation, channel cycle requests alternate unconditionally. If
channel 2 requests a DMA cycle, it will always be granted, regardless of
any pending channel 1 requests.
CAUSE: Each pass through the instruction simulation loop checks for a
channel 1 request and then a channel 2 request, dispatching DMA cycles as
indicated. The check for a channel 2 request should not occur if a channel
1 request is still pending at the end of its DMA cycle.
RESOLUTION: Modify the instruction execution loop (hp2100_cpu.c) to
inhibit DMA channel 2 if a channel 1 request is still pending after a
channel 1 cycle.
STATUS: Fixed in version 3.8-2.
216. ENHANCEMENT: Rename DMA channels 0 and 1 to 1 and 2 to match the
documentation.
VERSION: 3.8-1
OBSERVATION: The HP 2100 simulator presents DMA0 and DMA1 as the DMA
devices. However, all HP literature refers to these as channel 1 and
channel 2.
RESOLUTION: Modify the device names (hp2100_cpu.c, hp2100_defs.h, and
hp2100_sys.c) from 0 and 1 to 1 and 2 to align with HP usage.
STATUS: Fixed in version 3.8-2.
217. PROBLEM: The comments for "cpu_set_idle" (hp2100_cpu.c) are obsolete.
VERSION: 3.8-1
OBSERVATION: The comments for the above routine note the requirement for
clock stabilization. This was added in 3.8-1, but the comments were not
changed.
CAUSE: Oversight.
RESOLUTION: Removed obsolete comments.
STATUS: Fixed in version 3.8-2.
218. PROBLEM: The 12578A DMA device is modeled incorrectly.
VERSION: 3.8-1
OBSERVATION: The 12578A DMA device simulation incorporates a latency
counter that delays the first DMA cycle for one instruction after the STC
is issued to enable the channel. This is incorrect; if SRQ is already
asserted, the first cycle occurs immediately after the channel is enabled.
CAUSE: Incorrect understanding.
RESOLUTION: Modify hp2100_cpu.c to remove the latency counter.
STATUS: Fixed in version 3.8-2.
219. PROBLEM: DMA IOO and CLF/EDT signals are not concurrent.
VERSION: 3.8-1
OBSERVATION: A DMA transfer to the 12821A Disc Interface should not set
the end-of-data-transfer flip-flop on the DI card until the last word has
been sent. Instead, each word transferred sets the flip-flop.
CAUSE: In the packed output mode, the end-of-data-transfer flip-flop is
set either if the the OTx instruction does not clear the flag (i.e., if OTA
used instead of OTA,C), or if the DMA EDT signal is asserted. DMA
transfers are programmed to clear the flag with each write to prevent the
flip-flop from setting until the EDT signal asserts when the last word is
output.
In hardware, CLF or EDT is asserted concurrently with IOO. In simulation,
"dma_cycle" calls the device's I/O signal handler with ioIOO, then with
ioCLF, and then, for the last cycle only, with ioEDT. At the time that the
handler receives ioIOO, it has no way of knowing whether ioCLF will follow.
Therefore, the DI sets its end-of-data-transfer flip-flop on the first word
transferred instead of on the last word transferred.
The fundamental problem is that DMA hardware may assert multiple concurrent
signals, upon which I/O card designs may test and act, but simulation
serializes the signals and therefore prevents concurrency detection.
RESOLUTION: Modify "dma_cycle" (hp2100_cpu.c) to send one set of
concurrent I/O signals to the target handler for each DMA I/O cycle, and
modify all I/O device handlers to allow processing of multiple concurrent
signals.
STATUS: Fixed in version 3.8-2.
220. ENHANCEMENT: Enhance the I/O signal dispatcher to provide for multiple
devices controlled by the same device signal handler.
VERSION: 3.8-1
OBSERVATION: Currently, the DCPC, IPL, and DI simulations control multiple
devices. The first two control a pair of devices each and determine the
desired device by checking the select code. The DI will control three,
complicating the test that would have to be done at each signal handler
entry.
RESOLUTION: Modify "devdisp" (hp2100_cpu.c) to pass the Device Information
Block (DIB) pointer instead of the select code to device signal handlers,
and modify all signal handlers accordingly. Modify all device DIBs to add
card numbers to allow for multiple-device handlers.
STATUS: Fixed in version 3.8-2.
221. PROBLEM: The LPS diagnostic mode is modeled incorrectly.
VERSION: 3.8-1
OBSERVATION: The 12578A DMA simulation was modified to remove the latency
from enabling a channel to issuing the first DMA cycle. After this change
was made, the card failed DMA diagnostic test 17.
CAUSE: The LPS device offers a diagnostic mode that simulates a 12566B
Microcircuit Interface card equipped with a loopback connector. This
configuration is used for a number of diagnostics that require an I/O card
in addition to the card under test. Typically, this is to test I/O or
interrupt capability. Jumpers on the card configure it for the diagnostic
response expected. The SET LPS DIAG mode configures the card properly for
all diagnostics except the 12578A DMA diagnostic.
SET LPS DIAG simulates jumper W1 in position C and W2 in position B. In
these positions, an STC will set the card flag one instruction later. When
used for a DMA transfer, instructions and DMA cycles will interleave 1:1,
i.e., DMA will steal every other cycle.
The 12578A diagnostic requires jumper W1 in position B and W2 in position
C. In these positions, an STC will set the card flag two instructions
later, so DMA will steal every third cycle, allowing two instructions
between DMA cycles. The 12578A diagnostic depends on this and will report
errors otherwise.
RESOLUTION: Modify "lpsio" (hp2100_lps.c) to schedule device service in
DIAG mode in three instructions if the CPU is a 2114, 2115, or 2116 and in
two instructions otherwise.
STATUS: Fixed in version 3.8-2.
222. PROBLEM: The 12821A Disc Interface diagnostic aborts with "Unit not
attached."
VERSION: 3.8-1
OBSERVATION: The 12821A Disc Interface diagnostic locates the card to test
by issuing a CLC sc,C / OTA sc / LIA sc sequence to each card in the card
cage; this writes a zero value and then looks for a specific response that
is characteristic of the DI. When the zero value is written to the MT
device (HP 3030 tape drive), it responds with "Unit not attached."
CAUSE: The MT device is unusual in that commands are executed when they
are written to the card, rather than in response to STC. Therefore, when
the zero value is written, the MT device attempts to interpret that value
as a command.
The IOO processor checks for a valid command before proceeding. Zero is
not a valid command, but the check is not coded properly. The search
through the command table loops for the number of bytes in the table, not
for the number of entries. One of the values beyond the end of the table
equals zero, so the command is considered valid, and unit service is
scheduled. The unit service routine determines that the unit is not
attached and returns an error code, causing a simulator stop.
RESOLUTION: Modify "mtcio" (hp2100_mt.c) to use the count of command table
entries as the loop count.
STATUS: Fixed in version 3.8-2.
223. ENHANCEMENT: Consolidate reporting of consecutive CRS signals.
VERSION: 3.8-1
OBSERVATION: HP 2000 Time Shared BASIC begins its start sequence by
issuing 128K CLC 0 instructions. This sequence is required by the 12920A
Terminal Multiplexer. If debugging is enabled, the IPL device writes 128K
lines to the log file. It would be more helpful if the ioCRS processor
detected consecutive calls and summarized them in a single line.
RESOLUTION: Modify "iplio" (hp2100_ipl.c) to add a CRS invocation counter
and to report a single debug line for consecutive CRS calls.
STATUS: Fixed in version 3.8-2.
224. PROBLEM: Simulation stops are ignored during DMA cycles.
VERSION: 3.8-1
OBSERVATION: An I/O routine may return an error code other than SCPE_OK to
stop the simulator. For example, IPL may return SCPE_IOERR if STC is
issued to a card with a disconnected socket. If the device is invoked via
programmed I/O, an error value return will cause a simulation stop. If the
device is invoked by DMA, it will not.
CAUSE: The "iogrp" function returns the status code to the instruction
loop, but the "dma_cycle" function ignores status returns from the I/O
handlers.
RESOLUTION: Modify "dma_cycle" (hp2100_cpu.c) to return the status from
the device signal handler, and modify "sim_instr" to stop instruction
execution if the returned status is not SCPE_OK.
STATUS: Fixed in version 3.8-2.
225. PROBLEM: Simulation stops do not always preserve the CPU state for
restarting.
VERSION: 3.8-1
OBSERVATION: If the CPU simulator is stopped by certain errors, e.g., an
unimplemented instruction execution, simulation control returns with the
CPU state set as it was just prior to the error. This allows the error to
be corrected and simulation to be resumed. It also allows identification
of the problem instruction.
Other errors, e.g., SCPE_IOERR returned by the IPL device signal handler,
stop the CPU after processing the offending instruction. In this case, the
PC points to the instruction after the offending instruction, so
identification, correction, and resumption are more difficult. DMA cycles
are also affected, as DMA registers are updated even if the I/O cycle
fails.
CAUSE: The CPU instruction and DMA cycle routines do not back out properly
when a simulation stop is indicated by a device signal handler.
RESOLUTION: Modify "sim_instr" (hp2100_cpu.c) to back out the current
instruction if it indicates a simulation stop (except for the HLT
instruction), modify "dma_cycle" to update the address and word count only
if the I/O cycle completes successfully, and modify "iplio" (hp2100_ipl.c)
to allow for restarting of a failed I/O cycle.
STATUS: Fixed in version 3.8-2.
226. PROBLEM: The comments for the floating-point divide routine are
incomplete.
VERSION: 3.8-1
OBSERVATION: In the comments for the "divide" function in "hp2100_fp1.c",
the explanation of the simulation implementation trails off with, "The
resulting 32-bit quotient is ..." It appears that the comments were never
finished before release.
CAUSE: Oversight.
RESOLUTION: Expanded and completed the comments in the "divide" function
(hp2100_fp1.c).
STATUS: Fixed in version 3.8-2.
227. PROBLEM: The 79xx disc returns incorrect status for a disabled drive.
VERSION: 3.8-1
OBSERVATION: The same "unit present; heads unloaded" status is reported
for both an enabled but unattached unit and a disabled unit. The latter
should report "unit not present" status.
CAUSE: SIMH initially defines the DS device as having eight 7905 drives
connected to the controller. Each drive reports "heads unloaded" status
(status-2 bits 1-0 = 11) until it has a disc image attached. If a unit is
disabled, it continues to report "heads unloaded" status. It should be
reporting "unit not present" (status-2 bits 1-0 = 10) status.
RESOLUTION: Modify "ds_updds2" (hp2100_ds.c) to report an "enabled and
unloaded" condition as Not Ready and Busy, and a "disabled" condition as
Not Ready only.
STATUS: Fixed in version 3.8-2.
228. PROBLEM: The 79xx disc returns incorrect status for an auto-seek beyond
the drive limits.
VERSION: 3.8-1
OBSERVATION: When an auto-seek causes the disc address to move beyond the
drive limits, the wrong status is returned. For example, the following
OPDSN program:
SM,3 -- set file mask to auto-seek, cylinder mode, incremental
SK,410,2,47 -- seek to last sector of the drive
RD,256 -- read two sectors
EN
...results in Cylinder Compare Error status; status-2 shows a seek check.
The result is identical if SM,1 (surface auto-seek, rather than cylinder
auto-seek) is used.
If the RD,256 is replaced by RF,276, the result is Normal Completion and a
seek check. The resulting disc address is 411,0,1.
If decremental seeks are used:
SM,13 -- set file mask to auto-seek, cylinder mode, decremental
SK,0,2,47 -- seek to last sector of the first cylinder
RD,256 -- read two sectors
EN
...the status return is the same as above.
In each of these cases, the result should be Status-2 (Seek Check) on the
second sector transfer.
CAUSE: If an auto-seek exceeds the drive bounds, a seek check is correctly
detected, but it is not reported back to the host.
RESOLUTION: Modify "ds_start_rw" (hp2100_ds.c) to check for Seek Check on
an auto-seek and to report Status-2 if set. Also, a reseek resulting from
a cylinder miscompare now either succeeds if the cylinder is valid or
reports Status-2 and Seek Check if the cylinder is invalid. Finally, an
invalid head or sector value reports Status-2 and Seek Check instead of
Head-Sector Compare Error (Head-Sector and Cylinder Compare Errors can only
occur during sparing operations which are not supported in simulation).
STATUS: Fixed in version 3.8-2.
229. PROBLEM: The Read Without Verify command does not verify the address when a
track boundary is crossed.
VERSION: 3.8-1
OBSERVATION: The Read Without Verify command is identical to the Read
command except that it skips address verification before beginning the
read. If the read continues past a track boundary and auto-seek is
enabled, the new track location should be verified. This does not occur.
The following OPDSN program illustrates the problem:
SM,3 -- set file mask to auto-seek, cylinder mode, incremental
SK,0,0,47 -- seek to last sector on cylinder 0 head 0
DB,128,000047 -- fill the sector buffer with the CHS address
WD,128 -- write sector 0/0/47
DB,128,000100 -- fill the sector buffer with the CHS address
WD,128 -- write sector 0/1/0
SK,1,0,47 -- seek to the last sector on cylinder 1 head 0
DB,128,100047 -- fill the sector buffer with the CHS address
WD,128 -- write sector 1/0/47
DB,128,100100 -- fill the sector buffer with the CHS address
WD,128 -- write sector 1/1/0
SK,0,0,47 -- seek to last sector on cylinder 0 head 0
AR,1,0,47 -- change controller address to cylinder 1
RW,256 -- read two sectors
DR,120,135 -- display end of first sector and start of second sector
EN
If address verification is performed at the end of track 0, the second
sector will be read from 1,1,0 instead of 0,1,0 because of the cylinder
miscompare after the auto-seek:
0120: 000047 000047 000047 000047 000047 000047 000047 000047
0128: 100100 100100 100100 100100 100100 100100 100100 100100
However, the above program prints:
0120: 000047 000047 000047 000047 000047 000047 000047 000047
0128: 000100 000100 000100 000100 000100 000100 000100 000100
...indicating that address verification was not done for either sector.
Note that if the Read Without Verify above is changed to Read (RD,256), the
result is:
0120: 100047 100047 100047 100047 100047 100047 100047 100047
0128: 100100 100100 100100 100100 100100 100100 100100 100100
...indicating that address verification was done correctly for the first
sector.
CAUSE: The Read Without Verify handler disables address verification for
the entire transfer. It should be disabled only until a track switch
occurs.
RESOLUTION: Modify the Read Without Verify command handler in "ds_svc_u"
(hp2100_ds.c) to begin verifying if a track boundary is crossed.
STATUS: Fixed in version 3.8-2.
230. PROBLEM: The Request Sector Address command does not check the unit
number.
VERSION: 3.8-1
OBSERVATION: The Request Sector Address command accepts invalid, unloaded,
or missing units without reporting status errors. Also, the specified unit
number is not reported in the status-1 field of a subsequent Request Status
command. Assuming that unit "ds1" is not attached (heads unloaded) and
unit "ds2" is disabled, the following OPDSN programs illustrate the
problem:
SD,1
RA
ST
SC,0001001100000001,1XXXXXX000X00011
DR,0
EN
SD,2
RA
ST
SC,0001001100000010,1XXXXXX000X00010
DR,0
EN
SD,10
RA
ST
SC
DR,0
EN
All of these should return Status-2 but instead return Normal Completion.
SD,15
RA
ST
SC,0001011100001111,1XXXXXX000X00010
DR,0
EN
This should return Unit Unavailable but instead returns Normal Completion.
CAUSE: The Request Sector Address command handler is not checking the unit
range or status.
RESOLUTION: Modify "ds_docmd" (hp2100_ds.c) to set the unit number into
the status-1 field and to check for invalid units and report Unit
Unavailable if so. Modify "ds_svc_u" to check that the heads are loaded on
the target unit and report Status-2 if not.
STATUS: Fixed in version 3.8-2.
231. PROBLEM: The Wakeup command does not check the unit number.
VERSION: 3.8-1
OBSERVATION: The Wakeup command accepts invalid units without reporting
status errors. Also, the specified unit number is not reported in the
status-1 field of a subsequent Request Status command.
CAUSE: The Wakeup command handler is not checking the unit range.
RESOLUTION: Modify "ds_docmd" (hp2100_ds.c) to set the unit number into
the status-1 field and to check for invalid units and report Unit
Unavailable if so.
STATUS: Fixed in version 3.8-2.

File diff suppressed because it is too large Load diff

View file

@ -281,24 +281,25 @@ extern uint32 O; /* O register */
/* CPU state */
extern uint32 err_PC;
extern uint32 dms_enb;
extern uint32 dms_ump;
extern uint32 dms_sr;
extern uint32 dms_vr;
extern FLIP_FLOP mp_control;
extern uint32 mp_fence;
extern uint32 mp_viol;
extern FLIP_FLOP mp_mevff;
extern uint32 iop_sp;
extern t_bool ion_defer;
extern uint32 intaddr;
extern uint16 pcq [PCQ_SIZE];
extern uint32 pcq_p;
extern uint32 stop_inst;
extern UNIT cpu_unit;
extern DEVICE cpu_dev;
extern jmp_buf save_env;
extern uint32 err_PC;
extern uint32 dms_enb;
extern uint32 dms_ump;
extern uint32 dms_sr;
extern uint32 dms_vr;
extern FLIP_FLOP mp_control;
extern uint32 mp_fence;
extern uint32 mp_viol;
extern FLIP_FLOP mp_mevff;
extern uint32 iop_sp;
extern t_bool ion_defer;
extern uint32 intaddr;
extern uint16 pcq [PCQ_SIZE];
extern uint32 pcq_p;
extern uint32 stop_inst;
extern UNIT cpu_unit;
extern DEVICE cpu_dev;
extern jmp_buf save_env;
/* CPU functions */

View file

@ -1,6 +1,6 @@
/* hp2100_cpu0.c: HP 1000 user microcode and unimplemented instruction set stubs
Copyright (c) 2006-2008, J. David Bryan
Copyright (c) 2006-2010, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
CPU0 User microcode and unimplemented firmware options
04-Nov-10 JDB Removed DS note regarding PIF card (is now implemented)
18-Sep-08 JDB .FLUN and self-tests for VIS and SIGNAL are NOP if not present
11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h
05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers)
@ -81,8 +82,7 @@
the cards.
Implementation of the DS instructions will also require simulation of the
12665A Hardwired Serial Data Interface Card and the 12620A RTE Privileged
Interrupt Fence. These are required for DS/1000.
12665A Hardwired Serial Data Interface Card.
Option implementation by CPU was as follows:
@ -180,11 +180,11 @@ t_stat reason = SCPE_OK;
if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2116/15/14 CPU? */
return stop_inst; /* user microprograms not supported */
switch (IR) { /* opcodes for firmware detection */
case 0105226: /* FFP .FLUN */
case 0105355: /* RTE-6/VM OS self-test */
case 0105477: /* VIS self-test */
case 0105617: /* SIGNAL/1000 self-test */
switch (IR) {
case 0105226: /* firmware detection: FFP .FLUN */
case 0105355: /* firmware detection: RTE-6/VM OS self-test */
case 0105477: /* firmware detection: VIS self-test */
case 0105617: /* firmware detection: SIGNAL/1000 self-test */
return SCPE_OK; /* execute as NOP */
}

View file

@ -1,6 +1,6 @@
/* hp2100_cpu6.c: HP 1000 RTE-6/VM OS instructions
Copyright (c) 2006-2008, J. David Bryan
Copyright (c) 2006-2010, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
CPU6 RTE-6/VM OS instructions
29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation
18-Sep-08 JDB Corrected .SIP debug formatting
11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h
05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers)
@ -258,8 +259,8 @@ if (iotrap) { /* do priv setup only if
if (priv_fence) { /* privileged system? */
reason = iogrp (STC_0 + priv_fence, iotrap); /* STC SC on priv fence */
reason = iogrp (CLC_0 + DMA0, iotrap); /* CLC 6 to inh IRQ on DCPC 0 */
reason = iogrp (CLC_0 + DMA1, iotrap); /* CLC 7 to inh IRQ on DCPC 1 */
reason = iogrp (CLC_0 + DMA1, iotrap); /* CLC 6 to inh IRQ on DCPC 1 */
reason = iogrp (CLC_0 + DMA2, iotrap); /* CLC 7 to inh IRQ on DCPC 2 */
reason = iogrp (STF_0, iotrap); /* turn interrupt system back on */
}
}
@ -600,11 +601,11 @@ switch (entry) { /* decode IR<3:0> */
reason = iogrp (CLC_0 + priv_fence, iotrap); /* CLC SC on priv fence */
reason = iogrp (STF_0 + priv_fence, iotrap); /* STF SC on priv fence */
if (cpu_get_intbl (DMA0) & SIGN) /* DCPC 0 active? */
reason = iogrp (STC_0 + DMA0, iotrap); /* STC 6 to enable IRQ on DCPC 0 */
if (cpu_get_intbl (DMA1) & SIGN) /* DCPC 1 active? */
reason = iogrp (STC_0 + DMA1, iotrap); /* STC 7 to enable IRQ on DCPC 1 */
reason = iogrp (STC_0 + DMA1, iotrap); /* STC 6 to enable IRQ on DCPC 1 */
if (cpu_get_intbl (DMA2) & SIGN) /* DCPC 2 active? */
reason = iogrp (STC_0 + DMA2, iotrap); /* STC 7 to enable IRQ on DCPC 2 */
}
tbg_tick = 0; /* .IRT terminates TBG servicing */

View file

@ -1,6 +1,6 @@
/* hp2100_defs.h: HP 2100 simulator definitions
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,10 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
28-Mar-11 JDB Tidied up signal handling
29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation
27-Oct-10 JDB Revised I/O signal enum values for concurrent signals
Revised I/O macros for new signal handling
07-Sep-08 JDB Added POLL_FIRST to indicate immediate connection attempt
15-Jul-08 JDB Rearranged declarations with hp2100_cpu.h
26-Jun-08 JDB Rewrote device I/O to model backplane signals
@ -128,87 +132,18 @@ typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization
#define soOTX 6 /* output from A/B */
#define soCTL 7 /* set/clear control */
/* I/O backplane signals.
The IOSIG declarations mirror the I/O backplane signals. These are sent to
the device I/O signal handlers for action. Normally, only one signal may be
sent at a time. However, the ioCLF signal may be added (arithmetically) to
another signal; the handlers will process the other signal first and then the
CLF signal.
Implementation notes:
1. The first valid signal must have a value > 0, and ioCLF must be
enumerated last, so that adding ioCLF produces a result > ioCLF.
2. The signals are structured so that all those that might change the
interrupt state are enumerated after ioSIR. The handlers will detect
this and add an ioSIR signal automatically.
3. In hardware, the POPIO signal is asserted concurrently with the CRS
signal. Under simulation, ioPOPIO implies ioCRS, so the handlers are
structured to fall from POPIO handling into CRS handling. It is not
necessary to send both signals for a PRESET.
4. In hardware, the SIR signal is generated unconditionally every T5 period
to time the setting of the IRQ flip-flop. Under simulation, ioSIR is
sent to set the PRL, IRQ, and SRQ signals as indicated by the interface
logic. It is necessary to send ioSIR only when that logic indicates a
change in one or more of the three signals.
5. In hardware, the ENF signal is unconditionally generated every T2 period
to time the setting of the flag flip-flop and to reset the IRQ flip-flop.
If the flag buffer flip-flip is set, then flag will be set by ENF. If
the flag buffer is clear, ENF will not affect flag. Under simulation,
ioENF is sent to set the flag buffer and flag flip-flops. For those
interfaces where this action is identical to that provided by STF, the
ioENF handler may simply fall into the ioSTF handler.
6. The ioSKF signal is never sent to an I/O device. Rather, it is returned
from the device if the SFC or SFS condition is true.
7. A device will receive ioNONE when a HLT instruction is executed, and the
H/C bit is clear (i.e., no CLF generated).
*/
typedef enum { CLEAR, SET } FLIP_FLOP; /* flip-flop type and values */
typedef enum { ioNONE, /* no signal asserted */
ioSKF, /* skip on flag */
ioSFC, /* skip if flag is clear */
ioSFS, /* skip if flag is set */
ioIOI, /* I/O data input */
ioIOO, /* I/O data output */
ioEDT, /* end data transfer */
ioSIR, /* set interrupt request */
ioIAK, /* interrupt acknowledge */
ioCRS, /* control reset */
ioPOPIO, /* power-on preset to I/O */
ioCLC, /* clear control flip-flop */
ioSTC, /* set control flip-flop */
ioENF, /* enable flag */
ioSTF, /* set flag flip-flop */
ioCLF } IOSIG; /* clear flag flip-flop */
/* I/O devices - fixed assignments */
/* I/O devices - fixed select code assignments */
#define CPU 000 /* interrupt control */
#define OVF 001 /* overflow */
#define DMALT0 002 /* DMA 0 alternate */
#define DMALT1 003 /* DMA 1 alternate */
#define DMALT1 002 /* DMA 1 alternate */
#define DMALT2 003 /* DMA 2 alternate */
#define PWR 004 /* power fail */
#define PRO 005 /* parity/mem protect */
#define DMA0 006 /* DMA channel 0 */
#define DMA1 007 /* DMA channel 1 */
#define OPTDEV DMALT0 /* start of optional devices */
#define VARDEV (DMA1 + 1) /* start of var assign */
#define M_NXDEV (INT_M (CPU) | INT_M (OVF) | \
INT_M (DMALT0) | INT_M (DMALT1))
#define M_FXDEV (M_NXDEV | INT_M (PWR) | INT_M (PRO) | \
INT_M (DMA0) | INT_M (DMA1))
#define DMA1 006 /* DMA channel 1 */
#define DMA2 007 /* DMA channel 2 */
/* I/O devices - variable assignment defaults */
/* I/O devices - variable select code assignment defaults */
#define PTR 010 /* 12597A-002 paper tape reader */
#define TTY 011 /* 12531C teleprinter */
@ -236,6 +171,11 @@ typedef enum { ioNONE, /* no signal asserted */
#define MUXU 041 /* 12920A upper data */
#define MUXC 042 /* 12920A control */
#define OPTDEV 002 /* start of optional devices */
#define CRSDEV 006 /* start of devices that receive CRS */
#define VARDEV 010 /* start of variable assignments */
#define MAXDEV 077 /* end of select code range */
/* IBL assignments */
#define IBL_V_SEL 14 /* ROM select */
@ -257,41 +197,240 @@ typedef enum { ioNONE, /* no signal asserted */
typedef uint16 BOOT_ROM [IBL_LNT]; /* boot ROM data */
/* Dynamic device information table */
typedef uint32 IODISP (uint32 select_code, IOSIG signal, uint32 data); /* I/O signal dispatch function */
/* I/O backplane signals.
typedef struct {
uint32 devno; /* device select code */
IODISP *iot; /* pointer to I/O signal dispatcher */
} DIB;
The IOSIGNAL declarations mirror the hardware I/O backplane signals. A set
of one or more signals forms an IOCYCLE that is sent to a device IOHANDLER
for action. The CPU and DMA dispatch one signal set to the target device
handler per I/O cycle. A CPU cycle consists of either one or two signals; if
present, the second signal will be CLF. A DMA cycle consists of from two to
five signals. In addition, a front-panel PRESET or power-on reset dispatches
two or three signals, respectively.
/* I/O macros */
In hardware, signals are assigned to one or more specific I/O T-periods, and
some signals are asserted concurrently. For example, a programmed STC sc,C
instruction asserts the STC and CLF signals together in period T4. Under
simulation, signals are ORed to form an I/O cycle; in this example, the
signal handler would receive an IOCYCLE value of "ioSTC | ioCLF".
#define IOBASE(S) ((S) > ioCLF ? (S) - ioCLF : (S)) /* base signal from compound signal */
Hardware allows parallel action for concurrent signals. Under simulation, a
"concurrent" set of signals is processed sequentially by the signal handler
in order of ascending numerical value. Although assigned T-periods differ
between programmed I/O and DMA I/O cycles, a single processing order is used.
The order of execution generally follows the order of T-period assertion,
except that ioSIR is processed after all other signals that may affect the
interrupt request chain.
#define INT_V(x) ((x) & 037) /* device bit position */
#define INT_M(x) (1u << INT_V (x)) /* device bit mask */
Implementation notes:
#define setSKF(B) data = (uint32) ((B) ? ioSKF : ioNONE)
1. The ioCLF signal must be processed after ioSFS/ioSFC to ensure that a
true skip test generates ioSKF before the flag is cleared, and after
ioIOI/ioIOO/ioSTC/ioCLC to meet the requirement that executing an
instruction having the H/C bit set is equivalent to executing the same
instruction with the H/C bit clear and then a CLF instruction.
#define setPRL(S,B) dev_prl[(S)/32] = dev_prl[(S)/32] & ~INT_M (S) | (((B) & 1) << INT_V (S))
#define setIRQ(S,B) dev_irq[(S)/32] = dev_irq[(S)/32] & ~INT_M (S) | (((B) & 1) << INT_V (S))
#define setSRQ(S,B) dev_srq[(S)/32] = dev_srq[(S)/32] & ~INT_M (S) | (((B) & 1) << INT_V (S))
2. The ioSKF signal is never sent to an I/O handler. Rather, it is returned
from the handler if the SFC or SFS condition is true. If the condition
is false, ioNONE is returned instead. As these two values are returned
in the 16-bit data portion of the returned value, their assigned values
must be <= 100000 octal.
#define setstdSKF(N) setSKF ((base_signal == ioSFC) && !N ## _flag || \
(base_signal == ioSFS) && N ## _flag)
3. An I/O handler will receive ioCRS as a result of a CLC 0 instruction,
ioPOPIO and ioCRS as a result of a RESET command, and ioPON, ioPOPIO, and
ioCRS as a result of a RESET -P command.
#define setstdPRL(S,N) setPRL ((S), !(N ## _control & N ## _flag));
#define setstdIRQ(S,N) setIRQ ((S), N ## _control & N ## _flag & N ## _flagbuf);
#define setstdSRQ(S,N) setSRQ ((S), N ## _flag);
4. An I/O handler will receive ioNONE when a HLT instruction is executed
that has the H/C bit clear (i.e., no CLF generated).
#define PRL(S) ((dev_prl[(S)/32] >> INT_V (S)) & 1)
#define IRQ(S) ((dev_irq[(S)/32] >> INT_V (S)) & 1)
#define SRQ(S) ((dev_srq[(S)/32] >> INT_V (S)) & 1)
5. In hardware, the SIR signal is generated unconditionally every T5 period
to time the setting of the IRQ flip-flop. Under simulation, ioSIR
indicates that the I/O handler must set the PRL, IRQ, and SRQ signals as
required by the interface logic. ioSIR must be included in the I/O cycle
if any of the flip-flops affecting these signals are changed and the
interface supports interrupts or DMA transfers.
6. In hardware, the ENF signal is unconditionally generated every T2 period
to time the setting of the flag flip-flop and to reset the IRQ flip-flop.
If the flag buffer flip-flip is set, then flag will be set by ENF. If
the flag buffer is clear, ENF will not affect flag. Under simulation,
ioENF is sent to set the flag buffer and flag flip-flops. For those
interfaces where this action is identical to that provided by STF, the
ioENF handler may simply fall into the ioSTF handler.
7. In hardware, the PON signal is asserted continuously while the CPU is
operating. Under simulation, ioPON is asserted only at simulator
initialization or when processing a RESET -P command.
*/
typedef enum { ioNONE = 0000000, /* -- -- -- -- -- no signal asserted */
ioPON = 0000001, /* T2 T3 T4 T5 T6 power on normal */
ioENF = 0000002, /* T2 -- -- -- -- enable flag */
ioIOI = 0000004, /* -- -- T4 T5 -- I/O data input (CPU)
T2 T3 -- -- -- I/O data input (DMA) */
ioIOO = 0000010, /* -- T3 T4 -- -- I/O data output */
ioSKF = 0000020, /* -- T3 T4 T5 -- skip on flag */
ioSFS = 0000040, /* -- T3 T4 T5 -- skip if flag is set */
ioSFC = 0000100, /* -- T3 T4 T5 -- skip if flag is clear */
ioSTC = 0000200, /* -- -- T4 -- -- set control flip-flop (CPU)
-- T3 -- -- -- set control flip-flop (DMA) */
ioCLC = 0000400, /* -- -- T4 -- -- clear control flip-flop (CPU)
-- T3 T4 -- -- clear control flip-flop (DMA) */
ioSTF = 0001000, /* -- T3 -- -- -- set flag flip-flop */
ioCLF = 0002000, /* -- -- T4 -- -- clear flag flip-flop (CPU)
-- T3 -- -- -- clear flag flip-flop (DMA) */
ioEDT = 0004000, /* -- -- T4 -- -- end data transfer */
ioCRS = 0010000, /* -- -- -- T5 -- control reset */
ioPOPIO = 0020000, /* -- -- -- T5 -- power-on preset to I/O */
ioIAK = 0040000, /* -- -- -- -- T6 interrupt acknowledge */
ioSIR = 0100000 } IOSIGNAL; /* -- -- -- T5 -- set interrupt request */
typedef uint32 IOCYCLE; /* a set of signals forming one I/O cycle */
#define IOIRQSET (ioSTC | ioCLC | ioENF | \
ioSTF | ioCLF | ioIAK | \
ioCRS | ioPOPIO | ioPON) /* signals that may affect interrupt state */
/* I/O structures */
typedef enum { CLEAR, SET } FLIP_FLOP; /* flip-flop type and values */
typedef struct dib DIB; /* incomplete definition */
typedef uint32 IOHANDLER (DIB *dibptr, /* I/O signal handler prototype */
IOCYCLE signal_set,
uint32 stat_data);
struct dib { /* Device information block */
IOHANDLER *io_handler; /* pointer to device's I/O signal handler */
uint32 select_code; /* device's select code */
uint32 card_index; /* device's card index for state variables */
};
/* I/O signal and status macros.
The following macros are useful in I/O signal handlers and unit service
routines. The parameter definition symbols employed are:
I = an IOCYCLE value
E = a t_stat error status value
D = a uint16 data value
C = a uint32 combined status and data value
P = a pointer to a DIB structure
B = a Boolean test value
Implementation notes:
1. The IONEXT macro isolates the next signal in sequence to process from the
I/O cycle I.
2. The IOADDSIR macro adds an ioSIR signal to the I/O cycle I if it
contains signals that might change the interrupt state.
3. The IORETURN macro forms the combined status and data value to be
returned by a handler from the t_stat error code E and the 16-bit data
value D.
4. The IOSTATUS macro isolates the t_stat error code from a combined status
and data value value C.
5. The IODATA macro isolates the 16-bit data value from a combined status
and data value value C.
6. The IOPOWERON macro calls signal handler P->H with DIB pointer P to
process a power-on reset action.
7. The IOPRESET macro calls signal handler P->H with DIB pointer P to
process a front-panel PRESET action.
8. The IOERROR macro returns t_stat error code E from a unit service routine
if the Boolean test B is true.
*/
#define IONEXT(I) (IOSIGNAL) ((I) & (IOCYCLE) (- (int32) (I))) /* extract next I/O signal to handle */
#define IOADDSIR(I) ((I) & IOIRQSET ? (I) | ioSIR : (I)) /* add SIR if IRQ state might change */
#define IORETURN(E,D) ((uint32) ((E) << 16 | (D) & DMASK)) /* form I/O handler return value */
#define IOSTATUS(C) ((t_stat) ((C) >> 16) & DMASK) /* extract I/O status from combined value */
#define IODATA(C) ((uint16) ((C) & DMASK)) /* extract data from combined value */
#define IOPOWERON(P) (P)->io_handler ((P), ioPON | ioPOPIO | ioCRS, 0) /* send power-on signals to handler */
#define IOPRESET(P) (P)->io_handler ((P), ioPOPIO | ioCRS, 0) /* send PRESET signals to handler */
#define IOERROR(B,E) ((B) ? (E) : SCPE_OK) /* stop on I/O error if enabled */
/* I/O signal logic macros.
The following macros implement the logic for the SKF, PRL, IRQ, and SRQ
signals. Both standard and general logic macros are provided. The parameter
definition symbols employed are:
S = a uint32 select code value
B = a Boolean test value
N = a name of a structure containing the standard flip-flops
Implementation notes:
1. The setSKF macro sets the Skip on Flag signal in the return data value if
the Boolean value B is true.
2. The setPRL macro sets the Priority Low signal for select code S to the
Boolean value B.
3. The setIRQ macro sets the Interrupt Request signal for select code S to
the Boolean value B.
4. The setSRQ macro sets the Service Request signal for select code S to the
Boolean value B.
5. The PRL macro returns the Priority Low signal for select code S as a
Boolean value.
6. The IRQ macro returns the Interrupt Request signal for select code S as a
Boolean value.
7. The SRQ macro returns the Service Request signal for select code S as a
Boolean value.
8. The setstdSKF macro sets Skip on Flag signal in the return data value if
the flag state in structure N matches the current skip test condition.
9. The setstdPRL macro sets the Priority Low signal for the select code
referenced by "dibptr" using the standard logic and the control and flag
states in structure N.
10. The setstdIRQ macro sets the Interrupt Request signal for the select code
referenced by "dibptr" using the standard logic and the control, flag,
and flag buffer states in structure N.
11. The setstdSRQ macro sets the Service Request signal for the select code
referenced by "dibptr" using the standard logic and the flag state in
structure N.
*/
#define BIT_V(S) ((S) & 037) /* convert select code to bit position */
#define BIT_M(S) (1u << BIT_V (S)) /* convert select code to bit mask */
#define setSKF(B) stat_data = IORETURN (SCPE_OK, (uint16) ((B) ? ioSKF : ioNONE))
#define setPRL(S,B) dev_prl[(S)/32] = dev_prl[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S))
#define setIRQ(S,B) dev_irq[(S)/32] = dev_irq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S))
#define setSRQ(S,B) dev_srq[(S)/32] = dev_srq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S))
#define PRL(S) ((dev_prl[(S)/32] >> BIT_V (S)) & 1)
#define IRQ(S) ((dev_irq[(S)/32] >> BIT_V (S)) & 1)
#define SRQ(S) ((dev_srq[(S)/32] >> BIT_V (S)) & 1)
#define setstdSKF(N) setSKF ((signal == ioSFC) && !N.flag || \
(signal == ioSFS) && N.flag)
#define setstdPRL(N) setPRL (dibptr->select_code, !(N.control & N.flag));
#define setstdIRQ(N) setIRQ (dibptr->select_code, N.control & N.flag & N.flagbuf);
#define setstdSRQ(N) setSRQ (dibptr->select_code, N.flag);
#define IOT_V_REASON 16
#define IORETURN(F,V) ((F) ? (V) : SCPE_OK) /* stop on I/O error */
/* CPU state */

View file

@ -1,6 +1,6 @@
/* hp2100_dp.c: HP 2100 12557A/13210A disk simulator
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,8 @@
DP 12557A 2871 disk subsystem
13210A 7900 disk subsystem
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size
26-Jun-08 JDB Rewrote device I/O to model backplane signals
28-Dec-06 JDB Added ioCRS state to I/O decoders
@ -206,10 +208,12 @@
#define STA_UNLOADED (dp_ctype ? (STA_NRDY | STA_BSY) : STA_NRDY)
#define STA_MBZ13 (STA_ATN | STA_RWU | STA_SKI) /* zero in 13210 */
FLIP_FLOP dpc_command = CLEAR; /* cch command flip-flop */
FLIP_FLOP dpc_control = CLEAR; /* cch control flip-flop */
FLIP_FLOP dpc_flag = CLEAR; /* cch flag flip-flop */
FLIP_FLOP dpc_flagbuf = CLEAR; /* cch flag buffer flip-flop */
struct {
FLIP_FLOP command; /* cch command flip-flop */
FLIP_FLOP control; /* cch control flip-flop */
FLIP_FLOP flag; /* cch flag flip-flop */
FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */
} dpc = { CLEAR, CLEAR, CLEAR, CLEAR };
enum { A12557, A13210 } dp_ctype = A13210; /* ctrl type */
int32 dpc_busy = 0; /* cch unit */
@ -223,10 +227,12 @@ int32 dpc_dtime = 2; /* dch time */
int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */
int32 dpc_obuf = 0; /* cch buffers */
FLIP_FLOP dpd_command = CLEAR; /* dch command flip-flop */
FLIP_FLOP dpd_control = CLEAR; /* dch control flip-flop */
FLIP_FLOP dpd_flag = CLEAR; /* dch flag flip-flop */
FLIP_FLOP dpd_flagbuf = CLEAR; /* dch flag buffer flip-flop */
struct {
FLIP_FLOP command; /* dch command flip-flop */
FLIP_FLOP control; /* dch control flip-flop */
FLIP_FLOP flag; /* dch flag flip-flop */
FLIP_FLOP flagbuf; /* dch flag buffer flip-flop */
} dpd = { CLEAR, CLEAR, CLEAR, CLEAR };
int32 dpd_xfer = 0; /* xfer in prog */
int32 dpd_wval = 0; /* write data valid */
@ -239,8 +245,10 @@ uint16 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */
uint16 dpxb[DP_NUMWD]; /* sector buffer */
DEVICE dpd_dev, dpc_dev;
uint32 dpdio (uint32 select_code, IOSIG signal, uint32 data);
uint32 dpcio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER dpdio;
IOHANDLER dpcio;
t_stat dpc_svc (UNIT *uptr);
t_stat dpd_svc (UNIT *uptr);
t_stat dpc_reset (DEVICE *dptr);
@ -261,8 +269,8 @@ t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
*/
DIB dp_dib[] = {
{ DPD, &dpdio },
{ DPC, &dpcio }
{ &dpdio, DPD },
{ &dpcio, DPC }
};
#define dpd_dib dp_dib[0]
@ -275,13 +283,13 @@ REG dpd_reg[] = {
{ ORDATA (OBUF, dpd_obuf, 16) },
{ BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) },
{ DRDATA (BPTR, dp_ptr, DP_N_NUMWD) },
{ FLDATA (CMD, dpd_command, 0) },
{ FLDATA (CTL, dpd_control, 0) },
{ FLDATA (FLG, dpd_flag, 0) },
{ FLDATA (FBF, dpd_flagbuf, 0) },
{ FLDATA (CMD, dpd.command, 0) },
{ FLDATA (CTL, dpd.control, 0) },
{ FLDATA (FLG, dpd.flag, 0) },
{ FLDATA (FBF, dpd.flagbuf, 0) },
{ FLDATA (XFER, dpd_xfer, 0) },
{ FLDATA (WVAL, dpd_wval, 0) },
{ ORDATA (DEVNO, dpd_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, dpd_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -322,10 +330,10 @@ REG dpc_reg[] = {
{ ORDATA (OBUF, dpc_obuf, 16) },
{ ORDATA (BUSY, dpc_busy, 4), REG_RO },
{ ORDATA (CNT, dpc_cnt, 5) },
{ FLDATA (CMD, dpc_command, 0) },
{ FLDATA (CTL, dpc_control, 0) },
{ FLDATA (FLG, dpc_flag, 0) },
{ FLDATA (FBF, dpc_flagbuf, 0) },
{ FLDATA (CMD, dpc.command, 0) },
{ FLDATA (CTL, dpc.control, 0) },
{ FLDATA (FLG, dpc.flag, 0) },
{ FLDATA (FBF, dpc.flagbuf, 0) },
{ FLDATA (EOC, dpc_eoc, 0) },
{ FLDATA (POLL, dpc_poll, 0) },
{ DRDATA (RARC, dpc_rarc, 8), PV_RZRO | REG_FIT },
@ -342,7 +350,7 @@ REG dpc_reg[] = {
DP_NUMDRV, REG_HRO) },
{ URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0,
DP_NUMDRV, PV_LEFT | REG_HRO) },
{ ORDATA (DEVNO, dpc_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, dpc_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -389,112 +397,114 @@ DEVICE dpc_dev = {
register.
*/
uint32 dpdio (uint32 select_code, IOSIG signal, uint32 data)
uint32 dpdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
dpd_flag = dpd_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
dpd.flag = dpd.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
dpd_flag = dpd_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
dpd.flag = dpd.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (dpd);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (dpd);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (dpd);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (dpd);
break;
case ioIOI: /* I/O data input */
data = dpd_ibuf;
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, dpd_ibuf); /* merge in return status */
break;
case ioIOO: /* I/O data output */
dpd_obuf = data;
case ioIOO: /* I/O data output */
dpd_obuf = IODATA (stat_data); /* clear supplied status */
if (!dpc_busy || dpd_xfer) /* if !overrun */
dpd_wval = 1; /* valid */
break;
if (!dpc_busy || dpd_xfer) /* if !overrun */
dpd_wval = 1; /* valid */
break;
case ioPOPIO: /* power-on preset to I/O */
dpd_flag = dpd_flagbuf = SET; /* set flag buffer and flag */
case ioPOPIO: /* power-on preset to I/O */
dpd.flag = dpd.flagbuf = SET; /* set flag buffer and flag */
if (dp_ctype == A12557) /* 12557? */
dpd_obuf = 0; /* clear output buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
dpd_command = CLEAR; /* clear command */
if (dp_ctype == A12557) /* 12557? */
dpd_control = CLEAR; /* clear control */
else { /* 13210 */
dpc_rarc = 0; /* clear controller cylinder address */
dpc_ucyl [CW_GETDRV (dpc_obuf)] = 0; /* clear last drive addressed cylinder */
}
break;
if (dp_ctype == A12557) /* 12557? */
dpd_obuf = 0; /* clear output buffer */
break;
case ioCLC: /* clear control flip-flop */
if (dp_ctype == A12557) /* 12557? */
dpd_control = CLEAR; /* clear control */
case ioCRS: /* control reset */
dpd.command = CLEAR; /* clear command */
dpd_xfer = 0; /* clr xfer in progress */
break;
if (dp_ctype == A12557) /* 12557? */
dpd.control = CLEAR; /* clear control */
else { /* 13210 */
dpc_rarc = 0; /* clear controller cylinder address */
dpc_ucyl [CW_GETDRV (dpc_obuf)] = 0; /* clear last drive addressed cylinder */
}
break;
case ioSTC: /* set control flip-flop */
if (dp_ctype == A12557) /* 12557? */
dpd_control = SET; /* set control */
case ioCLC: /* clear control flip-flop */
if (dp_ctype == A12557) /* 12557? */
dpd.control = CLEAR; /* clear control */
dpd_command = SET; /* set cmd */
if (dpc_busy && !dpd_xfer) /* overrun? */
dpc_sta[dpc_busy - 1] |= STA_OVR;
break;
dpd_xfer = 0; /* clr xfer in progress */
break;
case ioSIR: /* set interrupt request */
if (dp_ctype == A12557) { /* 12557? */
setstdPRL (select_code, dpd); /* set standard PRL signal */
setstdIRQ (select_code, dpd); /* set standard IRQ signal */
}
case ioSTC: /* set control flip-flop */
if (dp_ctype == A12557) /* 12557? */
dpd.control = SET; /* set control */
setstdSRQ (select_code, dpd); /* set standard SRQ signal */
break;
dpd.command = SET; /* set cmd */
if (dpc_busy && !dpd_xfer) /* overrun? */
dpc_sta[dpc_busy - 1] |= STA_OVR;
break;
case ioIAK: /* interrupt acknowledge */
if (dp_ctype == A12557) /* 12557? */
dpd_flagbuf = CLEAR; /* clear flag buffer */
break;
case ioSIR: /* set interrupt request */
if (dp_ctype == A12557) { /* 12557? */
setstdPRL (dpd); /* set standard PRL signal */
setstdIRQ (dpd); /* set standard IRQ signal */
}
setstdSRQ (dpd); /* set standard SRQ signal */
break;
default: /* all other signals */
break; /* are ignored */
case ioIAK: /* interrupt acknowledge */
if (dp_ctype == A12557) /* 12557? */
dpd.flagbuf = CLEAR; /* clear flag buffer */
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
dpdio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
dpdio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -515,139 +525,144 @@ return data;
to interrupt.
*/
uint32 dpcio (uint32 select_code, IOSIG signal, uint32 data)
uint32 dpcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
uint16 data;
int32 i, fnc, drv;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
dpc_flag = dpc_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
dpc.flag = dpc.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
dpc_flag = dpc_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
dpc.flag = dpc.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (dpc);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (dpc);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (dpc);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (dpc);
break;
case ioIOI: /* I/O data input */
data = 0;
case ioIOI: /* I/O data input */
data = 0;
for (i = 0; i < DP_NUMDRV; i++) /* form attention register value */
if (dpc_sta[i] & STA_ATN) data = data | (1 << i);
break;
for (i = 0; i < DP_NUMDRV; i++) /* form attention register value */
if (dpc_sta[i] & STA_ATN) data = data | (1 << i);
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
break;
case ioIOO: /* I/O data output */
dpc_obuf = data;
case ioIOO: /* I/O data output */
dpc_obuf = IODATA (stat_data); /* clear supplied status */
if (dp_ctype == A13210) /* 13210? */
dpcio (select_code, ioCLC, 0); /* OTx causes CLC */
break;
if (dp_ctype == A13210) /* 13210? */
dpcio (dibptr, ioCLC, 0); /* OTx causes CLC */
break;
case ioPOPIO: /* power-on preset to I/O */
dpc_flag = dpc_flagbuf = SET; /* set flag buffer and flag */
case ioPOPIO: /* power-on preset to I/O */
dpc.flag = dpc.flagbuf = SET; /* set flag buffer and flag */
if (dp_ctype == A12557) /* 12557? */
dpd_obuf = 0; /* clear output buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
dpc_control = CLEAR; /* clear control */
if (dp_ctype == A12557) /* 12557? */
dpc_command = CLEAR; /* clear command */
break;
case ioCLC: /* clear control flip-flop */
dpc_control = CLEAR; /* clr ctl */
if (dp_ctype == A12557) /* 12557? */
dpc_command = CLEAR; /* cancel non-seek */
if (dpc_busy)
sim_cancel (&dpc_unit[dpc_busy - 1]);
sim_cancel (&dpd_unit); /* cancel dch */
dpd_xfer = 0; /* clr dch xfer */
dpc_busy = 0; /* clr cch busy */
dpc_poll = 0; /* clr cch poll */
break;
case ioSTC: /* set control flip-flop */
dpc_control = SET; /* set ctl */
if ((dp_ctype == A13210) || !dpc_command) { /* 13210 or command is clear? */
if (dp_ctype == A12557) /* 12557? */
dpc_command = SET; /* set command */
drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */
fnc = CW_GETFNC (dpc_obuf); /* from cmd word */
switch (fnc) { /* case on fnc */
case FNC_SEEK: /* seek */
dpc_poll = 1; /* enable polling */
dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */
break;
case FNC_STA: /* rd sta */
if (dp_ctype == A13210) /* 13210? clr dch flag */
dpdio (dpd_dib.devno, ioCLF, 0);
case FNC_CHK: /* check */
case FNC_AR: /* addr rec */
dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */
break;
case FNC_RD: case FNC_WD: /* read, write */
case FNC_REF: case FNC_INIT: /* refine, init */
dp_goc (fnc, drv, dpc_ctime); /* sched drive */
break;
} /* end case */
} /* end if */
break;
dpd_obuf = 0; /* clear output buffer */
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, dpc); /* set standard PRL signal */
setstdIRQ (select_code, dpc); /* set standard IRQ signal */
setstdSRQ (select_code, dpc); /* set standard SRQ signal */
break;
case ioCRS: /* control reset */
dpc.control = CLEAR; /* clear control */
if (dp_ctype == A12557) /* 12557? */
dpc.command = CLEAR; /* clear command */
break;
case ioIAK: /* interrupt acknowledge */
dpc_flagbuf = CLEAR; /* clear flag buffer */
break;
case ioCLC: /* clear control flip-flop */
dpc.control = CLEAR; /* clr ctl */
if (dp_ctype == A12557) /* 12557? */
dpc.command = CLEAR; /* cancel non-seek */
if (dpc_busy)
sim_cancel (&dpc_unit[dpc_busy - 1]);
sim_cancel (&dpd_unit); /* cancel dch */
dpd_xfer = 0; /* clr dch xfer */
dpc_busy = 0; /* clr cch busy */
dpc_poll = 0; /* clr cch poll */
break;
default: /* all other signals */
break; /* are ignored */
case ioSTC: /* set control flip-flop */
dpc.control = SET; /* set ctl */
if ((dp_ctype == A13210) || !dpc.command) { /* 13210 or command is clear? */
if (dp_ctype == A12557) /* 12557? */
dpc.command = SET; /* set command */
drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */
fnc = CW_GETFNC (dpc_obuf); /* from cmd word */
switch (fnc) { /* case on fnc */
case FNC_SEEK: /* seek */
dpc_poll = 1; /* enable polling */
dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */
break;
case FNC_STA: /* rd sta */
if (dp_ctype == A13210) /* 13210? clr dch flag */
dpdio (&dpd_dib, ioCLF, 0);
case FNC_CHK: /* check */
case FNC_AR: /* addr rec */
dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */
break;
case FNC_RD: case FNC_WD: /* read, write */
case FNC_REF: case FNC_INIT: /* refine, init */
dp_goc (fnc, drv, dpc_ctime); /* sched drive */
break;
} /* end case */
} /* end if */
break;
case ioSIR: /* set interrupt request */
setstdPRL (dpc); /* set standard PRL signal */
setstdIRQ (dpc); /* set standard IRQ signal */
setstdSRQ (dpc); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
dpc.flagbuf = CLEAR; /* clear flag buffer */
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
dpcio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
dpcio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -712,12 +727,12 @@ switch (uptr->FNC) { /* case function */
case FNC_AR: /* arec, need cyl */
case FNC_SEEK: /* seek, need cyl */
if (dpd_command) { /* dch active? */
if (dpd.command) { /* dch active? */
dpc_rarc = DA_GETCYL (dpd_obuf); /* set RAR from cyl word */
dpd_wval = 0; /* clr data valid */
dpd_command = CLEAR; /* clr dch cmd */
dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */
dpd.command = CLEAR; /* clr dch cmd */
dpdio (&dpd_dib, ioENF, 0); /* set dch flg */
if (uptr->FNC == FNC_AR) uptr->FNC = FNC_AR1;
else uptr->FNC = FNC_SEEK1; /* advance state */
@ -727,17 +742,17 @@ switch (uptr->FNC) { /* case function */
case FNC_AR1: /* arec, need hd/sec */
case FNC_SEEK1: /* seek, need hd/sec */
if (dpd_command) { /* dch active? */
if (dpd.command) { /* dch active? */
dpc_rarh = DA_GETHD (dpd_obuf); /* set RAR from head */
dpc_rars = DA_GETSC (dpd_obuf); /* set RAR from sector */
dpd_wval = 0; /* clr data valid */
dpd_command = CLEAR; /* clr dch cmd */
dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */
dpd.command = CLEAR; /* clr dch cmd */
dpdio (&dpd_dib, ioENF, 0); /* set dch flg */
if (uptr->FNC == FNC_AR1) {
dpc_command = CLEAR; /* clr cch cmd */
dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */
dpc.command = CLEAR; /* clr cch cmd */
dpcio (&dpc_dib, ioENF, 0); /* set cch flg */
dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set drv attn */
break; /* done if Address Record */
@ -766,7 +781,7 @@ switch (uptr->FNC) { /* case function */
break;
case FNC_STA: /* read status */
if (dpd_command || (dp_ctype == A13210)) { /* dch act or 13210? */
if (dpd.command || (dp_ctype == A13210)) { /* dch act or 13210? */
if ((dpc_unit[drv].flags & UNIT_UNLOAD) == 0) { /* drive up? */
dpd_ibuf = dpc_sta[drv] & ~STA_ERR; /* clear err */
if (dp_ctype == A13210) dpd_ibuf = /* 13210? */
@ -777,9 +792,9 @@ switch (uptr->FNC) { /* case function */
if (dpd_ibuf & STA_ANYERR) /* errors? set flg */
dpd_ibuf = dpd_ibuf | STA_ERR;
dpc_command = CLEAR; /* clr cch cmd */
dpd_command = CLEAR; /* clr dch cmd */
dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */
dpc.command = CLEAR; /* clr cch cmd */
dpd.command = CLEAR; /* clr dch cmd */
dpdio (&dpd_dib, ioENF, 0); /* set dch flg */
}
dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */
@ -789,14 +804,14 @@ switch (uptr->FNC) { /* case function */
dpc_poll = 1; /* enable polling */
for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */
if (dpc_sta[i] & STA_ATN) { /* any ATN set? */
dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */
dpcio (&dpc_dib, ioENF, 0); /* set cch flg */
break;
}
}
break;
case FNC_CHK: /* check, need cnt */
if (dpd_command) { /* dch active? */
if (dpd.command) { /* dch active? */
dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */
dpd_wval = 0; /* clr data valid */
dp_goc (FNC_CHK1, drv, dpc_xtime); /* sched drv */
@ -836,8 +851,8 @@ err = 0; /* assume no err */
drv = uptr - dpc_dev.units; /* get drive no */
if (uptr->flags & UNIT_UNLOAD) { /* drive down? */
dpc_command = CLEAR; /* clr cch cmd */
dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */
dpc.command = CLEAR; /* clr cch cmd */
dpcio (&dpc_dib, ioENF, 0); /* set cch flg */
dpc_sta[drv] = 0; /* clr status */
dpc_busy = 0; /* ctlr is free */
@ -852,8 +867,8 @@ switch (uptr->FNC) { /* case function */
dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; /* fall into cmpl */
case FNC_SEEK3: /* seek complete */
if (dpc_poll) { /* polling enabled? */
dpc_command = CLEAR; /* clr cch cmd */
dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */
dpc.command = CLEAR; /* clr cch cmd */
dpcio (&dpc_dib, ioENF, 0); /* set cch flg */
}
return SCPE_OK;
@ -863,7 +878,7 @@ switch (uptr->FNC) { /* case function */
case FNC_RD: /* read */
case FNC_CHK1: /* check */
if (dp_ptr == 0) { /* new sector? */
if (!dpd_command && (uptr->FNC != FNC_CHK1)) break;
if (!dpd.command && (uptr->FNC != FNC_CHK1)) break;
if (dpc_rarc != dpc_ucyl[drv]) /* RAR cyl miscompare? */
dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, read */
if (dpc_rars >= DP_NUMSC) { /* bad sector? */
@ -893,17 +908,17 @@ switch (uptr->FNC) { /* case function */
}
dp_ptr = 0; /* wrap buf ptr */
}
if (dpd_command && dpd_xfer) /* dch on, xfer? */
dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */
if (dpd.command && dpd_xfer) /* dch on, xfer? */
dpdio (&dpd_dib, ioENF, 0); /* set dch flg */
dpd_command = CLEAR; /* clr dch cmd */
dpd.command = CLEAR; /* clr dch cmd */
sim_activate (uptr, dpc_xtime); /* sched next word */
return SCPE_OK;
case FNC_INIT: /* init */
case FNC_WD: /* write */
if (dp_ptr == 0) { /* start sector? */
if (!dpd_command && !dpd_wval) break; /* xfer done? */
if (!dpd.command && !dpd_wval) break; /* xfer done? */
if (uptr->flags & UNIT_WPRT) { /* wr prot? */
dpc_sta[drv] = dpc_sta[drv] | STA_FLG; /* set status */
break; /* done */
@ -933,10 +948,10 @@ switch (uptr->FNC) { /* case function */
if (err = ferror (uptr->fileref)) break; /* error? */
dp_ptr = 0; /* next sector */
}
if (dpd_command && dpd_xfer) /* dch on, xfer? */
dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */
if (dpd.command && dpd_xfer) /* dch on, xfer? */
dpdio (&dpd_dib, ioENF, 0); /* set dch flg */
dpd_command = CLEAR; /* clr dch cmd */
dpd.command = CLEAR; /* clr dch cmd */
sim_activate (uptr, dpc_xtime); /* sched next word */
return SCPE_OK;
@ -946,8 +961,8 @@ switch (uptr->FNC) { /* case function */
dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set ATN */
dpc_command = CLEAR; /* clr cch cmd */
dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */
dpc.command = CLEAR; /* clr cch cmd */
dpcio (&dpc_dib, ioENF, 0); /* set cch flg */
dpc_busy = 0; /* ctlr is free */
dpd_xfer = dpd_wval = 0;
@ -966,21 +981,18 @@ return SCPE_OK;
t_stat dpc_reset (DEVICE *dptr)
{
int32 drv;
DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */
hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &dpd_dev)? &dpc_dev: &dpd_dev);
(dptr == &dpd_dev) ? &dpc_dev : &dpd_dev);
if (sim_switches & SWMASK ('P')) { /* PON reset? */
dpd_ibuf = 0; /* clear buffers */
dpd_obuf = 0;
dpc_obuf = 0;
if (sim_switches & SWMASK ('P')) { /* initialization reset? */
dpd_ibuf = dpd_obuf = 0; /* clear buffers */
dpc_obuf = 0; /* clear buffer */
dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear RAR */
}
if (dptr == &dpc_dev) /* command channel reset? */
dpcio (dpc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */
else /* data channel reset */
dpdio (dpd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */
IOPRESET (dibptr); /* PRESET device (does not use PON) */
dpc_busy = 0; /* reset controller state */
dpc_poll = 0;
@ -1040,7 +1052,7 @@ else { /* load heads */
drv = uptr - dpc_dev.units; /* get drive no */
dpc_sta[drv] = dpc_sta[drv] | STA_ATN | STA_1ST; /* update status */
if (dpc_poll) /* polling enabled? */
dpcio (dpc_dib.devno, ioENF, 0); /* set flag */
dpcio (&dpc_dib, ioENF, 0); /* set flag */
}
return SCPE_OK;
}
@ -1144,7 +1156,7 @@ t_stat dpc_boot (int32 unitno, DEVICE *dptr)
int32 dev;
if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */
dev = dpd_dib.devno; /* get data chan dev */
dev = dpd_dib.select_code; /* get data chan dev */
if (ibl_copy (dp_rom, dev)) return SCPE_IERR; /* copy boot to memory */
SR = (SR & IBL_OPT) | IBL_DP | (dev << IBL_V_DEV); /* set SR */
if (sim_switches & SWMASK ('R')) SR = SR | IBL_DP_REM; /* boot from removable? */

View file

@ -1,7 +1,7 @@
/* hp2100_dq.c: HP 2100 12565A disk simulator
Copyright (c) 1993-2006, Bill McDermith
Copyright (c) 2004-2008 J. David Bryan
Copyright (c) 2004-2011 J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,8 @@
DQ 12565A 2883 disk system
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size
26-Jun-08 JDB Rewrote device I/O to model backplane signals
28-Dec-06 JDB Added ioCRS state to I/O decoders
@ -144,10 +146,12 @@
#define STA_ERR 0000001 /* any error */
#define STA_ANYERR (STA_NRDY | STA_EOC | STA_AER | STA_FLG | STA_DTE)
FLIP_FLOP dqc_command = CLEAR; /* cch command flip-flop */
FLIP_FLOP dqc_control = CLEAR; /* cch control flip-flop */
FLIP_FLOP dqc_flag = CLEAR; /* cch flag flip-flop */
FLIP_FLOP dqc_flagbuf = CLEAR; /* cch flag buffer flip-flop */
struct {
FLIP_FLOP command; /* cch command flip-flop */
FLIP_FLOP control; /* cch control flip-flop */
FLIP_FLOP flag; /* cch flag flip-flop */
FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */
} dqc = { CLEAR, CLEAR, CLEAR, CLEAR };
int32 dqc_busy = 0; /* cch xfer */
int32 dqc_cnt = 0; /* check count */
@ -156,10 +160,12 @@ int32 dqc_ctime = 100; /* command time */
int32 dqc_xtime = 3; /* xfer time */
int32 dqc_dtime = 2; /* dch time */
FLIP_FLOP dqd_command = CLEAR; /* dch command flip-flop */
FLIP_FLOP dqd_control = CLEAR; /* dch control flip-flop */
FLIP_FLOP dqd_flag = CLEAR; /* dch flag flip-flop */
FLIP_FLOP dqd_flagbuf = CLEAR; /* dch flag buffer flip-flop */
struct {
FLIP_FLOP command; /* dch command flip-flop */
FLIP_FLOP control; /* dch control flip-flop */
FLIP_FLOP flag; /* dch flag flip-flop */
FLIP_FLOP flagbuf; /* dch flag buffer flip-flop */
} dqd = { CLEAR, CLEAR, CLEAR, CLEAR };
int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */
int32 dqc_obuf = 0; /* cch buffers */
@ -175,8 +181,10 @@ uint16 dqc_sta[DQ_NUMDRV] = { 0 }; /* unit status */
uint16 dqxb[DQ_NUMWD]; /* sector buffer */
DEVICE dqd_dev, dqc_dev;
uint32 dqdio (uint32 select_code, IOSIG signal, uint32 data);
uint32 dqcio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER dqdio;
IOHANDLER dqcio;
t_stat dqc_svc (UNIT *uptr);
t_stat dqd_svc (UNIT *uptr);
t_stat dqc_reset (DEVICE *dptr);
@ -195,8 +203,8 @@ void dq_goc (int32 fnc, int32 drv, int32 time);
*/
DIB dq_dib[] = {
{ DQD, &dqdio },
{ DQC, &dqcio }
{ &dqdio, DQD },
{ &dqcio, DQC }
};
#define dqd_dib dq_dib[0]
@ -209,13 +217,13 @@ REG dqd_reg[] = {
{ ORDATA (OBUF, dqd_obuf, 16) },
{ BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) },
{ DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) },
{ FLDATA (CMD, dqd_command, 0) },
{ FLDATA (CTL, dqd_control, 0) },
{ FLDATA (FLG, dqd_flag, 0) },
{ FLDATA (FBF, dqd_flagbuf, 0) },
{ FLDATA (CMD, dqd.command, 0) },
{ FLDATA (CTL, dqd.control, 0) },
{ FLDATA (FLG, dqd.flag, 0) },
{ FLDATA (FBF, dqd.flagbuf, 0) },
{ FLDATA (XFER, dqd_xfer, 0) },
{ FLDATA (WVAL, dqd_wval, 0) },
{ ORDATA (DEVNO, dqd_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, dqd_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -252,10 +260,10 @@ REG dqc_reg[] = {
{ ORDATA (OBUF, dqc_obuf, 16) },
{ ORDATA (BUSY, dqc_busy, 2), REG_RO },
{ ORDATA (CNT, dqc_cnt, 9) },
{ FLDATA (CMD, dqc_command, 0) },
{ FLDATA (CTL, dqc_control, 0) },
{ FLDATA (FLG, dqc_flag, 0) },
{ FLDATA (FBF, dqc_flagbuf, 0) },
{ FLDATA (CMD, dqc.command, 0) },
{ FLDATA (CTL, dqc.control, 0) },
{ FLDATA (FLG, dqc.flag, 0) },
{ FLDATA (FBF, dqc.flagbuf, 0) },
{ DRDATA (RARC, dqc_rarc, 8), PV_RZRO | REG_FIT },
{ DRDATA (RARH, dqc_rarh, 5), PV_RZRO | REG_FIT },
{ DRDATA (RARS, dqc_rars, 5), PV_RZRO | REG_FIT },
@ -268,7 +276,7 @@ REG dqc_reg[] = {
{ DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT },
{ URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0,
DQ_NUMDRV, REG_HRO) },
{ ORDATA (DEVNO, dqc_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, dqc_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -293,93 +301,95 @@ DEVICE dqc_dev = {
/* Data channel I/O signal handler */
uint32 dqdio (uint32 select_code, IOSIG signal, uint32 data)
uint32 dqdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
dqd_flag = dqd_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
dqd.flag = dqd.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
dqd_flag = dqd_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
dqd.flag = dqd.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (dqd);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (dqd);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (dqd);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (dqd);
break;
case ioIOI: /* I/O data input */
data = dqd_ibuf;
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, dqd_ibuf); /* merge in return status */
break;
case ioIOO: /* I/O data output */
dqd_obuf = data;
case ioIOO: /* I/O data output */
dqd_obuf = IODATA (stat_data); /* clear supplied status */
if (!dqc_busy || dqd_xfer)
dqd_wval = 1; /* if !overrun, valid */
break;
if (!dqc_busy || dqd_xfer)
dqd_wval = 1; /* if !overrun, valid */
break;
case ioPOPIO: /* power-on preset to I/O */
dqd_flag = dqd_flagbuf = SET; /* set flag and flag buffer */
dqd_obuf = 0; /* clear output buffer */
/* fall into CRS handler */
case ioPOPIO: /* power-on preset to I/O */
dqd.flag = dqd.flagbuf = SET; /* set flag and flag buffer */
dqd_obuf = 0; /* clear output buffer */
break;
case ioCRS: /* control reset */
dqd_command = CLEAR; /* clear command */
case ioCRS: /* control reset */
dqd.command = CLEAR; /* clear command */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
dqd_control = CLEAR; /* clear control */
dqd_xfer = 0; /* clr xfer */
break;
case ioCLC: /* clear control flip-flop */
dqd.control = CLEAR; /* clear control */
dqd_xfer = 0; /* clr xfer */
break;
case ioSTC: /* set control flip-flop */
dqd_command = SET; /* set ctl, cmd */
dqd_control = SET;
case ioSTC: /* set control flip-flop */
dqd.command = SET; /* set ctl, cmd */
dqd.control = SET;
if (dqc_busy && !dqd_xfer) /* overrun? */
dqc_sta[dqc_busy - 1] |= STA_DTE;
break;
if (dqc_busy && !dqd_xfer) /* overrun? */
dqc_sta[dqc_busy - 1] |= STA_DTE;
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, dqd); /* set standard PRL signal */
setstdIRQ (select_code, dqd); /* set standard IRQ signal */
setstdSRQ (select_code, dqd); /* set standard SRQ signal */
break;
case ioSIR: /* set interrupt request */
setstdPRL (dqd); /* set standard PRL signal */
setstdIRQ (dqd); /* set standard IRQ signal */
setstdSRQ (dqd); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
dqd_flagbuf = CLEAR;
break;
case ioIAK: /* interrupt acknowledge */
dqd.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
dqdio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
dqdio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -392,113 +402,112 @@ return data;
signalled.
*/
uint32 dqcio (uint32 select_code, IOSIG signal, uint32 data)
uint32 dqcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
int32 fnc, drv;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
dqc_flag = dqc_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
dqc.flag = dqc.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
dqc_flag = dqc_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
dqc.flag = dqc.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (dqc);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (dqc);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (dqc);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (dqc);
break;
case ioIOI: /* I/O data input */
data = 0; /* no data */
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, 0); /* no data */
break;
case ioIOO: /* I/O data output */
dqc_obuf = data;
break;
case ioIOO: /* I/O data output */
dqc_obuf = IODATA (stat_data); /* clear supplied status */
break;
case ioPOPIO: /* power-on preset to I/O */
dqc_flag = dqc_flagbuf = SET; /* set flag and flag buffer */
dqc_obuf = 0; /* clear output buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
dqc_command = CLEAR; /* clear command */
dqc_control = CLEAR; /* clear control */
if (dqc_busy)
sim_cancel (&dqc_unit[dqc_busy - 1]);
sim_cancel (&dqd_unit); /* cancel dch */
dqd_xfer = 0; /* clr dch xfer */
dqc_busy = 0; /* clr busy */
break;
case ioPOPIO: /* power-on preset to I/O */
dqc.flag = dqc.flagbuf = SET; /* set flag and flag buffer */
dqc_obuf = 0; /* clear output buffer */
break;
case ioSTC: /* set control flip-flop */
dqc_control = SET; /* set ctl */
case ioCRS: /* control reset */
case ioCLC: /* clear control flip-flop */
dqc.command = CLEAR; /* clear command */
dqc.control = CLEAR; /* clear control */
if (!dqc_command) { /* cmd clr? */
dqc_command = SET; /* set cmd */
drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */
fnc = CW_GETFNC (dqc_obuf); /* from cmd word */
if (dqc_busy)
sim_cancel (&dqc_unit[dqc_busy - 1]);
switch (fnc) { /* case on fnc */
case FNC_SEEK: case FNC_RCL: /* seek, recal */
case FNC_CHK: /* check */
dqc_sta[drv] = 0; /* clear status */
case FNC_STA: case FNC_LA: /* rd sta, load addr */
dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */
break;
case FNC_RD: case FNC_WD: /* read, write */
case FNC_RA: case FNC_WA: /* rd addr, wr addr */
case FNC_AS: /* address skip */
dq_goc (fnc, drv, dqc_ctime); /* sched drive */
break;
} /* end case */
} /* end if !CMD */
break;
sim_cancel (&dqd_unit); /* cancel dch */
dqd_xfer = 0; /* clr dch xfer */
dqc_busy = 0; /* clr busy */
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, dqc); /* set standard PRL signal */
setstdIRQ (select_code, dqc); /* set standard IRQ signal */
setstdSRQ (select_code, dqc); /* set standard SRQ signal */
break;
case ioSTC: /* set control flip-flop */
dqc.control = SET; /* set ctl */
if (!dqc.command) { /* cmd clr? */
dqc.command = SET; /* set cmd */
drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */
fnc = CW_GETFNC (dqc_obuf); /* from cmd word */
switch (fnc) { /* case on fnc */
case FNC_SEEK: case FNC_RCL: /* seek, recal */
case FNC_CHK: /* check */
dqc_sta[drv] = 0; /* clear status */
case FNC_STA: case FNC_LA: /* rd sta, load addr */
dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */
break;
case FNC_RD: case FNC_WD: /* read, write */
case FNC_RA: case FNC_WA: /* rd addr, wr addr */
case FNC_AS: /* address skip */
dq_goc (fnc, drv, dqc_ctime); /* sched drive */
break;
} /* end case */
} /* end if !CMD */
break;
case ioIAK: /* interrupt acknowledge */
dqc_flagbuf = CLEAR;
break;
case ioSIR: /* set interrupt request */
setstdPRL (dqc); /* set standard PRL signal */
setstdIRQ (dqc); /* set standard IRQ signal */
setstdSRQ (dqc); /* set standard SRQ signal */
break;
default: /* all other signals */
break; /* are ignored */
case ioIAK: /* interrupt acknowledge */
dqc.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
dqcio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
dqcio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -562,11 +571,11 @@ switch (uptr->FNC) { /* case function */
case FNC_LA: /* arec, need cyl */
case FNC_SEEK: /* seek, need cyl */
if (dqd_command) { /* dch active? */
if (dqd.command) { /* dch active? */
dqc_rarc = DA_GETCYL (dqd_obuf); /* set RAR from cyl word */
dqd_wval = 0; /* clr data valid */
dqd_command = CLEAR; /* clr dch cmd */
dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */
dqd.command = CLEAR; /* clr dch cmd */
dqdio (&dqd_dib, ioENF, 0); /* set dch flg */
if (uptr->FNC == FNC_LA) uptr->FNC = FNC_LA1;
else uptr->FNC = FNC_SEEK1; /* advance state */
}
@ -575,15 +584,15 @@ switch (uptr->FNC) { /* case function */
case FNC_LA1: /* arec, need hd/sec */
case FNC_SEEK1: /* seek, need hd/sec */
if (dqd_command) { /* dch active? */
if (dqd.command) { /* dch active? */
dqc_rarh = DA_GETHD (dqd_obuf); /* set RAR from head */
dqc_rars = DA_GETSC (dqd_obuf); /* set RAR from sector */
dqd_wval = 0; /* clr data valid */
dqd_command = CLEAR; /* clr dch cmd */
dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */
dqd.command = CLEAR; /* clr dch cmd */
dqdio (&dqd_dib, ioENF, 0); /* set dch flg */
if (uptr->FNC == FNC_LA1) {
dqc_command = CLEAR; /* clr cch cmd */
dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */
dqc.command = CLEAR; /* clr cch cmd */
dqcio (&dqc_dib, ioENF, 0); /* set cch flg */
break; /* done if Load Address */
}
if (sim_is_active (&dqc_unit[drv])) break; /* if busy, seek check */
@ -610,23 +619,23 @@ switch (uptr->FNC) { /* case function */
break;
case FNC_STA: /* read status */
if (dqd_command) { /* dch active? */
if (dqd.command) { /* dch active? */
if ((dqc_unit[drv].flags & UNIT_UNLOAD) == 0) /* drive up? */
dqd_ibuf = dqc_sta[drv] & ~STA_DID;
else dqd_ibuf = STA_NRDY;
if (dqd_ibuf & STA_ANYERR) /* errors? set flg */
dqd_ibuf = dqd_ibuf | STA_ERR;
if (drv) dqd_ibuf = dqd_ibuf | STA_DID;
dqc_command = CLEAR; /* clr cch cmd */
dqd_command = CLEAR; /* clr dch cmd */
dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */
dqc.command = CLEAR; /* clr cch cmd */
dqd.command = CLEAR; /* clr dch cmd */
dqdio (&dqd_dib, ioENF, 0); /* set dch flg */
dqc_sta[drv] = dqc_sta[drv] & ~STA_ANYERR; /* clr sta flags */
}
else sim_activate (uptr, dqc_xtime); /* wait more */
break;
case FNC_CHK: /* check, need cnt */
if (dqd_command) { /* dch active? */
if (dqd.command) { /* dch active? */
dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */
dqd_wval = 0; /* clr data valid */
dq_goc (FNC_CHK1, drv, dqc_ctime); /* sched drv */
@ -663,15 +672,13 @@ return SCPE_OK;
t_stat dqc_svc (UNIT *uptr)
{
int32 da, drv, devc, devd, err;
int32 da, drv, err;
err = 0; /* assume no err */
drv = uptr - dqc_dev.units; /* get drive no */
devc = dqc_dib.devno; /* get cch devno */
devd = dqd_dib.devno; /* get dch devno */
if (uptr->flags & UNIT_UNLOAD) { /* drive down? */
dqc_command = CLEAR; /* clr cch cmd */
dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */
dqc.command = CLEAR; /* clr cch cmd */
dqcio (&dqc_dib, ioENF, 0); /* set cch flg */
dqc_sta[drv] = 0; /* clr status */
dqc_busy = 0; /* ctlr is free */
dqd_xfer = dqd_wval = 0;
@ -686,18 +693,18 @@ switch (uptr->FNC) { /* case function */
}
else dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; /* drive not busy */
case FNC_SEEK3:
if (dqc_busy || dqc_flag) { /* ctrl busy? */
if (dqc_busy || dqc.flag) { /* ctrl busy? */
uptr->FNC = FNC_SEEK3; /* next state */
sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */
}
else {
dqc_command = CLEAR; /* clr cch cmd */
dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */
dqc.command = CLEAR; /* clr cch cmd */
dqcio (&dqc_dib, ioENF, 0); /* set cch flg */
}
return SCPE_OK;
case FNC_RA: /* read addr */
if (!dqd_command) break; /* dch clr? done */
if (!dqd.command) break; /* dch clr? done */
if (dq_ptr == 0) dqd_ibuf = dqc_ucyl[drv]; /* 1st word? */
else if (dq_ptr == 1) { /* second word? */
dqd_ibuf = (dqc_uhed[drv] << DA_V_HD) | /* use drive head */
@ -706,8 +713,8 @@ switch (uptr->FNC) { /* case function */
}
else break;
dq_ptr = dq_ptr + 1;
dqd_command = CLEAR; /* clr dch cmd */
dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */
dqd.command = CLEAR; /* clr dch cmd */
dqdio (&dqd_dib, ioENF, 0); /* set dch flg */
sim_activate (uptr, dqc_xtime); /* sched next word */
return SCPE_OK;
@ -715,7 +722,7 @@ switch (uptr->FNC) { /* case function */
case FNC_RD: /* read */
case FNC_CHK1: /* check */
if (dq_ptr == 0) { /* new sector? */
if (!dqd_command && (uptr->FNC != FNC_CHK1)) break;
if (!dqd.command && (uptr->FNC != FNC_CHK1)) break;
if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */
(dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */
(dqc_rars >= DQ_NUMSC)) { /* bad sector? */
@ -743,17 +750,17 @@ switch (uptr->FNC) { /* case function */
}
dq_ptr = 0; /* wrap buf ptr */
}
if (dqd_command && dqd_xfer) { /* dch on, xfer? */
dqdio (dqd_dib.devno, ioENF, 0); /* set flag */
if (dqd.command && dqd_xfer) { /* dch on, xfer? */
dqdio (&dqd_dib, ioENF, 0); /* set flag */
}
dqd_command = CLEAR; /* clr dch cmd */
dqd.command = CLEAR; /* clr dch cmd */
sim_activate (uptr, dqc_xtime); /* sched next word */
return SCPE_OK;
case FNC_WA: /* write address */
case FNC_WD: /* write */
if (dq_ptr == 0) { /* sector start? */
if (!dqd_command && !dqd_wval) break; /* xfer done? */
if (!dqd.command && !dqd_wval) break; /* xfer done? */
if (uptr->flags & UNIT_WPRT) { /* write protect? */
dqc_sta[drv] = dqc_sta[drv] | STA_FLG;
break; /* done */
@ -782,10 +789,10 @@ switch (uptr->FNC) { /* case function */
if (err = ferror (uptr->fileref)) break;
dq_ptr = 0;
}
if (dqd_command && dqd_xfer) { /* dch on, xfer? */
dqdio (dqd_dib.devno, ioENF, 0); /* set flag */
if (dqd.command && dqd_xfer) { /* dch on, xfer? */
dqdio (&dqd_dib, ioENF, 0); /* set flag */
}
dqd_command = CLEAR; /* clr dch cmd */
dqd.command = CLEAR; /* clr dch cmd */
sim_activate (uptr, dqc_xtime); /* sched next word */
return SCPE_OK;
@ -793,8 +800,8 @@ switch (uptr->FNC) { /* case function */
return SCPE_IERR;
} /* end case fnc */
dqc_command = CLEAR; /* clr cch cmd */
dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */
dqc.command = CLEAR; /* clr cch cmd */
dqcio (&dqc_dib, ioENF, 0); /* set cch flg */
dqc_busy = 0; /* ctlr is free */
dqd_xfer = dqd_wval = 0;
if (err != 0) { /* error? */
@ -810,21 +817,19 @@ return SCPE_OK;
t_stat dqc_reset (DEVICE *dptr)
{
int32 drv;
DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */
hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &dqd_dev)? &dqc_dev: &dqd_dev);
if (sim_switches & SWMASK ('P')) { /* PON reset? */
if (sim_switches & SWMASK ('P')) { /* initialization reset? */
dqd_ibuf = 0; /* clear buffers */
dqd_obuf = 0;
dqc_obuf = 0;
dqc_obuf = 0; /* clear buffer */
dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */
}
if (dptr == &dqc_dev) /* command channel reset? */
dqcio (dqc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */
else /* data channel reset */
dqdio (dqd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */
IOPRESET (dibptr); /* PRESET device (does not use PON) */
dqc_busy = 0; /* reset controller state */
dqd_xfer = 0;
@ -947,7 +952,7 @@ t_stat dqc_boot (int32 unitno, DEVICE *dptr)
int32 dev;
if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */
dev = dqd_dib.devno; /* get data chan dev */
dev = dqd_dib.select_code; /* get data chan dev */
if (ibl_copy (dq_rom, dev)) return SCPE_IERR; /* copy boot to memory */
SR = (SR & IBL_OPT) | IBL_DQ | (dev << IBL_V_DEV); /* set SR */
return SCPE_OK;

View file

@ -1,6 +1,6 @@
/* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,8 @@
DR 12606B 2770/2771 fixed head disk
12610B 2773/2774/2775 drum
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
09-Jul-08 JDB Revised drc_boot to use ibl_copy
26-Jun-08 JDB Rewrote device I/O to model backplane signals
28-Dec-06 JDB Added ioCRS state to I/O decoders
@ -178,8 +180,10 @@ int32 drc_cw = 0; /* fnc, addr */
int32 drc_sta = 0; /* status */
int32 drc_run = 0; /* run flip-flop */
FLIP_FLOP drd_control = CLEAR;
FLIP_FLOP drd_flag = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
} drd = { CLEAR, CLEAR };
int32 drd_ibuf = 0; /* input buffer */
int32 drd_obuf = 0; /* output buffer */
@ -192,9 +196,9 @@ static int32 sz_tab[16] = {
184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288,
0, 655360, 0, 786432, 0, 917504, 0, 0 };
DEVICE drd_dev, drc_dev;
uint32 drdio (uint32 select_code, IOSIG signal, uint32 data);
uint32 drcio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER drdio;
IOHANDLER drcio;
t_stat drc_svc (UNIT *uptr);
t_stat drc_reset (DEVICE *dptr);
t_stat drc_attach (UNIT *uptr, char *cptr);
@ -205,6 +209,8 @@ t_stat dr_set_prot (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dr_show_prot (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
DEVICE drd_dev, drc_dev;
/* DRD data structures
drd_dev device descriptor
@ -213,8 +219,8 @@ t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
*/
DIB dr_dib[] = {
{ DRD, &drdio },
{ DRC, &drcio }
{ &drdio, DRD },
{ &drcio, DRC }
};
#define drd_dib dr_dib[0]
@ -231,10 +237,10 @@ UNIT drd_unit[] = {
REG drd_reg[] = {
{ ORDATA (IBUF, drd_ibuf, 16) },
{ ORDATA (OBUF, drd_obuf, 16) },
{ FLDATA (CTL, drd_control, 0) },
{ FLDATA (FLG, drd_flag, 0) },
{ FLDATA (CTL, drd.control, 0) },
{ FLDATA (FLG, drd.flag, 0) },
{ ORDATA (BPTR, drd_ptr, 6) },
{ ORDATA (DEVNO, drd_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, drd_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -272,7 +278,7 @@ REG drc_reg[] = {
{ FLDATA (RUN, drc_run, 0) },
{ DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, dr_stopioe, 0) },
{ ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, drc_dib.select_code, 6), REG_HRO },
{ DRDATA (CAPAC, drc_unit.capac, 24), REG_HRO },
{ NULL }
};
@ -326,82 +332,80 @@ DEVICE drc_dev = {
and as CRS is sent to all devices, we simply clear the control word here.
*/
uint32 drdio (uint32 select_code, IOSIG signal, uint32 data)
uint32 drdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
int32 t;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
drd_flag = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
drd.flag = CLEAR;
break;
case ioENF: /* enable flag */
drd_flag = SET;
break;
case ioENF: /* enable flag */
drd.flag = SET;
break;
case ioIOI: /* I/O data input */
data = drd_ibuf;
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, drd_ibuf); /* merge in return status */
break;
case ioIOO: /* I/O data output */
drd_obuf = data;
break;
case ioIOO: /* I/O data output */
drd_obuf = IODATA (stat_data); /* clear supplied status */
break;
case ioPOPIO: /* power-on preset to I/O */
/* fall into CRS handler */
case ioCRS: /* control reset */
if (!(drc_unit.flags & UNIT_DRUM)) /* 12606B? */
drc_cw = 0; /* clear control word */
case ioCRS: /* control reset */
if (!(drc_unit.flags & UNIT_DRUM)) /* 12606B? */
drc_cw = 0; /* clear control word */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
drd_flag = drd_control = CLEAR; /* clear control and flag */
case ioCLC: /* clear control flip-flop */
drd.flag = drd.control = CLEAR; /* clear control and flag */
if (!drc_run) /* cancel curr op */
sim_cancel (&drc_unit);
if (!drc_run) /* cancel curr op */
sim_cancel (&drc_unit);
drc_sta = drc_sta & ~DRS_SAC; /* clear SAC flag */
break;
drc_sta = drc_sta & ~DRS_SAC; /* clear SAC flag */
break;
case ioSTC: /* set control flip-flop */
drd_control = SET; /* set ctl */
case ioSTC: /* set control flip-flop */
drd.control = SET; /* set ctl */
if (drc_cw & CW_WR) /* writing? */
drd_flag = SET; /* prime DMA */
if (drc_cw & CW_WR) /* writing? */
drd.flag = SET; /* prime DMA */
drc_sta = 0; /* clr status */
drd_ptr = 0; /* clear sec ptr */
sim_cancel (&drc_unit); /* cancel curr op */
t = CW_GETSEC (drc_cw) - dr_seccntr (sim_gtime());
if (t <= 0) t = t + DR_NUMSC;
sim_activate (&drc_unit, t * DR_NUMWD * dr_time);
break;
drc_sta = 0; /* clr status */
drd_ptr = 0; /* clear sec ptr */
sim_cancel (&drc_unit); /* cancel curr op */
t = CW_GETSEC (drc_cw) - dr_seccntr (sim_gtime());
if (t <= 0) t = t + DR_NUMSC;
sim_activate (&drc_unit, t * DR_NUMWD * dr_time);
break;
case ioSIR: /* set interrupt request */
setstdSRQ (select_code, drd); /* set SRQ signal */
break;
case ioSIR: /* set interrupt request */
setstdSRQ (drd); /* set SRQ signal */
break;
default: /* all other signals */
break; /* are ignored */
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
drdio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
drdio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -423,81 +427,80 @@ return data;
2. The command channel cannot interrupt, so there is no SIR handler.
*/
uint32 drcio (uint32 select_code, IOSIG signal, uint32 data)
uint32 drcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
uint16 data;
int32 sec;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */
sec = dr_seccntr (sim_gtime ()); /* current sector */
sim_cancel (&drd_unit[TMR_ORG]); /* sched origin tmr */
sim_activate (&drd_unit[TMR_ORG],
(DR_FNUMSC - sec) * DR_NUMWD * dr_time);
}
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */
sec = dr_seccntr (sim_gtime ()); /* current sector */
sim_cancel (&drd_unit[TMR_ORG]); /* sched origin tmr */
sim_activate (&drd_unit[TMR_ORG],
(DR_FNUMSC - sec) * DR_NUMWD * dr_time);
}
break;
case ioSFC: /* skip if flag is clear */
if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */
setSKF (!(CALC_SCP (sim_gtime()))); /* skip if nearing end of sector */
break;
case ioSFC: /* skip if flag is clear */
if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */
setSKF (!(CALC_SCP (sim_gtime()))); /* skip if nearing end of sector */
break;
case ioSFS: /* skip if flag is set */
if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */
setSKF (!sim_is_active (&drd_unit[TMR_ORG])); /* skip if origin seen */
break;
case ioSFS: /* skip if flag is set */
if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */
setSKF (!sim_is_active (&drd_unit[TMR_ORG])); /* skip if origin seen */
break;
case ioIOI: /* I/O data input */
data = drc_sta; /* static bits */
case ioIOI: /* I/O data input */
data = drc_sta; /* static bits */
if (!(drc_unit.flags & UNIT_PROT) || /* not protected? */
(CW_GETTRK(drc_cw) >= drc_pcount)) /* or not in range? */
data = data | DRS_WEN; /* set wrt enb status */
if (!(drc_unit.flags & UNIT_PROT) || /* not protected? */
(CW_GETTRK(drc_cw) >= drc_pcount)) /* or not in range? */
data = data | DRS_WEN; /* set wrt enb status */
if (drc_unit.flags & UNIT_ATT) { /* attached? */
data = data | (dr_seccntr (sim_gtime()) << DRS_V_NS) | DRS_RDY;
if (sim_is_active (&drc_unit)) /* op in progress? */
data = data | DRS_BSY;
if (CALC_SCP (sim_gtime())) /* SCP ff set? */
data = data | DRS_SEC; /* set sector flag */
if (sim_is_active (&drd_unit[TMR_INH]) && /* inhibit timer on? */
!(drc_cw & CW_WR))
data = data | DRS_RIF; /* set read inh flag */
}
break;
if (drc_unit.flags & UNIT_ATT) { /* attached? */
data = data | (dr_seccntr (sim_gtime()) << DRS_V_NS) | DRS_RDY;
if (sim_is_active (&drc_unit)) /* op in progress? */
data = data | DRS_BSY;
if (CALC_SCP (sim_gtime())) /* SCP ff set? */
data = data | DRS_SEC; /* set sector flag */
if (sim_is_active (&drd_unit[TMR_INH]) && /* inhibit timer on? */
!(drc_cw & CW_WR))
data = data | DRS_RIF; /* set read inh flag */
}
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
break;
case ioIOO: /* I/O data output */
if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */
sim_cancel (&drd_unit[TMR_INH]); /* schedule inhibit timer */
sim_activate (&drd_unit[TMR_INH], DR_FTIME * DR_NUMWD);
}
drc_cw = data; /* get control word */
break;
case ioIOO: /* I/O data output */
if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */
sim_cancel (&drd_unit[TMR_INH]); /* schedule inhibit timer */
sim_activate (&drd_unit[TMR_INH], DR_FTIME * DR_NUMWD);
}
drc_cw = IODATA (stat_data); /* get control word */
break;
case ioPOPIO: /* power-on preset to I/O */
/* fall into CRS handler */
default: /* all other signals */
break; /* are ignored */
}
case ioCRS: /* control reset */
break; /* allow data channel to handle this */
default: /* all other signals */
break; /* are ignored */
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
drcio (select_code, ioCLF, 0); /* issue CLF */
return data;
return stat_data;
}
@ -511,7 +514,7 @@ uint16 *bptr = (uint16 *) uptr->filebuf;
if ((uptr->flags & UNIT_ATT) == 0) {
drc_sta = DRS_ABO;
return IORETURN (dr_stopioe, SCPE_UNATT);
return IOERROR (dr_stopioe, SCPE_UNATT);
}
trk = CW_GETTRK (drc_cw);
@ -527,8 +530,8 @@ if (drc_cw & CW_WR) { /* write? */
uptr->hwmark = da + drd_ptr + 1;
}
drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */
if (drd_control) { /* dch active? */
drdio (drd_dib.devno, ioENF, 0); /* set SRQ */
if (drd.control) { /* dch active? */
drdio (&drd_dib, ioENF, 0); /* set SRQ */
sim_activate (uptr, dr_time); /* sched next word */
}
else { /* done */
@ -541,11 +544,11 @@ if (drc_cw & CW_WR) { /* write? */
}
} /* end write */
else { /* read */
if (drd_control) { /* dch active? */
if (drd.control) { /* dch active? */
if ((da >= uptr->capac) || (sec >= DR_NUMSC)) drd_ibuf = 0;
else drd_ibuf = bptr[da + drd_ptr];
drd_ptr = dr_incda (trk, sec, drd_ptr);
drdio (drd_dib.devno, ioENF, 0); /* set SRQ */
drdio (&drd_dib, ioENF, 0); /* set SRQ */
sim_activate (uptr, dr_time); /* sched next word */
}
else drc_run = 0; /* clear run ff */
@ -601,16 +604,17 @@ else return ((curword - DR_OVRHEAD) / DR_NUMWD +
t_stat drc_reset (DEVICE *dptr)
{
DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */
hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &drd_dev)? &drc_dev: &drd_dev);
if (sim_switches & SWMASK ('P')) /* PON reset? */
drc_sta = drc_cw = drd_ptr = 0; /* clear controller state variables */
if (sim_switches & SWMASK ('P')) { /* power-on reset? */
drd_ptr = 0; /* clear sector pointer */
drc_sta = drc_cw = 0; /* clear controller state variables */
}
if (dptr == &drc_dev) /* command channel reset? */
drcio (drc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */
else /* data channel reset */
drdio (drd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */
IOPRESET (dibptr); /* PRESET device (does not use PON) */
sim_cancel (&drc_unit);
sim_cancel (&drd_unit[TMR_ORG]);
@ -726,7 +730,7 @@ static const BOOT_ROM dr_rom = { /* padded to start at x7
t_stat drc_boot (int32 unitno, DEVICE *dptr)
{
const int32 dev = drd_dib.devno; /* data chan select code */
const int32 dev = drd_dib.select_code; /* data chan select code */
if (unitno != 0) /* only unit 0 */
return SCPE_NOFNC;

View file

@ -1,6 +1,6 @@
/* hp2100_ds.c: HP 2100 13037 disk controller simulator
Copyright (c) 2004-2008, Robert M. Supnik
Copyright (c) 2004-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,13 @@
DS 13037 disk controller
21-Jun-11 JDB Corrected status returns for disabled drive, auto-seek
beyond drive limits, Request Sector Address and Wakeup
with invalid or offline unit
Address verification reenabled if auto-seek during
Read Without Verify
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
26-Jun-08 JDB Rewrote device I/O to model backplane signals
31-Dec-07 JDB Corrected and verified ioCRS action
20-Dec-07 JDB Corrected DPTR register definition from FLDATA to DRDATA
@ -346,10 +353,12 @@ static struct drvtyp drv_tab[] = {
{ 0 }
};
FLIP_FLOP ds_control = CLEAR;
FLIP_FLOP ds_flag = CLEAR;
FLIP_FLOP ds_flagbuf = CLEAR;
FLIP_FLOP ds_srq = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
FLIP_FLOP srq; /* service request flip-flop */
} ds = { CLEAR, CLEAR, CLEAR, CLEAR };
uint32 ds_fifo[DS_FIFO_SIZE] = { 0 }; /* fifo */
uint32 ds_fifo_ip = 0; /* insertion ptr */
@ -412,7 +421,9 @@ static const uint32 ds_opflags[32] = { /* flags for ops */
};
DEVICE ds_dev;
uint32 dsio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER dsio;
t_stat ds_svc_c (UNIT *uptr);
t_stat ds_svc_u (UNIT *uptr);
t_stat ds_svc_t (UNIT *uptr);
@ -455,7 +466,7 @@ void ds_fifo_reset (void);
ds_mod DS modifier list
*/
DIB ds_dib = { DS, &dsio };
DIB ds_dib = { &dsio, DS };
UNIT ds_unit[] = {
{ UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |
@ -491,10 +502,10 @@ REG ds_reg[] = {
{ DRDATA (FIP, ds_fifo_ip, 4) },
{ DRDATA (FRP, ds_fifo_rp, 4) },
{ DRDATA (FCNT, ds_fifo_cnt, 5) },
{ FLDATA (CTL, ds_control, 0) },
{ FLDATA (FLG, ds_flag, 0) },
{ FLDATA (FBF, ds_flagbuf, 0) },
{ FLDATA (SRQ, ds_srq, 0) },
{ FLDATA (CTL, ds.control, 0) },
{ FLDATA (FLG, ds.flag, 0) },
{ FLDATA (FBF, ds.flagbuf, 0) },
{ FLDATA (SRQ, ds.srq, 0) },
{ FLDATA (BUSY, ds_busy, 0) },
{ FLDATA (CMDF, ds_cmdf, 0) },
{ FLDATA (CMDP, ds_cmdp, 0) },
@ -515,7 +526,7 @@ REG ds_reg[] = {
DS_NUMDR + 1, REG_HRO) },
{ URDATA (CAPAC, ds_unit[0].capac, 10, T_ADDR_W, 0,
DS_NUMDR, PV_LEFT | REG_HRO) },
{ ORDATA (DEVNO, ds_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, ds_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -576,7 +587,7 @@ DEVICE ds_dev = {
of a command.
Also unusual is that SFC and SFS test different things, rather than
complementaty states of the same thing. SFC tests the busy flip-flop, and
complementary states of the same thing. SFC tests the busy flip-flop, and
SFS tests the flag flip-flop.
Implementation notes:
@ -586,108 +597,110 @@ DEVICE ds_dev = {
access to fail.
*/
uint32 dsio (uint32 select_code, IOSIG signal, uint32 data)
uint32 dsio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
ds_flag = ds_flagbuf = CLEAR; /* clear flag */
ds_srq = CLEAR; /* CLF clears SRQ */
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
ds.flag = ds.flagbuf = CLEAR; /* clear flag */
ds.srq = CLEAR; /* CLF clears SRQ */
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
ds_flag = ds_flagbuf = SET; /* set flag and flag buffer */
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
ds.flag = ds.flagbuf = SET; /* set flag and flag buffer */
break;
case ioSFC: /* skip if flag is clear */
setSKF (ds_busy == 0); /* skip if not busy */
break;
case ioSFC: /* skip if flag is clear */
setSKF (ds_busy == 0); /* skip if not busy */
break;
case ioSFS: /* skip if flag is set */
setstdSKF (ds);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (ds);
break;
case ioIOI: /* I/O data input */
data = ds_fifo_read ();
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, ds_fifo_read ()); /* merge in return status */
break;
case ioIOO: /* I/O data output */
if (ds_cmdf) { /* expecting command? */
ds_cmd = data; /* save command */
ds_cmdf = 0;
ds_cmdp = 1; /* command present */
}
case ioIOO: /* I/O data output */
if (ds_cmdf) { /* expecting command? */
ds_cmd = IODATA (stat_data); /* save command */
ds_cmdf = 0;
ds_cmdp = 1; /* command present */
}
else
ds_fifo_write (data); /* put in fifo */
break;
else
ds_fifo_write (IODATA (stat_data)); /* put in fifo */
break;
case ioPOPIO: /* power-on preset to I/O */
ds_flag = ds_flagbuf = SET; /* set flag and flag buffer */
ds_cmdp = 0; /* clear command ready */
/* fall into CRS handler */
case ioCRS: /* control reset */
ds_control = CLEAR; /* clear control */
ds_cmdf = 0; /* not expecting command */
ds_clear (); /* do controller CLEAR */
break;
case ioPOPIO: /* power-on preset to I/O */
ds.flag = ds.flagbuf = SET; /* set flag and flag buffer */
ds_cmdp = 0; /* clear command ready */
break;
case ioCLC: /* clear control flip-flop */
ds_control = CLEAR; /* clear control */
ds_cmdf = 1; /* expecting command */
ds_cmdp = 0; /* none pending */
ds_eod = 1; /* set EOD flag */
ds_fifo_reset (); /* clear fifo */
break;
case ioCRS: /* control reset */
ds.control = CLEAR; /* clear control */
ds_cmdf = 0; /* not expecting command */
ds_clear (); /* do controller CLEAR */
break;
case ioSTC: /* set control flip-flop */
ds_control = SET; /* set control */
break;
case ioCLC: /* clear control flip-flop */
ds.control = CLEAR; /* clear control */
ds_cmdf = 1; /* expecting command */
ds_cmdp = 0; /* none pending */
ds_eod = 1; /* set EOD flag */
ds_fifo_reset (); /* clear fifo */
break;
case ioEDT: /* end data transfer */
ds_eod = 1; /* flag end transfer */
break;
case ioSTC: /* set control flip-flop */
ds.control = SET; /* set control */
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, ds); /* set standard PRL signal */
setstdIRQ (select_code, ds); /* set standard IRQ signal */
setSRQ (select_code, ds_srq); /* set SRQ signal */
break;
case ioEDT: /* end data transfer */
ds_eod = 1; /* flag end transfer */
break;
case ioIAK: /* interrupt acknowledge */
ds_flagbuf = CLEAR;
break;
case ioSIR: /* set interrupt request */
setstdPRL (ds); /* set standard PRL signal */
setstdIRQ (ds); /* set standard IRQ signal */
setSRQ (dibptr->select_code, ds.srq); /* set SRQ signal */
break;
default: /* all other signals */
break; /* are ignored */
case ioIAK: /* interrupt acknowledge */
ds.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
dsio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
dsio (select_code, ioSIR, 0); /* set interrupt request */
if ((signal != ioSIR) && (signal != ioENF)) /* if not IRQ update */
if (!(signal_set & ioSIR) && !(signal_set & ioENF)) /* if not IRQ update */
ds_poll (); /* run the controller */
return data;
return stat_data;
}
@ -702,7 +715,7 @@ void ds_poll (void)
{
if ((ds_state != DS_BUSY) && ds_cmdp) /* cmd pending? */
ds_docmd (ds_cmd); /* do it */
if ((ds_state == DS_IDLE) && ds_control) /* idle? */
if ((ds_state == DS_IDLE) && ds.control) /* idle? */
ds_doatn (); /* check ATN */
return;
}
@ -719,7 +732,7 @@ return;
void ds_docmd (uint32 cmd)
{
uint32 op, f, dtyp, unum;
uint32 op, f, unum;
op = DSC_GETOP (cmd); /* operation */
f = ds_opflags[op]; /* flags */
@ -749,6 +762,7 @@ switch (op) {
(DSC_GETCSC (ds_cmd) << DSHS_V_SC);
case DSC_RECAL: /* recalibrate */
case DSC_SEEK: /* seek */
case DSC_RSA: /* read sector address */
case DSC_READ: /* read */
case DSC_RFULL: /* read full */
case DSC_ROFF: /* read offset */
@ -786,12 +800,6 @@ switch (op) {
ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */
break;
case DSC_RSA: /* read sector address */
dtyp = GET_DTYPE (ds_unit[unum].flags); /* get unit type */
dsxb[0] = GET_CURSEC (ds_dtime * DS_NUMWD, dtyp); /* rot position */
ds_sched_ctrl_op (DSC_RSTA, 1, SET_BUSY); /* sched 1 wd, busy */
break;
case DSC_RDA: /* read disk address */
ds_reqad (&dsxb[1], &dsxb[0]); /* return disk address */
ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */
@ -806,10 +814,15 @@ switch (op) {
/* Other controller commands */
case DSC_WAKE: /* wakeup */
ds_sr1 = unum; /* init status */
if (unum >= DS_NUMDR) { /* invalid unit? */
ds_sched_ctrl_op (DSC_BADU, unum, CLR_BUSY);/* sched, not busy */
return;
}
case DSC_SFM: /* set file mask */
case DSC_CLEAR: /* clear */
case DSC_AREC: /* address record */
case DSC_WAKE: /* wakeup */
case DSC_WTIO: /* write TIO */
ds_sched_ctrl_op (op, 0, SET_BUSY); /* schedule, busy */
break;
@ -833,7 +846,7 @@ for (i = 0; i < DS_NUMDR; i++) { /* intr disabled? */
ds_lastatn = (ds_lastatn + 1) & DS_DRMASK; /* loop through units */
if (ds_unit[ds_lastatn].STA & DS2_ATN) { /* ATN set? */
ds_unit[ds_lastatn].STA &= ~DS2_ATN; /* clear ATN */
dsio (ds_dib.devno, ioENF, 0); /* request interrupt */
dsio (&ds_dib, ioENF, 0); /* request interrupt */
ds_sr1 = DS1_ATN | ds_lastatn; /* set up status 1 */
ds_state = DS_WAIT; /* block atn intrs */
return;
@ -889,9 +902,9 @@ switch (op) {
case DSC_CLEAR: /* clear */
ds_clear (); /* reset ctrl */
ds_control = CLEAR; /* clear CTL, SRQ */
ds_srq = CLEAR;
dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */
ds.control = CLEAR; /* clear CTL, SRQ */
ds.srq = CLEAR;
dsio (&ds_dib, ioSIR, 0); /* set interrupt request */
ds_cmd_done (1, DS1_OK); /* op done, set flag */
break;
@ -994,6 +1007,15 @@ switch (op) { /* case on function */
/* Read variants */
case DSC_RSA: /* read sector address */
if ((uptr->flags & UNIT_UNLOAD) == 0) { /* drive up? */
dsxb[0] = GET_CURSEC (ds_dtime * DS_NUMWD, dtyp); /* rot position */
ds_sched_ctrl_op (DSC_RSTA, 1, SET_BUSY); /* sched 1 wd, busy */
}
else /* no drive or heads unloaded */
ds_cmd_done (1, DS1_S2ERR); /* not ready error */
break;
case DSC_ROFF: /* read with offset */
ds_wait_for_cpu (uptr, DSC_ROFF|DSC_2ND); /* set flag, new state */
break;
@ -1001,7 +1023,7 @@ switch (op) { /* case on function */
if (!DS_FIFO_EMPTY) { /* OTA ds? new state */
ds_fifo_read (); /* drain fifo */
uptr->FNC = DSC_READ;
dsio (ds_dib.devno, ioENF, 0); /* handshake */
dsio (&ds_dib, ioENF, 0); /* handshake */
}
sim_activate (uptr, ds_ctime); /* schedule unit */
break;
@ -1022,14 +1044,15 @@ switch (op) { /* case on function */
ds_end_rw (uptr, DSC_READ); /* see if more to do */
break;
case DSC_RNOVFY: /* read, no verify */
case DSC_RNOVFY: /* read, no verify before xfer */
if (r = ds_start_rd (uptr, 0, 0)) return r; /* new sector; error? */
break;
case DSC_RNOVFY | DSC_2ND: /* word transfer */
ds_cont_rd (uptr, DS_NUMWD); /* xfr wd, check end */
break;
case DSC_RNOVFY | DSC_3RD: /* end of sector */
ds_end_rw (uptr, DSC_RNOVFY); /* see if more to do */
ds_end_rw (uptr, /* see if more to do */
DSHS_GETSC (ds_hs) ? DSC_RNOVFY : DSC_READ); /* start verifying if end of track */
break;
case DSC_RFULL: /* read full */
@ -1049,7 +1072,7 @@ switch (op) { /* case on function */
case DSC_VFY: /* verify */
ds_wait_for_cpu (uptr, DSC_VFY|DSC_2ND); /* set flag, new state */
break;
case DSC_VFY | DSC_2ND: /* poll done */
case DSC_VFY | DSC_2ND: /* poll done */
if (!DS_FIFO_EMPTY) { /* OTA ds? */
ds_vctr = ds_fifo_read (); /* save count */
uptr->FNC = DSC_VFY | DSC_3RD; /* next state */
@ -1058,11 +1081,11 @@ switch (op) { /* case on function */
else sim_activate (uptr, ds_ctime); /* no, continue poll */
break;
case DSC_VFY | DSC_3RD: /* start sector */
if (ds_start_rw (uptr, ds_dtime * DS_NUMWD, 1)) break;
/* new sector; error? */
if (ds_start_rw (uptr, ds_dtime * DS_NUMWD, 1)) /* new sector; error? */
break;
ds_next_sec (uptr); /* increment hd, sc */
break;
case DSC_VFY | DSC_4TH: /* end sector */
case DSC_VFY | DSC_4TH: /* end sector */
ds_vctr = (ds_vctr - 1) & DMASK; /* decrement count */
if (ds_vctr) ds_end_rw (uptr, DSC_VFY|DSC_3RD); /* more to do? */
else ds_cmd_done (1, DS1_OK); /* no, set done */
@ -1120,7 +1143,7 @@ return SCPE_OK;
void ds_wait_for_cpu (UNIT *uptr, uint32 newst)
{
dsio (ds_dib.devno, ioENF, 0); /* set flag */
dsio (&ds_dib, ioENF, 0); /* set flag */
uptr->FNC = newst; /* new state */
sim_activate (uptr, ds_ctime); /* activate unit */
sim_cancel (&ds_timer); /* activate timeout */
@ -1154,7 +1177,7 @@ return;
void ds_cmd_done (t_bool sf, uint32 sr1)
{
if (sf) /* set host flag? */
dsio (ds_dib.devno, ioENF, 0); /* set flag */
dsio (&ds_dib, ioENF, 0); /* set flag */
ds_busy = 0; /* clear visible busy */
ds_sr1 = ds_sr1 | sr1; /* final status */
@ -1165,7 +1188,20 @@ return;
}
/* Return drive status (status word 2) */
/* Return drive status (status word 2).
In hardware, the controller outputs the Address Unit command on the drive tag
bus and the unit number on the drive control bus. The addressed drive
responds by setting its internal "selected" flag. The controller then
outputs Request Status on the tag bug. If a drive is selected but the heads
are unloaded, the drive returns Not Ready and Busy status on the control bus.
If no drive is selected, the control bus floats inactive. This is
interpreted by the controller as Not Ready status (because the drive returns
inactive Ready status).
Under simulation, an enabled but detached unit corresponds to "selected but
heads unloaded," and a disabled unit corresponds to a non-existent unit.
*/
uint32 ds_updds2 (UNIT *uptr)
{
@ -1174,10 +1210,11 @@ uint32 dtyp = GET_DTYPE (uptr->flags);
sta = drv_tab[dtyp].id | /* form status */
uptr->STA | /* static bits */
((uptr->flags & UNIT_WPR)? DS2_RO: 0) | /* dynamic bits */
((uptr->flags & UNIT_FMT)? DS2_FRM: 0) |
((uptr->flags & UNIT_UNLOAD)? DS2_NR | DS2_BS: 0) |
(sim_is_active (uptr)? DS2_BS: 0);
((uptr->flags & UNIT_WPR) ? DS2_RO : 0) | /* dynamic bits */
((uptr->flags & UNIT_FMT) ? DS2_FRM : 0) |
((uptr->flags & UNIT_DIS) ? DS2_NR :
(uptr->flags & UNIT_UNLOAD) ? DS2_NR | DS2_BS : 0) |
(sim_is_active (uptr) ? DS2_BS : 0);
if (sta & DS2_ALLERR) sta = sta | DS2_ERR; /* set error */
return sta;
}
@ -1240,7 +1277,12 @@ return;
- If error, set command done, return TRUE, nothing is scheduled
- If implicit seek, return TRUE, implicit seek is scheduled, but
state is not changed - we will return here when seek is done
- Otherwise, advance state, set position in file, schedule next state */
- Otherwise, advance state, set position in file, schedule next state
If a an auto-seek was done, it may have incremented or decremented beyond the
cylinder bounds. If so, then Seek Check status will have been set. If we
see that, terminate the current command with a Status-2 error.
*/
t_bool ds_start_rw (UNIT *uptr, int32 tm, t_bool vfy)
{
@ -1249,8 +1291,8 @@ uint32 dtyp = GET_DTYPE (uptr->flags);
ds_eod = 0; /* init eod */
ds_ptr = 0; /* init buffer ptr */
if (uptr->flags & UNIT_UNLOAD) { /* drive down? */
ds_cmd_done (1, DS1_S2ERR);
if (uptr->flags & UNIT_UNLOAD | uptr->STA & DS2_SC) { /* drive down or seek check? */
ds_cmd_done (1, DS1_S2ERR); /* report Status-2 error */
return TRUE;
}
if (ds_eoc) { /* at end of cylinder? */
@ -1258,21 +1300,16 @@ if (ds_eoc) { /* at end of cylinder? *
return TRUE; /* or error */
}
if (vfy && ((uint32) uptr->CYL != ds_cyl)) { /* on wrong cylinder? */
if (ds_cyl >= drv_tab[dtyp].cyl) /* seeking to bad? */
ds_cmd_done (1, DS1_CYLCE); /* lose */
else ds_start_seek (uptr, ds_cyl, uptr->FNC); /* seek right cyl */
ds_start_seek (uptr, ds_cyl, uptr->FNC); /* seek right cyl */
return TRUE;
}
hd = DSHS_GETHD (ds_hs);
sc = DSHS_GETSC (ds_hs);
if ((uint32) uptr->CYL >= drv_tab[dtyp].cyl) { /* valid cylinder? */
uptr->STA = uptr->STA | DS2_SC; /* set seek check */
ds_cmd_done (1, DS1_S2ERR); /* error */
return TRUE;
}
if ((hd >= drv_tab[dtyp].hd) || /* valid head, sector? */
if (((uint32) uptr->CYL >= drv_tab[dtyp].cyl) || /* valid cylinder? (sanity check) */
(hd >= drv_tab[dtyp].hd) || /* valid head, sector? */
(sc >= drv_tab[dtyp].sc)) {
ds_cmd_done (1, DS1_HSCE); /* no, error */
uptr->STA = uptr->STA | DS2_SC; /* set seek check */
ds_cmd_done (1, DS1_S2ERR); /* report Status-2 error */
return TRUE;
}
da = GET_DA (uptr->CYL, hd, sc, dtyp); /* position in file */
@ -1327,8 +1364,8 @@ if ((uptr->flags & UNIT_WPR) || /* write protected? */
}
if (ds_start_rw (uptr, ds_rtime, vfy)) return; /* new sec; err or seek? */
for (i = 0; i < DS_NUMWDF; i++) dsxb[i] = 0; /* clear buffer */
ds_srq = SET; /* request word */
dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */
ds.srq = SET; /* request word */
dsio (&ds_dib, ioSIR, 0); /* set interrupt request */
return;
}
@ -1355,7 +1392,10 @@ return;
/* Advance to next cylinder
- If autoseek enabled, seek to cylinder +/- 1
- Otherwise, done with end of cylinder error */
- Otherwise, done with end of cylinder error.
If we exceed the cylinder range, the seek will set Seek Check status.
*/
void ds_next_cyl (UNIT *uptr)
{
@ -1378,14 +1418,14 @@ return;
void ds_cont_rd (UNIT *uptr, uint32 bsize)
{
if (ds_eod) ds_cmd_done (1, DS1_OK); /* DMA end? done */
else if (ds_srq) { /* overrun? */
else if (ds.srq) { /* overrun? */
ds_cmd_done (1, DS1_OVRUN); /* set done */
return;
}
else {
ds_fifo_write (dsxb[ds_ptr++]); /* next word */
ds_srq = SET; /* request service */
dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */
ds.srq = SET; /* request service */
dsio (&ds_dib, ioSIR, 0); /* set interrupt request */
if (ds_ptr >= bsize) uptr->FNC += DSC_NEXT; /* sec done? next state */
sim_activate (uptr, ds_dtime); /* schedule */
}
@ -1398,13 +1438,13 @@ return;
- Copy word from fifo to buffer
- If end of data, write buffer, terminate command, nothing scheduled
- If end of sector, write buffer, next state, schedule
- Otherwises, set service request, schedule */
- Otherwise, set service request, schedule */
t_stat ds_cont_wr (UNIT *uptr, uint32 off, uint32 bsize)
{
uint32 i, dat;
if (ds_srq) { /* overrun? */
if (ds.srq) { /* overrun? */
ds_cmd_done (1, DS1_OVRUN); /* set done */
return SCPE_OK;
}
@ -1422,8 +1462,8 @@ if (ds_eod || (ds_ptr >= bsize)) { /* xfr or sector done? *
else uptr->FNC += DSC_NEXT; /* no, next state */
}
else {
ds_srq = SET; /* request next word */
dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */
ds.srq = SET; /* request next word */
dsio (&ds_dib, ioSIR, 0); /* set interrupt request */
}
sim_activate (uptr, ds_dtime); /* schedule */
return SCPE_OK;
@ -1529,8 +1569,8 @@ return SCPE_OK;
t_stat ds_reset (DEVICE *dptr)
{
dsio (ds_dib.devno, ioPOPIO, 0); /* send POPIO signal */
ds_srq = CLEAR; /* clear SRQ */
IOPRESET (&ds_dib); /* PRESET device */
ds.srq = CLEAR; /* clear SRQ */
return SCPE_OK;
}
@ -1593,7 +1633,7 @@ void ds_sched_atn (UNIT *uptr)
{
int32 i;
if (!ds_control || (sim_switches & SIM_SW_REST)) return;
if (!ds.control || (sim_switches & SIM_SW_REST)) return;
for (i = 0; i < (DS_NUMDR + 1); i++) { /* check units, ctrl */
if (sim_is_active (ds_dev.units + i)) return;
}
@ -1687,7 +1727,7 @@ t_stat ds_boot (int32 unitno, DEVICE *dptr)
int32 dev;
if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */
dev = ds_dib.devno; /* get data chan dev */
dev = ds_dib.select_code; /* get data chan dev */
if (ibl_copy (ds_rom, dev)) return SCPE_IERR; /* copy boot to memory */
SR = (SR & (IBL_OPT | IBL_DS_HEAD)) | IBL_DS | IBL_MAN | (dev << IBL_V_DEV);
return SCPE_OK;

View file

@ -1,6 +1,6 @@
/* hp2100_fp1.c: HP 1000 multiple-precision floating point routines
Copyright (c) 2005-2008, J. David Bryan
Copyright (c) 2005-2011, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author.
21-Jun-11 JDB Completed the comments for divide; no code changes
08-Jun-08 JDB Quieted bogus gcc warning in fp_exec
10-May-08 JDB Fixed uninitialized return in fp_accum when setting
19-Mar-08 JDB Reworked "complement" to avoid inlining bug in gcc-4.x
@ -153,7 +154,7 @@
initial letters of the instructions (F/X/T) to indicate the precision used.
The FPP hardware consisted of two circuit boards that interfaced to the main
CPU via the Microprogammable Processor Port (MPP) that had been introduced
CPU via the Microprogrammable Processor Port (MPP) that had been introduced
with the 1000 E-Series. One board contained argument registers and ALUs,
split into separate mantissa and exponent parts. The other contained a state
machine sequencer. FPP results were copied automatically to the argument
@ -675,9 +676,9 @@ return;
two operands. If the magnitude of the difference between the exponents is
greater than the number of significant bits, then the smaller number has been
scaled to zero (swamped), and so the sum is simply the larger operand.
Otherwise, the sum is computed and checked for overflow, which has occured if
the signs of the operands are the same but differ from that of the result.
Scaling and renormalization is perfomed if overflow occurred.
Otherwise, the sum is computed and checked for overflow, which has occurred
if the signs of the operands are the same but differ from that of the result.
Scaling and renormalization is performed if overflow occurred.
*/
static void add (FPU *sum, FPU augend, FPU addend)
@ -727,11 +728,11 @@ return;
The single-precision firmware (FMP) operates differently from the firmware
extended-precision (.XMPY) and the hardware multiplies of any precision.
Firmware implementations form 16-bit x 16-bit = 32-bit partial products and
sum them to form the result. The hardware uses a series of shifts and adds.
This means that firmware FMP and hardware FMP return slightly different
values, as may be seen by attempting to run the firmware FMP diagnostic on
the FPP.
Firmware implementations use the MPY micro-order to form 16-bit x 16-bit =
32-bit partial products and sum them to form the result. The hardware uses a
series of shifts and adds. This means that firmware FMP and hardware FMP
return slightly different values, as may be seen by attempting to run the
firmware FMP diagnostic on the FPP.
The FMP microcode calls a signed multiply routine to calculate three partial
products (all but LSB * LSB). Because the LSBs are unsigned, i.e., all bits
@ -779,7 +780,7 @@ return;
The basic FPP hardware algorithm scans the multiplier and adds a shifted copy
of the multiplicand whenever a one-bit is detected. To avoid successive adds
when a string of ones is encountered (because adds are more expensive than
shifts), the hardware instead adds the multiplicand shifted by N+1+P and
shifts), the hardware instead adds the multiplicand shifted by N + 1 + P and
subtracts the multiplicand shifted by P to obtain the equivalent value with a
maximum of two operations.
@ -884,16 +885,32 @@ return;
As with multiply, the single-precision firmware (FDV) operates differently
from the firmware extended-precision (.XDIV) and the hardware divisions of
any precision. Firmware implementations utilize a "divide and correct"
algorithm, wherein the quotient is estimated and then corrected by comparing
the dividend to the product of the quotient and the divisor. The hardware
uses a series of shifts and subtracts. This means that firmware FDV and
hardware FDV once again return slightly different values.
any precision. Firmware implementations use the DIV micro-order to form
32-bit / 16-bit = 16-bit quotients and 16-bit remainders. These are used in
a "divide and correct" algorithm, wherein the quotient is estimated and then
corrected by comparing the dividend to the product of the quotient and the
divisor. The hardware uses a series of shifts and subtracts. This means
that firmware FDV and hardware FDV once again return slightly different
values.
Under simulation, the classic divide-and-correct method is employed, using
64-bit / 32-bit = 32-bit divisions. This involves dividing the 64-bit
dividend "a1a2a3a4" by the first 32-bit digit "b1b2" of the 64-bit divisor
"b1b2b3b4". The resulting 32-bit quotient is ...
64-bit / 32-bit = 32-bit divisions. This method considers the 64-bit
dividend and divisor each to consist of two 32-bit "digits." The 64-bit
dividend "a1a2a3a4" is divided by the first 32-bit digit "b1b2" of the 64-bit
divisor "b1b2b3b4", yielding a 32-bit trial quotient digit and a 32-bit
remainder digit. A correction is developed by subtracting the product of the
second 32-bit digit "b3b4" of the divisor and the trial quotient digit from
the remainder (we take advantage of the eight bits vacated by the exponent
during unpacking to ensure that this product will not overflow into the sign
bit). If the remainder is negative, the trial quotient is too large, so it
is decremented, and the (full 64-bit) divisor is added to the correction.
This is repeated until the correction is non-negative, indicating that the
first quotient digit is correct. The process is then repeated using the
remainder as the dividend to develop the second 32-bit digit of the quotient.
The two digits are then concatenated for produce the final 64-bit value.
(See, "Divide-and-Correct Methods for Multiple Precision Division" by Marvin
L. Stein, Communications of the ACM, August 1964 for background.)
The microcoded single-precision division avoids overflows by right-shifting
some values, which leads to a loss of precision in the LSBs. We duplicate
@ -1365,7 +1382,7 @@ return 0;
}
/* Complement an unpacked mantissa.
/* Complement an unpacked mantissa.
An unpacked mantissa is passed as a "packed" number with a zero exponent.
The exponent increment, i.e., either zero or one, depending on whether a

View file

@ -1,6 +1,6 @@
/* hp2100_ipl.c: HP 2000 interprocessor link simulator
Copyright (c) 2002-2008, Robert M Supnik
Copyright (c) 2002-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,11 @@
IPLI, IPLO 12875A interprocessor link
07-Apr-11 JDB A failed STC may now be retried
28-Mar-11 JDB Tidied up signal handling
27-Mar-11 JDB Consolidated reporting of consecutive CRS signals
29-Oct-10 JDB Revised for new multi-card paradigm
26-Oct-10 JDB Changed I/O signal handler for revised signal model
07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach
15-Jul-08 JDB Revised EDT handler to refine completion delay conditions
09-Jul-08 JDB Revised ipl_boot to use ibl_copy
@ -62,6 +67,10 @@
#include "sim_sock.h"
#include "sim_tmxr.h"
typedef enum { ipli, iplo } CARD_INDEX; /* card index number */
#define CARD_COUNT 2 /* count of cards supported */
#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */
#define UNIT_V_ACTV (UNIT_V_UF + 1) /* making connection */
#define UNIT_V_ESTB (UNIT_V_UF + 2) /* connection established */
@ -83,19 +92,21 @@
extern DIB ptr_dib; /* need PTR select code for boot */
typedef enum { CIN, COUT } CARD; /* ipli/iplo selector */
int32 ipl_edtdelay = 1; /* EDT delay (msec) */
int32 ipl_ptime = 31; /* polling interval */
int32 ipl_stopioe = 0; /* stop on error */
int32 ipl_hold[2] = { 0 }; /* holding character */
FLIP_FLOP ipl_control [2] = { CLEAR, CLEAR };
FLIP_FLOP ipl_flag [2] = { CLEAR, CLEAR };
FLIP_FLOP ipl_flagbuf [2] = { CLEAR, CLEAR };
typedef struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
int32 hold; /* holding character */
} CARD_STATE;
CARD_STATE ipl [CARD_COUNT]; /* per-card state */
IOHANDLER iplio;
DEVICE ipli_dev, iplo_dev;
uint32 iplio (uint32 select_code, IOSIG signal, uint32 data);
t_stat ipl_svc (UNIT *uptr);
t_stat ipl_reset (DEVICE *dptr);
t_stat ipl_attach (UNIT *uptr, char *cptr);
@ -107,12 +118,37 @@ t_bool ipl_check_conn (UNIT *uptr);
/* Debug flags table */
DEBTAB ipl_deb[] = {
DEBTAB ipl_deb [] = {
{ "CMDS", DEB_CMDS },
{ "CPU", DEB_CPU },
{ "XFER", DEB_XFER },
{ NULL, 0 } };
/* Common structures */
DEVICE ipli_dev, iplo_dev;
static DEVICE *dptrs [] = { &ipli_dev, &iplo_dev };
UNIT ipl_unit [] = {
{ UDATA (&ipl_svc, UNIT_ATTABLE, 0) },
{ UDATA (&ipl_svc, UNIT_ATTABLE, 0) }
};
#define ipli_unit ipl_unit [ipli]
#define iplo_unit ipl_unit [iplo]
DIB ipl_dib [] = {
{ &iplio, IPLI, 0 },
{ &iplio, IPLO, 1 }
};
#define ipli_dib ipl_dib [ipli]
#define iplo_dib ipl_dib [iplo]
/* IPLI data structures
ipli_dev IPLI device descriptor
@ -120,36 +156,20 @@ DEBTAB ipl_deb[] = {
ipli_reg IPLI register list
*/
DIB ipl_dib[] = {
{ IPLI, &iplio },
{ IPLO, &iplio }
};
#define ipli_dib ipl_dib[0]
#define iplo_dib ipl_dib[1]
UNIT ipl_unit[] = {
{ UDATA (&ipl_svc, UNIT_ATTABLE, 0) },
{ UDATA (&ipl_svc, UNIT_ATTABLE, 0) }
};
#define ipli_unit ipl_unit[0]
#define iplo_unit ipl_unit[1]
REG ipli_reg[] = {
REG ipli_reg [] = {
{ ORDATA (IBUF, ipli_unit.IBUF, 16) },
{ ORDATA (OBUF, ipli_unit.OBUF, 16) },
{ FLDATA (CTL, ipl_control [CIN], 0) },
{ FLDATA (FLG, ipl_flag [CIN], 0) },
{ FLDATA (FBF, ipl_flagbuf [CIN], 0) },
{ ORDATA (HOLD, ipl_hold[CIN], 8) },
{ FLDATA (CTL, ipl [ipli].control, 0) },
{ FLDATA (FLG, ipl [ipli].flag, 0) },
{ FLDATA (FBF, ipl [ipli].flagbuf, 0) },
{ ORDATA (HOLD, ipl [ipli].hold, 8) },
{ DRDATA (TIME, ipl_ptime, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ipl_stopioe, 0) },
{ ORDATA (DEVNO, ipli_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, ipli_dib.select_code, 6), REG_HRO },
{ NULL }
};
MTAB ipl_mod[] = {
MTAB ipl_mod [] = {
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &ipl_setdiag },
{ UNIT_DIAG, 0, "link mode", "LINK", &ipl_setdiag },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT",
@ -175,15 +195,15 @@ DEVICE ipli_dev = {
iplo_reg IPLO register list
*/
REG iplo_reg[] = {
REG iplo_reg [] = {
{ ORDATA (IBUF, iplo_unit.IBUF, 16) },
{ ORDATA (OBUF, iplo_unit.OBUF, 16) },
{ FLDATA (CTL, ipl_control [COUT], 0) },
{ FLDATA (FLG, ipl_flag [COUT], 0) },
{ FLDATA (FBF, ipl_flagbuf [COUT], 0) },
{ ORDATA (HOLD, ipl_hold[COUT], 8) },
{ FLDATA (CTL, ipl [iplo].control, 0) },
{ FLDATA (FLG, ipl [iplo].flag, 0) },
{ FLDATA (FBF, ipl [iplo].flagbuf, 0) },
{ ORDATA (HOLD, ipl [iplo].hold, 8) },
{ DRDATA (TIME, ipl_ptime, 24), PV_LEFT },
{ ORDATA (DEVNO, iplo_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, iplo_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -206,11 +226,7 @@ DEVICE iplo_dev = {
Implementation notes:
1. Because this routine is written to handle two devices, the flip-flops are
stored in arrays, preventing the use of the "setstd" macros for PRL, IRQ,
and SRQ signals. The logic for all three is standard, however.
2. 2000 Access has a race condition that manifests itself by an apparently
1. 2000 Access has a race condition that manifests itself by an apparently
normal boot and operational system console but no PLEASE LOG IN response
to terminals connected to the multiplexer. The frequency of occurrence
is higher on multiprocessor host systems, where the SP and IOP instances
@ -259,157 +275,176 @@ DEVICE iplo_dev = {
sleep expiration, the SP still has not executed the STC/CLC. Still, in
testing, the incidence dropped dramatically, so the problem is much less
intrusive.
2. The operating manual for the 12920A Terminal Multiplexer says that "at
least 100 milliseconds of CLC 0s must be programmed" by systems employing
the multiplexer to ensure that the multiplexer resets. In practice, such
systems issue 128K CLC 0 instructions. As we provide debug logging of
IPL resets, a CRS counter is used to ensure that only one debug line is
printed in response to these 128K CRS invocations.
3. The STC handler may return "Unit not attached", "I/O error", or "No
connection on interprocessor link" status if the link fails or is
improperly configured. If the error is corrected, the operation may be
retried by resuming simulated execution.
*/
uint32 iplio (uint32 select_code, IOSIG signal, uint32 data)
uint32 iplio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const CARD card = (select_code == iplo_dib.devno); /* set card selector */
UNIT *const uptr = &(ipl_unit [card]); /* associated unit pointer */
const char uc = (card == CIN) ? 'I' : 'O'; /* identify unit for debug */
const DEVICE *dbdev = (card == CIN) ? &ipli_dev : &iplo_dev; /* identify device for debug */
const char *iotype[] = { "Status", "Command" };
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
const CARD_INDEX card = dibptr->card_index; /* set card selector */
UNIT *const uptr = &(ipl_unit [card]); /* associated unit pointer */
const char *iotype [] = { "Status", "Command" };
int32 sta;
char msg[2];
char msg [2];
static uint32 crs_count [CARD_COUNT] = { 0, 0 }; /* per-card cntrs for ioCRS repeat */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
if (crs_count [card] && !(signal_set & ioCRS)) { /* counting CRSes and not present? */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) /* report reset count */
fprintf (sim_deb, ">>%s cmds: [CRS] Control cleared %d times\n",
dptrs [card]->name, crs_count [card]);
case ioCLF: /* clear flag flip-flop */
ipl_flag [card] = ipl_flagbuf [card] = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
ipl_flag [card] = ipl_flagbuf [card] = SET;
break;
case ioSFC: /* skip if flag is clear */
setSKF (!ipl_flag [card]);
break;
case ioSFS: /* skip if flag is set */
setSKF (ipl_flag [card]);
break;
case ioIOI: /* I/O data input */
data = uptr->IBUF; /* get return data */
if (DEBUG_PRJ (dbdev, DEB_CPU))
fprintf (sim_deb, ">>IPL%c LIx: %s = %06o\n", uc, iotype [card ^ 1], data);
break;
case ioIOO: /* I/O data output */
uptr->OBUF = data;
if (DEBUG_PRJ (dbdev, DEB_CPU))
fprintf (sim_deb, ">>IPL%c OTx: %s = %06o\n", uc, iotype [card], data);
break;
case ioPOPIO: /* power-on preset to I/O */
ipl_flag [card] = ipl_flagbuf [card] = SET; /* set flag buffer and flag */
uptr->OBUF = 0; /* clear output buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
ipl_control [card] = CLEAR; /* clear control */
if (DEBUG_PRJ (dbdev, DEB_CMDS))
fprintf (sim_deb, ">>IPL%c CRS: Control cleared\n", uc);
break;
case ioCLC: /* clear control flip-flop */
ipl_control [card] = CLEAR; /* clear ctl */
if (DEBUG_PRJ (dbdev, DEB_CMDS))
fprintf (sim_deb, ">>IPL%c CLC: Control cleared\n", uc);
break;
case ioSTC: /* set control flip-flop */
ipl_control [card] = SET; /* set ctl */
if (DEBUG_PRJ (dbdev, DEB_CMDS))
fprintf (sim_deb, ">>IPL%c STC: Control set\n", uc);
if (uptr->flags & UNIT_ATT) { /* attached? */
if ((uptr->flags & UNIT_ESTB) == 0) /* established? */
if (!ipl_check_conn (uptr)) { /* not established? */
data = STOP_NOCONN << IOT_V_REASON; /* lose */
break;
}
msg[0] = (uptr->OBUF >> 8) & 0377;
msg[1] = uptr->OBUF & 0377;
sta = sim_write_sock (uptr->DSOCKET, msg, 2);
if (DEBUG_PRJ (dbdev, DEB_XFER))
fprintf (sim_deb,
">>IPL%c STC: Socket write = %06o, status = %d\n",
uc, uptr->OBUF, sta);
if (sta == SOCKET_ERROR) {
printf ("IPL: socket write error\n");
data = SCPE_IOERR << IOT_V_REASON;
break;
}
sim_os_sleep (0);
}
else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */
ipl_unit [card ^ 1].IBUF = uptr->OBUF; /* output to other */
iplio (ipl_dib [card ^ 1].devno, ioENF, 0); /* set other flag */
}
else
data = SCPE_UNATT << IOT_V_REASON; /* lose */
break;
case ioEDT: /* end data transfer */
if ((cpu_unit.flags & UNIT_IOP) && /* are we the IOP? */
((IOSIG) data == ioIOO) && (card == CIN)) { /* and doing output on input card? */
if (DEBUG_PRJ (dbdev, DEB_CMDS))
fprintf (sim_deb,
">>IPL%c EDT: Delaying DMA completion interrupt for %d msec\n",
uc, ipl_edtdelay);
sim_os_ms_sleep (ipl_edtdelay); /* delay completion */
}
break;
case ioSIR: /* set interrupt request */
setPRL (select_code, !(ipl_control [card] & ipl_flag [card]));
setIRQ (select_code, ipl_control [card] & ipl_flag [card] & ipl_flagbuf [card]);
setSRQ (select_code, ipl_flag [card]);
break;
case ioIAK: /* interrupt acknowledge */
ipl_flagbuf [card] = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
crs_count [card] = 0; /* clear counter */
}
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
if (signal > ioCLF) /* multiple signals? */
iplio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
iplio (select_code, ioSIR, 0); /* set interrupt request */
switch (signal) { /* dispatch I/O signal */
return data;
case ioCLF: /* clear flag flip-flop */
ipl [card].flag = ipl [card].flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
ipl [card].flag = ipl [card].flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (ipl [card]);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (ipl [card]);
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, uptr->IBUF); /* get return data */
if (DEBUG_PRJ (dptrs [card], DEB_CPU))
fprintf (sim_deb, ">>%s cpu: [LIx] %s = %06o\n", dptrs [card]->name, iotype [card ^ 1], uptr->IBUF);
break;
case ioIOO: /* I/O data output */
uptr->OBUF = IODATA (stat_data); /* clear supplied status */
if (DEBUG_PRJ (dptrs [card], DEB_CPU))
fprintf (sim_deb, ">>%s cpu: [OTx] %s = %06o\n", dptrs [card]->name, iotype [card], uptr->OBUF);
break;
case ioPOPIO: /* power-on preset to I/O */
ipl [card].flag = ipl [card].flagbuf = SET; /* set flag buffer and flag */
uptr->OBUF = 0; /* clear output buffer */
break;
case ioCRS: /* control reset */
if (crs_count [card] == 0) /* first reset? */
ipl [card].control = CLEAR; /* clear control */
crs_count [card] = crs_count [card] + 1; /* increment count */
break;
case ioCLC: /* clear control flip-flop */
ipl [card].control = CLEAR; /* clear ctl */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb, ">>%s cmds: [CLC] Control cleared\n", dptrs [card]->name);
break;
case ioSTC: /* set control flip-flop */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb, ">>%s cmds: [STC] Control set\n", dptrs [card]->name);
if (uptr->flags & UNIT_ATT) { /* attached? */
if (!ipl_check_conn (uptr)) /* not established? */
return IORETURN (STOP_NOCONN, 0); /* lose */
msg [0] = (uptr->OBUF >> 8) & 0377;
msg [1] = uptr->OBUF & 0377;
sta = sim_write_sock (uptr->DSOCKET, msg, 2);
if (DEBUG_PRJ (dptrs [card], DEB_XFER))
fprintf (sim_deb,
">>%s xfer: [STC] Socket write = %06o, status = %d\n",
dptrs [card]->name, uptr->OBUF, sta);
if (sta == SOCKET_ERROR) {
printf ("IPL socket write error\n");
return IORETURN (SCPE_IOERR, 0);
}
ipl [card].control = SET; /* set ctl */
sim_os_sleep (0);
}
else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */
ipl [card].control = SET; /* set ctl */
ipl_unit [card ^ 1].IBUF = uptr->OBUF; /* output to other */
iplio ((DIB *) dptrs [card ^ 1]->ctxt, ioENF, 0); /* set other flag */
}
else
return IORETURN (SCPE_UNATT, 0); /* lose */
break;
case ioEDT: /* end data transfer */
if ((cpu_unit.flags & UNIT_IOP) && /* are we the IOP? */
(signal_set & ioIOO) && /* and doing output? */
(card == ipli)) { /* on the input card? */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb,
">>%s cmds: [EDT] Delaying DMA completion interrupt for %d msec\n",
dptrs [card]->name, ipl_edtdelay);
sim_os_ms_sleep (ipl_edtdelay); /* delay completion */
}
break;
case ioSIR: /* set interrupt request */
setstdPRL (ipl [card]);
setstdIRQ (ipl [card]);
setstdSRQ (ipl [card]);
break;
case ioIAK: /* interrupt acknowledge */
ipl [card].flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
return stat_data;
}
@ -417,46 +452,46 @@ return data;
t_stat ipl_svc (UNIT *uptr)
{
CARD card;
CARD_INDEX card;
int32 nb;
char msg[2], uc;
DEVICE *dbdev; /* device ptr for debug */
char msg [2];
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return SCPE_OK;
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* not attached? */
sim_activate (uptr, ipl_ptime); /* reactivate */
if ((uptr->flags & UNIT_ESTB) == 0) /* not established? */
if (!ipl_check_conn (uptr)) /* check for conn */
return SCPE_OK; /* cot connected */
if (!ipl_check_conn (uptr)) /* check for conn */
return SCPE_OK; /* not connected */
nb = sim_read_sock (uptr->DSOCKET, msg, ((uptr->flags & UNIT_HOLD)? 1: 2));
if (nb < 0) { /* connection closed? */
printf ("IPL: socket read error\n");
printf ("IPL socket read error\n");
return SCPE_IOERR;
}
if (nb == 0) return SCPE_OK; /* no data? */
else if (nb == 0) /* no data? */
return SCPE_OK;
card = (uptr == &iplo_unit); /* set card selector */
if (uptr->flags & UNIT_HOLD) { /* holdover byte? */
uptr->IBUF = (ipl_hold[card] << 8) | (((int32) msg[0]) & 0377);
uptr->IBUF = (ipl [card].hold << 8) | (((int32) msg [0]) & 0377);
uptr->flags = uptr->flags & ~UNIT_HOLD;
}
else if (nb == 1) {
ipl_hold[card] = ((int32) msg[0]) & 0377;
ipl [card].hold = ((int32) msg [0]) & 0377;
uptr->flags = uptr->flags | UNIT_HOLD;
}
else uptr->IBUF = ((((int32) msg[0]) & 0377) << 8) |
(((int32) msg[1]) & 0377);
else
uptr->IBUF = ((((int32) msg [0]) & 0377) << 8) | (((int32) msg [1]) & 0377);
iplio (ipl_dib [card].devno, ioENF, 0); /* set flag */
iplio ((DIB *) dptrs [card]->ctxt, ioENF, 0); /* set flag */
uc = (card == CIN) ? 'I' : 'O'; /* identify unit for debug */
dbdev = (card == CIN) ? &ipli_dev : &iplo_dev; /* identify device for debug */
if (DEBUG_PRJ (dbdev, DEB_XFER))
fprintf (sim_deb, ">>IPL%c svc: Socket read = %06o, status = %d\n",
uc, uptr->IBUF, nb);
if (DEBUG_PRJ (dptrs [card], DEB_XFER))
fprintf (sim_deb, ">>%s xfer: Socket read = %06o, status = %d\n",
dptrs [card]->name, uptr->IBUF, nb);
return SCPE_OK;
}
@ -466,15 +501,23 @@ t_bool ipl_check_conn (UNIT *uptr)
{
SOCKET sock;
if (uptr->flags & UNIT_ESTB) return TRUE; /* established? */
if (uptr->flags & UNIT_ESTB) /* established? */
return TRUE;
if (uptr->flags & UNIT_ACTV) { /* active connect? */
if (sim_check_conn (uptr->DSOCKET, 0) <= 0) return FALSE;
if (sim_check_conn (uptr->DSOCKET, 0) <= 0)
return FALSE;
}
else {
sock = sim_accept_conn (uptr->LSOCKET, NULL); /* poll connect */
if (sock == INVALID_SOCKET) return FALSE; /* got a live one? */
if (sock == INVALID_SOCKET) /* got a live one? */
return FALSE;
uptr->DSOCKET = sock; /* save data socket */
}
uptr->flags = uptr->flags | UNIT_ESTB; /* conn established */
return TRUE;
}
@ -493,17 +536,15 @@ return TRUE;
t_stat ipl_reset (DEVICE *dptr)
{
UNIT *uptr = dptr->units;
DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */
CARD_INDEX card = dibptr->card_index; /* card number */
hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &ipli_dev)? &iplo_dev: &ipli_dev);
hp_enbdis_pair (dptr, dptrs [card ^ 1]); /* make pair cons */
if (sim_switches & SWMASK ('P')) /* PON reset? */
if (sim_switches & SWMASK ('P')) /* initialization reset? */
uptr->IBUF = uptr->OBUF = 0; /* clr buffers */
if (dptr == &ipli_dev) /* input channel reset? */
iplio (ipli_dib.devno, ioPOPIO, 0); /* send POPIO signal */
else /* output channel reset */
iplio (iplo_dib.devno, ioPOPIO, 0); /* send POPIO signal */
IOPRESET (dibptr); /* PRESET device (does not use PON) */
if (uptr->flags & UNIT_ATT) /* socket attached? */
sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */
@ -529,31 +570,39 @@ char *tptr;
t_stat r;
r = get_ipaddr (cptr, &ipa, &ipp);
if ((r != SCPE_OK) || (ipp == 0)) return SCPE_ARG;
if ((r != SCPE_OK) || (ipp == 0))
return SCPE_ARG;
oldf = uptr->flags;
if (oldf & UNIT_ATT) ipl_detach (uptr);
if (oldf & UNIT_ATT)
ipl_detach (uptr);
if ((sim_switches & SWMASK ('C')) ||
((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) {
if (ipa == 0) ipa = 0x7F000001;
if (ipa == 0)
ipa = 0x7F000001;
newsock = sim_connect_sock (ipa, ipp);
if (newsock == INVALID_SOCKET) return SCPE_IOERR;
if (newsock == INVALID_SOCKET)
return SCPE_IOERR;
printf ("Connecting to IP address %d.%d.%d.%d, port %d\n",
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
if (sim_log) fprintf (sim_log,
"Connecting to IP address %d.%d.%d.%d, port %d\n",
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
if (sim_log)
fprintf (sim_log,
"Connecting to IP address %d.%d.%d.%d, port %d\n",
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
uptr->flags = uptr->flags | UNIT_ACTV;
uptr->LSOCKET = 0;
uptr->DSOCKET = newsock;
}
else {
if (ipa != 0) return SCPE_ARG;
if (ipa != 0)
return SCPE_ARG;
newsock = sim_master_sock (ipp);
if (newsock == INVALID_SOCKET) return SCPE_IOERR;
if (newsock == INVALID_SOCKET)
return SCPE_IOERR;
printf ("Listening on port %d\n", ipp);
if (sim_log) fprintf (sim_log, "Listening on port %d\n", ipp);
if (sim_log)
fprintf (sim_log, "Listening on port %d\n", ipp);
uptr->flags = uptr->flags & ~UNIT_ACTV;
uptr->LSOCKET = newsock;
uptr->DSOCKET = 0;
@ -570,12 +619,14 @@ uptr->filename = tptr; /* save */
sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */
if (sim_switches & SWMASK ('W')) { /* wait? */
for (i = 0; i < 30; i++) { /* check for 30 sec */
if (t = ipl_check_conn (uptr)) break; /* established? */
if (t = ipl_check_conn (uptr)) /* established? */
break;
if ((i % 10) == 0) /* status every 10 sec */
printf ("Waiting for connnection\n");
sim_os_sleep (1); /* sleep 1 sec */
}
if (t) printf ("Connection established\n");
if (t)
printf ("Connection established\n");
}
return SCPE_OK;
}
@ -584,13 +635,18 @@ return SCPE_OK;
t_stat ipl_detach (UNIT *uptr)
{
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */
if (uptr->flags & UNIT_ACTV) sim_close_sock (uptr->DSOCKET, 1);
if (!(uptr->flags & UNIT_ATT)) /* attached? */
return SCPE_OK;
if (uptr->flags & UNIT_ACTV)
sim_close_sock (uptr->DSOCKET, 1);
else {
if (uptr->flags & UNIT_ESTB) /* if established, */
sim_close_sock (uptr->DSOCKET, 0); /* close data socket */
sim_close_sock (uptr->LSOCKET, 1); /* closen listen socket */
}
free (uptr->filename); /* free string */
uptr->filename = NULL;
uptr->LSOCKET = 0;
@ -604,9 +660,12 @@ return SCPE_OK;
t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (cptr) return SCPE_ARG;
if (((uptr->flags & UNIT_ATT) == 0) || (uptr->flags & UNIT_ACTV) ||
((uptr->flags & UNIT_ESTB) == 0)) return SCPE_NOFNC;
if (cptr)
return SCPE_ARG;
if (((uptr->flags & UNIT_ATT) == 0) ||
(uptr->flags & UNIT_ACTV) ||
((uptr->flags & UNIT_ESTB) == 0))
return SCPE_NOFNC;
sim_close_sock (uptr->DSOCKET, 0);
uptr->DSOCKET = 0;
uptr->flags = uptr->flags & ~UNIT_ESTB;
@ -705,14 +764,14 @@ static const BOOT_ROM ipl_rom = {
t_stat ipl_boot (int32 unitno, DEVICE *dptr)
{
const int32 devi = ipli_dib.devno;
const int32 devp = ptr_dib.devno;
const int32 devi = ipli_dib.select_code;
const int32 devp = ptr_dib.select_code;
ibl_copy (ipl_rom, devi); /* copy bootstrap to memory */
SR = (devi << IBL_V_DEV) | devp; /* set SR */
WritePW (PC + MAX_BASE, (~PC + 1) & DMASK); /* fix ups */
WritePW (PC + IPL_PNTR, ipl_rom[IPL_PNTR] | PC);
WritePW (PC + PTR_PNTR, ipl_rom[PTR_PNTR] | PC);
WritePW (PC + IPL_PNTR, ipl_rom [IPL_PNTR] | PC);
WritePW (PC + PTR_PNTR, ipl_rom [PTR_PNTR] | PC);
WritePW (PC + IPL_DEVA, devi);
WritePW (PC + PTR_DEVA, devp);
return SCPE_OK;

View file

@ -1,6 +1,6 @@
/* hp2100_lps.c: HP 2100 12653A/2767 line printer simulator
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,10 @@
LPS 12653A 2767 line printer
12566B microcircuit interface with loopback diagnostic connector
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
Revised detection of CLC at last DMA cycle
19-Oct-10 JDB Corrected 12566B (DIAG mode) jumper settings
26-Jun-08 JDB Rewrote device I/O to model backplane signals
10-May-07 RMS Added UNIT_TEXT flag
11-Jan-07 JDB CLC cancels I/O event if DIAG (jumper W9 in "A" pos)
@ -58,16 +62,24 @@
This module simulates two different devices. In "diagnostic mode," it
simulates a 12566B microcircuit interface card with a loopback connector and
the jumpers set as required for execution of the General Purpose Register
diagnostic. In non-diagnostic mode, it simulates a 12653A line printer
interface card and a 2767 line printer.
simulates a 12566B microcircuit interface card with a loopback connector. In
non-diagnostic mode, it simulates a 12653A line printer interface card and a
2767 line printer.
In diagnostic mode, the 12566B interface has a loopback connector that ties
the output data lines to the input data lines and the device command output
to the device flag input. In addition, card configuration jumpers are set as
needed for the diagnostic programs.
Jumper settings depend on the CPU model. For the 2114/15/16 CPUs, jumper W1
is installed in position B and jumper W2 in position C. In these positions,
the card flag sets two instructions after the STC, allowing DMA to steal
every third cycle. For the 2100 and 1000 CPUs, jumper W1 is installed in
position C and jumper W2 in position B. In these positions, the card flag
sets one instruction after the STC, allowing DMA to steal every other cycle.
For all CPUs, jumpers W3 and W4 are installed in position B, W5-W8 are
installed, and W9 is installed in position A.
The 12566B interface with the loopback connector ties the device command
output to the device flag input. Setting control therefore causes device
flag to set almost immediately. Device command is active only during that
interim. Under simulation, the loopback occurs within the STC handler, and
CMD is never set.
The 2767 impact printer has a rotating drum with 80 columns of 64 raised
characters. ASCII codes 32 through 95 (SPACE through "_") form the print
@ -144,9 +156,11 @@
#define UNIT_POWEROFF (1 << UNIT_V_POWEROFF)
#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE)
FLIP_FLOP lps_control = CLEAR;
FLIP_FLOP lps_flag = CLEAR;
FLIP_FLOP lps_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} lps = { CLEAR, CLEAR, CLEAR };
int32 lps_ccnt = 0; /* character count */
int32 lps_lcnt = 0; /* line count */
@ -190,7 +204,9 @@ const TIMESET lps_times[2] = {
};
DEVICE lps_dev;
uint32 lpsio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER lpsio;
t_stat lps_svc (UNIT *uptr);
t_stat lps_reset (DEVICE *dptr);
t_stat lps_restart (UNIT *uptr, int32 value, char *cptr, void *desc);
@ -207,7 +223,7 @@ t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc);
lps_reg LPS register list
*/
DIB lps_dib = { LPS, &lpsio };
DIB lps_dib = { &lpsio, LPS };
UNIT lps_unit = {
UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0)
@ -217,9 +233,9 @@ REG lps_reg[] = {
{ ORDATA (BUF, lps_unit.buf, 16) },
{ ORDATA (STA, lps_sta, 16) },
{ ORDATA (POWER, lps_power, 2), REG_RO },
{ FLDATA (CTL, lps_control, 0) },
{ FLDATA (FLG, lps_flag, 0) },
{ FLDATA (FBF, lps_flagbuf, 0) },
{ FLDATA (CTL, lps.control, 0) },
{ FLDATA (FLG, lps.flag, 0) },
{ FLDATA (FBF, lps.flagbuf, 0) },
{ DRDATA (CCNT, lps_ccnt, 7), PV_LEFT },
{ DRDATA (LCNT, lps_lcnt, 7), PV_LEFT },
{ DRDATA (POS, lps_unit.pos, T_ADDR_W), PV_LEFT },
@ -229,7 +245,7 @@ REG lps_reg[] = {
{ DRDATA (RTIME, lps_rtime, 24), PV_LEFT },
{ FLDATA (TIMING, lps_timing, 0), REG_HRO },
{ FLDATA (STOP_IOE, lps_stopioe, 0) },
{ ORDATA (DEVNO, lps_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, lps_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -260,164 +276,174 @@ DEVICE lps_dev = {
};
/* I/O signal handler */
/* I/O signal handler.
uint32 lpsio (uint32 select_code, IOSIG signal, uint32 data)
Implementation note:
1. The 211x DMA diagnostic expects that a programmed STC and CLC sequence
will set the card flag in two instructions, whereas a last-DMA-cycle
assertion of STC and CLC simultaneously will not.
*/
uint32 lpsio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const t_bool clf = (signal > ioCLF);
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
int32 sched;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
lps_flag = lps_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
lps.flag = lps.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
lps_flag = lps_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
lps.flag = lps.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (lps);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (lps);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (lps);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (lps);
break;
case ioIOI: /* I/O data input */
if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */
if (lps_power == LPS_ON) { /* power on? */
if (((lps_unit.flags & UNIT_ATT) == 0) || /* paper out? */
(lps_unit.flags & UNIT_OFFLINE) || /* offline? */
sim_is_active (&lps_unit)) lps_sta = LPS_BUSY;
case ioIOI: /* I/O data input */
if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */
if (lps_power == LPS_ON) { /* power on? */
if (((lps_unit.flags & UNIT_ATT) == 0) || /* paper out? */
(lps_unit.flags & UNIT_OFFLINE) || /* offline? */
sim_is_active (&lps_unit)) lps_sta = LPS_BUSY;
else
lps_sta = 0;
}
else
lps_sta = LPS_PWROFF;
}
data = lps_sta; /* diag, rtn status */
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", data);
break;
case ioIOO: /* I/O data output */
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS OTx: Character %06o output\n", data);
lps_unit.buf = data;
break;
case ioPOPIO: /* power-on preset to I/O */
lps_flag = lps_flagbuf = SET; /* set flag and flag buffer */
lps_unit.buf = 0; /* clear output buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
lps_control = CLEAR; /* clear control */
sim_cancel (&lps_unit); /* deactivate unit */
break;
case ioCLC: /* clear control flip-flop */
lps_control = CLEAR;
if ((lps_unit.flags & UNIT_DIAG) && clf) /* diagnostic mode and clearing flag? */
sim_cancel (&lps_unit); /* prevent FLG/SRQ */
break;
case ioSTC: /* set control flip-flop */
lps_control = SET; /* set control */
if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */
lps_sta = lps_unit.buf; /* loop back data */
sim_activate (&lps_unit, 2); /* schedule flag */
}
else { /* real lpt, sched */
if (DEBUG_PRS (lps_dev)) fprintf (sim_deb,
">>LPS STC: Character %06o scheduled for line %d, column %d, ",
lps_unit.buf, lps_lcnt + 1, lps_ccnt + 1);
if ((lps_unit.buf != '\f') &&
(lps_unit.buf != '\n') &&
(lps_unit.buf != '\r')) { /* normal char */
lps_ccnt = lps_ccnt + 1; /* incr char counter */
if (lps_ccnt % LPS_ZONECNT == 0) /* end of zone? */
sched = lps_ptime; /* print zone */
else
sched = lps_ctime; /* xfer char */
}
else { /* print cmd */
if (lps_ccnt % LPS_ZONECNT == 0) /* last zone printed? */
sched = lps_ctime; /* yes, so just char time */
else
sched = lps_ptime; /* no, so print needed */
lps_ccnt = 0; /* reset char counter */
if (lps_unit.buf == '\n') { /* line advance */
lps_lcnt = (lps_lcnt + 1) % LPS_PAGELNT;
if (lps_lcnt > 0)
sched = sched + lps_stime;
else
sched = sched + /* allow for perf skip */
lps_stime * (LPS_FORMLNT - LPS_PAGELNT);
lps_sta = 0;
}
else if (lps_unit.buf == '\f') { /* form advance */
sched = sched + lps_stime * (LPS_FORMLNT - lps_lcnt);
lps_lcnt = 0;
}
else
lps_sta = LPS_PWROFF;
}
sim_activate (&lps_unit, sched);
stat_data = IORETURN (SCPE_OK, lps_sta); /* diag, rtn status */
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, "time = %d\n", sched);
}
break;
fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", lps_sta);
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, lps); /* set standard PRL signal */
setstdIRQ (select_code, lps); /* set standard IRQ signal */
setstdSRQ (select_code, lps); /* set standard SRQ signal */
break;
case ioIOO: /* I/O data output */
lps_unit.buf = IODATA (stat_data);
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS OTx: Character %06o output\n", lps_unit.buf);
break;
case ioIAK: /* interrupt acknowledge */
lps_flagbuf = CLEAR;
break;
case ioPOPIO: /* power-on preset to I/O */
lps.flag = lps.flagbuf = SET; /* set flag and flag buffer */
lps_unit.buf = 0; /* clear output buffer */
break;
default: /* all other signals */
break; /* are ignored */
case ioCRS: /* control reset */
lps.control = CLEAR; /* clear control */
sim_cancel (&lps_unit); /* deactivate unit */
break;
case ioCLC: /* clear control flip-flop */
lps.control = CLEAR;
break;
case ioSTC: /* set control flip-flop */
lps.control = SET; /* set control */
if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */
lps_sta = lps_unit.buf; /* loop back data */
if (!(signal_set & ioCLC)) /* CLC not asserted simultaneously? */
if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2114/15/16 CPU? */
sim_activate (&lps_unit, 3); /* schedule flag after two instructions */
else /* 2100 or 1000 */
sim_activate (&lps_unit, 2); /* schedule flag after next instruction */
}
else { /* real lpt, sched */
if (DEBUG_PRS (lps_dev)) fprintf (sim_deb,
">>LPS STC: Character %06o scheduled for line %d, column %d, ",
lps_unit.buf, lps_lcnt + 1, lps_ccnt + 1);
if ((lps_unit.buf != '\f') &&
(lps_unit.buf != '\n') &&
(lps_unit.buf != '\r')) { /* normal char */
lps_ccnt = lps_ccnt + 1; /* incr char counter */
if (lps_ccnt % LPS_ZONECNT == 0) /* end of zone? */
sched = lps_ptime; /* print zone */
else
sched = lps_ctime; /* xfer char */
}
else { /* print cmd */
if (lps_ccnt % LPS_ZONECNT == 0) /* last zone printed? */
sched = lps_ctime; /* yes, so just char time */
else
sched = lps_ptime; /* no, so print needed */
lps_ccnt = 0; /* reset char counter */
if (lps_unit.buf == '\n') { /* line advance */
lps_lcnt = (lps_lcnt + 1) % LPS_PAGELNT;
if (lps_lcnt > 0)
sched = sched + lps_stime;
else
sched = sched + /* allow for perf skip */
lps_stime * (LPS_FORMLNT - LPS_PAGELNT);
}
else if (lps_unit.buf == '\f') { /* form advance */
sched = sched + lps_stime * (LPS_FORMLNT - lps_lcnt);
lps_lcnt = 0;
}
}
sim_activate (&lps_unit, sched);
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, "time = %d\n", sched);
}
break;
case ioSIR: /* set interrupt request */
setstdPRL (lps); /* set standard PRL signal */
setstdIRQ (lps); /* set standard IRQ signal */
setstdSRQ (lps); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
lps.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
lpsio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
lpsio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -435,17 +461,17 @@ if (lps_power == LPS_TURNING_ON) { /* printer warmed up? */
return SCPE_OK; /* done */
}
if (uptr->flags & UNIT_DIAG) { /* diagnostic? */
lpsio (lps_dib.devno, ioENF, 0); /* set flag */
lpsio (&lps_dib, ioENF, 0); /* set flag */
return SCPE_OK; /* done */
}
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lps_stopioe, SCPE_UNATT);
return IOERROR (lps_stopioe, SCPE_UNATT);
else if (uptr->flags & UNIT_OFFLINE) /* offline? */
return IORETURN (lps_stopioe, STOP_OFFLINE);
return IOERROR (lps_stopioe, STOP_OFFLINE);
else if (uptr->flags & UNIT_POWEROFF) /* powered off? */
return IORETURN (lps_stopioe, STOP_PWROFF);
return IOERROR (lps_stopioe, STOP_PWROFF);
lpsio (lps_dib.devno, ioENF, 0); /* set flag */
lpsio (&lps_dib, ioENF, 0); /* set flag */
if (((c < ' ') || (c > '_')) && /* non-printing char? */
(c != '\f') && (c != '\n') && (c != '\r')) {
@ -482,12 +508,12 @@ return SCPE_OK;
t_stat lps_reset (DEVICE *dptr)
{
if (sim_switches & SWMASK ('P')) { /* PON reset? */
if (sim_switches & SWMASK ('P')) { /* power-on reset? */
lps_power = LPS_ON; /* power is on */
lps_set_timing (NULL, lps_timing, NULL, NULL); /* init timing set */
}
lpsio (lps_dib.devno, ioPOPIO, 0); /* send POPIO signal */
IOPRESET (&lps_dib); /* PRESET device (does not use PON) */
lps_sta = 0; /* clear status */
sim_cancel (&lps_unit); /* deactivate unit */
@ -511,7 +537,7 @@ return SCPE_OK;
t_stat lps_restart (UNIT *uptr, int32 value, char *cptr, void *desc)
{
if (lps_control && !sim_is_active (uptr))
if (lps.control && !sim_is_active (uptr))
sim_activate (uptr, 0); /* reschedule I/O */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* hp2100_lpt.c: HP 2100 12845B line printer simulator
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
LPT 12845B 2607 line printer
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
26-Jun-08 JDB Rewrote device I/O to model backplane signals
Changed CTIME register width to match documentation
22-Jan-07 RMS Added UNIT_TEXT flag
@ -89,9 +91,11 @@
#define UNIT_POWEROFF (1 << UNIT_V_POWEROFF)
#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE)
FLIP_FLOP lpt_control = CLEAR;
FLIP_FLOP lpt_flag = CLEAR;
FLIP_FLOP lpt_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} lpt = { CLEAR, CLEAR, CLEAR };
int32 lpt_ctime = 4; /* char time */
int32 lpt_ptime = 10000; /* print time */
@ -102,7 +106,9 @@ static int32 lpt_cct[8] = {
};
DEVICE lpt_dev;
uint32 lptio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER lptio;
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_restart (UNIT *uptr, int32 value, char *cptr, void *desc);
@ -115,7 +121,7 @@ t_stat lpt_attach (UNIT *uptr, char *cptr);
lpt_reg LPT register list
*/
DIB lpt_dib = { LPT, &lptio };
DIB lpt_dib = { &lptio, LPT };
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0)
@ -123,15 +129,15 @@ UNIT lpt_unit = {
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 7) },
{ FLDATA (CTL, lpt_control, 0) },
{ FLDATA (FLG, lpt_flag, 0) },
{ FLDATA (FBF, lpt_flagbuf, 0) },
{ FLDATA (CTL, lpt.control, 0) },
{ FLDATA (FLG, lpt.flag, 0) },
{ FLDATA (FBF, lpt.flagbuf, 0) },
{ DRDATA (LCNT, lpt_lcnt, 7) },
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (CTIME, lpt_ctime, 24), PV_LEFT },
{ DRDATA (PTIME, lpt_ptime, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ ORDATA (DEVNO, lpt_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, lpt_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -156,101 +162,102 @@ DEVICE lpt_dev = {
/* I/O signal handler */
uint32 lptio (uint32 select_code, IOSIG signal, uint32 data)
uint32 lptio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
uint16 data;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
lpt_flag = lpt_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
lpt.flag = lpt.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
lpt_flag = lpt_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
lpt.flag = lpt.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (lpt);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (lpt);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (lpt);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (lpt);
break;
case ioIOI: /* I/O data input */
if (lpt_unit.flags & UNIT_POWEROFF) /* power off? */
data = LPT_PWROFF;
case ioIOI: /* I/O data input */
data = 0;
else if (!(lpt_unit.flags & UNIT_OFFLINE)) { /* online? */
if (lpt_unit.flags & UNIT_ATT) { /* paper loaded? */
data = LPT_RDY;
if (!sim_is_active (&lpt_unit)) /* printer busy? */
data = data | LPT_NBSY;
if (lpt_unit.flags & UNIT_POWEROFF) /* power off? */
data = LPT_PWROFF;
else if (!(lpt_unit.flags & UNIT_OFFLINE)) { /* online? */
if (lpt_unit.flags & UNIT_ATT) { /* paper loaded? */
data = LPT_RDY;
if (!sim_is_active (&lpt_unit)) /* printer busy? */
data = data | LPT_NBSY;
}
else if (lpt_lcnt == LPT_PAGELNT - 1) /* paper out, at BOF? */
data = LPT_PAPO;
}
else if (lpt_lcnt == LPT_PAGELNT - 1) /* paper out, at BOF? */
data = LPT_PAPO;
}
else
data = 0;
break;
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
break;
case ioIOO: /* I/O data output */
lpt_unit.buf = data & (LPT_CTL | 0177);
break;
case ioIOO: /* I/O data output */
lpt_unit.buf = IODATA (stat_data) & (LPT_CTL | 0177);
break;
case ioPOPIO: /* power-on preset to I/O */
lpt_flag = lpt_flagbuf = SET; /* set flag and flag buffer */
lpt_unit.buf = 0; /* clear output buffer */
/* fall into CRS handler */
case ioPOPIO: /* power-on preset to I/O */
lpt.flag = lpt.flagbuf = SET; /* set flag and flag buffer */
lpt_unit.buf = 0; /* clear output buffer */
break;
case ioCRS: /* control reset */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
lpt_control = CLEAR;
break;
case ioCRS: /* control reset */
case ioCLC: /* clear control flip-flop */
lpt.control = CLEAR;
break;
case ioSTC: /* set control flip-flop */
lpt_control = SET;
sim_activate (&lpt_unit, /* schedule op */
(lpt_unit.buf & LPT_CTL)? lpt_ptime: lpt_ctime);
break;
case ioSTC: /* set control flip-flop */
lpt.control = SET;
sim_activate (&lpt_unit, /* schedule op */
(lpt_unit.buf & LPT_CTL)? lpt_ptime: lpt_ctime);
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, lpt); /* set standard PRL signal */
setstdIRQ (select_code, lpt); /* set standard IRQ signal */
setstdSRQ (select_code, lpt); /* set standard SRQ signal */
break;
case ioSIR: /* set interrupt request */
setstdPRL (lpt); /* set standard PRL signal */
setstdIRQ (lpt); /* set standard IRQ signal */
setstdSRQ (lpt); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
lpt_flagbuf = CLEAR;
break;
case ioIAK: /* interrupt acknowledge */
lpt.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
lptio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
lptio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -261,13 +268,13 @@ t_stat lpt_svc (UNIT *uptr)
int32 i, skip, chan;
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
return IOERROR (lpt_stopioe, SCPE_UNATT);
else if (uptr->flags & UNIT_OFFLINE) /* offline? */
return IORETURN (lpt_stopioe, STOP_OFFLINE);
return IOERROR (lpt_stopioe, STOP_OFFLINE);
else if (uptr->flags & UNIT_POWEROFF) /* powered off? */
return IORETURN (lpt_stopioe, STOP_PWROFF);
return IOERROR (lpt_stopioe, STOP_PWROFF);
lptio (lpt_dib.devno, ioENF, 0); /* set flag */
lptio (&lpt_dib, ioENF, 0); /* set flag */
if (uptr->buf & LPT_CTL) { /* control word? */
if (uptr->buf & LPT_CHAN) {
@ -302,7 +309,7 @@ return SCPE_OK;
t_stat lpt_reset (DEVICE *dptr)
{
lptio (lpt_dib.devno, ioPOPIO, 0); /* send POPIO signal */
IOPRESET (&lpt_dib); /* PRESET device (does not use PON) */
sim_cancel (&lpt_unit); /* deactivate unit */
return SCPE_OK;
@ -325,7 +332,7 @@ return SCPE_OK;
t_stat lpt_restart (UNIT *uptr, int32 value, char *cptr, void *desc)
{
if (lpt_control && !sim_is_active (uptr))
if (lpt.control && !sim_is_active (uptr))
sim_activate (uptr, 0); /* reschedule I/O */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* hp2100_mpx.c: HP 12792C eight-channel asynchronous multiplexer simulator
Copyright (c) 2008, J. David Bryan
Copyright (c) 2008-2011, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
MPX 12792C 8-channel multiplexer card
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
25-Nov-08 JDB Revised for new multiplexer library SHOW routines
14-Nov-08 JDB Cleaned up VC++ size mismatch warnings for zero assignments
03-Oct-08 JDB Fixed logic for ENQ/XOFF transmit wait
@ -517,10 +519,11 @@ uint32 mpx_portkey = 0; /* current port's key */
t_bool mpx_uien = FALSE; /* unsolicited interrupts enabled */
uint32 mpx_uicode = 0; /* unsolicited interrupt reason and port */
FLIP_FLOP mpx_control = CLEAR; /* control flip-flop */
FLIP_FLOP mpx_flag = CLEAR; /* flag flip-flop */
FLIP_FLOP mpx_flagbuf = CLEAR; /* flag buffer flip-flop */
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} mpx = { CLEAR, CLEAR, CLEAR };
/* Multiplexer per-line state variables */
@ -581,7 +584,7 @@ static uint32 buf_avail (IO_OPER rw, uint32 port);
/* Multiplexer global routines */
uint32 mpx_io (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER mpx_io;
t_stat mpx_line_svc (UNIT *uptr);
t_stat mpx_cntl_svc (UNIT *uptr);
@ -632,7 +635,7 @@ int32 mpx_order [MPX_PORTS] = { -1 }; /* connection order
TMLN mpx_ldsc [MPX_PORTS] = { { 0 } }; /* line descriptors */
TMXR mpx_desc = { MPX_PORTS, 0, 0, mpx_ldsc, mpx_order }; /* device descriptor */
DIB mpx_dib = { MPX, &mpx_io };
DIB mpx_dib = { &mpx_io, MPX };
DEVICE mpx_dev;
@ -682,10 +685,10 @@ REG mpx_reg [] = {
{ BRDATA (SEP, mpx_sep, 10, 10, MPX_PORTS * 2) },
{ BRDATA (PUT, mpx_put, 10, 10, MPX_PORTS * 2) },
{ FLDATA (CTL, mpx_control, 0) },
{ FLDATA (FLG, mpx_flag, 0) },
{ FLDATA (FBF, mpx_flagbuf, 0) },
{ ORDATA (DEVNO, mpx_dib.devno, 6), REG_HRO },
{ FLDATA (CTL, mpx.control, 0) },
{ FLDATA (FLG, mpx.flag, 0) },
{ FLDATA (FBF, mpx.flagbuf, 0) },
{ ORDATA (DEVNO, mpx_dib.select_code, 6), REG_HRO },
{ BRDATA (CONNORD, mpx_order, 10, 32, MPX_PORTS), REG_HRO },
{ NULL }
@ -746,7 +749,6 @@ DEVICE mpx_dev = {
NULL }; /* logical device name */
/* I/O signal handler.
Commands are sent to the card via an OTA/B. Issuing an STC SC,C causes the
@ -798,161 +800,156 @@ DEVICE mpx_dev = {
2. The "Fast binary read" command inhibits all other commands until the card
is reset.
3. The card does not respond to POPIO. However, as PRESET asserts POPIO and
CRS together, we fall into the latter from the former.
*/
uint32 mpx_io (uint32 select_code, IOSIG signal, uint32 data)
uint32 mpx_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
static const char *output_state [] = { "Command", "Command override", "Parameter", "Data" };
static const char *input_state [] = { "Status", "Invalid status", "Parameter", "Data" };
const char *hold_or_clear = (signal > ioCLF ? ",C" : "");
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
const char *hold_or_clear = (signal_set & ioCLF ? ",C" : "");
int32 delay;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
mpx_flag = mpx_flagbuf = CLEAR; /* clear flag and flag buffer */
switch (signal) { /* dispatch I/O signal */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fputs (">>MPX cmds: [CLF] Flag cleared\n", sim_deb);
break;
case ioSTF: /* set flag flip-flop */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fputs (">>MPX cmds: [STF] Flag set\n", sim_deb);
/* fall into ENF */
case ioENF: /* enable flag */
mpx_flag = mpx_flagbuf = SET; /* set flag and flag buffer */
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (mpx);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (mpx);
break;
case ioIOI: /* I/O data input */
data = mpx_ibuf; /* return info */
if (DEBUG_PRI (mpx_dev, DEB_CPU))
fprintf (sim_deb, ">>MPX cpu: [LIx%s] %s = %06o\n",
hold_or_clear, input_state [mpx_state], data);
if (mpx_state == exec) /* if this is input data word */
sim_activate (&mpx_cntl, DATA_DELAY); /* continue transmission */
break;
case ioIOO: /* I/O data output */
if (DEBUG_PRI (mpx_dev, DEB_CPU))
fprintf (sim_deb, ">>MPX cpu: [OTx%s] %s = %06o\n",
hold_or_clear, output_state [mpx_state], data);
mpx_obuf = data; /* save word */
if (mpx_state == param) { /* if this is parameter word */
sim_activate (&mpx_cntl, CMD_DELAY); /* do command now */
case ioCLF: /* clear flag flip-flop */
mpx.flag = mpx.flagbuf = CLEAR; /* clear flag and flag buffer */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fprintf (sim_deb, ">>MPX cmds: [OTx%s] Command %03o parameter %06o scheduled, "
"time = %d\n", hold_or_clear, mpx_cmd, mpx_obuf, CMD_DELAY);
}
else if (mpx_state == exec) /* else if this is output data word */
sim_activate (&mpx_cntl, DATA_DELAY); /* then do transmission */
break;
fputs (">>MPX cmds: [CLF] Flag cleared\n", sim_deb);
break;
case ioPOPIO: /* power-on preset to I/O */
/* fall into CRS handler */
case ioSTF: /* set flag flip-flop */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fputs (">>MPX cmds: [STF] Flag set\n", sim_deb);
/* fall into ENF */
case ioCRS: /* control reset */
controller_reset (); /* reset firmware to power-on defaults */
mpx_obuf = 0; /* clear output buffer */
mpx_control = CLEAR; /* clear control */
mpx_flagbuf = CLEAR; /* clear flag buffer */
mpx_flag = CLEAR; /* clear flag */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fputs (">>MPX cmds: [CRS] Controller reset\n", sim_deb);
break;
case ioENF: /* enable flag */
mpx.flag = mpx.flagbuf = SET; /* set flag and flag buffer */
break;
case ioCLC: /* clear control flip-flop */
mpx_control = CLEAR; /* clear control */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fprintf (sim_deb, ">>MPX cmds: [CLC%s] Control cleared\n", hold_or_clear);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (mpx);
break;
case ioSTC: /* set control flip-flop */
mpx_control = SET; /* set control */
if (mpx_cmd == CMD_BINARY_READ) /* executing fast binary read? */
break; /* further command execution inhibited */
mpx_cmd = GET_OPCODE (mpx_obuf); /* get command opcode */
mpx_portkey = GET_KEY (mpx_obuf); /* get port key */
if (mpx_state == cmd) /* already scheduled? */
sim_cancel (&mpx_cntl); /* cancel to get full delay */
mpx_state = cmd; /* set command state */
if (mpx_cmd & CMD_TWO_WORDS) /* two-word command? */
delay = PARAM_DELAY; /* specify parameter wait */
else /* one-word command */
delay = CMD_DELAY; /* specify command wait */
sim_activate (&mpx_cntl, delay); /* schedule command */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fprintf (sim_deb, ">>MPX cmds: [STC%s] Command %03o key %d scheduled, "
"time = %d\n", hold_or_clear, mpx_cmd, mpx_portkey, delay);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (mpx);
break;
case ioEDT: /* end data transfer */
if (DEBUG_PRI (mpx_dev, DEB_CPU))
fputs (">>MPX cpu: [EDT] DCPC transfer ended\n", sim_deb);
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, mpx_ibuf); /* return info */
if (DEBUG_PRI (mpx_dev, DEB_CPU))
fprintf (sim_deb, ">>MPX cpu: [LIx%s] %s = %06o\n",
hold_or_clear, input_state [mpx_state], mpx_ibuf);
if (mpx_state == exec) /* if this is input data word */
sim_activate (&mpx_cntl, DATA_DELAY); /* continue transmission */
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, mpx); /* set standard PRL signal */
setstdIRQ (select_code, mpx); /* set standard IRQ signal */
setstdSRQ (select_code, mpx); /* set standard SRQ signal */
break;
case ioIOO: /* I/O data output */
mpx_obuf = IODATA (stat_data); /* save word */
if (DEBUG_PRI (mpx_dev, DEB_CPU))
fprintf (sim_deb, ">>MPX cpu: [OTx%s] %s = %06o\n",
hold_or_clear, output_state [mpx_state], mpx_obuf);
if (mpx_state == param) { /* if this is parameter word */
sim_activate (&mpx_cntl, CMD_DELAY); /* do command now */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fprintf (sim_deb, ">>MPX cmds: [OTx%s] Command %03o parameter %06o scheduled, "
"time = %d\n", hold_or_clear, mpx_cmd, mpx_obuf, CMD_DELAY);
}
else if (mpx_state == exec) /* else if this is output data word */
sim_activate (&mpx_cntl, DATA_DELAY); /* then do transmission */
break;
case ioIAK: /* interrupt acknowledge */
mpx_flagbuf = CLEAR; /* clear flag buffer */
break;
case ioCRS: /* control reset */
controller_reset (); /* reset firmware to power-on defaults */
mpx_obuf = 0; /* clear output buffer */
mpx.control = CLEAR; /* clear control */
mpx.flagbuf = CLEAR; /* clear flag buffer */
mpx.flag = CLEAR; /* clear flag */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fputs (">>MPX cmds: [CRS] Controller reset\n", sim_deb);
break;
default: /* all other signals */
break; /* are ignored */
case ioCLC: /* clear control flip-flop */
mpx.control = CLEAR; /* clear control */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fprintf (sim_deb, ">>MPX cmds: [CLC%s] Control cleared\n", hold_or_clear);
break;
case ioSTC: /* set control flip-flop */
mpx.control = SET; /* set control */
if (mpx_cmd == CMD_BINARY_READ) /* executing fast binary read? */
break; /* further command execution inhibited */
mpx_cmd = GET_OPCODE (mpx_obuf); /* get command opcode */
mpx_portkey = GET_KEY (mpx_obuf); /* get port key */
if (mpx_state == cmd) /* already scheduled? */
sim_cancel (&mpx_cntl); /* cancel to get full delay */
mpx_state = cmd; /* set command state */
if (mpx_cmd & CMD_TWO_WORDS) /* two-word command? */
delay = PARAM_DELAY; /* specify parameter wait */
else /* one-word command */
delay = CMD_DELAY; /* specify command wait */
sim_activate (&mpx_cntl, delay); /* schedule command */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fprintf (sim_deb, ">>MPX cmds: [STC%s] Command %03o key %d scheduled, "
"time = %d\n", hold_or_clear, mpx_cmd, mpx_portkey, delay);
break;
case ioEDT: /* end data transfer */
if (DEBUG_PRI (mpx_dev, DEB_CPU))
fputs (">>MPX cpu: [EDT] DCPC transfer ended\n", sim_deb);
break;
case ioSIR: /* set interrupt request */
setstdPRL (mpx); /* set standard PRL signal */
setstdIRQ (mpx); /* set standard IRQ signal */
setstdSRQ (mpx); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
mpx.flagbuf = CLEAR; /* clear flag buffer */
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
mpx_io (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
mpx_io (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -1591,7 +1588,7 @@ if (DEBUG_PRI (mpx_dev, DEB_CMDS) && /* debug print? */
}
if (set_flag) {
mpx_io (mpx_dib.devno, ioENF, 0); /* set device flag */
mpx_io (&mpx_dib, ioENF, 0); /* set device flag */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fputs (">>MPX cmds: Flag set\n", sim_deb);
@ -1909,7 +1906,7 @@ if (fast_binary_read) { /* fast binary read
mpx_ibuf = mpx_ibuf | (chx & DMASK8); /* merge it into word */
mpx_flags [0] |= FL_HAVEBUF; /* mark buffer as ready */
mpx_io (mpx_dib.devno, ioENF, 0); /* set device flag */
mpx_io (&mpx_dib, ioENF, 0); /* set device flag */
if (DEBUG_PRI (mpx_dev, DEB_CMDS))
fputs (">>MPX cmds: Flag and SRQ set\n", sim_deb);
@ -2021,14 +2018,14 @@ return SCPE_OK;
t_stat mpx_reset (DEVICE *dptr)
{
if (sim_switches & SWMASK ('P')) { /* PON reset? */
if (sim_switches & SWMASK ('P')) { /* power-on reset? */
emptying_flags [ioread] = FL_RDEMPT; /* initialize buffer flags constants */
emptying_flags [iowrite] = FL_WREMPT;
filling_flags [ioread] = FL_RDFILL;
filling_flags [iowrite] = FL_WRFILL;
}
mpx_io (mpx_dib.devno, ioPOPIO, 0); /* send POPIO signal */
IOPRESET (&mpx_dib); /* PRESET device (does not use PON) */
mpx_ibuf = 0; /* clear input buffer */

View file

@ -1,6 +1,6 @@
/* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape simulator
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,8 @@
MS 13181A 7970B 800bpi nine track magnetic tape
13183A 7970E 1600bpi nine track magnetic tape
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
11-Aug-08 JDB Revised to use AR instead of saved_AR in boot
26-Jun-08 JDB Rewrote device I/O to model backplane signals
28-Dec-06 JDB Added ioCRS state to I/O decoders
@ -152,9 +154,11 @@
enum { A13181, A13183 } ms_ctype = A13181; /* ctrl type */
int32 ms_timing = 1; /* timing type */
FLIP_FLOP msc_control = CLEAR;
FLIP_FLOP msc_flag = CLEAR;
FLIP_FLOP msc_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} msc = { CLEAR, CLEAR, CLEAR };
int32 msc_sta = 0; /* status */
int32 msc_buf = 0; /* buffer */
@ -162,9 +166,11 @@ int32 msc_usl = 0; /* unit select */
int32 msc_1st = 0; /* first service */
int32 msc_stopioe = 1; /* stop on error */
FLIP_FLOP msd_control = CLEAR;
FLIP_FLOP msd_flag = CLEAR;
FLIP_FLOP msd_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} msd = { CLEAR, CLEAR, CLEAR };
int32 msd_buf = 0; /* data buffer */
uint8 msxb[DBSIZE] = { 0 }; /* data buffer */
@ -206,8 +212,10 @@ const TIMESET msc_times[3] = {
};
DEVICE msd_dev, msc_dev;
uint32 msdio (uint32 select_code, IOSIG signal, uint32 data);
uint32 mscio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER msdio;
IOHANDLER mscio;
t_stat msc_svc (UNIT *uptr);
t_stat msc_reset (DEVICE *dptr);
t_stat msc_attach (UNIT *uptr, char *cptr);
@ -235,8 +243,8 @@ t_stat ms_clear (void);
*/
DIB ms_dib[] = {
{ MSD, &msdio },
{ MSC, &mscio }
{ &msdio, MSD },
{ &mscio, MSC }
};
#define msd_dib ms_dib[0]
@ -246,13 +254,13 @@ UNIT msd_unit = { UDATA (NULL, 0, 0) };
REG msd_reg[] = {
{ ORDATA (BUF, msd_buf, 16) },
{ FLDATA (CTL, msd_control, 0) },
{ FLDATA (FLG, msd_flag, 0) },
{ FLDATA (FBF, msd_flagbuf, 0) },
{ FLDATA (CTL, msd.control, 0) },
{ FLDATA (FLG, msd.flag, 0) },
{ FLDATA (FBF, msd.flagbuf, 0) },
{ BRDATA (DBUF, msxb, 8, 8, DBSIZE) },
{ DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) },
{ DRDATA (BMAX, ms_max, DB_N_SIZE + 1) },
{ ORDATA (DEVNO, msd_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, msd_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -295,9 +303,9 @@ REG msc_reg[] = {
{ ORDATA (BUF, msc_buf, 16) },
{ ORDATA (USEL, msc_usl, 2) },
{ FLDATA (FSVC, msc_1st, 0) },
{ FLDATA (CTL, msc_control, 0) },
{ FLDATA (FLG, msc_flag, 0) },
{ FLDATA (FBF, msc_flagbuf, 0) },
{ FLDATA (CTL, msc.control, 0) },
{ FLDATA (FLG, msc.flag, 0) },
{ FLDATA (FBF, msc.flagbuf, 0) },
{ URDATA (POS, msc_unit[0].pos, 10, T_ADDR_W, 0, MS_NUMDR, PV_LEFT) },
{ URDATA (FNC, msc_unit[0].FNC, 8, 8, 0, MS_NUMDR, REG_HRO) },
{ URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) },
@ -311,7 +319,7 @@ REG msc_reg[] = {
{ FLDATA (TIMING, ms_timing, 0), REG_HRO },
{ FLDATA (STOP_IOE, msc_stopioe, 0) },
{ FLDATA (CTYPE, ms_ctype, 0), REG_HRO },
{ ORDATA (DEVNO, msc_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, msc_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -362,75 +370,77 @@ DEVICE msc_dev = {
/* Data channel I/O signal handler */
uint32 msdio (uint32 select_code, IOSIG signal, uint32 data)
uint32 msdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
msd_flag = msd_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
msd.flag = msd.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
msd_flag = msd_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
msd.flag = msd.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (msd);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (msd);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (msd);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (msd);
break;
case ioIOI: /* I/O data input */
data = msd_buf;
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, msd_buf); /* merge in return status */
break;
case ioIOO: /* I/O data output */
msd_buf = data; /* store data */
break;
case ioIOO: /* I/O data output */
msd_buf = IODATA (stat_data); /* store data */
break;
case ioPOPIO: /* power-on preset to I/O */
ms_clear (); /* issue CLR to controller */
/* fall into CRS handler */
case ioCRS: /* control reset */
msd_flag = msd_flagbuf = SET; /* set flag and flag buffer */
case ioPOPIO: /* power-on preset to I/O */
ms_clear (); /* issue CLR to controller */
break;
case ioCRS: /* control reset */
msd.flag = msd.flagbuf = SET; /* set flag and flag buffer */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
msd_control = CLEAR;
break;
case ioCLC: /* clear control flip-flop */
msd.control = CLEAR;
break;
case ioSTC: /* set control flip-flop */
msd_control = SET;
break;
case ioSTC: /* set control flip-flop */
msd.control = SET;
break;
case ioEDT: /* end data transfer */
msd_flag = msd_flagbuf = CLEAR; /* same as CLF */
break;
case ioEDT: /* end data transfer */
msd.flag = msd.flagbuf = CLEAR; /* same as CLF */
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, msd); /* set standard PRL signal */
setstdIRQ (select_code, msd); /* set standard IRQ signal */
setstdSRQ (select_code, msd); /* set standard SRQ signal */
break;
case ioSIR: /* set interrupt request */
setstdPRL (msd); /* set standard PRL signal */
setstdIRQ (msd); /* set standard IRQ signal */
setstdSRQ (msd); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
msd_flagbuf = CLEAR;
break;
case ioIAK: /* interrupt acknowledge */
msd.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
msdio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
msdio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -453,195 +463,197 @@ return data;
the command card under simulation to allow the command card to interrupt.
*/
uint32 mscio (uint32 select_code, IOSIG signal, uint32 data)
uint32 mscio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
static const uint8 map_sel[16] = {
0, 0, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3
};
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
uint16 data;
int32 sched_time;
UNIT *uptr = msc_dev.units + msc_usl;
switch (base_signal) { /* dispatch base I/O signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
case ioCLF: /* clear flag flip-flop */
msc_flag = msc_flagbuf = CLEAR;
break;
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
switch (signal) { /* dispatch I/O signal */
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
msc_flag = msc_flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (msc);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (msc);
break;
case ioIOI: /* I/O data input */
data = msc_sta & ~STA_DYN; /* get card status */
if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */
data = data | uptr->UST; /* add unit status */
if (sim_tape_bot (uptr)) /* BOT? */
data = data | STA_BOT;
if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */
!((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr)))
data = data | STA_TBSY;
if (sim_tape_wrp (uptr)) /* write prot? */
data = data | STA_WLK;
if (sim_tape_eot (uptr)) /* EOT? */
data = data | STA_EOT;
}
else
data = data | STA_TBSY | STA_LOCAL;
if (ms_ctype == A13183) /* 13183A? */
data = data | STA_PE | (msc_usl << STA_V_SEL);
if (DEBUG_PRI (msc_dev, DEB_CPU))
fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", data);
break;
case ioIOO: /* I/O data output */
if (DEBUG_PRI (msc_dev, DEB_CPU))
fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", data);
msc_buf = data;
msc_sta = msc_sta & ~STA_REJ; /* clear reject */
if ((data & 0377) == FNC_CLR) /* clear always ok */
case ioCLF: /* clear flag flip-flop */
msc.flag = msc.flagbuf = CLEAR;
break;
if (msc_sta & STA_BUSY) { /* busy? reject */
msc_sta = msc_sta | STA_REJ; /* dont chg select */
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
msc.flag = msc.flagbuf = SET;
break;
}
if (data & FNF_CHS) { /* select change */
msc_usl = map_sel[FNC_GETSEL (data)]; /* is immediate */
uptr = msc_dev.units + msc_usl;
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl);
}
if (((data & FNF_MOT) && sim_is_active (uptr)) ||
((data & FNF_REV) && sim_tape_bot (uptr)) ||
((data & FNF_WRT) && sim_tape_wrp (uptr)))
msc_sta = msc_sta | STA_REJ; /* reject? */
break;
case ioPOPIO: /* power-on preset to I/O */
/* fall into CRS handler */
case ioSFC: /* skip if flag is clear */
setstdSKF (msc);
break;
case ioCRS: /* control reset */
msc_flag = msc_flagbuf = SET; /* set flag and flag buffer */
case ioSFS: /* skip if flag is set */
setstdSKF (msc);
break;
case ioIOI: /* I/O data input */
data = msc_sta & ~STA_DYN; /* get card status */
if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */
data = data | uptr->UST; /* add unit status */
if (sim_tape_bot (uptr)) /* BOT? */
data = data | STA_BOT;
if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */
!((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr)))
data = data | STA_TBSY;
if (sim_tape_wrp (uptr)) /* write prot? */
data = data | STA_WLK;
if (sim_tape_eot (uptr)) /* EOT? */
data = data | STA_EOT;
}
else
data = data | STA_TBSY | STA_LOCAL;
if (ms_ctype == A13183) /* 13183A? */
data = data | STA_PE | (msc_usl << STA_V_SEL);
if (DEBUG_PRI (msc_dev, DEB_CPU))
fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", data);
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
break;
case ioIOO: /* I/O data output */
msc_buf = IODATA (stat_data); /* clear supplied status */
if (DEBUG_PRI (msc_dev, DEB_CPU))
fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", msc_buf);
msc_sta = msc_sta & ~STA_REJ; /* clear reject */
if ((msc_buf & 0377) == FNC_CLR) /* clear always ok */
break;
if (msc_sta & STA_BUSY) { /* busy? reject */
msc_sta = msc_sta | STA_REJ; /* dont chg select */
break;
}
if (msc_buf & FNF_CHS) { /* select change */
msc_usl = map_sel[FNC_GETSEL (msc_buf)]; /* is immediate */
uptr = msc_dev.units + msc_usl;
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl);
}
if (((msc_buf & FNF_MOT) && sim_is_active (uptr)) ||
((msc_buf & FNF_REV) && sim_tape_bot (uptr)) ||
((msc_buf & FNF_WRT) && sim_tape_wrp (uptr)))
msc_sta = msc_sta | STA_REJ; /* reject? */
break;
case ioCRS: /* control reset */
msc.flag = msc.flagbuf = SET; /* set flag and flag buffer */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
msc_control = CLEAR;
break;
case ioCLC: /* clear control flip-flop */
msc.control = CLEAR;
break;
case ioSTC: /* set control flip-flop */
if (!(msc_sta & STA_REJ)) { /* last cmd rejected? */
if ((msc_buf & 0377) == FNC_CLR) { /* clear? */
ms_clear (); /* issue CLR to controller */
case ioSTC: /* set control flip-flop */
if (!(msc_sta & STA_REJ)) { /* last cmd rejected? */
if ((msc_buf & 0377) == FNC_CLR) { /* clear? */
ms_clear (); /* issue CLR to controller */
msc_control = SET; /* set CTL for STC */
msc_flag = msc_flagbuf = SET; /* set FLG for completion */
msc.control = SET; /* set CTL for STC */
msc.flag = msc.flagbuf = SET; /* set FLG for completion */
signal = ioSTC; /* eliminate possible CLF */
working_set = working_set & ~ioCLF; /* eliminate possible CLF */
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fputs (">>MSC STC: Controller cleared\n", sim_deb);
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fputs (">>MSC STC: Controller cleared\n", sim_deb);
break; /* command completes immediately */
break; /* command completes immediately */
}
uptr->FNC = msc_buf & 0377; /* save function */
if (uptr->FNC & FNF_RWD) { /* rewind? */
if (!sim_tape_bot (uptr)) /* not at BOT? */
uptr->UST = STA_REW; /* set rewinding */
sched_time = msc_rtime; /* set response time */
}
else {
if (sim_tape_bot (uptr)) /* at BOT? */
sched_time = msc_btime; /* use BOT start time */
else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM))
sched_time = msc_gtime; /* use gap traversal time */
else sched_time = 0;
if (uptr->FNC != FNC_GAP)
sched_time += msc_ctime; /* add base command time */
}
if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */
sim_activate (uptr, sched_time); /* else schedule op */
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb,
">>MSC STC: Unit %d command %03o (%s) scheduled, "
"pos = %d, time = %d\n",
msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC),
uptr->pos, sched_time);
}
else if (DEBUG_PRI (msc_dev, DEB_CMDS))
fputs (">>MSC STC: Unit select (NOP)\n", sim_deb);
msc_sta = STA_BUSY; /* ctrl is busy */
msc_1st = 1;
msc.control = SET; /* go */
}
uptr->FNC = msc_buf & 0377; /* save function */
if (uptr->FNC & FNF_RWD) { /* rewind? */
if (!sim_tape_bot (uptr)) /* not at BOT? */
uptr->UST = STA_REW; /* set rewinding */
sched_time = msc_rtime; /* set response time */
}
else {
if (sim_tape_bot (uptr)) /* at BOT? */
sched_time = msc_btime; /* use BOT start time */
else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM))
sched_time = msc_gtime; /* use gap traversal time */
else sched_time = 0;
if (uptr->FNC != FNC_GAP)
sched_time += msc_ctime; /* add base command time */
}
if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */
sim_activate (uptr, sched_time); /* else schedule op */
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb,
">>MSC STC: Unit %d command %03o (%s) scheduled, "
"pos = %d, time = %d\n",
msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC),
uptr->pos, sched_time);
}
else if (DEBUG_PRI (msc_dev, DEB_CMDS))
fputs (">>MSC STC: Unit select (NOP)\n", sim_deb);
msc_sta = STA_BUSY; /* ctrl is busy */
msc_1st = 1;
msc_control = SET; /* go */
}
break;
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, msc); /* set standard PRL signal */
setstdIRQ (select_code, msc); /* set standard IRQ signal */
setstdSRQ (select_code, msc); /* set standard SRQ signal */
break;
case ioSIR: /* set interrupt request */
setstdPRL (msc); /* set standard PRL signal */
setstdIRQ (msc); /* set standard IRQ signal */
setstdSRQ (msc); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
msc_flagbuf = CLEAR;
break;
case ioIAK: /* interrupt acknowledge */
msc.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
mscio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
mscio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -671,8 +683,8 @@ unum = uptr - msc_dev.units; /* get unit number */
if ((uptr->FNC != FNC_RWS) && (uptr->flags & UNIT_OFFLINE)) { /* offline? */
msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */
mscio (msc_dib.devno, ioENF, 0); /* set flag */
return IORETURN (msc_stopioe, SCPE_UNATT);
mscio (&msc_dib, ioENF, 0); /* set flag */
return IOERROR (msc_stopioe, SCPE_UNATT);
}
switch (uptr->FNC) { /* case on function */
@ -779,12 +791,12 @@ switch (uptr->FNC) { /* case on function */
if (ms_ctype == A13183)
msc_sta = msc_sta | STA_ODD; /* set ODD for 13183A */
}
if (msd_control && (ms_ptr < ms_max)) { /* DCH on, more data? */
if (msd_flag) msc_sta = msc_sta | STA_TIM | STA_PAR;
if (msd.control && (ms_ptr < ms_max)) { /* DCH on, more data? */
if (msd.flag) msc_sta = msc_sta | STA_TIM | STA_PAR;
msd_buf = ((uint16) msxb[ms_ptr] << 8) |
((ms_ptr + 1 == ms_max) ? 0 : msxb[ms_ptr + 1]);
ms_ptr = ms_ptr + 2;
msdio (msd_dib.devno, ioENF, 0); /* set flag */
msdio (&msd_dib, ioENF, 0); /* set flag */
sim_activate (uptr, msc_xtime); /* re-activate */
return SCPE_OK;
}
@ -822,8 +834,8 @@ switch (uptr->FNC) { /* case on function */
}
else msc_sta = msc_sta | STA_PAR;
}
if (msd_control) { /* xfer flop set? */
msdio (msd_dib.devno, ioENF, 0); /* set flag */
if (msd.control) { /* xfer flop set? */
msdio (&msd_dib, ioENF, 0); /* set flag */
sim_activate (uptr, msc_xtime); /* re-activate */
return SCPE_OK;
}
@ -853,7 +865,7 @@ switch (uptr->FNC) { /* case on function */
break;
}
mscio (msc_dib.devno, ioENF, 0); /* set flag */
mscio (&msc_dib, ioENF, 0); /* set flag */
msc_sta = msc_sta & ~STA_BUSY; /* update status */
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb,
@ -973,17 +985,15 @@ t_stat msc_reset (DEVICE *dptr)
{
int32 i;
UNIT *uptr;
DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */
hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &msd_dev) ? &msc_dev : &msd_dev);
if (sim_switches & SWMASK ('P')) /* PON reset? */
if (sim_switches & SWMASK ('P')) /* initialization reset? */
ms_config_timing ();
if (dptr == &msc_dev) /* command channel reset? */
mscio (msc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */
else /* data channel reset */
msdio (msd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */
IOPRESET (dibptr); /* PRESET device (does not use PON) */
msc_buf = msd_buf = 0;
msc_sta = msc_usl = 0;
@ -1247,7 +1257,7 @@ t_stat msc_boot (int32 unitno, DEVICE *dptr)
int32 dev;
if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */
dev = msd_dib.devno; /* get data chan dev */
dev = msd_dib.select_code; /* get data chan dev */
if (ibl_copy (ms_rom, dev)) return SCPE_IERR; /* copy boot to memory */
SR = (SR & IBL_OPT) | IBL_MS | (dev << IBL_V_DEV); /* set SR */
if ((sim_switches & SWMASK ('S')) && AR) SR = SR | 1; /* skip? */

View file

@ -1,6 +1,6 @@
/* hp2100_mt.c: HP 2100 12559A magnetic tape simulator
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,9 @@
MT 12559A 3030 nine track magnetic tape
28-Mar-11 JDB Tidied up signal handling
29-Oct-10 JDB Fixed error in command scan in mtcio ioIOO handler
26-Oct-10 JDB Changed I/O signal handler for revised signal model
04-Sep-08 JDB Fixed missing flag after CLR command
02-Sep-08 JDB Moved write enable and format commands from MTD to MTC
26-Jun-08 JDB Rewrote device I/O to model backplane signals
@ -105,12 +108,16 @@
#define STA_PAR 0002 /* parity error */
#define STA_BUSY 0001 /* busy (d) */
FLIP_FLOP mtd_flag = CLEAR;
FLIP_FLOP mtd_flagbuf = CLEAR;
struct {
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} mtd = { CLEAR, CLEAR };
FLIP_FLOP mtc_control = CLEAR;
FLIP_FLOP mtc_flag = CLEAR;
FLIP_FLOP mtc_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} mtc = { CLEAR, CLEAR, CLEAR };
int32 mtc_fnc = 0; /* function */
int32 mtc_sta = 0; /* status register */
@ -124,10 +131,13 @@ uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */
t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */
static const uint32 mtc_cmd[] = {
FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM };
static const uint32 mtc_cmd_count = sizeof (mtc_cmd) / sizeof (mtc_cmd[0]);
DEVICE mtd_dev, mtc_dev;
uint32 mtdio (uint32 select_code, IOSIG signal, uint32 data);
uint32 mtcio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER mtdio;
IOHANDLER mtcio;
t_stat mtc_svc (UNIT *uptr);
t_stat mt_reset (DEVICE *dptr);
t_stat mtc_attach (UNIT *uptr, char *cptr);
@ -143,8 +153,8 @@ t_stat mt_clear (void);
*/
DIB mt_dib[] = {
{ MTD, &mtdio },
{ MTC, &mtcio }
{ &mtdio, MTD },
{ &mtcio, MTC }
};
#define mtd_dib mt_dib[0]
@ -153,12 +163,12 @@ DIB mt_dib[] = {
UNIT mtd_unit = { UDATA (NULL, 0, 0) };
REG mtd_reg[] = {
{ FLDATA (FLG, mtd_flag, 0) },
{ FLDATA (FBF, mtd_flagbuf, 0) },
{ FLDATA (FLG, mtd.flag, 0) },
{ FLDATA (FBF, mtd.flagbuf, 0) },
{ BRDATA (DBUF, mtxb, 8, 8, DBSIZE) },
{ DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) },
{ DRDATA (BMAX, mt_max, DB_V_SIZE + 1) },
{ ORDATA (DEVNO, mtd_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, mtd_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -190,9 +200,9 @@ REG mtc_reg[] = {
{ ORDATA (FNC, mtc_fnc, 8) },
{ ORDATA (STA, mtc_sta, 9) },
{ ORDATA (BUF, mtc_unit.buf, 8) },
{ FLDATA (CTL, mtc_control, 0) },
{ FLDATA (FLG, mtc_flag, 0) },
{ FLDATA (FBF, mtc_flagbuf, 0) },
{ FLDATA (CTL, mtc.control, 0) },
{ FLDATA (FLG, mtc.flag, 0) },
{ FLDATA (FBF, mtc.flagbuf, 0) },
{ FLDATA (DTF, mtc_dtf, 0) },
{ FLDATA (FSVC, mtc_1st, 0) },
{ DRDATA (POS, mtc_unit.pos, T_ADDR_W), PV_LEFT },
@ -200,7 +210,7 @@ REG mtc_reg[] = {
{ DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT },
{ DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, mtc_stopioe, 0) },
{ ORDATA (DEVNO, mtc_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, mtc_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -240,63 +250,63 @@ DEVICE mtc_dev = {
so the flag buffer serves no other purpose.
*/
uint32 mtdio (uint32 select_code, IOSIG signal, uint32 data)
uint32 mtdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
mtd_flag = mtd_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
mtd_flag = mtd_flagbuf = SET;
break;
case ioCLF: /* clear flag flip-flop */
mtd.flag = mtd.flagbuf = CLEAR;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (mtd);
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
mtd.flag = mtd.flagbuf = SET;
break;
case ioSFS: /* skip if flag is set */
setstdSKF (mtd);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (mtd);
break;
case ioIOI: /* I/O data input */
data = mtc_unit.buf;
break;
case ioSFS: /* skip if flag is set */
setstdSKF (mtd);
break;
case ioIOO: /* I/O data output */
mtc_unit.buf = data & 0377; /* store data */
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, mtc_unit.buf); /* merge in return status */
break;
case ioPOPIO: /* power-on preset to I/O */
mt_clear (); /* issue CLR to controller */
mtd_flag = mtd_flagbuf = CLEAR; /* clear flag and flag buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
break;
case ioIOO: /* I/O data output */
mtc_unit.buf = IODATA (stat_data) & DMASK8; /* store data */
break;
case ioCLC: /* clear control flip-flop */
mtc_dtf = 0; /* clr xfer flop */
mtd_flag = mtd_flagbuf = CLEAR; /* clear flag and flag buffer */
break;
case ioPOPIO: /* power-on preset to I/O */
mt_clear (); /* issue CLR to controller */
mtd.flag = mtd.flagbuf = CLEAR; /* clear flag and flag buffer */
break;
case ioSIR: /* set interrupt request */
setstdSRQ (select_code, mtd); /* set standard SRQ signal */
break;
case ioCLC: /* clear control flip-flop */
mtc_dtf = 0; /* clr xfer flop */
mtd.flag = mtd.flagbuf = CLEAR; /* clear flag and flag buffer */
break;
default: /* all other signals */
break; /* are ignored */
case ioSIR: /* set interrupt request */
setstdSRQ (mtd); /* set standard SRQ signal */
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
mtdio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
mtdio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -322,126 +332,131 @@ return data;
complete immediately, and the BUSY bit never sets..
*/
uint32 mtcio (uint32 select_code, IOSIG signal, uint32 data)
uint32 mtcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
uint16 data;
uint32 i;
int32 valid;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
mtc_flag = mtc_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
mtc.flag = mtc.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
mtc_flag = mtc_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
mtc.flag = mtc.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (mtc);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (mtc);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (mtc);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (mtc);
break;
case ioIOI: /* I/O data input */
data = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY);
case ioIOI: /* I/O data input */
data = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY);
if (mtc_unit.flags & UNIT_ATT) { /* construct status */
if (sim_is_active (&mtc_unit))
data = data | STA_BUSY;
if (mtc_unit.flags & UNIT_ATT) { /* construct status */
if (sim_is_active (&mtc_unit))
data = data | STA_BUSY;
if (sim_tape_wrp (&mtc_unit))
data = data | STA_WLK;
}
else
data = data | STA_BUSY | STA_LOCAL;
break;
if (sim_tape_wrp (&mtc_unit))
data = data | STA_WLK;
}
else
data = data | STA_BUSY | STA_LOCAL;
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
break;
case ioIOO: /* I/O data output */
data = data & 0377;
mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */
case ioIOO: /* I/O data output */
data = IODATA (stat_data) & DMASK8;
mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */
if (data == FNC_CLR) { /* clear? */
mt_clear (); /* send CLR to controller */
if (data == FNC_CLR) { /* clear? */
mt_clear (); /* send CLR to controller */
mtd_flag = mtd_flagbuf = CLEAR; /* clear data flag and flag buffer */
mtc_flag = mtc_flagbuf = SET; /* set command flag and flag buffer */
break; /* command completes immediately */
}
mtd.flag = mtd.flagbuf = CLEAR; /* clear data flag and flag buffer */
mtc.flag = mtc.flagbuf = SET; /* set command flag and flag buffer */
break; /* command completes immediately */
}
for (i = valid = 0; i < sizeof (mtc_cmd); i++) /* is fnc valid? */
if (data == mtc_cmd[i])
valid = 1;
for (i = valid = 0; i < mtc_cmd_count; i++) /* is fnc valid? */
if (data == mtc_cmd[i]) {
valid = 1;
break;
}
if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */
((mtc_sta & STA_BOT) && (data == FNC_BSR)) ||
(sim_tape_wrp (&mtc_unit) &&
((data == FNC_WC) || (data == FNC_GAP) || (data == FNC_WFM))))
mtc_sta = mtc_sta | STA_REJ;
if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */
((mtc_sta & STA_BOT) && (data == FNC_BSR)) ||
(sim_tape_wrp (&mtc_unit) &&
((data == FNC_WC) || (data == FNC_GAP) || (data == FNC_WFM))))
mtc_sta = mtc_sta | STA_REJ;
else {
sim_activate (&mtc_unit, mtc_ctime); /* start tape */
mtc_fnc = data; /* save function */
mtc_sta = STA_BUSY; /* unit busy */
mt_ptr = 0; /* init buffer ptr */
else {
sim_activate (&mtc_unit, mtc_ctime); /* start tape */
mtc_fnc = data; /* save function */
mtc_sta = STA_BUSY; /* unit busy */
mt_ptr = 0; /* init buffer ptr */
mtcio (select_code, ioCLF, 0); /* clear flags */
mtcio (mtd_dib.devno, ioCLF, 0);
mtcio (&mtc_dib, ioCLF, 0); /* clear flags */
mtcio (&mtd_dib, ioCLF, 0);
mtc_1st = 1; /* set 1st flop */
mtc_dtf = 1; /* set xfer flop */
}
break;
mtc_1st = 1; /* set 1st flop */
mtc_dtf = 1; /* set xfer flop */
}
break;
case ioPOPIO: /* power-on preset to I/O */
mtc_flag = mtc_flagbuf = CLEAR; /* clear flag and flag buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
mtc_control = CLEAR;
break;
case ioPOPIO: /* power-on preset to I/O */
mtc.flag = mtc.flagbuf = CLEAR; /* clear flag and flag buffer */
break;
case ioSTC: /* set control flip-flop */
mtc_control = SET;
break;
case ioCRS: /* control reset */
case ioCLC: /* clear control flip-flop */
mtc.control = CLEAR;
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, mtc); /* set standard PRL signal */
setstdIRQ (select_code, mtc); /* set standard IRQ signal */
setstdSRQ (select_code, mtc); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
mtc_flagbuf = CLEAR;
break;
case ioSTC: /* set control flip-flop */
mtc.control = SET;
break;
default: /* all other signals */
break; /* are ignored */
case ioSIR: /* set interrupt request */
setstdPRL (mtc); /* set standard PRL signal */
setstdIRQ (mtc); /* set standard IRQ signal */
setstdSRQ (mtc); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
mtc.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
mtcio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
mtcio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -460,8 +475,8 @@ t_stat st, r = SCPE_OK;
if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */
mtc_sta = STA_LOCAL | STA_REJ; /* rejected */
mtcio (mtc_dib.devno, ioENF, 0); /* set cch flg */
return IORETURN (mtc_stopioe, SCPE_UNATT);
mtcio (&mtc_dib, ioENF, 0); /* set cch flg */
return IOERROR (mtc_stopioe, SCPE_UNATT);
}
switch (mtc_fnc) { /* case on function */
@ -514,9 +529,9 @@ switch (mtc_fnc) { /* case on function */
}
}
if (mtc_dtf && (mt_ptr < mt_max)) { /* more chars? */
if (mtd_flag) mtc_sta = mtc_sta | STA_TIM;
if (mtd.flag) mtc_sta = mtc_sta | STA_TIM;
mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */
mtdio (mtd_dib.devno, ioENF, 0); /* set dch flg */
mtdio (&mtd_dib, ioENF, 0); /* set dch flg */
sim_activate (uptr, mtc_xtime); /* re-activate */
return SCPE_OK;
}
@ -534,7 +549,7 @@ switch (mtc_fnc) { /* case on function */
else mtc_sta = mtc_sta | STA_PAR;
}
if (mtc_dtf) { /* xfer flop set? */
mtdio (mtd_dib.devno, ioENF, 0); /* set dch flg */
mtdio (&mtd_dib, ioENF, 0); /* set dch flg */
sim_activate (uptr, mtc_xtime); /* re-activate */
return SCPE_OK;
}
@ -552,7 +567,7 @@ switch (mtc_fnc) { /* case on function */
break;
}
mtcio (mtc_dib.devno, ioENF, 0); /* set cch flg */
mtcio (&mtc_dib, ioENF, 0); /* set cch flg */
mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */
return r;
}
@ -626,13 +641,12 @@ return SCPE_OK;
t_stat mt_reset (DEVICE *dptr)
{
DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */
hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &mtd_dev) ? &mtc_dev : &mtd_dev);
if (dptr == &mtc_dev) /* command channel reset? */
mtcio (mtc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */
else /* data channel reset */
mtdio (mtd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */
IOPRESET (dibptr); /* PRESET device (does not use PON) */
mtc_fnc = 0;
mtc_1st = mtc_dtf = 0;

View file

@ -1,6 +1,6 @@
/* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator
Copyright (c) 2002-2008, Robert M Supnik
Copyright (c) 2002-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
MUX,MUXL,MUXM 12920A terminal multiplexor
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
25-Nov-08 JDB Revised for new multiplexer library SHOW routines
09-Oct-08 JDB "muxl_unit" defined one too many units (17 instead of 16)
10-Sep-08 JDB SHOW MUX CONN/STAT with SET MUX DIAG is no longer disallowed
@ -265,9 +267,11 @@ static const uint8 odd_par [256] = {
/* Multiplexer controller state variables */
FLIP_FLOP muxl_control = CLEAR;
FLIP_FLOP muxl_flag = CLEAR;
FLIP_FLOP muxl_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} muxl = { CLEAR, CLEAR, CLEAR };
uint32 muxl_ibuf = 0; /* low in: rcv data */
uint32 muxl_obuf = 0; /* low out: param */
@ -275,9 +279,11 @@ uint32 muxl_obuf = 0; /* low out: param */
uint32 muxu_ibuf = 0; /* upr in: status */
uint32 muxu_obuf = 0; /* upr out: chan */
FLIP_FLOP muxc_control = CLEAR;
FLIP_FLOP muxc_flag = CLEAR;
FLIP_FLOP muxc_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} muxc = { CLEAR, CLEAR, CLEAR };
uint32 muxc_chan = 0; /* ctrl chan */
uint32 muxc_scan = 0; /* ctrl scan */
@ -311,9 +317,10 @@ void mux_diag (int32 c);
/* Multiplexer global routines */
uint32 muxlio (uint32 select_code, IOSIG signal, uint32 data);
uint32 muxuio (uint32 select_code, IOSIG signal, uint32 data);
uint32 muxcio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER muxlio;
IOHANDLER muxuio;
IOHANDLER muxcio;
t_stat muxi_svc (UNIT *uptr);
t_stat muxo_svc (UNIT *uptr);
t_stat muxc_reset (DEVICE *dptr);
@ -334,8 +341,8 @@ TMLN mux_ldsc [MUX_LINES] = { { 0 } }; /* line descriptors
TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc, mux_order }; /* device descriptor */
DIB mux_dib[] = {
{ MUXL, &muxlio },
{ MUXU, &muxuio }
{ &muxlio, MUXL },
{ &muxuio, MUXU }
};
#define muxl_dib mux_dib[0]
@ -373,9 +380,9 @@ UNIT muxl_unit[] = {
};
REG muxl_reg[] = {
{ FLDATA (CTL, muxl_control, 0) },
{ FLDATA (FLG, muxl_flag, 0) },
{ FLDATA (FBF, muxl_flagbuf, 0) },
{ FLDATA (CTL, muxl.control, 0) },
{ FLDATA (FLG, muxl.flag, 0) },
{ FLDATA (FBF, muxl.flagbuf, 0) },
{ BRDATA (STA, mux_sta, 8, 16, MUX_LINES + MUX_ILINES) },
{ BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) },
{ BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) },
@ -386,7 +393,7 @@ REG muxl_reg[] = {
{ BRDATA (BDFR, mux_defer, 8, 1, MUX_LINES) },
{ URDATA (TIME, muxl_unit[0].wait, 10, 24, 0,
MUX_LINES, REG_NZ + PV_LEFT) },
{ ORDATA (DEVNO, muxl_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, muxl_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -450,7 +457,7 @@ UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_FIRST };
REG muxu_reg[] = {
{ ORDATA (IBUF, muxu_ibuf, 16) },
{ ORDATA (OBUF, muxu_obuf, 16) },
{ ORDATA (DEVNO, muxu_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, muxu_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -512,19 +519,19 @@ DEVICE muxu_dev = {
DEVICE muxc_dev;
DIB muxc_dib = { MUXC, &muxcio };
DIB muxc_dib = { &muxcio, MUXC };
UNIT muxc_unit = { UDATA (NULL, 0, 0) };
REG muxc_reg[] = {
{ FLDATA (CTL, muxc_control, 0) },
{ FLDATA (FLG, muxc_flag, 0) },
{ FLDATA (FBF, muxc_flagbuf, 0) },
{ FLDATA (CTL, muxc.control, 0) },
{ FLDATA (FLG, muxc.flag, 0) },
{ FLDATA (FBF, muxc.flagbuf, 0) },
{ FLDATA (SCAN, muxc_scan, 0) },
{ ORDATA (CHAN, muxc_chan, 4) },
{ BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) },
{ BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) },
{ ORDATA (DEVNO, muxc_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, muxc_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -570,191 +577,190 @@ DEVICE muxc_dev = {
to these 128K CRS invocations.
*/
uint32 muxlio (uint32 select_code, IOSIG signal, uint32 data)
uint32 muxlio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
int32 ln;
const char *hold_or_clear = (signal > ioCLF ? ",C" : "");
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
const char *hold_or_clear = (signal_set & ioCLF ? ",C" : "");
static uint32 crs_count = 0; /* cntr for ioCRS repeat */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
case ioCLF: /* clear flag flip-flop */
muxl_flag = muxl_flagbuf = CLEAR;
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fputs (">>MUXl cmds: [CLF] Flag cleared\n", sim_deb);
mux_data_int (); /* look for new int */
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
muxl_flag = muxl_flagbuf = SET;
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fputs (">>MUXl cmds: [STF] Flag set\n", sim_deb);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (muxl);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (muxl);
break;
case ioIOI: /* I/O data input */
data = muxl_ibuf;
if (DEBUG_PRI (muxu_dev, DEB_CPU))
fprintf (sim_deb, ">>MUXl cpu: [LIx%s] Data = %06o\n", hold_or_clear, data);
break;
case ioIOO: /* I/O data output */
muxl_obuf = data; /* store data */
if (DEBUG_PRI (muxu_dev, DEB_CPU))
if (data & OTL_P)
fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Parameter = %06o\n", hold_or_clear, data);
else
fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Data = %06o\n", hold_or_clear, data);
break;
case ioPOPIO: /* power-on preset to I/O */
muxl_flag = muxl_flagbuf = SET; /* set flag andflag buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
if (crs_count) /* already reset? */
break; /* skip redundant clear */
muxl_control = CLEAR; /* clear control flip-flop */
for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */
mux_xbuf[ln] = mux_xpar[ln] = 0;
muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0;
}
for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) {
mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */
mux_sta[ln] = mux_rchp[ln] = 0;
}
break;
case ioCLC: /* clear control flip-flop */
muxl_control = CLEAR;
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb, ">>MUXl cmds: [CLC%s] Data interrupt inhibited\n", hold_or_clear);
break;
case ioSTC: /* set control flip-flop */
muxl_control = SET; /* set control */
ln = MUX_CHAN (muxu_obuf); /* get chan # */
if (muxl_obuf & OTL_TX) { /* transmit? */
if (ln < MUX_LINES) { /* line valid? */
if (muxl_obuf & OTL_P) { /* parameter? */
mux_xpar[ln] = muxl_obuf; /* store param value */
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb,
">>MUXl cmds: [STC%s] Transmit channel %d parameter %06o stored\n",
hold_or_clear, ln, muxl_obuf);
}
else { /* data */
if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */
muxl_obuf = /* add parity bit */
muxl_obuf & ~OTL_PAR |
XMT_PAR(muxl_obuf);
mux_xbuf[ln] = muxl_obuf; /* load buffer */
if (sim_is_active (&muxl_unit[ln])) { /* still working? */
mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data overrun\n",
hold_or_clear, ln);
}
else {
if (muxu_unit.flags & UNIT_DIAG) /* loopback? */
mux_ldsc[ln].conn = 1; /* connect this line */
sim_activate (&muxl_unit[ln], muxl_unit[ln].wait);
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data %06o scheduled\n",
hold_or_clear, ln, muxl_obuf);
}
}
}
else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */
fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d invalid\n", hold_or_clear, ln);
}
else /* receive */
if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */
if (muxl_obuf & OTL_P) { /* parameter? */
mux_rpar[ln] = muxl_obuf; /* store param value */
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb,
">>MUXl cmds: [STC%s] Receive channel %d parameter %06o stored\n",
hold_or_clear, ln, muxl_obuf);
}
else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */
fprintf (sim_deb,
">>MUXl cmds: [STC%s] Receive channel %d parameter %06o invalid action\n",
hold_or_clear, ln, muxl_obuf);
}
else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */
fprintf (sim_deb, ">>MUXl cmds: [STC%s] Receive channel %d invalid\n", hold_or_clear, ln);
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, muxl); /* set standard PRL signal */
setstdIRQ (select_code, muxl); /* set standard IRQ signal */
setstdSRQ (select_code, muxl); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
muxl_flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
if (signal > ioCLF) /* multiple signals? */
muxlio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
muxlio (select_code, ioSIR, 0); /* set interrupt request */
if (signal == ioCRS) /* control reset? */
crs_count = crs_count + 1; /* increment count */
else if (crs_count && (signal != ioSIR)) { /* counting CRSes? */
if (crs_count && !(signal_set & ioCRS)) { /* counting CRSes and not present? */
if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* report reset count */
fprintf (sim_deb, ">>MUXl cmds: [CRS] Multiplexer reset %d times\n",
crs_count);
crs_count = 0; /* clear counter */
}
return data;
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
muxl.flag = muxl.flagbuf = CLEAR;
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fputs (">>MUXl cmds: [CLF] Flag cleared\n", sim_deb);
mux_data_int (); /* look for new int */
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
muxl.flag = muxl.flagbuf = SET;
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fputs (">>MUXl cmds: [STF] Flag set\n", sim_deb);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (muxl);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (muxl);
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, muxl_ibuf); /* merge in return status */
if (DEBUG_PRI (muxu_dev, DEB_CPU))
fprintf (sim_deb, ">>MUXl cpu: [LIx%s] Data = %06o\n", hold_or_clear, muxl_ibuf);
break;
case ioIOO: /* I/O data output */
muxl_obuf = IODATA (stat_data); /* store data */
if (DEBUG_PRI (muxu_dev, DEB_CPU))
if (muxl_obuf & OTL_P)
fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Parameter = %06o\n", hold_or_clear, muxl_obuf);
else
fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Data = %06o\n", hold_or_clear, muxl_obuf);
break;
case ioPOPIO: /* power-on preset to I/O */
muxl.flag = muxl.flagbuf = SET; /* set flag andflag buffer */
break;
case ioCRS: /* control reset */
if (crs_count == 0) { /* first reset? */
muxl.control = CLEAR; /* clear control flip-flop */
for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */
mux_xbuf[ln] = mux_xpar[ln] = 0;
muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0;
}
for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) {
mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */
mux_sta[ln] = mux_rchp[ln] = 0;
}
}
crs_count = crs_count + 1; /* increment count */
break;
case ioCLC: /* clear control flip-flop */
muxl.control = CLEAR;
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb, ">>MUXl cmds: [CLC%s] Data interrupt inhibited\n", hold_or_clear);
break;
case ioSTC: /* set control flip-flop */
muxl.control = SET; /* set control */
ln = MUX_CHAN (muxu_obuf); /* get chan # */
if (muxl_obuf & OTL_TX) { /* transmit? */
if (ln < MUX_LINES) { /* line valid? */
if (muxl_obuf & OTL_P) { /* parameter? */
mux_xpar[ln] = muxl_obuf; /* store param value */
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb,
">>MUXl cmds: [STC%s] Transmit channel %d parameter %06o stored\n",
hold_or_clear, ln, muxl_obuf);
}
else { /* data */
if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */
muxl_obuf = /* add parity bit */
muxl_obuf & ~OTL_PAR |
XMT_PAR(muxl_obuf);
mux_xbuf[ln] = muxl_obuf; /* load buffer */
if (sim_is_active (&muxl_unit[ln])) { /* still working? */
mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data overrun\n",
hold_or_clear, ln);
}
else {
if (muxu_unit.flags & UNIT_DIAG) /* loopback? */
mux_ldsc[ln].conn = 1; /* connect this line */
sim_activate (&muxl_unit[ln], muxl_unit[ln].wait);
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data %06o scheduled\n",
hold_or_clear, ln, muxl_obuf);
}
}
}
else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */
fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d invalid\n", hold_or_clear, ln);
}
else /* receive */
if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */
if (muxl_obuf & OTL_P) { /* parameter? */
mux_rpar[ln] = muxl_obuf; /* store param value */
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb,
">>MUXl cmds: [STC%s] Receive channel %d parameter %06o stored\n",
hold_or_clear, ln, muxl_obuf);
}
else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */
fprintf (sim_deb,
">>MUXl cmds: [STC%s] Receive channel %d parameter %06o invalid action\n",
hold_or_clear, ln, muxl_obuf);
}
else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */
fprintf (sim_deb, ">>MUXl cmds: [STC%s] Receive channel %d invalid\n", hold_or_clear, ln);
break;
case ioSIR: /* set interrupt request */
setstdPRL (muxl); /* set standard PRL signal */
setstdIRQ (muxl); /* set standard IRQ signal */
setstdSRQ (muxl); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
muxl.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
return stat_data;
}
@ -771,34 +777,41 @@ return data;
the lower data card CRS handler.
*/
uint32 muxuio (uint32 select_code, IOSIG signal, uint32 data)
uint32 muxuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioIOI: /* I/O data input */
data = muxu_ibuf;
switch (signal) { /* dispatch I/O signal */
if (DEBUG_PRI (muxu_dev, DEB_CPU))
fprintf (sim_deb, ">>MUXu cpu: [LIx] Status = %06o, channel = %d\n",
data, MUX_CHAN(data));
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, muxu_ibuf); /* merge in return status */
if (DEBUG_PRI (muxu_dev, DEB_CPU))
fprintf (sim_deb, ">>MUXu cpu: [LIx] Status = %06o, channel = %d\n",
muxu_ibuf, MUX_CHAN(muxu_ibuf));
break;
case ioIOO: /* I/O data output */
muxu_obuf = data; /* store data */
case ioIOO: /* I/O data output */
muxu_obuf = IODATA (stat_data); /* store data */
if (DEBUG_PRI (muxu_dev, DEB_CPU))
fprintf (sim_deb, ">>MUXu cpu: [OTx] Data channel = %d\n", MUX_CHAN(data));
break;
if (DEBUG_PRI (muxu_dev, DEB_CPU))
fprintf (sim_deb, ">>MUXu cpu: [OTx] Data channel = %d\n", MUX_CHAN(muxu_obuf));
break;
default: /* all other signals */
break; /* are ignored */
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
return data;
return stat_data;
}
@ -809,139 +822,142 @@ return data;
test is performed after IOO processing.
*/
uint32 muxcio (uint32 select_code, IOSIG signal, uint32 data)
uint32 muxcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const char *hold_or_clear = (signal > ioCLF ? ",C" : "");
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
const char *hold_or_clear = (signal_set & ioCLF ? ",C" : "");
uint16 data;
int32 ln, old;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
muxc_flag = muxc_flagbuf = CLEAR;
switch (signal) { /* dispatch I/O signal */
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fputs (">>MUXc cmds: [CLF] Flag cleared\n", sim_deb);
case ioCLF: /* clear flag flip-flop */
muxc.flag = muxc.flagbuf = CLEAR;
mux_ctrl_int (); /* look for new int */
break;
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fputs (">>MUXc cmds: [CLF] Flag cleared\n", sim_deb);
mux_ctrl_int (); /* look for new int */
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
muxc_flag = muxc_flagbuf = SET;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
muxc.flag = muxc.flagbuf = SET;
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fputs (">>MUXc cmds: [STF] Flag set\n", sim_deb);
break;
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fputs (">>MUXc cmds: [STF] Flag set\n", sim_deb);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (muxc);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (muxc);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (muxc);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (muxc);
break;
case ioIOI: /* I/O data input */
data = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */
LIC_TSTI (muxc_chan) | /* I2, I1 */
(muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */
(muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */
case ioIOI: /* I/O data input */
data = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */
LIC_TSTI (muxc_chan) | /* I2, I1 */
(muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */
(muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */
if (DEBUG_PRI (muxu_dev, DEB_CPU))
fprintf (sim_deb, ">>MUXc cpu: [LIx%s] Status = %06o, channel = %d\n",
hold_or_clear, data, muxc_chan);
if (DEBUG_PRI (muxu_dev, DEB_CPU))
fprintf (sim_deb, ">>MUXc cpu: [LIx%s] Status = %06o, channel = %d\n",
hold_or_clear, data, muxc_chan);
muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */
break;
muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
break;
case ioIOO: /* I/O data output */
ln = muxc_chan = OTC_CHAN (data); /* set channel */
case ioIOO: /* I/O data output */
data = IODATA (stat_data); /* clear supplied status */
ln = muxc_chan = OTC_CHAN (data); /* set channel */
if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */
else muxc_scan = 0;
if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */
else muxc_scan = 0;
if (data & OTC_UPD) { /* update? */
old = muxc_ota[ln]; /* save prior val */
muxc_ota[ln] = /* save ESn,SSn */
(muxc_ota[ln] & ~OTC_RW) | (data & OTC_RW);
if (data & OTC_UPD) { /* update? */
old = muxc_ota[ln]; /* save prior val */
muxc_ota[ln] = /* save ESn,SSn */
(muxc_ota[ln] & ~OTC_RW) | (data & OTC_RW);
if (data & OTC_EC2) /* if EC2, upd C2 */
muxc_ota[ln] =
(muxc_ota[ln] & ~OTC_C2) | (data & OTC_C2);
if (data & OTC_EC2) /* if EC2, upd C2 */
muxc_ota[ln] =
(muxc_ota[ln] & ~OTC_C2) | (data & OTC_C2);
if (data & OTC_EC1) /* if EC1, upd C1 */
muxc_ota[ln] =
(muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1);
if (data & OTC_EC1) /* if EC1, upd C1 */
muxc_ota[ln] =
(muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1);
if (muxu_unit.flags & UNIT_DIAG) /* loopback? */
muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */
(muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) |
(muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C;
if (muxu_unit.flags & UNIT_DIAG) /* loopback? */
muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */
(muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) |
(muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C;
else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */
(old & DTR) && /* DTR drop? */
!(muxc_ota[ln] & DTR)) {
tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n");
tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
muxc_lia[ln] = 0; /* dataset off */
}
} /* end update */
else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */
(old & DTR) && /* DTR drop? */
!(muxc_ota[ln] & DTR)) {
tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n");
tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
muxc_lia[ln] = 0; /* dataset off */
}
} /* end update */
if (DEBUG_PRI (muxu_dev, DEB_CPU))
fprintf (sim_deb, ">>MUXc cpu: [OTx%s] Parameter = %06o, channel = %d\n",
hold_or_clear, data, ln);
if (DEBUG_PRI (muxu_dev, DEB_CPU))
fprintf (sim_deb, ">>MUXc cpu: [OTx%s] Parameter = %06o, channel = %d\n",
hold_or_clear, data, ln);
if ((muxu_unit.flags & UNIT_DIAG) && (!muxc_flag)) /* loopback and flag clear? */
mux_ctrl_int (); /* status chg may interrupt */
break;
if ((muxu_unit.flags & UNIT_DIAG) && (!muxc.flag)) /* loopback and flag clear? */
mux_ctrl_int (); /* status chg may interrupt */
break;
case ioPOPIO: /* power-on preset to I/O */
muxc_flag = muxc_flagbuf = SET; /* set flag and flag buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
muxc_control = CLEAR;
break;
case ioPOPIO: /* power-on preset to I/O */
muxc.flag = muxc.flagbuf = SET; /* set flag and flag buffer */
break;
case ioSTC: /* set control flip-flop */
muxc_control = SET;
break;
case ioCRS: /* control reset */
case ioCLC: /* clear control flip-flop */
muxc.control = CLEAR;
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, muxc); /* set standard PRL signal */
setstdIRQ (select_code, muxc); /* set standard IRQ signal */
setstdSRQ (select_code, muxc); /* set standard SRQ signal */
break;
case ioSTC: /* set control flip-flop */
muxc.control = SET;
break;
case ioIAK: /* interrupt acknowledge */
muxc_flagbuf = CLEAR;
break;
case ioSIR: /* set interrupt request */
setstdPRL (muxc); /* set standard PRL signal */
setstdIRQ (muxc); /* set standard IRQ signal */
setstdSRQ (muxc); /* set standard SRQ signal */
break;
default: /* all other signals */
break; /* are ignored */
case ioIAK: /* interrupt acknowledge */
muxc.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
muxcio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
muxcio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -1004,8 +1020,8 @@ for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */
muxc_lia[ln] = 0; /* line disconnected */
}
if (!muxl_flag) mux_data_int (); /* scan for data int */
if (!muxc_flag) mux_ctrl_int (); /* scan modem */
if (!muxl.flag) mux_data_int (); /* scan for data int */
if (!muxc.flag) mux_ctrl_int (); /* scan modem */
return SCPE_OK;
}
@ -1066,7 +1082,7 @@ if (mux_ldsc[ln].conn) { /* connected? */
}
}
if (!muxl_flag) mux_data_int (); /* scan for int */
if (!muxl.flag) mux_data_int (); /* scan for int */
return SCPE_OK;
}
@ -1143,7 +1159,7 @@ for (i = 0; i < MUX_LINES; i++) { /* rcv lines */
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i);
muxlio (muxl_dib.devno, ioENF, 0); /* interrupt */
muxlio (&muxl_dib, ioENF, 0); /* interrupt */
return;
}
}
@ -1159,7 +1175,7 @@ for (i = 0; i < MUX_LINES; i++) { /* xmt lines */
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb, ">>MUXl cmds: Transmit channel %d interrupt requested\n", i);
muxlio (muxl_dib.devno, ioENF, 0); /* interrupt */
muxlio (&muxl_dib, ioENF, 0); /* interrupt */
return;
}
}
@ -1175,7 +1191,7 @@ for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */
if (DEBUG_PRI (muxu_dev, DEB_CMDS))
fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i);
muxlio (muxl_dib.devno, ioENF, 0); /* interrupt */
muxlio (&muxl_dib, ioENF, 0); /* interrupt */
return;
}
}
@ -1208,7 +1224,7 @@ for (i = 0; i < line_count; i++) {
">>MUXc cmds: Control channel %d interrupt requested (poll = %d)\n",
muxc_chan, i + 1);
muxcio (muxc_dib.devno, ioENF, 0); /* set flag */
muxcio (&muxc_dib, ioENF, 0); /* set flag */
break;
}
}
@ -1260,6 +1276,7 @@ return;
t_stat muxc_reset (DEVICE *dptr)
{
int32 i;
DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */
if (dptr == &muxc_dev) { /* make all consistent */
hp_enbdis_pair (dptr, &muxl_dev);
@ -1274,12 +1291,7 @@ else {
hp_enbdis_pair (dptr, &muxl_dev);
}
if (dptr == &muxl_dev) /* lower data reset? */
muxlio (muxl_dib.devno, ioPOPIO, 0); /* send POPIO signal to lower data card */
else if (dptr == &muxu_dev) /* upper data reset? */
muxuio (muxu_dib.devno, ioPOPIO, 0); /* send POPIO signal to upper data card */
else /* control card reset */
muxcio (muxc_dib.devno, ioPOPIO, 0); /* send POPIO signal to control card */
IOPRESET (dibptr); /* PRESET device (does not use PON) */
muxc_chan = muxc_scan = 0; /* init modem scan */

View file

@ -1,6 +1,6 @@
/* hp2100_pif.c: HP 12620A/12936A privileged interrupt fence simulator
Copyright (c) 2008, J. David Bryan
Copyright (c) 2008-2011, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
PIF 12620A/12936A privileged interrupt fence
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
26-Jun-08 JDB Rewrote device I/O to model backplane signals
18-Jun-08 JDB Created PIF device
@ -103,14 +105,16 @@
/* PIF state variables */
FLIP_FLOP pif_control = CLEAR; /* control flip-flop */
FLIP_FLOP pif_flag = CLEAR; /* flag flip-flop */
FLIP_FLOP pif_flagbuf = CLEAR; /* flag buffer flip-flop */
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} pif = { CLEAR, CLEAR, CLEAR };
/* PIF global routines */
uint32 pif_io (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER pif_io;
t_stat pif_reset (DEVICE *dptr);
t_stat pif_set_card (UNIT *uptr, int32 val, char *cptr, void *desc);
@ -136,17 +140,17 @@ t_stat pif_show_card (FILE *st, UNIT *uptr, int32 val, void *desc);
DEVICE pif_dev;
DIB pif_dib = { PIF, &pif_io };
DIB pif_dib = { &pif_io, PIF };
UNIT pif_unit = {
UDATA (NULL, 0, 0) /* dummy unit */
};
REG pif_reg [] = {
{ FLDATA (CTL, pif_control, 0) },
{ FLDATA (FLG, pif_flag, 0) },
{ FLDATA (FBF, pif_flagbuf, 0) },
{ ORDATA (DEVNO, pif_dib.devno, 6), REG_HRO },
{ FLDATA (CTL, pif.control, 0) },
{ FLDATA (FLG, pif.flag, 0) },
{ FLDATA (FBF, pif.flagbuf, 0) },
{ ORDATA (DEVNO, pif_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -155,7 +159,6 @@ MTAB pif_mod [] = {
{ MTAB_XTD | MTAB_VDV, 1, NULL, "12936A", &pif_set_card, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, NULL, &pif_show_card, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &pif_dev },
{ 0 }
};
@ -184,7 +187,6 @@ DEVICE pif_dev = {
NULL }; /* logical device name */
/* I/O signal handler.
Operation of the 12620A and the 12936A is different. The I/O responses of
@ -210,118 +212,120 @@ DEVICE pif_dev = {
Note that PRL and IRQ are non-standard for the 12936A.
*/
uint32 pif_io (uint32 select_code, IOSIG signal, uint32 data)
uint32 pif_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const char *hold_or_clear = (signal > ioCLF ? ",C" : "");
const char *hold_or_clear = (signal_set & ioCLF ? ",C" : "");
const t_bool is_rte_pif = (pif_dev.flags & DEV_12936) == 0;
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
switch (base_signal) { /* dispatch base I/O signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
case ioCLF: /* clear flag flip-flop */
pif_flag = pif_flagbuf = CLEAR; /* clear flag buffer and flag */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
if (DEBUG_PRS (pif_dev))
fputs (">>PIF: [CLF] Flag cleared\n", sim_deb);
break;
switch (signal) { /* dispatch I/O signal */
case ioSTF: /* set flag flip-flop */
if (is_rte_pif) { /* RTE PIF? */
pif_flag = pif_flagbuf = SET; /* set flag buffer and flag */
case ioCLF: /* clear flag flip-flop */
pif.flag = pif.flagbuf = CLEAR; /* clear flag buffer and flag */
if (DEBUG_PRS (pif_dev))
fputs (">>PIF: [STF] Flag set\n", sim_deb);
}
break;
fputs (">>PIF: [CLF] Flag cleared\n", sim_deb);
break;
case ioSFC: /* skip if flag is clear */
if (is_rte_pif) /* RTE PIF? */
setstdSKF (pif); /* card responds to SFC */
break;
case ioSTF: /* set flag flip-flop */
if (is_rte_pif) { /* RTE PIF? */
pif.flag = pif.flagbuf = SET; /* set flag buffer and flag */
if (DEBUG_PRS (pif_dev))
fputs (">>PIF: [STF] Flag set\n", sim_deb);
}
break;
case ioSFS: /* skip if flag is set */
if (is_rte_pif) /* RTE PIF? */
setstdSKF (pif); /* card responds to SFS */
break;
case ioSFC: /* skip if flag is clear */
if (is_rte_pif) /* RTE PIF? */
setstdSKF (pif); /* card responds to SFC */
break;
case ioIOO: /* I/O data output */
if (!is_rte_pif) { /* DOS PIF? */
pif_flag = pif_flagbuf = SET; /* set flag buffer and flag */
pif_io (select_code, ioSIR, 0); /* set IRQ (not normally done for IOO) */
case ioSFS: /* skip if flag is set */
if (is_rte_pif) /* RTE PIF? */
setstdSKF (pif); /* card responds to SFS */
break;
case ioIOO: /* I/O data output */
if (!is_rte_pif) { /* DOS PIF? */
pif.flag = pif.flagbuf = SET; /* set flag buffer and flag */
working_set = working_set | ioSIR; /* set SIR (not normally done for IOO) */
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [OTx%s] Flag set\n", hold_or_clear);
}
break;
case ioPOPIO: /* power-on preset to I/O */
pif.flag = pif.flagbuf = /* set or clear flag and flag buffer */
(is_rte_pif ? SET : CLEAR);
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [OTx%s] Flag set\n", hold_or_clear);
}
break;
fprintf (sim_deb, ">>PIF: [POPIO] Flag %s\n",
(is_rte_pif ? "set" : "cleared"));
break;
case ioPOPIO: /* power-on preset to I/O */
pif_flag = pif_flagbuf = /* set or clear flag and flag buffer */
(is_rte_pif ? SET : CLEAR);
case ioCRS: /* control reset */
case ioCLC: /* clear control flip-flop */
pif.control = CLEAR; /* clear control */
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [POPIO] Flag %s\n",
(is_rte_pif ? "set" : "cleared"));
/* fall into CRS handler */
case ioCRS: /* control reset */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
pif_control = CLEAR; /* clear control */
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [%s%s] Control cleared\n",
(signal == ioCRS ? "CRS" : "CLC"), hold_or_clear);
break;
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [%s%s] Control cleared\n",
(signal == ioCRS ? "CRS" : "CLC"), hold_or_clear);
break;
case ioSTC: /* set control flip-flop */
pif_control = SET; /* set control */
case ioSTC: /* set control flip-flop */
pif.control = SET; /* set control */
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [STC%s] Control set\n", hold_or_clear);
break;
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [STC%s] Control set\n", hold_or_clear);
break;
case ioSIR: /* set interrupt request */
if (is_rte_pif) { /* RTE PIF? */
setstdPRL (select_code, pif); /* set standard PRL signal */
setstdIRQ (select_code, pif); /* set standard IRQ signal */
setstdSRQ (select_code, pif); /* set standard SRQ signal */
}
case ioSIR: /* set interrupt request */
if (is_rte_pif) { /* RTE PIF? */
setstdPRL (pif); /* set standard PRL signal */
setstdIRQ (pif); /* set standard IRQ signal */
setstdSRQ (pif); /* set standard SRQ signal */
}
else { /* DOS PIF */
setPRL (select_code, !(pif_control | pif_flag));
setIRQ (select_code, !pif_control & pif_flag & pif_flagbuf);
}
else { /* DOS PIF */
setPRL (dibptr->select_code, !(pif.control | pif.flag));
setIRQ (dibptr->select_code, !pif.control & pif.flag & pif.flagbuf);
}
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [SIR] PRL = %d, IRQ = %d\n",
PRL (select_code), IRQ (select_code));
break;
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [SIR] PRL = %d, IRQ = %d\n",
PRL (dibptr->select_code),
IRQ (dibptr->select_code));
break;
case ioIAK: /* interrupt acknowledge */
pif_flagbuf = CLEAR;
break;
case ioIAK: /* interrupt acknowledge */
pif.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
pif_io (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
pif_io (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -329,7 +333,7 @@ return data;
t_stat pif_reset (DEVICE *dptr)
{
pif_io (pif_dib.devno, ioPOPIO, 0); /* send POPIO signal */
IOPRESET (&pif_dib); /* PRESET device (does not use PON) */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* hp2100_stddev.c: HP2100 standard devices simulator
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -28,6 +28,8 @@
TTY 12531C buffered teleprinter interface
CLK 12539C time base generator
28-Mar-11 JDB Tidied up signal handling
26-Oct-10 JDB Changed I/O signal handler for revised signal model
26-Jun-08 JDB Rewrote device I/O to model backplane signals
25-Apr-08 JDB Changed TTY output wait from 100 to 200 for MSU BASIC
18-Apr-08 JDB Removed redundant control char handling definitions
@ -125,23 +127,29 @@
#define CLK_V_ERROR 4 /* clock overrun */
#define CLK_ERROR (1 << CLK_V_ERROR)
FLIP_FLOP ptr_control = CLEAR;
FLIP_FLOP ptr_flag = CLEAR;
FLIP_FLOP ptr_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} ptr = { CLEAR, CLEAR, CLEAR };
int32 ptr_stopioe = 0; /* stop on error */
int32 ptr_trlcnt = 0; /* trailer counter */
int32 ptr_trllim = 40; /* trailer to add */
FLIP_FLOP ptp_control = CLEAR;
FLIP_FLOP ptp_flag = CLEAR;
FLIP_FLOP ptp_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} ptp = { CLEAR, CLEAR, CLEAR };
int32 ptp_stopioe = 0;
FLIP_FLOP tty_control = CLEAR;
FLIP_FLOP tty_flag = CLEAR;
FLIP_FLOP tty_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} tty = { CLEAR, CLEAR, CLEAR };
int32 ttp_stopioe = 0;
int32 tty_buf = 0; /* tty buffer */
@ -149,9 +157,11 @@ int32 tty_mode = 0; /* tty mode */
int32 tty_shin = 0377; /* tty shift in */
int32 tty_lf = 0; /* lf flag */
FLIP_FLOP clk_control = CLEAR;
FLIP_FLOP clk_flag = CLEAR;
FLIP_FLOP clk_flagbuf = CLEAR;
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} clk = { CLEAR, CLEAR, CLEAR };
int32 clk_select = 0; /* clock time select */
int32 clk_error = 0; /* clock error */
@ -169,17 +179,17 @@ uint32 clk_tick = 0; /* instructions per tick
DEVICE ptr_dev, ptp_dev, tty_dev, clk_dev;
uint32 ptrio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER ptrio;
t_stat ptr_svc (UNIT *uptr);
t_stat ptr_attach (UNIT *uptr, char *cptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
uint32 ptpio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER ptpio;
t_stat ptp_svc (UNIT *uptr);
t_stat ptp_reset (DEVICE *dptr);
uint32 ttyio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER ttyio;
t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tty_reset (DEVICE *dptr);
@ -188,7 +198,7 @@ t_stat tty_set_alf (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat tto_out (int32 c);
t_stat ttp_out (int32 c);
uint32 clkio (uint32 select_code, IOSIG signal, uint32 data);
IOHANDLER clkio;
t_stat clk_svc (UNIT *uptr);
t_stat clk_reset (DEVICE *dptr);
int32 clk_delay (int32 flg);
@ -201,7 +211,7 @@ int32 clk_delay (int32 flg);
ptr_reg PTR register list
*/
DIB ptr_dib = { PTR, &ptrio };
DIB ptr_dib = { &ptrio, PTR };
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
@ -210,15 +220,15 @@ UNIT ptr_unit = {
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 8) },
{ FLDATA (CTL, ptr_control, 0) },
{ FLDATA (FLG, ptr_flag, 0) },
{ FLDATA (FBF, ptr_flagbuf, 0) },
{ FLDATA (CTL, ptr.control, 0) },
{ FLDATA (FLG, ptr.flag, 0) },
{ FLDATA (FBF, ptr.flagbuf, 0) },
{ DRDATA (TRLCTR, ptr_trlcnt, 8), REG_HRO },
{ DRDATA (TRLLIM, ptr_trllim, 8), PV_LEFT },
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
{ ORDATA (DEVNO, ptr_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, ptr_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -246,7 +256,7 @@ DEVICE ptr_dev = {
ptp_reg PTP register list
*/
DIB ptp_dib = { PTP, &ptpio };
DIB ptp_dib = { &ptpio, PTP };
UNIT ptp_unit = {
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
@ -254,13 +264,13 @@ UNIT ptp_unit = {
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (CTL, ptp_control, 0) },
{ FLDATA (FLG, ptp_flag, 0) },
{ FLDATA (FBF, ptp_flagbuf, 0) },
{ FLDATA (CTL, ptp.control, 0) },
{ FLDATA (FLG, ptp.flag, 0) },
{ FLDATA (FBF, ptp.flagbuf, 0) },
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
{ ORDATA (DEVNO, ptp_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, ptp_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -290,7 +300,7 @@ DEVICE ptp_dev = {
#define TTO 1
#define TTP 2
DIB tty_dib = { TTY, &ttyio };
DIB tty_dib = { &ttyio, TTY };
UNIT tty_unit[] = {
{ UDATA (&tti_svc, UNIT_IDLE | TT_MODE_UC, 0), POLL_WAIT },
@ -302,9 +312,9 @@ REG tty_reg[] = {
{ ORDATA (BUF, tty_buf, 8) },
{ ORDATA (MODE, tty_mode, 16) },
{ ORDATA (SHIN, tty_shin, 8), REG_HRO },
{ FLDATA (CTL, tty_control, 0) },
{ FLDATA (FLG, tty_flag, 0) },
{ FLDATA (FBF, tty_flagbuf, 0) },
{ FLDATA (CTL, tty.control, 0) },
{ FLDATA (FLG, tty.flag, 0) },
{ FLDATA (FBF, tty.flagbuf, 0) },
{ FLDATA (KLFP, tty_lf, 0), REG_HRO },
{ DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
@ -312,7 +322,7 @@ REG tty_reg[] = {
{ DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (PPOS, tty_unit[TTP].pos, T_ADDR_W), PV_LEFT },
{ FLDATA (STOP_IOE, ttp_stopioe, 0) },
{ ORDATA (DEVNO, tty_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, tty_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -344,20 +354,20 @@ DEVICE tty_dev = {
clk_reg CLK register list
*/
DIB clk_dib = { CLK, &clkio };
DIB clk_dib = { &clkio, CLK };
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0) };
REG clk_reg[] = {
{ ORDATA (SEL, clk_select, 3) },
{ DRDATA (CTR, clk_ctr, 14) },
{ FLDATA (CTL, clk_control, 0) },
{ FLDATA (FLG, clk_flag, 0) },
{ FLDATA (FBF, clk_flagbuf, 0) },
{ FLDATA (CTL, clk.control, 0) },
{ FLDATA (FLG, clk.flag, 0) },
{ FLDATA (FBF, clk.flagbuf, 0) },
{ FLDATA (ERR, clk_error, CLK_V_ERROR) },
{ BRDATA (TIME, clk_time, 10, 24, 8) },
{ DRDATA (IPTICK, clk_tick, 24), PV_RSPC | REG_RO },
{ ORDATA (DEVNO, clk_dib.devno, 6), REG_HRO },
{ ORDATA (DEVNO, clk_dib.select_code, 6), REG_HRO },
{ NULL }
};
@ -392,78 +402,79 @@ DEVICE clk_dev = {
simulation, we omit the buffer clear.
*/
uint32 ptrio (uint32 select_code, IOSIG signal, uint32 data)
uint32 ptrio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
ptr_flag = ptr_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
ptr.flag = ptr.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
ptr_flag = ptr_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
ptr.flag = ptr.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (ptr);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (ptr);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (ptr);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (ptr);
break;
case ioIOI: /* I/O data input */
data = ptr_unit.buf;
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, ptr_unit.buf); /* merge in return status */
break;
case ioPOPIO: /* power-on preset to I/O */
ptr_flag = ptr_flagbuf = SET; /* set flag and flag buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
ptr_control = CLEAR;
break;
case ioPOPIO: /* power-on preset to I/O */
ptr.flag = ptr.flagbuf = SET; /* set flag and flag buffer */
break;
case ioSTC: /* set control flip-flop */
ptr_control = SET;
sim_activate (&ptr_unit, ptr_unit.wait);
break;
case ioCRS: /* control reset */
case ioCLC: /* clear control flip-flop */
ptr.control = CLEAR;
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, ptr); /* set standard PRL signal */
setstdIRQ (select_code, ptr); /* set standard IRQ signal */
setstdSRQ (select_code, ptr); /* set standard SRQ signal */
break;
case ioSTC: /* set control flip-flop */
ptr.control = SET;
sim_activate (&ptr_unit, ptr_unit.wait);
break;
case ioIAK: /* interrupt acknowledge */
ptr_flagbuf = CLEAR;
break;
case ioSIR: /* set interrupt request */
setstdPRL (ptr); /* set standard PRL signal */
setstdIRQ (ptr); /* set standard IRQ signal */
setstdSRQ (ptr); /* set standard SRQ signal */
break;
default: /* all other signals */
break; /* are ignored */
case ioIAK: /* interrupt acknowledge */
ptr.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
ptrio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
ptrio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -474,7 +485,7 @@ t_stat ptr_svc (UNIT *uptr)
int32 temp;
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptr_stopioe, SCPE_UNATT);
return IOERROR (ptr_stopioe, SCPE_UNATT);
while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */
if (feof (ptr_unit.fileref)) { /* end of file? */
if ((ptr_unit.flags & UNIT_DIAG) && (ptr_unit.pos > 0)) {
@ -501,7 +512,7 @@ while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */
}
}
ptrio (ptr_dib.devno, ioENF, 0); /* set flag */
ptrio (&ptr_dib, ioENF, 0); /* set flag */
ptr_unit.buf = temp & 0377; /* put byte in buf */
ptr_unit.pos = ftell (ptr_unit.fileref);
@ -526,7 +537,7 @@ return attach_unit (uptr, cptr);
t_stat ptr_reset (DEVICE *dptr)
{
ptrio (ptr_dib.devno, ioPOPIO, 0); /* send POPIO signal */
IOPRESET (&ptr_dib); /* PRESET device (does not use PON) */
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
}
@ -591,7 +602,7 @@ t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{
int32 dev;
dev = ptr_dib.devno; /* get device no */
dev = ptr_dib.select_code; /* get device no */
if (ibl_copy (ptr_rom, dev)) return SCPE_IERR; /* copy boot to memory */
SR = (SR & IBL_OPT) | IBL_PTR | (dev << IBL_V_DEV); /* set SR */
return SCPE_OK;
@ -608,87 +619,88 @@ return SCPE_OK;
state is implied by the activation of the PTP unit.
*/
uint32 ptpio (uint32 select_code, IOSIG signal, uint32 data)
uint32 ptpio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
ptp_flag = ptp_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
ptp.flag = ptp.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
ptp_flag = ptp_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
ptp.flag = ptp.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (ptp);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (ptp);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (ptp);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (ptp);
break;
case ioIOI: /* I/O data input */
if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */
data = PTP_LOW; /* report as out of tape */
else
data = 0;
break;
case ioIOI: /* I/O data input */
if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */
stat_data = IORETURN (SCPE_OK, PTP_LOW); /* report as out of tape */
else
stat_data = IORETURN (SCPE_OK, 0);
break;
case ioIOO: /* I/O data output */
ptp_unit.buf = data;
break;
case ioIOO: /* I/O data output */
ptp_unit.buf = IODATA (stat_data); /* clear supplied status */
break;
case ioPOPIO: /* power-on preset to I/O */
ptp_flag = ptp_flagbuf = SET; /* set flag and flag buffer */
ptp_unit.buf = 0; /* clear output buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
ptp_control = CLEAR;
break;
case ioPOPIO: /* power-on preset to I/O */
ptp.flag = ptp.flagbuf = SET; /* set flag and flag buffer */
ptp_unit.buf = 0; /* clear output buffer */
break;
case ioSTC: /* set control flip-flop */
ptp_control = SET;
sim_activate (&ptp_unit, ptp_unit.wait);
break;
case ioCRS: /* control reset */
case ioCLC: /* clear control flip-flop */
ptp.control = CLEAR;
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, ptp); /* set standard PRL signal */
setstdIRQ (select_code, ptp); /* set standard IRQ signal */
setstdSRQ (select_code, ptp); /* set standard SRQ signal */
break;
case ioSTC: /* set control flip-flop */
ptp.control = SET;
sim_activate (&ptp_unit, ptp_unit.wait);
break;
case ioIAK: /* interrupt acknowledge */
ptp_flagbuf = CLEAR;
break;
case ioSIR: /* set interrupt request */
setstdPRL (ptp); /* set standard PRL signal */
setstdIRQ (ptp); /* set standard IRQ signal */
setstdSRQ (ptp); /* set standard SRQ signal */
break;
default: /* all other signals */
break; /* are ignored */
case ioIAK: /* interrupt acknowledge */
ptp.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
ptpio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
ptpio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -696,10 +708,10 @@ return data;
t_stat ptp_svc (UNIT *uptr)
{
ptpio (ptp_dib.devno, ioENF, 0); /* set flag */
ptpio (&ptp_dib, ioENF, 0); /* set flag */
if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptp_stopioe, SCPE_UNATT);
return IOERROR (ptp_stopioe, SCPE_UNATT);
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* output byte */
perror ("PTP I/O error");
clearerr (ptp_unit.fileref);
@ -714,7 +726,7 @@ return SCPE_OK;
t_stat ptp_reset (DEVICE *dptr)
{
ptpio (ptp_dib.devno, ioPOPIO, 0); /* send POPIO signal */
IOPRESET (&ptp_dib); /* PRESET device (does not use PON) */
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
}
@ -722,97 +734,100 @@ return SCPE_OK;
/* Terminal I/O signal handler */
uint32 ttyio (uint32 select_code, IOSIG signal, uint32 data)
uint32 ttyio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
uint16 data;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
tty_flag = tty_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
tty.flag = tty.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
tty_flag = tty_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
tty.flag = tty.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (tty);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (tty);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (tty);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (tty);
break;
case ioIOI: /* I/O data input */
data = tty_buf;
case ioIOI: /* I/O data input */
data = tty_buf;
if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO]))
data = data | TP_BUSY;
break;
if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO]))
data = data | TP_BUSY;
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
break;
case ioIOO: /* I/O data output */
if (data & TM_MODE)
tty_mode = data & (TM_KBD|TM_PRI|TM_PUN);
case ioIOO: /* I/O data output */
data = IODATA (stat_data); /* clear supplied status */
tty_buf = data & 0377;
break;
if (data & TM_MODE)
tty_mode = data & (TM_KBD|TM_PRI|TM_PUN);
tty_buf = data & 0377;
break;
case ioPOPIO: /* power-on preset to I/O */
/* fall into CRS handler */
case ioCRS: /* control reset */
tty_control = CLEAR; /* clear control */
tty_flag = tty_flagbuf = SET; /* set flag and flag buffer */
tty_mode = TM_KBD; /* set tty, clear print/punch */
tty_shin = 0377; /* input inactive */
tty_lf = 0; /* no lf pending */
break;
case ioCRS: /* control reset */
tty.control = CLEAR; /* clear control */
tty.flag = tty.flagbuf = SET; /* set flag and flag buffer */
tty_mode = TM_KBD; /* set tty, clear print/punch */
tty_shin = 0377; /* input inactive */
tty_lf = 0; /* no lf pending */
break;
case ioCLC: /* clear control flip-flop */
tty_control = CLEAR;
break;
case ioCLC: /* clear control flip-flop */
tty.control = CLEAR;
break;
case ioSTC: /* set control flip-flop */
tty_control = SET;
case ioSTC: /* set control flip-flop */
tty.control = SET;
if (!(tty_mode & TM_KBD)) /* output? */
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait);
break;
if (!(tty_mode & TM_KBD)) /* output? */
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait);
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, tty); /* set standard PRL signal */
setstdIRQ (select_code, tty); /* set standard IRQ signal */
setstdSRQ (select_code, tty); /* set standard SRQ signal */
break;
case ioSIR: /* set interrupt request */
setstdPRL (tty); /* set standard PRL signal */
setstdIRQ (tty); /* set standard IRQ signal */
setstdSRQ (tty); /* set standard SRQ signal */
break;
case ioIAK: /* interrupt acknowledge */
tty_flagbuf = CLEAR;
break;
case ioIAK: /* interrupt acknowledge */
tty.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
ttyio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
ttyio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -880,7 +895,7 @@ if (tty_mode & TM_KBD) { /* keyboard enabled? */
tty_buf = c; /* put char in buf */
uptr->pos = uptr->pos + 1;
ttyio (tty_dib.devno, ioENF, 0); /* set flag */
ttyio (&tty_dib, ioENF, 0); /* set flag */
if (c) {
tto_out (c); /* echo? */
@ -907,7 +922,7 @@ if ((r = tto_out (c)) != SCPE_OK) { /* output; error? */
return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */
}
ttyio (tty_dib.devno, ioENF, 0); /* set flag */
ttyio (&tty_dib, ioENF, 0); /* set flag */
return ttp_out (c); /* punch if enabled */
}
@ -932,7 +947,7 @@ t_stat ttp_out (int32 c)
{
if (tty_mode & TM_PUN) { /* punching? */
if ((tty_unit[TTP].flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ttp_stopioe, SCPE_UNATT);
return IOERROR (ttp_stopioe, SCPE_UNATT);
if (putc (c, tty_unit[TTP].fileref) == EOF) { /* output char */
perror ("TTP I/O error");
clearerr (tty_unit[TTP].fileref);
@ -948,10 +963,10 @@ return SCPE_OK;
t_stat tty_reset (DEVICE *dptr)
{
if (sim_switches & SWMASK ('P')) /* PON reset? */
if (sim_switches & SWMASK ('P')) /* initialization reset? */
tty_buf = 0; /* clear buffer */
ttyio (tty_dib.devno, ioPOPIO, 0); /* send POPIO signal */
IOPRESET (&tty_dib); /* PRESET device (does not use PON) */
tty_unit[TTI].wait = POLL_WAIT; /* reset initial poll */
sim_rtcn_init (tty_unit[TTI].wait, TMR_POLL); /* init poll timer */
@ -1024,105 +1039,105 @@ int32 poll_time;
expected.
*/
uint32 clkio (uint32 select_code, IOSIG signal, uint32 data)
uint32 clkio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const IOSIG base_signal = IOBASE (signal); /* derive base signal */
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
switch (base_signal) { /* dispatch base I/O signal */
while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */
case ioCLF: /* clear flag flip-flop */
clk_flag = clk_flagbuf = CLEAR;
break;
switch (signal) { /* dispatch I/O signal */
case ioCLF: /* clear flag flip-flop */
clk.flag = clk.flagbuf = CLEAR;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
clk_flag = clk_flagbuf = SET;
break;
case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */
clk.flag = clk.flagbuf = SET;
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (clk);
break;
case ioSFC: /* skip if flag is clear */
setstdSKF (clk);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (clk);
break;
case ioSFS: /* skip if flag is set */
setstdSKF (clk);
break;
case ioIOI: /* I/O data input */
data = clk_error;
break;
case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, clk_error); /* merge in return status */
break;
case ioIOO: /* I/O data output */
clk_select = data & 07; /* save select */
sim_cancel (&clk_unit); /* stop the clock */
clk_control = CLEAR; /* clear control */
clkio (select_code, ioSIR, 0); /* set interrupt request (IOO normally doesn't) */
break;
case ioIOO: /* I/O data output */
clk_select = IODATA (stat_data) & 07; /* save select */
sim_cancel (&clk_unit); /* stop the clock */
clk.control = CLEAR; /* clear control */
working_set = working_set | ioSIR; /* set interrupt request (IOO normally doesn't) */
break;
case ioPOPIO: /* power-on preset to I/O */
clk_flag = clk_flagbuf = SET; /* set flag and flag buffer */
/* fall into CRS handler */
case ioCRS: /* control reset */
/* fall into CLC handler */
case ioCLC: /* clear control flip-flop */
clk_control = CLEAR;
sim_cancel (&clk_unit); /* deactivate unit */
break;
case ioPOPIO: /* power-on preset to I/O */
clk.flag = clk.flagbuf = SET; /* set flag and flag buffer */
break;
case ioSTC: /* set control flip-flop */
clk_control = SET;
if (clk_unit.flags & UNIT_DIAG) /* diag mode? */
clk_unit.flags = clk_unit.flags & ~UNIT_IDLE; /* not calibrated */
else
clk_unit.flags = clk_unit.flags | UNIT_IDLE; /* is calibrated */
if (!sim_is_active (&clk_unit)) { /* clock running? */
clk_tick = clk_delay (0); /* get tick count */
if ((clk_unit.flags & UNIT_DIAG) == 0) /* calibrated? */
if (clk_select == 2) /* 10 msec. interval? */
clk_tick = sync_poll (INITIAL); /* sync poll */
else
sim_rtcn_init (clk_tick, TMR_CLK); /* initialize timer */
sim_activate (&clk_unit, clk_tick); /* start clock */
clk_ctr = clk_delay (1); /* set repeat ctr */
}
clk_error = 0; /* clear error */
break;
case ioCRS: /* control reset */
case ioCLC: /* clear control flip-flop */
clk.control = CLEAR;
sim_cancel (&clk_unit); /* deactivate unit */
break;
case ioSIR: /* set interrupt request */
setstdPRL (select_code, clk); /* set standard PRL signal */
setstdIRQ (select_code, clk); /* set standard IRQ signal */
setstdSRQ (select_code, clk); /* set standard SRQ signal */
break;
case ioSTC: /* set control flip-flop */
clk.control = SET;
if (clk_unit.flags & UNIT_DIAG) /* diag mode? */
clk_unit.flags = clk_unit.flags & ~UNIT_IDLE; /* not calibrated */
else
clk_unit.flags = clk_unit.flags | UNIT_IDLE; /* is calibrated */
if (!sim_is_active (&clk_unit)) { /* clock running? */
clk_tick = clk_delay (0); /* get tick count */
if ((clk_unit.flags & UNIT_DIAG) == 0) /* calibrated? */
if (clk_select == 2) /* 10 msec. interval? */
clk_tick = sync_poll (INITIAL); /* sync poll */
else
sim_rtcn_init (clk_tick, TMR_CLK); /* initialize timer */
sim_activate (&clk_unit, clk_tick); /* start clock */
clk_ctr = clk_delay (1); /* set repeat ctr */
}
clk_error = 0; /* clear error */
break;
case ioIAK: /* interrupt acknowledge */
clk_flagbuf = CLEAR;
break;
case ioSIR: /* set interrupt request */
setstdPRL (clk); /* set standard PRL signal */
setstdIRQ (clk); /* set standard IRQ signal */
setstdSRQ (clk); /* set standard SRQ signal */
break;
default: /* all other signals */
break; /* are ignored */
case ioIAK: /* interrupt acknowledge */
clk.flagbuf = CLEAR;
break;
default: /* all other signals */
break; /* are ignored */
}
working_set = working_set & ~signal; /* remove current signal from set */
}
if (signal > ioCLF) /* multiple signals? */
clkio (select_code, ioCLF, 0); /* issue CLF */
else if (signal > ioSIR) /* signal affected interrupt status? */
clkio (select_code, ioSIR, 0); /* set interrupt request */
return data;
return stat_data;
}
@ -1134,7 +1149,7 @@ return data;
t_stat clk_svc (UNIT *uptr)
{
if (!clk_control) /* control clear? */
if (!clk.control) /* control clear? */
return SCPE_OK; /* done */
if (clk_unit.flags & UNIT_DIAG) /* diag mode? */
@ -1147,10 +1162,10 @@ else
sim_activate (uptr, clk_tick); /* reactivate */
clk_ctr = clk_ctr - 1; /* decrement counter */
if (clk_ctr <= 0) { /* end of interval? */
if (clk_flag)
if (clk.flag)
clk_error = CLK_ERROR; /* overrun? error */
else
clkio (clk_dib.devno, ioENF, 0); /* set flag */
clkio (&clk_dib, ioENF, 0); /* set flag */
clk_ctr = clk_delay (1); /* reset counter */
}
return SCPE_OK;
@ -1161,13 +1176,13 @@ return SCPE_OK;
t_stat clk_reset (DEVICE *dptr)
{
if (sim_switches & SWMASK ('P')) { /* PON reset? */
if (sim_switches & SWMASK ('P')) { /* initialization reset? */
clk_error = 0; /* clear error */
clk_select = 0; /* clear select */
clk_ctr = 0; /* clear counter */
}
clkio (clk_dib.devno, ioPOPIO, 0); /* send POPIO signal */
IOPRESET (&clk_dib); /* PRESET device (does not use PON) */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* hp2100_sys.c: HP 2100 simulator interface
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2010, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,8 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation
26-Oct-10 JDB Changed DIB access for revised signal model
03-Sep-08 JDB Fixed IAK instruction dual-use mnemonic display
07-Aug-08 JDB Moved hp_setdev, hp_showdev from hp2100_cpu.c
Changed sim_load to use WritePW instead of direct M[] access
@ -60,7 +62,7 @@ extern UNIT cpu_unit;
extern REG cpu_reg[];
extern DEVICE mp_dev;
extern DEVICE dma0_dev, dma1_dev;
extern DEVICE dma1_dev, dma2_dev;
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tty_dev, clk_dev;
extern DEVICE lps_dev;
@ -98,8 +100,7 @@ int32 sim_emax = 3;
DEVICE *sim_devices[] = {
&cpu_dev,
&mp_dev,
&dma0_dev,
&dma1_dev,
&dma1_dev, &dma2_dev,
&ptr_dev,
&ptp_dev,
&tty_dev,
@ -772,18 +773,18 @@ else { /* printable character *
t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc)
{
DEVICE *dptr = (DEVICE *) desc;
DIB *dibp;
DIB *dibptr;
int32 i, newdev;
t_stat r;
if (cptr == NULL) return SCPE_ARG;
if ((desc == NULL) || (num > 1)) return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL) return SCPE_IERR;
dibptr = (DIB *) dptr->ctxt;
if (dibptr == NULL) return SCPE_IERR;
newdev = get_uint (cptr, 8, I_DEVMASK - num, &r);
if (r != SCPE_OK) return r;
if (newdev < VARDEV) return SCPE_ARG;
for (i = 0; i <= num; i++, dibp++) dibp->devno = newdev + i;
for (i = 0; i <= num; i++, dibptr++) dibptr->select_code = newdev + i;
return SCPE_OK;
}
@ -793,13 +794,13 @@ return SCPE_OK;
t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc)
{
DEVICE *dptr = (DEVICE *) desc;
DIB *dibp;
DIB *dibptr;
int32 i;
if ((desc == NULL) || (num > 1)) return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL) return SCPE_IERR;
fprintf (st, "devno=%o", dibp->devno);
for (i = 1; i <= num; i++) fprintf (st, "/%o", dibp->devno + i);
dibptr = (DIB *) dptr->ctxt;
if (dibptr == NULL) return SCPE_IERR;
fprintf (st, "devno=%o", dibptr->select_code);
for (i = 1; i <= num; i++) fprintf (st, "/%o", dibptr->select_code + i);
return SCPE_OK;
}

View file

@ -266,6 +266,7 @@ REG cpu_reg[] = {
{ FLDATA (IOCHK, iochk, 0) },
{ FLDATA (PRCHK, prchk, 0) },
{ FLDATA (HBPEND, hb_pend, 0) },
{ BRDATA (IND, ind, 8, 32, 64), REG_HIDDEN + PV_LEFT },
{ BRDATA (ISQ, pcq, 10, 14, PCQ_SIZE), REG_RO+REG_CIRC },
{ DRDATA (ISQP, pcq_p, 6), REG_HRO },
{ ORDATA (WRU, sim_int_char, 8) },

View file

@ -93,8 +93,8 @@ ind[IN_INC] = 0; /* clear inq clear */
switch (mod) { /* case on mod */
case BCD_R: /* input */
/* if (ind[IN_INR] == 0) /* return if no req */
return SCPE_OK;
/* if (ind[IN_INR] == 0)
/* return SCPE_OK; /* return if no req */
ind[IN_INR] = 0; /* clear req */
puts_tty ("[Enter]\r\n"); /* prompt */
for (i = 0; M[BS] != (BCD_GRPMRK + WM); i++) { /* until GM + WM */

View file

@ -1,6 +1,6 @@
/* i7094_clk.c: IBM 7094 clock
Copyright (c) 2003-2008, Robert M. Supnik
Copyright (c) 2003-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
clk RPQ F89349 interval timer
Chronolog calendar clock
25-Mar-11 RMS According to RPQ, clock clears on RESET
*/
#include "i7094_defs.h"
@ -68,9 +70,9 @@ t_uint64 ctr;
if ((clk_dev.flags & DEV_DIS) == 0) { /* clock enabled? */
ctr = ReadP (CLK_CTR);
ctr = (ctr + 1) & DMASK; /* increment */
ctr = (ctr + 1) & MMASK; /* increment */
WriteP (CLK_CTR, ctr);
if ((ctr & MMASK) == 0) /* overflow? req trap */
if (ctr == 0) /* overflow? req trap */
chtr_clk = 1;
sim_activate (uptr, sim_rtcn_calb (CLK_TPS, TMR_CLK)); /* reactivate unit */
}
@ -126,6 +128,9 @@ t_stat clk_reset (DEVICE *dptr)
chtr_clk = 0;
if (clk_dev.flags & DEV_DIS)
sim_cancel (&clk_unit);
else sim_activate (&clk_unit, sim_rtcn_init (clk_unit.wait, TMR_CLK));
else {
sim_activate (&clk_unit, sim_rtcn_init (clk_unit.wait, TMR_CLK));
WriteP (CLK_CTR, 0);
}
return SCPE_OK;
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* i7094_cpu.c: IBM 7094 CPU simulator
Copyright (c) 2003-2010, Robert M. Supnik
Copyright (c) 2003-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,7 +25,10 @@
cpu 7094 central processor
16-Jul-10 RMS Fixed PSE, MSE user mode protection (found by Dave Pitts)
31-Dec-11 RMS Select traps have priority over protect traps
Added SRI, SPI
Fixed user mode and relocation from CTSS RPQ documentation
16-Jul-10 RMS Fixed user mode protection (found by Dave Pitts)
Fixed issues in storage nullification mode
28-Apr-07 RMS Removed clock initialization
29-Oct-06 RMS Added additional expanded core instructions
@ -57,6 +60,9 @@
protection, and relocation. Additional state:
USER user mode
RELOCM relocation mode
USER_BUF user mode buffer
RELOC_BUF relocation buffer
INST_BASE instruction memory select (A vs B core)
DATA_BASE data memory select (A vs B core)
IND_RELOC<0:6> relocation value (block number)
@ -121,8 +127,8 @@
ch_flags[0..7] flags for channels A..H
chtr_enab channel trap enables
chtr_inht channel trap inhibit due to trap (cleared by RCT)
chtr_inhi channel trap inhibit due to XEC, ENAB, RCT, RDS,
or WDS (cleared after one instruction)
chtr_inhi channel trap inhibit due to XEC, ENB, RCT, LRI,
LPI, SEA, SEB (cleared after one instruction)
Channel traps are summarized in variable chtr_pend.
@ -179,6 +185,9 @@ uint32 ind_dvc = 0; /* divide check */
uint32 ind_ioc = 0; /* IO check */
uint32 cpu_model = I_9X|I_94; /* CPU type */
uint32 mode_user = 0; /* (CTSS) user mode */
uint32 mode_reloc = 0; /* (CTSS) relocation mode */
uint32 user_buf = 0; /* (CTSS) user mode buffer */
uint32 reloc_buf = 0; /* (CTSS) reloc mode buffer */
uint32 ind_reloc = 0; /* (CTSS) relocation */
uint32 ind_start = 0; /* (CTSS) prot start */
uint32 ind_limit = 0; /* (CTSS) prot limit */
@ -307,6 +316,9 @@ REG cpu_reg[] = {
{ FLDATA (CHTR_INHI, chtr_inhi, 0) },
{ ORDATA (CHTR_ENAB, chtr_enab, 30) },
{ FLDATA (USERM, mode_user, 0) },
{ FLDATA (RELOCM, mode_reloc, 0) },
{ FLDATA (USERBUF, user_buf, 0) },
{ FLDATA (RELOCBUF, reloc_buf, 0) },
{ FLDATA (IMEM, inst_base, BCORE_V) },
{ FLDATA (DMEM, data_base, BCORE_V) },
{ GRDATA (RELOC, ind_reloc, 8, VA_N_BLK, VA_V_BLK) },
@ -572,8 +584,8 @@ const uint8 op_flags[1024] = {
I_XNR|I_CT, 0 , 0 , 0 ,
0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 ,
I_XN , 0 , I_XNR|I_9X, I_XN|I_94 , /* -600 */
0 , 0 , 0 , 0 ,
I_XN , I_CT , I_XNR|I_9X, I_XN|I_94 , /* -600 */
I_CT , 0 , 0 , 0 ,
0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 ,
I_XNR|I_9X, 0 , 0 , 0 , /* -620 */
@ -685,6 +697,10 @@ while (reason == SCPE_OK) { /* loop until error */
chtr_inhi = 0; /* clear */
chtr_pend = chtr_eval (NULL); /* re-evaluate */
}
else if (cpu_model & I_CT) { /* CTSS? */
mode_user = user_buf; /* load modes from buffers */
mode_reloc = reloc_buf;
}
oldPC = PC; /* save current PC */
PC = (PC + 1) & EAMASK; /* increment PC */
if (!ReadI (oldPC, &IR)) /* get inst; trap? */
@ -945,9 +961,15 @@ while (reason == SCPE_OK) { /* loop until error */
case 00101: /* (CTSS) TIA */
if (prot_trap (0)) /* not user mode? */
break;
PCQ_ENTRY;
PC = ea;
inst_base = 0;
if (mode_ttrap) { /* trap? */
WriteTA (TRAP_STD_SAV, oldPC); /* save PC */
TrapXfr (TRAP_TRA_PC); /* trap */
}
else {
PCQ_ENTRY;
PC = ea;
inst_base = 0;
}
break;
case 00114: case 00115: case 00116: case 00117: /* CVR */
@ -1267,6 +1289,9 @@ while (reason == SCPE_OK) { /* loop until error */
if (prot_trap (0)) /* user mode? */
break;
ind_reloc = ((uint32) SR) & VA_BLK;
reloc_buf = 1; /* set mode buffer */
chtr_inhi = 1; /* delay traps */
chtr_pend = 0; /* no trap now */
break;
case 00564: /* ENB */
@ -1380,6 +1405,8 @@ while (reason == SCPE_OK) { /* loop until error */
/* Negative instructions */
case 01021: /* ESNT */
if (prot_trap (0)) /* user mode? */
break;
mode_storn = 1; /* enter nullification */
PCQ_ENTRY;
PC = ea; /* branch, no trap */
@ -1431,10 +1458,15 @@ while (reason == SCPE_OK) { /* loop until error */
case 01101: /* (CTSS) TIB */
if (prot_trap (0)) /* user mode? */
break;
PCQ_ENTRY;
PC = ea;
mode_user = 1;
inst_base = BCORE_BASE;
if (mode_ttrap) { /* trap? */
WriteTA (TRAP_STD_SAV, oldPC); /* save PC */
TrapXfr (TRAP_TRA_PC); /* trap */
}
else {
PCQ_ENTRY;
PC = ea;
inst_base = BCORE_BASE;
}
break;
case 01114: case 01115: case 01116: case 01117: /* CAQ */
@ -1624,12 +1656,21 @@ while (reason == SCPE_OK) { /* loop until error */
break;
ind_start = ((uint32) SR) & VA_BLK;
ind_limit = (GET_DEC (SR) & VA_BLK) | VA_OFF;
user_buf = 1; /* set mode buffer */
chtr_inhi = 1; /* delay traps */
chtr_pend = 0; /* no trap now */
break;
case 01600: /* STQ */
Write (ea, MQ);
break;
case 01601: /* SRI (CTSS) */
SR = ind_reloc & VA_BLK;
/* add reloc mode in bit 1 */
Write (ea, SR);
break;
case 01602: /* ORS */
SR = SR | (AC & DMASK);
Write (ea, SR);
@ -1642,6 +1683,13 @@ while (reason == SCPE_OK) { /* loop until error */
Write ((ea + 1) & EAMASK, MQ);
break;
case 01604: /* SPI (CTSS) */
SR = (((t_uint64) (ind_limit & VA_BLK)) << INST_V_DEC) |
((t_uint64) (ind_start & VA_BLK));
/* add prot mode in bit 2 */
Write (ea, SR);
break;
case 01620: /* SLQ */
SR = (SR & RMASK) | (MQ & LMASK);
Write (ea, SR);
@ -1833,10 +1881,8 @@ while (reason == SCPE_OK) { /* loop until error */
case 00640: case 00641: case 00642: case 00643: /* SCHx */
case 01640: case 01641: case 01642: case 01643:
if (prot_trap (0)) /* user mode? */
break;
ch = ((op & 03) << 1) | ((op >> 9) & 01);
if ((reason = ch_op_store (ch, &SR)) == SCPE_OK)
ch = ((op & 03) << 1) | ((op >> 9) & 01);
if ((reason = ch_op_store (ch, &SR)) == SCPE_OK)
Write (ea, SR);
break;
@ -1848,7 +1894,7 @@ while (reason == SCPE_OK) { /* loop until error */
break;
case 00762: /* RDS */
if (prot_trap (0) || sel_trap (PC))
if (sel_trap (0) || prot_trap (PC)) /* select takes priority */
break;
ch = GET_U_CH (IR);
reason = ch_op_ds (ch, CHSL_RDS, GET_U_UNIT (ea));
@ -1856,7 +1902,7 @@ while (reason == SCPE_OK) { /* loop until error */
break;
case 00764: /* BSR */
if (prot_trap (0) || sel_trap (PC))
if (sel_trap (0) || prot_trap (PC)) /* select takes priority */
break;
ch = GET_U_CH (IR);
reason = ch_op_nds (ch, CHSL_BSR, GET_U_UNIT (ea));
@ -1864,7 +1910,7 @@ while (reason == SCPE_OK) { /* loop until error */
break;
case 00766: /* WRS */
if (prot_trap (0) || sel_trap (PC))
if (sel_trap (0) || prot_trap (PC)) /* select takes priority */
break;
ch = GET_U_CH (IR);
reason = ch_op_ds (ch, CHSL_WRS, GET_U_UNIT (ea));
@ -1872,7 +1918,7 @@ while (reason == SCPE_OK) { /* loop until error */
break;
case 00770: /* WEF */
if (prot_trap (0) || sel_trap (PC))
if (sel_trap (0) || prot_trap (PC)) /* select takes priority */
break;
ch = GET_U_CH (IR);
reason = ch_op_nds (ch, CHSL_WEF, GET_U_UNIT (ea));
@ -1880,7 +1926,7 @@ while (reason == SCPE_OK) { /* loop until error */
break;
case 00772: /* REW */
if (prot_trap (0) || sel_trap (PC))
if (sel_trap (0) || prot_trap (PC)) /* select takes priority */
break;
ch = GET_U_CH (IR);
reason = ch_op_nds (ch, CHSL_REW, GET_U_UNIT (ea));
@ -1888,7 +1934,7 @@ while (reason == SCPE_OK) { /* loop until error */
break;
case 01764: /* BSF */
if (prot_trap (0) || sel_trap (PC))
if (sel_trap (0) || prot_trap (PC)) /* select takes priority */
break;
ch = GET_U_CH (IR);
reason = ch_op_nds (ch, CHSL_BSF, GET_U_UNIT (ea));
@ -1896,7 +1942,7 @@ while (reason == SCPE_OK) { /* loop until error */
break;
case 01772: /* RUN */
if (prot_trap (0) || sel_trap (PC))
if (sel_trap (0) || prot_trap (PC)) /* select takes priority */
break;
ch = GET_U_CH (IR);
reason = ch_op_nds (ch, CHSL_RUN, GET_U_UNIT (ea));
@ -1904,7 +1950,7 @@ while (reason == SCPE_OK) { /* loop until error */
break;
case 00776: /* SDN */
if (prot_trap (0) || sel_trap (PC))
if (sel_trap (0) || prot_trap (PC)) /* select takes priority */
break;
ch = GET_U_CH (IR);
reason = ch_op_nds (ch, CHSL_SDN, GET_U_UNIT (ea));
@ -2069,7 +2115,8 @@ WriteP (pa, mem);
mode_ctrap = 0;
mode_strap = 0;
mode_storn = 0;
mode_user = 0;
mode_user = user_buf = 0;
mode_reloc = reloc_buf = 0;
inst_base = 0;
data_base = 0;
return;
@ -2121,7 +2168,8 @@ PC = newpc;
mode_ctrap = 0;
mode_strap = 0;
mode_storn = 0;
mode_user = 0;
mode_user = user_buf = 0;
mode_reloc = reloc_buf = 0;
inst_base = 0;
data_base = 0;
return;
@ -2131,12 +2179,11 @@ return;
t_bool ReadI (uint32 va, t_uint64 *val)
{
if (mode_user) {
if (mode_reloc)
va = (va + ind_reloc) & AMASK;
if ((va < ind_start) || (va > ind_limit)) {
prot_trap (0);
return FALSE;
}
if (mode_user && ((va < ind_start) || (va > ind_limit))) {
prot_trap (0);
return FALSE;
}
*val = M[va | inst_base];
return TRUE;
@ -2146,12 +2193,11 @@ return TRUE;
t_bool Read (uint32 va, t_uint64 *val)
{
if (mode_user) {
if (mode_reloc)
va = (va + ind_reloc) & AMASK;
if ((va < ind_start) || (va > ind_limit)) {
prot_trap (0);
return FALSE;
}
if (mode_user && ((va < ind_start) || (va > ind_limit))) {
prot_trap (0);
return FALSE;
}
*val = M[va | data_base];
return TRUE;
@ -2161,12 +2207,11 @@ return TRUE;
t_bool Write (uint32 va, t_uint64 dat)
{
if (mode_user) {
if (mode_reloc)
va = (va + ind_reloc) & AMASK;
if ((va < ind_start) || (va > ind_limit)) {
prot_trap (0);
return FALSE;
}
if (mode_user && ((va < ind_start) || (va > ind_limit))) {
prot_trap (0);
return FALSE;
}
M[va | data_base] = dat;
return TRUE;
@ -2191,7 +2236,8 @@ mode_storn = 0;
if (cpu_model & (I_94|I_CT))
mode_multi = 0;
else mode_multi = 1;
mode_user = 0;
mode_user = user_buf = 0;
mode_reloc = reloc_buf = 0;
inst_base = 0;
data_base = 0;
ch_req = 0;
@ -2220,8 +2266,7 @@ if (vptr == NULL)
return SCPE_ARG;
if ((sw & (SWMASK ('A') | SWMASK ('B')))? (ea > AMASK): (ea >= MEMSIZE))
return SCPE_NXM;
if ((sw & SWMASK ('B')) ||
((sw & SWMASK ('V')) && mode_user && inst_base))
if (sw & SWMASK ('B'))
ea = ea | BCORE_BASE;
*vptr = M[ea] & DMASK;
return SCPE_OK;

View file

@ -1,6 +1,6 @@
/* i7094_cpu1.c: IBM 7094 CPU complex instructions
Copyright (c) 2003-2010, Robert M. Supnik
Copyright (c) 2003-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,9 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
31-Dec-11 RMS Refined PSE and MSE user-mode protection based on
CTSS RPQ specification
Select traps have priority over protection traps
16-Jul-10 RMS Fixed PSE and MSE user-mode protection (from Dave Pitts)
Added SPUx, SPTx, SPRx
*/
@ -296,10 +299,11 @@ switch (addr) {
break;
case 00007: /* ETM */
if (prot_trap (0)) /* user mode? */
break;
if (cpu_model & I_9X) /* 709X only */
if (cpu_model & I_9X) { /* 709X only */
if (prot_trap (0)) /* user mode? */
break;
mode_ttrap = 1;
}
break;
case 00010: /* RND */
@ -322,6 +326,8 @@ switch (addr) {
break;
case 00014: /* RCT */
if (prot_trap (0)) /* user mode? */
break;
chtr_inhi = 1; /* 1 cycle delay */
chtr_inht = 0; /* clr inhibit trap */
chtr_pend = 0; /* no trap now */
@ -350,10 +356,8 @@ switch (addr) {
case 001000: case 002000: case 003000: case 004000: /* BTT */
case 005000: case 060000: case 070000: case 010000:
if (prot_trap (0)) /* user mode? */
break;
if (cpu_model & I_9X) { /* 709X only */
if (sel_trap (PC)) /* sel trap? */
if (cpu_model & I_9X) { /* 709X only */
if (sel_trap (0) || prot_trap (PC)) /* select takes priority */
break;
ch = GET_U_CH (addr); /* get channel */
if (ch_flags[ch] & CHF_BOT) /* BOT? */
@ -437,32 +441,43 @@ switch (addr) {
break;
case 00004: /* LFTM */
if (prot_trap (0)) /* user mode? */
break;
if (cpu_model & I_9X) /* 709X only */
if (cpu_model & I_9X) { /* 709X only */
if (prot_trap (0)) /* user mode? */
break;
mode_ftrap = 0;
}
break;
case 00005: /* ESTM */
if (cpu_model & I_9X) /* 709X only */
if (cpu_model & I_9X) { /* 709X only */
if (prot_trap (0)) /* user mode? */
break;
mode_strap = 1;
}
break;
case 00006: /* ECTM */
if (cpu_model & I_9X) /* 709X only */
if (cpu_model & I_9X) { /* 709X only */
if (prot_trap (0)) /* user mode? */
break;
mode_ctrap = 1;
}
break;
case 00007: /* LTM */
if (prot_trap (0)) /* user mode? */
break;
if (cpu_model & I_9X) /* 709X only */
if (cpu_model & I_9X) { /* 709X only */
if (prot_trap (0)) /* user mode? */
break;
mode_ttrap = 0;
}
break;
case 00010: /* LSNM */
if (cpu_model & I_9X) /* 709X only */
if (cpu_model & I_9X) { /* 709X only */
if (prot_trap (0)) /* user mode? */
break;
mode_storn = 0;
}
break;
case 00012: /* RTT (704) */
@ -497,7 +512,7 @@ switch (addr) {
case 001000: case 002000: case 003000: case 004000: /* ETT */
case 005000: case 006000: case 007000: case 010000:
if (sel_trap (PC)) /* sel trap? */
if (sel_trap (0) || prot_trap (PC)) /* select takes priority */
break;
ch = GET_U_CH (addr); /* get channel */
if (ch_flags[ch] & CHF_EOT) /* EOT? */

View file

@ -1,887 +0,0 @@
/* i7094_cpu1.c: IBM 7094 CPU complex instructions
Copyright (c) 2003-2008, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include "i7094_defs.h"
#define FP_HIFRAC(x) ((uint32) ((x) >> FP_N_FR) & FP_FMASK)
#define FP_LOFRAC(x) ((uint32) (x) & FP_FMASK)
#define FP_PACK38(s,e,f) (((s)? AC_S: 0) | ((t_uint64) (f)) | \
(((t_uint64) ((e) & FP_M_ACCH)) << FP_V_CH))
#define FP_PACK36(s,e,f) (((s)? SIGN: 0) | ((t_uint64) (f)) | \
(((t_uint64) ((e) & FP_M_CH)) << FP_V_CH))
extern t_uint64 AC, MQ, SI, KEYS;
extern uint32 PC;
extern uint32 SLT, SSW;
extern uint32 cpu_model, stop_illop;
extern uint32 ind_ovf, ind_dvc, ind_ioc, ind_mqo;
extern uint32 mode_ttrap, mode_strap, mode_ctrap, mode_ftrap;
extern uint32 mode_storn, mode_multi;
extern uint32 chtr_pend, chtr_inht, chtr_inhi;
extern uint32 ch_flags[NUM_CHAN];
typedef struct { /* unpacked fp */
uint32 s; /* sign: 0 +, 1 - */
int32 ch; /* exponent */
t_uint64 fr; /* fraction (54b) */
} UFP;
uint32 op_frnd (void);
t_uint64 fp_fracdiv (t_uint64 dvd, t_uint64 dvr, t_uint64 *rem);
void fp_norm (UFP *op);
void fp_unpack (t_uint64 h, t_uint64 l, t_bool q_ac, UFP *op);
uint32 fp_pack (UFP *op, uint32 mqs, int32 mqch);
extern t_bool fp_trap (uint32 spill);
extern t_bool sel_trap (uint32 va);
extern t_stat ch_op_reset (uint32 ch, t_bool ch7909);
/* Integer add
Sherman: "As the result of an addition or subtraction, if the C(AC) is
zero, the sign of AC is unchanged." */
void op_add (t_uint64 op)
{
t_uint64 mac = AC & AC_MMASK; /* get magnitudes */
t_uint64 mop = op & MMASK;
AC = AC & AC_S; /* isolate AC sign */
if ((AC? 1: 0) ^ ((op & SIGN)? 1: 0)) { /* signs diff? sub */
if (mac >= mop) /* AC >= MQ */
AC = AC | (mac - mop);
else AC = (AC ^ AC_S) | (mop - mac); /* <, sign change */
}
else {
AC = AC | ((mac + mop) & AC_MMASK); /* signs same, add */
if ((AC ^ mac) & AC_P) /* P change? overflow */
ind_ovf = 1;
}
return;
}
/* Multiply */
void op_mpy (t_uint64 ac, t_uint64 sr, uint32 sc)
{
uint32 sign;
if (sc == 0) /* sc = 0? nop */
return;
sign = ((MQ & SIGN)? 1: 0) ^ ((sr & SIGN)? 1: 0); /* result sign */
ac = ac & AC_MMASK; /* clear AC sign */
sr = sr & MMASK; /* mpy magnitude */
MQ = MQ & MMASK; /* MQ magnitude */
if (sr && MQ) { /* mpy != 0? */
while (sc--) { /* for sc */
if (MQ & 1) /* MQ35? AC += mpy */
ac = (ac + sr) & AC_MMASK;
MQ = (MQ >> 1) | ((ac & 1) << 34); /* AC'MQ >> 1 */
ac = ac >> 1;
}
}
else ac = MQ = 0; /* result = 0 */
if (sign) { /* negative? */
ac = ac | AC_S; /* insert signs */
MQ = MQ | SIGN;
}
AC = ac; /* update AC */
return;
}
/* Divide */
t_bool op_div (t_uint64 sr, uint32 sc)
{
uint32 signa, signm;
if (sc == 0) /* sc = 0? nop */
return FALSE;
signa = (AC & AC_S)? 1: 0; /* get signs */
signm = (sr & SIGN)? 1: 0;
sr = sr & MMASK; /* get dvr magn */
if ((AC & AC_MMASK) >= sr) /* |AC| >= |sr|? */
return TRUE;
AC = AC & AC_MMASK; /* AC, MQ magn */
MQ = MQ & MMASK;
while (sc--) { /* for sc */
AC = ((AC << 1) & AC_MMASK) | (MQ >> 34); /* AC'MQ << 1 */
MQ = (MQ << 1) & MMASK;
if (AC >= sr) { /* AC >= dvr? */
AC = AC - sr; /* AC -= dvr */
MQ = MQ | 1; /* set quo bit */
}
}
if (signa ^ signm) /* quo neg? */
MQ = MQ | SIGN;
if (signa) /* rem neg? */
AC = AC | AC_S;
return FALSE; /* div ok */
}
/* Shifts */
void op_als (uint32 addr)
{
uint32 sc = addr & SCMASK;
if ((sc >= 35)? /* shift >= 35? */
((AC & MMASK) != 0): /* test all bits for ovf */
(((AC & MMASK) >> (35 - sc)) != 0)) /* test only 35-sc bits */
ind_ovf = 1;
if (sc >= 37) /* sc >= 37? result 0 */
AC = AC & AC_S;
else AC = (AC & AC_S) | ((AC << sc) & AC_MMASK); /* shift, save sign */
return;
}
void op_ars (uint32 addr)
{
uint32 sc = addr & SCMASK;
if (sc >= 37) /* sc >= 37? result 0 */
AC = AC & AC_S;
else AC = (AC & AC_S) | ((AC & AC_MMASK) >> sc); /* shift, save sign */
return;
}
void op_lls (uint32 addr)
{
uint32 sc; /* get sc */
AC = AC & AC_MMASK; /* clear AC sign */
for (sc = addr & SCMASK; sc != 0; sc--) { /* for SC */
AC = ((AC << 1) & AC_MMASK) | ((MQ >> 34) & 1); /* AC'MQ << 1 */
MQ = (MQ & SIGN) | ((MQ << 1) & MMASK); /* preserve MQ sign */
if (AC & AC_P) /* if P, overflow */
ind_ovf = 1;
}
if (MQ & SIGN) /* set ACS from MQS */
AC = AC | AC_S;
return;
}
void op_lrs (uint32 addr)
{
uint32 sc = addr & SCMASK;
t_uint64 mac;
MQ = MQ & MMASK; /* get MQ magnitude */
if (sc != 0) {
mac = AC & AC_MMASK; /* get AC magnitude, */
AC = AC & AC_S; /* sign */
if (sc < 35) { /* sc [1,34]? */
MQ = ((MQ >> sc) | (mac << (35 - sc))) & MMASK; /* MQ has AC'MQ */
AC = AC | (mac >> sc); /* AC has AC only */
}
else if (sc < 37) { /* sc [35:36]? */
MQ = (mac >> (sc - 35)) & MMASK; /* MQ has AC only */
AC = AC | (mac >> sc); /* AC has <QP> */
}
else if (sc < 72) /* sc [37:71]? */
MQ = (mac >> (sc - 35)) & MMASK; /* MQ has AC only */
else MQ = 0; /* >72? MQ = 0 */
}
if (AC & AC_S) /* set MQS from ACS */
MQ = MQ | SIGN;
return;
}
void op_lgl (uint32 addr)
{
uint32 sc; /* get sc */
for (sc = addr & SCMASK; sc != 0; sc--) { /* for SC */
AC = (AC & AC_S) | ((AC << 1) & AC_MMASK) | /* AC'MQ << 1 */
((MQ >> 35) & 1); /* preserve AC sign */
MQ = (MQ << 1) & DMASK;
if (AC & AC_P) /* if P, overflow */
ind_ovf = 1;
}
return;
}
void op_lgr (uint32 addr)
{
uint32 sc = addr & SCMASK;
t_uint64 mac;
if (sc != 0) {
mac = AC & AC_MMASK; /* get AC magnitude, */
AC = AC & AC_S; /* sign */
if (sc < 36) { /* sc [1,35]? */
MQ = ((MQ >> sc) | (mac << (36 - sc))) & DMASK; /* MQ has AC'MQ */
AC = AC | (mac >> sc); /* AC has AC only */
}
else if (sc == 36) { /* sc [36]? */
MQ = mac & DMASK; /* MQ = AC<P,1:35> */
AC = AC | (mac >> 36); /* AC = AC<Q> */
}
else if (sc < 73) /* sc [37, 72]? */
MQ = (mac >> (sc - 36)) & DMASK; /* MQ has AC only */
else MQ = 0; /* >72, AC,MQ = 0 */
}
return;
}
/* Plus sense - undefined operations are NOPs */
t_stat op_pse (uint32 addr)
{
uint32 ch, spill;
switch (addr) {
case 00000: /* CLM */
if (cpu_model & I_9X) /* 709X only */
AC = AC & AC_S;
break;
case 00001: /* LBT */
if ((AC & 1) != 0)
PC = (PC + 1) & AMASK;
break;
case 00002: /* CHS */
AC = AC ^ AC_S;
break;
case 00003: /* SSP */
AC = AC & ~AC_S;
break;
case 00004: /* ENK */
MQ = KEYS;
break;
case 00005: /* IOT */
if (ind_ioc)
ind_ioc = 0;
else PC = (PC + 1) & AMASK;
break;
case 00006: /* COM */
AC = AC ^ AC_MMASK;
break;
case 00007: /* ETM */
if (cpu_model & I_9X) /* 709X only */
mode_ttrap = 1;
break;
case 00010: /* RND */
if ((cpu_model & I_9X) && (MQ & B1)) /* 709X only, MQ1 set? */
op_add ((t_uint64) 1); /* incr AC */
break;
case 00011: /* FRN */
if (cpu_model & I_9X) { /* 709X only */
spill = op_frnd ();
if (spill)
fp_trap (spill);
}
break;
case 00012: /* DCT */
if (ind_dvc)
ind_dvc = 0;
else PC = (PC + 1) & AMASK;
break;
case 00014: /* RCT */
chtr_inhi = 1; /* 1 cycle delay */
chtr_inht = 0; /* clr inhibit trap */
chtr_pend = 0; /* no trap now */
break;
case 00016: /* LMTM */
if (cpu_model & I_94) /* 709X only */
mode_multi = 0;
break;
case 00140: /* SLF */
if (cpu_model & I_9X) /* 709X only */
SLT = 0;
break;
case 00141: case 00142: case 00143: case 00144: /* SLN */
if (cpu_model & I_9X) /* 709X only */
SLT = SLT | (1u << (00144 - addr));
break;
case 00161: case 00162: case 00163: /* SWT */
case 00164: case 00165: case 00166:
if ((SSW & (1u << (00166 - addr))) != 0)
PC = (PC + 1) & AMASK;
break;
case 01000: case 02000: case 03000: case 04000: /* BTT */
case 05000: case 06000: case 07000: case 10000:
if (cpu_model & I_9X) { /* 709X only */
if (sel_trap (PC)) /* sel trap? */
break;
ch = GET_U_CH (addr); /* get channel */
if (ch_flags[ch] & CHF_BOT) /* BOT? */
ch_flags[ch] &= ~CHF_BOT; /* clear */
else PC = (PC + 1) & AMASK; /* else skip */
}
break;
case 001350: case 002350: case 003350: case 004350: /* RICx */
case 005350: case 006350: case 007350: case 010350:
ch = GET_U_CH (addr); /* get channel */
return ch_op_reset (ch, 1);
case 001352: case 002352: case 003352: case 004352: /* RDCx */
case 005352: case 006352: case 007352: case 010352:
ch = GET_U_CH (addr); /* get channel */
return ch_op_reset (ch, 0);
} /* end case */
return SCPE_OK;
}
/* Minus sense */
t_stat op_mse (uint32 addr)
{
uint32 t, ch;
switch (addr) {
case 00000: /* CLM */
if (cpu_model & I_9X) /* 709X only */
AC = AC & AC_S;
break;
case 00001: /* PBT */
if ((AC & AC_P) != 0)
PC = (PC + 1) & AMASK;
break;
case 00002: /* EFTM */
if (cpu_model & I_9X) { /* 709X only */
mode_ftrap = 1;
ind_mqo = 0; /* clears MQ ovf */
}
break;
case 00003: /* SSM */
if (cpu_model & I_9X) /* 709X only */
AC = AC | AC_S;
break;
case 00004: /* LFTM */
if (cpu_model & I_9X) /* 709X only */
mode_ftrap = 0;
break;
case 00005: /* ESTM */
if (cpu_model & I_9X) /* 709X only */
mode_strap = 1;
break;
case 00006: /* ECTM */
if (cpu_model & I_9X) /* 709X only */
mode_ctrap = 1;
break;
case 00007: /* LTM */
if (cpu_model & I_9X) /* 709X only */
mode_ttrap = 0;
break;
case 00010: /* LSNM */
if (cpu_model & I_9X) /* 709X only */
mode_storn = 0;
break;
case 00012: /* RTT (704) */
if (cpu_model & I_9X) /* 709X only */
sel_trap (PC);
break;
case 00016: /* EMTM */
mode_multi = 1;
break;
case 00140: /* SLF */
if (cpu_model & I_9X) /* 709X only */
SLT = 0;
break;
case 00141: case 00142: case 00143: case 00144: /* SLT */
if (cpu_model & I_9X) { /* 709X only */
t = SLT & (1u << (00144 - addr));
SLT = SLT & ~t;
if (t != 0)
PC = (PC + 1) & AMASK;
}
break;
case 00161: case 00162: case 00163: /* SWT */
case 00164: case 00165: case 00166:
if ((cpu_model & I_9X) && /* 709X only */
((SSW & (1u << (00166 - addr))) != 0))
PC = (PC + 1) & AMASK;
break;
case 001000: case 002000: case 003000: case 004000: /* ETT */
case 005000: case 006000: case 007000: case 010000:
if (sel_trap (PC)) /* sel trap? */
break;
ch = GET_U_CH (addr); /* get channel */
if (ch_flags[ch] & CHF_EOT) /* EOT? */
ch_flags[ch] = ch_flags[ch] & ~CHF_EOT; /* clear */
else PC = (PC + 1) & AMASK; /* else skip */
break;
}
return SCPE_OK;
}
/* Floating add
Notes:
- AC<Q,P> enter into the initial exponent comparison. If either is set,
the numbers are always swapped. AC<P> gets OR'd into AC<S> during the
swap, and AC<Q,P> are cleared afterwards
- The early end test is actually > 077 if AC <= SR and > 100 if
AC > SR. However, any shift >= 54 will produce a zero fraction,
so the difference can be ignored */
uint32 op_fad (t_uint64 sr, t_bool norm)
{
UFP op1, op2, t;
int32 mqch, diff;
MQ = 0; /* clear MQ */
fp_unpack (AC, 0, 1, &op1); /* unpack AC */
fp_unpack (sr, 0, 0, &op2); /* unpack sr */
if (op1.ch > op2.ch) { /* AC exp > SR exp? */
if (AC & AC_P) /* AC P or's with S */
op1.s = 1;
t = op1; /* swap operands */
op1 = op2;
op2 = t;
op2.ch = op2.ch & FP_M_CH; /* clear P,Q */
}
diff = op2.ch - op1.ch; /* exp diff */
if (diff) { /* any shift? */
if ((diff < 0) || (diff > 077)) /* diff > 63? */
op1.fr = 0;
else op1.fr = op1.fr >> diff; /* no, denormalize */
}
if (op1.s ^ op2.s) { /* subtract? */
if (op1.fr >= op2.fr) { /* op1 > op2? */
op2.fr = op1.fr - op2.fr; /* op1 - op2 */
op2.s = op1.s; /* op2 sign is result */
}
else op2.fr = op2.fr - op1.fr; /* else op2 - op1 */
}
else {
op2.fr = op2.fr + op1.fr; /* op2 + op1 */
if (op2.fr & FP_FCRY) { /* carry? */
op2.fr = op2.fr >> 1; /* renormalize */
op2.ch++; /* incr exp */
}
}
if (norm) { /* normalize? */
if (op2.fr) { /* non-zero frac? */
fp_norm (&op2);
mqch = op2.ch - FP_N_FR;
}
else op2.ch = mqch = 0; /* else true zero */
}
else mqch = op2.ch - FP_N_FR;
return fp_pack (&op2, op2.s, mqch); /* pack AC, MQ */
}
/* Floating multiply */
uint32 op_fmp (t_uint64 sr, t_bool norm)
{
UFP op1, op2;
int32 mqch;
uint32 f1h, f2h;
fp_unpack (MQ, 0, 0, &op1); /* unpack MQ */
fp_unpack (sr, 0, 0, &op2); /* unpack sr */
op1.s = op1.s ^ op2.s; /* result sign */
if ((op2.ch == 0) && (op2.fr == 0)) { /* sr a normal 0? */
AC = op1.s? AC_S: 0; /* result is 0 */
MQ = op1.s? SIGN: 0;
return 0;
}
f1h = FP_HIFRAC (op1.fr); /* get hi fracs */
f2h = FP_HIFRAC (op2.fr);
op1.fr = ((t_uint64) f1h) * ((t_uint64) f2h); /* f1h * f2h */
op1.ch = (op1.ch & FP_M_CH) + op2.ch - FP_BIAS; /* result exponent */
if (norm) { /* normalize? */
if (!(op1.fr & FP_FNORM)) { /* not normalized? */
op1.fr = op1.fr << 1; /* shift frac left 1 */
op1.ch--; /* decr exp */
}
if (FP_HIFRAC (op1.fr)) /* hi result non-zero? */
mqch = op1.ch - FP_N_FR; /* set MQ exp */
else op1.ch = mqch = 0; /* clear AC, MQ exp */
}
else mqch = op1.ch - FP_N_FR; /* set MQ exp */
return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */
}
/* Floating divide */
uint32 op_fdv (t_uint64 sr)
{
UFP op1, op2;
int32 mqch;
uint32 spill, quos;
t_uint64 rem;
fp_unpack (AC, 0, 1, &op1); /* unpack AC */
fp_unpack (sr, 0, 0, &op2); /* unpack sr */
quos = op1.s ^ op2.s; /* quotient sign */
if (op1.fr >= (2 * op2.fr)) { /* |AC| >= 2*|sr|? */
MQ = quos? SIGN: 0; /* MQ = sign only */
return TRAP_F_DVC; /* divide check */
}
if (op1.fr == 0) { /* |AC| == 0? */
MQ = quos? SIGN: 0; /* MQ = sign only */
AC = 0; /* AC = +0 */
return 0; /* done */
}
op1.ch = op1.ch & FP_M_CH; /* remove AC<Q,P> */
if (op1.fr >= op2.fr) { /* |AC| >= |sr|? */
op1.fr = op1.fr >> 1; /* denorm AC */
op1.ch++;
}
op1.fr = fp_fracdiv (op1.fr, op2.fr, &rem); /* fraction divide */
op1.fr = op1.fr | (rem << FP_N_FR); /* rem'quo */
mqch = op1.ch - op2.ch + FP_BIAS; /* quotient exp */
op1.ch = op1.ch - FP_N_FR; /* remainder exp */
spill = fp_pack (&op1, quos, mqch); /* pack up */
return (spill? (spill | TRAP_F_SGL): 0); /* if spill, set SGL */
}
/* Double floating add
Notes:
- AC<Q,P> enter into the initial exponent comparison. If either is set,
the numbers are always swapped. AC<P> gets OR'd into AC<S> during the
swap, and AC<Q,P> are cleared afterwards
- For most cases, SI ends up with the high order part of the larger number
- The 'early end' cases (smaller number is shifted away) must be tracked
exactly for SI impacts. The early end cases are:
(a) AC > SR, diff > 0100, and AC normalized
(b) AC <= SR, diff > 077, and SR normalized
In case (a), SI is unchanged. In case (b), SI ends up with the SR sign
and characteristic but the MQ (!) fraction */
uint32 op_dfad (t_uint64 sr, t_uint64 sr1, t_bool norm)
{
UFP op1, op2, t;
int32 mqch, diff;
fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */
fp_unpack (sr, sr1, 0, &op2); /* unpack sr'sr1 */
if (op1.ch > op2.ch) { /* AC exp > SR exp? */
if (((op1.ch - op2.ch) > 0100) && (AC & B9)) ; /* early out */
else SI = FP_PACK36 (op1.s, op1.ch, FP_HIFRAC (op1.fr));
if (AC & AC_P) /* AC P or's with S */
op1.s = 1;
t = op1; /* swap operands */
op1 = op2;
op2 = t;
op2.ch = op2.ch & FP_M_CH; /* clear P,Q */
}
else { /* AC <= SR */
if (((op2.ch - op1.ch) > 077) && (sr & B9)) /* early out */
SI = FP_PACK36 (op2.s, op2.ch, FP_LOFRAC (MQ));
else SI = FP_PACK36 (op2.s, op2.ch, FP_HIFRAC (op2.fr));
}
diff = op2.ch - op1.ch; /* exp diff */
if (diff) { /* any shift? */
if ((diff < 0) || (diff > 077)) /* diff > 63? */
op1.fr = 0;
else op1.fr = op1.fr >> diff; /* no, denormalize */
}
if (op1.s ^ op2.s) { /* subtract? */
if (op1.fr >= op2.fr) { /* op1 > op2? */
op2.fr = op1.fr - op2.fr; /* op1 - op2 */
op2.s = op1.s; /* op2 sign is result */
}
else op2.fr = op2.fr - op1.fr; /* op2 - op1 */
}
else {
op2.fr = op2.fr + op1.fr; /* op2 + op1 */
if (op2.fr & FP_FCRY) { /* carry? */
op2.fr = op2.fr >> 1; /* renormalize */
op2.ch++; /* incr exp */
}
}
if (norm) { /* normalize? */
if (op2.fr) { /* non-zero frac? */
fp_norm (&op2);
mqch = op2.ch - FP_N_FR;
}
else op2.ch = mqch = 0; /* else true zero */
}
else mqch = op2.ch - FP_N_FR;
return fp_pack (&op2, op2.s, mqch); /* pack AC, MQ */
}
/* Double floating multiply
Notes (notation is A+B' * C+D', where ' denotes 2^-27):
- The instruction returns 0 if A and C are both zero, because B*D is never
done as part of the algorithm
- For most cases, SI ends up with B*C, with a zero sign and exponent
- For the A+B' both zero 'early end' case SI ends up with A or C,
depending on whether the operation is normalized or not */
uint32 op_dfmp (t_uint64 sr, t_uint64 sr1, t_bool norm)
{
UFP op1, op2;
int32 mqch;
uint32 f1h, f2h, f1l, f2l;
t_uint64 tx;
fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */
fp_unpack (sr, sr1, 0, &op2); /* unpack sr'sr1 */
op1.s = op1.s ^ op2.s; /* result sign */
f1h = FP_HIFRAC (op1.fr); /* A */
f1l = FP_LOFRAC (op1.fr); /* B */
f2h = FP_HIFRAC (op2.fr); /* C */
f2l = FP_LOFRAC (op2.fr); /* D */
if (((op1.ch == 0) && (op1.fr == 0)) || /* AC'MQ normal 0? */
((op2.ch == 0) && (op2.fr == 0)) || /* sr'sr1 normal 0? */
((f1h == 0) && (f2h == 0))) { /* both hi frac zero? */
AC = op1.s? AC_S: 0; /* result is 0 */
MQ = op1.s? SIGN: 0;
SI = sr; /* SI has C */
return 0;
}
op1.ch = (op1.ch & FP_M_CH) + op2.ch - FP_BIAS; /* result exponent */
if (op1.fr) { /* A'B != 0? */
op1.fr = ((t_uint64) f1h) * ((t_uint64) f2h); /* A * C */
tx = ((t_uint64) f1h) * ((t_uint64) f2l); /* A * D */
op1.fr = op1.fr + (tx >> FP_N_FR); /* add in hi 27b */
tx = ((t_uint64) f1l) * ((t_uint64) f2h); /* B * C */
op1.fr = op1.fr + (tx >> FP_N_FR); /* add in hi 27b */
SI = tx >> FP_N_FR; /* SI keeps B * C */
}
else {
if (norm) /* early out */
SI = sr;
else SI = FP_PACK36 (op2.s, op2.ch, 0);
}
if (norm) { /* normalize? */
if (!(op1.fr & FP_FNORM)) { /* not normalized? */
op1.fr = op1.fr << 1; /* shift frac left 1 */
op1.ch--; /* decr exp */
}
if (FP_HIFRAC (op1.fr)) { /* non-zero? */
mqch = op1.ch - FP_N_FR; /* set MQ exp */
}
else op1.ch = mqch = 0; /* clear AC, MQ exp */
}
else mqch = op1.ch - FP_N_FR; /* set MQ exp */
return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */
}
/* Double floating divide
Notes:
- This is a Taylor series expansion (where ' denotes >> 27):
(A+B') * (C+D')^-1 = (A+B') * C^-1 - (A+B') * D'* C^-2 +...
to two terms, which can be rewritten as terms Q1, Q2:
Q1 = (A+B')/C
Q2' = (R - Q1*D)'/C
- Tracking the sign of Q2' is complicated:
Q1 has the sign of the quotient, s_AC ^ s_SR
D has the sign of the divisor, s_SR
R has the sign of the dividend, s_AC
Q1*D sign is s_AC ^ s_SR ^ s^SR = s^AC
Therefore, R and Q1*D have the same sign, s_AC
Q2' sign is s^AC ^ s_SR, which is the sign of the quotient
- For first divide check, SI is 0
- For other cases, including second divide check, SI ends up with Q1
- R-Q1*D is only calculated to the high 27b; using the full 54b
throws off the result
- The second divide must check for divd >= divr, otherwise an extra
bit of quotient would be devloped, throwing off the result
- A late ECO added full post-normalization; single precision divide
does no normalization */
uint32 op_dfdv (t_uint64 sr, t_uint64 sr1)
{
UFP op1, op2;
int32 mqch;
uint32 csign, ac_s;
t_uint64 f1h, f2h, tr, tq1, tq1d, trmq1d, tq2;
fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */
fp_unpack (sr, 0, 0, &op2); /* unpack sr only */
ac_s = op1.s; /* save AC sign */
op1.s = op1.s ^ op2.s; /* sign of result */
f1h = FP_HIFRAC (op1.fr);
f2h = FP_HIFRAC (op2.fr);
if (f1h >= (2 * f2h)) { /* |A| >= 2*|C|? */
SI = 0; /* clear SI */
return TRAP_F_DVC; /* divide check */
}
if (f1h == 0) { /* |AC| == 0? */
SI = MQ = op1.s? SIGN: 0; /* MQ, SI = sign only */
AC = op1.s? AC_S: 0; /* AC = sign only */
return 0; /* done */
}
op1.ch = op1.ch & FP_M_CH; /* remove AC<Q,P> */
if (f1h >= f2h) { /* |A| >= |C|? */
op1.fr = op1.fr >> 1; /* denorm AC */
op1.ch++;
}
op1.ch = op1.ch - op2.ch + FP_BIAS; /* exp of quotient */
tq1 = fp_fracdiv (op1.fr, op2.fr, &tr); /* |A+B| / |C| */
tr = tr << FP_N_FR; /* R << 27 */
tq1d = (tq1 * ((t_uint64) FP_LOFRAC (sr1))) & /* Q1 * D */
~((t_uint64) FP_FMASK); /* top 27 bits */
csign = (tr < tq1d); /* correction sign */
if (csign) /* |R|<|Q1*D|? compl */
trmq1d = tq1d - tr;
else trmq1d = tr - tq1d; /* no, subtr ok */
SI = FP_PACK36 (op1.s, op1.ch, tq1); /* SI has Q1 */
if (trmq1d >= (2 * op2.fr)) { /* |R-Q1*D| >= 2*|C|? */
AC = FP_PACK38 (csign ^ ac_s, 0, FP_HIFRAC (trmq1d)); /* AC has R-Q1*D */
MQ = (csign ^ ac_s)? SIGN: 0; /* MQ = sign only */
return TRAP_F_DVC; /* divide check */
}
tq2 = fp_fracdiv (trmq1d, op2.fr, NULL); /* |R-Q1*D| / |C| */
if (trmq1d >= op2.fr) /* can only gen 27b quo */
tq2 &= ~((t_uint64) 1);
op1.fr = tq1 << FP_N_FR; /* shift Q1 into place */
if (csign) /* sub or add Q2 */
op1.fr = op1.fr - tq2;
else op1.fr = op1.fr + tq2;
fp_norm (&op1); /* normalize */
if (op1.fr) /* non-zero? */
mqch = op1.ch - FP_N_FR;
else op1.ch = mqch = 0; /* clear AC, MQ exp */
return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */
}
/* Floating round */
uint32 op_frnd (void)
{
UFP op;
uint32 spill;
spill = 0; /* no error */
if (MQ & B9) { /* MQ9 set? */
fp_unpack (AC, 0, 1, &op); /* unpack AC */
op.fr = op.fr + ((t_uint64) (1 << FP_N_FR)); /* round up */
if (op.fr & FP_FCRY) { /* carry out? */
op.fr = op.fr >> 1; /* renormalize */
op.ch++; /* incr exp */
if (op.ch == (FP_M_CH + 1)) /* ovf with QP = 0? */
spill = TRAP_F_OVF | TRAP_F_AC;
}
AC = FP_PACK38 (op.s, op.ch, FP_HIFRAC (op.fr)); /* pack AC */
}
return spill;
}
/* Fraction divide - 54/27'0 yielding quotient and remainder */
t_uint64 fp_fracdiv (t_uint64 dvd, t_uint64 dvr, t_uint64 *rem)
{
dvr = dvr >> FP_N_FR;
if (rem)
*rem = dvd % dvr;
return (dvd / dvr);
}
/* Floating point normalize */
void fp_norm (UFP *op)
{
op->fr = op->fr & FP_DFMASK; /* mask fraction */
if (op->fr == 0) /* zero? */
return;
while ((op->fr & FP_FNORM) == 0) { /* until norm */
op->fr = op->fr << 1; /* lsh 1 */
op->ch--; /* decr exp */
}
return;
}
/* Floating point unpack */
void fp_unpack (t_uint64 h, t_uint64 l, t_bool q_ac, UFP *op)
{
if (q_ac) { /* AC? */
op->s = (h & AC_S)? 1: 0; /* get sign */
op->ch = (uint32) ((h >> FP_V_CH) & FP_M_ACCH); /* get exp */
}
else {
op->s = (h & SIGN)? 1: 0; /* no, mem */
op->ch = (uint32) ((h >> FP_V_CH) & FP_M_CH);
}
op->fr = (((t_uint64) FP_LOFRAC (h)) << FP_N_FR) | /* get frac hi */
((t_uint64) FP_LOFRAC (l)); /* get frac lo */
return;
}
/* Floating point pack */
uint32 fp_pack (UFP *op, uint32 mqs, int32 mqch)
{
uint32 spill;
AC = FP_PACK38 (op->s, op->ch, FP_HIFRAC (op->fr)); /* pack AC */
MQ = FP_PACK36 (mqs, mqch, FP_LOFRAC (op->fr)); /* pack MQ */
if (op->ch > FP_M_CH) /* check AC exp */
spill = TRAP_F_OVF | TRAP_F_AC;
else if (op->ch < 0)
spill = TRAP_F_AC;
else spill = 0;
if (mqch > FP_M_CH) /* check MQ exp */
spill |= (TRAP_F_OVF | TRAP_F_MQ);
else if (mqch < 0)
spill |= TRAP_F_MQ;
return spill;
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* i7094_defs.h: IBM 7094 simulator definitions
Copyright (c) 2003-2010, Robert M Supnik
Copyright (c) 2003-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -28,6 +28,7 @@
helped to reconstruct the CTSS hardware RPQ's. Dave Pitts gets special
thanks for patiently coaching me through IBSYS debug.
25-Mar-11 RMS Updated SDC mask based on 7230 documentation
22-May-10 RMS Added check for 64b addresses
*/
@ -419,7 +420,7 @@ typedef struct {
#define CHF_M_LCC 077
#define CHF_CLR_7909 07775000177 /* 7909 clear flags */
#define CHF_SDC_7909 07776000000 /* 7909 SDC flags */
#define CHF_SDC_7909 07777600000 /* 7909 SDC flags */
/* Channel characteristics (in dev.flags) */

View file

@ -1,6 +1,6 @@
/* i7094_drm.c: 7289/7320A drum simulator
Copyright (c) 2005-2008, Robert M Supnik
Copyright (c) 2005-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,31 +25,29 @@
drm 7289/7320A "fast" drum
Very little is known about this device; the behavior simulated here is
what is used by CTSS.
25-Mar-11 RMS Updated based on RPQ
This simulator implements a subset of the functionality of the 7289, as
required by CTSS.
- The drum channel/controller behaves like a hybrid of the 7607 and the 7909.
It responds to SCD (like the 7909), gets its address from the channel
program (like the 7909), but responds to IOCD/IOCP (like the 7607) and
sets channel flags (like the 7607).
- The drum channel supports at least 2 drums. The maximum is 8 or less.
- The drum channel supports at least 2 drums. The maximum is 4 or less.
Physical drums are numbered from 0.
- Each drum has a capacity of 192K 36b words. This is divided into 6
"logical" drum of 32KW each. Each "logical" drum has 16 2048W "sectors".
Logical drums are numbered from 1.
- The drum's behavior if a sector boundary is crossed in mid-transfer is
unknown. CTSS never does this.
- The drum's behavior with record operations is unknown. CTSS only uses
IOCD and IOCP.
- The drum's error indicators are unknown. CTSS regards bits <0:2,13> of
the returned SCD data as errors, as well as the normal 7607 trap flags.
- The drum's rotational speed is unknown.
- The drum allows transfers across sector boundaries, but not logical
drum boundaries.
- The drum's only supports IOCD, IOCP, and IOCT. IOCT (and chaining mode)
are not used by CTSS.
Assumptions in this simulator:
Limitations in this simulator:
- Transfers may not cross a sector boundary. An attempt to do so sets
the EOF flag and causes an immediate disconnect.
- The hardware never sets end of record.
- Chain mode is not implemented.
- Write protect switches are not implemented.
For speed, the entire drum is buffered in memory.
*/
@ -65,6 +63,7 @@
#define DRM_SCMASK (DRM_NUMWDS - 1) /* sector mask */
#define DRM_NUMSC 16 /* sectors/log drum */
#define DRM_NUMWDL (DRM_NUMWDS * DRM_NUMSC) /* words/log drum */
#define DRM_LDMASK (DRM_NUMWDL - 1) /* logical disk mask */
#define DRM_NUMLD 6 /* log drums/phys drum */
#define DRM_SIZE (DRM_NUMLD * DRM_NUMWDL) /* words/phys drum */
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
@ -73,7 +72,7 @@
/* Drum address from channel */
#define DRM_V_PHY 30 /* physical drum sel */
#define DRM_M_PHY 07
#define DRM_M_PHY 03
#define DRM_V_LOG 18 /* logical drum sel */
#define DRM_M_LOG 07
#define DRM_V_WDA 0 /* word address */
@ -83,15 +82,30 @@
#define DRM_GETWDA(x) ((((uint32) (x)) >> DRM_V_WDA) & DRM_M_WDA)
#define DRM_GETDA(x) (((DRM_GETLOG(x) - 1) * DRM_NUMWDL) + DRM_GETWDA(x))
/* SCD word */
#define DRMS_V_IOC 35 /* IO check */
#define DRMS_V_INV 33 /* invalid command */
#define DRMS_V_PHY 31 /* physical drum */
#define DRMS_V_LOG 28 /* logical drum */
#define DRMS_V_HWDA 24 /* high word addr */
#define DRMS_M_HWDA 017
#define DRMS_V_GRP 23 /* group */
#define DRMS_V_WRP 22 /* write protect */
#define DRMS_V_LPCR 18 /* LPRCR */
#define DRMS_M_LPCR 017
/* Drum controller states */
#define DRM_IDLE 0
#define DRM_1ST 1
#define DRM_DATA 2
#define DRM_EOS 3
#define DRM_FILL 2
#define DRM_DATA 3
#define DRM_EOD 4
uint32 drm_ch = CH_G; /* drum channel */
uint32 drm_da = 0; /* drum address */
uint32 drm_phy = 0; /* physical drum */
uint32 drm_sta = 0; /* state */
uint32 drm_op = 0; /* operation */
t_uint64 drm_chob = 0; /* output buf */
@ -131,13 +145,14 @@ UNIT drm_unit[] = {
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },
};
REG drm_reg[] = {
{ ORDATA (STATE, drm_sta, 2) },
{ ORDATA (STATE, drm_sta, 3) },
{ ORDATA (DA, drm_da, 18) },
{ FLDATA (OP, drm_op, 0) },
{ ORDATA (UNIT,drm_phy, 3) },
{ ORDATA (CHOB, drm_chob, 36) },
{ FLDATA (CHOBV, drm_chob_v, 0) },
{ DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },
@ -188,14 +203,14 @@ return SCPE_OK;
t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags)
{
uint32 u, l;
uint32 l;
int32 cp, dp;
if (drm_sta == DRM_1ST) {
u = DRM_GETPHY (val); /* get unit */
drm_phy = DRM_GETPHY (val); /* get unit */
l = DRM_GETLOG (val); /* get logical address */
if ((u >= DRM_NUMDR) || /* invalid unit? */
(drm_unit[u].flags & UNIT_DIS) || /* disabled unit? */
if ((drm_phy >= DRM_NUMDR) || /* invalid unit? */
(drm_unit[drm_phy].flags & UNIT_DIS) || /* disabled unit? */
(l == 0) || (l > DRM_NUMLD)) { /* invalid log drum? */
ch6_err_disc (ch, U_DRM, CHF_TRC); /* disconnect */
drm_sta = DRM_IDLE;
@ -206,10 +221,12 @@ if (drm_sta == DRM_1ST) {
dp = (drm_da & DRM_SCMASK) - cp; /* delta to desired pos */
if (dp <= 0) /* if neg, add rev */
dp = dp + DRM_NUMWDS;
sim_activate (&drm_unit[u], dp * drm_time); /* schedule */
if (drm_op) /* if write, get word */
sim_activate (&drm_unit[drm_phy], dp * drm_time); /* schedule */
if (drm_op) { /* if write, get word */
ch6_req_wr (ch, U_DRM);
drm_sta = DRM_DATA;
drm_sta = DRM_FILL; /* sector fill */
}
else drm_sta = DRM_DATA; /* data transfer */
drm_chob = 0; /* clr, inval buffer */
drm_chob_v = 0;
}
@ -224,6 +241,7 @@ return SCPE_OK;
t_stat drm_svc (UNIT *uptr)
{
uint32 i;
t_uint64 *fbuf = (t_uint64 *) uptr->filebuf;
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? */
@ -239,6 +257,13 @@ if (drm_da >= DRM_SIZE) { /* nx logical drum? */
switch (drm_sta) { /* case on state */
case DRM_FILL: /* write, clr sector */
for (i = drm_da & ~DRM_SCMASK; i <= (drm_da | DRM_SCMASK); i++)
fbuf[i] = 0; /* clear sector */
if (i >= uptr-> hwmark)
uptr->hwmark = i + 1;
drm_sta = DRM_DATA; /* now data */
/* fall through */
case DRM_DATA: /* data */
if (drm_op) { /* write? */
if (drm_chob_v) /* valid? clear */
@ -258,7 +283,7 @@ switch (drm_sta) { /* case on state */
sim_activate (uptr, drm_time); /* next word */
break;
case DRM_EOS: /* end sector */
case DRM_EOD: /* end logical disk */
if (ch6_qconn (drm_ch, U_DRM)) /* drum still conn? */
ch6_err_disc (drm_ch, U_DRM, CHF_EOF); /* set EOF, disc */
drm_sta = DRM_IDLE; /* drum is idle */
@ -272,10 +297,10 @@ return SCPE_OK;
t_bool drm_da_incr (void)
{
drm_da = drm_da + 1;
if (drm_da & DRM_SCMASK)
drm_da = (drm_da & ~DRM_LDMASK) | ((drm_da + 1) & DRM_LDMASK);
if ((drm_da & DRM_LDMASK) != 0)
return FALSE;
drm_sta = DRM_EOS;
drm_sta = DRM_EOD;
return TRUE;
}
@ -285,6 +310,7 @@ t_stat drm_reset (DEVICE *dptr)
{
uint32 i;
drm_phy = 0;
drm_da = 0;
drm_op = 0;
drm_sta = DRM_IDLE;

View file

@ -1,861 +0,0 @@
/* i7094_mt.c: IBM 7094 magnetic tape simulator
Copyright (c) 2003-2008, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
mt magtape simulator
*/
#include "i7094_defs.h"
#include "sim_tape.h"
#define UST u3 /* unit state */
#define UCH u4 /* channel number */
#define MTUF_V_LDN (MTUF_V_UF + 0)
#define MTUF_LDN (1 << MTUF_V_LDN)
#define MT_MAXFR ((1 << 18) + 2)
#define QCHRONO(c,u) ((cpu_model & I_CT) && \
((c) == CHRONO_CH) && ((u) == CHRONO_UNIT))
uint8 *mtxb[NUM_CHAN] = { NULL }; /* xfer buffer */
uint32 mt_unit[NUM_CHAN]; /* unit */
uint32 mt_bptr[NUM_CHAN];
uint32 mt_blnt[NUM_CHAN];
t_uint64 mt_chob[NUM_CHAN];
uint32 mt_chob_v[NUM_CHAN];
uint32 mt_tshort = 2;
uint32 mt_twef = 25000; /* 50 msec */
uint32 mt_tstart = 29000; /* 58 msec */
uint32 mt_tstop = 10000; /* 20 msec */
uint32 mt_tword = 50; /* 125 usec */
static const uint8 odd_par[64] = {
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1
};
static const char *tape_stat[] = {
"OK", "TMK", "UNATT", "IOERR", "INVRECLNT",
"FMT", "BOT", "EOM", "RECERR", "WRPROT"
};
extern uint32 PC;
extern uint32 cpu_model;
extern uint32 ind_ioc;
extern FILE *sim_deb;
extern char *sel_name[];
t_stat mt_chsel (uint32 ch, uint32 sel, uint32 unit);
t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 flags);
t_stat mt_rec_end (UNIT *uptr);
t_stat mt_svc (UNIT *uptr);
t_stat mt_reset (DEVICE *dptr);
t_stat mt_attach (UNIT *uptr, char *cptr);
t_stat mt_boot (int32 unitno, DEVICE *dptr);
t_stat mt_map_err (UNIT *uptr, t_stat st);
extern uint32 chrono_rd (uint8 *buf, uint32 bufsiz);
/* MT data structures
mt_dev MT device descriptor
mt_unit MT unit list
mt_reg MT register list
mt_mod MT modifier list
*/
DIB mt_dib = { &mt_chsel, &mt_chwr };
MTAB mt_mod[] = {
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
{ MTUF_LDN, 0, "high density", "HIGH", NULL },
{ MTUF_LDN, MTUF_LDN, "low density", "LOW", NULL },
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ 0 }
};
UNIT mta_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mta_reg[] = {
{ ORDATA (UNIT, mt_unit[0], 5) },
{ ORDATA (CHOB, mt_chob[0], 36) },
{ FLDATA (CHOBV, mt_chob_v[0], 0) },
{ DRDATA (BPTR, mt_bptr[0], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[0], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mta_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mta_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mtb_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mtb_reg[] = {
{ ORDATA (UNIT, mt_unit[1], 5) },
{ ORDATA (CHOB, mt_chob[1], 36) },
{ FLDATA (CHOBV, mt_chob_v[1], 0) },
{ DRDATA (BPTR, mt_bptr[1], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[1], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mtb_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mtb_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mtc_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mtc_reg[] = {
{ ORDATA (UNIT, mt_unit[2], 5) },
{ ORDATA (CHOB, mt_chob[2], 36) },
{ FLDATA (CHOBV, mt_chob_v[2], 0) },
{ DRDATA (BPTR, mt_bptr[2], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[2], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mtc_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mtc_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mtd_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mtd_reg[] = {
{ ORDATA (UNIT, mt_unit[3], 5) },
{ ORDATA (CHOB, mt_chob[3], 36) },
{ FLDATA (CHOBV, mt_chob_v[3], 0) },
{ DRDATA (BPTR, mt_bptr[3], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[3], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mtd_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mtd_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mte_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mte_reg[] = {
{ ORDATA (UNIT, mt_unit[4], 5) },
{ ORDATA (CHOB, mt_chob[4], 36) },
{ FLDATA (CHOBV, mt_chob_v[4], 0) },
{ DRDATA (BPTR, mt_bptr[4], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[4], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mte_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mte_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mtf_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mtf_reg[] = {
{ ORDATA (UNIT, mt_unit[5], 5) },
{ ORDATA (CHOB, mt_chob[5], 36) },
{ FLDATA (CHOBV, mt_chob_v[5], 0) },
{ DRDATA (BPTR, mt_bptr[5], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[5], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mtf_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mtf_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mtg_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mtg_reg[] = {
{ ORDATA (UNIT, mt_unit[6], 5) },
{ ORDATA (CHOB, mt_chob[6], 36) },
{ FLDATA (CHOBV, mt_chob_v[6], 0) },
{ DRDATA (BPTR, mt_bptr[6], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[6], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mtg_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mtg_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mth_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mth_reg[] = {
{ ORDATA (UNIT, mt_unit[7], 5) },
{ ORDATA (CHOB, mt_chob[7], 36) },
{ FLDATA (CHOBV, mt_chob_v[7], 0) },
{ DRDATA (BPTR, mt_bptr[7], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[7], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mth_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mth_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
DEVICE mt_dev[NUM_CHAN] = {
{
"MTA", mta_unit, mta_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
&mt_boot, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DEBUG
},
{
"MTB", mtb_unit, mtb_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTC", mtc_unit, mtc_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTD", mtd_unit, mtd_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTE", mte_unit, mte_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTF", mtf_unit, mtf_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTG", mtg_unit, mtg_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTH", mth_unit, mth_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
}
};
/* Select controller
Inputs:
ch = channel
cmd = select command
unit = unit
Outputs:
status = SCPE_OK if ok
STOP_STALL if busy
error code if error
*/
static const int mt_must_att[CHSL_NUM] = {
0, 1, 1, 0, 1, 1, 0, 0,
1, 1, 1, 1, 1, 1, 0, 0
};
static const int mt_will_wrt[CHSL_NUM] = {
0, 0, 1, 0, 0, 1, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0
};
t_stat mt_chsel (uint32 ch, uint32 cmd, uint32 unit)
{
UNIT *uptr;
uint32 u = unit & 017;
if ((ch >= NUM_CHAN) || (cmd == 0) || (cmd >= CHSL_NUM))
return SCPE_IERR; /* invalid arg? */
if (mt_dev[ch].flags & DEV_DIS) /* disabled? */
return STOP_NXDEV;
if ((u == 0) || (u > MT_NUMDR)) /* valid unit? */
return STOP_NXDEV;
uptr = mt_dev[ch].units + u; /* get unit ptr */
if (uptr->flags & UNIT_DIS) /* disabled? */
return STOP_NXDEV;
if (mt_unit[ch] || sim_is_active (uptr)) /* ctrl or unit busy? */
return ERR_STALL; /* stall */
if (QCHRONO (ch, u)) { /* Chronolog clock? */
if (cmd != CHSL_RDS) /* only reads */
return STOP_ILLIOP;
sim_activate (uptr, mt_tword); /* responds quickly */
}
else { /* real tape */
if (!(uptr->flags & UNIT_ATT) && mt_must_att[cmd]) /* unit unatt? */
return SCPE_UNATT;
if (sim_tape_wrp (uptr) && mt_will_wrt[cmd]) /* unit wrp && write? */
return STOP_WRP;
if (DEBUG_PRS (mt_dev[ch]))
fprintf (sim_deb, ">>%s%d %s, pos = %d\n",
mt_dev[ch].name, u, sel_name[cmd], uptr->pos);
switch (cmd) { /* case on cmd */
case CHSL_RDS:
case CHSL_WRS:
case CHSL_BSR:
case CHSL_BSF: /* rd, wr, backspace */
sim_activate (uptr, mt_tstart); /* schedule op */
break;
case CHSL_WEF: /* write eof? */
sim_activate (uptr, mt_twef); /* schedule op */
break;
case CHSL_RUN:
sim_activate (uptr, mt_tshort); /* schedule quick event */
break;
case CHSL_REW:
case CHSL_SDN: /* rew, rew/unl, set det */
sim_activate (uptr, mt_tshort); /* schedule quick event */
break;
default:
return SCPE_IERR;
} /* end switch */
} /* end else */
uptr->UST = cmd; /* set cmd */
mt_unit[ch] = unit & 0777; /* save unit */
return SCPE_OK;
}
/* Channel write routine */
t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 eorfl)
{
int32 k, u;
uint8 by, *xb;
UNIT *uptr;
if (ch >= NUM_CHAN) /* invalid chan? */
return SCPE_IERR;
xb = mtxb[ch]; /* get xfer buf */
u = mt_unit[ch] & 017;
if ((xb == NULL) || (u > MT_NUMDR)) /* invalid args? */
return SCPE_IERR;
uptr = mt_dev[ch].units + u; /* get unit */
mt_chob[ch] = val & DMASK; /* save word from chan */
mt_chob_v[ch] = 1; /* set valid */
if (uptr->UST == (CHSL_WRS|CHSL_2ND)) { /* data write? */
for (k = 30; /* proc 6 bytes */
(k >= 0) && (mt_bptr[ch] < MT_MAXFR);
k = k - 6) {
by = (uint8) ((val >> k) & 077); /* get byte */
if ((mt_unit[ch] & 020) == 0) { /* BCD? */
if (by == 0) /* cvt bin 0 */
by = BCD_ZERO;
else if (by & 020) /* invert zones */
by = by ^ 040;
if (!odd_par[by]) /* even parity */
by = by | 0100;
}
else if (odd_par[by]) /* bin, odd par */
by = by | 0100;
xb[mt_bptr[ch]++] = by; /* put in buffer */
}
if (eorfl)
return mt_rec_end (uptr); /* EOR? write rec */
return SCPE_OK;
}
return SCPE_IERR;
}
/* Unit timeout */
t_stat mt_svc (UNIT *uptr)
{
uint32 i, u, ch = uptr->UCH; /* get channel number */
uint8 by, *xb = mtxb[ch]; /* get xfer buffer */
t_uint64 dat;
t_mtrlnt bc;
t_stat r;
if (xb == NULL) /* valid buffer? */
return SCPE_IERR;
u = uptr - mt_dev[ch].units;
switch (uptr->UST) { /* case on state */
case CHSL_RDS: /* read start */
if (QCHRONO (ch, mt_unit[ch] & 017)) /* Chronolog clock? */
bc = chrono_rd (xb, MT_MAXFR); /* read clock */
else { /* real tape */
r = sim_tape_rdrecf (uptr, xb, &bc, MT_MAXFR); /* read record */
if (r = mt_map_err (uptr, r)) /* map status */
return r;
if (mt_unit[ch] == 0) /* disconnected? */
return SCPE_OK;
} /* end else Chrono */
if (!ch6_qconn (ch, mt_unit[ch])) { /* chan disconnected? */
mt_unit[ch] = 0; /* clr ctrl busy */
return SCPE_OK;
}
for (i = bc; i < (bc + 6); i++) /* extra 0's */
xb[i] = 0;
mt_bptr[ch] = 0; /* set ptr, lnt */
mt_blnt[ch] = bc;
uptr->UST = CHSL_RDS|CHSL_2ND; /* next state */
sim_activate (uptr, mt_tword);
break;
case CHSL_RDS|CHSL_2ND: /* read word */
for (i = 0, dat = 0; i < 6; i++) { /* proc 6 bytes */
by = xb[mt_bptr[ch]++] & 077; /* get next byte */
if ((mt_unit[ch] & 020) == 0) { /* BCD? */
if (by == BCD_ZERO) /* cvt BCD 0 */
by = 0;
else if (by & 020) /* invert zones */
by = by ^ 040;
}
dat = (dat << 6) | ((t_uint64) by);
}
if (mt_bptr[ch] >= mt_blnt[ch]) { /* end of record? */
ch6_req_rd (ch, mt_unit[ch], dat, CH6DF_EOR);
uptr->UST = CHSL_RDS|CHSL_3RD; /* next state */
sim_activate (uptr, mt_tstop); /* long timing */
}
else {
ch6_req_rd (ch, mt_unit[ch], dat, 0); /* send to channel */
sim_activate (uptr, mt_tword); /* next word */
}
break;
case CHSL_RDS|CHSL_3RD: /* end record */
if (ch6_qconn (ch, mt_unit[ch])) { /* ch still conn? */
uptr->UST = CHSL_RDS; /* initial state */
sim_activate (uptr, mt_tshort); /* sched next record */
}
else mt_unit[ch] = 0; /* clr ctrl busy */
if (DEBUG_PRS (mt_dev[ch]))
fprintf (sim_deb, ">>%s%d RDS complete, pos = %d, %s\n",
mt_dev[ch].name, u, uptr->pos,
mt_unit[ch]? "continuing": "disconnecting");
return SCPE_OK;
case CHSL_WRS: /* write start */
if (!ch6_qconn (ch, mt_unit[ch])) { /* chan disconnected? */
mt_unit[ch] = 0; /* clr ctrl busy */
return SCPE_OK; /* (writes blank tape) */
}
mt_bptr[ch] = 0; /* init buffer */
uptr->UST = CHSL_WRS|CHSL_2ND; /* next state */
ch6_req_wr (ch, mt_unit[ch]); /* request channel */
mt_chob[ch] = 0; /* clr, inval buffer */
mt_chob_v[ch] = 0;
sim_activate (uptr, mt_tword); /* wait for word */
break;
case CHSL_WRS|CHSL_2ND: /* write word */
if (!ch6_qconn (ch, mt_unit[ch])) /* disconnected? */
return mt_rec_end (uptr); /* write record */
if (mt_chob_v[ch]) /* valid? clear */
mt_chob_v[ch] = 0;
else ind_ioc = 1; /* no, io check */
ch6_req_wr (ch, mt_unit[ch]); /* request channel */
sim_activate (uptr, mt_tword); /* next word */
break;
case CHSL_WRS|CHSL_3RD: /* write stop */
if (ch6_qconn (ch, mt_unit[ch])) { /* chan active? */
uptr->UST = CHSL_WRS; /* initial state */
sim_activate (uptr, mt_tshort); /* sched next record */
}
else mt_unit[ch] = 0; /* clr ctrl busy */
if (DEBUG_PRS (mt_dev[ch]))
fprintf (sim_deb, ">>%s%d WRS complete, pos = %d, %s\n",
mt_dev[ch].name, u, uptr->pos,
mt_unit[ch]? "continuing": "disconnecting");
return SCPE_OK;
case CHSL_BSR: /* backspace rec */
r = sim_tape_sprecr (uptr, &bc); /* space backwards */
mt_unit[ch] = 0; /* clr ctrl busy */
ch6_end_nds (ch); /* disconnect */
if (DEBUG_PRS (mt_dev[ch]))
fprintf (sim_deb, ">>%s%d BSR complete, pos = %d\n",
mt_dev[ch].name, u, uptr->pos);
if (r == MTSE_TMK) /* allow tape mark */
return SCPE_OK;
return mt_map_err (uptr, r);
case CHSL_BSF: /* backspace file */
while ((r = sim_tape_sprecr (uptr, &bc)) == MTSE_OK) ;
mt_unit[ch] = 0; /* clr ctrl busy */
ch6_end_nds (ch); /* disconnect */
if (DEBUG_PRS (mt_dev[ch]))
fprintf (sim_deb, ">>%s%d BSF complete, pos = %d\n",
mt_dev[ch].name, u, uptr->pos);
if (r == MTSE_TMK) /* allow tape mark */
return SCPE_OK;
return mt_map_err (uptr, r); /* map others */
case CHSL_WEF: /* write eof */
r = sim_tape_wrtmk (uptr); /* write tape mark */
mt_unit[ch] = 0; /* clr ctrl busy */
ch6_end_nds (ch); /* disconnect */
if (DEBUG_PRS (mt_dev[ch]))
fprintf (sim_deb, ">>%s%d WEF complete, pos = %d\n",
mt_dev[ch].name, u, uptr->pos);
return mt_map_err (uptr, r);
case CHSL_REW: case CHSL_RUN: /* rewind, unload */
uptr->UST = uptr->UST | CHSL_2ND; /* set 2nd state */
sim_activate (uptr, mt_tstart); /* reactivate */
mt_unit[ch] = 0; /* clr ctrl busy */
ch6_end_nds (ch); /* disconnect */
return SCPE_OK;
case CHSL_REW | CHSL_2ND:
sim_tape_rewind (uptr);
if (DEBUG_PRS (mt_dev[ch]))
fprintf (sim_deb, ">>%s%d REW complete, pos = %d\n",
mt_dev[ch].name, u, uptr->pos);
return SCPE_OK;
case CHSL_RUN | CHSL_2ND:
sim_tape_detach (uptr);
if (DEBUG_PRS (mt_dev[ch]))
fprintf (sim_deb, ">>%s%d RUN complete, pos = %d\n",
mt_dev[ch].name, u, uptr->pos);
return SCPE_OK;
case CHSL_SDN:
if (mt_unit[ch] & 020) /* set density flag */
uptr->flags = uptr-> flags & ~MTUF_LDN;
else uptr->flags = uptr->flags | MTUF_LDN;
mt_unit[ch] = 0; /* clr ctrl busy */
ch6_end_nds (ch); /* disconnect */
if (DEBUG_PRS (mt_dev[ch]))
fprintf (sim_deb, ">>%s%d SDN complete, pos = %d\n",
mt_dev[ch].name, u, uptr->pos);
return SCPE_OK;
default:
return SCPE_IERR;
}
return SCPE_OK;
}
/* End record routine */
t_stat mt_rec_end (UNIT *uptr)
{
uint32 ch = uptr->UCH;
uint8 *xb = mtxb[ch];
t_stat r;
if (mt_bptr[ch]) { /* any data? */
if (xb == NULL)
return SCPE_IERR;
r = sim_tape_wrrecf (uptr, xb, mt_bptr[ch]); /* write record */
if (r = mt_map_err (uptr, r)) /* map error */
return r;
}
uptr->UST = CHSL_WRS|CHSL_3RD; /* next state */
sim_cancel (uptr); /* cancel current */
sim_activate (uptr, mt_tstop); /* long timing */
return SCPE_OK;
}
/* Map tape error status */
t_stat mt_map_err (UNIT *uptr, t_stat st)
{
uint32 ch = uptr->UCH;
uint32 u = mt_unit[ch];
uint32 up = uptr - mt_dev[ch].units;
if ((st != MTSE_OK) && DEBUG_PRS (mt_dev[ch]))
fprintf (sim_deb, ">>%s%d status = %s, pos = %d\n",
mt_dev[ch].name, up, tape_stat[st], uptr->pos);
switch (st) {
case MTSE_FMT: /* illegal fmt */
case MTSE_UNATT: /* not attached */
ch6_err_disc (ch, u, CHF_TRC);
mt_unit[ch] = 0; /* disconnect */
return SCPE_IERR;
case MTSE_IOERR: /* IO error */
ch6_err_disc (ch, u, CHF_TRC);
mt_unit[ch] = 0; /* disconnect */
return SCPE_IOERR;
case MTSE_INVRL: /* invalid rec lnt */
ch6_err_disc (ch, u, CHF_TRC);
mt_unit[ch] = 0; /* disconnect */
return SCPE_MTRLNT;
case MTSE_WRP: /* write protect */
ch6_err_disc (ch, u, 0);
mt_unit[ch] = 0; /* disconnect */
return STOP_WRP;
case MTSE_EOM: /* end of medium */
case MTSE_TMK: /* tape mark */
ch6_err_disc (ch, u, CHF_EOF);
mt_unit[ch] = 0; /* disconnect */
break;
case MTSE_RECE: /* record in error */
ch6_set_flags (ch, u, CHF_TRC);
break;
case MTSE_BOT: /* reverse into BOT */
ch6_set_flags (ch, u, CHF_BOT);
break;
case MTSE_OK: /* no error */
break;
}
return SCPE_OK;
}
/* Magtape reset */
t_stat mt_reset (DEVICE *dptr)
{
uint32 ch = dptr - &mt_dev[0];
uint32 j;
REG *rptr;
UNIT *uptr;
if (mtxb[ch] == NULL)
mtxb[ch] = (uint8 *) calloc (MT_MAXFR + 6, sizeof (uint8));
if (mtxb[ch] == NULL) /* allocate buffer */
return SCPE_MEM;
rptr = find_reg ("BUF", NULL, dptr); /* update reg ptr */
if (rptr == NULL)
return SCPE_IERR;
rptr->loc = (void *) mtxb[ch];
mt_unit[ch] = 0; /* clear busy */
mt_bptr[ch] = 0; /* clear buf ptrs */
mt_blnt[ch] = 0;
mt_chob[ch] = 0;
mt_chob_v[ch] = 0;
for (j = 1; j <= MT_NUMDR; j++) { /* for all units */
uptr = dptr->units + j;
uptr->UST = 0; /* clear state */
uptr->UCH = ch;
sim_cancel (uptr); /* stop activity */
} /* end for */
return SCPE_OK; /* done */
}
/* Magtape attach */
t_stat mt_attach (UNIT *uptr, char *cptr)
{
uptr->flags = uptr->flags & ~MTUF_LDN; /* start as hi den */
return sim_tape_attach (uptr, cptr);
}
/* Magtape boot */
#define BOOT_START 01000
static const t_uint64 boot_rom[5] = {
0076200000000 + U_MTBIN - 1, /* RDS MT_binary */
0054000000000 + BOOT_START + 4, /* RCHA *+3 */
0054400000000, /* LCHA 0 */
0002100000001, /* TTR 1 */
0500003000000, /* IOCT 0,,3 */
};
t_stat mt_boot (int32 unitno, DEVICE *dptr)
{
uint32 i, chan;
extern t_uint64 *M;
chan = dptr - &mt_dev[0] + 1;
WriteP (BOOT_START, boot_rom[0] + unitno + (chan << 9));
for (i = 1; i < 5; i++)
WriteP (BOOT_START + i, boot_rom[i]);
PC = BOOT_START;
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* i7094_sys.c: IBM 7094 simulator interface
Copyright (c) 2003-2010, Robert M Supnik
Copyright (c) 2003-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
31-Dec-11 RMS Added SPI, SPI
16-Jul-10 RMS Added SPUx, SPTx, SPRx
29-Oct-06 RMS Added additional expanded core instructions
08-Jun-06 RMS Added Dave Pitts' binary loader
@ -362,7 +363,8 @@ static const char *opcode[] = {
"RSCF", "RSCH",
"STCB", "STCD",
"STCF", "STCH",
"STQ", "ORS", "DST",
"STQ", "SRI", "ORS", "DST",
"SPI",
"SLQ", "STL",
"SXD", "SCD",
"SCHB", "SCHD",
@ -533,7 +535,8 @@ static const t_uint64 opc_v[] = {
0454200000000+I_MXN, 0454300000000+I_MXN,
0454400000000+I_MXN, 0454500000000+I_MXN,
0454600000000+I_MXN, 0454700000000+I_MXN,
0460000000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN,
0460000000000+I_MXN, 0460100000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN,
0460400000000+I_MXN,
0462000000000+I_MXN, 0462500000000+I_MXN,
0463400000000+I_MXR, 0463600000000+I_MXR,
0464000000000+I_MXN, 0464000000000+I_MXN,

View file

@ -1,748 +0,0 @@
/* i7094_sys.c: IBM 7094 simulator interface
Copyright (c) 2003-2008, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
29-Oct-06 RMS Added additional expanded core instructions
08-Jun-06 RMS Added Dave Pitts' binary loader
*/
#include "i7094_defs.h"
#include <ctype.h>
#include "i7094_dat.h"
extern DEVICE cpu_dev;
extern DEVICE ch_dev[NUM_CHAN];
extern DEVICE mt_dev[NUM_CHAN];
extern DEVICE drm_dev;
extern DEVICE dsk_dev;
extern DEVICE com_dev, coml_dev;
extern DEVICE cdr_dev, cdp_dev;
extern DEVICE lpt_dev;
extern DEVICE clk_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
uint32 cvt_code_to_ascii (uint32 c, int32 sw);
uint32 cvt_ascii_to_code (uint32 c, int32 sw);
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "IBM 7094";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 1;
DEVICE *sim_devices[] = {
&cpu_dev,
&clk_dev,
&ch_dev[0],
&ch_dev[1],
&ch_dev[2],
&ch_dev[3],
&ch_dev[4],
&ch_dev[5],
&ch_dev[6],
&ch_dev[7],
&mt_dev[0],
&mt_dev[1],
&mt_dev[2],
&mt_dev[3],
&mt_dev[4],
&mt_dev[5],
&mt_dev[6],
&mt_dev[7],
&cdr_dev,
&cdp_dev,
&lpt_dev,
&dsk_dev,
&drm_dev,
&com_dev,
&coml_dev,
NULL
};
char ch_bkpt_msg[] = "Channel A breakpoint, CLC: xxxxxx";
const char *sim_stop_messages[] = {
"Unknown error",
"HALT instruction",
"Breakpoint",
"Undefined instruction",
"Divide check",
"Nested XEC limit exceeded",
"Address stop",
"Non-existent channel",
"Illegal instruction for 7909 channel",
"Illegal instruction for non-7909 channel",
"Non-existent device",
"Undefined channel instruction",
"Write to protected device",
"Illegal instruction for device",
"Invalid 7631 track format",
"7750 buffer pool empty on input",
"7750 buffer pool empty on output",
"7750 invalid line number",
"7750 invalid message",
ch_bkpt_msg
};
/* Modify channel breakpoint message */
t_stat ch_bkpt (uint32 ch, uint32 clc)
{
ch_bkpt_msg[8] = 'A' + ch;
sprintf (&ch_bkpt_msg[27], "%06o", clc);
return STOP_CHBKPT;
}
/* Binary loader, not implemented */
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
extern t_stat binloader (FILE *fd, char *file, int loadpt);
if (flag == 0)
return binloader (fileref, cptr, 0);
return SCPE_NOFNC;
}
/* Symbol tables */
#define I_V_FL 39 /* inst class */
#define I_M_FL 017 /* class mask */
#define I_NOP 0000000000000000 /* no operand */
#define I_MXR 0010000000000000 /* addr(tag) */
#define I_MXN 0020000000000000 /* *addr(tag) */
#define I_MXV 0030000000000000 /* var mul/div */
#define I_MXC 0040000000000000 /* convert */
#define I_DNP 0050000000000000 /* decr, no oper */
#define I_DEC 0060000000000000 /* decrement */
#define I_SNS 0070000000000000 /* sense */
#define I_IMM 0100000000000000 /* 18b immediate */
#define I_TAG 0110000000000000 /* tag only */
#define I_IOX 0120000000000000 /* IO channel */
#define I_TCH 0130000000000000 /* transfer channel */
#define I_I9N 0140000000000000 /* 7909 with nostore */
#define I_I9S 0150000000000000 /* 7909 */
#define IFAKE_7607 0001000000000000 /* fake op extensions */
#define IFAKE_7909 0002000000000000
#define DFAKE (DMASK|IFAKE_7607|IFAKE_7909)
#define I_N_NOP 000
#define I_N_MXR 001
#define I_N_MXN 002
#define I_N_MXV 003
#define I_N_MXC 004
#define I_N_DNP 005
#define I_N_DEC 006
#define I_N_SNS 007
#define I_N_IMM 010
#define I_N_TAG 011
#define I_N_IOX 012
#define I_N_TCH 013
#define I_N_I9N 014
#define I_N_I9S 015
#define INST_P_XIT 0 /* exit */
#define INST_P_SKP 1 /* do not print */
#define INST_P_PRA 2 /* print always */
#define INST_P_PNZ 3 /* print if nz */
#define INST_P_PNT 4 /* print if nz, term */
static const t_uint64 masks[14] = {
03777700000000, 03777700000000,
03777700000000, 03777700000000,
03777400000000, 03700000000000,
03700000000000, 03777700077777,
03777700000000, 03777700000000,
03700000200000, 03700000200000,
03760000200000, 03740000200000 };
static const uint32 fld_max[14][3] = { /* addr,tag,decr limit */
{ INST_M_ADDR, INST_M_TAG, 0 },
{ INST_M_ADDR, INST_M_TAG, 0 },
{ INST_M_ADDR, INST_M_TAG, 0 },
{ INST_M_ADDR, INST_M_TAG, INST_M_VCNT },
{ INST_M_ADDR, INST_M_TAG, INST_M_CCNT },
{ INST_M_ADDR, INST_M_TAG, INST_M_DEC },
{ INST_M_ADDR, INST_M_TAG, INST_M_DEC },
{ 0, INST_M_TAG, 0 },
{ RMASK, 0, 0 },
{ INST_M_ADDR, INST_M_TAG, 0 },
{ INST_M_ADDR, 1, INST_M_DEC },
{ INST_M_ADDR, 1, 0 },
{ INST_M_ADDR, 1, 0 },
{ INST_M_ADDR, 1, 0 }
};
static const uint32 fld_fmt[14][3] = { /* addr,tag,decr print */
{ INST_P_PNT, INST_P_PNT, INST_P_XIT }, /* nop: all optional */
{ INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* mxr: tag optional */
{ INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* mxn: tag optional */
{ INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* mxv: tag optional */
{ INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* cvt: tag optional */
{ INST_P_PNT, INST_P_PNT, INST_P_PNT }, /* dnp: all optional */
{ INST_P_PRA, INST_P_PRA, INST_P_PRA }, /* dec: print all */
{ INST_P_SKP, INST_P_PNT, INST_P_XIT }, /* sns: skip addr, tag opt */
{ INST_P_PRA, INST_P_XIT, INST_P_XIT }, /* immediate: addr only */
{ INST_P_PNZ, INST_P_PRA, INST_P_XIT }, /* tag: addr optional */
{ INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* iox: tag optional */
{ INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* tch: tag optional */
{ INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* i9n: tag optional */
{ INST_P_PRA, INST_P_PNT, INST_P_XIT } /* i9s: tag optional */
};
static const t_uint64 ind_test[14] = {
0, 0, INST_IND, 0, 0, 0, 0,
0, 0, 0, CHI_IND, CHI_IND, CHI_IND, CHI_IND
};
static const char *opcode[] = {
"TXI", "TIX", "TXH",
"STR", "TNX", "TXL",
"HTR", "TRA", "TTR",
"CLM", "LBT", "CHS",
"SSP", "ENK", "IOT",
"COM", "ETM", "RND",
"FRN", "DCT", "RCT",
"LMTM", "SLF", "SLN1",
"SLN2", "SLN3", "SLN4",
"SWT1", "SWT2", "SWT3",
"SWT4", "SWT5", "SWT6",
"BTTA", "BTTB", "BTTC",
"BTTD", "BTTE", "BTTF",
"BTTG", "BTTH",
"RICA", "RICB", "RICC",
"RICD", "RICE", "RICF",
"RICG", "RICH",
"RDCA", "RDCB", "RDCC",
"RDCD", "RDCE", "RDCF",
"RDCG", "RDCH",
"TRCA", "TRCC",
"TRCE", "TRCG",
"TEFA", "TEFC",
"TEFE", "TEFG",
"TLQ", "IIA", "TIO",
"OAI", "PAI", "TIF",
"IIR", "RFT", "SIR",
"RNT", "RIR",
"TCOA", "TCOB", "TCOC",
"TCOD", "TCOE", "TCOF",
"TCOG", "TCOH", "TSX",
"TZE", "CVR", "TPL",
"XCA", "TOV",
"TQO", "TQP",
"MPY", "VLM", "VLM1",
"DVH", "DVP",
"VDH", "VDP",
"VDH2", "VDP2",
"FDH", "FDP",
"FMP", "DFMP",
"FAD", "DFAD",
"FSB", "DFSB",
"FAM", "DFAM",
"FSM", "DFSM",
"ANS", "ERA",
"CAS", "ACL",
"ADD", "ADM",
"SUB", "SBM",
"HPR", "IIS", "LDI",
"OSI", "DLD", "OFT",
"RIS", "ONT",
"CLA", "CLS",
"ZET", "XEC",
"LXA", "LAC",
"RCHA", "RCHC",
"RCHE", "RCHG",
"LCHA", "LCHC",
"LCHE", "LCHG",
"RSCA", "RSCC",
"RSCE", "RSCG",
"STCA", "STCC",
"STCE", "STCG",
"LDQ", "ENB",
"STZ", "STO", "SLW",
"STI", "STA", "STD",
"STT", "STP",
"SXA", "SCA",
"SCHA", "SCHC",
"SCHE", "SCHG",
"SCDA", "SCDC",
"SCDE", "SCDG",
"PAX", "PAC",
"PXA", "PCA",
"PSE", "NOP", "RDS",
"LLS", "BSR", "LRS",
"WRS", "ALS", "WEF",
"ARS", "REW", "AXT",
"SDN",
"CLM", "PBT", "EFTM",
"SSM", "LFTM", "ESTM",
"ECTM", "LTM", "LSNM",
"EMTM", "SLT1", "SLT2",
"SLT3", "SLT4",
"ETTA", "ETTB", "ETTC",
"ETTD", "ETTE", "ETTF",
"ETTG", "ETTH",
"ESNT",
"TRCB", "TRCD",
"TRCF", "TRCH",
"TEFB", "TEFD",
"TEFF", "TEFH",
"RIA", "PIA",
"IIL", "LFT", "SIL",
"LNT", "RIL",
"TCNA", "TCNB", "TCNC",
"TCND", "TCNE", "TCNF",
"TCNG", "TCNH",
"TNZ", "CVR", "TMI",
"XCL", "TNO", "CRQ",
"MPR", "DFDH", "DFDP",
"UFM", "DUFM",
"UFA", "DUFA",
"UFS", "DUFS",
"UAM", "DUAM",
"USM", "DUSM",
"ANA", "LAS",
"CAL", "ORA", "NZT",
"LXD", "LXC",
"RCHB", "RCHD",
"RCHF", "RCHH",
"LCHB", "LCHD",
"LCHF", "LCHH",
"RSCB", "RSCD",
"RSCF", "RSCH",
"STCB", "STCD",
"STCF", "STCH",
"STQ", "ORS", "DST",
"SLQ", "STL",
"SXD", "SCD",
"SCHB", "SCHD",
"SCHF", "SCHH",
"SCDB", "SCDD",
"SCDF", "SCDH",
"PDX", "PDC",
"PXD", "PCD",
"MSE", "LGL", "BSF",
"LGR", "RQL", "RUN",
"AXC",
"TIA", "TIB",
"LRI", "LPI",
"SEA", "SEB",
"IFT", "EFT",
"IOCD", "IOCDN", "TCH",
"IORP", "IORPN",
"IORT", "IORTN",
"IOCP", "IOCPN",
"IOCT", "IOCTN",
"IOSP", "IOSPN",
"IOST", "IOSTN",
"WTR", "XMT",
"TCH", "LIPT",
"CTL", "CTLN",
"CTLR", "CTLRN",
"CTLW", "CTLWN",
"SNS",
"LAR", "SAR", "TWT",
"CPYP",
"CPYD", "TCM",
"LIP", "TDC", "LCC",
"SMS", "ICC",
NULL
};
static const t_uint64 opc_v[] = {
0100000000000+I_DEC, 0200000000000+I_DEC, 0300000000000+I_DEC,
0500000000000+I_DNP, 0600000000000+I_DEC, 0700000000000+I_DEC,
0000000000000+I_MXN, 0002000000000+I_MXN, 0002100000000+I_MXN,
0076000000000+I_SNS, 0076000000001+I_SNS, 0076000000002+I_SNS,
0076000000003+I_SNS, 0076000000004+I_SNS, 0076000000005+I_SNS,
0076000000006+I_SNS, 0076000000007+I_SNS, 0076000000010+I_SNS,
0076000000011+I_SNS, 0076000000012+I_SNS, 0076000000014+I_SNS,
0076000000016+I_SNS, 0076000000140+I_SNS, 0076000000141+I_SNS,
0076000000142+I_SNS, 0076000000143+I_SNS, 0076000000144+I_SNS,
0076000000161+I_SNS, 0076000000162+I_SNS, 0076000000163+I_SNS,
0076000000164+I_SNS, 0076000000165+I_SNS, 0076000000166+I_SNS,
0076000001000+I_SNS, 0076000002000+I_SNS, 0076000003000+I_SNS,
0076000004000+I_SNS, 0076000005000+I_SNS, 0076000006000+I_SNS,
0076000007000+I_SNS, 0076000010000+I_SNS,
0076000001350+I_SNS, 0076000002350+I_SNS, 0076000003350+I_SNS,
0076000004350+I_SNS, 0076000005350+I_SNS, 0076000006350+I_SNS,
0076000007350+I_SNS, 0076000010350+I_SNS,
0076000001352+I_SNS, 0076000002352+I_SNS, 0076000003352+I_SNS,
0076000004352+I_SNS, 0076000005352+I_SNS, 0076000006352+I_SNS,
0076000007352+I_SNS, 0076000010352+I_SNS,
0002200000000+I_MXN, 0002400000000+I_MXN,
0002600000000+I_MXN, 0002700000000+I_MXN,
0003000000000+I_MXN, 0003100000000+I_MXN,
0003200000000+I_MXN, 0003300000000+I_MXN,
0004000000000+I_MXN, 0004100000000+I_NOP, 0004200000000+I_MXR,
0004300000000+I_NOP, 0004400000000+I_NOP, 0004600000000+I_MXR,
0005100000000+I_IMM, 0005400000000+I_IMM, 0005500000000+I_IMM,
0005600000000+I_IMM, 0005700000000+I_IMM,
0006000000000+I_MXN, 0006100000000+I_MXN, 0006200000000+I_MXN,
0006300000000+I_MXN, 0006400000000+I_MXN, 0006500000000+I_MXN,
0006600000000+I_MXN, 0006700000000+I_MXN, 0007400000000+I_MXR,
0010000000000+I_MXN, 0011400000000+I_MXC, 0012000000000+I_MXN,
0013100000000+I_NOP, 0014000000000+I_MXN,
0016100000000+I_MXN, 0016200000000+I_MXN,
0020000000000+I_MXN, 0020400000000+I_MXV, 0020500000000+I_MXV,
0022000000000+I_MXN, 0022100000000+I_MXN,
0022400000000+I_MXV, 0022500000000+I_MXV,
0022600000000+I_MXV, 0022700000000+I_MXV,
0024000000000+I_MXN, 0024100000000+I_MXN,
0026000000000+I_MXN, 0026100000000+I_MXN,
0030000000000+I_MXN, 0030100000000+I_MXN,
0030200000000+I_MXN, 0030300000000+I_MXN,
0030400000000+I_MXN, 0030500000000+I_MXN,
0030600000000+I_MXN, 0030700000000+I_MXN,
0032000000000+I_MXN, 0032200000000+I_MXN,
0034000000000+I_MXN, 0036100000000+I_MXN,
0040000000000+I_MXN, 0040100000000+I_MXN,
0040200000000+I_MXN, 0440000000000+I_MXN,
0042000000000+I_NOP, 0044000000000+I_MXN, 0044100000000+I_MXN,
0044200000000+I_MXN, 0044300000000+I_MXN, 0044400000000+I_MXN,
0044500000000+I_MXN, 0044600000000+I_MXN,
0050000000000+I_MXN, 0050200000000+I_MXN,
0052000000000+I_MXN, 0052200000000+I_MXN,
0053400000000+I_MXR, 0053500000000+I_MXR,
0054000000000+I_MXN, 0054100000000+I_MXN,
0054200000000+I_MXN, 0054300000000+I_MXN,
0054400000000+I_MXN, 0054500000000+I_MXN,
0054600000000+I_MXN, 0054700000000+I_MXN,
0054000000000+I_MXN, 0054100000000+I_MXN,
0054200000000+I_MXN, 0054300000000+I_MXN,
0054400000000+I_MXN, 0054500000000+I_MXN,
0054600000000+I_MXN, 0054700000000+I_MXN,
0056000000000+I_MXN, 0056400000000+I_MXN,
0060000000000+I_MXN, 0060100000000+I_MXN, 0060200000000+I_MXN,
0060400000000+I_MXN, 0062100000000+I_MXN, 0062200000000+I_MXN,
0062500000000+I_MXN, 0063000000000+I_MXN,
0063400000000+I_MXR, 0063600000000+I_MXR,
0064000000000+I_MXN, 0064000000000+I_MXN,
0064200000000+I_MXN, 0064300000000+I_MXN,
0064400000000+I_MXN, 0064500000000+I_MXN,
0064600000000+I_MXN, 0064700000000+I_MXN,
0073400000000+I_TAG, 0073700000000+I_TAG,
0075400000000+I_TAG, 0075600000000+I_TAG,
0076000000000+I_MXR, 0076100000000+I_NOP, 0076200000000+I_MXR,
0076300000000+I_MXR, 0076400000000+I_MXR, 0076500000000+I_MXR,
0076600000000+I_MXR, 0076700000000+I_MXR, 0077000000000+I_MXR,
0077100000000+I_MXR, 0077200000000+I_MXR, 0077400000000+I_MXR,
0077600000000+I_MXR,
0476000000000+I_SNS, 0476000000001+I_SNS, 0476000000002+I_SNS,
0476000000003+I_SNS, 0476000000004+I_SNS, 0476000000005+I_SNS,
0476000000006+I_SNS, 0476000000007+I_SNS, 0476000000010+I_SNS,
0476000000016+I_SNS, 0476000000141+I_SNS, 0476000000142+I_SNS,
0476000000143+I_SNS, 0476000000144+I_SNS,
0476000001000+I_SNS, 0476000002000+I_SNS, 0476000003000+I_SNS,
0476000004000+I_SNS, 0476000005000+I_SNS, 0476000006000+I_SNS,
0476000007000+I_SNS, 0476000010000+I_SNS,
0402100000000+I_MXN,
0402200000000+I_MXN, 0402400000000+I_MXN,
0402600000000+I_MXN, 0402700000000+I_MXN,
0403000000000+I_MXN, 0403100000000+I_MXN,
0403200000000+I_MXN, 0403300000000+I_MXN,
0404200000000+I_NOP, 0404600000000+I_NOP,
0405100000000+I_IMM, 0405400000000+I_IMM, 0405500000000+I_IMM,
0405600000000+I_IMM, 0405700000000+I_IMM,
0406000000000+I_MXN, 0406100000000+I_MXN, 0406200000000+I_MXN,
0406300000000+I_MXN, 0406400000000+I_MXN, 0406500000000+I_MXN,
0406600000000+I_MXN, 0406700000000+I_MXN,
0410000000000+I_MXN, 0411400000000+I_MXC, 0412000000000+I_MXN,
0413000000000+I_NOP, 0414000000000+I_MXN, 0415400000000+I_MXC,
0420000000000+I_MXN, 0424000000000+I_MXN, 0424100000000+I_MXN,
0426000000000+I_MXN, 0426100000000+I_MXN,
0430000000000+I_MXN, 0430100000000+I_MXN,
0430200000000+I_MXN, 0430300000000+I_MXN,
0430400000000+I_MXN, 0430500000000+I_MXN,
0430600000000+I_MXN, 0430700000000+I_MXN,
0432000000000+I_MXN, 0434000000000+I_MXN,
0450000000000+I_MXN, 0450100000000+I_MXN, 0452000000000+I_MXN,
0453400000000+I_MXR, 0453500000000+I_MXR,
0454000000000+I_MXN, 0454100000000+I_MXN,
0454200000000+I_MXN, 0454300000000+I_MXN,
0454400000000+I_MXN, 0454500000000+I_MXN,
0454600000000+I_MXN, 0454700000000+I_MXN,
0454000000000+I_MXN, 0454100000000+I_MXN,
0454200000000+I_MXN, 0454300000000+I_MXN,
0454400000000+I_MXN, 0454500000000+I_MXN,
0454600000000+I_MXN, 0454700000000+I_MXN,
0460000000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN,
0462000000000+I_MXN, 0462500000000+I_MXN,
0463400000000+I_MXR, 0463600000000+I_MXR,
0464000000000+I_MXN, 0464000000000+I_MXN,
0464200000000+I_MXN, 0464300000000+I_MXN,
0464400000000+I_MXN, 0464500000000+I_MXN,
0464600000000+I_MXN, 0464700000000+I_MXN,
0473400000000+I_TAG, 0473700000000+I_TAG,
0475400000000+I_TAG, 0475600000000+I_TAG,
0476000000000+I_MXR, 0476300000000+I_MXR, 0476400000000+I_MXR,
0476500000000+I_MXR, 0477300000000+I_MXR, 0477200000000+I_MXR,
0477400000000+I_MXR,
0010100000000+I_MXN, 0410100000000+I_MXN,
0056200000000+I_MXN, 0456400000000+I_MXN,
0476100000041+I_SNS, 0476100000042+I_SNS,
0476100000043+I_SNS, 0476100000044+I_SNS,
01000000000000+I_IOX, 01000000200000+I_IOX, 01100000000000+I_TCH,
01200000000000+I_IOX, 01200000200000+I_IOX,
01300000000000+I_IOX, 01300000200000+I_IOX,
01400000000000+I_IOX, 01400000200000+I_IOX,
01500000000000+I_IOX, 01500000200000+I_IOX,
01600000000000+I_IOX, 01600000200000+I_IOX,
01700000000000+I_IOX, 01700000200000+I_IOX,
02000000000000+I_TCH, 02000000200000+I_IOX,
02100000000000+I_TCH, 02100000200000+I_TCH,
02200000000000+I_I9N, 02220000000000+I_TCH,
02200000200000+I_I9N, 02220000200000+I_TCH,
02240000000000+I_I9N, 02260000000000+I_TCH,
02240000200000+I_I9N,
02300000000000+I_I9S, 02300000200000+I_I9S,
02340000000000+I_I9S,
02400000000000+I_IOX,
02500000000000+I_IOX, 02500000200000+I_IOX,
02600000200000+I_I9S, 02640000000000+I_I9S, 02640000200000+I_I9S,
02700000000000+I_I9S, 02700000200000+I_IOX,
0
};
/* 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)
{
uint32 i, j, k, l, fmt, c, fld[3];
DEVICE *dptr;
t_uint64 inst;
inst = val[0];
if (uptr == NULL)
uptr = &cpu_unit;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
return SCPE_IERR;
if (sw & SWMASK ('C')) { /* character? */
c = (uint32) (inst & 077);
fprintf (of, "%c", cvt_code_to_ascii (c, sw));
return SCPE_OK;
}
if (sw & SWMASK ('S')) { /* string? */
for (i = 36; i > 0; i = i - 6) {
c = (uint32) ((inst >> (i - 6)) & 077);
fprintf (of, "%c", cvt_code_to_ascii (c, sw));
}
return SCPE_OK;
}
if (!(sw & (SWMASK ('M')|SWMASK ('I')|SWMASK ('N'))) || /* M, N or I? */
(dptr->dwidth != 36))
return SCPE_ARG;
/* Instruction decode */
fld[0] = ((uint32) inst & 0777777);
fld[1] = GET_TAG (inst); /* get 3 fields */
fld[2] = GET_DEC (inst);
if (sw & SWMASK ('I')) /* decode as 7607? */
inst |= IFAKE_7607;
if (sw & SWMASK ('N')) /* decode as 7909? */
inst |= IFAKE_7909;
for (i = 0; opc_v[i] > 0; i++) { /* loop thru ops */
j = (int32) ((opc_v[i] >> I_V_FL) & I_M_FL); /* get class */
if ((opc_v[i] & DFAKE) == (inst & masks[j])) { /* match? */
if (inst & ind_test[j]) /* indirect? */
fprintf (of, "%s*", opcode[i]);
else fprintf (of, "%s", opcode[i]); /* opcode */
for (k = 0; k < 3; k++)
fld[k] = fld[k] & fld_max[j][k];
for (k = 0; k < 3; k++) { /* loop thru fields */
fmt = fld_fmt[j][k]; /* get format */
if (fmt == INST_P_XIT)
return SCPE_OK;
switch (fmt) { /* case on format */
case INST_P_PNT: /* print nz, else term */
for (l = k, c = 0; l < 3; l++) c |= fld[k];
if (c == 0)
return SCPE_OK;
case INST_P_PNZ: /* print non-zero */
fputc (k? ',': ' ', of);
if (fld[k])
fprintf (of, "%-o", fld[k]);
break;
case INST_P_PRA: /* print always */
fputc (k? ',': ' ', of);
fprintf (of, "%-o", fld[k]);
break;
case INST_P_SKP: /* skip */
break;
} /* end switch */
} /* end for k */
return SCPE_OK; /* done */
} /* end if */
} /* end for i */
return SCPE_ARG;
}
/* Convert character to code to ASCII
-b BCD
-a business-chain */
uint32 cvt_code_to_ascii (uint32 c, int32 sw)
{
if (sw & SWMASK ('B')) {
if (sw & SWMASK ('A'))
return bcd_to_ascii_a[c];
else return bcd_to_ascii_h[c];
}
else if (sw & SWMASK ('A'))
return nine_to_ascii_a[c];
else return nine_to_ascii_h[c];
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
uint32 i, j, c;
t_uint64 fld[3];
t_bool ind;
t_stat r;
char gbuf[CBUFSIZE];
while (isspace (*cptr)) cptr++;
if ((sw & SWMASK ('C')) || ((*cptr == '\'') && cptr++)) { /* character? */
if (cptr[0] == 0) /* must have 1 char */
return SCPE_ARG;
val[0] = (t_value) cvt_ascii_to_code (cptr[0] & 0177, sw);
return SCPE_OK;
}
if ((sw & SWMASK ('S')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
if (cptr[0] == 0) /* must have 1 char */
return SCPE_ARG;
for (i = 0; i < 6; i++) {
c = cptr[0] & 0177;
if (c)
val[0] = (val[0] << 6) | ((t_value) cvt_ascii_to_code (c, sw));
else {
val[0] = val[0] << (6 * (6 - i));
break;
}
}
return SCPE_OK;
}
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
j = strlen (gbuf); /* get length */
if (gbuf[j - 1] == '*') { /* indirect? */
ind = TRUE;
gbuf[j - 1] = 0;
}
else ind = FALSE;
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL)
return SCPE_ARG;
j = (uint32) ((opc_v[i] >> I_V_FL) & I_M_FL); /* get class */
val[0] = opc_v[i] & DMASK;
if (ind) {
if (ind_test[j])
val[0] |= ind_test[j];
else return SCPE_ARG;
}
for (i = 0; i < 3; i++) /* clear inputs */
fld[i] = 0;
for (i = 0; (i < 3) && *cptr; i++) { /* parse inputs */
if (i < 2) /* get glyph */
cptr = get_glyph (cptr, gbuf, ',');
else cptr = get_glyph (cptr, gbuf, 0);
if (gbuf[0]) { /* anything? */
fld[i] = get_uint (gbuf, 8, fld_max[j][i], &r);
if ((r != SCPE_OK) || (fld_max[j][i] == 0))
return SCPE_ARG;
}
}
if (*cptr != 0) /* junk at end? */
return SCPE_ARG;
val[0] = val[0] | fld[0] | (fld[1] << INST_V_TAG) | (fld[2] << INST_V_DEC);
return SCPE_OK;
}
/* Convert ASCII to character code
-b BCD */
uint32 cvt_ascii_to_code (uint32 c, int32 sw)
{
if (sw & SWMASK ('B'))
return ascii_to_bcd[c];
else return ascii_to_nine[c];
}

View file

@ -24,7 +24,6 @@
in this Software without prior written authorization from Robert M Supnik.
22-May-10 RMS Added check for 64b definitions
*/
#ifndef _LGP_DEFS_H_

View file

@ -1,6 +1,6 @@
/* pdp10_sys.c: PDP-10 simulator interface
Copyright (c) 1993-2008, Robert M Supnik
Copyright (c) 1993-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
04-Apr-11 RMS Removed DEUNA/DELUA support - never implemented
01-Feb-07 RMS Added CD support
22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn)
09-Jan-03 RMS Added DEUNA/DELUA support
@ -54,7 +55,6 @@ extern DEVICE dz_dev;
extern DEVICE ry_dev;
extern DEVICE cr_dev;
extern DEVICE lp20_dev;
extern DEVICE xu_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern d10 *M;
@ -90,7 +90,6 @@ DEVICE *sim_devices[] = {
&rp_dev,
&tu_dev,
&dz_dev,
&xu_dev,
NULL
};

View file

@ -1,6 +1,6 @@
/* pdp11_dc.c: PDP-11 DC11 multiple terminal interface simulator
Copyright (c) 1993-2008, Robert M Supnik
Copyright (c) 1993-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
dci,dco DC11 terminal input/output
17-Aug-2011 RMS Added AUTOCONFIGURE modifier
19-Nov-2008 RMS Revised for common TMXR show routines
Revised to autoconfigure vectors
@ -175,6 +176,8 @@ MTAB dci_mod[] = {
NULL, &tmxr_show_cstat, (void *) &dcx_desc },
{ MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL,
&set_addr, &show_addr, NULL },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
&set_addr_flt, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 1, "VECTOR", NULL,
&set_vec, &show_vec_mux, (void *) &dcx_desc },
{ MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES",

View file

@ -1,6 +1,6 @@
/* pdp11_dl.c: PDP-11 multiple terminal interface simulator
Copyright (c) 1993-2008, Robert M Supnik
Copyright (c) 1993-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
dli,dlo DL11 terminal input/output
17-Aug-2011 RMS Added AUTOCONFIGURE modifier
19-Nov-2008 RMS Revised for common TMXR show routines
Revised to autoconfigure vectors
20-May-2008 RMS Added modem control support
@ -142,6 +143,8 @@ MTAB dli_mod[] = {
NULL, &tmxr_show_cstat, (void *) &dlx_desc },
{ MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL,
&set_addr, &show_addr, NULL },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
&set_addr_flt, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 1, "VECTOR", NULL,
&set_vec, &show_vec_mux, (void *) &dlx_desc },
{ MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES",

View file

@ -23,7 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
12-Dec-11 RMS Fixed interrupts to treat all Qbus devices as BR4
12-Dec-11 RMS Fixed Qbus interrupts to treat all IO devices as BR4
19-Nov-08 RMS Moved I/O support routines to I/O library
16-May-08 RMS Added multiple DC11 support
Renamed DL11 in autoconfigure

File diff suppressed because it is too large Load diff

View file

@ -850,14 +850,14 @@ MTAB rq_mod[] = {
#if defined (VM_PDP11)
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
&set_addr_flt, NULL, NULL },
#else
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,
NULL, &show_addr, NULL },
#endif
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
NULL, &show_vec, NULL },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
&set_addr_flt, NULL, NULL },
{ 0 }
};

View file

@ -130,7 +130,7 @@ t_stat rx_wr (int32 data, int32 PA, int32 access);
t_stat rx_svc (UNIT *uptr);
t_stat rx_reset (DEVICE *dptr);
t_stat rx_boot (int32 unitno, DEVICE *dptr);
void rx_done (int32 esr_flags, int32 new_ecode);
void rx_done (int esr_flags, int new_ecode);
/* RX11 data structures
@ -179,12 +179,19 @@ REG rx_reg[] = {
MTAB rx_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
#if defined (VM_PDP11)
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
&set_vec, &show_vec, NULL },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
&set_addr_flt, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
&set_vec, &show_vec, NULL },
#else
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
NULL, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
NULL, &show_vec, NULL },
#endif
{ 0 }
};

View file

@ -161,7 +161,7 @@ t_stat ry_wr (int32 data, int32 PA, int32 access);
t_stat ry_svc (UNIT *uptr);
t_stat ry_reset (DEVICE *dptr);
t_stat ry_boot (int32 unitno, DEVICE *dptr);
void ry_done (int32 esr_flags, int32 new_ecode);
void ry_done (int esr_flags, int new_ecode);
t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat ry_attach (UNIT *uptr, char *cptr);
@ -223,13 +223,18 @@ MTAB ry_mod[] = {
{ UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
{ (UNIT_AUTO+UNIT_DEN), 0, NULL, "SINGLE", &ry_set_size },
{ (UNIT_AUTO+UNIT_DEN), UNIT_DEN, NULL, "DOUBLE", &ry_set_size },
#if defined (VM_PDP11)
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
&set_vec, &show_vec, NULL },
#if defined (VM_PDP11)
{ MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
&set_addr_flt, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
&set_vec, &show_vec, NULL },
#else
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
NULL, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
NULL, &show_vec, NULL },
#endif
{ 0 }
};

View file

@ -27,6 +27,7 @@
23-Jan-12 MP Added missing support for Logical EOT detection while
positioning.
17-Aug-11 RMS Added CAPACITY modifier
05-Mar-11 MP Added missing state for proper save/restore
01-Mar-11 MP - Migrated complex physical tape activities to sim_tape
- adopted use of asynch I/O interfaces from sim_tape
@ -419,10 +420,10 @@ DIB tq_dib = {
};
UNIT tq_unit[] = {
{ UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP },
{ UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP },
{ UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP },
{ UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP },
{ UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) },
{ UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) },
{ UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) },
{ UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) },
{ UDATA (&tq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) },
{ UDATA (&tq_quesvc, UNIT_IDLE|UNIT_DIS, 0) }
};
@ -499,9 +500,13 @@ MTAB tq_mod[] = {
NULL, &tq_show_unitq, NULL },
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",
&sim_tape_set_capac, &sim_tape_show_capac, NULL },
#if defined (VM_PDP11)
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
&set_addr_flt, NULL, NULL },
#else
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,
NULL, &show_addr, NULL },

View file

@ -56,6 +56,11 @@ Bugs Found And Fixed During Simulator Debug
53. MTPR SBR/PCBB/SCBB: 11/780 only checks that bits<1:0> == 0.
54. MTPR xLR: 11/780 excludes bits<31:24> from mbz test.
55. MTPR PxBR: 11/780 only checks bits<31,1:0> == 1,00.
56. EMODx: integer overflow case requiring left shift returns wrong result.
57. BPT, XFC: not clearing PSL<tp> before taking exception.
58. POLYx: add step <does> require truncation (proved by AXE tests).

View file

@ -1,4 +1,4 @@
/* vax_syslist.c: VAX device list
/* vax780_syslist.c: VAX 780 device list
Copyright (c) 1998-2008, Robert M Supnik

View file

@ -35,6 +35,8 @@
approach taken in the other BSD derived OSes.
Determining a reasonable idle detection pattern does
not seem possible for these versions.
13-Sep-11 RMS Fixed XFC, BPT to clear PSL<tp> before exception
(found by Camiel Vanderhoeven)
23-Mar-11 RMS Revised for new idle design (from Mark Pizzolato)
05-Jan-11 MP Added Asynch I/O support
24-Apr-10 RMS Added OLDVMS idle timer option
@ -1585,7 +1587,7 @@ for ( ;; ) {
case TSTL:
CC_IIZZ_L (op0); /* set cc's */
if ((cc == CC_Z) &&
if ((cc == CC_Z) && /* zero result and */
((((cpu_idle_mask & VAX_IDLE_ULTOLD) && /* running Old Ultrix or friends? */
(PSL_GETIPL (PSL) == 0x1)) || /* at IPL 1? */
((cpu_idle_mask & VAX_IDLE_QUAD) && /* running Quasijarus or friends? */
@ -2553,12 +2555,14 @@ for ( ;; ) {
case BPT:
SETPC (fault_PC);
PSL = PSL & ~PSL_TP; /* clear <tp> */
cc = intexc (SCB_BPT, cc, 0, IE_EXC);
GET_CUR;
break;
case XFC:
SETPC (fault_PC);
PSL = PSL & ~PSL_TP; /* clear <tp> */
cc = intexc (SCB_XFC, cc, 0, IE_EXC);
GET_CUR;
break;

View file

@ -1,6 +1,6 @@
/* vax_cpu1.c: VAX complex instructions
Copyright (c) 1998-2011, Robert M Supnik
Copyright (c) 1998-2012, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
15-Mar-12 RMS Fixed potential integer overflow in LDPCTX (from Mark Pizzolato)
25-Nov-11 RMS Added VEC_QBUS test in interrupt handler
23-Mar-11 RMS Revised idle design (from Mark Pizzolato)
28-May-08 RMS Inlined physical memory routines
@ -1137,7 +1138,7 @@ else {
SP = KSP; /* new stack */
}
}
if (ei == IE_INT) { /* if int, new IPL */
if (ei > 0) { /* if int, new IPL */
int32 newipl;
if (VEC_QBUS && ((vec & VEC_Q) != 0)) /* Qbus and Qbus vector? */
newipl = PSL_IPL17; /* force IPL 17 */
@ -1274,7 +1275,7 @@ return newpsl & CC_MASK; /* set new cc */
void op_ldpctx (int32 acc)
{
int32 newpc, newpsl, pcbpa, t;
uint32 newpc, newpsl, pcbpa, t;
if (PSL & PSL_CUR) /* must be kernel */
RSVD_INST_FAULT;

View file

@ -1,6 +1,6 @@
/* vax_defs.h: VAX architecture definitions file
Copyright (c) 1998-2008, Robert M Supnik
Copyright (c) 1998-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,7 @@
The author gratefully acknowledges the help of Stephen Shirron, Antonio
Carlini, and Kevin Peterson in providing specifications for the Qbus VAX's
05-Nov-11 RMS Added PSL_IPL17 definition
09-May-06 RMS Added system PTE ACV error code
03-May-06 RMS Added EDITPC get/put cc's macros
03-Nov-05 RMS Added 780 stop codes

View file

@ -1,6 +1,6 @@
/* vax_fpa.c - VAX f_, d_, g_floating instructions
Copyright (c) 1998-2008, Robert M Supnik
Copyright (c) 1998-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,9 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
15-Sep-11 RMS Fixed integer overflow bug in EMODx
Fixed POLYx normalizing before add mask bug
(both from Camiel Vanderhoeven)
28-May-08 RMS Inlined physical memory routines
16-May-06 RMS Fixed bug in 32b floating multiply routine
Fixed bug in 64b extended modulus routine
@ -103,7 +106,7 @@ void unpackg (int32 hi, int32 lo, UFP *a);
void norm (UFP *a);
int32 rpackfd (UFP *a, int32 *rh);
int32 rpackg (UFP *a, int32 *rh);
void vax_fadd (UFP *a, UFP *b);
void vax_fadd (UFP *a, UFP *b, uint32 mhi, uint32 mlo);
void vax_fmul (UFP *a, UFP *b, t_bool qd, int32 bias, uint32 mhi, uint32 mlo);
void vax_fdiv (UFP *b, UFP *a, int32 prec, int32 bias);
void vax_fmod (UFP *a, int32 bias, int32 *intgr, int32 *flg);
@ -347,10 +350,11 @@ return rpackg (&a, flo); /* return frac */
/* Unpacked floating point routines */
void vax_fadd (UFP *a, UFP *b)
void vax_fadd (UFP *a, UFP *b, uint32 mhi, uint32 mlo)
{
int32 ediff;
UFP t;
t_uint64 mask = (((t_uint64) mhi) << 32) | ((t_uint64) mlo);
if (a->frac == 0) { /* s1 = 0? */
*a = *b;
@ -374,6 +378,7 @@ if (a->sign ^ b->sign) { /* eff sub? */
a->frac = a->frac + b->frac; /* add frac */
}
else a->frac = a->frac - b->frac; /* sub frac */
a->frac = a->frac & ~mask; /* mask before norm */
norm (a); /* normalize */
}
else {
@ -386,6 +391,7 @@ else {
a->frac = UF_NM | (a->frac >> 1); /* shift in carry */
a->exp = a->exp + 1; /* skip norm */
}
a->frac = a->frac & ~mask; /* mask */
}
return;
}
@ -454,7 +460,11 @@ else if (a->exp <= (bias + 64)) { /* in range [1,64]? */
a->exp = bias;
}
else {
*intgr = 0; /* out of range */
if (a->exp < (bias + 96)) /* need left shift? */
*intgr = (int32) (a->frac << (a->exp - bias - 64));
else *intgr = 0; /* out of range */
if (a->sign)
*intgr = -*intgr;
a->frac = a->sign = a->exp = 0; /* result 0 */
*flg = CC_V; /* overflow */
}
@ -639,7 +649,7 @@ void unpackg (uint32 hi, uint32 lo, UFP *a);
void norm (UFP *a);
int32 rpackfd (UFP *a, int32 *rh);
int32 rpackg (UFP *a, int32 *rh);
void vax_fadd (UFP *a, UFP *b);
void vax_fadd (UFP *a, UFP *b, uint32 mhi, uint32 mlo);
void vax_fmul (UFP *a, UFP *b, t_bool qd, int32 bias, uint32 mhi, uint32 mlo);
void vax_fmod (UFP *a, int32 bias, int32 *intgr, int32 *flg);
void vax_fdiv (UFP *b, UFP *a, int32 prec, int32 bias);
@ -921,6 +931,8 @@ if (a->sign ^ b->sign) { /* eff sub? */
dp_add (&a->frac, &b->frac); /* "add" frac */
}
else dp_sub (&a->frac, &b->frac); /* a >= b */
a->frac.hi = a->frac.hi & ~mhi; /* mask before norm */
a->frac.lo = a->frac.lo & ~mlo;
norm (a); /* normalize */
}
else {
@ -932,6 +944,8 @@ else {
a->frac.hi = a->frac.hi | UF_NM_H; /* add norm bit */
a->exp = a->exp + 1; /* skip norm */
}
a->frac.hi = a->frac.hi & ~mhi; /* mask */
a->frac.lo = a->frac.lo & ~mlo;
}
return;
}
@ -1004,7 +1018,14 @@ else if (a->exp <= (bias + 64)) { /* in range [1,64]? */
a->exp = bias;
}
else {
*intgr = 0; /* out of range */
if (a->exp < (bias + 96)) { /* need left shift? */
ifr = a->frac;
dp_lsh (&ifr, a->exp - bias - 64);
*intgr = ifr.lo;
}
else *intgr = 0; /* out of range */
if (a->sign)
*intgr = -*intgr;
a->frac.hi = a->frac.lo = a->sign = a->exp = 0; /* result 0 */
*flg = CC_V; /* overflow */
}
@ -1379,7 +1400,7 @@ unpackf (opnd[0], &a); /* F format */
unpackf (opnd[1], &b);
if (sub) /* sub? -s1 */
a.sign = a.sign ^ FPSIGN;
vax_fadd (&a, &b); /* add fractions */
vax_fadd (&a, &b, 0, 0); /* add fractions */
return rpackfd (&a, NULL);
}
@ -1391,7 +1412,7 @@ unpackd (opnd[0], opnd[1], &a);
unpackd (opnd[2], opnd[3], &b);
if (sub) /* sub? -s1 */
a.sign = a.sign ^ FPSIGN;
vax_fadd (&a, &b); /* add fractions */
vax_fadd (&a, &b, 0, 0); /* add fractions */
return rpackfd (&a, rh);
}
@ -1403,7 +1424,7 @@ unpackg (opnd[0], opnd[1], &a);
unpackg (opnd[2], opnd[3], &b);
if (sub) /* sub? -s1 */
a.sign = a.sign ^ FPSIGN;
vax_fadd (&a, &b); /* add fractions */
vax_fadd (&a, &b, 0, 0); /* add fractions */
return rpackg (&a, rh); /* round and pack */
}
@ -1499,7 +1520,7 @@ for (i = 0; i < deg; i++) { /* loop */
wd = Read (ptr, L_LONG, RD); /* get Cnext */
ptr = ptr + 4;
unpackf (wd, &c); /* unpack Cnext */
vax_fadd (&r, &c); /* r = r + Cnext */
vax_fadd (&r, &c, 1, LMASK); /* r = r + Cnext */
res = rpackfd (&r, NULL); /* round and pack */
}
R[0] = res;
@ -1530,7 +1551,7 @@ for (i = 0; i < deg; i++) { /* loop */
wd1 = Read (ptr + 4, L_LONG, RD);
ptr = ptr + 8;
unpackd (wd, wd1, &c); /* unpack Cnext */
vax_fadd (&r, &c); /* r = r + Cnext */
vax_fadd (&r, &c, 0, 1); /* r = r + Cnext */
res = rpackfd (&r, &resh); /* round and pack */
}
R[0] = res;
@ -1564,7 +1585,7 @@ for (i = 0; i < deg; i++) { /* loop */
wd1 = Read (ptr + 4, L_LONG, RD);
ptr = ptr + 8;
unpackg (wd, wd1, &c); /* unpack Cnext */
vax_fadd (&r, &c); /* r = r + Cnext */
vax_fadd (&r, &c, 0, 1); /* r = r + Cnext */
res = rpackg (&r, &resh); /* round and pack */
}
R[0] = res;

View file

@ -1,6 +1,6 @@
/* vax_octa.c - VAX octaword and h_floating instructions
Copyright (c) 2004-2008, Robert M Supnik
Copyright (c) 2004-2011, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,9 @@
This module simulates the VAX h_floating instruction set.
15-Sep-11 RMS Fixed integer overflow bug in EMODH
Fixed POLYH normalizing before add mask bug
(both from Camiel Vanderhoeven)
28-May-08 RMS Inlined physical memory routines
10-May-06 RMS Fixed bug in reported VA on faulting cross-page write
03-May-06 RMS Fixed MNEGH to test negated sign, clear C
@ -93,7 +96,7 @@ void h_write_w (int32 spec, int32 va, int32 val, int32 acc);
void h_write_l (int32 spec, int32 va, int32 val, int32 acc);
void h_write_q (int32 spec, int32 va, int32 vl, int32 vh, int32 acc);
void h_write_o (int32 spec, int32 va, int32 *val, int32 acc);
void vax_hadd (UFPH *a, UFPH *b);
void vax_hadd (UFPH *a, UFPH *b, uint32 mlo);
void vax_hmul (UFPH *a, UFPH *b, uint32 mlo);
void vax_hmod (UFPH *a, int32 *intgr, int32 *flg);
void vax_hdiv (UFPH *a, UFPH *b);
@ -581,7 +584,7 @@ h_unpackh (&opnd[0], &a); /* unpack s1, s2 */
h_unpackh (&opnd[4], &b);
if (sub) /* sub? -s1 */
a.sign = a.sign ^ FPSIGN;
vax_hadd (&a, &b); /* do add */
vax_hadd (&a, &b, 0); /* do add */
return h_rpackh (&a, hflt); /* round and pack */
}
@ -643,7 +646,7 @@ for (i = 0; i < deg; i++) { /* loop */
wd[3] = Read (ptr + 12, L_LONG, RD);
ptr = ptr + 16;
h_unpackh (wd, &c); /* unpack Cnext */
vax_hadd (&r, &c); /* r = r + Cnext */
vax_hadd (&r, &c, 1); /* r = r + Cnext */
h_rpackh (&r, res); /* round and pack */
}
R[0] = res[0]; /* result */
@ -678,7 +681,7 @@ return h_rpackh (&a, hflt); /* round and pack frac *
/* Floating add */
void vax_hadd (UFPH *a, UFPH *b)
void vax_hadd (UFPH *a, UFPH *b, uint32 mlo)
{
int32 ediff;
UFPH t;
@ -703,6 +706,7 @@ if (a->sign ^ b->sign) { /* eff sub? */
if (ediff) /* denormalize */
qp_rsh_s (&b->frac, ediff, 1);
qp_add (&a->frac, &b->frac); /* "add" frac */
a->frac.f0 = a->frac.f0 & ~mlo; /* mask before norm */
h_normh (a); /* normalize */
}
else {
@ -713,6 +717,7 @@ else {
a->frac.f3 = a->frac.f3 | UH_NM_H; /* add norm bit */
a->exp = a->exp + 1; /* incr exp */
}
a->frac.f0 = a->frac.f0 & ~mlo; /* mask */
}
return;
}
@ -778,7 +783,14 @@ else if (a->exp <= (H_BIAS + 128)) { /* in range? */
a->exp = H_BIAS;
}
else {
*intgr = 0; /* out of range */
if (a->exp < (H_BIAS + 160)) { /* left shift needed? */
ifr = a->frac;
qp_lsh (&ifr, a->exp - H_BIAS - 128);
*intgr = ifr.f0;
}
else *intgr = 0; /* out of range */
if (a->sign)
*intgr = -*intgr;
a->frac.f0 = a->frac.f1 = 0; /* result 0 */
a->frac.f2 = a->frac.f3 = 0;
a->sign = a->exp = 0;

View file

@ -1,4 +1,4 @@
/* vax_sys.c: VAX simulator interface
/* vax_syslist.c: VAX device list
Copyright (c) 1998-2008, Robert M Supnik

View file

@ -237,10 +237,6 @@
RelativePath="..\AltairZ80\i86_prim_ops.c"
>
</File>
<File
RelativePath="..\AltairZ80\insnsa.c"
>
</File>
<File
RelativePath="..\AltairZ80\insnsd.c"
>

View file

@ -0,0 +1,49 @@
/* alpha_500au_syslist.c: Alpha device list for 500au
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include "alpha_defs.h"
extern DEVICE cpu_dev;
extern DEVICE tlb_dev;
extern DEVICE ev5pal_dev;
extern DEVICE rom_dev;
/* SCP data structures and interface routines
sim_name simulator name
sim_devices array of pointers to simulated devices
*/
char sim_name[] = "Alpha";
DEVICE *sim_devices[] = {
&cpu_dev,
&tlb_dev,
&ev5pal_dev,
&rom_dev,
NULL
};

1865
alpha/alpha_cpu.c Normal file

File diff suppressed because it is too large Load diff

457
alpha/alpha_defs.h Normal file
View file

@ -0,0 +1,457 @@
/* alpha_defs.h: Alpha architecture definitions file
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
Respectfully dedicated to the great people of the Alpha chip, systems, and
software development projects; and to the memory of Peter Conklin, of the
Alpha Program Office.
*/
#ifndef _ALPHA_DEFS_H_
#define _ALPHA_DEFS_H_ 0
#include "sim_defs.h"
#include <setjmp.h>
#if defined (__GNUC__)
#define INLINE inline
#else
#define INLINE
#endif
/* Configuration */
#define INITMEMSIZE (1 << 24) /* !!debug!! */
#define MEMSIZE (cpu_unit.capac)
#define ADDR_IS_MEM(x) ((x) < MEMSIZE)
#define DEV_DIB (1u << (DEV_V_UF + 0)) /* takes a DIB */
/* Simulator stops */
#define STOP_HALT 1 /* halt */
#define STOP_IBKPT 2 /* breakpoint */
#define STOP_NSPAL 3 /* non-supported PAL */
#define STOP_KSNV 4 /* kernel stk inval */
#define STOP_INVABO 5 /* invalid abort code */
#define STOP_MME 6 /* console mem mgt error */
/* Bit patterns */
#define M8 0xFF
#define M16 0xFFFF
#define M32 0xFFFFFFFF
#define M64 0xFFFFFFFFFFFFFFFF
#define B_SIGN 0x80
#define W_SIGN 0x8000
#define L_SIGN 0x80000000
#define Q_SIGN 0x8000000000000000
#define Q_GETSIGN(x) (((uint32) ((x) >> 63)) & 1)
/* Architectural variants */
#define AMASK_BWX 0x0001 /* byte/word */
#define AMASK_FIX 0x0002 /* sqrt/flt-int moves */
#define AMASK_CIX 0x0004 /* counts */
#define AMASK_MVI 0x0100 /* multimedia */
#define AMASK_PRC 0x0200 /* precise exceptions */
#define AMASK_PFM 0x1000 /* prefetch w modify */
#define IMPLV_EV4 0x0 /* EV4 (21064) */
#define IMPLV_EV5 0x1 /* EV5 (21164) */
#define IMPLV_EV6 0x2 /* EV6 (21264) */
#define IMPLV_EV7 0x3 /* EV7 (21364) */
/* Instruction formats */
#define I_V_OP 26 /* opcode */
#define I_M_OP 0x3F
#define I_OP (I_M_OP << I_V_OP)
#define I_V_RA 21 /* Ra */
#define I_M_RA 0x1F
#define I_V_RB 16 /* Rb */
#define I_M_RB 0x1F
#define I_V_FTRP 13 /* floating trap mode */
#define I_M_FTRP 0x7
#define I_FTRP (I_M_FTRP << I_V_FTRP)
#define I_F_VAXRSV 0x4800 /* VAX reserved */
#define I_FTRP_V 0x2000 /* /V trap */
#define I_FTRP_U 0x2000 /* /U trap */
#define I_FTRP_S 0x8000 /* /S trap */
#define I_FTRP_SUI 0xE000 /* /SUI trap */
#define I_FTRP_SVI 0xE000 /* /SVI trap */
#define I_V_FRND 11 /* floating round mode */
#define I_M_FRND 0x3
#define I_FRND (I_M_FRND << I_V_FRND)
#define I_FRND_C 0 /* chopped */
#define I_FRND_M 1 /* to minus inf */
#define I_FRND_N 2 /* normal */
#define I_FRND_D 3 /* dynamic */
#define I_FRND_P 3 /* in FPCR: plus inf */
#define I_V_FSRC 9 /* floating source */
#define I_M_FSRC 0x3
#define I_FSRC (I_M_FSRC << I_V_FSRC)
#define I_FSRC_X 0x0200 /* data type X */
#define I_V_FFNC 5 /* floating function */
#define I_M_FFNC 0x3F
#define I_V_LIT8 13 /* integer 8b literal */
#define I_M_LIT8 0xFF
#define I_V_ILIT 12 /* literal flag */
#define I_ILIT (1u << I_V_ILIT)
#define I_V_IFNC 5 /* integer function */
#define I_M_IFNC 0x3F
#define I_V_RC 0 /* Rc */
#define I_M_RC 0x1F
#define I_V_MDSP 0 /* memory displacement */
#define I_M_MDSP 0xFFFF
#define I_V_BDSP 0
#define I_M_BDSP 0x1FFFFF /* branch displacement */
#define I_V_PALOP 0
#define I_M_PALOP 0x3FFFFFF /* PAL subopcode */
#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP)
#define I_GETRA(x) (((x) >> I_V_RA) & I_M_RA)
#define I_GETRB(x) (((x) >> I_V_RB) & I_M_RB)
#define I_GETLIT8(x) (((x) >> I_V_LIT8) & I_M_LIT8)
#define I_GETIFNC(x) (((x) >> I_V_IFNC) & I_M_IFNC)
#define I_GETFRND(x) (((x) >> I_V_FRND) & I_M_FRND)
#define I_GETFFNC(x) (((x) >> I_V_FFNC) & I_M_FFNC)
#define I_GETRC(x) (((x) >> I_V_RC) & I_M_RC)
#define I_GETMDSP(x) (((x) >> I_V_MDSP) & I_M_MDSP)
#define I_GETBDSP(x) (((x) >> I_V_BDSP) & I_M_BDSP)
#define I_GETPAL(x) (((x) >> I_V_PALOP) & I_M_PALOP)
/* Floating point types */
#define DT_F 0 /* type F */
#define DT_G 1 /* type G */
#define DT_S 0 /* type S */
#define DT_T 1 /* type T */
/* Floating point memory format (VAX F) */
#define F_V_SIGN 15
#define F_SIGN (1u << F_V_SIGN)
#define F_V_EXP 7
#define F_M_EXP 0xFF
#define F_BIAS 0x80
#define F_EXP (F_M_EXP << F_V_EXP)
#define F_V_FRAC 29
#define F_GETEXP(x) ((uint32) (((x) >> F_V_EXP) & F_M_EXP))
#define SWAP_VAXF(x) ((((x) >> 16) & 0xFFFF) | (((x) & 0xFFFF) << 16))
/* Floating point memory format (VAX G) */
#define G_V_SIGN 15
#define G_SIGN (1u << F_V_SIGN)
#define G_V_EXP 4
#define G_M_EXP 0x7FF
#define G_BIAS 0x400
#define G_EXP (G_M_EXP << G_V_EXP)
#define G_GETEXP(x) ((uint32) (((x) >> G_V_EXP) & G_M_EXP))
#define SWAP_VAXG(x) ((((x) & 0x000000000000FFFF) << 48) | \
(((x) & 0x00000000FFFF0000) << 16) | \
(((x) >> 16) & 0x00000000FFFF0000) | \
(((x) >> 48) & 0x000000000000FFFF))
/* Floating memory format (IEEE S) */
#define S_V_SIGN 31
#define S_SIGN (1u << S_V_SIGN)
#define S_V_EXP 23
#define S_M_EXP 0xFF
#define S_BIAS 0x7F
#define S_NAN 0xFF
#define S_EXP (S_M_EXP << S_V_EXP)
#define S_V_FRAC 29
#define S_GETEXP(x) ((uint32) (((x) >> S_V_EXP) & S_M_EXP))
/* Floating point memory format (IEEE T) */
#define T_V_SIGN 63
#define T_SIGN 0x8000000000000000
#define T_V_EXP 52
#define T_M_EXP 0x7FF
#define T_BIAS 0x3FF
#define T_NAN 0x7FF
#define T_EXP 0x7FF0000000000000
#define T_FRAC 0x000FFFFFFFFFFFFF
#define T_GETEXP(x) ((uint32) (((uint32) ((x) >> T_V_EXP)) & T_M_EXP))
/* Floating point register format (all except VAX D) */
#define FPR_V_SIGN 63
#define FPR_SIGN 0x8000000000000000
#define FPR_V_EXP 52
#define FPR_M_EXP 0x7FF
#define FPR_NAN 0x7FF
#define FPR_EXP 0x7FF0000000000000
#define FPR_HB 0x0010000000000000
#define FPR_FRAC 0x000FFFFFFFFFFFFF
#define FPR_GUARD (UF_V_NM - FPR_V_EXP)
#define FPR_GETSIGN(x) (((uint32) ((x) >> FPR_V_SIGN)) & 1)
#define FPR_GETEXP(x) (((uint32) ((x) >> FPR_V_EXP)) & FPR_M_EXP)
#define FPR_GETFRAC(x) ((x) & FPR_FRAC)
#define FP_TRUE 0x4000000000000000 /* 0.5/2.0 in reg */
/* Floating point register format (VAX D) */
#define FDR_V_SIGN 63
#define FDR_SIGN 0x8000000000000000
#define FDR_V_EXP 55
#define FDR_M_EXP 0xFF
#define FDR_EXP 0x7F80000000000000
#define FDR_HB 0x0080000000000000
#define FDR_FRAC 0x007FFFFFFFFFFFFF
#define FDR_GUARD (UF_V_NM - FDR_V_EXP)
#define FDR_GETSIGN(x) (((uint32) ((x) >> FDR_V_SIGN)) & 1)
#define FDR_GETEXP(x) (((uint32) ((x) >> FDR_V_EXP)) & FDR_M_EXP)
#define FDR_GETFRAC(x) ((x) & FDR_FRAC)
#define D_BIAS 0x80
/* Unpacked floating point number */
typedef struct {
uint32 sign;
int32 exp;
t_uint64 frac;
} UFP;
#define UF_V_NM 63
#define UF_NM 0x8000000000000000 /* normalized */
/* IEEE control register (left 32b only) */
#define FPCR_SUM 0x80000000 /* summary */
#define FPCR_INED 0x40000000 /* inexact disable */
#define FPCR_UNFD 0x20000000 /* underflow disable */
#define FPCR_UNDZ 0x10000000 /* underflow to 0 */
#define FPCR_V_RMOD 26 /* rounding mode */
#define FPCR_M_RMOD 0x3
#define FPCR_IOV 0x02000000 /* integer overflow */
#define FPCR_INE 0x01000000 /* inexact */
#define FPCR_UNF 0x00800000 /* underflow */
#define FPCR_OVF 0x00400000 /* overflow */
#define FPCR_DZE 0x00200000 /* div by zero */
#define FPCR_INV 0x00100000 /* invalid operation */
#define FPCR_OVFD 0x00080000 /* overflow disable */
#define FPCR_DZED 0x00040000 /* div by zero disable */
#define FPCR_INVD 0x00020000 /* invalid op disable */
#define FPCR_DNZ 0x00010000 /* denormal to zero */
#define FPCR_DNOD 0x00008000 /* denormal disable */
#define FPCR_RAZ 0x00007FFF /* zero */
#define FPCR_ERR (FPCR_IOV|FPCR_INE|FPCR_UNF|FPCR_OVF|FPCR_DZE|FPCR_INV)
#define FPCR_GETFRND(x) (((x) >> FPCR_V_RMOD) & FPCR_M_RMOD)
/* PTE - hardware format */
#define PTE_V_PFN 32 /* PFN */
#define PFN_MASK 0xFFFFFFFF
#define PTE_V_UWE 15 /* write enables */
#define PTE_V_SWE 14
#define PTE_V_EWE 13
#define PTE_V_KWE 12
#define PTE_V_URE 11 /* read enables */
#define PTE_V_SRE 10
#define PTE_V_ERE 9
#define PTE_V_KRE 8
#define PTE_V_GH 5 /* granularity hint */
#define PTE_M_GH 0x3
#define PTE_GH (PTE_M_GH << PTE_V_GH)
#define PTE_V_ASM 4 /* address space match */
#define PTE_V_FOE 3 /* fault on execute */
#define PTE_V_FOW 2 /* fault on write */
#define PTE_V_FOR 1 /* fault on read */
#define PTE_V_V 0 /* valid */
#define PTE_UWE (1u << PTE_V_UWE)
#define PTE_SWE (1u << PTE_V_SWE)
#define PTE_EWE (1u << PTE_V_EWE)
#define PTE_KWE (1u << PTE_V_KWE)
#define PTE_URE (1u << PTE_V_URE)
#define PTE_SRE (1u << PTE_V_SRE)
#define PTE_ERE (1u << PTE_V_ERE)
#define PTE_KRE (1u << PTE_V_KRE)
#define PTE_ASM (1u << PTE_V_ASM)
#define PTE_FOE (1u << PTE_V_FOE)
#define PTE_FOW (1u << PTE_V_FOW)
#define PTE_FOR (1u << PTE_V_FOR)
#define PTE_V (1u << PTE_V_V)
#define PTE_MASK 0xFF7F
#define PTE_GETGH(x) ((((uint32) (x)) >> PTE_V_GH) & PTE_M_GH)
#define VPN_GETLVL1(x) (((x) >> ((2 * VA_N_LVL) - 3)) & (VA_M_LVL << 3))
#define VPN_GETLVL2(x) (((x) >> (VA_N_LVL - 3)) & (VA_M_LVL << 3))
#define VPN_GETLVL3(x) (((x) << 3) & (VA_M_LVL << 3))
#define ACC_E(m) ((PTE_KRE << (m)) | PTE_FOE | PTE_V)
#define ACC_R(m) ((PTE_KRE << (m)) | PTE_FOR | PTE_V)
#define ACC_W(m) ((PTE_KWE << (m)) | PTE_FOW | PTE_V)
#define ACC_M(m) (((PTE_KRE|PTE_KWE) << (m)) | PTE_FOR | PTE_FOW | PTE_V)
/* Exceptions */
#define ABORT(x) longjmp (save_env, (x))
#define ABORT1(x,y) { p1 = (x); longjmp (save_env, (y)); }
#define EXC_RSVI 0x01 /* reserved instruction */
#define EXC_RSVO 0x02 /* reserved operand */
#define EXC_ALIGN 0x03 /* operand alignment */
#define EXC_FPDIS 0x04 /* flt point disabled */
#define EXC_TBM 0x08 /* TLB miss */
#define EXC_FOX 0x10 /* fault on r/w/e */
#define EXC_ACV 0x14 /* access control viol */
#define EXC_TNV 0x18 /* translation not valid */
#define EXC_BVA 0x1C /* bad address format */
#define EXC_E 0x00 /* offset for execute */
#define EXC_R 0x01 /* offset for read */
#define EXC_W 0x02 /* offset for write */
/* Traps - corresponds to arithmetic trap summary register */
#define TRAP_SWC 0x001 /* software completion */
#define TRAP_INV 0x002 /* invalid operand */
#define TRAP_DZE 0x004 /* divide by zero */
#define TRAP_OVF 0x008 /* overflow */
#define TRAP_UNF 0x010 /* underflow */
#define TRAP_INE 0x020 /* inexact */
#define TRAP_IOV 0x040 /* integer overflow */
#define TRAP_SUMM_RW 0x07F
/* PALcode */
#define SP R[30] /* stack pointer */
#define MODE_K 0 /* kernel */
#define MODE_E 1 /* executive (UNIX user) */
#define MODE_S 2 /* supervisor */
#define MODE_U 3 /* user */
#define PAL_UNDF 0 /* undefined */
#define PAL_VMS 1 /* VMS */
#define PAL_UNIX 2 /* UNIX */
#define PAL_NT 3 /* Windows NT */
/* Machine check error summary register */
#define MCES_INP 0x01 /* in progress */
#define MCES_SCRD 0x02 /* sys corr in prog */
#define MCES_PCRD 0x04 /* proc corr in prog */
#define MCES_DSCRD 0x08 /* disable system corr */
#define MCES_DPCRD 0x10 /* disable proc corr */
#define MCES_W1C (MCES_INP|MCES_SCRD|MCES_PCRD)
#define MCES_DIS (MCES_DSCRD|MCES_DPCRD)
/* I/O devices */
#define L_BYTE 0 /* IO request lengths */
#define L_WORD 1
#define L_LONG 2
#define L_QUAD 3
/* Device information block */
typedef struct { /* device info block */
t_uint64 low; /* low addr */
t_uint64 high; /* high addr */
t_bool (*read)(t_uint64 pa, t_uint64 *val, uint32 lnt);
t_bool (*write)(t_uint64 pa, t_uint64 val, uint32 lnt);
uint32 ipl;
} DIB;
/* Interrupt system - 6 levels in EV4 and EV6, 4 in EV5 - software expects 4 */
#define IPL_HMAX 0x17 /* highest hwre level */
#define IPL_HMIN 0x14 /* lowest hwre level */
#define IPL_HLVL (IPL_HMAX - IPL_HMIN + 1) /* # hardware levels */
#define IPL_SMAX 0x0F /* highest swre level */
/* Macros */
#define PCQ_SIZE 64 /* must be 2**n */
#define PCQ_MASK (PCQ_SIZE - 1)
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = (PC - 4) & M64
#define SEXT_B_Q(x) (((x) & B_SIGN)? ((x) | ~((t_uint64) M8)): ((x) & M8))
#define SEXT_W_Q(x) (((x) & W_SIGN)? ((x) | ~((t_uint64) M16)): ((x) & M16))
#define SEXT_L_Q(x) (((x) & L_SIGN)? ((x) | ~((t_uint64) M32)): ((x) & M32))
#define NEG_Q(x) ((~(x) + 1) & M64)
#define ABS_Q(x) (((x) & Q_SIGN)? NEG_Q (x): (x))
#define SIGN_BDSP 0x100000
#define SIGN_MDSP 0x008000
#define SEXT_MDSP(x) (((x) & SIGN_MDSP)? \
((x) | ~((t_uint64) I_M_MDSP)): ((x) & I_M_MDSP))
#define SEXT_BDSP(x) (((x) & SIGN_BDSP)? \
((x) | ~((t_uint64) I_M_BDSP)): ((x) & I_M_BDSP))
/* Opcodes */
enum opcodes {
OP_PAL, OP_OPC01, OP_OPC02, OP_OPC03,
OP_OPC04, OP_OPC05, OP_OPC06, OP_OPC07,
OP_LDA, OP_LDAH, OP_LDBU, OP_LDQ_U,
OP_LDWU, OP_STW, OP_STB, OP_STQ_U,
OP_IALU, OP_ILOG, OP_ISHFT, OP_IMUL,
OP_IFLT, OP_VAX, OP_IEEE, OP_FP,
OP_MISC, OP_PAL19, OP_JMP, OP_PAL1B,
OP_FLTI, OP_PAL1D, OP_PAL1E, OP_PAL1F,
OP_LDF, OP_LDG, OP_LDS, OP_LDT,
OP_STF, OP_STG, OP_STS, OP_STT,
OP_LDL, OP_LDQ, OP_LDL_L, OP_LDQ_L,
OP_STL, OP_STQ, OP_STL_C, OP_STQ_C,
OP_BR, OP_FBEQ, OP_FBLT, OP_FBLE,
OP_BSR, OP_FBNE, OP_FBGE, OP_FBGT,
OP_BLBC, OP_BEQ, OP_BLT, OP_BLE,
OP_BLBS, OP_BNE, OP_BGE, OP_BGT
};
/* Function prototypes */
uint32 ReadI (t_uint64 va);
t_uint64 ReadB (t_uint64 va);
t_uint64 ReadW (t_uint64 va);
t_uint64 ReadL (t_uint64 va);
t_uint64 ReadQ (t_uint64 va);
t_uint64 ReadAccL (t_uint64 va, uint32 acc);
t_uint64 ReadAccQ (t_uint64 va, uint32 acc);
INLINE t_uint64 ReadPB (t_uint64 pa);
INLINE t_uint64 ReadPW (t_uint64 pa);
INLINE t_uint64 ReadPL (t_uint64 pa);
INLINE t_uint64 ReadPQ (t_uint64 pa);
t_bool ReadIO (t_uint64 pa, t_uint64 *val, uint32 lnt);
void WriteB (t_uint64 va, t_uint64 dat);
void WriteW (t_uint64 va, t_uint64 dat);
void WriteL (t_uint64 va, t_uint64 dat);
void WriteQ (t_uint64 va, t_uint64 dat);
void WriteAccL (t_uint64 va, t_uint64 dat, uint32 acc);
void WriteAccQ (t_uint64 va, t_uint64 dat, uint32 acc);
INLINE void WritePB (t_uint64 pa, t_uint64 dat);
INLINE void WritePW (t_uint64 pa, t_uint64 dat);
INLINE void WritePL (t_uint64 pa, t_uint64 dat);
INLINE void WritePQ (t_uint64 pa, t_uint64 dat);
t_bool WriteIO (t_uint64 pa, t_uint64 val, uint32 lnt);
uint32 mmu_set_cm (uint32 mode);
void mmu_set_icm (uint32 mode);
void mmu_set_dcm (uint32 mode);
void arith_trap (uint32 trap, uint32 ir);
#endif

143
alpha/alpha_ev5_cons.c Normal file
View file

@ -0,0 +1,143 @@
/* alpha_ev5_cons.c - Alpha console support routines for EV5
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include "alpha_defs.h"
#include "alpha_ev5_defs.h"
t_uint64 srm_ptbr = 1;
extern uint32 dtlb_spage;
extern uint32 pal_type;
extern uint32 ev5_mcsr;
extern t_uint64 *M;
extern t_uint64 ev5_mvptbr;
extern UNIT cpu_unit;
/* Local quadword physical read - <no> exceptions or IO space lookups */
t_stat l_ReadPQ (t_uint64 pa, t_uint64 *dat)
{
if (ADDR_IS_MEM (pa)) {
*dat = M[pa >> 3];
return TRUE;
}
return FALSE;
}
/* "SRM" 3-level pte lookup
Inputs:
va = virtual address
*pte = pointer to pte to be returned
Output:
status = 0 for successful fill
EXC_ACV for ACV on intermediate level
EXC_TNV for TNV on intermediate level
*/
uint32 cons_find_pte_srm (t_uint64 va, t_uint64 *l3pte)
{
t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte;
uint32 vpte_vpn;
TLBENT *vpte_p;
vptea = FMT_MVA_VMS (va); /* try virt lookup */
vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */
vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */
if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V)))
l3ptea = PHYS_ADDR (vpte_p->pfn, vptea);
else {
uint32 vpn = VA_GETVPN (va);
if (srm_ptbr & 1) return 1; /* uninitialized? */
l1ptea = srm_ptbr + VPN_GETLVL1 (vpn);
if (!l_ReadPQ (l1ptea, &l1pte)) return 1;
if ((l1pte & PTE_V) == 0)
return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV);
l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF);
l2ptea = l2ptea + VPN_GETLVL2 (vpn);
if (!l_ReadPQ (l2ptea, &l2pte)) return 1;
if ((l2pte & PTE_V) == 0)
return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV);
l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF);
l3ptea = l3ptea + VPN_GETLVL3 (vpn);
}
if (!l_ReadPQ (l3ptea, l3pte)) return 1;
return 0;
}
/* NT 2-level pte lookup
Inputs:
va = virtual address
*pte = pointer to pte to be returned
Output:
status = 0 for successful fill
EXC_ACV for ACV on intermediate level
EXC_TNV for TNV on intermediate level
*/
uint32 cons_find_pte_nt (t_uint64 va, t_uint64 *l3pte)
{
t_uint64 vptea, l3ptea;
uint32 vpte_vpn;
TLBENT *vpte_p;
vptea = FMT_MVA_NT (va); /* try virt lookup */
vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */
vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */
if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V)))
l3ptea = PHYS_ADDR (vpte_p->pfn, vptea);
else {
return 1; /* for now */
}
if (!l_ReadPQ (l3ptea, l3pte)) return 1;
return 0;
}
/* Translate address for console access */
t_uint64 trans_c (t_uint64 va)
{
uint32 va_sext = VA_GETSEXT (va);
uint32 vpn = VA_GETVPN (va);
TLBENT *tlbp;
t_uint64 pte64;
uint32 exc, pfn;
if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */
return M64;
if ((dtlb_spage & SPEN_43) && (VPN_GETSP43 (vpn) == 2))
return (va & SP43_MASK); /* 43b superpage? */
if ((dtlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE))
return (va & SP32_MASK); /* 32b superpage? */
if (tlbp = dtlb_lookup (vpn)) /* try TLB */
return PHYS_ADDR (tlbp->pfn, va); /* found it */
if (ev5_mcsr & MCSR_NT) exc = cons_find_pte_nt (va, &pte64);
else exc = cons_find_pte_srm (va, &pte64);
if (exc || ((pte64 & PTE_V) == 0)) return M64; /* check valid */
pfn = (uint32) (pte64 >> 32) & M32;
return PHYS_ADDR (pfn, va); /* return phys addr */
}

428
alpha/alpha_ev5_defs.h Normal file
View file

@ -0,0 +1,428 @@
/* alpha_ev5_defs.h: Alpha EV5 chip definitions file
Copyright (c) 2003-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
Respectfully dedicated to the great people of the Alpha chip, systems, and
software development projects; and to the memory of Peter Conklin, of the
Alpha Program Office.
*/
#ifndef _ALPHA_EV5_DEFS_H_
#define _ALPHA_EV5_DEFS_H_ 0
/* Address limits */
#define VA_SIZE 43 /* VA size */
#define NTVA_WIDTH 32 /* VA width for NT */
#define VA_MASK 0x000007FFFFFFFFFF
#define EV5_PA_SIZE 40 /* PA size */
#define EV5_PA_MASK 0x000000FFFFFFFFFF
/* Virtual address */
#define VA_N_OFF 13 /* offset size */
#define VA_PAGSIZE (1u << VA_N_OFF) /* page size */
#define VA_M_OFF ((1u << VA_N_OFF) - 1) /* offset mask */
#define VA_N_LVL 10 /* width per level */
#define VA_M_LVL ((1u << VA_N_LVL) - 1) /* level mask */
#define VA_V_VPN VA_N_OFF /* vpn start */
#define VA_N_VPN (VA_N_LVL * 3) /* vpn size */
#define VA_M_VPN ((1u << VA_N_VPN) - 1) /* vpn mask */
#define VA_WIDTH (VA_N_VPN + VA_N_OFF) /* total VA size */
#define VA_V_SEXT (VA_WIDTH - 1) /* sext start */
#define VA_M_SEXT ((1u << (64 - VA_V_SEXT)) - 1) /* sext mask */
#define VA_GETOFF(x) (((uint32) (x)) & VA_M_OFF)
#define VA_GETVPN(x) (((uint32) ((x) >> VA_V_VPN)) & VA_M_VPN)
#define VA_GETSEXT(x) (((uint32) ((x) >> VA_V_SEXT)) & VA_M_SEXT)
#define PHYS_ADDR(p,v) ((((t_uint64) (p)) < VA_N_OFF) | VA_GETOFF (v))
/* 43b and 32b superpages - present in all implementations */
#define SPEN_43 0x2
#define SPEN_32 0x1
#define SP43_MASK 0x000001FFFFFFFFFF
#define SP32_MASK 0x000000003FFFFFFF
#define VPN_GETSP43(x) ((uint32) (((x) >> (VA_WIDTH - VA_N_OFF - 2)) & 3))
#define VPN_GETSP32(x) ((uint32) (((x) >> (NTVA_WIDTH - VA_N_OFF - 2)) & 0x1FFF))
/* TLBs */
#define INV_TAG M32
#define ITLB_SIZE 48
#define DTLB_SIZE 64
#define ITLB_WIDTH 6
#define DTLB_WIDTH 6
#define TLB_CI 0x1 /* clear I */
#define TLB_CD 0x2 /* clear D */
#define TLB_CA 0x4 /* clear all */
typedef struct {
uint32 tag; /* tag */
uint8 asn; /* addr space # */
uint8 idx; /* entry # */
uint16 gh_mask; /* gh mask */
uint32 pfn; /* pfn */
uint32 pte; /* swre/pte */
} TLBENT;
/* Register shadow */
#define PALSHAD_SIZE 8
#define PAL_USE_SHADOW \
ev5_palsave[0] = R[8]; ev5_palsave[1] = R[9]; \
ev5_palsave[2] = R[10]; ev5_palsave[3] = R[11]; \
ev5_palsave[4] = R[12]; ev5_palsave[5] = R[13]; \
ev5_palsave[6] = R[14]; ev5_palsave[7] = R[25]; \
R[8] = ev5_palshad[0]; R[9] = ev5_palshad[1]; \
R[10] = ev5_palshad[2]; R[11] = ev5_palshad[3]; \
R[12] = ev5_palshad[4]; R[13] = ev5_palshad[5]; \
R[14] = ev5_palshad[6]; R[25] = ev5_palshad[7]
#define PAL_USE_MAIN \
ev5_palshad[0] = R[8]; ev5_palshad[1] = R[9]; \
ev5_palshad[2] = R[10]; ev5_palshad[3] = R[11]; \
ev5_palshad[4] = R[12]; ev5_palshad[5] = R[13]; \
ev5_palshad[6] = R[14]; ev5_palshad[7] = R[25]; \
R[8] = ev5_palsave[0]; R[9] = ev5_palsave[1]; \
R[10] = ev5_palsave[2]; R[11] = ev5_palsave[3]; \
R[12] = ev5_palsave[4]; R[13] = ev5_palsave[5]; \
R[14] = ev5_palsave[6]; R[25] = ev5_palsave[7]
/* PAL instructions */
#define HW_MFPR 0x19
#define HW_LD 0x1B
#define HW_MTPR 0x1D
#define HW_REI 0x1E
#define HW_ST 0x1F
#define HW_LD_V 0x8000
#define HW_LD_ALT 0x4000
#define HW_LD_WCH 0x2000
#define HW_LD_Q 0x1000
#define HW_LD_PTE 0x0800
#define HW_LD_LCK 0x0400
#define HW_LD_DSP 0x03FF
#define SIGN_HW_LD_DSP 0x0200
#define HW_LD_GETDSP(x) ((x) & HW_LD_DSP)
#define SEXT_HW_LD_DSP(x) (((x) & SIGN_HW_LD_DSP)? \
((x) | ~((t_uint64) HW_LD_DSP)): ((x) & HW_LD_DSP))
#define HW_REI_S 0x4000
/* PAL entry offsets */
#define PALO_RESET 0x0000
#define PALO_IACV 0x0080
#define PALO_INTR 0x0100
#define PALO_ITBM 0x0180
#define PALO_DTBM 0x0200
#define PALO_DTBM_D 0x0280
#define PALO_ALGN 0x0300
#define PALO_DFLT 0x0380
#define PALO_MCHK 0x0400
#define PALO_RSVI 0x0480
#define PALO_TRAP 0x0500
#define PALO_FDIS 0x0580
#define PALO_CALLPR 0x2000
#define PALO_CALLUNPR 0x3000
/* Special (above 1F) and normal interrupt levels */
#define IPL_HALT 0x40
#define IPL_SLI 0x20
#define IPL_1F 0x1F /* highest level */
#define IPL_CRD 0x1F /* corrected read data */
#define IPL_PWRFL 0x1E /* power fail */
#define IPL_AST 0x02 /* AST interrupt level */
/* Internal registers */
#define PALTEMP_SIZE 24
enum ev5_internal_reg {
ISR = 0x100, ITB_TAG, ITB_PTE, ITB_ASN,
ITB_PTE_TEMP, ITB_IA, ITB_IAP, ITB_IS,
SIRR, ASTRR, ASTEN, EXC_ADDR,
EXC_SUMM, EXC_MASK, PAL_BASE, ICM,
IPLR, INTID, IFAULT_VA_FORM, IVPTBR,
HWINT_CLR = 0x115, SL_XMIT, SL_RCV,
ICSR, IC_FLUSH_CTL, ICPERR_STAT, PMCTR = 0x11C,
PALTEMP = 0x140,
DTB_ASN = 0x200, DTB_CM, DTB_TAG, DTB_PTE,
DTB_PTE_TEMP, MM_STAT, VA, VA_FORM,
MVPTBR, DTB_IAP, DTB_IA, DTB_IS,
ALTMODE, CC, CC_CTL, MCSR,
DC_FLUSH, DC_PERR_STAT = 0x212, DC_TEST_CTL,
DC_TEST_TAG, DC_TEST_TAG_TEMP, DC_MODE, MAF_MODE
};
/* Ibox registers */
/* ISR - instruction summary register - read only */
#define ISR_V_AST 0
#define ISR_V_SIRR 4
#define ISR_V_ATR 19
#define ISR_V_IRQ0 20
#define ISR_V_IRQ1 21
#define ISR_V_IRQ2 22
#define ISR_V_IRQ3 23
#define ISR_V_PFL 30
#define ISR_V_MCHK 31
#define ISR_V_CRD 32
#define ISR_V_SLI 33
#define ISR_V_HALT 34
#define ISR_ATR (((t_uint64) 1u) << ISR_V_ATR)
#define ISR_IRQ0 (((t_uint64) 1u) << ISR_V_IRQ0)
#define ISR_IRQ1 (((t_uint64) 1u) << ISR_V_IRQ1)
#define ISR_IRQ2 (((t_uint64) 1u) << ISR_V_IRQ2)
#define ISR_IRQ3 (((t_uint64) 1u) << ISR_V_IRQ3)
#define ISR_HALT (((t_uint64) 1u) << ISR_V_HALT)
/* ITB_TAG - ITLB tag - write only - stores VPN (tag) of faulting address */
/* ITB_PTE - ITLB pte - read and write in different formats */
#define ITBR_PTE_V_ASM 13
#define ITBR_PTE_ASM (1u << ITBR_PTE_V_ASM)
#define ITBR_PTE_V_KRE 18
#define ITBR_PTE_GH0 0x00000000
#define ITBR_PTE_GH1 0x20000000
#define ITBR_PTE_GH2 0x60000000
#define ITBR_PTE_GH3 0xE0000000
/* ITB_ASN - ITLB ASN - read write */
#define ITB_ASN_V_ASN 4
#define ITB_ASN_M_ASN 0x7F
#define ITB_ASN_WIDTH 7
/* ITB_PTE_TEMP - ITLB PTE readout - read only */
/* ITB_IA, ITB_IAP, ITB_IS - ITLB invalidates - write only */
/* SIRR - software interrupt request register - read/write */
#define SIRR_V_SIRR 4
#define SIRR_M_SIRR 0x7FFF
/* ASTRR, ASTEN - AST request, enable registers - read/write */
#define AST_MASK 0xF /* AST bits */
/* EXC_ADDR - read/write */
/* EXC_SUMM - read/cleared on write */
/* EXC_MASK - read only */
/* PAL_BASE - read/write */
#define PAL_BASE_RW 0x000000FFFFFFFFC000
/* ICM - ITLB current mode - read/write */
#define ICM_V_CM 3
#define ICM_M_CM 0x3
/* IPLR - interrupt priority level - read/write */
#define IPLR_V_IPL 0
#define IPLR_M_IPL 0x1F
/* INTID - interrupt ID - read only */
#define INTID_MASK 0x1F
/* IFAULT_VA_FORM - formated fault VA - read only */
/* IVPTBR - virtual page table base - read/write */
#define IVPTBR_VMS 0xFFFFFFF800000000
#define IVPTBR_NT 0xFFFFFFFFC0000000
#define FMT_IVA_VMS(x) (ev5_ivptbr | (((x) >> (VA_N_OFF - 3)) & 0x1FFFFFFF8))
#define FMT_IVA_NT(x) (ev5_ivptbr | (((x) >> (VA_N_OFF - 3)) & 0x0003FFFF8))
/* HWINT_CLR - hardware interrupt clear - write only */
#define HWINT_CLR_W1C 0x00000003C8000000
/* SL_XMIT - serial line transmit - write only */
/* SL_RCV - real line receive - read only */
/* ICSR - Ibox control/status - read/write */
#define ICSR_V_PME 8
#define ICSR_M_PME 0x3
#define ICSR_V_BSE 17
#define ICSR_V_MSK0 20
#define ICSR_V_MSK1 21
#define ICSR_V_MSK2 22
#define ICSR_V_MSK3 23
#define ICSR_V_TMM 24
#define ICSR_V_TMD 25
#define ICSR_V_FPE 26
#define ICSR_V_HWE 27
#define ICSR_V_SPE 28
#define ICSR_M_SPE 0x3
#define ICSR_V_SDE 30
#define ICSR_V_CRDE 32
#define ICSR_V_SLE 33
#define ICSR_V_FMS 34
#define ICSR_V_FBT 35
#define ICSR_V_FBD 36
#define ICSR_V_BIST 38
#define ICSR_V_TEST 39
#define ICSR_NT (((t_uint64) 1u) << ICSR_V_SPE)
#define ICSR_BSE (((t_uint64) 1u) << ICSR_V_BSE)
#define ICSR_MSK0 (((t_uint64) 1u) << ICSR_V_MSK0)
#define ICSR_MSK1 (((t_uint64) 1u) << ICSR_V_MSK1)
#define ICSR_MSK2 (((t_uint64) 1u) << ICSR_V_MSK2)
#define ICSR_MSK3 (((t_uint64) 1u) << ICSR_V_MSK3)
#define ICSR_HWE (((t_uint64) 1u) << ICSR_V_HWE)
#define ICSR_SDE (((t_uint64) 1u) << ICSR_V_SDE)
#define ICSR_CRDE (((t_uint64) 1u) << ICSR_V_CRDE)
#define ICSR_SLE (((t_uint64) 1u) << ICSR_V_SLE)
#define ICSR_RW 0x0000009F4BF00300
#define ICSR_MBO 0x0000006000000000
/* IC_FLUSH_CTL - Icache flush control - write only */
/* ICPERR_STAT - Icache parity status - read/write 1 to clear */
#define ICPERR_V_DPE 11
#define ICPERR_V_TPE 12
#define ICPERR_V_TMO 13
#define ICPERR_DPE (1u << ICPERR_V_DPE)
#define ICPERR_TPE (1u << ICPERR_V_TPE)
#define ICPERR_TMO (1u << ICPERR_V_TMO)
#define ICPERR_W1C (ICPERR_DPE|ICPERR_TPE|ICPERR_TMO)
/* Mbox registers */
/* DTB_ASN - DTLB ASN - write only */
#define DTB_ASN_V_ASN 57
#define DTB_ASN_M_ASN 0x7F
#define DTB_ASN_WIDTH 7
/* DTB_CM - DTLB current mode - write only */
#define DCM_V_CM 3
#define DCM_M_CM 0x3
/* DTB_TAG - DTLB tag and update - write only */
/* DTB_PTE - DTLB PTE - read/write */
/* DTB_PTE_TEMP - DTLB PTE read out register - read only */
/* MM_STAT - data fault status register - read only */
#define MM_STAT_WR 0x00001
#define MM_STAT_ACV 0x00002
#define MM_STAT_FOR 0x00004
#define MM_STAT_FOW 0x00008
#define MM_STAT_TBM 0x00010
#define MM_STAT_BVA 0x00020
#define MM_STAT_V_RA 6
#define MM_STAT_IMASK 0x1FFC0
/* VA - data fault virtual address - read only */
/* VA_FORM - data fault formated virtual address - read only */
#define FMT_MVA_VMS(x) (ev5_mvptbr | (((x) >> (VA_N_OFF - 3)) & 0x1FFFFFFF8))
#define FMT_MVA_NT(x) (ev5_mvptbr | (((x) >> (VA_N_OFF - 3)) & 0x0003FFFF8))
/* MVPTBR - DTB virtual page table base - write only */
#define MVPTBR_MBZ ((t_uint64) 0x3FFFFFFF)
/* DTB_IAP, DTB_IA, DTB_IS - DTB invalidates - write only */
/* ALT_MODE - DTLB current mode - write only */
#define ALT_V_CM 3
#define ALT_M_CM 0x3
/* CC - cycle counter - upper half is RW, lower half is RO */
/* CC_CTL - cycle counter control - write only */
#define CC_CTL_ENB 0x100000000
#define CC_CTL_MBZ 0xF
/* MCSR - Mbox control/status register - read/write */
#define MCSR_RW 0x11
#define MCSR_V_SPE 1
#define MCSR_M_SPE 0x3
#define MCSR_NT 0x02
/* DC_PERR_STAT - data cache parity error status - read/write */
#define DC_PERR_W1C 0x3
#define DC_PERR_ERR 0x1C
/* DC_MODE - data cache mode - read/write */
#define DC_MODE_RW 0xF
/* MAF_MODE - miss address file mode - read/write */
#define MAF_MODE_RW 0xFF
/* DC_TEST_CTL - data cache test control - read/write */
#define DC_TEST_CTL_RW 0x1FFFB
/* DC_TEST_TAG - data cache test tag - read/write */
#define DC_TEST_TAG_RW 0x0000007FFFFFFF04
/* Function prototypes (TLB interface) */
void tlb_ia (uint32 flags);
void tlb_is (t_uint64 va, uint32 flags);
void itlb_set_asn (uint32 asn);
void itlb_set_cm (uint32 mode);
void itlb_set_spage (uint32 spage);
TLBENT *itlb_lookup (uint32 vpn);
TLBENT *itlb_load (uint32 vpn, t_uint64 pte);
t_uint64 itlb_read (void);
void dtlb_set_asn (uint32 asn);
void dtlb_set_cm (uint32 mode);
void dtlb_set_spage (uint32 spage);
TLBENT *dtlb_lookup (uint32 vpn);
TLBENT *dtlb_load (uint32 vpn, t_uint64 pte);
t_uint64 dtlb_read (void);
#endif

961
alpha/alpha_ev5_pal.c Normal file
View file

@ -0,0 +1,961 @@
/* alpha_ev5_pal.c - Alpha EV5 PAL mode simulator
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
EV5 was the second generation Alpha CPU. It was a four-way, in order issue
CPU with onchip primary instruction and data caches, an onchip second level
cache, and support for an offchip third level cache. EV56 was a shrink, with
added support for byte and word operations. PCA56 was a version of EV56
without the onchip second level cache. PCA57 was a shrink of PCA56.
EV5 includes the usual five PALcode instructions:
HW_LD PALcode load
HW_ST PALcode store
HW_MTPR PALcode move to internal processor register
HW_MFPR PALcode move from internal processor register
HW_REI PALcode return
PALcode instructions can only be issued in PALmode, or in kernel mode
if the appropriate bit is set in ICSR.
EV5 implements 8 "PAL shadow" registers, which replace R8-R14, R25 in
PALmode without save/restore; and 24 "PAL temporary" registers.
Internal registers fall into three groups: IBox IPRs, MBox IPRs, and
PAL temporaries.
*/
#include "alpha_defs.h"
#include "alpha_ev5_defs.h"
t_uint64 ev5_palshad[PALSHAD_SIZE] = { 0 }; /* PAL shadow reg */
t_uint64 ev5_palsave[PALSHAD_SIZE] = { 0 }; /* PAL save main */
t_uint64 ev5_paltemp[PALTEMP_SIZE] = { 0 }; /* PAL temps */
t_uint64 ev5_palbase = 0; /* PALcode base */
t_uint64 ev5_excaddr = 0; /* exception address */
t_uint64 ev5_isr = 0; /* intr summary */
t_uint64 ev5_icsr = 0; /* IBox control */
t_uint64 ev5_itb_pte = 0; /* ITLB pte */
t_uint64 ev5_itb_pte_temp = 0; /* ITLB readout */
t_uint64 ev5_ivptbr = 0; /* IBox virt ptbl */
t_uint64 ev5_iva_form = 0; /* Ibox fmt'd VA */
t_uint64 ev5_va = 0; /* Mbox VA */
t_uint64 ev5_mvptbr = 0; /* Mbox virt ptbl */
t_uint64 ev5_va_form = 0; /* Mbox fmt'd VA */
t_uint64 ev5_dtb_pte = 0; /* DTLB pte */
t_uint64 ev5_dtb_pte_temp = 0; /* DTLB readout */
t_uint64 ev5_dc_test_tag = 0; /* Dcache test tag */
t_uint64 ev5_dc_test_tag_temp = 0; /* Dcache tag readout */
uint32 ev5_itb_tag = 0; /* ITLB tag (vpn) */
uint32 ev5_dtb_tag = 0; /* DTLB tag (vpn) */
uint32 ev5_icperr = 0; /* Icache par err */
uint32 ev5_mm_stat = 0; /* MBox fault code */
uint32 ev5_mcsr = 0; /* MBox control */
uint32 ev5_alt_mode = 0; /* MBox alt mode */
uint32 ev5_dc_mode = 0; /* Dcache mode */
uint32 ev5_dcperr = 0; /* Dcache par err */
uint32 ev5_dc_test_ctl = 0; /* Dcache test ctrl */
uint32 ev5_maf_mode = 0; /* MAF mode */
uint32 ev5_va_lock = 0; /* VA lock flag */
uint32 ev5_mchk = 0; /* machine check pin */
uint32 ev5_sli = 0; /* serial line intr */
uint32 ev5_crd = 0; /* corr read data pin */
uint32 ev5_pwrfl = 0; /* power fail pin */
uint32 ev5_ipl = 0; /* ipl */
uint32 ev5_sirr = 0; /* software int req */
uint32 ev5_astrr = 0; /* AST requests */
uint32 ev5_asten = 0; /* AST enables */
const uint32 ast_map[4] = { 0x1, 0x3, 0x7, 0xF };
t_stat ev5_palent (t_uint64 fpc, uint32 off);
t_stat ev5_palent_d (t_uint64 fpc, uint32 off, uint32 sta);
t_stat pal_proc_reset_hwre (DEVICE *dptr);
t_stat pal_proc_intr_ev5 (uint32 lvl);
uint32 pal_eval_intr_ev5 (uint32 flag);
extern t_uint64 R[32];
extern t_uint64 PC;
extern t_uint64 trap_mask;
extern t_uint64 p1;
extern uint32 ir;
extern uint32 vax_flag, lock_flag;
extern uint32 fpen;
extern uint32 pcc_h, pcc_l, pcc_enb;
extern uint32 trap_summ;
extern uint32 arch_mask;
extern uint32 pal_mode, pal_type;
extern uint32 int_req[IPL_HLVL];
extern uint32 itlb_cm, dtlb_cm;
extern uint32 itlb_asn, dtlb_asn;
extern uint32 itlb_spage, dtlb_spage;
extern jmp_buf save_env;
extern uint32 pal_type;
extern t_uint64 pcq[PCQ_SIZE]; /* PC queue */
extern int32 pcq_p; /* PC queue ptr */
extern int32 parse_reg (char *cptr);
/* EV5PAL data structures
ev5pal_dev device descriptor
ev5pal_unit unit
ev5pal_reg register list
*/
UNIT ev5pal_unit = { UDATA (NULL, 0, 0) };
REG ev5pal_reg[] = {
{ BRDATA (PALSHAD, ev5_palshad, 16, 64, PALSHAD_SIZE) },
{ BRDATA (PALSAVE, ev5_palsave, 16, 64, PALSHAD_SIZE) },
{ BRDATA (PALTEMP, ev5_paltemp, 16, 64, PALTEMP_SIZE) },
{ HRDATA (PALBASE, ev5_palbase, 64) },
{ HRDATA (EXCADDR, ev5_excaddr, 64) },
{ HRDATA (IPL, ev5_ipl, 5) },
{ HRDATA (SIRR, ev5_sirr, 15) },
{ HRDATA (ASTRR, ev5_astrr, 4) },
{ HRDATA (ASTEN, ev5_asten, 4) },
{ HRDATA (ISR, ev5_isr, 35) },
{ HRDATA (ICSR, ev5_icsr, 40) },
{ HRDATA (ITB_TAG, ev5_itb_tag, 32) },
{ HRDATA (ITB_PTE, ev5_itb_pte, 64) },
{ HRDATA (ITB_PTE_TEMP, ev5_itb_pte_temp, 64) },
{ HRDATA (IVA_FORM, ev5_iva_form, 64) },
{ HRDATA (IVPTBR, ev5_ivptbr, 64) },
{ HRDATA (ICPERR_STAT, ev5_icperr, 14) },
{ HRDATA (VA, ev5_va, 64) },
{ HRDATA (VA_FORM, ev5_va_form, 64) },
{ HRDATA (MVPTBR, ev5_mvptbr, 64) },
{ HRDATA (MM_STAT, ev5_mm_stat, 17) },
{ HRDATA (MCSR, ev5_mcsr, 6) },
{ HRDATA (DTB_TAG, ev5_dtb_tag, 32) },
{ HRDATA (DTB_PTE, ev5_dtb_pte, 64) },
{ HRDATA (DTB_PTE_TEMP, ev5_dtb_pte_temp, 64) },
{ HRDATA (DC_MODE, ev5_dc_mode, 4) },
{ HRDATA (DC_PERR_STAT, ev5_dcperr, 6) },
{ HRDATA (DC_TEST_CTL, ev5_dc_test_ctl, 13) },
{ HRDATA (DC_TEST_TAG, ev5_dc_test_tag, 39) },
{ HRDATA (DC_TEST_TAG_TEMP, ev5_dc_test_tag_temp, 39) },
{ HRDATA (MAF_MODE, ev5_maf_mode, 8) },
{ FLDATA (VA_LOCK, ev5_va_lock, 0) },
{ FLDATA (MCHK, ev5_mchk, 0) },
{ FLDATA (CRD, ev5_crd, 0) },
{ FLDATA (PWRFL, ev5_pwrfl, 0) },
{ FLDATA (SLI, ev5_sli, 0) },
{ NULL }
};
DEVICE ev5pal_dev = {
"EV5PAL", &ev5pal_unit, ev5pal_reg, NULL,
1, 16, 1, 1, 16, 8,
NULL, NULL, &pal_proc_reset_hwre,
NULL, NULL, NULL,
NULL, DEV_DIS
};
/* EV5 interrupt dispatch - reached from top of instruction loop -
dispatch to PALcode */
t_stat pal_proc_intr (uint32 lvl)
{
return ev5_palent (PC, PALO_INTR);
}
/* EV5 trap dispatch - reached from bottom of instruction loop -
trap_mask and trap_summ are set up correctly - dispatch to PALcode */
t_stat pal_proc_trap (uint32 summ)
{
return ev5_palent (PC, PALO_TRAP);
}
/* EV5 exception dispatch - reached from ABORT handler -
set up any exception-specific registers - dispatch to PALcode */
t_stat pal_proc_excp (uint32 abval)
{
switch (abval) {
case EXC_RSVI: /* reserved instruction */
return ev5_palent (PC, PALO_RSVI);
case EXC_ALIGN: /* unaligned */
return ev5_palent (PC, PALO_ALGN);
case EXC_FPDIS: /* fp disabled */
return ev5_palent (PC, PALO_FDIS);
case EXC_FOX+EXC_R: /* FOR */
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_FOR);
case EXC_FOX+EXC_W: /* FOW */
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_FOR|MM_STAT_WR);
case EXC_BVA+EXC_E: /* instr bad VA */
case EXC_ACV+EXC_E: /* instr ACV */
ev5_itb_tag = VA_GETVPN (PC); /* fault VPN */
if (ev5_icsr & ICSR_NT) /* formatted addr */
ev5_iva_form = ev5_ivptbr | FMT_IVA_NT (PC);
else ev5_iva_form = ev5_ivptbr | FMT_IVA_VMS (PC);
return ev5_palent (PC, PALO_IACV);
case EXC_ACV+EXC_R: /* data read ACV */
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_ACV);
case EXC_ACV+EXC_W: /* data write ACV */
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_ACV|MM_STAT_WR);
case EXC_BVA+EXC_R: /* data read bad addr */
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_BVA);
case EXC_BVA+EXC_W: /* data write bad addr */
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_BVA|MM_STAT_WR);
case EXC_TBM + EXC_E: /* TLB miss */
ev5_itb_tag = VA_GETVPN (PC); /* fault VPN */
if (ev5_icsr & ICSR_NT) /* formatted addr */
ev5_iva_form = ev5_ivptbr | FMT_IVA_NT (PC);
else ev5_iva_form = ev5_ivptbr | FMT_IVA_VMS (PC);
return ev5_palent (PC, PALO_ITBM);
case EXC_TBM + EXC_R: /* data TB miss read */
if ((I_GETOP (ir) == HW_LD) && (ir & HW_LD_PTE))
return ev5_palent_d (PC, PALO_DTBM_D, MM_STAT_TBM);
return ev5_palent_d (PC, PALO_DTBM, MM_STAT_TBM);
case EXC_TBM + EXC_W: /* data TB miss write */
if ((I_GETOP (ir) == HW_LD) && (ir & HW_LD_PTE))
return ev5_palent_d (PC, PALO_DTBM_D, MM_STAT_TBM|MM_STAT_WR);
return ev5_palent_d (PC, PALO_DTBM, MM_STAT_TBM|MM_STAT_WR);
case EXC_RSVO: /* reserved operand */
case EXC_TNV+EXC_E: /* instr TNV */
case EXC_TNV+EXC_R: /* data read TNV */
case EXC_TNV+EXC_W: /* data write TNV */
case EXC_FOX+EXC_E: /* FOE */
return SCPE_IERR; /* should never get here */
default:
return STOP_INVABO;
}
return SCPE_OK;
}
/* EV5 call PAL - reached from instruction decoder -
compute offset from function code - dispatch to PALcode */
t_stat pal_proc_inst (uint32 fnc)
{
uint32 off = (fnc & 0x3F) << 6;
if (fnc & 0x80) return ev5_palent (PC, PALO_CALLUNPR + off);
if (itlb_cm != MODE_K) ABORT (EXC_RSVI);
return ev5_palent (PC, PALO_CALLPR + off);
}
/* EV5 evaluate interrupts - returns highest outstanding
interrupt level about target ipl - plus nonmaskable flags
flag = 1: evaluate for real interrupt capability
flag = 0: evaluate as though IPL = 0, normal mode */
uint32 pal_eval_intr (uint32 flag)
{
uint32 i, req = 0;
uint32 lvl = flag? ev5_ipl: 0;
if (flag && pal_mode) return 0;
if (ev5_mchk) req = IPL_1F;
else if (ev5_crd && (ICSR & ICSR_CRDE)) req = IPL_CRD;
else if (ev5_pwrfl) req = IPL_PWRFL;
else if (int_req[3] && !(ICSR & ICSR_MSK3)) req = IPL_HMIN + 3;
else if (int_req[2] && !(ICSR & ICSR_MSK2)) req = IPL_HMIN + 2;
else if (int_req[1] && !(ICSR & ICSR_MSK1)) req = IPL_HMIN + 1;
else if (int_req[0] && !(ICSR & ICSR_MSK0)) req = IPL_HMIN + 0;
else if (ev5_sirr) {
for (i = IPL_SMAX; i > 0; i--) { /* check swre int */
if ((ev5_sirr >> (i - 1)) & 1) { /* req != 0? int */
req = i;
break;
}
}
}
if ((req < IPL_AST) && (ev5_astrr & ev5_asten & ast_map[itlb_cm]))
req = IPL_AST;
if (req <= lvl) req = 0;
if (ev5_sli && (ICSR & ICSR_SLE)) req = req | IPL_SLI;
if (ev5_isr & ISR_HALT) req = req | IPL_HALT;
return req;
}
/* EV5 enter PAL, data TLB miss/memory management flows -
set Mbox registers - dispatch to PALcode */
t_stat ev5_palent_d (t_uint64 fpc, uint32 off, uint32 sta)
{
if (!ev5_va_lock) { /* not locked? */
ev5_mm_stat = sta | /* merge IR<31:21> */
((ir >> (I_V_RA - MM_STAT_V_RA)) & MM_STAT_IMASK);
ev5_va = p1; /* fault address */
if (ev5_mcsr & MCSR_NT) /* formatted VA */
ev5_va_form = ev5_mvptbr | FMT_MVA_NT (p1);
else ev5_va_form = ev5_mvptbr | FMT_MVA_VMS (p1);
ev5_va_lock = 1; /* lock registers */
}
return ev5_palent (fpc, off);
}
/* EV5 enter PAL */
t_stat ev5_palent (t_uint64 fpc, uint32 off)
{
ev5_excaddr = fpc | pal_mode; /* save exc addr */
PCQ_ENTRY; /* save PC */
PC = ev5_palbase + off; /* new PC */
if (!pal_mode && (ev5_icsr & ICSR_SDE)) { /* entering PALmode? */
PAL_USE_SHADOW; /* swap in shadows */
}
pal_mode = 1; /* in PAL mode */
return SCPE_OK;
}
/* PAL instructions */
/* 1B: HW_LD */
t_stat pal_1b (uint32 ir)
{
t_uint64 dsp, ea, res;
uint32 ra, rb, acc, mode;
if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */
!(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */
ra = I_GETRA (ir); /* get ra */
rb = I_GETRB (ir); /* get rb */
dsp = HW_LD_GETDSP (ir); /* get displacement */
ea = (R[rb] + (SEXT_HW_LD_DSP (dsp))) & M64; /* eff address */
if (ir & HW_LD_V) { /* virtual? */
mode = (ir & HW_LD_ALT)? ev5_alt_mode: dtlb_cm; /* access mode */
acc = (ir & HW_LD_WCH)? ACC_W (mode): ACC_R (mode);
if (ir & HW_LD_Q) res = ReadAccQ (ea, acc); /* quad? */
else { /* long, sext */
res = ReadAccL (ea, acc);
res = SEXT_L_Q (res);
}
}
else if (ir & HW_LD_Q) R[ra] = ReadPQ (ea); /* physical, quad? */
else {
res = ReadPL (ea); /* long, sext */
res = SEXT_L_Q (res);
}
if (ir & HW_LD_LCK) lock_flag = 1; /* lock? set flag */
if (ra != 31) R[ra] = res; /* if not R31, store */
return SCPE_OK;
}
/* 1F: HW_ST */
t_stat pal_1f (uint32 ir)
{
t_uint64 dsp, ea;
uint32 ra, rb, acc, mode;
if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */
!(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */
ra = I_GETRA (ir); /* get ra */
rb = I_GETRB (ir); /* get rb */
dsp = HW_LD_GETDSP (ir); /* get displacement */
ea = (R[rb] + (SEXT_HW_LD_DSP (dsp))) & M64; /* eff address */
if ((ir & HW_LD_LCK) && !lock_flag) R[ra] = 0; /* lock fail? */
else {
if (ir & HW_LD_V) { /* virtual? */
mode = (ir & HW_LD_ALT)? ev5_alt_mode: dtlb_cm; /* access mode */
acc = ACC_W (mode);
if (ir & HW_LD_Q) WriteAccQ (ea, R[ra], acc); /* quad? */
else WriteAccL (ea, R[ra], acc); /* long */
}
else if (ir & HW_LD_Q) WritePQ (ea, R[ra]); /* physical, quad? */
else WritePL (ea, R[ra]); /* long */
if (ir & HW_LD_LCK) lock_flag = 0; /* unlock? clr flag */
}
return SCPE_OK;
}
/* 1E: HW_REI */
t_stat pal_1e (uint32 ir)
{
uint32 new_pal = ((uint32) ev5_excaddr) & 1;
if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */
!(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */
PCQ_ENTRY;
PC = ev5_excaddr;
if (pal_mode && !new_pal && (ev5_icsr & ICSR_SDE)) { /* leaving PAL mode? */
PAL_USE_MAIN; /* swap out shadows */
}
pal_mode = new_pal;
return SCPE_OK;
}
/* PAL move from processor registers */
t_stat pal_19 (uint32 ir)
{
t_uint64 res;
uint32 fnc, ra;
static const uint32 itbr_map_gh[4] = {
ITBR_PTE_GH0, ITBR_PTE_GH1, ITBR_PTE_GH2, ITBR_PTE_GH3 };
if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */
!(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */
fnc = I_GETMDSP (ir);
ra = I_GETRA (ir);
switch (fnc) {
case ISR: /* intr summary */
res = ev5_isr | ((ev5_astrr & ev5_asten) << ISR_V_AST) |
((ev5_sirr & SIRR_M_SIRR) << ISR_V_SIRR) |
(int_req[0] && !(ev5_icsr & ICSR_MSK0)? ISR_IRQ0: 0) |
(int_req[1] && !(ev5_icsr & ICSR_MSK1)? ISR_IRQ1: 0) |
(int_req[2] && !(ev5_icsr & ICSR_MSK2)? ISR_IRQ2: 0) |
(int_req[3] && !(ev5_icsr & ICSR_MSK3)? ISR_IRQ3: 0);
if (ev5_astrr & ev5_asten & ast_map[itlb_cm]) res = res | ISR_ATR;
break;
case ITB_PTE:
res = itlb_read ();
ev5_itb_pte_temp = (res & PFN_MASK) |
((res & PTE_ASM)? ITBR_PTE_ASM: 0) |
((res & (PTE_KRE|PTE_ERE|PTE_SRE|PTE_URE)) <<
(ITBR_PTE_V_KRE - PTE_V_KRE)) |
itbr_map_gh[PTE_GETGH (res)];
res = 0;
break;
case ITB_ASN:
res = (itlb_asn & ITB_ASN_M_ASN) << ITB_ASN_V_ASN;
break;
case ITB_PTE_TEMP:
res = ev5_itb_pte_temp;
break;
case SIRR:
res = (ev5_sirr & SIRR_M_SIRR) << SIRR_V_SIRR;
break;
case ASTRR:
res = ev5_astrr & AST_MASK;
break;
case ASTEN:
res = ev5_asten & AST_MASK;
break;
case EXC_ADDR:
res = ev5_excaddr;
break;
case EXC_SUMM:
res = trap_summ & TRAP_SUMM_RW;
break;
case EXC_MASK:
res = trap_mask;
break;
case PAL_BASE:
res = ev5_palbase & PAL_BASE_RW;
break;
case ICM:
res = (itlb_cm & ICM_M_CM) << ICM_V_CM;
break;
case IPLR:
res = (ev5_ipl & IPLR_M_IPL) << IPLR_V_IPL;
break;
case INTID:
res = pal_eval_intr (0) & INTID_MASK;
break;
case IFAULT_VA_FORM:
res = ev5_iva_form;
break;
case IVPTBR:
res = ev5_ivptbr;
break;
case ICSR:
res = (ev5_icsr & ICSR_RW) | ICSR_MBO |
((itlb_spage & ICSR_M_SPE) << ICSR_V_SPE) |
((fpen & 1) << ICSR_V_FPE) |
((arch_mask & AMASK_BWX)? ICSR_BSE: 0);
break;
case PALTEMP+0x00: case PALTEMP+0x01: case PALTEMP+0x02: case PALTEMP+0x03:
case PALTEMP+0x04: case PALTEMP+0x05: case PALTEMP+0x06: case PALTEMP+0x07:
case PALTEMP+0x08: case PALTEMP+0x09: case PALTEMP+0x0A: case PALTEMP+0x0B:
case PALTEMP+0x0C: case PALTEMP+0x0D: case PALTEMP+0x0E: case PALTEMP+0x0F:
case PALTEMP+0x10: case PALTEMP+0x11: case PALTEMP+0x12: case PALTEMP+0x13:
case PALTEMP+0x14: case PALTEMP+0x15: case PALTEMP+0x16: case PALTEMP+0x17:
res = ev5_paltemp[fnc - PALTEMP];
break;
case DTB_PTE:
ev5_dtb_pte_temp = dtlb_read ();
res = 0;
break;
case DTB_PTE_TEMP:
res = ev5_dtb_pte_temp;
break;
case MM_STAT:
res = ev5_mm_stat;
break;
case VA:
res = ev5_va;
ev5_va_lock = 0;
break;
case VA_FORM:
res = ev5_va_form;
break;
case DC_PERR_STAT:
res = ev5_dcperr;
break;
case MCSR:
res = (ev5_mcsr & MCSR_RW) | ((dtlb_spage & MCSR_M_SPE) << MCSR_V_SPE);
break;
case DC_MODE:
res = ev5_dc_mode & DC_MODE_RW;
break;
case MAF_MODE:
res = ev5_maf_mode & MAF_MODE_RW;
break;
case CC:
res = (((t_uint64) pcc_h) << 32) | ((t_uint64) pcc_l);
break;
case DC_TEST_CTL:
res = ev5_dc_test_ctl & DC_TEST_CTL_RW;
break;
case DC_TEST_TAG:
// to be determined
res = 0;
break;
case DC_TEST_TAG_TEMP:
res = ev5_dc_test_tag_temp & DC_TEST_TAG_RW;
break;
default:
res = 0;
break;
}
if (ra != 31) R[ra] = res & M64;
return SCPE_OK;
}
/* PAL move to processor registers */
t_stat pal_1d (uint32 ir)
{
uint32 fnc = I_GETMDSP (ir);
uint32 ra = I_GETRA (ir);
t_uint64 val = R[ra];
if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */
!(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */
switch (fnc) {
case ITB_TAG:
ev5_itb_tag = VA_GETVPN (val);
break;
case ITB_PTE:
ev5_itb_pte = (val | PTE_V) & (PFN_MASK | ((t_uint64) (PTE_ASM | PTE_GH |
PTE_KRE | PTE_ERE | PTE_SRE | PTE_URE)));
itlb_load (ev5_itb_tag, ev5_itb_pte);
break;
case ITB_ASN:
itlb_set_asn ((((uint32) val) >> ITB_ASN_V_ASN) & ITB_ASN_M_ASN);
break;
case ITB_IA:
tlb_ia (TLB_CI | TLB_CA);
break;
case ITB_IAP:
tlb_ia (TLB_CI);
break;
case ITB_IS:
tlb_is (val, TLB_CI);
break;
case SIRR:
ev5_sirr = (((uint32) val) >> SIRR_V_SIRR) & SIRR_M_SIRR;
break;
case ASTRR:
ev5_astrr = ((uint32) val) & AST_MASK;
break;
case ASTEN:
ev5_asten = ((uint32) val) & AST_MASK;
break;
case EXC_ADDR:
ev5_excaddr = val;
break;
case EXC_SUMM:
trap_summ = 0;
trap_mask = 0;
break;
case PAL_BASE:
ev5_palbase = val & PAL_BASE_RW;
break;
case ICM:
itlb_set_cm ((((uint32) val) >> ICM_V_CM) & ICM_M_CM);
break;
case IPLR:
ev5_ipl = (((uint32) val) >> IPLR_V_IPL) & IPLR_M_IPL;
break;
case IVPTBR:
if (ev5_icsr & ICSR_NT) ev5_ivptbr = val & IVPTBR_NT;
else ev5_ivptbr = val & IVPTBR_VMS;
break;
case HWINT_CLR:
ev5_isr = ev5_isr & ~(val & HWINT_CLR_W1C);
break;
case ICSR:
if (pal_mode && ((val ^ ev5_icsr) & ICSR_SDE)) {
if (val & ICSR_SDE) { PAL_USE_SHADOW; }
else { PAL_USE_MAIN; }
}
ev5_icsr = val & ICSR_RW;
itlb_set_spage ((((uint32) val) >> ICSR_V_SPE) & ICSR_M_SPE);
fpen = (((uint32) val) >> ICSR_V_FPE) & 1;
if (val & ICSR_BSE) arch_mask = arch_mask | AMASK_BWX;
else arch_mask = arch_mask & ~AMASK_BWX;
break;
case ICPERR_STAT:
ev5_icperr = ev5_icperr & ~(((uint32) val) & ICPERR_W1C);
break;
case PALTEMP+0x00: case PALTEMP+0x01: case PALTEMP+0x02: case PALTEMP+0x03:
case PALTEMP+0x04: case PALTEMP+0x05: case PALTEMP+0x06: case PALTEMP+0x07:
case PALTEMP+0x08: case PALTEMP+0x09: case PALTEMP+0x0A: case PALTEMP+0x0B:
case PALTEMP+0x0C: case PALTEMP+0x0D: case PALTEMP+0x0E: case PALTEMP+0x0F:
case PALTEMP+0x10: case PALTEMP+0x11: case PALTEMP+0x12: case PALTEMP+0x13:
case PALTEMP+0x14: case PALTEMP+0x15: case PALTEMP+0x16: case PALTEMP+0x17:
ev5_paltemp[fnc - PALTEMP] = val;
break;
case DTB_ASN:
dtlb_set_asn (((uint32) (val >> DTB_ASN_V_ASN)) & DTB_ASN_M_ASN);
break;
case DTB_CM:
dtlb_set_cm (((uint32) (val >> ICM_V_CM)) & ICM_M_CM);
break;
case DTB_TAG:
ev5_dtb_tag = VA_GETVPN (val);
val = (val | PTE_V) & (PFN_MASK | ((t_uint64) (PTE_MASK & ~PTE_FOE)));
dtlb_load (ev5_dtb_tag, val);
break;
case DTB_PTE:
ev5_dtb_pte = val;
break;
case MVPTBR:
ev5_mvptbr = val & ~MVPTBR_MBZ;
break;
case DC_PERR_STAT:
ev5_dcperr = ev5_dcperr & ~(((uint32) val) & DC_PERR_W1C);
if ((ev5_dcperr & DC_PERR_W1C) == 0) ev5_dcperr = 0;
break;
case DTB_IA:
tlb_ia (TLB_CD | TLB_CA);
break;
case DTB_IAP:
tlb_ia (TLB_CD);
break;
case DTB_IS:
tlb_is (val, TLB_CD);
break;
case MCSR:
ev5_mcsr = ((uint32) val) & MCSR_RW;
dtlb_set_spage ((((uint32) val) >> MCSR_V_SPE) & MCSR_M_SPE);
if (ev5_mcsr & MCSR_NT) pal_type = PAL_NT;
break;
case DC_MODE:
ev5_dc_mode = ((uint32) val) & DC_MODE_RW;
break;
case MAF_MODE:
ev5_maf_mode = ((uint32) val) & MAF_MODE_RW;
break;
case CC:
pcc_h = (uint32) ((val >> 32) & M32);
break;
case CC_CTL:
pcc_l = ((uint32) val) & (M32 & ~CC_CTL_MBZ);
if (val & CC_CTL_ENB) pcc_enb = 1;
else pcc_enb = 0;
break;
case DC_TEST_CTL:
ev5_dc_test_ctl = ((uint32) val) & DC_TEST_CTL_RW;
break;
case DC_TEST_TAG:
ev5_dc_test_tag = val & DC_TEST_TAG_RW;
break;
default:
break;
}
return SCPE_OK;
}
/* EV5 PALcode reset */
t_stat pal_proc_reset_hwre (DEVICE *dptr)
{
ev5_palbase = 0;
ev5_mchk = 0;
ev5_pwrfl = 0;
ev5_crd = 0;
ev5_sli = 0;
itlb_set_cm (MODE_K);
itlb_set_asn (0);
itlb_set_spage (0);
dtlb_set_cm (MODE_K);
dtlb_set_asn (0);
dtlb_set_spage (0);
return SCPE_OK;
}
/* EV5 PAL instruction print and parse routines */
static const char *pal_inam[] = {
"HW_MFPR", "HW_LD", "HW_MTPR", "HW_REI", "HW_ST", NULL
};
static const uint32 pal_ival[] = {
0x64000000, 0x6C000000, 0x74000000, 0x7BFF8000, 0x7C000000
};
struct pal_opt {
uint32 mask; /* bit mask */
char let; /* matching letter */
};
static struct pal_opt ld_st_opt[] = {
{ HW_LD_V, 'V' },
{ HW_LD_ALT, 'A' },
{ HW_LD_WCH, 'W' },
{ HW_LD_Q, 'Q' },
{ HW_LD_PTE, 'P' },
{ HW_LD_LCK, 'L' },
{ 0 }
};
static struct pal_opt rei_opt[] = {
{ HW_REI_S, 'S' },
{ 0 }
};
/* Print options for hardware PAL instruction */
void fprint_opt_ev5 (FILE *of, uint32 inst, struct pal_opt opt[])
{
uint32 i;
for (i = 0; opt[i].mask != 0; i++) {
if (inst & opt[i].mask) {
fprintf (of, "/%c", opt[i].let);
inst = inst & ~opt[i].mask;
}
}
return;
}
/* Parse options for hardware PAL instruction */
char *parse_opt_ev5 (char *cptr, uint32 *val, struct pal_opt opt[])
{
uint32 i;
char *tptr, gbuf[CBUFSIZE];
if (*(cptr - 1) != '/') return cptr;
cptr = get_glyph (cptr - 1, tptr = gbuf, 0);
while (*tptr == '/') {
tptr++;
for (i = 0; opt[i].mask != 0; i++) {
if (*tptr == opt[i].let) {
*val = *val | opt[i].mask;
break;
}
}
if (opt[i].mask == 0) return NULL;
tptr++;
}
if (*tptr != 0) return NULL;
return cptr;
}
/* Print PAL hardware opcode symbolically */
t_stat fprint_pal_hwre (FILE *of, uint32 inst)
{
uint32 op, ra, rb;
op = I_GETOP (inst);
ra = I_GETRA (inst);
rb = I_GETRB (inst);
switch (op) {
case OP_PAL19: /* HW_MFPR */
case OP_PAL1D: /* HW_MTPR */
fputs ((op == OP_PAL19)? "HW_MFPR": "HW_MTPR", of);
fprintf (of, " R%d,%X", ra, inst & M16);
break;
case OP_PAL1B: /* HW_LD */
case OP_PAL1F: /* HW_ST */
fputs ((op == OP_PAL1B)? "HW_LD": "HW_ST", of);
fprint_opt_ev5 (of, inst, ld_st_opt);
fprintf (of, " R%d,%X", ra, inst & HW_LD_DSP);
if (rb != 31) fprintf (of, "(R%d)", rb);
break;
case OP_PAL1E: /* HW_REI */
fputs ("HW_REI", of);
fprint_opt_ev5 (of, inst, rei_opt);
break;
default:
return SCPE_ARG;
}
return -3;
}
/* Parse PAL hardware opcode symbolically */
t_stat parse_pal_hwre (char *cptr, t_value *inst)
{
uint32 i, d, val = 0;
int32 reg;
char *tptr, gbuf[CBUFSIZE];
t_stat r;
cptr = get_glyph (cptr, gbuf, '/');
for (i = 0; pal_inam[i] != NULL; i++) {
if (strcmp (gbuf, pal_inam[i]) == 0) val = pal_ival[i];
}
if (val == 0) return SCPE_ARG;
switch (I_GETOP (val)) {
case OP_PAL19: /* HW_MFPR */
case OP_PAL1D: /* HW_MTPR */
if (*(cptr - 1) == '/') return SCPE_ARG;
cptr = get_glyph (cptr, gbuf, ','); /* get reg */
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
val = val | (reg << I_V_RA) | (reg << I_V_RB);
cptr = get_glyph (cptr, gbuf, 0); /* get ipr */
d = (uint32) get_uint (gbuf, 16, M16, &r);
if (r != SCPE_OK) return r;
val = val | d;
break;
case OP_PAL1B: /* HW_LD */
case OP_PAL1F: /* HW_ST */
cptr = parse_opt_ev5 (cptr, &val, ld_st_opt);
if (cptr == NULL) return SCPE_ARG;
cptr = get_glyph (cptr, gbuf, ','); /* get reg */
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
val = val | (reg << I_V_RA);
cptr = get_glyph (cptr, gbuf, 0);
d = (uint32) strtotv (gbuf, &tptr, 16);
if ((gbuf == tptr) || (d > HW_LD_DSP)) return SCPE_ARG;
val = val | d;
if (*tptr == '(') {
tptr = get_glyph (tptr + 1, gbuf, ')');
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
val = val | (reg << I_V_RB);
}
else val = val | (31 << I_V_RB);
break;
case OP_PAL1E: /* HW_REI */
cptr = parse_opt_ev5 (cptr, &val, rei_opt);
if (cptr == NULL) return SCPE_ARG;
break;
default:
return SCPE_ARG;
}
*inst = val;
if (*cptr != 0) return SCPE_ARG;
return -3;
}

566
alpha/alpha_ev5_tlb.c Normal file
View file

@ -0,0 +1,566 @@
/* alpha_ev5_tlb.c - Alpha EV5 TLB simulator
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
EV5 was the second generation Alpha CPU. It was a four-way, in order issue
CPU with onchip primary instruction and data caches, an onchip second level
cache, and support for an offchip third level cache. EV56 was a shrink, with
added support for byte and word operations. EV56PC was a version of EV56
without the onchip second level cache.
This module contains the routines for
itlb_lookup lookup vpn in instruction TLB
itlb_load load pte into instruction TLB
itlb_read read pte from instruction TLB using NLU pointer
itlb_set_asn set iasn
itlb_set_cm set icm
itlb_set_spage set ispage
dtlb_lookup lookup vpn in data TLB
dtlb_load load pte into data TLB
dtlb_read read pte from data TLB using NLU pointer
dtlb_set_asn set dasn
dtlb_set_cm set dcm
dtlb_set_spage set dspage
tlb_ia TLB invalidate all
tlb_is TLB invalidate single
tlb_set_cm TLB set current mode
*/
#include "alpha_defs.h"
#include "alpha_ev5_defs.h"
#define ITLB_SORT qsort (itlb, ITLB_SIZE, sizeof (TLBENT), &tlb_comp);
#define DTLB_SORT qsort (dtlb, DTLB_SIZE, sizeof (TLBENT), &tlb_comp);
#define TLB_ESIZE (sizeof (TLBENT)/sizeof (uint32))
#define MM_RW(x) (((x) & PTE_FOW)? EXC_W: EXC_R)
uint32 itlb_cm = 0; /* current modes */
uint32 itlb_spage = 0; /* superpage enables */
uint32 itlb_asn = 0;
uint32 itlb_nlu = 0;
TLBENT i_mini_tlb;
TLBENT itlb[ITLB_SIZE];
uint32 dtlb_cm = 0;
uint32 dtlb_spage = 0;
uint32 dtlb_asn = 0;
uint32 dtlb_nlu = 0;
TLBENT d_mini_tlb;
TLBENT dtlb[DTLB_SIZE];
uint32 cm_eacc = ACC_E (MODE_K); /* precomputed */
uint32 cm_racc = ACC_R (MODE_K); /* access checks */
uint32 cm_wacc = ACC_W (MODE_K);
uint32 cm_macc = ACC_M (MODE_K);
extern t_uint64 p1;
extern jmp_buf save_env;
uint32 mm_exc (uint32 macc);
void tlb_inval (TLBENT *tlbp);
t_stat itlb_reset (void);
t_stat dtlb_reset (void);
int tlb_comp (const void *e1, const void *e2);
t_stat tlb_reset (DEVICE *dptr);
/* TLB data structures
tlb_dev pager device descriptor
tlb_unit pager units
tlb_reg pager register list
*/
UNIT tlb_unit = { UDATA (NULL, 0, 0) };
REG tlb_reg[] = {
{ HRDATA (ICM, itlb_cm, 2) },
{ HRDATA (ISPAGE, itlb_spage, 2), REG_HRO },
{ HRDATA (IASN, itlb_asn, ITB_ASN_WIDTH) },
{ HRDATA (INLU, itlb_nlu, ITLB_WIDTH) },
{ BRDATA (IMINI, &i_mini_tlb, 16, 32, TLB_ESIZE) },
{ BRDATA (ITLB, itlb, 16, 32, ITLB_SIZE*TLB_ESIZE) },
{ HRDATA (DCM, dtlb_cm, 2) },
{ HRDATA (DSPAGE, dtlb_spage, 2), REG_HRO },
{ HRDATA (DASN, dtlb_asn, DTB_ASN_WIDTH) },
{ HRDATA (DNLU, dtlb_nlu, DTLB_WIDTH) },
{ BRDATA (DMINI, &d_mini_tlb, 16, 32, TLB_ESIZE) },
{ BRDATA (DTLB, dtlb, 16, 32, DTLB_SIZE*TLB_ESIZE) },
{ NULL }
};
DEVICE tlb_dev = {
"TLB", &tlb_unit, tlb_reg, NULL,
1, 0, 0, 1, 0, 0,
NULL, NULL, &tlb_reset,
NULL, NULL, NULL
};
/* Translate address, instruction, data, and console
Inputs:
va = virtual address
acc = (VAX only) access mode
Outputs:
pa = translation buffer index
*/
t_uint64 trans_i (t_uint64 va)
{
uint32 va_sext = VA_GETSEXT (va);
uint32 vpn = VA_GETVPN (va);
TLBENT *tlbp;
if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */
ABORT1 (va, EXC_BVA + EXC_E);
if ((itlb_spage & SPEN_43) && VPN_GETSP43 (vpn) == 2) { /* 43b superpage? */
if (itlb_cm != MODE_K) ABORT1 (va, EXC_ACV + EXC_E);
return (va & SP43_MASK);
}
if ((itlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) {
if (itlb_cm != MODE_K) ABORT1 (va, EXC_ACV + EXC_E);
return (va & SP32_MASK); /* 32b superpage? */
}
if (!(tlbp = itlb_lookup (vpn))) /* lookup vpn; miss? */
ABORT1 (va, EXC_TBM + EXC_E); /* abort reference */
if (cm_eacc & ~tlbp->pte) /* check access */
ABORT1 (va, mm_exc (cm_eacc & ~tlbp->pte) | EXC_E);
return PHYS_ADDR (tlbp->pfn, va); /* return phys addr */
}
t_uint64 trans_d (t_uint64 va, uint32 acc)
{
uint32 va_sext = VA_GETSEXT (va);
uint32 vpn = VA_GETVPN (va);
TLBENT *tlbp;
if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */
ABORT1 (va, EXC_BVA + MM_RW (acc));
if ((dtlb_spage & SPEN_43) && (VPN_GETSP43 (vpn) == 2)) {
if (dtlb_cm != MODE_K) ABORT1 (va, EXC_ACV + MM_RW (acc));
return (va & SP43_MASK); /* 43b superpage? */
}
if ((dtlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) {
if (dtlb_cm != MODE_K) ABORT1 (va, EXC_ACV + MM_RW (acc));
return (va & SP32_MASK); /* 32b superpage? */
}
if (!(tlbp = dtlb_lookup (vpn))) /* lookup vpn; miss? */
ABORT1 (va, EXC_TBM + MM_RW (acc)); /* abort reference */
if (acc & ~tlbp->pte) /* check access */
ABORT1 (va, mm_exc (acc & ~tlbp->pte) | MM_RW (acc));
return PHYS_ADDR (tlbp->pfn, va); /* return phys addr */
}
/* Generate a memory management error code, based on the access check bits not
set in PTE
- If the access check bits, without FOx and V, fail, then ACV
- If FOx set, then FOx
- Otherwise, TNV */
uint32 mm_exc (uint32 not_set)
{
uint32 tacc;
tacc = not_set & ~(PTE_FOR | PTE_FOW | PTE_FOE | PTE_V);
if (tacc) return EXC_ACV;
tacc = not_set & (PTE_FOR | PTE_FOW | PTE_FOE);
if (tacc) return EXC_FOX;
return EXC_TNV;
}
/* TLB invalidate single */
void tlb_is (t_uint64 va, uint32 flags)
{
uint32 va_sext = VA_GETSEXT (va);
uint32 vpn = VA_GETVPN (va);
TLBENT *itlbp, *dtlbp;
if ((va_sext != 0) && (va_sext != VA_M_SEXT)) return;
if ((flags & TLB_CI) && (itlbp = itlb_lookup (vpn))) {
tlb_inval (itlbp);
tlb_inval (&i_mini_tlb);
ITLB_SORT;
}
if ((flags & TLB_CD) && (dtlbp = dtlb_lookup (vpn))) {
tlb_inval (dtlbp);
tlb_inval (&d_mini_tlb);
DTLB_SORT;
}
return;
}
/* TLB invalidate all */
void tlb_ia (uint32 flags)
{
uint32 i;
if (flags & TLB_CA) {
if (flags & TLB_CI) itlb_reset ();
if (flags & TLB_CD) dtlb_reset ();
return;
}
if (flags & TLB_CI) {
for (i = 0; i < ITLB_SIZE; i++) {
if (!(itlb[i].pte & PTE_ASM)) tlb_inval (&itlb[i]);
}
tlb_inval (&i_mini_tlb);
ITLB_SORT;
}
if (flags & TLB_CD) {
for (i = 0; i < DTLB_SIZE; i++) {
if (!(dtlb[i].pte & PTE_ASM)) tlb_inval (&dtlb[i]);
}
tlb_inval (&d_mini_tlb);
DTLB_SORT;
}
return;
}
/* TLB lookup */
TLBENT *itlb_lookup (uint32 vpn)
{
int32 p, hi, lo;
if (vpn == i_mini_tlb.tag) return &i_mini_tlb;
lo = 0; /* initial bounds */
hi = ITLB_SIZE - 1;
do {
p = (lo + hi) >> 1; /* probe */
if ((itlb_asn == itlb[p].asn) &&
(((vpn ^ itlb[p].tag) &
~((uint32) itlb[p].gh_mask)) == 0)) { /* match to TLB? */
i_mini_tlb.tag = vpn;
i_mini_tlb.pte = itlb[p].pte;
i_mini_tlb.pfn = itlb[p].pfn;
itlb_nlu = itlb[p].idx + 1;
if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0;
return &i_mini_tlb;
}
if ((itlb_asn < itlb[p].asn) ||
((itlb_asn == itlb[p].asn) && (vpn < itlb[p].tag)))
hi = p - 1; /* go down? p is upper */
else lo = p + 1; /* go up? p is lower */
}
while (lo <= hi);
return NULL;
}
TLBENT *dtlb_lookup (uint32 vpn)
{
int32 p, hi, lo;
if (vpn == d_mini_tlb.tag) return &d_mini_tlb;
lo = 0; /* initial bounds */
hi = DTLB_SIZE - 1;
do {
p = (lo + hi) >> 1; /* probe */
if ((dtlb_asn == dtlb[p].asn) &&
(((vpn ^ dtlb[p].tag) &
~((uint32) dtlb[p].gh_mask)) == 0)) { /* match to TLB? */
d_mini_tlb.tag = vpn;
d_mini_tlb.pte = dtlb[p].pte;
d_mini_tlb.pfn = dtlb[p].pfn;
dtlb_nlu = dtlb[p].idx + 1;
if (dtlb_nlu >= DTLB_SIZE) dtlb_nlu = 0;
return &d_mini_tlb;
}
if ((dtlb_asn < dtlb[p].asn) ||
((dtlb_asn == dtlb[p].asn) && (vpn < dtlb[p].tag)))
hi = p - 1; /* go down? p is upper */
else lo = p + 1; /* go up? p is lower */
}
while (lo <= hi);
return NULL;
}
/* Load TLB entry at NLU pointer, advance NLU pointer */
TLBENT *itlb_load (uint32 vpn, t_uint64 l3pte)
{
uint32 i, gh;
for (i = 0; i < ITLB_SIZE; i++) {
if (itlb[i].idx == itlb_nlu) {
TLBENT *tlbp = itlb + i;
itlb_nlu = itlb_nlu + 1;
if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0;
tlbp->tag = vpn;
tlbp->pte = (uint32) (l3pte & PTE_MASK) ^ (PTE_FOR|PTE_FOR|PTE_FOE);
tlbp->pfn = ((uint32) (l3pte >> PTE_V_PFN)) & PFN_MASK;
tlbp->asn = itlb_asn;
gh = PTE_GETGH (tlbp->pte);
tlbp->gh_mask = (1u << (3 * gh)) - 1;
tlb_inval (&i_mini_tlb);
ITLB_SORT;
return tlbp;
}
}
fprintf (stderr, "%%ITLB entry not found, itlb_nlu = %d\n", itlb_nlu);
ABORT (-SCPE_IERR);
return NULL;
}
TLBENT *dtlb_load (uint32 vpn, t_uint64 l3pte)
{
uint32 i, gh;
for (i = 0; i < DTLB_SIZE; i++) {
if (dtlb[i].idx == dtlb_nlu) {
TLBENT *tlbp = dtlb + i;
dtlb_nlu = dtlb_nlu + 1;
if (dtlb_nlu >= ITLB_SIZE) dtlb_nlu = 0;
tlbp->tag = vpn;
tlbp->pte = (uint32) (l3pte & PTE_MASK) ^ (PTE_FOR|PTE_FOR|PTE_FOE);
tlbp->pfn = ((uint32) (l3pte >> PTE_V_PFN)) & PFN_MASK;
tlbp->asn = dtlb_asn;
gh = PTE_GETGH (tlbp->pte);
tlbp->gh_mask = (1u << (3 * gh)) - 1;
tlb_inval (&d_mini_tlb);
DTLB_SORT;
return tlbp;
}
}
fprintf (stderr, "%%DTLB entry not found, dtlb_nlu = %d\n", dtlb_nlu);
ABORT (-SCPE_IERR);
return NULL;
}
/* Read TLB entry at NLU pointer, advance NLU pointer */
t_uint64 itlb_read (void)
{
uint8 i;
for (i = 0; i < ITLB_SIZE; i++) {
if (itlb[i].idx == itlb_nlu) {
TLBENT *tlbp = itlb + i;
itlb_nlu = itlb_nlu + 1;
if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0;
return (((t_uint64) tlbp->pfn) << PTE_V_PFN) |
((tlbp->pte ^ (PTE_FOR|PTE_FOR|PTE_FOE)) & PTE_MASK);
}
}
fprintf (stderr, "%%ITLB entry not found, itlb_nlu = %d\n", itlb_nlu);
ABORT (-SCPE_IERR);
return 0;
}
t_uint64 dtlb_read (void)
{
uint8 i;
for (i = 0; i < DTLB_SIZE; i++) {
if (dtlb[i].idx == dtlb_nlu) {
TLBENT *tlbp = dtlb + i;
dtlb_nlu = dtlb_nlu + 1;
if (dtlb_nlu >= DTLB_SIZE) dtlb_nlu = 0;
return (((t_uint64) tlbp->pfn) << PTE_V_PFN) |
((tlbp->pte ^ (PTE_FOR|PTE_FOR|PTE_FOE)) & PTE_MASK);
}
}
fprintf (stderr, "%%DTLB entry not found, dtlb_nlu = %d\n", dtlb_nlu);
ABORT (-SCPE_IERR);
return 0;
}
/* Set ASN - rewrite TLB globals with correct ASN */
void itlb_set_asn (uint32 asn)
{
int32 i;
itlb_asn = asn;
for (i = 0; i < ITLB_SIZE; i++) {
if (itlb[i].pte & PTE_ASM) itlb[i].asn = asn;
}
tlb_inval (&i_mini_tlb);
ITLB_SORT;
return;
}
void dtlb_set_asn (uint32 asn)
{
int32 i;
dtlb_asn = asn;
for (i = 0; i < DTLB_SIZE; i++) {
if (dtlb[i].pte & PTE_ASM) dtlb[i].asn = asn;
}
tlb_inval (&d_mini_tlb);
DTLB_SORT;
return;
}
/* Set superpage */
void itlb_set_spage (uint32 spage)
{
itlb_spage = spage;
return;
}
void dtlb_set_spage (uint32 spage)
{
dtlb_spage = spage;
return;
}
/* Set current mode */
void itlb_set_cm (uint32 mode)
{
itlb_cm = mode;
cm_eacc = ACC_E (mode);
return;
}
void dtlb_set_cm (uint32 mode)
{
dtlb_cm = mode;
cm_racc = ACC_R (mode);
cm_wacc = ACC_W (mode);
return;
}
uint32 tlb_set_cm (int32 cm)
{
if (cm >= 0) {
itlb_set_cm (cm);
dtlb_set_cm (cm);
return cm;
}
itlb_set_cm (itlb_cm);
dtlb_set_cm (dtlb_cm);
return dtlb_cm;
}
/* Invalidate TLB entry */
void tlb_inval (TLBENT *tlbp)
{
tlbp->tag = INV_TAG;
tlbp->pte = 0;
tlbp->pfn = 0;
tlbp->asn = tlbp->idx;
tlbp->gh_mask = 0;
return;
}
/* Compare routine for qsort */
int tlb_comp (const void *e1, const void *e2)
{
TLBENT *t1 = (TLBENT *) e1;
TLBENT *t2 = (TLBENT *) e2;
if (t1->asn > t2->asn) return +1;
if (t1->asn < t2->asn) return -1;
if (t1->tag > t2->tag) return +1;
if (t1->tag < t2->tag) return -1;
return 0;
}
/* ITLB reset */
t_stat itlb_reset (void)
{
int32 i;
itlb_nlu = 0;
for (i = 0; i < ITLB_SIZE; i++) {
itlb[i].tag = INV_TAG;
itlb[i].pte = 0;
itlb[i].pfn = 0;
itlb[i].asn = i;
itlb[i].gh_mask = 0;
itlb[i].idx = i;
}
tlb_inval (&i_mini_tlb);
return SCPE_OK;
}
/* DTLB reset */
t_stat dtlb_reset (void)
{
int32 i;
dtlb_nlu = 0;
for (i = 0; i < DTLB_SIZE; i++) {
dtlb[i].tag = INV_TAG;
dtlb[i].pte = 0;
dtlb[i].pfn = 0;
dtlb[i].asn = i;
dtlb[i].gh_mask = 0;
dtlb[i].idx = i;
}
tlb_inval (&d_mini_tlb);
return SCPE_OK;
}
/* SimH reset */
t_stat tlb_reset (DEVICE *dptr)
{
itlb_reset ();
dtlb_reset ();
return SCPE_OK;
}
/* Show TLB entry or entries */
t_stat cpu_show_tlb (FILE *of, UNIT *uptr, int32 val, void *desc)
{
t_addr lo, hi;
uint32 lnt;
TLBENT *tlbp;
DEVICE *dptr;
char *cptr = (char *) desc;
lnt = (val)? DTLB_SIZE: ITLB_SIZE;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
if (cptr) {
cptr = get_range (dptr, cptr, &lo, &hi, 10, lnt, 0);
if ((cptr == NULL) || (*cptr != 0)) return SCPE_ARG;
}
else {
lo = 0;
hi = lnt - 1;
}
tlbp = (val)? dtlb + lo: itlb + lo;
do {
fprintf (of, "TLB %02d\tTAG=%02X/%08X, ", (uint32) lo, tlbp->asn, tlbp->tag);
fprintf (of, "MASK=%X, INDX=%d, ", tlbp->gh_mask, tlbp->idx);
fprintf (of, "PTE=%04X, PFN=%08X\n", tlbp->pte, tlbp->pfn);
tlbp++;
lo++;
} while (lo <= hi);
return SCPE_OK;
}

776
alpha/alpha_fpi.c Normal file
View file

@ -0,0 +1,776 @@
/* alpha_fpi.c - Alpha IEEE floating point simulator
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This module contains the instruction simulators for
- single precision floating point, S
- double precision floating point, T
Portions of this module (specifically, the convert floating to integer
routine and the square root routine) are a derivative work from SoftFloat,
written by John Hauser. SoftFloat includes the following license terms:
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page 'http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
*/
#include "alpha_defs.h"
#define UFT_ZERO 0 /* unpacked: zero */
#define UFT_FIN 1 /* finite */
#define UFT_DENORM 2 /* denormal */
#define UFT_INF 3 /* infinity */
#define UFT_NAN 4 /* not a number */
#define Q_FINITE(x) ((x) <= UFT_FIN) /* finite */
#define Q_SUI(x) (((x) & I_FTRP) == I_FTRP_SVI)
/* Register format constants */
#define QNAN 0x0008000000000000 /* quiet NaN flag */
#define CQNAN 0xFFF8000000000000 /* canonical quiet NaN */
#define FPZERO 0x0000000000000000 /* plus zero (fp) */
#define FMZERO 0x8000000000000000 /* minus zero (fp) */
#define FPINF 0x7FF0000000000000 /* plus infinity (fp) */
#define FMINF 0xFFF0000000000000 /* minus infinity (fp) */
#define FPMAX 0x7FEFFFFFFFFFFFFF /* plus MAX (fp) */
#define FMMAX 0xFFEFFFFFFFFFFFFF /* minus MAX (fp) */
#define IPMAX 0x7FFFFFFFFFFFFFFF /* plus MAX (int) */
#define IMMAX 0x8000000000000000 /* minus MAX (int) */
/* Unpacked rounding constants */
#define UF_SRND 0x0000008000000000 /* S normal round */
#define UF_SINF 0x000000FFFFFFFFFF /* S infinity round */
#define UF_TRND 0x0000000000000400 /* T normal round */
#define UF_TINF 0x00000000000007FF /* T infinity round */
extern t_uint64 FR[32];
extern uint32 fpcr;
extern jmp_buf save_env;
t_bool ieee_unpack (t_uint64 op, UFP *r, uint32 ir);
void ieee_norm (UFP *r);
t_uint64 ieee_rpack (UFP *r, uint32 ir, uint32 dp);
void ieee_trap (uint32 trap, uint32 instenb, uint32 fpcrdsb, uint32 ir);
int32 ieee_fcmp (t_uint64 a, t_uint64 b, uint32 ir, uint32 signal_nan);
t_uint64 ieee_cvtst (t_uint64 op, uint32 ir);
t_uint64 ieee_cvtts (t_uint64 op, uint32 ir);
t_uint64 ieee_cvtif (t_uint64 val, uint32 ir, uint32 dp);
t_uint64 ieee_cvtfi (t_uint64 op, uint32 ir);
t_uint64 ieee_fadd (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp, t_bool sub);
t_uint64 ieee_fmul (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp);
t_uint64 ieee_fdiv (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp);
uint32 estimateSqrt32 (uint32 exp, uint32 a);
t_uint64 estimateDiv128 (t_uint64 hi, t_uint64 lo, t_uint64 dvr);
extern t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi);
extern t_uint64 ufdiv64 (t_uint64 dvd, t_uint64 dvr, uint32 prec, uint32 *sticky);
t_uint64 fsqrt64 (t_uint64 frac, int32 exp);
/* IEEE S load */
t_uint64 op_lds (t_uint64 op)
{
uint32 exp = S_GETEXP (op); /* get exponent */
if (exp == S_NAN) exp = FPR_NAN; /* inf or NaN? */
else if (exp != 0) exp = exp + T_BIAS - S_BIAS; /* zero or denorm? */
return (((t_uint64) (op & S_SIGN))? FPR_SIGN: 0) | /* reg format */
(((t_uint64) exp) << FPR_V_EXP) |
(((t_uint64) (op & ~(S_SIGN|S_EXP))) << S_V_FRAC);
}
/* IEEE S store */
t_uint64 op_sts (t_uint64 op)
{
uint32 sign = FPR_GETSIGN (op)? S_SIGN: 0;
uint32 frac = ((uint32) (op >> S_V_FRAC)) & M32;
uint32 exp = FPR_GETEXP (op);
if (exp == FPR_NAN) exp = S_NAN; /* inf or NaN? */
else if (exp != 0) exp = exp + S_BIAS - T_BIAS; /* non-zero? */
exp = (exp & S_M_EXP) << S_V_EXP;
return (t_uint64) (sign | exp | (frac & ~(S_SIGN|S_EXP)));
}
/* IEEE floating operate */
void ieee_fop (uint32 ir)
{
UFP a, b;
uint32 ftpa, ftpb, fnc, ra, rb, rc;
t_uint64 res;
fnc = I_GETFFNC (ir); /* get function */
ra = I_GETRA (ir); /* get registers */
rb = I_GETRB (ir);
rc = I_GETRC (ir);
switch (fnc) { /* case on func */
case 0x00: /* ADDS */
res = ieee_fadd (FR[ra], FR[rb], ir, DT_S, 0);
break;
case 0x01: /* SUBS */
res = ieee_fadd (FR[ra], FR[rb], ir, DT_S, 1);
break;
case 0x02: /* MULS */
res = ieee_fmul (FR[ra], FR[rb], ir, DT_S);
break;
case 0x03: /* DIVS */
res = ieee_fdiv (FR[ra], FR[rb], ir, DT_S);
break;
case 0x20: /* ADDT */
res = ieee_fadd (FR[ra], FR[rb], ir, DT_T, 0);
break;
case 0x21: /* SUBT */
res = ieee_fadd (FR[ra], FR[rb], ir, DT_T, 1);
break;
case 0x22: /* MULT */
res = ieee_fmul (FR[ra], FR[rb], ir, DT_T);
break;
case 0x23: /* DIVT */
res = ieee_fdiv (FR[ra], FR[rb], ir, DT_T);
break;
case 0x24: /* CMPTUN */
ftpa = ieee_unpack (FR[ra], &a, ir); /* unpack */
ftpb = ieee_unpack (FR[rb], &b, ir);
if ((ftpa == UFT_NAN) || (ftpb == UFT_NAN)) /* if NaN, T */
res = FP_TRUE;
else res = 0;
break;
case 0x25: /* CMPTEQ */
if (ieee_fcmp (FR[ra], FR[rb], ir, 0) == 0) res = FP_TRUE;
else res = 0;
break;
case 0x26: /* CMPTLT */
if (ieee_fcmp (FR[ra], FR[rb], ir, 1) < 0) res = FP_TRUE;
else res = 0;
break;
case 0x27: /* CMPTLE */
if (ieee_fcmp (FR[ra], FR[rb], ir, 1) <= 0) res = FP_TRUE;
else res = 0;
break;
case 0x2C: /* CVTST, CVTTS */
if (ir & 0x2000) res = ieee_cvtst (FR[rb], ir); /* CVTST */
else res = ieee_cvtts (FR[rb], ir); /* CVTTS */
break;
case 0x2F: /* CVTTQ */
res = ieee_cvtfi (FR[rb], ir);
break;
case 0x3C: /* CVTQS */
res = ieee_cvtif (FR[rb], ir, DT_S);
break;
case 0x3E: /* CVTQT */
res = ieee_cvtif (FR[rb], ir, DT_T);
break;
default:
if ((ir & I_FSRC) == I_FSRC_X) ABORT (EXC_RSVI);
res = FR[rc];
break;
}
if (rc != 31) FR[rc] = res & M64;
return;
}
/* IEEE S to T convert - LDS doesn't handle denorms correctly */
t_uint64 ieee_cvtst (t_uint64 op, uint32 ir)
{
UFP b;
uint32 ftpb;
ftpb = ieee_unpack (op, &b, ir); /* unpack; norm dnorm */
if (ftpb == UFT_DENORM) { /* denormal? */
b.exp = b.exp + T_BIAS - S_BIAS; /* change 0 exp to T */
return ieee_rpack (&b, ir, DT_T); /* round, pack */
}
else return op; /* identity */
}
/* IEEE T to S convert */
t_uint64 ieee_cvtts (t_uint64 op, uint32 ir)
{
UFP b;
uint32 ftpb;
ftpb = ieee_unpack (op, &b, ir); /* unpack */
if (Q_FINITE (ftpb)) return ieee_rpack (&b, ir, DT_S); /* finite? round, pack */
if (ftpb == UFT_NAN) return (op | QNAN); /* nan? cvt to quiet */
if (ftpb == UFT_INF) return op; /* inf? unchanged */
return 0; /* denorm? 0 */
}
/* IEEE floating compare
- Take care of NaNs
- Force -0 to +0
- Then normal compare will work (even on inf and denorms) */
int32 ieee_fcmp (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 trap_nan)
{
UFP a, b;
uint32 ftpa, ftpb;
ftpa = ieee_unpack (s1, &a, ir);
ftpb = ieee_unpack (s2, &b, ir);
if ((ftpa == UFT_NAN) || (ftpb == UFT_NAN)) { /* NaN involved? */
if (trap_nan) ieee_trap (TRAP_INV, 1, FPCR_INVD, ir);
return +1; /* force failure */
}
if (ftpa == UFT_ZERO) a.sign = 0; /* only +0 allowed */
if (ftpb == UFT_ZERO) b.sign = 0;
if (a.sign != b.sign) return (a.sign? -1: +1); /* unequal signs? */
if (a.exp != b.exp) return ((a.sign ^ (a.exp < b.exp))? -1: +1);
if (a.frac != b.frac) return ((a.sign ^ (a.frac < b.frac))? -1: +1);
return 0;
}
/* IEEE integer to floating convert */
t_uint64 ieee_cvtif (t_uint64 val, uint32 ir, uint32 dp)
{
UFP a;
if (val == 0) return 0; /* 0? return +0 */
if (val & FPR_SIGN) { /* < 0? */
a.sign = 1; /* set sign */
val = NEG_Q (val); /* |val| */
}
else a.sign = 0;
a.exp = 63 + T_BIAS; /* set exp */
a.frac = val; /* set frac */
ieee_norm (&a); /* normalize */
return ieee_rpack (&a, ir, dp); /* round and pack */
}
/* IEEE floating to integer convert - rounding code from SoftFloat
The Alpha architecture specifies return of the low order bits of
the true result, whereas the IEEE standard specifies the return
of the maximum plus or minus value */
t_uint64 ieee_cvtfi (t_uint64 op, uint32 ir)
{
UFP a;
t_uint64 sticky;
uint32 rndm, ftpa, ovf;
int32 ubexp;
ftpa = ieee_unpack (op, &a, ir); /* unpack */
if (!Q_FINITE (ftpa)) { /* inf, NaN, dnorm? */
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv operation */
return 0;
}
if (ftpa == UFT_ZERO) return 0; /* zero? */
ovf = 0; /* assume no ovflo */
ubexp = a.exp - T_BIAS; /* unbiased exp */
if (ubexp < 0) { /* < 1? */
if (ubexp == -1) sticky = a.frac; /* [.5,1)? */
else sticky = 1; /* (0,.5) */
a.frac = 0;
}
else if (ubexp < UF_V_NM) { /* in range? */
sticky = (a.frac << (64 - (UF_V_NM - ubexp))) & M64;
a.frac = a.frac >> (UF_V_NM - ubexp); /* result */
}
else if (ubexp == UF_V_NM) sticky = 0; /* at limit of range? */
else {
if ((ubexp - UF_V_NM) > 63) a.frac = 0; /* out of range */
else a.frac = (a.frac << (ubexp - UF_V_NM)) & M64;
ovf = 1; /* overflow */
sticky = 0; /* no rounding */
}
rndm = I_GETFRND (ir); /* get round mode */
if (((rndm == I_FRND_N) && (sticky & Q_SIGN)) || /* nearest? */
((rndm == I_FRND_P) && !a.sign && sticky) || /* +inf and +? */
((rndm == I_FRND_M) && a.sign && sticky)) { /* -inf and -? */
a.frac = (a.frac + 1) & M64;
if (a.frac == 0) ovf = 1; /* overflow? */
if ((rndm == I_FRND_N) && (sticky == Q_SIGN)) /* round nearest hack */
a.frac = a.frac & ~1;
}
if (a.frac > (a.sign? IMMAX: IPMAX)) ovf = 1; /* overflow? */
if (ovf) ieee_trap (TRAP_IOV, ir & I_FTRP_V, 0, 0); /* overflow trap */
if (ovf || sticky) /* ovflo or round? */
ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir);
return (a.sign? NEG_Q (a.frac): a.frac);
}
/* IEEE floating add
- Take care of NaNs and infinites
- Test for zero (fast exit)
- Sticky logic for floating add
> If result normalized, sticky in right place
> If result carries out, renormalize, retain sticky
- Sticky logic for floating subtract
> If shift < guard, no sticky bits; 64b result is exact
If shift <= 1, result may require extensive normalization,
but there are no sticky bits to worry about
> If shift >= guard, there is a sticky bit,
but normalization is at most 1 place, sticky bit is retained
for rounding purposes (but not in low order bit) */
t_uint64 ieee_fadd (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp, t_bool sub)
{
UFP a, b, t;
uint32 ftpa, ftpb;
uint32 sticky, rndm;
int32 ediff;
ftpa = ieee_unpack (s1, &a, ir); /* unpack operands */
ftpb = ieee_unpack (s2, &b, ir);
if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */
if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */
if (sub) b.sign = b.sign ^ 1; /* sign of B */
if (ftpb == UFT_INF) { /* B = inf? */
if ((ftpa == UFT_INF) && (a.sign ^ b.sign)) { /* eff sub of inf? */
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */
return CQNAN; /* canonical NaN */
}
return (sub? (s2 ^ FPR_SIGN): s2); /* return B */
}
if (ftpa == UFT_INF) return s1; /* A = inf? ret A */
rndm = I_GETFRND (ir); /* inst round mode */
if (rndm == I_FRND_D) rndm = FPCR_GETFRND (fpcr); /* dynamic? use FPCR */
if (ftpa == UFT_ZERO) { /* A = 0? */
if (ftpb != UFT_ZERO) a = b; /* B != 0? result is B */
else if (a.sign != b.sign) /* both 0, subtract? */
a.sign = (rndm == I_FRND_M); /* +0 unless RM */
}
else if (ftpb != UFT_ZERO) { /* s2 != 0? */
if ((a.exp < b.exp) || /* s1 < s2? swap */
((a.exp == b.exp) && (a.frac < b.frac))) {
t = a;
a = b;
b = t;
}
ediff = a.exp - b.exp; /* exp diff */
if (ediff > 63) b.frac = 1; /* >63? retain sticky */
else if (ediff) { /* [1,63]? shift */
sticky = ((b.frac << (64 - ediff)) & M64)? 1: 0; /* lost bits */
b.frac = ((b.frac >> ediff) & M64) | sticky;
}
if (a.sign ^ b.sign) { /* eff sub? */
a.frac = (a.frac - b.frac) & M64; /* subtract fractions */
if (a.frac == 0) { /* result 0? */
a.exp = 0;
a.sign = (rndm == I_FRND_M); /* +0 unless RM */
}
else ieee_norm (&a); /* normalize */
}
else { /* eff add */
a.frac = (a.frac + b.frac) & M64; /* add frac */
if (a.frac < b.frac) { /* chk for carry */
a.frac = UF_NM | (a.frac >> 1) | /* shift in carry */
(a.frac & 1); /* retain sticky */
a.exp = a.exp + 1; /* skip norm */
}
}
} /* end else if */
return ieee_rpack (&a, ir, dp); /* round and pack */
}
/* IEEE floating multiply
- Take care of NaNs and infinites
- Test for zero operands (fast exit)
- 64b x 64b fraction multiply, yielding 128b result
- Normalize (at most 1 bit)
- Insert "sticky" bit in low order fraction, for rounding
Because IEEE fractions have a range of [1,2), the result can have a range
of [1,4). Results in the range of [1,2) appear to be denormalized by one
place, when in fact they are correct. Results in the range of [2,4) appear
to be in correct, when in fact they are 2X larger. This problem is taken
care of in the result exponent calculation. */
t_uint64 ieee_fmul (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp)
{
UFP a, b;
uint32 ftpa, ftpb;
t_uint64 resl;
ftpa = ieee_unpack (s1, &a, ir); /* unpack operands */
ftpb = ieee_unpack (s2, &b, ir);
if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */
if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */
a.sign = a.sign ^ b.sign; /* sign of result */
if ((ftpa == UFT_ZERO) || (ftpb == UFT_ZERO)) { /* zero operand? */
if ((ftpa == UFT_INF) || (ftpb == UFT_INF)) { /* 0 * inf? */
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */
return CQNAN; /* canonical NaN */
}
return (a.sign? FMZERO: FPZERO); /* return signed 0 */
}
if (ftpb == UFT_INF) return (a.sign? FMINF: FPINF); /* B = inf? */
if (ftpa == UFT_INF) return (a.sign? FMINF: FPINF); /* A = inf? */
a.exp = a.exp + b.exp + 1 - T_BIAS; /* add exponents */
resl = uemul64 (a.frac, b.frac, &a.frac); /* multiply fracs */
ieee_norm (&a); /* normalize */
a.frac = a.frac | (resl? 1: 0); /* sticky bit */
return ieee_rpack (&a, ir, dp); /* round and pack */
}
/* Floating divide
- Take care of NaNs and infinites
- Check for zero cases
- Divide fractions (55b to develop a rounding bit)
- Set sticky bit if remainder non-zero
Because IEEE fractions have a range of [1,2), the result can have a range
of (.5,2). Results in the range of [1,2) are correct. Results in the
range of (.5,1) need to be normalized by one place. */
t_uint64 ieee_fdiv (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp)
{
UFP a, b;
uint32 ftpa, ftpb, sticky;
ftpa = ieee_unpack (s1, &a, ir);
ftpb = ieee_unpack (s2, &b, ir);
if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */
if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */
a.sign = a.sign ^ b.sign; /* sign of result */
if (ftpb == UFT_INF) { /* B = inf? */
if (ftpa == UFT_INF) { /* inf/inf? */
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */
return CQNAN; /* canonical NaN */
}
return (a.sign? FMZERO: FPZERO); /* !inf/inf, ret 0 */
}
if (ftpa == UFT_INF) /* A = inf? */
return (a.sign? FMINF: FPINF); /* return inf */
if (ftpb == UFT_ZERO) { /* B = 0? */
if (ftpa == UFT_ZERO) { /* 0/0? */
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */
return CQNAN; /* canonical NaN */
}
ieee_trap (TRAP_DZE, 1, FPCR_DZED, ir); /* div by 0 trap */
return (a.sign? FMINF: FPINF); /* return inf */
}
if (ftpa == UFT_ZERO) return (a.sign? FMZERO: FPZERO); /* A = 0? */
a.exp = a.exp - b.exp + T_BIAS; /* unbiased exp */
a.frac = a.frac >> 1; /* allow 1 bit left */
b.frac = b.frac >> 1;
a.frac = ufdiv64 (a.frac, b.frac, 55, &sticky); /* divide */
ieee_norm (&a); /* normalize */
a.frac = a.frac | sticky; /* insert sticky */
return ieee_rpack (&a, ir, dp); /* round and pack */
}
/* IEEE floating square root
- Take care of NaNs, +infinite, zero
- Check for negative operand
- Compute result exponent
- Compute sqrt of fraction */
t_uint64 ieee_sqrt (uint32 ir, uint32 dp)
{
t_uint64 op;
uint32 ftpb;
UFP b;
op = FR[I_GETRB (ir)]; /* get F[rb] */
ftpb = ieee_unpack (op, &b, ir); /* unpack */
if (ftpb == UFT_NAN) return op | QNAN; /* NaN? */
if ((ftpb == UFT_ZERO) || /* zero? */
((ftpb == UFT_INF) && !b.sign)) return op; /* +infinity? */
if (b.sign) { /* minus? */
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */
return CQNAN;
}
b.exp = ((b.exp - T_BIAS) >> 1) + T_BIAS - 1; /* result exponent */
b.frac = fsqrt64 (b.frac, b.exp); /* result fraction */
return ieee_rpack (&b, ir, dp); /* round and pack */
}
/* Support routines */
t_bool ieee_unpack (t_uint64 op, UFP *r, uint32 ir)
{
r->sign = FPR_GETSIGN (op); /* get sign */
r->exp = FPR_GETEXP (op); /* get exponent */
r->frac = FPR_GETFRAC (op); /* get fraction */
if (r->exp == 0) { /* exponent = 0? */
if (r->frac == 0) return UFT_ZERO; /* frac = 0? then true 0 */
if (fpcr & FPCR_DNZ) { /* denorms to 0? */
r->frac = 0; /* clear fraction */
return UFT_ZERO;
}
r->frac = r->frac << FPR_GUARD; /* guard fraction */
ieee_norm (r); /* normalize dnorm */
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */
return UFT_DENORM;
}
if (r->exp == FPR_NAN) { /* exponent = max? */
if (r->frac == 0) return UFT_INF; /* frac = 0? then inf */
if (!(r->frac & QNAN)) /* signaling NaN? */
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */
return UFT_NAN;
}
r->frac = (r->frac | FPR_HB) << FPR_GUARD; /* ins hidden bit, guard */
return UFT_FIN; /* finite */
}
/* Normalize - input must be zero, finite, or denorm */
void ieee_norm (UFP *r)
{
int32 i;
static t_uint64 normmask[5] = {
0xc000000000000000, 0xf000000000000000, 0xff00000000000000,
0xffff000000000000, 0xffffffff00000000
};
static int32 normtab[6] = { 1, 2, 4, 8, 16, 32 };
r->frac = r->frac & M64;
if (r->frac == 0) { /* if fraction = 0 */
r->sign = 0;
r->exp = 0; /* result is 0 */
return;
}
while ((r->frac & UF_NM) == 0) { /* normalized? */
for (i = 0; i < 5; i++) { /* find first 1 */
if (r->frac & normmask[i]) break;
}
r->frac = r->frac << normtab[i]; /* shift frac */
r->exp = r->exp - normtab[i]; /* decr exp */
}
return;
}
/* Round and pack
Much of the treachery of the IEEE standard is buried here
- Rounding modes (chopped, +infinity, nearest, -infinity)
- Inexact (set if there are any rounding bits, regardless of rounding)
- Overflow (result is infinite if rounded, max if not)
- Underflow (no denorms!)
Underflow handling is particularly complicated
- Result is always 0
- UNF and INE are always set in FPCR
- If /U is set,
o If /S is clear, trap
o If /S is set, UNFD is set, but UNFZ is clear, ignore UNFD and
trap, because the hardware cannot produce denormals
o If /S is set, UNFD is set, and UNFZ is set, do not trap
- If /SUI is set, and INED is clear, trap */
t_uint64 ieee_rpack (UFP *r, uint32 ir, uint32 dp)
{
static const t_uint64 stdrnd[2] = { UF_SRND, UF_TRND };
static const t_uint64 infrnd[2] = { UF_SINF, UF_TINF };
static const int32 expmax[2] = { T_BIAS - S_BIAS + S_M_EXP - 1, T_M_EXP - 1 };
static const int32 expmin[2] = { T_BIAS - S_BIAS, 0 };
t_uint64 rndadd, rndbits, res;
uint32 rndm;
if (r->frac == 0) /* result 0? */
return ((t_uint64) r->sign << FPR_V_SIGN);
rndm = I_GETFRND (ir); /* inst round mode */
if (rndm == I_FRND_D) rndm = FPCR_GETFRND (fpcr); /* dynamic? use FPCR */
rndbits = r->frac & infrnd[dp]; /* isolate round bits */
if (rndm == I_FRND_N) rndadd = stdrnd[dp]; /* round to nearest? */
else if (((rndm == I_FRND_P) && !r->sign) || /* round to inf and */
((rndm == I_FRND_M) && r->sign)) /* right sign? */
rndadd = infrnd[dp];
else rndadd = 0;
r->frac = (r->frac + rndadd) & M64; /* round */
if ((r->frac & UF_NM) == 0) { /* carry out? */
r->frac = (r->frac >> 1) | UF_NM; /* renormalize */
r->exp = r->exp + 1;
}
if (rndbits) /* inexact? */
ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */
if (r->exp > expmax[dp]) { /* ovflo? */
ieee_trap (TRAP_OVF, 1, FPCR_OVFD, ir); /* set overflow trap */
ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */
if (rndadd) /* did we round? */
return (r->sign? FMINF: FPINF); /* return infinity */
return (r->sign? FMMAX: FPMAX); /* no, return max */
}
if (r->exp <= expmin[dp]) { /* underflow? */
ieee_trap (TRAP_UNF, ir & I_FTRP_U, /* set underflow trap */
(fpcr & FPCR_UNDZ)? FPCR_UNFD: 0, ir); /* (dsbl only if UNFZ set) */
ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */
return 0; /* underflow to +0 */
}
res = (((t_uint64) r->sign) << FPR_V_SIGN) | /* form result */
(((t_uint64) r->exp) << FPR_V_EXP) |
((r->frac >> FPR_GUARD) & FPR_FRAC);
if ((rndm == I_FRND_N) && (rndbits == stdrnd[dp])) /* nearest and halfway? */
res = res & ~1; /* clear lo bit */
return res;
}
/* IEEE arithmetic trap - only one can be set at a time! */
void ieee_trap (uint32 trap, uint32 instenb, uint32 fpcrdsb, uint32 ir)
{
fpcr = fpcr | (trap << 19); /* FPCR to trap summ offset */
if ((instenb == 0) || /* not enabled in inst? ignore */
((ir & I_FTRP_S) && (fpcr & fpcrdsb))) return; /* /S and disabled? ignore */
arith_trap (trap, ir); /* set Alpha trap */
return;
}
/* Fraction square root routine - code from SoftFloat */
t_uint64 fsqrt64 (t_uint64 asig, int32 exp)
{
t_uint64 zsig, remh, reml, t;
uint32 sticky = 0;
zsig = estimateSqrt32 (exp, (uint32) (asig >> 32));
/* Calculate the final answer in two steps. First, do one iteration of
Newton's approximation. The divide-by-2 is accomplished by clever
positioning of the operands. Then, check the bits just below the
(double precision) rounding bit to see if they are close to zero
(that is, the rounding bits are close to midpoint). If so, make
sure that the result^2 is <below> the input operand */
asig = asig >> ((exp & 1)? 3: 2); /* leave 2b guard */
zsig = estimateDiv128 (asig, 0, zsig << 32) + (zsig << 30 );
if ((zsig & 0x1FF) <= 5) { /* close to even? */
reml = uemul64 (zsig, zsig, &remh); /* result^2 */
remh = asig - remh - (reml? 1:0); /* arg - result^2 */
reml = NEG_Q (reml);
while (Q_GETSIGN (remh) != 0) { /* if arg < result^2 */
zsig = zsig - 1; /* decr result */
t = (zsig << 1) | 1; /* incr result^2 */
reml = reml + t; /* and retest */
remh = remh + (zsig >> 63) + ((reml < t)? 1: 0);
}
if ((remh | reml) != 0 ) sticky = 1; /* not exact? */
}
return zsig;
}
/* Estimate 32b SQRT
Calculate an approximation to the square root of the 32-bit significand given
by 'a'. Considered as an integer, 'a' must be at least 2^31. If bit 0 of
'exp' (the least significant bit) is 1, the integer returned approximates
2^31*sqrt('a'/2^31), where 'a' is considered an integer. If bit 0 of 'exp'
is 0, the integer returned approximates 2^31*sqrt('a'/2^30). In either
case, the approximation returned lies strictly within +/-2 of the exact
value. */
uint32 estimateSqrt32 (uint32 exp, uint32 a)
{
uint32 index, z;
static const uint32 sqrtOdd[] = {
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
};
static const uint32 sqrtEven[] = {
0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
};
index = (a >> 27) & 0xF; /* bits<30:27> */
if (exp & 1) { /* odd exp? */
z = 0x4000 + (a >> 17) - sqrtOdd[index]; /* initial guess */
z = ((a / z) << 14) + (z << 15); /* Newton iteration */
a = a >> 1;
}
else {
z = 0x8000 + (a >> 17) - sqrtEven[index]; /* initial guess */
z = (a / z) + z; /* Newton iteration */
z = (z >= 0x20000) ? 0xFFFF8000: (z << 15);
if (z <= a) z = (a >> 1) | 0x80000000;
}
return (uint32) ((((((t_uint64) a) << 31) / ((t_uint64) z)) + (z >> 1)) & M32);
}
/* Estimate 128b unsigned divide */
t_uint64 estimateDiv128 (t_uint64 a0, t_uint64 a1, t_uint64 b)
{
t_uint64 b0, b1;
t_uint64 rem0, rem1, term0, term1;
t_uint64 z;
if (b <= a0) return 0xFFFFFFFFFFFFFFFF;
b0 = b >> 32;
z = ((b0 << 32) <= a0)? 0xFFFFFFFF00000000: ((a0 / b0) << 32);
term1 = uemul64 (b, z, &term0);
rem0 = a0 - term0 - (a1 < term1);
rem1 = a1 - term1;
while (Q_GETSIGN (rem0)) {
z = z - ((t_uint64) 0x100000000);
b1 = b << 32;
rem1 = b1 + rem1;
rem0 = b0 + rem0 + (rem1 < b1);
}
rem0 = (rem0 << 32) | (rem1 >> 32);
z |= (((b0 << 32) <= rem0)? 0xFFFFFFFF : (rem0 / b0));
return z;
}

457
alpha/alpha_fpv.c Normal file
View file

@ -0,0 +1,457 @@
/* alpha_fpv.c - Alpha VAX floating point simulator
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This module contains the instruction simulators for
- single precision floating point, F
- double precision floating point, G
*/
#include "alpha_defs.h"
#define IPMAX 0x7FFFFFFFFFFFFFFF /* plus MAX (int) */
#define IMMAX 0x8000000000000000 /* minus MAX (int) */
/* Unpacked rounding constants */
#define UF_FRND 0x0000008000000000 /* F round */
#define UF_DRND 0x0000000000000080 /* D round */
#define UF_GRND 0x0000000000000400 /* G round */
extern t_uint64 FR[32];
extern jmp_buf save_env;
t_bool vax_unpack (t_uint64 op, UFP *a, uint32 ir);
t_bool vax_unpack_d (t_uint64 op, UFP *a, uint32 ir);
void vax_norm (UFP *a);
t_uint64 vax_rpack (UFP *a, uint32 ir, uint32 dp);
t_uint64 vax_rpack_d (UFP *a, uint32 ir);
int32 vax_fcmp (t_uint64 a, t_uint64 b, uint32 ir);
t_uint64 vax_cvtif (t_uint64 val, uint32 ir, uint32 dp);
t_uint64 vax_cvtfi (t_uint64 op, uint32 ir);
t_uint64 vax_fadd (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp, t_bool sub);
t_uint64 vax_fmul (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp);
t_uint64 vax_fdiv (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp);
extern t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi);
extern t_uint64 ufdiv64 (t_uint64 dvd, t_uint64 dvr, uint32 prec, uint32 *sticky);
extern t_uint64 fsqrt64 (t_uint64 frac, int32 exp);
/* VAX floating point loads and stores */
t_uint64 op_ldf (t_uint64 op)
{
uint32 exp = F_GETEXP (op);
if (exp != 0) exp = exp + G_BIAS - F_BIAS; /* zero? */
return (((t_uint64) (op & F_SIGN))? FPR_SIGN: 0) | /* finite non-zero */
(((t_uint64) exp) << FPR_V_EXP) |
(((t_uint64) SWAP_VAXF (op & ~(F_SIGN|F_EXP))) << F_V_FRAC);
}
t_uint64 op_ldg (t_uint64 op)
{
return SWAP_VAXG (op); /* swizzle bits */
}
t_uint64 op_stf (t_uint64 op)
{
uint32 sign = FPR_GETSIGN (op)? F_SIGN: 0;
uint32 frac = (uint32) (op >> F_V_FRAC);
uint32 exp = FPR_GETEXP (op);
if (exp != 0) exp = exp + F_BIAS - G_BIAS; /* zero? */
exp = (exp & F_M_EXP) << F_V_EXP;
return (t_uint64) (sign | exp | (SWAP_VAXF (frac) & ~(F_SIGN|F_EXP)));
}
t_uint64 op_stg (t_uint64 op)
{
return SWAP_VAXG (op); /* swizzle bits */
}
/* VAX floating point operate */
void vax_fop (uint32 ir)
{
UFP b;
t_uint64 res;
uint32 fnc, ra, rb, rc;
fnc = I_GETFFNC (ir); /* get function */
ra = I_GETRA (ir); /* get registers */
rb = I_GETRB (ir);
rc = I_GETRC (ir);
switch (fnc) { /* case on func */
case 0x00: /* ADDF */
res = vax_fadd (FR[ra], FR[rb], ir, DT_F, 0);
break;
case 0x01: /* SUBF */
res = vax_fadd (FR[ra], FR[rb], ir, DT_F, 1);
break;
case 0x02: /* MULF */
res = vax_fmul (FR[ra], FR[rb], ir, DT_F);
break;
case 0x03: /* DIVF */
res = vax_fdiv (FR[ra], FR[rb], ir, DT_F);
break;
case 0x20: /* ADDG */
res = vax_fadd (FR[ra], FR[rb], ir, DT_G, 0);
break;
case 0x21: /* SUBG */
res = vax_fadd (FR[ra], FR[rb], ir, DT_G, 1);
break;
case 0x22: /* MULG */
res = vax_fmul (FR[ra], FR[rb], ir, DT_G);
break;
case 0x23: /* DIVG */
res = vax_fdiv (FR[ra], FR[rb], ir, DT_G);
break;
case 0x25: /* CMPGEQ */
if (vax_fcmp (FR[ra], FR[rb], ir) == 0) res = FP_TRUE;
else res = 0;
break;
case 0x26: /* CMPGLT */
if (vax_fcmp (FR[ra], FR[rb], ir) < 0) res = FP_TRUE;
else res = 0;
break;
case 0x27: /* CMPGLE */
if (vax_fcmp (FR[ra], FR[rb], ir) <= 0) res = FP_TRUE;
else res = 0;
break;
case 0x1E: /* CVTDG */
if (vax_unpack_d (FR[rb], &b, ir)) res = 0;
else res = vax_rpack (&b, ir, DT_G);
break;
case 0x2C: /* CVTGF */
if (vax_unpack (FR[rb], &b, ir)) res = 0;
else res = vax_rpack (&b, ir, DT_F);
break;
case 0x2D: /* CVTGD */
if (vax_unpack (FR[rb], &b, ir)) res = 0;
else res = vax_rpack_d (&b, ir);
break;
case 0x2F: /* CVTGQ */
res = vax_cvtfi (FR[rb], ir);
break;
case 0x3C: /* CVTQF */
res = vax_cvtif (FR[rb], ir, DT_F);
break;
case 0x3E: /* CVTQG */
res = vax_cvtif (FR[rb], ir, DT_G);
break;
default:
res = FR[rc];
break;
}
if (rc != 31) FR[rc] = res & M64;
return;
}
/* VAX floating compare */
int32 vax_fcmp (t_uint64 s1, t_uint64 s2, uint32 ir)
{
UFP a, b;
if (vax_unpack (s1, &a, ir)) return +1; /* unpack, rsv? */
if (vax_unpack (s2, &b, ir)) return +1; /* unpack, rsv? */
if (s1 == s2) return 0; /* equal? */
if (a.sign != b.sign) return (a.sign? -1: +1); /* opp signs? */
return (((s1 < s2) ^ a.sign)? -1: +1); /* like signs */
}
/* VAX integer to floating convert */
t_uint64 vax_cvtif (t_uint64 val, uint32 ir, uint32 dp)
{
UFP a;
if (val == 0) return 0; /* 0? return +0 */
if (val < 0) { /* < 0? */
a.sign = 1; /* set sign */
val = NEG_Q (val); /* |val| */
}
else a.sign = 0;
a.exp = 64 + G_BIAS; /* set exp */
a.frac = val; /* set frac */
vax_norm (&a); /* normalize */
return vax_rpack (&a, ir, dp); /* round and pack */
}
/* VAX floating to integer convert - note that rounding cannot cause a
carry unless the fraction has been shifted right at least FP_GUARD
places; in which case a carry out is impossible */
t_uint64 vax_cvtfi (t_uint64 op, uint32 ir)
{
UFP a;
uint32 rndm = I_GETFRND (ir);
int32 ubexp;
if (vax_unpack (op, &a, ir)) return 0; /* unpack, rsv? */
ubexp = a.exp - G_BIAS; /* unbiased exp */
if (ubexp < 0) return 0; /* zero or too small? */
if (ubexp <= UF_V_NM) { /* in range? */
a.frac = a.frac >> (UF_V_NM - ubexp); /* leave rnd bit */
if (rndm) a.frac = a.frac + 1; /* not chopped, round */
a.frac = a.frac >> 1; /* now justified */
if ((a.frac > (a.sign? IMMAX: IPMAX)) && /* out of range? */
(ir & I_FTRP_V)) /* trap enabled? */
arith_trap (TRAP_IOV, ir); /* set overflow */
}
else {
if (ubexp > (UF_V_NM + 64)) a.frac = 0; /* out of range */
else a.frac = (a.frac << (ubexp - UF_V_NM - 1)) & M64; /* no rnd bit */
if (ir & I_FTRP_V) /* trap enabled? */
arith_trap (TRAP_IOV, ir); /* set overflow */
}
return (a.sign? NEG_Q (a.frac): a.frac);
}
/* VAX floating add */
t_uint64 vax_fadd (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp, t_bool sub)
{
UFP a, b, t;
uint32 sticky;
int32 ediff;
if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */
if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */
if (sub) b.sign = b.sign ^ 1; /* sub? invert b sign */
if (a.exp == 0) a = b; /* s1 = 0? */
else if (b.exp) { /* s2 != 0? */
if ((a.exp < b.exp) || /* |s1| < |s2|? swap */
((a.exp == b.exp) && (a.frac < b.frac))) {
t = a;
a = b;
b = t;
}
ediff = a.exp - b.exp; /* exp diff */
if (a.sign ^ b.sign) { /* eff sub? */
if (ediff > 63) b.frac = 1; /* >63? retain sticky */
else if (ediff) { /* [1,63]? shift */
sticky = ((b.frac << (64 - ediff)) & M64)? 1: 0; /* lost bits */
b.frac = (b.frac >> ediff) | sticky;
}
a.frac = (a.frac - b.frac) & M64; /* subtract fractions */
vax_norm (&a); /* normalize */
}
else { /* eff add */
if (ediff > 63) b.frac = 0; /* >63? b disappears */
else if (ediff) b.frac = b.frac >> ediff; /* denormalize */
a.frac = (a.frac + b.frac) & M64; /* add frac */
if (a.frac < b.frac) { /* chk for carry */
a.frac = UF_NM | (a.frac >> 1); /* shift in carry */
a.exp = a.exp + 1; /* skip norm */
}
}
} /* end else if */
return vax_rpack (&a, ir, dp); /* round and pack */
}
/* VAX floating multiply */
t_uint64 vax_fmul (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp)
{
UFP a, b;
if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */
if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */
if ((a.exp == 0) || (b.exp == 0)) return 0; /* zero argument? */
a.sign = a.sign ^ b.sign; /* sign of result */
a.exp = a.exp + b.exp - G_BIAS; /* add exponents */
uemul64 (a.frac, b.frac, &a.frac); /* mpy fractions */
vax_norm (&a); /* normalize */
return vax_rpack (&a, ir, dp); /* round and pack */
}
/* VAX floating divide
Needs to develop at least one rounding bit. Since the first
divide step can fail, develop 2 more bits than the precision of
the fraction. */
t_uint64 vax_fdiv (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp)
{
UFP a, b;
if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */
if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */
if (b.exp == 0) { /* divr = 0? */
arith_trap (TRAP_DZE, ir); /* dze trap */
return 0;
}
if (a.exp == 0) return 0; /* divd = 0? */
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp - b.exp + G_BIAS + 1; /* unbiased exp */
a.frac = a.frac >> 1; /* allow 1 bit left */
b.frac = b.frac >> 1;
a.frac = ufdiv64 (a.frac, b.frac, 55, NULL); /* divide */
vax_norm (&a); /* normalize */
return vax_rpack (&a, ir, dp); /* round and pack */
}
/* VAX floating square root */
t_uint64 vax_sqrt (uint32 ir, uint32 dp)
{
t_uint64 op;
UFP b;
op = FR[I_GETRB (ir)]; /* get F[rb] */
if (vax_unpack (op, &b, ir)) return 0; /* unpack, rsv? */
if (b.exp == 0) return 0; /* zero? */
if (b.sign) { /* minus? */
arith_trap (TRAP_INV, ir); /* invalid operand */
return 0;
}
b.exp = ((b.exp + 1 - G_BIAS) >> 1) + G_BIAS; /* result exponent */
b.frac = fsqrt64 (b.frac, b.exp); /* result fraction */
return vax_rpack (&b, ir, dp); /* round and pack */
}
/* Support routines */
t_bool vax_unpack (t_uint64 op, UFP *r, uint32 ir)
{
r->sign = FPR_GETSIGN (op); /* get sign */
r->exp = FPR_GETEXP (op); /* get exponent */
r->frac = FPR_GETFRAC (op); /* get fraction */
if (r->exp == 0) { /* exp = 0? */
if (op != 0) arith_trap (TRAP_INV, ir); /* rsvd op? */
r->frac = r->sign = 0;
return TRUE;
}
r->frac = (r->frac | FPR_HB) << FPR_GUARD; /* ins hidden bit, guard */
return FALSE;
}
t_bool vax_unpack_d (t_uint64 op, UFP *r, uint32 ir)
{
r->sign = FDR_GETSIGN (op); /* get sign */
r->exp = FDR_GETEXP (op); /* get exponent */
r->frac = FDR_GETFRAC (op); /* get fraction */
if (r->exp == 0) { /* exp = 0? */
if (op != 0) arith_trap (TRAP_INV, ir); /* rsvd op? */
r->frac = r->sign = 0;
return TRUE;
}
r->exp = r->exp + G_BIAS - D_BIAS; /* change to G bias */
r->frac = (r->frac | FDR_HB) << FDR_GUARD; /* ins hidden bit, guard */
return FALSE;
}
/* VAX normalize */
void vax_norm (UFP *r)
{
int32 i;
static t_uint64 normmask[5] = {
0xc000000000000000, 0xf000000000000000, 0xff00000000000000,
0xffff000000000000, 0xffffffff00000000
};
static int32 normtab[6] = { 1, 2, 4, 8, 16, 32 };
r->frac = r->frac & M64;
if (r->frac == 0) { /* if fraction = 0 */
r->sign = r->exp = 0; /* result is 0 */
return;
}
while ((r->frac & UF_NM) == 0) { /* normalized? */
for (i = 0; i < 5; i++) { /* find first 1 */
if (r->frac & normmask[i]) break;
}
r->frac = r->frac << normtab[i]; /* shift frac */
r->exp = r->exp - normtab[i]; /* decr exp */
}
return;
}
/* VAX round and pack */
t_uint64 vax_rpack (UFP *r, uint32 ir, uint32 dp)
{
uint32 rndm = I_GETFRND (ir);
static const t_uint64 roundbit[2] = { UF_FRND, UF_GRND };
static const int32 expmax[2] = { G_BIAS - F_BIAS + F_M_EXP, G_M_EXP };
static const int32 expmin[2] = { G_BIAS - F_BIAS, 0 };
if (r->frac == 0) return 0; /* result 0? */
if (rndm) { /* round? */
r->frac = (r->frac + roundbit[dp]) & M64; /* add round bit */
if ((r->frac & UF_NM) == 0) { /* carry out? */
r->frac = (r->frac >> 1) | UF_NM; /* renormalize */
r->exp = r->exp + 1;
}
}
if (r->exp > expmax[dp]) { /* ovflo? */
arith_trap (TRAP_OVF, ir); /* set trap */
r->exp = expmax[dp]; /* return max */
}
if (r->exp <= expmin[dp]) { /* underflow? */
if (ir & I_FTRP_V) arith_trap (TRAP_UNF, ir); /* enabled? set trap */
return 0; /* underflow to 0 */
}
return (((t_uint64) r->sign) << FPR_V_SIGN) |
(((t_uint64) r->exp) << FPR_V_EXP) |
((r->frac >> FPR_GUARD) & FPR_FRAC);
}
t_uint64 vax_rpack_d (UFP *r, uint32 ir)
{
if (r->frac == 0) return 0; /* result 0? */
r->exp = r->exp + D_BIAS - G_BIAS; /* rebias */
if (r->exp > FDR_M_EXP) { /* ovflo? */
arith_trap (TRAP_OVF, ir); /* set trap */
r->exp = FDR_M_EXP; /* return max */
}
if (r->exp <= 0) { /* underflow? */
if (ir & I_FTRP_V) arith_trap (TRAP_UNF, ir); /* enabled? set trap */
return 0; /* underflow to 0 */
}
return (((t_uint64) r->sign) << FDR_V_SIGN) |
(((t_uint64) r->exp) << FDR_V_EXP) |
((r->frac >> FDR_GUARD) & FDR_FRAC);
}

214
alpha/alpha_io.c Normal file
View file

@ -0,0 +1,214 @@
/* alpha_io.c: Alpha I/O and miscellaneous devices
Copyright (c) 2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rom boot ROM
*/
#include "alpha_defs.h"
#include "alpha_sys_defs.h"
t_uint64 *rom = NULL; /* boot ROM */
extern DEVICE *sim_devices[];
t_bool rom_rd (t_uint64 pa, t_uint64 *val, uint32 lnt);
t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt);
t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);
t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw);
t_stat rom_reset (DEVICE *dptr);
/* ROM data structures
rom_dev ROM device descriptor
rom_unit ROM units
rom_reg ROM register list
*/
DIB rom_dib = {
ROMBASE, ROMBASE + ROMSIZE, &rom_rd, &rom_wr, 0
};
UNIT rom_unit = {
UDATA (NULL, UNIT_FIX+UNIT_BINK, ROMSIZE)
};
REG rom_reg[] = {
{ NULL }
};
DEVICE rom_dev = {
"ROM", &rom_unit, rom_reg, NULL,
1, 16, 24, 8, 16, 64,
&rom_ex, &rom_dep, &rom_reset,
NULL, NULL, NULL,
&rom_dib, DEV_DIB
};
/* ReadIO - read IO space
Inputs:
pa = physical address
*dat = pointer to data
lnt = length (BWLQ)
Output:
TRUE if read succeeds, else FALSE
*/
t_bool ReadIO (t_uint64 pa, t_uint64 *dat, uint32 lnt)
{
DEVICE *dptr;
uint32 i;
for (i = 0; sim_devices[i] != NULL; i++) {
dptr = sim_devices[i];
if (dptr->flags & DEV_DIB) {
DIB *dibp = (DIB *) dptr->ctxt;
if ((pa >= dibp->low) && (pa < dibp->high))
return dibp->read (pa, dat, lnt);
}
}
return FALSE;
}
/* WriteIO - write register space
Inputs:
ctx = CPU context
pa = physical address
val = data to write, right justified in 64b quadword
lnt = length (BWLQ)
Output:
TRUE if write succeeds, else FALSE
*/
t_bool WriteIO (t_uint64 pa, t_uint64 dat, uint32 lnt)
{
DEVICE *dptr;
uint32 i;
for (i = 0; sim_devices[i] != NULL; i++) {
dptr = sim_devices[i];
if (dptr->flags & DEV_DIB) {
DIB *dibp = (DIB *) dptr->ctxt;
if ((pa >= dibp->low) && (pa < dibp->high))
return dibp->write (pa, dat, lnt);
}
}
return FALSE;
}
/* Boot ROM read */
t_bool rom_rd (t_uint64 pa, t_uint64 *val, uint32 lnt)
{
uint32 sc, rg = ((uint32) ((pa - ROMBASE) & (ROMSIZE - 1))) >> 3;
switch (lnt) {
case L_BYTE:
sc = (((uint32) pa) & 7) * 8;
*val = (rom[rg] >> sc) & M8;
break;
case L_WORD:
sc = (((uint32) pa) & 6) * 8;
*val = (rom[rg] >> sc) & M16;
break;
case L_LONG:
if (pa & 4) *val = (rom[rg] >> 32) & M32;
else *val = rom[rg] & M32;
break;
case L_QUAD:
*val = rom[rg];
break;
}
return TRUE;
}
/* Boot ROM write */
t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt)
{
uint32 sc, rg = ((uint32) ((pa - ROMBASE) & (ROMSIZE - 1))) >> 3;
switch (lnt) {
case L_BYTE:
sc = (((uint32) pa) & 7) * 8;
rom[rg] = (rom[rg] & ~(((t_uint64) M8) << sc)) | (((t_uint64) (val & M8)) << sc);
break;
case L_WORD:
sc = (((uint32) pa) & 6) * 8;
rom[rg] = (rom[rg] & ~(((t_uint64) M16) << sc)) | (((t_uint64) (val & M16)) << sc);
break;
case L_LONG:
if (pa & 4) rom[rg] = ((t_uint64) (rom[rg] & M32)) | (((t_uint64) (val & M32)) << 32);
else rom[rg] = (rom[rg] & ~((t_uint64) M32)) | ((t_uint64) val & M32);
break;
case L_QUAD:
rom[rg] = val;
break;
}
return TRUE;
}
/* ROM examine */
t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)
{
uint32 addr = (uint32) exta;
if (vptr == NULL) return SCPE_ARG;
if (addr >= ROMSIZE) return SCPE_NXM;
*vptr = rom[addr >> 3];
return SCPE_OK;
}
/* ROM deposit */
t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)
{
uint32 addr = (uint32) exta;
if (addr >= ROMSIZE) return SCPE_NXM;
rom[addr >> 3] = val;
return SCPE_OK;
}
/* ROM reset */
t_stat rom_reset (DEVICE *dptr)
{
if (rom == NULL) rom = (t_uint64 *) calloc (ROMSIZE >> 3, sizeof (t_uint64));
if (rom == NULL) return SCPE_MEM;
return SCPE_OK;
}

308
alpha/alpha_mmu.c Normal file
View file

@ -0,0 +1,308 @@
/* alpha_mmu.c - Alpha memory management simulator
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This module contains the routines for
ReadB,W,L,Q - read aligned virtual
ReadAccL,Q - read aligned virtual, special access check
ReadPB,W,L,Q - read aligned physical
WriteB,W,L,Q - write aligned virtual
WriteAccL,Q - write aligned virtual, special access check
WritePB,W,L,Q - write aligned physical
The TLB is organized for optimum lookups and is broken up into three fields:
tag VA<42:13> for an 8KB page system
pte PTE<31:0>, <31:16> are zero; FOE, FOR, FOW stored inverted
pfn PFN<31:0> left shifted by page size
The inversion of FOE, FOR, FOW means that all checked bits must be one
for a reference to proceed.
All Alpha implementations provide support for a 43b superpage for Unix,
and a 32b superpage for NT:
43b superpage 0xFFFFFC0000000000:0xFFFFFDFFFFFFFFFF
32b superpage 0xFFFFFFFF80000000:0xFFFFFFFFBFFFFFFF
*/
#include "alpha_defs.h"
extern t_uint64 trans_i (t_uint64 va);
extern t_uint64 trans_d (t_uint64 va, uint32 acc);
extern t_uint64 *M;
extern t_uint64 p1;
extern uint32 pal_mode, dmapen;
extern uint32 cm_eacc, cm_racc, cm_wacc;
extern jmp_buf save_env;
extern UNIT cpu_unit;
/* Read virtual aligned
Inputs:
va = virtual address
Output:
returned data, right justified
*/
t_uint64 ReadB (t_uint64 va)
{
t_uint64 pa;
if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */
else pa = va;
return ReadPB (pa);
}
t_uint64 ReadW (t_uint64 va)
{
t_uint64 pa;
if (va & 1) ABORT1 (va, EXC_ALIGN); /* must be W aligned */
if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */
else pa = va;
return ReadPW (pa);
}
t_uint64 ReadL (t_uint64 va)
{
t_uint64 pa;
if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */
if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */
else pa = va;
return ReadPL (pa);
}
t_uint64 ReadQ (t_uint64 va)
{
t_uint64 pa;
if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */
if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */
else pa = va;
return ReadPQ (pa);
}
/* Read with generalized access controls - used by PALcode */
t_uint64 ReadAccL (t_uint64 va, uint32 acc)
{
t_uint64 pa;
if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */
if (dmapen) pa = trans_d (va, acc); /* mapping on? */
else pa = va;
return ReadPL (pa);
}
t_uint64 ReadAccQ (t_uint64 va, uint32 acc)
{
t_uint64 pa;
if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */
if (dmapen) pa = trans_d (va, acc); /* mapping on? */
else pa = va;
return ReadPQ (pa);
}
/* Read instruction */
uint32 ReadI (t_uint64 va)
{
t_uint64 pa;
if (!pal_mode) pa = trans_i (va); /* mapping on? */
else pa = va;
return (uint32) ReadPL (pa);
}
/* Write virtual aligned
Inputs:
va = virtual address
val = data to be written, right justified in 32b or 64b
Output:
none
*/
void WriteB (t_uint64 va, t_uint64 dat)
{
t_uint64 pa;
if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */
else pa = va;
WritePB (pa, dat);
return;
}
void WriteW (t_uint64 va, t_uint64 dat)
{
t_uint64 pa;
if (va & 1) ABORT1 (va, EXC_ALIGN); /* must be W aligned */
if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */
else pa = va;
WritePW (pa, dat);
return;
}
void WriteL (t_uint64 va, t_uint64 dat)
{
t_uint64 pa;
if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */
if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */
else pa = va;
WritePL (pa, dat);
return;
}
void WriteQ (t_uint64 va, t_uint64 dat)
{
t_uint64 pa;
if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */
if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */
else pa = va;
WritePQ (pa, dat);
return;
}
/* Write with generalized access controls - used by PALcode */
void WriteAccL (t_uint64 va, t_uint64 dat, uint32 acc)
{
t_uint64 pa;
if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */
if (dmapen) pa = trans_d (va, acc); /* mapping on? */
else pa = va;
WritePL (pa, dat);
return;
}
void WriteAccQ (t_uint64 va, t_uint64 dat, uint32 acc)
{
t_uint64 pa;
if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */
if (dmapen) pa = trans_d (va, acc); /* mapping on? */
else pa = va;
WritePQ (pa, dat);
return;
}
/* Read and write physical aligned - access point to I/O */
INLINE t_uint64 ReadPB (t_uint64 pa)
{
t_uint64 val;
if (ADDR_IS_MEM (pa)) {
uint32 bo = ((uint32) pa) & 07;
return (((M[pa >> 3] >> (bo << 3))) & M8);
}
if (ReadIO (pa, &val, L_BYTE)) return val;
return 0;
}
INLINE t_uint64 ReadPW (t_uint64 pa)
{
t_uint64 val;
if (ADDR_IS_MEM (pa)) {
uint32 bo = ((uint32) pa) & 06;
return (((M[pa >> 3] >> (bo << 3))) & M16);
}
if (ReadIO (pa, &val, L_WORD)) return val;
return 0;
}
INLINE t_uint64 ReadPL (t_uint64 pa)
{
t_uint64 val;
if (ADDR_IS_MEM (pa)) {
if (pa & 4) return (((M[pa >> 3] >> 32)) & M32);
return ((M[pa >> 3]) & M32);
}
if (ReadIO (pa, &val, L_LONG)) return val;
return 0;
}
INLINE t_uint64 ReadPQ (t_uint64 pa)
{
t_uint64 val;
if (ADDR_IS_MEM (pa)) return M[pa >> 3];
if (ReadIO (pa, &val, L_QUAD)) return val;
return 0;
}
INLINE void WritePB (t_uint64 pa, t_uint64 dat)
{
dat = dat & M8;
if (ADDR_IS_MEM (pa)) {
uint32 bo = ((uint32) pa) & 07;
M[pa >> 3] = (M[pa >> 3] & ~(((t_uint64) M8) << (bo << 3))) |
(dat << (bo << 3));
}
else WriteIO (pa, dat, L_BYTE);
return;
}
INLINE void WritePW (t_uint64 pa, t_uint64 dat)
{
dat = dat & M16;
if (ADDR_IS_MEM (pa)) {
uint32 bo = ((uint32) pa) & 07;
M[pa >> 3] = (M[pa >> 3] & ~(((t_uint64) M16) << (bo << 3))) |
(dat << (bo << 3));
}
else WriteIO (pa, dat, L_WORD);
return;
}
INLINE void WritePL (t_uint64 pa, t_uint64 dat)
{
dat = dat & M32;
if (ADDR_IS_MEM (pa)) {
if (pa & 4) M[pa >> 3] = (M[pa >> 3] & M32) |
(dat << 32);
else M[pa >> 3] = (M[pa >> 3] & ~((t_uint64) M32)) | dat;
}
else WriteIO (pa, dat, L_LONG);
return;
}
INLINE void WritePQ (t_uint64 pa, t_uint64 dat)
{
if (ADDR_IS_MEM (pa)) M[pa >> 3] = dat;
else WriteIO (pa, dat, L_QUAD);
return;
}

814
alpha/alpha_sys.c Normal file
View file

@ -0,0 +1,814 @@
/* alpha_sys.c: Alpha simulator interface
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include "alpha_defs.h"
#include <ctype.h>
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern int32 sim_switches;
extern uint32 pal_type;
t_stat fprint_sym_m (FILE *of, t_addr addr, uint32 inst);
t_stat parse_sym_m (char *cptr, t_addr addr, t_value *inst);
int32 parse_reg (char *cptr);
extern t_stat fprint_pal_hwre (FILE *of, uint32 inst);
extern t_stat parse_pal_hwre (char *cptr, t_value *inst);
extern t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt);
/* SCP data structures and interface routines
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 1;
const char *sim_stop_messages[] = {
"Unknown error",
"HALT instruction",
"Breakpoint",
"Unsupported PAL variation",
"Kernel stack not valid",
"Unknown abort code",
"Memory management error"
};
/* Binary loader
The binary loader handles absolute system images, that is, system
images linked /SYSTEM. These are simply a byte stream, with no
origin or relocation information.
-r load ROM
-o specify origin
*/
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
t_stat r;
int32 i;
t_uint64 origin;
if (flag) return SCPE_ARG; /* dump? */
origin = 0; /* memory */
if (sim_switches & SWMASK ('O')) { /* origin? */
origin = get_uint (cptr, 16, 0xFFFFFFFF, &r);
if (r != SCPE_OK) return SCPE_ARG;
}
while ((i = getc (fileref)) != EOF) { /* read byte stream */
if (sim_switches & SWMASK ('R')) { /* ROM? */
if (!rom_wr (origin, i, L_BYTE))
return SCPE_NXM;
}
else if (ADDR_IS_MEM (origin)) /* valid memory? */
WritePB (origin, i);
else return SCPE_NXM;
origin = origin + 1;
}
return SCPE_OK;
}
/* Opcode mnemonics table */
#define CL_NO 0 /* no operand */
#define CL_BR 1 /* branch */
#define CL_MR 2 /* memory reference */
#define CL_IO 3 /* integer opr */
#define CL_FO 4 /* floating opr */
#define CL_MO 5 /* memory opr */
#define CL_JP 6 /* jump */
#define CL_HW 7 /* hardware */
#define CL_M_PAL 0x00F0
#define CL_V_PAL 4
#define CL_VMS (1u << (PAL_VMS + CL_V_PAL))
#define CL_UNIX (1u << (PAL_UNIX + CL_V_PAL))
#define CL_NT (1u << (PAL_NT + CL_V_PAL))
#define FL_RA 0x0100
#define FL_RB 0x0200
#define FL_RC 0x0400
#define FL_RBI 0x0800
#define FL_MDP 0x1000
#define FL_BDP 0x2000
#define FL_JDP 0x4000
#define FL_LIT 0x8000
#define CL_CLASS 0x000F
#define PAL_MASK(x) (1u << (pal_type + CL_V_PAL))
#define C_NO CL_NO
#define C_PCM CL_NO | CL_VMS | CL_UNIX | CL_NT
#define C_PVM CL_NO | CL_VMS
#define C_PUN CL_NO | CL_UNIX
#define C_PNT CL_NO | CL_NT
#define C_BR CL_BR | FL_RA | FL_BDP
#define C_MR CL_MR | FL_RA | FL_RB | FL_RBI | FL_MDP
#define C_FE CL_MO | FL_RB | FL_RBI
#define C_RV CL_MO | FL_RA
#define C_MO CL_MO | FL_RA | FL_RB
#define C_IO CL_IO | FL_RA | FL_RB | FL_RC | FL_LIT
#define C_IAC CL_IO | FL_RA | FL_RC
#define C_IBC CL_IO | FL_RB | FL_RC | FL_LIT
#define C_FO CL_FO | FL_RA | FL_RB | FL_RC
#define C_FAC CL_FO | FL_RA | FL_RC
#define C_FBC CL_FO | FL_RB | FL_RC
#define C_JP CL_JP | FL_RA | FL_RB | FL_RBI | FL_JDP
#define C_HW CL_HW
uint32 masks[8] = {
0xFFFFFFFF, 0xFC000000,
0xFC000000, 0xFC000FE0,
0xFC00FFE0, 0xFC00FFFF,
0xFC00C000, 0xFC000000
};
const char *opcode[] = {
"HALT", "DRAINA", "CFLUSH", "LDQP", /* VMS PALcode */
"STQP", "SWPCTX", "MFPR_ASN", "MTPR_ASTEN",
"MTPR_ASTSR", "CSERVE", "SWPPAL", "MFPR_FEN",
"MTPR_FEN", "MTPR_IPIR", "MFPR_IPL", "MTPR_IPL",
"MFPR_MCES", "MTPR_MCES", "MFPR_PCBB", "MFPR_PRBR",
"MTPR_PRBR", "MFPR_PTBR", "MFPR_SCBB", "MTPR_SCBB",
"MTPR_SIRR", "MFPR_SISR", "MFPR_TBCHK", "MTPR_TBIA",
"MTPR_TBIAP", "MTPR_TBIS", "MFPR_ESP", "MTPR_ESP",
"MFPR_SSP", "MTPR_SSP", "MFPR_USP", "MTPR_USP",
"MTPR_TBISD", "MTPR_TBISI", "MFPR_ASTEN", "MFPR_ASTSR",
"MFPR_VTBR", "MTPR_VTBR", "MTPR_PERFMON", "MTPR_DATFX",
"MFPR_VIRBND", "MTPR_VIRBND", "MFPR_SYSPTBR", "MTPR_SYSPTBR",
"WTINT", "MFPR_WHAMI",
"BPT", "BUGCHK", "CHME", "CHMK",
"CHMS", "CHMU", "IMB", "INSQHIL",
"INSQTIL", "INSQHIQ", "INSQTIQ", "INSQUEL",
"INSQUEQ", "INSQUEL/D", "INSQUEQ/D", "PROBER",
"PROBEW", "RD_PS", "REI", "REMQHIL",
"REMQTIL", "REMQHIQ", "REMQTIQ", "REMQUEL",
"REMQUEQ", "REMQUEL/D", "REMQUEQ/D", "SWASTEN",
"WR_PS_SW", "RSCC", "RD_UNQ", "WR_UNQ",
"AMOVRR", "AMOVRM", "INSQHILR", "INSQTILR",
"INSQHIQR", "INSQTIQR", "REMQHILR", "REMQTILR",
"REMQHIQR", "REMQTIQR", "GENTRAP", "CLRFEN",
"RDMCES", "WRMCES", "WRVIRBND", "WRSYSPTBR", /* UNIX PALcode */
"WRFEN", "WRVPTPTR", "WRASN",
"SWPCTX", "WRVAL", "RDVAL", "TBI",
"WRENT", "SWPIPL", "RDPS", "WRKGP",
"WRUSP", "WRPERFMON", "RDUSP",
"WHAMI", "RETSYS", "RTI",
"URTI", "RDUNIQUE", "WRUNIQUE",
"LDA", "LDAH", "LDBU", "LDQ_U",
"LDWU", "STW", "STB", "STQ_U",
"ADDL", "S4ADDL", "SUBL", "S4SUBL",
"CMPBGE", "S8ADDL", "S8SUBL", "CMPULT",
"ADDQ", "S4ADDQ", "SUBQ", "S4SUBQ",
"CMPEQ", "S8ADDQ", "S8SUBQ", "CMPULE",
"ADDL/V", "SUBL/V", "CMPLT",
"ADDQ/V", "SUBQ/V", "CMPLE",
"AND", "BIC", "CMOVLBS", "CMOVLBC",
"BIS", "CMOVEQ", "CMOVNE", "ORNOT",
"XOR", "CMOVLT", "CMOVGE", "EQV",
"CMOVLE", "CMOVGT",
"MSKBL", "EXTBL", "INSBL",
"MSKWL", "EXTWL", "INSWL",
"MSKLL", "EXTLL", "INSLL",
"ZAP", "ZAPNOT", "MSKQL", "SRL",
"EXTQL", "SLL", "INSQL", "SRA",
"MSKWQ", "EXTWQ", "INSWQ",
"MSKLQ", "EXTLQ", "INSLQ",
"MSKQH", "EXTQH", "INSQH",
"MULL", "MULQ", "UMULH",
"MULL/V", "MULLQ/V",
"ITOFS", "ITOFF", "ITOFT",
"SQRTF/C", "SQRTF", "SQRTF/UC", "SQRTF/U",
"SQRTF/SC", "SQRTF/S", "SQRTF/SUC", "SQRTF/SU",
"SQRTG/C", "SQRTG", "SQRTG/UC", "SQRTG/U",
"SQRTG/SC", "SQRTG/S", "SQRTG/SUC", "SQRTG/SU",
"SQRTS/C", "SQRTS/M", "SQRTS", "SQRTS/D",
"SQRTS/UC", "SQRTS/UM", "SQRTS/U", "SQRTS/UD",
"SQRTS/SUC", "SQRTS/SUM", "SQRTS/SU", "SQRTS/SUD",
"SQRTS/SUIC", "SQRTS/SUIM", "SQRTS/SUI", "SQRTS/SUID",
"SQRTT/C", "SQRTT/M", "SQRTT", "SQRTT/D",
"SQRTT/UC", "SQRTT/UM", "SQRTT/U", "SQRTT/UD",
"SQRTT/SUC", "SQRTT/SUM", "SQRTT/SU", "SQRTT/SUD",
"SQRTT/SUIC", "SQRTT/SUIM", "SQRTT/SUI", "SQRTT/SUID",
"ADDF/C", "ADDF", "ADDF/UC", "ADDF/U",
"ADDF/SC", "ADDF/S", "ADDF/SUC", "ADDF/SU",
"SUBF/C", "SUBF", "SUBF/UC", "SUBF/U",
"SUBF/SC", "SUBF/S", "SUBF/SUC", "SUBF/SU",
"MULF/C", "MULF", "MULF/UC", "MULF/U",
"MULF/SC", "MULF/S", "MULF/SUC", "MULF/SU",
"DIVF/C", "DIVF", "DIVF/UC", "DIVF/U",
"DIVF/SC", "DIVF/S", "DIVF/SUC", "DIVF/SU",
"ADDG/C", "ADDG", "ADDG/UC", "ADDG/U",
"ADDG/SC", "ADDG/S", "ADDG/SUC", "ADDG/SU",
"SUBG/C", "SUBG", "SUBG/UC", "SUBG/U",
"SUBG/SC", "SUBG/S", "SUBG/SUC", "SUBG/SU",
"MULG/C", "MULG", "MULG/UC", "MULG/U",
"MULG/SC", "MULG/S", "MULG/SUC", "MULG/SU",
"DIVG/C", "DIVG", "DIVG/UC", "DIVG/U",
"DIVG/SC", "DIVG/S", "DIVG/SUC", "DIVG/SU",
"CVTDG/C", "CVTDG", "CVTDG/UC", "CVTDG/U",
"CVTDG/SC", "CVTDG/S", "CVTDG/SUC", "CVTDG/SU",
"CVTGF/C", "CVTGF", "CVTGF/UC", "CVTGF/U",
"CVTGF/SC", "CVTGF/S", "CVTGF/SUC", "CVTGF/SU",
"CVTGD/C", "CVTGD", "CVTGD/UC", "CVTGD/U",
"CVTGD/SC", "CVTGD/S", "CVTGD/SUC", "CVTGD/SU",
"CVTGQ/C", "CVTGQ", "CVTGQ/VC", "CVTGQ/V",
"CVTGQ/SC", "CVTGQ/S", "CVTGQ/SVC", "CVTGQ/SV",
"CVTQF/C", "CVTQF", "CVTQG/C", "CVTQG",
"CMPGEQ/C", "CMPGEQ/SC", "CMPGLT/C", "CMPGLT/SC",
"CMPGLE/C", "CMPGLE/SC",
"ADDS/C", "ADDS/M", "ADDS", "ADDS/D",
"ADDS/UC", "ADDS/UM", "ADDS/U", "ADDS/UD",
"ADDS/SUC", "ADDS/SUM", "ADDS/SU", "ADDS/SUD",
"ADDS/SUIC", "ADDS/SUIM", "ADDS/SUI", "ADDS/SUID",
"SUBS/C", "SUBS/M", "SUBS", "SUBS/D",
"SUBS/UC", "SUBS/UM", "SUBS/U", "SUBS/UD",
"SUBS/SUC", "SUBS/SUM", "SUBS/SU", "SUBS/SUD",
"SUBS/SUIC", "SUBS/SUIM", "SUBS/SUI", "SUBS/SUID",
"MULS/C", "MULS/M", "MULS", "MULS/D",
"MULS/UC", "MULS/UM", "MULS/U", "MULS/UD",
"MULS/SUC", "MULS/SUM", "MULS/SU", "MULS/SUD",
"MULS/SUIC", "MULS/SUIM", "MULS/SUI", "MULS/SUID",
"DIVS/C", "DIVS/M", "DIVS", "DIVS/D",
"DIVS/UC", "DIVS/UM", "DIVS/U", "DIVS/UD",
"DIVS/SUC", "DIVS/SUM", "DIVS/SU", "DIVS/SUD",
"DIVS/SUIC", "DIVS/SUIM", "DIVS/SUI", "DIVS/SUID",
"ADDT/C", "ADDT/M", "ADDT", "ADDT/D",
"ADDT/UC", "ADDT/UM", "ADDT/U", "ADDT/UD",
"ADDT/SUC", "ADDT/SUM", "ADDT/SU", "ADDT/SUD",
"ADDT/SUIC", "ADDT/SUIM", "ADDT/SUI", "ADDT/SUID",
"SUBT/C", "SUBT/M", "SUBT", "SUBT/D",
"SUBT/UC", "SUBT/UM", "SUBT/U", "SUBT/UD",
"SUBT/SUC", "SUBT/SUM", "SUBT/SU", "SUBT/SUD",
"SUBT/SUIC", "SUBT/SUIM", "SUBT/SUI", "SUBT/SUID",
"MULT/C", "MULT/M", "MULT", "MULT/D",
"MULT/UC", "MULT/UM", "MULT/U", "MULT/UD",
"MULT/SUC", "MULT/SUM", "MULT/SU", "MULT/SUD",
"MULT/SUIC", "MULT/SUIM", "MULT/SUI", "MULT/SUID",
"DIVT/C", "DIVT/M", "DIVT", "DIVT/D",
"DIVT/UC", "DIVT/UM", "DIVT/U", "DIVT/UD",
"DIVT/SUC", "DIVT/SUM", "DIVT/SU", "DIVT/SUD",
"DIVT/SUIC", "DIVT/SUIM", "DIVT/SUI", "DIVT/SUID",
"CVTTS/C", "CVTTS/M", "CVTTS", "CVTTS/D",
"CVTTS/UC", "CVTTS/UM", "CVTTS/U", "CVTTS/UD",
"CVTTS/SUC", "CVTTS/SUM", "CVTTS/SU", "CVTTS/SUD",
"CVTTS/SUIC", "CVTTS/SUIM", "CVTTS/SUI", "CVTTS/SUID",
"CVTTQ/C", "CVTTQ/M", "CVTTQ", "CVTTQ/D",
"CVTTQ/VC", "CVTTQ/VM", "CVTTQ/V", "CVTTQ/VD",
"CVTTQ/SVC", "CVTTQ/SVM", "CVTTQ/SV", "CVTTQ/SVD",
"CVTTQ/SVIC", "CVTTQ/SVIM", "CVTTQ/SVI", "CVTTQ/SVID",
"CVTQS/C", "CVTQS/M", "CVTQS", "CVTQS/D",
"CVTQS/SUIC", "CVTQS/SUIM", "CVTQS/SUI", "CVTQS/SUID",
"CVTQT/C", "CVTQT/M", "CVTQT", "CVTQT/D",
"CVTQT/SUIC", "CVTQT/SUIM", "CVTQT/SUI", "CVTQT/SUID",
"CMPTUN/C", "CMPTUN/S", "CMPTEQ/C", "CMPTEQ/S",
"CMPTLT/C", "CMPTLT/S", "CMPTLE/C", "CMPTLE/S",
"CVTLQ", "CPYS", "CPYSN", "CPYSE",
"MT_FPCR", "MF_FPCR",
"FCMOVEQ", "FCMOVNE", "FCMOVLT",
"FCMOVGE", "FCMOVLE", "FCMOVGT",
"CVTQL", "CVTQL/V", "CVTQL/SV",
"TRAPB", "EXCB", "MB", "WMB",
"FETCH", "FETCH_M", "RPCC",
"RC", "RS",
"JMP", "JSR", "RET", "JSR_COROUTINE",
"SEXTB", "SEXTW",
"CTPOP", "PERR", "CTLZ", "CTTZ",
"UNPKBW", "UNPKBL", "PKWB", "PKLB",
"MINSB8", "MINSW4", "MINUB8", "MINUW4",
"MAXSB8", "MAXSW4", "MAXUB8", "MAXUW4",
"FTOIT", "FTOIS",
"LDF", "LDG", "LDS", "LDT",
"STS", "STG", "STS", "STT",
"LDL", "LDQ", "LDL_L", "LDQ_L",
"STL", "STQ", "STL_L", "STQ_L",
"BR", "FBEQ", "FBLT", "FBLE",
"BSR", "FBNE", "BFGE", "FBGT",
"BLBC", "BEQ", "BLT", "BLE",
"BLBS", "BNE", "BGE", "BGT",
NULL
};
const uint32 opval[] = {
0x00000000, C_PCM, 0x00000001, C_PCM, 0x00000002, C_PCM, 0x00000003, C_PVM,
0x00000004, C_PVM, 0x00000005, C_PVM, 0x00000006, C_PVM, 0x00000007, C_PVM,
0x00000008, C_PVM, 0x00000009, C_PCM, 0x0000000A, C_PCM, 0x0000000B, C_PVM,
0x0000000C, C_PVM, 0x0000000D, C_PVM, 0x0000000E, C_PVM, 0x0000000F, C_PVM,
0x00000010, C_PVM, 0x00000011, C_PVM, 0x00000012, C_PVM, 0x00000013, C_PVM,
0x00000014, C_PVM, 0x00000015, C_PVM, 0x00000016, C_PVM, 0x00000017, C_PVM,
0x00000018, C_PVM, 0x00000019, C_PVM, 0x0000001A, C_PVM, 0x0000001B, C_PVM,
0x0000001C, C_PVM, 0x0000001D, C_PVM, 0x0000001E, C_PVM, 0x0000001F, C_PVM,
0x00000020, C_PVM, 0x00000021, C_PVM, 0x00000022, C_PVM, 0x00000023, C_PVM,
0x00000024, C_PVM, 0x00000025, C_PVM, 0x00000026, C_PVM, 0x00000027, C_PVM,
0x00000029, C_PVM, 0x0000002A, C_PVM, 0x0000002B, C_PVM, 0x0000002E, C_PVM,
0x00000030, C_PVM, 0x00000031, C_PVM, 0x00000032, C_PVM, 0x00000033, C_PVM,
0x0000003E, C_PCM, 0x0000003F, C_PVM,
0x00000080, C_PCM, 0x00000081, C_PCM, 0x00000082, C_PVM, 0x00000083, C_PVM,
0x00000084, C_PVM, 0x00000085, C_PVM, 0x00000086, C_PCM, 0x00000087, C_PVM,
0x00000088, C_PVM, 0x00000089, C_PVM, 0x0000008A, C_PVM, 0x0000008B, C_PVM,
0x0000008C, C_PVM, 0x0000008D, C_PVM, 0x0000008E, C_PVM, 0x0000008F, C_PVM,
0x00000090, C_PVM, 0x00000091, C_PVM, 0x00000092, C_PVM, 0x00000093, C_PVM,
0x00000094, C_PVM, 0x00000095, C_PVM, 0x00000096, C_PVM, 0x00000097, C_PVM,
0x00000098, C_PVM, 0x00000099, C_PVM, 0x0000009A, C_PVM, 0x0000009B, C_PVM,
0x0000009C, C_PVM, 0x0000009D, C_PVM, 0x0000009E, C_PVM, 0x0000009F, C_PVM,
0x000000A0, C_PVM, 0x000000A1, C_PVM, 0x000000A2, C_PVM, 0x000000A3, C_PVM,
0x000000A4, C_PVM, 0x000000A5, C_PVM, 0x000000A6, C_PVM, 0x000000A7, C_PVM,
0x000000A8, C_PVM, 0x000000A9, C_PVM, 0x000000AA, C_PCM, 0x000000AE, C_PCM,
0x00000010, C_PUN, 0x00000011, C_PUN, 0x00000013, C_PUN, 0x00000014, C_PUN,
0x0000002B, C_PUN, 0x0000002D, C_PUN, 0x0000002E, C_PUN,
0x00000030, C_PUN, 0x00000031, C_PUN, 0x00000032, C_PUN, 0x00000033, C_PUN,
0x00000034, C_PUN, 0x00000035, C_PUN, 0x00000036, C_PUN, 0x00000037, C_PUN,
0x00000038, C_PUN, 0x00000039, C_PUN, 0x0000003A, C_PUN,
0x0000003C, C_PUN, 0x0000003D, C_PUN, 0x0000003F, C_PUN,
0x00000092, C_PUN, 0x0000009E, C_PUN, 0x0000009F, C_PUN,
0x20000000, C_MR, 0x24000000, C_MR, 0x28000000, C_MR, 0x2C000000, C_MR,
0x30000000, C_MR, 0x34000000, C_MR, 0x38000000, C_MR, 0x3C000000, C_MR,
0x40000000, C_IO, 0x40000040, C_IO, 0x40000120, C_IO, 0x40000160, C_IO,
0x400001C0, C_IO, 0x40000240, C_IO, 0x40000360, C_IO, 0x400003A0, C_IO,
0x40000400, C_IO, 0x40000440, C_IO, 0x40000520, C_IO, 0x40000560, C_IO,
0x400005A0, C_IO, 0x40000640, C_IO, 0x40000760, C_IO, 0x400007A0, C_IO,
0x40000800, C_IO, 0x40000920, C_IO, 0x400009A0, C_IO,
0x40000C00, C_IO, 0x40000D20, C_IO, 0x40000DA0, C_IO,
0x44000000, C_IO, 0x44000100, C_IO, 0x44000280, C_IO, 0x440002C0, C_IO,
0x44000400, C_IO, 0x44000480, C_IO, 0x440004C0, C_IO, 0x44000500, C_IO,
0x44000800, C_IO, 0x44000880, C_IO, 0x440008C0, C_IO, 0x44000900, C_IO,
0x44000C80, C_IO, 0x44000CC0, C_IO,
0x48000040, C_IO, 0x480000C0, C_IO, 0x48000160, C_IO,
0x48000240, C_IO, 0x480002C0, C_IO, 0x48000360, C_IO,
0x48000440, C_IO, 0x480004C0, C_IO, 0x48000560, C_IO,
0x48000600, C_IO, 0x48000620, C_IO, 0x48000640, C_IO, 0x48000680, C_IO,
0x480006C0, C_IO, 0x48000720, C_IO, 0x48000760, C_IO, 0x48000780, C_IO,
0x48000A40, C_IO, 0x48000AE0, C_IO, 0x48000B40, C_IO,
0x48000C40, C_IO, 0x48000CE0, C_IO, 0x48000D40, C_IO,
0x48000E40, C_IO, 0x48000EE0, C_IO, 0x48000F40, C_IO,
0x4C000000, C_IO, 0x4C000400, C_IO, 0x4C000600, C_IO,
0x4C000800, C_IO, 0x4C000C00, C_IO,
0x501F0080, C_FAC, 0x501F0280, C_FAC, 0x501F0480, C_FAC,
0x53E00140, C_FBC, 0x53E01140, C_FBC, 0x53E02140, C_FBC, 0x53E03140, C_FBC,
0x53E08140, C_FBC, 0x53E09140, C_FBC, 0x53E0A140, C_FBC, 0x53E0B140, C_FBC,
0x53E00540, C_FBC, 0x53E01540, C_FBC, 0x53E02540, C_FBC, 0x53E03540, C_FBC,
0x53E08540, C_FBC, 0x53E09540, C_FBC, 0x53E0A540, C_FBC, 0x53E0B540, C_FBC,
0x53E00160, C_FBC, 0x53E00960, C_FBC, 0x53E01160, C_FBC, 0x53E01960, C_FBC,
0x53E02160, C_FBC, 0x53E02960, C_FBC, 0x53E03160, C_FBC, 0x53E03960, C_FBC,
0x53E0A160, C_FBC, 0x53E0A960, C_FBC, 0x53E0B160, C_FBC, 0x53E0B960, C_FBC,
0x53E0E160, C_FBC, 0x53E0E960, C_FBC, 0x53E0F160, C_FBC, 0x53E0F960, C_FBC,
0x53E00560, C_FBC, 0x53E00D60, C_FBC, 0x53E01560, C_FBC, 0x53E01D60, C_FBC,
0x53E02560, C_FBC, 0x53E02D60, C_FBC, 0x53E03560, C_FBC, 0x53E03D60, C_FBC,
0x53E0A560, C_FBC, 0x53E0AD60, C_FBC, 0x53E0B560, C_FBC, 0x53E0BD60, C_FBC,
0x53E0E560, C_FBC, 0x53E0ED60, C_FBC, 0x53E0F560, C_FBC, 0x53E0FD60, C_FBC,
0x54000000, C_FO, 0x54001000, C_FO, 0x54002000, C_FO, 0x54003000, C_FO,
0x54008000, C_FO, 0x54009000, C_FO, 0x5400A000, C_FO, 0x5400B000, C_FO,
0x54000020, C_FO, 0x54001020, C_FO, 0x54002020, C_FO, 0x54003020, C_FO,
0x54008020, C_FO, 0x54009020, C_FO, 0x5400A020, C_FO, 0x5400B020, C_FO,
0x54000040, C_FO, 0x54001040, C_FO, 0x54002040, C_FO, 0x54003040, C_FO,
0x54008040, C_FO, 0x54009040, C_FO, 0x5400A040, C_FO, 0x5400B040, C_FO,
0x54000060, C_FO, 0x54001060, C_FO, 0x54002060, C_FO, 0x54003060, C_FO,
0x54008060, C_FO, 0x54009060, C_FO, 0x5400A060, C_FO, 0x5400B060, C_FO,
0x54000400, C_FO, 0x54001400, C_FO, 0x54002400, C_FO, 0x54003400, C_FO,
0x54008400, C_FO, 0x54009400, C_FO, 0x5400A400, C_FO, 0x5400B400, C_FO,
0x54000420, C_FO, 0x54001420, C_FO, 0x54002420, C_FO, 0x54003420, C_FO,
0x54008420, C_FO, 0x54009420, C_FO, 0x5400A420, C_FO, 0x5400B420, C_FO,
0x54000440, C_FO, 0x54001440, C_FO, 0x54002440, C_FO, 0x54003440, C_FO,
0x54008440, C_FO, 0x54009440, C_FO, 0x5400A440, C_FO, 0x5400B440, C_FO,
0x54000460, C_FO, 0x54001460, C_FO, 0x54002460, C_FO, 0x54003460, C_FO,
0x54008460, C_FO, 0x54009460, C_FO, 0x5400A460, C_FO, 0x5400B460, C_FO,
0x57E003C0, C_FBC, 0x57E013C0, C_FBC, 0x57E023C0, C_FBC, 0x57E033C0, C_FBC,
0x57E083C0, C_FBC, 0x57E093C0, C_FBC, 0x57E0A3C0, C_FBC, 0x57E0B3C0, C_FBC,
0x57E00580, C_FBC, 0x57E01580, C_FBC, 0x57E02580, C_FBC, 0x57E03580, C_FBC,
0x57E08580, C_FBC, 0x57E09580, C_FBC, 0x57E0A580, C_FBC, 0x57E0B580, C_FBC,
0x57E005A0, C_FBC, 0x57E015A0, C_FBC, 0x57E025A0, C_FBC, 0x57E035A0, C_FBC,
0x57E085A0, C_FBC, 0x57E095A0, C_FBC, 0x57E0A5A0, C_FBC, 0x57E0B5A0, C_FBC,
0x57E005E0, C_FBC, 0x57E015E0, C_FBC, 0x57E025E0, C_FBC, 0x57E035E0, C_FBC,
0x57E085E0, C_FBC, 0x57E095E0, C_FBC, 0x57E0A5E0, C_FBC, 0x57E0B5E0, C_FBC,
0x57E00780, C_FBC, 0x57E01780, C_FBC, 0x57E007C0, C_FBC, 0x57E017C0, C_FBC,
0x540014A0, C_FO, 0x540094A0, C_FO, 0x540014C0, C_FO, 0x540094C0, C_FO,
0x540014E0, C_FO, 0x540094E0, C_FO,
0x58000000, C_FO, 0x58000800, C_FO, 0x58001000, C_FO, 0x58001800, C_FO,
0x58002000, C_FO, 0x58002800, C_FO, 0x58003000, C_FO, 0x58003800, C_FO,
0x5800A000, C_FO, 0x5800A800, C_FO, 0x5800B000, C_FO, 0x5800B800, C_FO,
0x5800E000, C_FO, 0x5800E800, C_FO, 0x5800F000, C_FO, 0x5800F800, C_FO,
0x58000020, C_FO, 0x58000820, C_FO, 0x58001020, C_FO, 0x58001820, C_FO,
0x58002020, C_FO, 0x58002820, C_FO, 0x58003020, C_FO, 0x58003820, C_FO,
0x5800A020, C_FO, 0x5800A820, C_FO, 0x5800B020, C_FO, 0x5800B820, C_FO,
0x5800E020, C_FO, 0x5800E820, C_FO, 0x5800F020, C_FO, 0x5800F820, C_FO,
0x58000040, C_FO, 0x58000840, C_FO, 0x58001040, C_FO, 0x58001840, C_FO,
0x58002040, C_FO, 0x58002840, C_FO, 0x58003040, C_FO, 0x58003840, C_FO,
0x5800A040, C_FO, 0x5800A840, C_FO, 0x5800B040, C_FO, 0x5800B840, C_FO,
0x5800E040, C_FO, 0x5800E840, C_FO, 0x5800F040, C_FO, 0x5800F840, C_FO,
0x58000060, C_FO, 0x58000860, C_FO, 0x58001060, C_FO, 0x58001860, C_FO,
0x58002060, C_FO, 0x58002860, C_FO, 0x58003060, C_FO, 0x58003860, C_FO,
0x5800A060, C_FO, 0x5800A860, C_FO, 0x5800B060, C_FO, 0x5800B860, C_FO,
0x5800E060, C_FO, 0x5800E860, C_FO, 0x5800F060, C_FO, 0x5800F860, C_FO,
0x58000400, C_FO, 0x58000C00, C_FO, 0x58001400, C_FO, 0x58001C00, C_FO,
0x58002400, C_FO, 0x58002C00, C_FO, 0x58003400, C_FO, 0x58003C00, C_FO,
0x5800A400, C_FO, 0x5800AC00, C_FO, 0x5800B400, C_FO, 0x5800BC00, C_FO,
0x5800E400, C_FO, 0x5800EC00, C_FO, 0x5800F400, C_FO, 0x5800FC00, C_FO,
0x58000420, C_FO, 0x58000C20, C_FO, 0x58001420, C_FO, 0x58001C20, C_FO,
0x58002420, C_FO, 0x58002C20, C_FO, 0x58003420, C_FO, 0x58003C20, C_FO,
0x5800A420, C_FO, 0x5800AC20, C_FO, 0x5800B420, C_FO, 0x5800BC20, C_FO,
0x5800E420, C_FO, 0x5800EC20, C_FO, 0x5800F420, C_FO, 0x5800FC20, C_FO,
0x58000440, C_FO, 0x58000C40, C_FO, 0x58001440, C_FO, 0x58001C40, C_FO,
0x58002440, C_FO, 0x58002C40, C_FO, 0x58003440, C_FO, 0x58003C40, C_FO,
0x5800A440, C_FO, 0x5800AC40, C_FO, 0x5800B440, C_FO, 0x5800BC40, C_FO,
0x5800E440, C_FO, 0x5800EC40, C_FO, 0x5800F440, C_FO, 0x5800FC40, C_FO,
0x58000460, C_FO, 0x58000C60, C_FO, 0x58001460, C_FO, 0x58001C60, C_FO,
0x58002460, C_FO, 0x58002C60, C_FO, 0x58003460, C_FO, 0x58003C60, C_FO,
0x5800A460, C_FO, 0x5800AC60, C_FO, 0x5800B460, C_FO, 0x5800BC60, C_FO,
0x5800E460, C_FO, 0x5800EC60, C_FO, 0x5800F460, C_FO, 0x5800FC60, C_FO,
0x5BE00580, C_FBC, 0x5BE00D80, C_FBC, 0x5BE01580, C_FBC, 0x5BE01D80, C_FBC,
0x5BE02580, C_FBC, 0x5BE02D80, C_FBC, 0x5BE03580, C_FBC, 0x5BE03D80, C_FBC,
0x5BE0A580, C_FBC, 0x5BE0AD80, C_FBC, 0x5BE0B580, C_FBC, 0x5BE0BD80, C_FBC,
0x5BE0E580, C_FBC, 0x5BE0ED80, C_FBC, 0x5BE0F580, C_FBC, 0x5BE0FD80, C_FBC,
0x5BE005E0, C_FBC, 0x5BE00DE0, C_FBC, 0x5BE015E0, C_FBC, 0x5BE01DE0, C_FBC,
0x5BE025E0, C_FBC, 0x5BE02DE0, C_FBC, 0x5BE035E0, C_FBC, 0x5BE03DE0, C_FBC,
0x5BE0A5E0, C_FBC, 0x5BE0ADE0, C_FBC, 0x5BE0B5E0, C_FBC, 0x5BE0BDE0, C_FBC,
0x5BE0E5E0, C_FBC, 0x5BE0EDE0, C_FBC, 0x5BE0F5E0, C_FBC, 0x5BE0FDE0, C_FBC,
0x5BE00780, C_FBC, 0x5BE00F80, C_FBC, 0x5BE01780, C_FBC, 0x5BE01F80, C_FBC,
0x5BE0E780, C_FBC, 0x5BE0EF80, C_FBC, 0x5BE0F780, C_FBC, 0x5BE0FF80, C_FBC,
0x5BE007C0, C_FBC, 0x5BE00FC0, C_FBC, 0x5BE017C0, C_FBC, 0x5BE01FC0, C_FBC,
0x5BE0E7C0, C_FBC, 0x5BE0EFC0, C_FBC, 0x5BE0F7C0, C_FBC, 0x5BE0FFC0, C_FBC,
0x58001480, C_FO, 0x58009480, C_FO, 0x580014A0, C_FO, 0x580094A0, C_FO,
0x580014C0, C_FO, 0x580094C0, C_FO, 0x580014E0, C_FO, 0x580094E0, C_FO,
0x5FE00200, C_IBC, 0x5C000400, C_IO, 0x5C000420, C_IO, 0x5C000440, C_IO,
0x5C000480, C_IO, 0x5C0004A0, C_IO,
0x5C000540, C_IO, 0x5C000560, C_IO, 0x5C000580, C_IO,
0x5C0005A0, C_IO, 0x5C0005C0, C_IO, 0x5C0005E0, C_IO,
0x5FE00060, C_IBC, 0x5FE00260, C_IBC, 0x5FE00A60, C_IBC,
0x60000000, C_NO, 0x60000400, C_NO, 0x60004000, C_NO, 0x60004400, C_NO,
0x60008000, C_FE, 0x6000A000, C_FE, 0x6000C000, C_NO,
0x6000E000, C_RV, 0x6000F000, C_RV,
0x68000000, C_JP, 0x68004000, C_JP, 0x68008000, C_JP, 0x6800C000, C_JP,
0x73E00000, C_IBC, 0x73E00020, C_IBC,
0x73E00600, C_IBC, 0x70000620, C_IO, 0x73E00640, C_IBC, 0x73E00660, C_IBC,
0x73E00680, C_IBC, 0x73E006A0, C_IBC, 0x73E006C0, C_IBC, 0x73E006E0, C_IBC,
0x70000700, C_IO, 0x70000720, C_IO, 0x70000740, C_IO, 0x70000780, C_IO,
0x70000780, C_IO, 0x700007A0, C_IO, 0x700007C0, C_IO, 0x700007E0, C_IO,
0x701F0E00, C_IAC, 0x701F0F00, C_IAC,
0x80000000, C_MR, 0x84000000, C_MR, 0x88000000, C_MR, 0x8C000000, C_MR,
0x90000000, C_MR, 0x94000000, C_MR, 0x98000000, C_MR, 0x9C000000, C_MR,
0xA0000000, C_MR, 0xA4000000, C_MR, 0xA8000000, C_MR, 0xAC000000, C_MR,
0xB0000000, C_MR, 0xB4000000, C_MR, 0xB8000000, C_MR, 0xBC000000, C_MR,
0xC0000000, C_BR, 0xC4000000, C_BR, 0xC8000000, C_BR, 0xCC000000, C_BR,
0xD0000000, C_BR, 0xD4000000, C_BR, 0xD8000000, C_BR, 0xDC000000, C_BR,
0xE0000000, C_BR, 0xE4000000, C_BR, 0xE8000000, C_BR, 0xEC000000, C_BR,
0xF0000000, C_BR, 0xF4000000, C_BR, 0xF8000000, C_BR, 0xFC000000, C_BR,
M32, 0
};
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = values to decode
*uptr = pointer to unit
sw = switches
Outputs:
return = if >= 0, error code
if < 0, number of extra bytes retired
*/
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
uint32 c, sc, rdx;
t_stat r;
DEVICE *dptr;
if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */
else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */
dptr = find_dev_from_unit (uptr); /* find dev */
if (dptr == NULL) return SCPE_IERR;
if (sw & SWMASK ('D')) rdx = 10; /* get radix */
else if (sw & SWMASK ('O')) rdx = 8;
else if (sw & SWMASK ('H')) rdx = 16;
else rdx = dptr->dradix;
if (sw & SWMASK ('A')) { /* ASCII? */
sc = (uint32) (addr & 0x7) * 8; /* shift count */
c = (uint32) (val[0] >> sc) & 0x7F;
fprintf (of, (c < 0x20)? "<%02X>": "%c", c);
return 0;
}
if (sw & SWMASK ('B')) { /* byte? */
sc = (uint32) (addr & 0x7) * 8; /* shift count */
c = (uint32) (val[0] >> sc) & M8;
fprintf (of, "%02X", c);
return 0;
}
if (sw & SWMASK ('W')) { /* word? */
sc = (uint32) (addr & 0x6) * 8; /* shift count */
c = (uint32) (val[0] >> sc) & M16;
fprintf (of, "%04X", c);
return -1;
}
if (sw & SWMASK ('L')) { /* long? */
if (addr & 4) c = (uint32) (val[0] >> 32) & M32;
else c = (uint32) val[0] & M32;
fprintf (of, "%08X", c);
return -3;
}
if (sw & SWMASK ('C')) { /* char format? */
for (sc = 0; sc < 64; sc = sc + 8) { /* print string */
c = (uint32) (val[0] >> sc) & 0x7F;
fprintf (of, (c < 0x20)? "<%02X>": "%c", c);
}
return -7; /* return # chars */
}
if (sw & SWMASK ('M')) { /* inst format? */
if (addr & 4) c = (uint32) (val[0] >> 32) & M32;
else c = (uint32) val[0] & M32;
r = fprint_sym_m (of, addr, c); /* decode inst */
if (r <= 0) return r;
}
fprint_val (of, val[0], rdx, 64, PV_RZRO);
return -7;
}
/* Symbolic decode for -m
Inputs:
of = output stream
addr = current PC
inst = instruction to decode
Outputs:
return = if >= 0, error code
if < 0, number of extra bytes retired (-3)
*/
t_stat fprint_sym_m (FILE *of, t_addr addr, uint32 inst)
{
uint32 i, j, k, fl, ra, rb, rc, md, bd, jd, lit8, any;
t_stat r;
if ((r = fprint_pal_hwre (of, inst)) < 0) return r; /* PAL instruction? */
for (i = 0; opval[i] != M32; i = i + 2) { /* loop thru ops */
fl = opval[i + 1]; /* flags */
j = fl & CL_CLASS; /* get class */
k = i >> 1;
if (((opval[i] & masks[j]) == (inst & masks[j])) && /* match? */
((j != CL_NO) || (fl & PAL_MASK (pal_type)))) {
ra = I_GETRA (inst); /* all fields */
rb = I_GETRB (inst);
rc = I_GETRC (inst);
lit8 = I_GETLIT8 (inst);
md = I_GETMDSP (inst);
bd = I_GETBDSP (inst);
jd = inst & 0x3FFF;
any = 0;
fprintf (of, "%s", opcode[k]); /* opcode */
if (fl & FL_RA) /* ra? */
any = fprintf (of, " R%d", ra);
if (fl & FL_BDP) { /* branch? */
addr = (addr + (SEXT_BDSP (bd) << 2) + 4) & M64;
any = fprintf (of, (any? ",": " "));
fprint_val (of, addr, 16, 64, PV_LEFT);
}
else if (fl & FL_MDP) { /* mem ref? */
if ((fl & FL_RBI) && (rb != 31))
any = fprintf (of, (any? ",%X(R%d)": " %X(R%d)"), md, rb);
else any = fprintf (of, (any? ",%X": " %X"), md);
}
else if (fl & FL_RB) { /* rb? */
if (fl & FL_RBI)
any = fprintf (of, (any? ",(R%d)": " (R%d)"), rb);
else if ((fl & FL_LIT) && (inst & I_ILIT))
any = fprintf (of, (any? ",#%X": " #%X"), lit8);
else any = fprintf (of, (any? ",R%d": " R%d"), rb);
}
if ((fl & FL_JDP) && jd) /* jmp? */
any = fprintf (of, (any? ",%X": " %X"), jd);
else if (fl & FL_RC) /* rc? */
any = fprintf (of, (any? ",R%d": " R%d"), rc);
return -3;
} /* end if */
} /* end for */
return SCPE_ARG;
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
*uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = > 0 error code
<= 0 -number of extra words
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
t_value num;
uint32 i, sc, rdx;
t_stat r;
DEVICE *dptr;
if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */
else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */
dptr = find_dev_from_unit (uptr); /* find dev */
if (dptr == NULL) return SCPE_IERR;
if (sw & SWMASK ('D')) rdx = 10; /* get radix */
else if (sw & SWMASK ('O')) rdx = 8;
else if (sw & SWMASK ('H')) rdx = 16;
else rdx = dptr->dradix;
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
sc = (uint32) (addr & 0x7) * 8; /* shift count */
val[0] = (val[0] & ~(((t_uint64) M8) << sc)) |
(((t_uint64) cptr[0]) << sc);
return 0;
}
if (sw & SWMASK ('B')) { /* byte? */
num = get_uint (cptr, rdx, M8, &r); /* get byte */
if (r != SCPE_OK) return SCPE_ARG;
sc = (uint32) (addr & 0x7) * 8; /* shift count */
val[0] = (val[0] & ~(((t_uint64) M8) << sc)) |
(num << sc);
return 0;
}
if (sw & SWMASK ('W')) { /* word? */
num = get_uint (cptr, rdx, M16, &r); /* get word */
if (r != SCPE_OK) return SCPE_ARG;
sc = (uint32) (addr & 0x6) * 8; /* shift count */
val[0] = (val[0] & ~(((t_uint64) M16) << sc)) |
(num << sc);
return -1;
}
if (sw & SWMASK ('L')) { /* longword? */
num = get_uint (cptr, rdx, M32, &r); /* get longword */
if (r != SCPE_OK) return SCPE_ARG;
sc = (uint32) (addr & 0x4) * 8; /* shift count */
val[0] = (val[0] & ~(((t_uint64) M32) << sc)) |
(num << sc);
return -3;
}
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII chars? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
for (i = 0; i < 8; i++) {
if (cptr[i] == 0) break;
sc = i * 8;
val[0] = (val[0] & ~(((t_uint64) M8) << sc)) |
(((t_uint64) cptr[i]) << sc);
}
return -7;
}
if ((addr & 3) == 0) { /* aligned only */
r = parse_sym_m (cptr, addr, &num); /* try to parse inst */
if (r <= 0) { /* ok? */
sc = (uint32) (addr & 0x4) * 8; /* shift count */
val[0] = (val[0] & ~(((t_uint64) M32) << sc)) |
(num << sc);
return -3;
}
}
val[0] = get_uint (cptr, rdx, M64, &r); /* get number */
if (r != SCPE_OK) return r;
return -7;
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
*val = pointer to output values
Outputs:
status = > 0 error code
<= 0 -number of extra words
*/
t_stat parse_sym_m (char *cptr, t_addr addr, t_value *inst)
{
t_uint64 bra, df, db;
uint32 i, k, lit8, fl;
int32 reg;
t_stat r;
char *tptr, gbuf[CBUFSIZE];
if ((r = parse_pal_hwre (cptr, inst)) < 0) return r; /* PAL hardware? */
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; opcode[i] != NULL; i++) { /* loop thru opcodes */
if (strcmp (opcode[i], gbuf) == 0) { /* string match? */
k = i << 1; /* index to opval */
fl = opval[k + 1]; /* get flags */
if (((fl & CL_CLASS) != CL_NO) || /* not PAL or */
(fl & PAL_MASK (pal_type))) break; /* PAL type match? */
}
}
if (opcode[i] == NULL) return SCPE_ARG;
*inst = opval[k]; /* save base op */
if (fl & FL_RA) { /* need Ra? */
cptr = get_glyph (cptr, gbuf, ','); /* get reg */
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
*inst = *inst | (reg << I_V_RA);
}
if (fl & FL_BDP) { /* need branch disp? */
cptr = get_glyph (cptr, gbuf, 0);
bra = get_uint (gbuf, 16, M64, &r);
if ((r != SCPE_OK) || (bra & 3)) return SCPE_ARG;
df = ((bra - (addr + 4)) >> 2) & I_M_BDSP;
db = ((addr + 4 - bra) >> 2) & I_M_BDSP;
if (bra == ((addr + 4 + (SEXT_BDSP (df) << 2)) & M64))
*inst = *inst | (uint32) df;
else if (bra == ((addr + 4 + (SEXT_BDSP (db) << 2)) & M64))
*inst = *inst | (uint32) db;
else return SCPE_ARG;
}
else if (fl & FL_MDP) { /* need mem disp? */
cptr = get_glyph (cptr, gbuf, 0);
df = strtotv (gbuf, &tptr, 16);
if ((gbuf == tptr) || (df > I_M_MDSP)) return SCPE_ARG;
*inst = *inst | (uint32) df;
if (*tptr == '(') {
tptr = get_glyph (tptr + 1, gbuf, ')');
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
*inst = *inst | (reg << I_V_RB);
}
else *inst = *inst | (31 << I_V_RB);
if (*tptr != 0) return SCPE_ARG;
}
else if (fl & FL_RBI) { /* indexed? */
cptr = get_glyph (cptr, gbuf, ',');
if (gbuf[0] != '(') return SCPE_ARG;
tptr = get_glyph (gbuf + 1, gbuf, ')');
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
*inst = *inst | (reg << I_V_RB);
if (*tptr != 0) return SCPE_ARG;
}
else if (fl & FL_RB) {
cptr = get_glyph (cptr, gbuf, ','); /* get reg/lit */
if ((gbuf[0] == '#') && (fl & FL_LIT)) { /* literal? */
lit8 = (uint32) get_uint (gbuf + 1, 16, I_M_LIT8, &r);
if (r != SCPE_OK) return r;
*inst = *inst | I_ILIT | (lit8 << I_V_LIT8);
}
else { /* rb */
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
*inst = *inst | (reg << I_V_RB);
}
}
if (fl & FL_JDP) { /* jmp? */
cptr = get_glyph (cptr, gbuf, 0); /* get disp */
df = get_uint (gbuf, 16, 0x3FFF, &r);
if (r != SCPE_OK) return r;
*inst = *inst | df;
}
else if (fl & FL_RC) { /* rc? */
cptr = get_glyph (cptr, gbuf, ','); /* get reg */
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
*inst = *inst | (reg << I_V_RC);
}
if (*cptr != 0) return SCPE_ARG; /* any leftovers? */
return -3;
}
/* Parse a register */
int32 parse_reg (char *cptr)
{
t_stat r;
int32 reg;
if ((*cptr == 'R') || (*cptr == 'r') ||
(*cptr == 'F') || (*cptr == 'f')) cptr++;
reg = (int32) get_uint (cptr, 10, 31, &r);
if (r != SCPE_OK) return -1;
return reg;
}

43
alpha/alpha_sys_defs.h Normal file
View file

@ -0,0 +1,43 @@
/* alpha_system_defs.h: Alpha system definitions file
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
Respectfully dedicated to the great people of the Alpha chip, systems, and
software development projects; and to the memory of Peter Conklin, of the
Alpha Program Office.
This is a STUB!
*/
#ifndef _ALPHA_SYS_DEFS_H_
#define _ALPHA_SYS_DEFS_H_ 0
#define PA_SIZE 36 /* PA size */
#define PA_MASK 0x0000000FFFFFFFFF
#define ROMBASE 0x000000FFFC000000
#define ROMSIZE 0x0000000004000000
#endif

View file

@ -0,0 +1,208 @@
/* alpha_pal_defs.h: Alpha architecture PAL definitions file
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
Respectfully dedicated to the great people of the Alpha chip, systems, and
software development projects; and to the memory of Peter Conklin, of the
Alpha Program Office.
*/
#ifndef _ALPHA_PAL_DEFS_H_
#define _ALPHA_PAL_DEFS_H_ 0
/* VA - NT software format */
#define NTVA_N_PDE (VA_N_OFF - 2) /* PDE width */
#define NTVA_M_PDE ((1u << NTVA_N_PDE) - 1) /* PDE mask */
#define NTVA_N_PTD (32 - VA_N_OFF - NTVA_N_PDE) /* PTD width */
#define NTVA_M_PTD ((1u << NTVA_N_PTD) - 1) /* PTD mask */
#define NTVA_M_VPN (M32 >> VA_N_OFF) /* 32b VPN mask */
#define NTVPN_N_SEXT (VA_WIDTH - 32 + 1) /* VPN sext size */
#define NTVPN_V_SEXT (VA_N_VPN - NTVPN_N_SEXT) /* VPN sext start */
#define NTVPN_M_SEXT ((1u << NTVPN_N_SEXT) - 1) /* VPN sext mask */
#define NTVPN_GETSEXT(x) (((x) >> NTVPN_V_SEXT) & NTVPN_M_SEXT)
/* PTE - NT software format */
#define NT_VPTB 0xFFFFFFFFC0000000 /* virt page tbl base */
#define NTP_V_PFN 9 /* PFN */
#define NTP_M_PFN 0x7FFFFF
#define NTP_PFN (NTP_M_PFN << NTP_V_PFN)
#define NTP_V_GH 5
#define NTP_M_GH 0x3
#define NTP_V_GBL 4 /* global = ASM */
#define NTP_V_DIRTY 2 /* dirty = !FOW */
#define NTP_V_OWNER 1 /* owner */
#define NTP_V_V 0 /* valid */
#define NTP_GBL (1u << NTP_V_GBL)
#define NTP_DIRTY (1u << NTP_V_DIRTY)
#define NTP_OWNER (1u << NTP_V_OWNER)
#define NTP_V (1u << NTP_V_V)
#define NT_VPNPTD(x) (((x) >> (NTVA_N_PDE - 2)) & (NTVA_M_PTD << 2))
#define NT_VPNPDE(x) (((x) << 2) & (NTVA_M_PDE << 2))
/* VMS PALcode */
#define PSV_V_SPA 56 /* VMS PS: stack align */
#define PSV_M_SPA 0x3F
#define PSV_V_IPL 8 /* interrupt priority */
#define PSV_M_IPL 0x1F
#define PSV_V_VMM 7 /* virt machine monitor */
#define PSV_V_CM 3 /* current mode */
#define PSV_M_CM 0x3
#define PSV_V_IP 2 /* intr in progress */
#define PSV_V_SW 0 /* software */
#define PSV_M_SW 0x3
#define PSV_VMM (1u << PSV_V_VMM)
#define PSV_IP (1u << PSV_V_IP)
#define PSV_MASK (PSV_VMM | PSV_IP | PSV_M_SW)
#define PSV_MBZ 0xC0FFFFFFFFFFE0E4 /* must be zero */
#define PCBV_FLAGS 56 /* PCB flags word */
#define SISR_MASK 0xFFFE /* SISR bits */
#define IPL_SMAX 0x0F /* highest swre level */
#define SCB_FDIS 0x010 /* SCB offsets */
#define SCB_ACV 0x080
#define SCB_TNV 0x090
#define SCB_FOR 0x0A0
#define SCB_FOW 0x0B0
#define SCB_FOE 0x0C0
#define SCB_ARITH 0x200
#define SCB_KAST 0x240
#define SCB_EAST 0x250
#define SCB_SAST 0x260
#define SCB_UAST 0x270
#define SCB_ALIGN 0x280
#define SCB_BPT 0x400
#define SCB_BUG 0x410
#define SCB_RSVI 0x420
#define SCB_RSVO 0x430
#define SCB_GENTRAP 0x440
#define SCB_CHMK 0x480
#define SCB_CHME 0x490
#define SCB_CHMS 0x4A0
#define SCB_CHMU 0x4B0
#define SCB_SISR0 0x500
#define SCB_CLOCK 0x600
#define SCB_IPIR 0x610
#define SCB_SCRD 0x620
#define SCB_PCRD 0x630
#define SCB_POWER 0x640
#define SCB_PERFM 0x650
#define SCB_SMCHK 0x660
#define SCB_PMCHK 0x670
#define SCB_PASVR 0x6F0
#define SCB_IO 0x800
#define VMS_L_STKF (8 * 8) /* stack frame length */
#define VMS_MME_E 0x0000000000000001 /* mem mgt error flags */
#define VMS_MME_R 0x0000000000000000
#define VMS_MME_W 0x8000000000000000
/* VAX compatible data length definitions (for ReadUna, WriteUna) */
#define L_BYTE 1
#define L_WORD 2
#define L_LONG 4
#define L_QUAD 8
/* Unix PALcode */
#define PSU_V_CM 3 /* Unix PS: curr mode */
#define PSU_M_CM 0x1
#define PSU_CM (PSU_M_CM << PSU_V_CM)
#define PSU_V_IPL 0 /* IPL */
#define PSU_M_IPL 0x7
#define PSU_IPL (PSU_M_IPL << PSU_V_IPL)
#define PCBU_FLAGS 40 /* PCB flags word */
#define UNIX_L_STKF (6 * 8) /* kernel stack frame */
#define UNIX_IF_BPT 0 /* entIF a0 values */
#define UNIX_IF_BUG 1
#define UNIX_IF_GEN 2
#define UNIX_IF_FDIS 3
#define UNIX_IF_RSVI 4
#define UNIX_INT_IPIR 0 /* entInt a0 values */
#define UNIX_INT_CLK 1
#define UNIX_INT_MCRD 2
#define UNIX_INT_IO 3
#define UNIX_INT_PERF 4
#define UNIX_MMCSR_TNV 0 /* entMM a1 values */
#define UNIX_MMCSR_ACV 1
#define UNIX_MMCSR_FOR 2
#define UNIX_MMCSR_FOW 3
#define UNIX_MMCSR_FOE 4
#define UNIX_MME_E M64 /* entMM a2 values */
#define UNIX_MME_R 0
#define UNIX_MME_W 1
enum vms_pal_opcodes {
OP_HALT, OP_DRAINA, OP_CFLUSH, OP_LDQP,
OP_STQP, OP_SWPCTX, MF_ASN, MT_ASTEN,
MT_ASTSR, OP_CSERVE, OP_SWPPAL, MF_FEN,
MT_FEN, MT_IPIR, MF_IPL, MT_IPL,
MF_MCES, MT_MCES, MF_PCBB, MF_PRBR,
MT_PRBR, MF_PTBR, MF_SCBB, MT_SCBB,
MT_SIRR, MF_SISR, MF_TBCHK, MT_TBIA,
MT_TBIAP, MT_TBIS, MF_ESP, MT_ESP,
MF_SSP, MT_SSP, MF_USP, MT_USP,
MT_TBISD, MT_TBISI, MF_ASTEN, MF_ASTSR,
MF_VTBR = 0x29, MT_VTBR,MT_PERFMON, MT_DATFX = 0x2E,
MF_VIRBND = 0x30, MT_VIRBND, MF_SYSPTBR, MT_SYSPTBR,
OP_WTINT = 0x3E, MF_WHAMI = 0x3F,
OP_BPT = 0x80, OP_BUGCHK, OP_CHME, OP_CHMK,
OP_CHMS, OP_CHMU, OP_IMB, OP_INSQHIL,
OP_INSQTIL, OP_INSQHIQ, OP_INSQTIQ, OP_INSQUEL,
OP_INSQUEQ, OP_INSQUELD,OP_INSQUEQD,OP_PROBER,
OP_PROBEW, OP_RD_PS, OP_REI, OP_REMQHIL,
OP_REMQTIL, OP_REMQHIQ, OP_REMQTIQ, OP_REMQUEL,
OP_REMQUEQ, OP_REMQUELD,OP_REMQUEQD,OP_SWASTEN,
OP_WR_PS_SW,OP_RSCC, OP_RD_UNQ, OP_WR_UNQ,
OP_AMOVRR, OP_AMOVRM, OP_INSQHILR,OP_INSQTILR,
OP_INSQHIQR,OP_INSQTIQR,OP_REMQHILR,OP_REMQTILR,
OP_REMQHIQR,OP_REMQTIQR,OP_GENTRAP,
OP_CLRFEN = 0xAE
};
enum unix_pal_opcodes {
OP_halt, OP_draina, OP_cflush,
OP_cserve = 0x9, OP_swppal,
OP_rdmces = 0x10, OP_wrmces,
OP_wrvirbnd = 0x13, OP_wrsysptbr = 0x14,
OP_wrfen = 0x2B, OP_wrvptptr = 0x2D, OP_wrasn,
OP_swpctx = 0x30, OP_wrval, OP_rdval, OP_tbi,
OP_wrent, OP_swpipl, OP_rdps, OP_wrkgp,
OP_wrusp, OP_wrperfmon, OP_rdusp,
OP_whami = 0x3C, OP_retsys, OP_wtint, OP_rti,
OP_bpt = 0x80, OP_bugchk, OP_syscall = 0x83,
OP_imb = 0x86,
OP_urti = 0x92, OP_rdunique = 0x9E, OP_wrunique,
OP_gentrap = 0xAA, OP_clrfen = 0xAE
};
#endif

View file

@ -0,0 +1,702 @@
/* alpha_pal_unix.c - Alpha Unix PAL code simulator
Copyright (c) 2003-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This module contains the PALcode implementation for Alpha Unix, except for
the console, which is always done in hardware mode.
Alpha Unix/Linux requires the following privileged state:
ps<3:0> processor status
cm<0> current mode - in base
ipl<2:0> interrupt level - in base
ksp<63:0> kernel stack pointer
kgp<63:0> kernel global pointer
usp<63:0> user stack pointer
pcbb<63:0> process control block base
ptptr<63:0> page table base
vptptr<63:0> virtual page table base
virbnd<63:0> virtual address boundary
sysptbr<63:0> system page table base register
sysval<63:0> processor base (sysvalue)
unique<63:0> thread-unique value
entArith<63:0> entry vector, arithmetic trap
entIF<63:0> entry vector, instruction
entInt<63:0> entry vector, interrupt
entSys<63:0> entry vector, system call
entMM<63:0> entry vector, memory management fault
entUna<63:0> entry vector, unaligned
Unix maps kernel/user to the hardware's kernel/executive. It maps the
8 IPL's to the hardware IPL's as follows:
0 0
1 1
2 2
3 IPL_HMIN
4 IPL_HMIN+1
5 IPL_HMIN+2
6 IPL_HMIN+3
7 IPL_1F
*/
#include "alpha_defs.h"
#define GET_PSU (((unix_cm & PSU_M_CM) << PSU_V_CM) | \
((unix_ipl & PSU_M_IPL) << PSU_V_IPL))
// kludge for debugging...
#define io_get_vec(x) 0
#define ksp unix_stkp[MODE_K]
#define usp unix_stkp[MODE_E]
#define entInt unix_entVec[0]
#define entArith unix_entVec[1]
#define entMM unix_entVec[2]
#define entIF unix_entVec[3]
#define entUna unix_entVec[4]
#define entSys unix_entVec[5]
#define v0 R[0]
#define a0 R[16]
#define a1 R[17]
#define a2 R[18]
#define a3 R[19]
#define at R[28]
#define gp R[29]
t_uint64 unix_ptptr = 0; /* page table base */
t_uint64 unix_vptptr = 0; /* virt page table base */
t_uint64 unix_virbnd = M64; /* virtual boundary */
t_uint64 unix_sysptbr = 0; /* system page table base */
t_uint64 unix_hwpcb = 0; /* hardware PCB */
t_uint64 unix_unique = 0; /* thread unique */
t_uint64 unix_sysval = 0; /* processor unique */
t_uint64 unix_mces = 0; /* machine check err summ */
t_uint64 unix_stkp[2] = { 0 };
t_uint64 unix_entVec[6] = { 0 };
t_uint64 unix_kgp = 0;
uint32 unix_ipl = 0;
uint32 unix_cm = 0;
static const uint32 map_ipl[8] = {
0, 1, 2, IPL_HMIN, IPL_HMIN + 1, IPL_HMIN + 2, IPL_HMIN + 3, IPL_1F
};
extern t_uint64 R[32];
extern t_uint64 PC, trap_mask;
extern t_uint64 p1;
extern uint32 vax_flag, lock_flag;
extern uint32 fpen;
extern uint32 ir, pcc_h, pcc_l, pcc_enb;
extern uint32 cm_racc, cm_wacc;
extern uint32 mmu_ispage, mmu_dspage;
extern jmp_buf save_env;
extern uint32 int_req[IPL_HLVL];
t_stat unix_syscall (void);
t_stat unix_retsys (void);
t_stat unix_rti (void);
void unix_urti (void);
void unix_swpctx (void);
t_stat unix_intexc (t_uint64 vec, t_uint64 arg);
t_stat unix_mm_intexc (t_uint64 par1, t_uint64 par2);
t_stat pal_proc_reset_unix (DEVICE *dptr);
uint32 pal_find_pte_unix (uint32 vpn, t_uint64 *l3pte);
extern t_stat (*pal_eval_intr) (uint32 ipl);
extern t_stat (*pal_proc_excp) (uint32 type);
extern t_stat (*pal_proc_trap) (uint32 type);
extern t_stat (*pal_proc_intr) (uint32 type);
extern t_stat (*pal_proc_inst) (uint32 fnc);
extern uint32 (*pal_find_pte) (uint32 vpn, t_uint64 *pte);
extern uint32 Test (t_uint64 va, uint32 acc, t_uint64 *pa);
/* UNIXPAL data structures
unixpal_dev device descriptor
unixpal_unit unit
unixpal_reg register list
*/
UNIT unixpal_unit = { UDATA (NULL, 0, 0) };
REG unixpal_reg[] = {
{ HRDATA (KSP, ksp, 64) },
{ HRDATA (USP, usp, 64) },
{ HRDATA (ENTARITH, entArith, 64) },
{ HRDATA (ENTIF, entIF, 64) },
{ HRDATA (ENTINT, entInt, 64) },
{ HRDATA (ENTMM, entMM, 64) },
{ HRDATA (ENTSYS, entSys, 64) },
{ HRDATA (ENTUNA, entUna, 64) },
{ HRDATA (KGP, unix_kgp, 64) },
{ HRDATA (PTPTR, unix_ptptr, 64) },
{ HRDATA (VPTPTR, unix_vptptr, 64) },
{ HRDATA (VIRBND, unix_virbnd, 64) },
{ HRDATA (SYSPTBR, unix_sysptbr, 64) },
{ HRDATA (UNIQUE, unix_unique, 64) },
{ HRDATA (SYSVAL, unix_sysval, 64) },
{ HRDATA (HWPCB, unix_hwpcb, 64) },
{ HRDATA (MCES, unix_mces, 64) },
{ HRDATA (IPL, unix_ipl, 3) },
{ HRDATA (CM, unix_cm, 0) },
{ NULL }
};
DEVICE unixpal_dev = {
"UNIXPAL", &unixpal_unit, unixpal_reg, NULL,
1, 16, 1, 1, 16, 8,
NULL, NULL, &pal_proc_reset_unix,
NULL, NULL, NULL,
NULL, DEV_DIS
};
/* Unix interrupt evaluator - returns IPL of highest priority interrupt */
uint32 pal_eval_intr_unix (uint32 lvl)
{
uint32 i;
uint32 mipl = map_ipl[lvl & PSU_M_IPL];
for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */
if (i <= mipl) return 0; /* at ipl? no int */
if (int_req[i - IPL_HMIN]) return i; /* req != 0? int */
}
return 0;
}
/* Unix interrupt dispatch - reached from top of execute loop */
t_stat pal_proc_intr_unix (uint32 lvl)
{
t_stat r;
if (lvl > IPL_HMAX) return SCPE_IERR; /* above max? */
else if (lvl >= IPL_HMIN) a1 = io_get_vec (lvl); /* hwre? get vector */
else return SCPE_IERR; /* bug */
r = unix_intexc (entInt, UNIX_INT_IO); /* do interrupt */
if (a1 == SCB_CLOCK) a0 = UNIX_INT_CLK;
if (a1 == SCB_IPIR) a0 = UNIX_INT_IPIR;
unix_ipl = lvl;
return r;
}
/* Unix trap dispatch - reached synchronously from bottom of execute loop */
t_stat pal_proc_trap_unix (uint32 tsum)
{
t_stat r;
r = unix_intexc (entArith, tsum); /* arithmetic trap */
a1 = trap_mask; /* set parameter */
return r;
}
/* Unix exception dispatch - reached from the ABORT handler */
t_stat pal_proc_excp_unix (uint32 abval)
{
t_stat r;
switch (abval) {
case EXC_RSVI: /* reserved instruction */
return unix_intexc (entIF, UNIX_IF_RSVI); /* trap */
case EXC_RSVO: /* reserved operand */
return unix_intexc (entIF, UNIX_IF_RSVI); /* trap */
case EXC_ALIGN: /* unaligned */
PC = (PC - 4) & M64; /* back up PC */
r = unix_intexc (entUna, PC); /* fault */
a1 = I_GETOP (ir); /* get opcode */
a2 = I_GETRA (ir); /* get ra */
return r;
case EXC_FPDIS: /* fp disabled */
PC = (PC - 4) & M64; /* backup PC */
return unix_intexc (entIF, UNIX_IF_FDIS); /* fault */
case EXC_FOX+EXC_E: /* FOE */
tlb_is (p1, TLB_CI);
return unix_mm_intexc (UNIX_MMCSR_FOE, UNIX_MME_E);
case EXC_FOX+EXC_R: /* FOR */
PC = (PC - 4) & M64; /* back up PC */
return unix_mm_intexc (UNIX_MMCSR_FOR, UNIX_MME_R);
case EXC_FOX+EXC_W: /* FOW */
PC = (PC - 4) & M64; /* back up PC */
return unix_mm_intexc (UNIX_MMCSR_FOW, UNIX_MME_W);
case EXC_BVA+EXC_E:
case EXC_ACV+EXC_E: /* instr ACV */
return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_E);
case EXC_BVA+EXC_R:
case EXC_ACV+EXC_R: /* data read ACV */
PC = (PC - 4) & M64; /* back up PC */
return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_R);
case EXC_BVA+EXC_W:
case EXC_ACV+EXC_W: /* data write ACV */
PC = (PC - 4) & M64; /* back up PC */
return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_W);
case EXC_TNV+EXC_E: /* instr TNV */
tlb_is (p1, TLB_CI);
return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_E);
case EXC_TNV+EXC_R: /* data read TNV */
tlb_is (p1, TLB_CD);
PC = (PC - 4) & M64; /* back up PC */
return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_R);
case EXC_TNV+EXC_W: /* data write TNV */
tlb_is (p1, TLB_CD);
PC = (PC - 4) & M64; /* back up PC */
return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_W);
case EXC_TBM + EXC_E: /* TLB miss */
case EXC_TBM + EXC_R:
case EXC_TBM + EXC_W:
return SCPE_IERR; /* should not occur */
default:
return STOP_INVABO;
}
return SCPE_OK;
}
/* PALcode instruction dispatcher - function code verified in CPU */
t_stat pal_proc_inst_unix (uint32 fnc)
{
uint32 arg32 = (uint32) a0;
if ((fnc < 0x40) && (unix_cm != MODE_K)) ABORT (EXC_RSVI);
switch (fnc) {
case OP_halt:
return STOP_HALT;
case OP_cflush:
case OP_draina:
break;
case OP_cserve:
//tbd
break;
case OP_swppal:
v0 = 0;
break;
case OP_rdmces:
v0 = unix_mces;
break;
case OP_wrmces:
unix_mces = (unix_mces | (arg32 & MCES_DIS)) & ~(arg32 & MCES_W1C);
break;
case OP_wrvirbnd:
unix_virbnd = a0;
break;
case OP_wrsysptbr:
unix_sysptbr = a0;
break;
case OP_wrfen:
fpen = arg32 & 1;
arg32 = ReadPL (unix_hwpcb + PCBU_FLAGS);
arg32 = (arg32 & ~1) | fpen;
WritePL (unix_hwpcb + PCBU_FLAGS, arg32);
break;
case OP_wrvptptr:
unix_vptptr = a0;
break;
case OP_wrasn:
itlb_set_asn (arg32 & M16);
dtlb_set_asn (arg32 & M16);
WritePL (unix_hwpcb + 28, arg32 & M16);
break;
case OP_swpctx:
unix_swpctx ();
break;
case OP_wrval:
unix_sysval = a0;
break;
case OP_rdval:
v0 = unix_sysval;
break;
case OP_tbi:
switch (a0 + 2) {
case 0: /* -2 = tbia */
tlb_ia (TLB_CI | TLB_CD | TLB_CA);
break;
case 1: /* -1 = tbiap */
tlb_ia (TLB_CI | TLB_CD);
break;
case 3: /* +1 = tbis */
tlb_is (a1, TLB_CI | TLB_CD);
break;
case 4: /* +2 = tbisd */
tlb_is (a1, TLB_CD);
break;
case 5: /* +3 = tbisi */
tlb_is (a1, TLB_CI);
break;
default:
break;
}
break;
case OP_wrent:
if (a0 <= 5) unix_entVec[arg32] = a0;
break;
case OP_swpipl:
v0 = unix_ipl;
unix_ipl = arg32 & PSU_M_IPL;
break;
case OP_rdps:
v0 = GET_PSU;
break;
case OP_wrkgp:
unix_kgp = a0;
break;
case OP_wrusp:
usp = a0;
break;
case OP_wrperfmon:
// tbd
break;
case OP_rdusp:
v0 = usp;
break;
case OP_whami:
v0 = 0;
break;
case OP_retsys:
unix_retsys ();
break;
case OP_wtint:
v0 = 0;
break;
case OP_rti:
unix_rti ();
break;
/* Non-privileged */
case OP_bpt:
return unix_intexc (entIF, UNIX_IF_BPT);
case OP_bugchk:
return unix_intexc (entIF, UNIX_IF_BUG);
case OP_syscall:
if (unix_cm == MODE_K) {
//tbd
}
return unix_syscall ();
case OP_imb:
break;
case OP_urti:
if (unix_cm == MODE_K) {
//tbd
}
unix_urti ();
break;
case OP_rdunique:
v0 = unix_unique;
break;
case OP_wrunique:
unix_unique = a0;
break;
case OP_gentrap:
return unix_intexc (entIF, UNIX_IF_GEN);
case OP_clrfen:
fpen = 0;
arg32 = ReadPL (unix_hwpcb + PCBU_FLAGS);
arg32 = arg32 & ~1;
WritePL (unix_hwpcb + PCBU_FLAGS, arg32);
break;
default:
ABORT (EXC_RSVI);
}
return SCPE_OK;
}
/* Swap privileged context */
void unix_swpctx (void)
{
t_uint64 val;
uint32 tmp1;
WritePQ (unix_hwpcb + 0, SP); /* save stack ptrs */
WritePQ (unix_hwpcb + 8, usp);
tmp1 = (pcc_h + pcc_l) & M32; /* elapsed time */
WritePL (unix_hwpcb + 24, tmp1); /* save PCC */
WritePQ (unix_hwpcb + 32, unix_unique); /* save unique */
v0 = unix_hwpcb; /* return curr PCBB */
unix_hwpcb = a0; /* new PCBB */
SP = ksp = ReadPQ (unix_hwpcb + 0); /* read stack ptrs */
usp = ReadPQ (unix_hwpcb + 8);
val = ReadPQ (unix_hwpcb + 16) << VA_N_OFF; /* read new PTBR */
if (val != unix_ptptr) tlb_ia (TLB_CI | TLB_CD); /* ptbr change? zap TLB */
unix_ptptr = val;
tmp1 = ReadPL (unix_hwpcb + 24); /* restore PCC */
pcc_h = (tmp1 - pcc_l) & M32;
tmp1 = ReadPL (unix_hwpcb + 28) & M16; /* read ASN */
itlb_set_asn (tmp1);
dtlb_set_asn (tmp1);
unix_unique = ReadPQ (unix_hwpcb + 32); /* read unique */
fpen = ReadPL (unix_hwpcb + PCBU_FLAGS) & 1; /* read FEN */
return;
}
/* Unix interrupt or exception - always to kernel mode
Inputs:
vec = entry vector
arg = argument for a0
Outputs:
reason = possible processor halt
*/
t_stat unix_intexc (t_uint64 vec, t_uint64 arg)
{
t_uint64 sav_ps = GET_PSU; /* old PS */
if ((unix_cm & PSU_M_CM) != MODE_K) { /* not kernel? */
usp = SP; /* save SP */
SP = ksp; /* load new SP */
unix_cm = mmu_set_cm (MODE_K); /* PS = 0 */
unix_ipl = 0;
}
SP = (SP - UNIX_L_STKF) & M64; /* decr stack */
if (Test (SP, cm_wacc, NULL)) return STOP_KSNV; /* validate writes */
if (Test (SP + UNIX_L_STKF - 8, cm_wacc, NULL) < 0) return STOP_KSNV;
WriteQ (SP, sav_ps); /* save PS, PC, gp */
WriteQ (SP + 8, PC);
WriteQ (SP + 16, gp);
WriteQ (SP + 24, a0); /* save a0-a2 */
WriteQ (SP + 32, a1);
WriteQ (SP + 40, a2);
PC = vec; /* new PC */
gp = unix_kgp; /* kernel GP */
a0 = arg; /* argument */
return SCPE_OK;
}
/* Memory management fault */
t_stat unix_mm_intexc (t_uint64 par1, t_uint64 par2)
{
t_stat r;
r = unix_intexc (entMM, p1); /* do exception */
a1 = par1; /* set arguments */
a2 = par2;
tlb_is (p1, TLB_CI | TLB_CD); /* zap TLB entry */
return r;
}
/* System call - always user to kernel, abbreviated stack frame, no arguments */
t_stat unix_syscall (void)
{
t_uint64 sav_ps = GET_PSU; /* save PS */
usp = SP; /* save user SP */
SP = ksp; /* load kernel SP */
unix_cm = mmu_set_cm (MODE_K); /* PS = 0 */
unix_ipl = 0;
SP = (SP - UNIX_L_STKF) & M64; /* decr stack */
if (Test (SP, cm_wacc, NULL)) return STOP_KSNV; /* validate writes */
if (Test (SP + UNIX_L_STKF - 8, cm_wacc, NULL)) return STOP_KSNV;
WriteQ (SP, sav_ps); /* save PS, PC, gp */
WriteQ (SP + 8, PC);
WriteQ (SP + 16, gp);
PC = entSys; /* new PC */
gp = unix_kgp; /* kernel GP */
return SCPE_OK;
}
/* Return from trap or interrupt - always from kernel */
t_stat unix_rti (void)
{
t_uint64 tpc;
uint32 tps, newm;
if (Test (SP, cm_racc, NULL)) return STOP_KSNV; /* validate reads */
if (Test (SP + UNIX_L_STKF - 8, cm_racc, NULL)) return STOP_KSNV;
tps = (uint32) ReadQ (SP); /* read PS, PC */
tpc = ReadQ (SP + 8);
gp = ReadQ (SP + 16); /* restore gp, a0-a2 */
a0 = ReadQ (SP + 24);
a1 = ReadQ (SP + 32);
a2 = ReadQ (SP + 40);
SP = (SP + UNIX_L_STKF); /* incr stack */
newm = (tps >> PSU_V_CM) & PSU_M_CM;
unix_cm = mmu_set_cm (newm); /* new current mode */
if (newm) { /* to user? */
ksp = SP; /* save kernel stack */
SP = usp; /* load user stack */
unix_ipl = 0; /* ipl = 0 */
}
else unix_ipl = (tps >> PSU_V_IPL) & PSU_V_IPL; /* restore ipl */
PC = tpc; /* restore PC */
vax_flag = 0; /* clear VAX, lock flags */
lock_flag = 0;
return SCPE_OK;
}
/* Return from system call - always from kernel to user */
t_stat unix_retsys (void)
{
t_uint64 tpc;
if (Test (SP + 8, cm_racc, NULL)) return STOP_KSNV; /* validate reads */
if (Test (SP + 16, cm_racc, NULL)) return STOP_KSNV;
tpc = ReadQ (SP + 8); /* read PC */
gp = ReadQ (SP + 16); /* restore GP */
ksp = (SP + UNIX_L_STKF); /* update kernel stack */
SP = usp; /* restore user stack */
unix_cm = mmu_set_cm (MODE_E); /* PS = 8 */
unix_ipl = 0;
PC = tpc; /* restore PC */
vax_flag = 0; /* clear VAX, lock flags */
lock_flag = 0;
return SCPE_OK;
}
/* Return from user mode trap - always from user to user */
void unix_urti (void)
{
t_uint64 tsp, tpc;
uint32 tps;
if (SP & 0x3F) ABORT (EXC_RSVO); /* not aligned? */
tps = ReadL (SP + 16); /* read PS */
if (!(tps & PSU_CM) || (tps & PSU_IPL)) ABORT (EXC_RSVO);
at = ReadQ (SP + 0); /* restore at */
tsp = ReadQ (SP + 8); /* read SP, PC */
tpc = ReadQ (SP + 24);
gp = ReadQ (SP + 32); /* restore gp, a0-a2 */
a0 = ReadQ (SP + 40);
a1 = ReadQ (SP + 48);
a2 = ReadQ (SP + 56);
SP = tsp; /* restore SP */
PC = tpc; /* restore PC */
vax_flag = 0; /* clear VAX, lock flags */
lock_flag = 0;
return;
}
/* Unix 3-level PTE lookup
Inputs:
vpn = virtual page number (30b, sext)
*pte = pointer to pte to be returned
Output:
status = 0 for successful fill
EXC_ACV for ACV on intermediate level
EXC_TNV for TNV on intermediate level
*/
uint32 pal_find_pte_unix (uint32 vpn, t_uint64 *l3pte)
{
t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte;
uint32 vpte_vpn;
TLBENT *vpte_p;
vptea = unix_vptptr | (((t_uint64) (vpn & VA_M_VPN)) << 3); /* try virtual lookup */
vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */
vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */
if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V)))
l3ptea = vpte_p->pfn | VA_GETOFF (vptea);
else {
l1ptea = unix_ptptr + VPN_GETLVL1 (vpn);
l1pte = ReadPQ (l1ptea);
if ((l1pte & PTE_V) == 0)
return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV);
l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF);
l2ptea = l2ptea + VPN_GETLVL2 (vpn);
l2pte = ReadPQ (l2ptea);
if ((l2pte & PTE_V) == 0)
return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV);
l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF);
l3ptea = l3ptea + VPN_GETLVL3 (vpn);
}
*l3pte = ReadPQ (l3ptea);
return 0;
}
/* Unix PALcode reset */
t_stat pal_proc_reset_unix (DEVICE *dptr)
{
mmu_ispage = mmu_dspage = SPEN_43;
unix_ipl = PSU_M_IPL;
unix_cm = mmu_set_cm (MODE_K);
pcc_enb = 1;
pal_eval_intr = &pal_eval_intr_unix;
pal_proc_intr = &pal_proc_intr_unix;
pal_proc_trap = &pal_proc_trap_unix;
pal_proc_excp = &pal_proc_excp_unix;
pal_proc_inst = &pal_proc_inst_unix;
pal_find_pte = &pal_find_pte_unix;
return SCPE_OK;
}

Some files were not shown because too many files have changed in this diff Show more