1
0
mirror of https://github.com/simh/simh.git synced 2026-01-23 10:58:43 +00:00
simh.simh/sigma/sigma_fp.c
Mark Pizzolato 3071894c78 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
2012-03-18 09:43:12 -07:00

422 lines
19 KiB
C

/* sigma_fp.c: XDS Sigma floating point simulator
Copyright (c) 2007-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 "sigma_defs.h"
#define UFP_V_GUARD 4
#define UFP_NORM (FP_NORM << UFP_V_GUARD)
#define UFP_CARRY (UFP_NORM << 4)
#define UFP_FRHI (UFP_CARRY|UFP_NORM|FP_M_FRHI)
#define UFP_FRLO 0xFFFFFFFF
/* Double precision fraction add/subtract/compare */
/* Note: UFP_ADD (s, r, r) will not work!!! */
#define UFP_ADD(s1,s2,d) do { \
d.l = (s1.l + s2.l) & UFP_FRLO; \
d.h = (s1.h + s2.h + (d.l < s2.l)) & UFP_FRHI; \
} while (0)
#define UFP_SUB(s1,s2,d) do { \
d.h = (s1.h - s2.h - (s1.l < s2.l)) & UFP_FRHI; \
d.l = (s1.l - s2.l) & UFP_FRLO; \
} while (0)
#define UFP_GE(s1,s2) ((s1.h > s2.h) || \
((s1.h == s2.h) && (s1.l >= s2.l)))
/* Variable and constant shifts; for constants, 0 < k < 32 */
#define UFP_RSH_V(v,s) do { \
if ((s) < 32) { \
v.l = ((v.l >> (s)) | \
( v.h << (32 - (s)))) & UFP_FRLO; \
v.h = v.h >> (s); \
} \
else if ((s) < 64) { \
v.l = v.h >> ((s) - 32); \
v.h = 0; \
} \
else v.l = v.h = 0; \
} while (0)
#define UFP_RSH_K(v,s) do { \
v.l = ((v.l >> (s)) | \
(v.h << (32 - (s)))) & UFP_FRLO; \
v.h = v.h >> (s); \
} while (0)
#define UFP_LSH_K(v,s) do { \
v.h = ((v.h << (s)) | \
(v.l >> (32 - (s)))) & UFP_FRHI; \
v.l = (v.l << (s)) & UFP_FRLO; \
} while (0)
#define UFP_RSH_KP(v,s) do { \
v->l = ((v->l >> (s)) | \
(v->h << (32 - (s)))) & UFP_FRLO; \
v->h = v->h >> (s); \
} while (0)
#define UFP_LSH_KP(v,s) do { \
v->h = ((v->h << (s)) | \
(v->l >> (32 - (s)))) & UFP_FRHI; \
v->l = (v->l << (s)) & UFP_FRLO; \
} while (0)
typedef struct {
uint32 sign;
int32 exp;
uint32 h;
uint32 l;
} ufp_t;
extern uint32 *R;
extern uint32 PSW1;
extern uint32 CC;
void fp_unpack (uint32 hi, uint32 lo, ufp_t *dst);
t_bool fp_clnzro (ufp_t *src, t_bool abnorm);
uint32 fp_pack (ufp_t *src, uint32 rn, t_bool dbl, t_bool rndtrap);
uint32 fp_norm (ufp_t *src);
uint32 fp (uint32 op, uint32 rn, uint32 bva)
{
uint32 rh, rl, mh, ml, i, ediff, nsh;
t_bool s1nz, s2nz;
t_bool dbl = ((op & 0x20) == 0);
ufp_t fop1, fop2, t;
ufp_t res = { 0, 0, 0, 0 };
uint32 tr;
if (dbl) { /* double prec? */
rh = R[rn]; /* get reg operands */
rl = R[rn|1];
if ((tr = ReadD (bva, &mh, &ml, VR)) != 0) /* get mem word */
return tr;
}
else { /* single precision */
rh = R[rn]; /* pad to double */
rl = 0;
if ((tr = ReadW (bva, &mh, VR)) != 0)
return tr;
ml = 0;
}
fp_unpack (rh, rl, &fop1); /* unpack, test */
fp_unpack (mh, ml, &fop2);
CC = 0;
switch (op) { /* case on opcode */
case OP_FSS: /* subtract */
case OP_FSL:
fop2.sign = fop2.sign ^ 1; /* invert mem sign */
/* fall through */
case OP_FAS: /* add */
case OP_FAL:
s1nz = fp_clnzro (&fop1, TRUE); /* test, clean op1 */
s2nz = fp_clnzro (&fop2, TRUE);
if (!s1nz) /* op1 = 0? res = op2 */
res = fop2;
else if (!s2nz) /* op2 = 0? res = op1 */
res = fop1;
else { /* both non-zero */
if (fop1.exp < fop2.exp) { /* exp1 < exp2? */
t = fop2; /* swap operands */
fop2 = fop1;
fop1 = t;
}
ediff = fop1.exp - fop2.exp; /* exp difference */
res.sign = fop1.sign; /* result sign, exp */
res.exp = fop1.exp;
if (ediff) { /* any difference? */
UFP_RSH_V (fop2, ediff * 4); /* shift frac */
if (dbl) { /* double? */
if ((PSW1 & PSW1_FR) == 0) /* rounding off? */
fop2.l &= ~0xF; /* no guard */
}
else fop2.l = 0; /* single? clr lo */
}
if (fop1.sign ^ fop2.sign) { /* eff subtract */
if (UFP_GE (fop1, fop2)) { /* fop1 >= fop2? */
UFP_SUB (fop1, fop2, res); /* sub fractions */
}
else { /* fop2 > fop1 */
UFP_SUB (fop2, fop1, res); /* rev subtract */
res.sign = fop2.sign; /* change signs */
}
} /* end subtract */
else { /* eff add */
UFP_ADD (fop1, fop2, res); /* add fractions */
if (res.h & UFP_CARRY) { /* carry out? */
UFP_RSH_K (res, 4); /* renormalize */
res.exp = res.exp + 1; /* incr exp */
}
} /* end add */
} /* end nz operands */
if (!dbl) /* single? clr lo */
res.l = 0;
if ((PSW1 & PSW1_FN) == 0) { /* postnormalize? */
if ((res.h | res.l) == 0) { /* result zero? */
CC = CC1; /* set signif flag */
if (PSW1 & PSW1_FS) /* trap enabled? */
return TR_FLT;
return fp_pack (&res, rn, dbl, FALSE); /* pack up */
}
nsh = fp_norm (&res); /* normalize */
if ((res.exp < 0) && /* underflow? */
!(PSW1 & PSW1_FZ) && /* !FN */
(PSW1 & PSW1_FS) && /* FS */
(nsh > 2)) { /* shifts > 2? */
CC = CC1 | (res.sign? CC4: CC3); /* signif CC's */
return TR_FLT; /* trap */
} /* end if underflow */
else if (nsh > 2) { /* shifts > 2? */
CC |= CC1 | (res.sign? CC4: CC3); /* set CC1 */
if (PSW1 & PSW1_FS) /* trap enabled? */
return TR_FLT;
}
} /* end if postnorm */
return fp_pack (&res, rn, dbl, TRUE); /* pack result */
case OP_FMS:
case OP_FML: /* floating multiply */
s1nz = fp_clnzro (&fop1, FALSE); /* test, clean op1 */
s2nz = fp_clnzro (&fop2, FALSE);
if (s1nz && s2nz) { /* both non-zero? */
fp_norm (&fop1); /* prenormalize */
fp_norm (&fop2);
UFP_RSH_K (fop2, 4); /* undo guard */
res.sign = fop1.sign ^ fop2.sign; /* result sign */
res.exp = fop1.exp + fop2.exp - FP_BIAS; /* result exp */
if (!dbl) { /* 24b x 24b? */
for (i = 0; i < 24; i++) { /* 24 iterations */
if (fop2.h & 1)
res.h = res.h + fop1.h; /* add hi only */
UFP_RSH_K (res, 1); /* shift dp res */
fop2.h = fop2.h >> 1;
}
res.l = 0; /* single prec */
}
else { /* some low 0's */
for (i = 0; i < 56; i++) { /* 56 iterations */
if (fop2.l & 1) {
UFP_ADD (res, fop1, res);
}
UFP_RSH_K (res, 1);
UFP_RSH_K (fop2, 1);
}
}
fp_norm (&res); /* normalize result */
}
return fp_pack (&res, rn, dbl, TRUE); /* pack result */
case OP_FDS:
case OP_FDL: /* floating divide */
s1nz = fp_clnzro (&fop1, FALSE); /* test, clean op1 */
s2nz = fp_clnzro (&fop2, FALSE);
if (!s2nz) { /* divide by zero? */
CC = CC2; /* set CC2 */
return TR_FLT; /* trap */
}
if (s1nz) { /* divd non-zero? */
fp_norm (&fop1); /* prenormalize */
fp_norm (&fop2);
res.sign = fop1.sign ^ fop2.sign; /* result sign */
res.exp = fop1.exp - fop2.exp + FP_BIAS; /* result exp */
if (!UFP_GE (fop1, fop2)) {
UFP_LSH_K (fop1, 4); /* ensure success */
}
else res.exp = res.exp + 1; /* incr exponent */
for (i = 0; i < (uint32)(dbl? 15: 7); i++) {/* 7/15 hex digits */
UFP_LSH_K (res, 4); /* shift quotient */
while (UFP_GE (fop1, fop2)) { /* while sub works */
UFP_SUB (fop1, fop2, fop1); /* decrement */
res.l = res.l + 1; /* add quo bit */
}
UFP_LSH_K (fop1, 4); /* shift divd */
} /* end hex loop */
if (!dbl) { /* single? */
res.h = res.l; /* move quotient */
res.l = 0;
}
fp_norm (&res); /* normalize result */
}
return fp_pack (&res, rn, dbl, TRUE); /* pack result */
} /* end case */
return SCPE_IERR;
}
void ShiftF (uint32 rn, uint32 stype, uint32 sc)
{
uint32 opnd, opnd1;
ufp_t src;
opnd = R[rn]; /* get operands */
opnd1 = stype? R[rn|1]: 0; /* zextend single */
fp_unpack (opnd, opnd1, &src); /* unpack */
CC = 0;
if (sc & SCSIGN) { /* right? */
sc = SHF_M_SC + 1 - sc;
while (sc > 0) { /* while count */
UFP_RSH_K (src, 4); /* shift right hex */
if (stype) /* zero guard */
src.l &= ~0xF;
else src.h &= ~0xF;
src.exp++; /* incr exp */
sc--;
if (src.exp > FP_M_EXP) { /* overflow? */
CC |= CC2; /* set CC2, stop */
break;
}
} /* end while */
if ((src.h | src.l) == 0) { /* result 0? */
if (stype) /* result is true 0 */
R[rn|1] = 0;
R[rn] = 0;
CC = 0;
return;
}
}
else { /* left */
if ((src.h | src.l) == 0) { /* fraction 0? */
if (stype) /* result is true 0 */
R[rn|1] = 0;
R[rn] = 0;
CC = CC1;
return;
}
while ((sc > 0) && ((src.h & UFP_NORM) == 0)) { /* while count & !norm */
UFP_LSH_K (src, 4); /* hex shift left */
src.exp--; /* decr exp */
sc--;
if (src.exp < 0) { /* underflow? */
CC |= CC2; /* set CC2, stop */
break;
}
} /* end while */
if (src.h & UFP_NORM) /* normalized? */
CC |= CC1; /* set CC1 */
}
fp_pack (&src, rn, stype, FALSE); /* pack result */
return;
}
void fp_unpack (uint32 hi, uint32 lo, ufp_t *dst)
{
dst->sign = FP_GETSIGN (hi); /* get sign */
if (dst->sign) /* negative? */
NEG_D (hi, lo); /* 2's compl */
dst->h = FP_GETFRHI (hi); /* get fraction */
dst->l = FP_GETFRLO (lo);
dst->exp = FP_GETEXP (hi); /* get exp */
UFP_LSH_KP (dst, 4); /* guard result */
return;
}
/* Test for and clean a floating point zero
abnorm defines whether to allow "abnormal" zeros */
t_bool fp_clnzro (ufp_t *src, t_bool abnorm)
{
if (((src->h | src->l) == 0) && /* frac zero and */
(!abnorm || (src->exp == 0))) { /* exp zero or !ab */
src->sign = 0; /* true zero */
src->exp = 0;
return FALSE;
}
return TRUE; /* non-zero */
}
uint32 fp_pack (ufp_t *src, uint32 rn, t_bool dbl, t_bool rndtrap)
{
static ufp_t fp_zero = { 0, 0, 0, 0};
uint32 opnd, opnd1;
if (src->h || (dbl && src->l)) { /* result != 0? */
CC |= (src->sign? CC4: CC3); /* set CC's */
if (rndtrap) { /* round, trap? */
if (PSW1 & PSW1_FR) { /* round? */
if (dbl) { /* double prec? */
src->l = (src->l + 0x8) & UFP_FRLO;
src->h = src->h + (src->l < 0x8);
}
else src->h = src->h + 0x8; /* no, single */
if (src->h & UFP_CARRY) { /* carry out? */
UFP_RSH_KP (src, 4); /* renormalize */
src->exp = src->exp + 1;
}
} /* end if round */
if (src->exp > FP_M_EXP) { /* overflow? */
CC |= CC2; /* flag */
return TR_FLT;
}
else if (src->exp < 0) { /* underflow? */
if (PSW1 & PSW1_FZ) { /* trap enabled? */
CC |= CC1 | CC2; /* flag */
return TR_FLT;
}
*src = fp_zero; /* result 0 */
CC = CC1|CC2; /* special CC's */
}
} /* end rnd trap */
UFP_RSH_KP (src, 4); /* remove guard */
if (!dbl) /* single? lose lower */
src->l = 0;
if ((src->h | src->l) == 0) /* result now 0? */
src->exp = src->sign = 0;
}
else *src = fp_zero;
opnd = ((src->exp & FP_M_EXP) << FP_V_EXP) | /* repack */
((src->h & FP_M_FRHI) << FP_V_FRHI);
opnd1 = src->l & FP_M_FRLO;
if (src->sign) /* negative? */
NEG_D (opnd, opnd1);
R[rn] = opnd; /* store result */
if (dbl && ((rn & 1) == 0))
R[rn|1] = opnd1;
return 0;
}
uint32 fp_norm (ufp_t *src)
{
uint32 nsh;
nsh = 0;
src->h &= UFP_FRHI;
if (src->h || src->l) { /* if non-zero */
while ((src->h & UFP_NORM) == 0) { /* until normalized */
UFP_LSH_KP (src, 4); /* hex shift left */
src->exp--; /* decr exponent */
nsh++; /* count shifts */
}
}
return nsh;
}