1
0
mirror of https://github.com/DoctorWkt/unix-jun72.git synced 2026-02-14 12:05:02 +00:00
Files
DoctorWkt.unix-jun72/tools/apout/ke11a.c
2008-05-06 23:25:22 +00:00

231 lines
6.9 KiB
C

/* ke11a.c - this holds the emulation of the PDP 11/20 extended
* arithmetic element. We only need this for 1st Edition a.out support.
* Code kindly borrowed from the eae support written by Tim Shoppa
* (shoppa@trailing-edge.com) for Bob Supnik's PDP-11 emulator.
*
* $Revision: 1.7 $
* $Date: 1999/12/28 03:57:31 $
*/
#ifdef EMUV1
#include "defines.h"
#include <unistd.h>
void eae_wr(u_int16_t data, u_int16_t PA, int32_t access);
void set_SR(void);
/* I/O dispatch routine, I/O addresses 177300 - 177316 */
#define eae_DIV 0177300 /* Divide */
#define eae_AC 0177302 /* Accumulator */
#define eae_MQ 0177304 /* MQ */
#define eae_MUL 0177306 /* Multiply */
#define eae_SC 0177310 /* Step counter */
#define eae_SR 0177311 /* Status register */
#define eae_NOR 0177312 /* Normalize */
#define eae_LSH 0177314 /* Logical shift */
#define eae_ASH 0177316 /* Arithmetic shift */
#define WRITEB 1 /* Write of a byte */
#define WRITEW 2 /* Write of a word */
/* The MQ, AC, SC, and SR registers specify the state of the EAE */
/* Here we define them as int32's, though in real life the MQ and AC */
/* are 16 bits and the SC and SR are 8 bits */
int32_t MQ; /* Multiply quotient */
int32_t AC; /* Accumulator */
int32_t SC = 0; /* Shift counter */
int32_t SR; /* Status register */
/* Load a word from one of the KE11 registers */
int16_t kell_word(u_int16_t addr)
{
int16_t data;
int pid;
switch (addr) {
case eae_DIV:
data = 0; break;
case eae_MQ:
data = MQ; break;
case eae_AC: /* high 16 bits of MQ */
data = AC; break;
case eae_SC:
set_SR();
data = (SR << 8) | SC; break;
case eae_SR:
set_SR();
data = (SR << 8); break;
case eae_NOR:
data = SC; break;
case eae_LSH:
case eae_ASH:
case eae_MUL:
data = 0; break;
default:
pid = getpid();
(void) fprintf(stderr, "Apout - pid %d unknown KE11 register 0%o\n",
pid, addr);
exit(EXIT_FAILURE);
}
return data;
}
/* Load a byte from one of the KE11 registers */
int8_t kell_byte(u_int16_t addr)
{
if (addr&1) printf("Hmm, KE11 access on 0%o\n",addr);
return ((int8_t) kell_word(addr));
}
/* Save a word to one of the KE11 registers */
void kesl_word(u_int16_t addr, u_int16_t word)
{
eae_wr(word, addr, WRITEW);
}
/* Save a byte to one of the KE11 registers */
void kesl_byte(u_int16_t addr, u_int8_t byte)
{
eae_wr(byte, addr, WRITEB);
}
void eae_wr(u_int16_t data, u_int16_t PA, int32_t access)
{
int32_t divisor, quotient, remainder;
int32_t dividend, product;
int32_t oldMQ;
int pid;
switch (PA) {
case eae_DIV:
SC = 0;
dividend = (AC << 16) | MQ;
divisor = data;
if (divisor >> 15) divisor = divisor | ~077777;
quotient = dividend / divisor;
MQ = quotient & 0177777;
remainder = dividend % divisor;
AC = remainder & 0177777;
SR = SR & 076;
if ((quotient > 32767) || (quotient < -32768)) { /* did we overflow? */
if (dividend < 0) SR = SR | 0100;
else SR = SR | 0200;
} else {
if (quotient < 0) SR = SR | 0300;
}
return;
case eae_AC:
AC = data;
if ((access == WRITEB) & (data >> 7))
AC = AC | 0177400;
return;
case eae_AC + 1:
printf("write to AC+1; data=%o", data);
AC = (AC & 0377) | (data << 8);
return;
case eae_MQ:
MQ = data;
if ((access == WRITEB) & (data >> 7)) MQ = MQ | 0177400;
if (MQ >> 15) AC = 0177777;
else AC = 0;
return;
case eae_MQ + 1:
printf("write to MQ+1; data=%o", data);
MQ = (MQ & 0377) | (data << 8);
if (MQ >> 15) AC = 0177777;
else AC = 0;
return;
case eae_MUL:
SC = 0;
if (data >> 15) data = data | ~077777;
if (MQ >> 15) MQ = MQ | ~077777;
product = MQ * data;
MQ = product & 0177777;
AC = (product >> 16) & 0177777;
SR = SR & 076;
if (AC >> 15) SR = SR | 0300; /* set sign bit if necessary */
return;
case eae_SC:
if (access == WRITEB) return; /* byte writes are no-ops */
SR = (data >> 8) & 0177777;
SC = data & 0000077;
return;
case eae_SR:
return; /* this is a No-op */
case eae_NOR: /* Normalize */
MQ = (AC << 16) | MQ; /* 32-bit number to normalize in MQ */
for (SC = 0; SC < 31; SC++) {
if (MQ == (0140000 << 16))
break;
if ((((MQ >> 30) & 3) == 1) || (((MQ >> 30) & 3) == 2))
break;
MQ = MQ << 1;
}
printf("SC = %o\r\n", SC);
AC = (MQ >> 16) & 0177777;
MQ = MQ & 0177777;
return;
case eae_LSH: /* Logical shift */
MQ=(AC<<16)|MQ; /* Form a temporary 32-bit entity */
oldMQ=MQ & 0x80000000; /* Save the sign bit for later */
SR=SR&0176; /* Clear overflow & carry bits */
data=data & 077; /* Convert data from 6-bit */
if (data>31) {
data=64-data; /* Shift in a -ve direction */
SR=SR|((MQ>>(data-1))&1); /* Get the bit that went off the end */
MQ=MQ>>data; /* and do the right shift */
} else { /* Else left shift */
if ((MQ<<(data-1))&0x80000000) SR|=1; /* Get the bit off the end */
MQ=MQ<<data; /* and do the left shift */
}
oldMQ= oldMQ ^ MQ; /* Any difference in sign bit? */
if (oldMQ & 0x80000000) SR|=0200;/* Yes, set the overflow bit */
AC=(MQ>>16)&0177777; /* Save result in AC and MQ */
MQ=MQ&0177777;
set_SR();
return;
case eae_ASH: /* Arithmetic shift */
MQ=(AC<<16)|MQ; /* Form a temporary 32-bit entity */
oldMQ=MQ & 0x80000000; /* Save the sign bit for later */
SR=SR&0176; /* Clear overflow & carry bits */
data=data & 077; /* Convert data from 6-bit */
if (data>31) {
data=64-data; /* Shift in a -ve direction */
divisor=1 << data; /* Work out the dividing factor */
SR=SR|((MQ>>(data-1))&1); /* Get the bit that went off the end */
MQ=MQ/divisor; /* and do the right shift */
} else { /* Else left shift */
product=1 << data; /* Work out the multiplying factor */
if ((MQ<<(data-1))&0x80000000) SR|=1; /* Get the bit off the end */
MQ=MQ*product; /* and do the left shift */
}
oldMQ= oldMQ ^ MQ; /* Any difference in sign bit? */
if (oldMQ & 0x80000000) SR|=0200;/* Yes, set the overflow bit */
AC=(MQ>>16)&0177777; /* Save result in AC and MQ */
MQ=MQ&0177777;
set_SR();
return;
default:
pid = getpid();
(void) fprintf(stderr, "Apout - pid %d unknown KE11 register 0%o\n",
pid, PA);
exit(EXIT_FAILURE);
}
}
void set_SR(void)
{
SR = SR & 0301; /* clear the result bits we can set here */
if (((MQ & 0100000) == 0) && (AC == 0)) SR = SR | 002;
if (((MQ & 0100000) == 0100000) && (AC == 0177777)) SR = SR | 002;
if ((AC == 0) && (MQ == 0)) SR = SR | 0004;
if (MQ == 0) SR = SR | 0010;
if (AC == 0) SR = SR | 0020;
if (AC == 0177777) SR = SR | 0040;
}
#endif /* EMUV1 */