1
0
mirror of https://github.com/livingcomputermuseum/ContrAlto.git synced 2026-01-18 09:03:01 +00:00

Fixed instruction register decoding SFs for Emulator Task; first stab at handling (most) DNS<- operations including setting SKIP and CARRY flip flops. BLT now succeeds, Nova code in bootstrap is running.

This commit is contained in:
Josh Dersch 2015-10-29 17:02:22 -07:00
parent 2918ede7ce
commit c0f23685b1
6 changed files with 246 additions and 37 deletions

View File

@ -1,4 +1,5 @@
using System;
using Contralto.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -65,7 +66,13 @@ namespace Contralto.CPU
case AluFunction.BusMinus1:
r = bus - 1;
_carry = (r < 0) ? 1 : 0;
// Just for clarification; the datasheet specifies:
// "Because subtraction is actually performed by complementary
// addition (1s complement), a carry out means borrow; thus,
// a carry is generated when there is no underflow and no carry
// is generated when there is underflow."
_carry = (r <= 0) ? 0 : 1;
break;
case AluFunction.BusPlusT:
@ -75,12 +82,12 @@ namespace Contralto.CPU
case AluFunction.BusMinusT:
r = bus - t;
_carry = (r < 0) ? 1 : 0;
_carry = (r <= 0) ? 0 : 1;
break;
case AluFunction.BusMinusTMinus1:
r = bus - t - 1;
_carry = (r < 0) ? 1 : 0;
_carry = (r <= 0) ? 0 : 1;
break;
case AluFunction.BusPlusTPlus1:

View File

@ -134,8 +134,8 @@ namespace Contralto.CPU
}
}
// And invert lines 1-7
return ((~mappedData) & 0x7f) | (mappedData & 0x80);
// And invert data lines
return (~mappedData) & 0xff;
}
private static RomFile[] _constantRoms =

View File

