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

Added (temporary) code to debug floating point issue with Dance,Starwars.

This commit is contained in:
Josh Dersch 2016-03-08 17:23:32 -08:00
parent 41b6a76b2a
commit b6e43080f2
18 changed files with 451 additions and 58 deletions

View File

@ -126,15 +126,12 @@ namespace Contralto.CPU
// Invoke the task switch, this will take effect after
// the NEXT instruction, not this one.
TaskSwitch();
}
else
}
else if (_nextTask != null)
{
// If we have a new task, switch to it now.
if (_nextTask != null)
{
_currentTask = _nextTask;
_nextTask = null;
}
// If we have a new task, switch to it now.
_currentTask = _nextTask;
_nextTask = null;
}
}
@ -172,7 +169,7 @@ namespace Contralto.CPU
//
WakeupTask(CPU.TaskType.DiskSector);
Log.Write(Logging.LogComponent.CPU, "Silent Boot; microcode banks initialized to {0}", Conversion.ToOctal(_rmr));
Log.Write(LogComponent.CPU, "Silent Boot; microcode banks initialized to {0}", Conversion.ToOctal(_rmr));
}
/// <summary>

View File

@ -159,22 +159,24 @@ namespace Contralto.CPU
}
break;
case ShifterOp.RotateLeft:
// TODO: optimize, this is stupid
_output = input;
for (int i = 0; i < _count; i++)
{
int c = (_output & 0x8000) >> 15;
_output = (ushort)((_output << 1) | c);
}
case ShifterOp.RotateLeft:
if (_dns)
{
//
// "Swap the 8-bit halves of the 16-bit result. The carry is not affected."
//
_output = (ushort)(((input & 0xff00) >> 8) | ((input & 0x00ff) << 8));
}
}
else
{
// TODO: optimize, this is stupid
_output = input;
for (int i = 0; i < _count; i++)
{
int c = (_output & 0x8000) >> 15;
_output = (ushort)((_output << 1) | c);
}
}
break;
case ShifterOp.RotateRight:

View File

@ -1,4 +1,5 @@
using System;
using Contralto.Logging;
using System;
namespace Contralto.CPU
{
@ -50,7 +51,7 @@ namespace Contralto.CPU
// "When an S register is being loaded from M, the processor bus receives an
// undefined value rather than being set to zero."
_loadS = true;
return 0xffff; // TODO: technically this is an "undefined value.".
return 0xffff; // Technically this is an "undefined value," we're defining it as -1.
default:
throw new InvalidOperationException(String.Format("Unhandled bus source {0}", bs));
@ -125,7 +126,7 @@ namespace Contralto.CPU
}
else
{
Logging.Log.Write(Logging.LogType.Warning, Logging.LogComponent.EmulatorTask, "STARTF for non-Ethernet device (code {0})",
Log.Write(Logging.LogType.Warning, Logging.LogComponent.EmulatorTask, "STARTF for non-Ethernet device (code {0})",
Conversion.ToOctal(_busData));
}
}
@ -198,8 +199,7 @@ namespace Contralto.CPU
_cpu._ir = _busData;
// "IR<- also merges bus bits 0, 5, 6 and 7 into NEXT[6-9] which does a first level
// instruction dispatch."
// TODO: is this an AND or an OR operation? (how is the "merge" done?)
// instruction dispatch."
// Assuming for now this is an OR operation like everything else that modifies NEXT.
_nextModifier = (ushort)(((_busData & 0x8000) >> 12) | ((_busData & 0x0700) >> 8));
@ -302,8 +302,7 @@ namespace Contralto.CPU
break;
case EmulatorF2.BUSODD:
// "...merges BUS[15] into NEXT[9]."
// TODO: is this an AND or an OR?
// "...merges BUS[15] into NEXT[9]."
_nextModifier |= (ushort)(_busData & 0x1);
break;
@ -450,7 +449,7 @@ namespace Contralto.CPU
// particular, if IR[12] is true, CARRY will not change. DNS also addresses R from (3-IR[3 - 4]), causes a store
// into R unless IR[12] is set, and sets the SKIP flip flop if appropriate(see section 3.1). The emulator
// microcode increments PC by 1 at the beginning of the next emulated instruction if SKIP is set, using
// BUS+SKIP(ALUF= 13B). IR_ clears SKIP."
// BUS+SKIP(ALUF= 13B). IR<- clears SKIP."
//
// NB: _skip is in the encapsulating AltoCPU class to make it easier to reference since the ALU needs to know about it.
private int _carry;

