ALU PROM A10?

Juergen Buchmueller pullmoll at t-online.de
Fri Jun 29 15:58:12 PDT 2007


I think there's still one PROM missing: the ALU PROM A10 (82S23). It
contains the mapping of ALU functions to the 74181 chips. Its contents is
described in the documentation, however, it isn't entirely obvious if e.g.
the SKIP address input is active 0 or 1. SKIP _should_ affect just one data
word, but we don't know for sure.

I'm asking because I rewrote the ALU code with the 74181 docs in hand,
now doing a "full 74181", even if not all of its functions are used.

I wanted to do it right instead of too much guessing. Should I be asking
for too much, we can still construct the 32 bytes from the PDF and a little
experimentation.

Eric, there are some more discrepancies or misleading things lurking in
Altogether's ALU and shifter emulation:

The normal shifts, i.e. without MAGIC or DNS, do not set or alter any
carry. There is no such thing as a "shifter carry out".

There's really only one carry in the ALU: the most significant 74181's
output ALUCO', which is used only to be latched in LALUC0 when the L flag
of a microcode is set, and it is then latched as ALUC0 (inverted).

This is because the 74181 sees 1 (high) as no carry, and 0 (low) as carry
for active HIGH inputs and outputs, which is how the 74181s are used in the
Alto. Thus the ALUC0' output is 0 for a carry from bit 16, i.e.
	aluc0_inv = (~alu >> 16) & 1;

If the L flag of the microcode is set, then either ALUC0 or a zero is
latched in LALUC0, and which one is latched depends on the signal ALUM' from
said PROM.

As I see it, ALUC0 is latched in LALUC0 for arithmetic operations, while a 0
is latched for all logic operations. This is how I understood it, and I
hope I got the multiple inverting right.

The Emulator carry is, as we know, entirely different from the ALUC0 and
LALUC0. It is, however, used to define what's shifted into the bits opened
in the shifter. The name for this shifted-in carry is "XC" in the
schematics.

Here's my latest version of DNS based on the ALU schematics.

/*
 *  CARRY     = !emulator_carry
 *  exorB     = IR11 ^ IR10
 *  ORA       = !(exorB | CARRY)
 *            = (exorB | CARRY) ^ 1
 *  exorC     = ORA ^ !IR11
 *            = ORA ^ IR11 ^ 1
 *  exorD     = exorC ^ LALUC0
 *  XC        = !(!(DNS & exorD) & !(MAGIC & OUTza))
 *            = (DNS & exorD) | (MAGIC & OUTza)
 *            = exorD, because this is the DNS function
 *  NEWCARRY  = [XC, L(00), L(15), XC]
 *                  for F1 = no shift, <-L RSH 1, <-L LSH 1, <-L LCY 8
 *  SHZERO    = shifter == 0
 *  DCARRY    = !((!IR12 & NEWCARRY) | (IR12 & CARRY))
 *            = (((IR12 ^ 1) & NEWCARRY) | (IR12 & CARRY)) ^ 1
 *  DSKIP     = !((!NEWCARRY & IR14) | (SHZERO & IR13)) ^ !IR15
 *            = ((((NEWCARRY^1) & IR14) | (SHZERO & IR13)) ^ 1) ^ (IR15^1)
 *            = (((NEWCARRY^1) & IR14) | (SHZERO & IR13)) ^ IR15
 */
	uint8_t IR10 = (ir >> (15-10)) & 1;
	uint8_t IR11 = (ir >> (15-11)) & 1;
	uint8_t IR12 = (ir >> (15-12)) & 1;
	uint8_t IR13 = (ir >> (15-13)) & 1;
	uint8_t IR14 = (ir >> (15-14)) & 1;
	/* the compiler knows how to simplify the following line */
	uint8_t IR15 = (ir >> (15-15)) & 1;
	uint8_t exorB = IR11 ^ IR10;
	uint8_t CARRY = emulator_carry ^ 1;
	uint8_t ORA = (exorB | CARRY) ^ 1;
	uint8_t exorC = ORA ^ (IR11 ^ 1);
	uint8_t exorD = exorC ^ LALUC0;
	uint8_t XC = exorD;
	uint8_t NEWCARRY;
	uint8_t DCARRY;
	uint8_t DSKIP;
	uint8_t SHZERO;

	switch (f1) {	/* F1 of the microcode */
	case f1_l_rsh_1:	/* <-L RSH 1 */
		cpu.shifter |= XC << 15;
		NEWCARRY = cpu.l & 1;
		break;
	case f1_l_lsh_1:	/* <-L LSH 1 */
		cpu.shifter |= XC;
		NEWCARRY = cpu.l >> 15;
		break;
	case f1_l_lcy_8:	/* <-L LCY 8 */
	default:		/* other */
		NEWCARRY = XC;
		break;
	}
	SHZERO = (cpu.shifter == 0);

	DCARRY = (((IR12 ^ 1) & NEWCARRY) | (IR12 & CARRY)) ^ 1;

	DSKIP = (((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ IR15;

	/* DCARRY is latched as new emulator_carry on F2=DNS */
	emulator_carry = DCARRY;

	/* DSKIP is latched as new emulator skip */
	emulator_skip = DSKIP;

	/* !(IR12 & DNS) -> write the register file */
	if (!IR12) {
		r[rsel] = shifter;
	}

And this is how I do MAGIC now:

	int XC;

	switch (MIR_F1(cpu.mir)) {
	case f1_l_rsh_1:	/* <-L MRSH 1 */
		XC = t & 1;
		cpu.shifter |= XC << 15;
		break;
	case f1_l_lsh_1:	/* <-L MLSH 1 */
		XC = t >> 15;
		shifter |= XC;
		break;
	case f1_l_lcy_8:	/* <-L LCY 8 */
	default:		/* other */
		/* leave shifter alone */
		break;
	}

I'm not yet 100% sure if I got all the DeMorgan simplifications and the
multiple inversions right, so please take it with a grain of salt until I
can confirm success :-)

Juergen


More information about the Altogether-devel mailing list