diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs index 1710b30..80b5898 100644 --- a/Contralto/CPU/CPU.cs +++ b/Contralto/CPU/CPU.cs @@ -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)); } /// diff --git a/Contralto/CPU/Shifter.cs b/Contralto/CPU/Shifter.cs index 122f98b..4887b02 100644 --- a/Contralto/CPU/Shifter.cs +++ b/Contralto/CPU/Shifter.cs @@ -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: diff --git a/Contralto/CPU/Tasks/EmulatorTask.cs b/Contralto/CPU/Tasks/EmulatorTask.cs index f4d6564..b2bc3d6 100644 --- a/Contralto/CPU/Tasks/EmulatorTask.cs +++ b/Contralto/CPU/Tasks/EmulatorTask.cs @@ -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; diff --git a/Contralto/CPU/Tasks/Task.cs b/Contralto/CPU/Tasks/Task.cs index c84371e..2e3e395 100644 --- a/Contralto/CPU/Tasks/Task.cs +++ b/Contralto/CPU/Tasks/Task.cs @@ -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)); } // diff --git a/Contralto/CPU/UCodeMemory.cs b/Contralto/CPU/UCodeMemory.cs index 4db1658..a17722b 100644 --- a/Contralto/CPU/UCodeMemory.cs +++ b/Contralto/CPU/UCodeMemory.cs @@ -1,4 +1,5 @@ -using System; +using Contralto.Logging; +using System; using System.IO; namespace Contralto.CPU @@ -126,7 +127,7 @@ namespace Contralto.CPU /// 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 = diff --git a/Contralto/ClassDiagram1.cd b/Contralto/ClassDiagram1.cd new file mode 100644 index 0000000..7b89419 --- /dev/null +++ b/Contralto/ClassDiagram1.cd @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Contralto/ClassDiagram2.cd b/Contralto/ClassDiagram2.cd new file mode 100644 index 0000000..7b89419 --- /dev/null +++ b/Contralto/ClassDiagram2.cd @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj index ca432d1..d3fcb2a 100644 --- a/Contralto/Contralto.csproj +++ b/Contralto/Contralto.csproj @@ -179,6 +179,8 @@ + + diff --git a/Contralto/Disk/Josh.dsk b/Contralto/Disk/Josh.dsk index 867d8f8..9ab1408 100644 Binary files a/Contralto/Disk/Josh.dsk and b/Contralto/Disk/Josh.dsk differ diff --git a/Contralto/Disk/allgames.dsk b/Contralto/Disk/allgames.dsk index 1954a55..7aabfb6 100644 Binary files a/Contralto/Disk/allgames.dsk and b/Contralto/Disk/allgames.dsk differ diff --git a/Contralto/Disk/tdisk8.dsk b/Contralto/Disk/tdisk8.dsk index 8f3404d..df0f21e 100644 Binary files a/Contralto/Disk/tdisk8.dsk and b/Contralto/Disk/tdisk8.dsk differ diff --git a/Contralto/Display/DisplayController.cs b/Contralto/Display/DisplayController.cs index 115d25e..9dd9d90 100644 --- a/Contralto/Display/DisplayController.cs +++ b/Contralto/Display/DisplayController.cs @@ -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. diff --git a/Contralto/IO/DiabloDrive.cs b/Contralto/IO/DiabloDrive.cs index 6d473e7..daccb5b 100644 --- a/Contralto/IO/DiabloDrive.cs +++ b/Contralto/IO/DiabloDrive.cs @@ -225,8 +225,7 @@ namespace Contralto.IO /// /// 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. /// private void CommitSector() { diff --git a/Contralto/IO/DiskController.cs b/Contralto/IO/DiskController.cs index dbdf1d4..4b0eb26 100644 --- a/Contralto/IO/DiskController.cs +++ b/Contralto/IO/DiskController.cs @@ -19,8 +19,7 @@ namespace Contralto.IO Reset(); } - /// - /// TODO: this is messy; the read and write sides of KDATA are distinct hardware. + /// /// According to docs, on a Write, eventually it appears on the Read side during an actual write to the disk /// but not right away. /// @@ -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) { diff --git a/Contralto/IO/UDPEncapsulation.cs b/Contralto/IO/UDPEncapsulation.cs index 4d1c226..1e6b426 100644 --- a/Contralto/IO/UDPEncapsulation.cs +++ b/Contralto/IO/UDPEncapsulation.cs @@ -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)) diff --git a/Contralto/Logging/Log.cs b/Contralto/Logging/Log.cs index 16ef657..6a80274 100644 --- a/Contralto/Logging/Log.cs +++ b/Contralto/Logging/Log.cs @@ -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"); diff --git a/Contralto/UI/AltoWindow.cs b/Contralto/UI/AltoWindow.cs index 25acab9..ba1e02c 100644 --- a/Contralto/UI/AltoWindow.cs +++ b/Contralto/UI/AltoWindow.cs @@ -296,7 +296,10 @@ namespace Contralto _frame++; // Wait for the next frame - _frameTimer.WaitForFrame(); + if (Configuration.ThrottleSpeed) + { + _frameTimer.WaitForFrame(); + } if (Configuration.InterlaceDisplay) { diff --git a/Contralto/UI/Debugger.cs b/Contralto/UI/Debugger.cs index f67d78e..f46bfd6 100644 --- a/Contralto/UI/Debugger.cs +++ b/Contralto/UI/Debugger.cs @@ -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; + + /// + /// Temporary, for debugging floating point ucode issues + /// + /// + 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); + } + } + + /// + /// Gets a float from memory in "packed" format + /// + /// + /// + 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; + + } + + /// + /// Gets the float value for register, from alto code + /// + /// + /// + 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; + } + + /// + /// Gets the float value for register, from ucode store + /// + /// + /// + 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 ******"); } } }