@ -12,6 +12,36 @@ namespace Contralto.CPU.Nova
/// </summary>
public static class NovaDisassembler
{
static NovaDisassembler()
{
_altoIOTable = new Dictionary<ushort, string>();
_altoIOTable.Add(0x6210, "MUL");
_altoIOTable.Add(0x6211, "DIV");
_altoIOTable.Add(0x6000, "CYCLE");
_altoIOTable.Add(0x6900, "JSRII");
_altoIOTable.Add(0x6a00, "JSRIS");
_altoIOTable.Add(0x6e00, "CONVERT");
_altoIOTable.Add(0x6203, "RCLK");
_altoIOTable.Add(0x6204, "SIO");
_altoIOTable.Add(0x6205, "BLT");
_altoIOTable.Add(0x6206, "BLKS");
_altoIOTable.Add(0x6207, "SIT");
_altoIOTable.Add(0x6208, "JMPRAM");
_altoIOTable.Add(0x6209, "RDRAM");
_altoIOTable.Add(0x620a, "WRTRAM");
_altoIOTable.Add(0x620c, "VERSION");
_altoIOTable.Add(0x620d, "DREAD");
_altoIOTable.Add(0x620e, "DWRITE");
_altoIOTable.Add(0x620f, "DEXCH");
_altoIOTable.Add(0x6212, "DIAGNOSE1");
_altoIOTable.Add(0x6213, "DIAGNOSE2");
_altoIOTable.Add(0x6214, "BITBLT");
_altoIOTable.Add(0x6215, "XMLDA");
_altoIOTable.Add(0x6216, "XMSTA");
}
/// <summary>
/// Disassembles the specified instruction
/// </summary>
@ -165,6 +195,15 @@ namespace Contralto.CPU.Nova
{
StringBuilder d = new StringBuilder();
//
// First see if this is an Alto-specific instruction; if so
// use those mnemonics. Otherwise decode as a Nova I/O instruction.
//
if (_altoIOTable.ContainsKey(instructionWord))
{
return _altoIOTable[instructionWord];
}
// Accumulator
int ac = (instructionWord & 0x1800) >> 11;
@ -239,6 +278,11 @@ namespace Contralto.CPU.Nova
return d.ToString();
}
/// <summary>
/// Holds a map from opcode to Alto I/O mnemonics
/// </summary>
private static Dictionary<ushort, string> _altoIOTable;
private enum InstructionClass
{
MEM = 0x0000,

View File

@ -29,9 +29,26 @@ namespace Contralto.CPU
{
_op = ShifterOp.Invalid;
_count = 0;
_output = 0;
_magic = false;
}
/// <summary>
/// Returns the result of the last Shifter operation (via DoOperation).
/// </summary>
public static ushort Output
{
get { return _output; }
}
/// <summary>
/// Returns the last DNS-style Carry bit from the last operation (via DoOperation).
/// </summary>
public static int DNSCarry
{
get { return _dnsCarry; }
}
public static void SetOperation(ShifterOp op, int count)
{
_op = op;
@ -52,17 +69,18 @@ namespace Contralto.CPU
/// TODO: this is still kind of clumsy.
/// </summary>
/// <param name="dns"></param>
public static void SetDNS(bool dns)
public static void SetDNS(bool dns, int carry)
{
_dns = dns;
_dnsCarry = carry;
}
/// <summary>
/// Does the last specified operation to the specified inputs
/// Does the last specified operation to the specified inputs; the result
/// can be read from Output.
/// </summary>
/// <param name="input">Normal input to be shifted</param>
/// <param name="t">CPU t register, for MAGIC shifts only</param>
/// <returns></returns>
/// <param name="t">CPU t register, for MAGIC shifts only</param>
public static ushort DoOperation(ushort input, ushort t)
{
// Sanity check: MAGIC and DNS cannot be set at the same time.
@ -70,25 +88,24 @@ namespace Contralto.CPU
{
throw new InvalidOperationException("Both MAGIC and DNS bits are set.");
}
ushort output = 0;
switch(_op)
{
case ShifterOp.Invalid:
throw new InvalidOperationException("Shifter op has not been set.");
case ShifterOp.None:
output = input;
_output = input;
break;
case ShifterOp.ShiftLeft:
output = (ushort)(input << _count);
_output = (ushort)(input << _count);
if (_magic)
{
// "MAGIC places the high order bit of T into the low order bit of the
// shifter output on left shifts..."
output |= (ushort)((t & 0x8000) >> 15);
_output |= (ushort)((t & 0x8000) >> 15);
}
else if (_dns)
{
@ -97,13 +114,13 @@ namespace Contralto.CPU
break;
case ShifterOp.ShiftRight:
output = (ushort)(input >> _count);
_output = (ushort)(input >> _count);
if (_magic)
{
// "...and places the low order bit of T into the high order bit position
// of the shifter output on right shifts."
output |= (ushort)((t & 0x1) << 15);
_output |= (ushort)((t & 0x1) << 15);
}
else if (_dns)
{
@ -113,11 +130,11 @@ namespace Contralto.CPU
case ShifterOp.RotateLeft:
// TODO: optimize, this is stupid
output = input;
_output = input;
for (int i = 0; i < _count; i++)
{
int c = (output & 0x8000) >> 15;
output = (ushort)((output << 1) | c);
int c = (_output & 0x8000) >> 15;
_output = (ushort)((_output << 1) | c);
}
if (_dns)
@ -128,11 +145,11 @@ namespace Contralto.CPU
case ShifterOp.RotateRight:
// TODO: optimize, this is still stupid
output = input;
_output = input;
for (int i = 0; i < _count; i++)
{
int c = (output & 0x1) << 15;
output = (ushort)((output >> 1) | c);
int c = (_output & 0x1) << 15;
_output = (ushort)((_output >> 1) | c);
}
break;
@ -140,12 +157,14 @@ namespace Contralto.CPU
throw new InvalidOperationException(String.Format("Unhandled shift operation {0}", _op));
}
return output;
return _output;
}
private static ShifterOp _op;
private static ushort _output;
private static int _count;
private static bool _magic;
private static bool _dns;
private static int _dnsCarry;
}
}

View File

@ -99,6 +99,13 @@ namespace Contralto.CPU
_rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x1800) >> 11) ^ 3);
break;
case EmulatorF2.LoadDNS:
//
// "...DNS also addresses R from (3-IR[3 - 4])..."
//
_rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x1800) >> 11) ^ 3);
break;
}
}
@ -206,10 +213,8 @@ namespace Contralto.CPU
}
else
{
// Use the PROM.
// We OR in 0x80 because the top address line is controlled by the value of ACSOURCE(2), which is always
// 1 here (since ACSOURCE is 14 decimal).
_nextModifier = ControlROM.ACSourceROM[((_cpu._ir & 0x7f00) >> 8) | 0x80];
// Use the PROM.
_nextModifier = ControlROM.ACSourceROM[((_cpu._ir & 0x7f00) >> 8)];
}
break;
@ -228,8 +233,67 @@ namespace Contralto.CPU
break;
case EmulatorF2.LoadDNS:
// DNS<- modifies the normal shift operations.
Shifter.SetDNS(true);
// DNS<- does the following:
// - modifies the normal shift operations to perform Nova-style shifts (done here)
// - addresses R from 3-IR[3-4] (destination AC) (see Early LoadDNS handler)
// - stores into R unless IR[12] is set (done here)
// - calculates Nova-style CARRY bit (done here)
// - sets the SKIP and CARRY flip-flops appropriately (see Late LoadDNS handler)
int carry = 0;
// Also indicates modifying CARRY
_loadR = (_cpu._ir & 0x0008) == 0;
// At this point the ALU has already done its operation but the shifter has not yet run.
// We need to set the CARRY bit that will be passed through the shifter appropriately.
// Select carry input value based on carry control
switch(_cpu._ir & 0x30)
{
case 0x00:
// Nothing; CARRY unaffected.
carry = _carry;
break;
case 0x10:
carry = 0; // Z
break;
case 0x20:
carry = 1; // O
break;
case 0x30:
carry = (~_carry) & 0x1; // C
break;
}
// Now modify the result based on the current ALU result
switch (_cpu._ir & 0x700)
{
case 0x000:
case 0x200:
case 0x700:
// COM, MOV, AND - Carry unaffected
break;
case 0x100:
case 0x300:
case 0x400:
case 0x500:
case 0x600:
// NEG, INC, ADC, SUB, ADD, AND - invert the carry bit
if (ALU.Carry != 0)
{
carry = (~carry) & 0x1;
}
break;
}
// Tell the Shifter to do a Nova-style shift with the
// given carry bit.
Shifter.SetDNS(true, carry);
break;
default:
@ -238,6 +302,69 @@ namespace Contralto.CPU
}
}
protected override void ExecuteSpecialFunction2Late(MicroInstruction instruction)
{
EmulatorF2 ef2 = (EmulatorF2)instruction.F2;
switch (ef2)
{
case EmulatorF2.LoadDNS:
//
// Set SKIP and CARRY flip-flops based on the final result of the operation after having
// passed through the shifter.
//
ushort result = Shifter.Output;
int carry = Shifter.DNSCarry;
switch (_cpu._ir & 0x7)
{
case 0:
// None, SKIP is reset
_skip = 0;
break;
case 1: // SKP
// Always skip
_skip = 1;
break;
case 2: // SZC
// Skip if carry result is zero
_skip = (carry == 0) ? 1 : 0;
break;
case 3: // SNC
// Skip if carry result is nonzero
_skip = carry;
break;
case 4: // SZR
_skip = (result == 0) ? 1 : 0;
break;
case 5: // SNR
_skip = (result != 0) ? 1 : 0;
break;
case 6: // SEZ
_skip = (result == 0 || carry == 0) ? 1 : 0;
break;
case 7: // SBN
_skip = (result != 0 && carry != 0) ? 1 : 0;
break;
}
if (_loadR)
{
// Write carry flag back.
_carry = carry;
}
break;
}
}
// From Section 3, Pg. 31:
// "The emulator has two additional bits of state, the SKIP and CARRY flip flops. CARRY is distinct from the
// microprocessors ALUC0 bit, tested by the ALUCY function. CARRY is set or cleared as a function of IR and