View File

@ -1,6 +1,7 @@
using System;
using Contralto.Memory;
using Contralto.Logging;
namespace Contralto.CPU
{
@ -92,16 +93,12 @@ namespace Contralto.CPU
}
public bool ExecuteNext()
{
// TODO: cache microinstructions (or pre-decode them) to save consing all these up every time.
{
MicroInstruction instruction = UCodeMemory.GetInstruction(_mpc, _taskType);
// Grab BLOCK bit so that other tasks / hardware can look at it
_block = instruction.F1 == SpecialFunction1.Block;
//Console.WriteLine("R5:{0},R6:{1},IR:{2} - {3}:{4}", OctalHelpers.ToOctal(_cpu._r[5]), OctalHelpers.ToOctal(_cpu._r[6]), OctalHelpers.ToOctal(_cpu._ir), OctalHelpers.ToOctal(_mpc), UCodeDisassembler.DisassembleInstruction(instruction, _taskType));
return ExecuteInstruction(instruction);
}
@ -452,7 +449,7 @@ namespace Contralto.CPU
if (swMode)
{
UCodeMemory.SwitchMode((ushort)(instruction.NEXT | nextModifier), _taskType);
Logging.Log.Write(Logging.LogComponent.Microcode, "SWMODE: uPC {0}, next uPC {1}", Conversion.ToOctal(_mpc), Conversion.ToOctal(instruction.NEXT | nextModifier));
Log.Write(Logging.LogComponent.Microcode, "SWMODE: uPC {0}, next uPC {1}", Conversion.ToOctal(_mpc), Conversion.ToOctal(instruction.NEXT | nextModifier));
}
//

View File

@ -1,4 +1,5 @@
using System;
using Contralto.Logging;
using System;
using System.IO;
namespace Contralto.CPU
@ -126,7 +127,7 @@ namespace Contralto.CPU
/// <param name="nextAddress"></param>
public static void SwitchMode(ushort nextAddress, TaskType task)
{
Logging.Log.Write(Logging.LogComponent.Microcode, "SWMODE: Current Bank {0}", _microcodeBank[(int)task]);
Log.Write(Logging.LogComponent.Microcode, "SWMODE: Current Bank {0}", _microcodeBank[(int)task]);
switch (Configuration.SystemType)
{
@ -197,7 +198,7 @@ namespace Contralto.CPU
break;
}
Logging.Log.Write(Logging.LogComponent.Microcode, "SWMODE: New Bank {0} for Task {1}", _microcodeBank[(int)task], task);
Log.Write(Logging.LogComponent.Microcode, "SWMODE: New Bank {0} for Task {1}", _microcodeBank[(int)task], task);
}
public static ushort ReadRAM()
@ -207,7 +208,7 @@ namespace Contralto.CPU
throw new NotImplementedException("Read from microcode ROM not implemented.");
}
Logging.Log.Write(Logging.LogComponent.Microcode, "CRAM address for read: Bank {0}, RAM {1}, lowhalf {2} addr {3}",
Log.Write(Logging.LogComponent.Microcode, "CRAM address for read: Bank {0}, RAM {1}, lowhalf {2} addr {3}",
_ramBank,
_ramSelect,
_lowHalfsel,
@ -219,7 +220,7 @@ namespace Contralto.CPU
// (See table in section 8.3 of HWRef.)
ushort halfWord = (ushort)(_lowHalfsel ? data : (data >> 16));
Logging.Log.Write(Logging.LogComponent.Microcode, "CRAM data read: {0}-{1}",
Log.Write(Logging.LogComponent.Microcode, "CRAM data read: {0}-{1}",
_lowHalfsel ? "low" : "high",
Conversion.ToOctal(halfWord));
@ -234,11 +235,11 @@ namespace Contralto.CPU
return;
}
Logging.Log.Write(Logging.LogComponent.Microcode, "CRAM address for write: Bank {0}, addr {1}",
Log.Write(Logging.LogComponent.Microcode, "CRAM address for write: Bank {0}, addr {1}",
_ramBank,
Conversion.ToOctal(_ramAddr));
Logging.Log.Write(Logging.LogComponent.Microcode, "CRAM write of low {0}, high {1}",
Log.Write(Logging.LogComponent.Microcode, "CRAM write of low {0}, high {1}",
Conversion.ToOctal(low),
Conversion.ToOctal(high));
@ -337,8 +338,6 @@ namespace Contralto.CPU
{
UInt32 instructionWord = _uCodeRam[address];
_decodeCache[2048 + address] = new MicroInstruction(instructionWord);
//Console.WriteLine(_decodeCache[2048 + address]);
}
private static RomFile[] _uCodeRoms =

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram />

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram />

View File

@ -179,6 +179,8 @@
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="ClassDiagram1.cd" />
<None Include="ClassDiagram2.cd" />
<None Include="Disassembly\altocode24.mu" />
<None Include="App.config" />
<None Include="Disassembly\altoIIcode3.mu">

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -95,6 +95,8 @@ namespace Contralto.Display
_vblankScanlineCount = 0;
_dataBuffer.Clear();
// Schedule wakeup for first scanline of vblank
_verticalBlankScanlineWakeup.TimestampNsec = _verticalBlankScanlineDuration;
_system.Scheduler.Schedule(_verticalBlankScanlineWakeup);
@ -265,8 +267,7 @@ namespace Contralto.Display
public void LoadDDR(ushort word)
{
_dataBuffer.Enqueue(word);
_dataBuffer.Enqueue(word);
// Sanity check: data length should never exceed 16 words.
// TODO: we're allowing up to 18 before we start discarding things.

View File

@ -225,8 +225,7 @@ namespace Contralto.IO
/// <summary>
/// Commits modified sector data back to the emulated disk.
/// Intended to be called at the end of the sector / beginning of the next.
/// TODO: we should modify this so that checksums are persisted, possibly...
/// Intended to be called at the end of the sector / beginning of the next.
/// </summary>
private void CommitSector()
{

View File

@ -19,8 +19,7 @@ namespace Contralto.IO
Reset();
}
/// <summary>
/// TODO: this is messy; the read and write sides of KDATA are distinct hardware.
/// <summary>
/// According to docs, on a Write, eventually it appears on the Read side during an actual write to the disk
/// but not right away.
/// </summary>
@ -341,7 +340,7 @@ namespace Contralto.IO
if (_seclateEnable)
{
_seclate = true;
_kStat |= SECLATE; // TODO: move to constant field!
_kStat |= SECLATE;
Log.Write(LogComponent.DiskSectorTask, "SECLATE for sector {0}.", _sector);
}
}
@ -476,7 +475,7 @@ namespace Contralto.IO
//
// If the clock is enabled OR the WFFO bit is set (go ahead and run the bit clock)
// and we weren't late reading this sector, then we will wake up the word task
// and read in the data if transfers are not inhibited. TODO: this should only happen on reads.
// and read in the data if transfers are not inhibited.
//
if (!_seclate && (_wffo || _diskBitCounterEnable))
{
@ -525,7 +524,7 @@ namespace Contralto.IO
// If the WFFO bit is cleared (wait for the sync word to be read)
// then we check the word for a "1" (the sync word) to enable
// the clock. This occurs late in the cycle so that the NEXT word
// (not the sync word) is actually read. TODO: this should only happen on reads.
// (not the sync word) is actually read.
//
if (!IsWrite() && !_wffo && diskWord.Data == 1)
{

View File

@ -163,8 +163,15 @@ namespace Contralto.IO
while (true)
{
byte[] data = _udpClient.Receive(ref groupEndPoint);
// TODO: sanitize data before handing it off.
//
// Sanitize the data (at least make sure the length is valid):
//
if (data.Length < 4)
{
Log.Write(LogType.Verbose, LogComponent.HostNetworkInterface, "Invalid packet: Packet is fewer than 2 words long, dropping.");
continue;
}
// Drop our own UDP packets.
if (!groupEndPoint.Address.Equals(_thisIPAddress))

View File

@ -55,7 +55,7 @@ namespace Contralto.Logging
static Log()
{
// TODO: make configurable
_components = LogComponent.None; // LogComponent.EthernetPacket | LogComponent.HostEthernet | LogComponent.EthernetController; // LogComponent.DiskController | LogComponent.DiskSectorTask | LogComponent.Debug | LogComponent.CPU; // LogComponent.EthernetController; // | LogComponent.Microcode | LogComponent.Memory | LogComponent.CPU;
_components = LogComponent.None; // LogComponent.HostNetworkInterface | LogComponent.EthernetPacket; // | LogComponent.HostEthernet | LogComponent.EthernetController; // LogComponent.DiskController | LogComponent.DiskSectorTask | LogComponent.Debug | LogComponent.CPU; // LogComponent.EthernetController; // | LogComponent.Microcode | LogComponent.Memory | LogComponent.CPU;
_type = LogType.Normal | LogType.Warning | LogType.Error | LogType.Verbose;
//_logStream = new StreamWriter("log.txt");

View File

@ -296,7 +296,10 @@ namespace Contralto
_frame++;
// Wait for the next frame
_frameTimer.WaitForFrame();
if (Configuration.ThrottleSpeed)
{
_frameTimer.WaitForFrame();
}
if (Configuration.InterlaceDisplay)
{

View File

@ -13,6 +13,7 @@ using System.Threading;
using System.Drawing.Imaging;
using Contralto.IO;
using Contralto.Display;
using Contralto.Logging;
namespace Contralto
{
@ -805,6 +806,25 @@ namespace Contralto
case ExecutionType.Normal:
case ExecutionType.NextTask:
case ExecutionType.NextNovaInstruction:
// For debugging floating point microcode:
if (_system.CPU.CurrentTask.MPC == 0x10) // MPC is 20(octal) meaning a new Nova instruction.
{
if (_lastFPInstruction == 0)
{
// check for new floating instruction
FloatDebugPre(_system.MemoryBus.DebugReadWord(TaskType.Emulator, _system.CPU.R[6]));
}
else
{
// last instruction was a floating point instruction, check the result
FloatDebugPost();
// And see if this new one is also a floating point instruction...
FloatDebugPre(_system.MemoryBus.DebugReadWord(TaskType.Emulator, _system.CPU.R[6]));
}
}
// See if we need to stop here
if (_execAbort || // The Stop button was hit
_microcodeBreakpointEnabled[(int)UCodeMemory.GetBank(_system.CPU.CurrentTask.TaskType),_system.CPU.CurrentTask.MPC] || // A microcode breakpoint was hit
@ -835,7 +855,371 @@ namespace Contralto
return false;
}
// vars for float debug
ushort _lastFPInstruction;
ushort _ac0;
ushort _ac1;
ushort _ac2;
ushort _ac3;
ushort _fpRegAddr;
ushort _fpRegCount;
/// <summary>
/// Temporary, for debugging floating point ucode issues
/// </summary>
/// <param name="instruction"></param>
private void FloatDebugPre(ushort instruction)
{
_lastFPInstruction = 0;
// Float instructions are from 70001-70022 octal
if (instruction >= 0x7000 && instruction <= 0x7012)
{
// Save instruction
_lastFPInstruction = instruction;
// Save ACs
_ac0 = _system.CPU.R[3];
_ac1 = _system.CPU.R[2];
_ac2 = _system.CPU.R[1];
_ac3 = _system.CPU.R[0];
Console.Write("FP: ");
switch (instruction)
{
case 0x7000:
Console.WriteLine("FPSetup");
_fpRegAddr = _system.CPU.R[3];
_fpRegCount = _system.MemoryBus.DebugReadWord(TaskType.Emulator, _fpRegAddr);
Console.WriteLine(" FP register address {0}, count {1}", Conversion.ToOctal(_fpRegAddr), _fpRegCount);
break;
case 0x7001:
Console.WriteLine("FML {0},{1} ({2},{3})", _ac0, _ac1, GetFloat(_ac0), GetFloat(_ac1));
break;
case 0x7002:
Console.WriteLine("FDV {0},{1} ({2},{3})", _ac0, _ac1, GetFloat(_ac0), GetFloat(_ac1));
break;
case 0x7003:
Console.WriteLine("FAD {0},{1} ({2},{3})", _ac0, _ac1, GetFloat(_ac0), GetFloat(_ac1));
break;
case 0x7004:
Console.WriteLine("FSB {0},{1} ({2},{3})", _ac0, _ac1, GetFloat(_ac0), GetFloat(_ac1));
break;
case 0x7005:
Console.WriteLine("FLD {0},{1} (src {2})", _ac0, _ac1, GetFloat(_ac1));
break;
case 0x7006:
Console.WriteLine("FLDV {0},{1} (src {2})", _ac0, _ac1, GetFloatFromInternalFormat(_ac1));
break;
case 0x7007:
Console.WriteLine("FSTV {0},{1} (src {2})", _ac0, _ac1, GetFloat(_ac0));
break;
case 0x7008:
Console.WriteLine("FLDI {0},{1}", _ac0, Conversion.ToOctal(_ac1));
break;
case 0x7009:
Console.WriteLine("FTR {0} ({1})", _ac0, GetFloat(_ac0));
break;
case 0x700a:
Console.WriteLine("FNEG {0} ({1})", _ac0, GetFloat(_ac0));
break;
case 0x700b:
Console.WriteLine("FSN {0} ({1})", _ac0, GetFloat(_ac0));
break;
case 0x700c:
Console.WriteLine("FCM {0} ({1})", _ac0, GetFloat(_ac0));
break;
case 0x700d:
Console.WriteLine("FST");
break;
case 0x700e:
Console.WriteLine("FLDDP");
break;
case 0x700f:
Console.WriteLine("FSTDP");
break;
case 0x7010:
Console.WriteLine("DPAD");
break;
case 0x7011:
Console.WriteLine("DPSB");
break;
case 0x7012:
Console.WriteLine("FEXP {0},{1} ({2})", _ac0, _ac1, GetFloat(_ac0));
break;
}
/*
Console.WriteLine(" AC0={0} AC1={1} AC2={2} AC3={3}",
Conversion.ToOctal(_ac0),
Conversion.ToOctal(_ac1),
Conversion.ToOctal(_ac2),
Conversion.ToOctal(_ac3)); */
}
}
private void FloatDebugPost()
{
Console.Write("Post: ");
switch (_lastFPInstruction)
{
case 0x7000:
Console.WriteLine("FPSetup done.");
break;
case 0x7001:
Console.WriteLine("Result {0}", GetFloat(_ac0));
break;
case 0x7002:
Console.WriteLine("Result {0}", GetFloat(_ac0));
break;
case 0x7003:
Console.WriteLine("Result {0}", GetFloat(_ac0));
break;
case 0x7004:
Console.WriteLine("Result {0}", GetFloat(_ac0));
break;
case 0x7005:
Console.WriteLine("Loaded {0}", GetFloat(_ac0));
break;
case 0x7006:
Console.WriteLine("Loaded {0}", GetFloat(_ac0));
break;
case 0x7007:
Console.WriteLine("FSTV done.");
break;
case 0x7008:
Console.WriteLine("Loaded {0}", GetFloat(_ac0));
break;
case 0x7009:
Console.WriteLine("Result {0}", GetFloat(_ac0));
break;
case 0x700a:
Console.WriteLine("Result {0}", GetFloat(_ac0));
break;
case 0x700b:
Console.WriteLine("Result {0}", _ac3);
break;
case 0x700c:
Console.WriteLine("Result {0}", _ac3);
break;
case 0x700d:
Console.WriteLine("FST done.");
break;
case 0x700e:
Console.WriteLine("FLDDP done.");
break;
case 0x700f:
Console.WriteLine("FSTDP done.");
break;
case 0x7010:
Console.WriteLine("DPAD done.");
break;
case 0x7011:
Console.WriteLine("DPSB done.");
break;
case 0x7012:
Console.WriteLine("Result {0}", GetFloat(_ac0));
break;
default:
throw new InvalidOperationException("Unexpected op for post.");
}
_lastFPInstruction = 0;
}
private double GetFloat(ushort arg)
{
// If arg is less than the number of registers, it's assumed
// to be a register; otherwise an address
if (arg < _fpRegCount)
{
return GetFloatFromUcode(arg);
}
else
{
return GetFloatFromPackedFormat(arg);
}
}
/// <summary>
/// Gets a float from memory in "packed" format
/// </summary>
/// <param name="addr"></param>
/// <returns></returns>
private double GetFloatFromPackedFormat(ushort addr)
{
//
// Packed format is only two words:
// structure FP: [
// sign bit 1 //1 if negative.
// expon bit 8 //excess 128 format (complemented if number <0)
// mantissa1 bit 7 //High order 7 bits of mantissa
// mantissa2 bit 16 //Low order 16 bits of mantissa
// ]
//
uint packedWord =
(uint)(_system.MemoryBus.DebugReadWord(TaskType.Emulator, addr) << 16) |
(uint)(_system.MemoryBus.DebugReadWord(TaskType.Emulator, (ushort)(addr + 1)));
double sign = (packedWord & 0x80000000) != 0 ? -1.0 : 1.0;
uint exponent = (packedWord & 0x7f800000) >> 23;
uint mantissa = (packedWord & 0x007fffff);
double val = 0.0;
for (int i = 0; i < 23; i++)
{
double bit = (mantissa & (0x00400000 >> i)) != 0 ? 1.0 : 0.0;
val += (bit * (1.0 / Math.Pow(2.0, (double)i)));
}
double adjustedExponent = exponent - 128.0;
val = sign * (val) * Math.Pow(2.0, adjustedExponent);
Console.WriteLine("packed: {0}", val);
return val;
}
/// <summary>
/// Gets the float value for register, from alto code
/// </summary>
/// <param name="reg"></param>
/// <returns></returns>
private double GetFloatFromInternalFormat(ushort addr)
{
// Internal format is 4 words long:
// Word 0: sign
// Word 1: exponent
// Word 2-3: mantissa
//
double sign = (_system.MemoryBus.DebugReadWord(TaskType.Emulator, addr)) != 0 ? -1.0 : 1.0;
int exponent = (int)(short)(_system.MemoryBus.DebugReadWord(TaskType.Emulator, (ushort)(addr + 1)));
uint mantissa =
(uint)(_system.MemoryBus.DebugReadWord(TaskType.Emulator, (ushort)(addr + 2)) << 16) |
(uint)(_system.MemoryBus.DebugReadWord(TaskType.Emulator, (ushort)(addr + 3)));
double val = 0.0;
for (int i = 0; i < 32; i++)
{
double bit = (mantissa & (0x80000000 >> i)) != 0 ? 1.0 : 0.0;
val += (bit * (1.0 / Math.Pow(2.0, (double)i)));
}
val = sign * (val) * Math.Pow(2.0, exponent - 1);
if (double.IsInfinity(val) || double.IsNaN(val))
{
Console.WriteLine(" ERROR: sign {0} exp {1} mantissa {2:x} value {3}",
sign,
exponent,
mantissa,
val);
}
return val;
}
/// <summary>
/// Gets the float value for register, from ucode store
/// </summary>
/// <param name="reg"></param>
/// <returns></returns>
private double GetFloatFromUcode(ushort reg)
{
// Internal format is 4 words long:
// Word 0: sign
// Word 1: exponent
// Word 2-3: mantissa
//
// In current ucode, each word is staggered across the FP buffer space rather than being in linear order to prevent having to do multiplies.
// For FP register N of M total registers starting at offset O:
// Word 0 is at O + N + 1
// Word 1 is at O + N + M + 1
// Word 2 is at O + N + 2*M + 1
// Word 3 is at O + N + 3*M + 1
ushort oreg = reg;
reg += _fpRegAddr;
reg++;
//Console.WriteLine("reg base {0}, num {1} addr {2}", _fpRegAddr, oreg, Conversion.ToOctal(reg));
// reg is now an address; read things in...
double sign = (_system.MemoryBus.DebugReadWord(TaskType.Emulator, reg)) != 0 ? -1.0 : 1.0;
int exponent = (int)(short)(_system.MemoryBus.DebugReadWord(TaskType.Emulator, (ushort)(reg + _fpRegCount)));
uint mantissa =
(uint)(_system.MemoryBus.DebugReadWord(TaskType.Emulator, (ushort)(reg + 2 * _fpRegCount)) << 16) |
(uint)(_system.MemoryBus.DebugReadWord(TaskType.Emulator, (ushort)(reg + 3 * _fpRegCount)));
double val = 0.0;
for (int i = 0; i < 32; i++)
{
double bit = (mantissa & (0x80000000 >> i)) != 0 ? 1.0 : 0.0;
val += (bit * (1.0 / Math.Pow(2.0, (double)i)));
}
val = sign * (val) * Math.Pow(2.0, exponent - 1);
if (double.IsInfinity(val) || double.IsNaN(val))
{
Console.WriteLine(" ERROR: sign {0} exp {1} mantissa {2:x} value {3}",
sign,
exponent,
mantissa,
val);
}
return val;
}
private void SetExecutionState(ExecutionState state)
{
@ -961,7 +1345,7 @@ namespace Contralto
private void HackButton_Click(object sender, EventArgs e)
{
Logging.Log.LogComponents |= Logging.LogComponent.TaskSwitch;
Logging.Log.Write(Logging.LogComponent.Debug, "***** HACK HIT ******");
Log.Write(Logging.LogComponent.Debug, "***** HACK HIT ******");
}
}
}