View File

@ -90,16 +90,17 @@ namespace Contralto.CPU
/// <returns>True if a task switch has been requested by a TASK instruction, false otherwise.</returns>
protected virtual bool ExecuteInstruction(MicroInstruction instruction)
{
bool nextTask = false;
bool loadR = false;
bool nextTask = false;
ushort aluData = 0;
ushort nextModifier = 0;
_loadR = false;
_loadS = false;
_rSelect = 0;
_busData = 0;
Shifter.SetMagic(false);
Shifter.SetDNS(false, 0);
//
// Wait for memory state machine if a memory operation is requested by this instruction and
@ -157,7 +158,7 @@ namespace Contralto.CPU
case BusSource.LoadR:
_busData = 0; // "Loading R forces the BUS to 0 so that an ALU function of 0 and T may be executed simultaneously"
loadR = true;
_loadR = true;
break;
case BusSource.None:
@ -215,7 +216,7 @@ namespace Contralto.CPU
// more than one source is gated to it. Up to 32 such mask contans can be provided for each of the four bus sources
// > 4.
// NOTE also:
// "Note that the [emulator task F2] functions which replace the low bits of RSELECT with IR aaffect only the
// "Note that the [emulator task F2] functions which replace the low bits of RSELECT with IR affect only the
// selection of R; they do not affect the address supplied to the constant ROM."
// Hence we use the unmodified RSELECT value here and above.
if ((int)instruction.BS > 4 ||
@ -342,9 +343,9 @@ namespace Contralto.CPU
// Write back to registers:
//
// Do writeback to selected R register from shifter output
if (loadR)
{
_cpu._r[_rSelect] = Shifter.DoOperation(_cpu._l, _cpu._t);
if (_loadR)
{
_cpu._r[_rSelect] = Shifter.DoOperation(_cpu._l, _cpu._t);
}
// Do writeback to selected R register from M
@ -384,6 +385,11 @@ namespace Contralto.CPU
_cpu._aluC0 = (ushort)ALU.Carry;
}
//
// Execute special functions that happen late in the cycle
//
ExecuteSpecialFunction2Late(instruction);
//
// Select next address, using the address modifier from the last instruction.
//
@ -405,6 +411,11 @@ namespace Contralto.CPU
protected abstract void ExecuteSpecialFunction2(MicroInstruction instruction);
protected virtual void ExecuteSpecialFunction2Late(MicroInstruction instruction)
{
// Nothing by default.
}
//
// Per uInstruction Task Data:
// Modified by both the base Task implementation and any subclasses
@ -415,6 +426,7 @@ namespace Contralto.CPU
protected ushort _nextModifier; // Bits ORed onto the NEXT field of the current instruction
protected uint _rSelect; // RSELECT field from current instruction, potentially modified by task
protected bool _loadS; // Whether to load S from M at and of cycle
protected bool _loadR; // Whether to load R from shifter at end of cycle.
//