public override int GetHashCode() { return (Position.GetHashCode() ^ SegmentIndex.GetHashCode() ^ Distance.GetHashCode()); }
// ====================================================================== // Ctor and private methods. // ====================================================================== public Segment(SegmentIndex segmentType, YBUS bus, uint register) { SegmentType = segmentType; m_Bus = bus; Register = register; RefreshMemoryReference(); }
public override int GetHashCode() { unchecked { return((SegmentIndex.GetHashCode() * 397) ^ Value.GetHashCode()); } }
/// <summary> /// Reads a 16-bit value from the address specified. /// </summary> public ushort ReadMemInt16(ushort address, SegmentIndex segment) { Segment s = GetSegment(segment); if (s == null) { throw new Exception("Unknown segment referenced in DebugReadMemory"); } if ((address & 0x0001) == 0x0001) { // This read is not 16-bit aligned. Two memory accesses needed. Cycles += 2; byte byte0 = s[address]; byte byte1 = s[(ushort)(address + 1)]; return((ushort)((byte1 << 8) + byte0)); } else { // This read is 16-bit aligned. Only one memory access is needed. Cycles += 1; byte byte0 = s[address]; byte byte1 = s[(ushort)(address + 1)]; return((ushort)((byte1 << 8) + byte0)); } }
private Segment GetSegment(SegmentIndex segment) { Segment s = null; if (PS_I && segment == SegmentIndex.CS) { segment = SegmentIndex.IS; } switch (segment) { case SegmentIndex.CS: s = PS_M ? (PS_S ? m_CSS : m_CSU) : m_CS_NoMMU; break; case SegmentIndex.DS: s = PS_M ? (PS_S ? m_DSS : m_DSU) : m_DS_NoMMU; break; case SegmentIndex.ES: s = PS_M ? (PS_S ? m_ESS : m_ESU) : m_ES_NoMMU; break; case SegmentIndex.SS: s = PS_M ? (PS_S ? m_SSS : m_SSU) : m_SS_NoMMU; break; case SegmentIndex.IS: s = PS_M ? m_IS : m_IS_NoMMU; break; } return(s); }
public ushort DebugReadMemory(ushort address, SegmentIndex segmentType) { Segment seg = GetSegment(segmentType); if (seg == null || seg.MemoryReference == null) throw new Exception("Unknown segment referenced in DebugReadMemory"); byte lo = seg.MemoryReference[seg.Base + address]; byte hi = seg.MemoryReference[seg.Base + address + 1]; return (ushort)((hi << 8) + lo); }
/// <summary> /// Reads an 8-bit value from the address specified. /// </summary> public byte ReadMemInt8(ushort address, SegmentIndex segment) { // Int8 accesses do not have to be 16-bit aligned. Only one memory access is needed. Cycles += 1; Segment s = GetSegment(segment); if (s == null) throw new Exception("Unknown segment referenced in DebugReadMemory"); return s[address]; }
/// <summary> /// Executes an ALU operation. /// </summary> /// <param name="operand">Input: machine code word</param> /// <param name="value">Output: result value of operation</param> /// <param name="destination">Output: index of general register result should be written to.</param> private void BitPatternALU(ushort operand, out ushort value, out RegGeneral destination) { ushort address; // Decode the operand word's constituent bits. FEDC BA98 7654 3210 // SAAA rrrE OOOO ORRR int addressingMode = (operand & 0x7000) >> 12; RegGeneral source = (RegGeneral)((operand & 0x0E00) >> 9); bool eightBitMode = (operand & 0x0100) != 0; destination = (RegGeneral)(operand & 0x0007); // R = destination register SegmentIndex dataSeg = (operand & 0x8000) != 0 ? SegmentIndex.ES : SegmentIndex.DS; switch (addressingMode) // will always be between 0x0 and 0x7 { case 0: // Addressing mode: Immediate (r == 0), Absolute (r == 1), else Control Register. if (source == 0) // Immediate { value = eightBitMode ? ReadMemInt8(PC, SegmentIndex.CS) : ReadMemInt16(PC, SegmentIndex.CS); PC += 2; // advance PC two bytes because we're reading an immediate value. } else if ((int)source == 1) // Absolute { address = ReadMemInt16(PC, SegmentIndex.CS); PC += 2; // advance PC two bytes because we're reading an immediate value. value = eightBitMode ? ReadMemInt8(address, dataSeg) : ReadMemInt16(address, dataSeg); } else // Control Register { RegControl cr = (RegControl)((operand & 0x0700) >> 8); value = ReadControlRegister(operand, cr); } break; case 1: // Addressing mode: Register value = R[(int)source]; break; case 2: // Addressing mode: Indirect value = eightBitMode ? ReadMemInt8(R[(int)source], dataSeg) : ReadMemInt16(R[(int)source], dataSeg); break; case 3: // Addressing mode: Absolute Offset AKA Indirect Offset address = (ushort)(R[(int)source] + ReadMemInt16(PC, SegmentIndex.CS)); PC += 2; // advance PC two bytes because we're reading an immediate value. value = eightBitMode ? ReadMemInt8(address, dataSeg) : ReadMemInt16(address, dataSeg); break; default: // addressing of 0x4 ~ 0x7 is an Indirect Indexed operation. int indexRegister = addressingMode; // bit pattern is 1ii, where ii = r4 - r7. address = (ushort)(R[(int)source] + R[indexRegister]); value = eightBitMode ? ReadMemInt8(address, dataSeg) : ReadMemInt16(address, dataSeg); break; } }
/// <summary> /// Reads an 8-bit value from the address specified. /// </summary> public byte ReadMemInt8(ushort address, SegmentIndex segment) { // Int8 accesses do not have to be 16-bit aligned. Only one memory access is needed. Cycles += 1; Segment s = GetSegment(segment); if (s == null) { throw new Exception("Unknown segment referenced in DebugReadMemory"); } return(s[address]); }
public ushort DebugReadMemory(ushort address, SegmentIndex segmentType) { Segment seg = GetSegment(segmentType); if (seg == null || seg.MemoryReference == null) { throw new Exception("Unknown segment referenced in DebugReadMemory"); } byte lo = seg.MemoryReference[seg.Base + address]; byte hi = seg.MemoryReference[seg.Base + address + 1]; return((ushort)((hi << 8) + lo)); }
internal void Interrupt_SegFault(SegmentIndex segmentType, ushort opcode, ushort address) { if (segmentType == SegmentIndex.CS) { Interrupt(Interrupts.SegFault, opcode); } else if (segmentType == SegmentIndex.IS) { Interrupt_DoubleFault(opcode); } else if (segmentType == SegmentIndex.DS || segmentType == SegmentIndex.ES) { Interrupt(Interrupts.SegFault, opcode); } else if (segmentType == SegmentIndex.SS) { Interrupt(Interrupts.StackFault, opcode); } }
public override void AwakeFromNib() { base.AwakeFromNib(); Window.Appearance = NSAppearance.GetAppearance(NSAppearance.NameVibrantDark); Window.TitleVisibility = NSWindowTitleVisibility.Hidden; SetupStatusDisplayTextField(); _ = NotificationCenter.AddObserver(ToggleCollapsed.Name, notification => { NSNumber?collapsed = (NSNumber)notification.UserInfo.ObjectForKey(IsCollapsed.NSString()); NSNumber?segmentIndex = (NSNumber)notification.UserInfo.ObjectForKey(SegmentIndex.NSString()); ToggleSidebarSegmentedControl.SetSelected(!collapsed.BoolValue, segmentIndex.NIntValue); }); }
private string DisassembleJMP(string name, ushort operand, ushort nextword, ushort address, bool showMemoryContents, out ushort instructionSize) { int addressingmode = (operand & 0x7000) >> 12; RegGeneral r_src = (RegGeneral)((operand & 0x1C00) >> 10); int index_bits = (operand & 0x0300) >> 8; SegmentIndex segData = (operand & 0x8000) != 0 ? SegmentIndex.ES : SegmentIndex.DS; bool isFar = (operand & 0x0100) != 0; if (isFar) { name += ".F"; } switch (addressingmode) { case 0: // Immediate or Absolute bool absolute = (operand & 0x0200) != 0; instructionSize = (ushort)(isFar && !absolute ? 8 : 4); if (absolute) { return ($"{name,-8}[${nextword:X4}]{string.Format($" (${DebugReadMemory(nextword, SegmentIndex.CS):X4})", DebugReadMemory(nextword, SegmentIndex.CS))}"); } return($"{name,-8}${nextword:X4}{(isFar ? ", $<SEGREG>" : string.Empty)}"); case 1: // Register instructionSize = 2; return($"{name,-8}{NameOfRegGP(r_src)} (${R[(int)r_src]:X4})"); case 2: // Indirect instructionSize = 2; return ($"{name,-8}[{NameOfRegGP(r_src)}] (${DebugReadMemory(R[(int)r_src], segData):X4})"); case 3: // Indirect Offset (also Absolute Offset) instructionSize = 4; return ($"{name,-8}[{NameOfRegGP(r_src)},${nextword:X4}] (${DebugReadMemory((ushort)(R[(int)r_src] + nextword), segData):X4})"); default: // $8 - $f = Indirect Indexed instructionSize = 2; index_bits += (operand & 0x4000) >> 12; return ($"{name,-8}[{NameOfRegGP(r_src)},{NameOfRegGP((RegGeneral)index_bits)}] (${DebugReadMemory((ushort)(R[(int)r_src] + R[index_bits]), segData):X4})"); } }
/// <summary> /// Reads a 16-bit value from the address specified. /// </summary> public ushort ReadMemInt16(ushort address, SegmentIndex segment) { Segment s = GetSegment(segment); if (s == null) throw new Exception("Unknown segment referenced in DebugReadMemory"); if ((address & 0x0001) == 0x0001) { // This read is not 16-bit aligned. Two memory accesses needed. Cycles += 2; byte byte0 = s[address]; byte byte1 = s[(ushort)(address + 1)]; return (ushort)((byte1 << 8) + byte0); } else { // This read is 16-bit aligned. Only one memory access is needed. Cycles += 1; byte byte0 = s[address]; byte byte1 = s[(ushort)(address + 1)]; return (ushort)((byte1 << 8) + byte0); } }
public void WriteMemInt16(ushort address, ushort value, SegmentIndex segment) { Segment s = GetSegment(segment); if (s == null) { throw new Exception("Unknown segment referenced in DebugReadMemory"); } if ((address & 0x0001) == 0x0001) { // This read is not 16-bit aligned. Two memory accesses needed. Cycles += 2; s[address] = (byte)(value & 0x00ff); s[(ushort)(address + 1)] = (byte)(value >> 8); } else { // This read is 16-bit aligned. Only one memory access is needed. Cycles += 1; s[address] = (byte)(value & 0x00ff); s[(ushort)(address + 1)] = (byte)(value >> 8); } }
private static unsafe uint GetSibAddress32ModZero(Processor processor, int sib, ref SegmentIndex segment) { int scale = (sib >> 6) & 0x3; int index = (sib >> 3) & 0x7; int baseIndex = sib & 0x7; int displacement = 0; int indexValue = 0; if (index != 4) { indexValue = (*(int *)processor.GetRegisterWordPointer(index)) << scale; } int baseValue = 0; if (baseIndex != 5) { baseValue = *(int *)processor.GetRegisterWordPointer(baseIndex); } else { displacement = *(int *)processor.CachedIP; processor.CachedIP += 4; //*(int*)processor.PIP = *(int*)processor.PIP + 4; } if (baseIndex == 4) { segment = SegmentIndex.SS; } uint address = (uint)(baseValue + indexValue + displacement); return(address); }
private static unsafe uint GetSibAddress32(Processor processor, int displacement, int sib, ref SegmentIndex segment) { int scale = (sib >> 6) & 0x3; int index = (sib >> 3) & 0x7; int baseIndex = sib & 0x7; int indexValue = 0; if (index != 4) { indexValue = (*(int *)processor.GetRegisterWordPointer(index)) << scale; } int baseValue = *(int *)processor.GetRegisterWordPointer(baseIndex); if (baseIndex == 4 || baseIndex == 5) { segment = SegmentIndex.SS; } uint address = (uint)(baseValue + indexValue + displacement); return(address); }
private static unsafe uint GetModRMAddress32Mod2(Processor processor, int rm, out SegmentIndex segment) { uint address; segment = SegmentIndex.DS; if (rm == 4) { int sib = *processor.CachedIP; processor.CachedIP++; int displacement = *(int *)processor.CachedIP; processor.CachedIP += 4; //*(int*)processor.PIP = *(int*)processor.PIP + 5; address = (uint)(GetSibAddress32(processor, displacement, sib, ref segment)); } else { if (rm == 5) { segment = SegmentIndex.SS; } int displacement = *(int *)processor.CachedIP; processor.CachedIP += 4; //*(int*)processor.PIP = *(int*)processor.PIP + 4; address = (uint)(*(int *)processor.GetRegisterWordPointer(rm) + displacement); } return(address); }
private static unsafe uint GetModRMAddress32Mod0(Processor processor, int rm, out SegmentIndex segment) { uint address; segment = SegmentIndex.DS; if (rm == 5) { //*(int*)processor.PIP += 4; address = *(uint *)processor.CachedIP; processor.CachedIP += 4; } else if (rm == 4) { //*(int*)processor.PIP = *(int*)processor.PIP + 1; int sib = *processor.CachedIP; processor.CachedIP++; address = GetSibAddress32ModZero(processor, sib, ref segment); } else { address = *(uint *)processor.GetRegisterWordPointer(rm); } return(address); }
public SegFaultException(SegmentIndex si, ushort address) { SegmentType = si; Address = address; }
private void BitPatternJMI(ushort operand, out ushort address, out uint addressFar, out bool isFarJump) { ushort nextword; // Decode the operand word's constituent bits. FEDC BA98 7654 3210 // SAAA rrrF OOOO ORRR int addressingMode = (operand & 0x7000) >> 12; RegGeneral source = (RegGeneral)((operand & 0x0E00) >> 9); SegmentIndex dataSeg = (operand & 0x8000) != 0 ? SegmentIndex.ES : SegmentIndex.DS; addressFar = 0; isFarJump = (operand & 0x0100) != 0; // F = far jump mode switch (addressingMode) // will always be between 0x0 and 0xf { case 0: // Immediate (r == 0) or Absolute (r == 1) if (source == 0) { address = ReadMemInt16(PC, SegmentIndex.CS); PC += 2; // advance PC two bytes because we're reading an immediate value. if (isFarJump) { addressFar = ReadMemInt16(PC, SegmentIndex.CS); PC += 2; // advance PC two bytes because we're reading an immediate value. addressFar |= (uint)ReadMemInt16(PC, SegmentIndex.CS) << 16; PC += 2; // advance PC two bytes because we're reading an immediate value. } } else { nextword = ReadMemInt16(PC, SegmentIndex.CS); PC += 2; // advance PC two bytes because we're reading an immediate value. address = ReadMemInt16(nextword, dataSeg); if (isFarJump) { addressFar = ReadMemInt16((ushort)(nextword + 2), dataSeg); addressFar |= (uint)ReadMemInt16((ushort)(nextword + 4), dataSeg) << 16; } } break; case 1: // Register address = R[(int)source]; break; case 2: // Indirect address = ReadMemInt16(R[(int)source], dataSeg); if (isFarJump) { addressFar = ReadMemInt16((ushort)(R[(int)source] + 2), dataSeg); addressFar |= (uint)ReadMemInt16((ushort)(R[(int)source] + 4), dataSeg) << 16; } break; case 3: // Indirect Offset AKA Absolute Offset nextword = ReadMemInt16(PC, SegmentIndex.CS); PC += 2; // advance PC two bytes because we're reading an immediate value. address = ReadMemInt16((ushort)(R[(int)source] + nextword), dataSeg); if (isFarJump) { addressFar = ReadMemInt16((ushort)(R[(int)source] + nextword + 2), dataSeg); addressFar |= (uint)ReadMemInt16((ushort)(R[(int)source] + nextword + 4), dataSeg) << 16; } break; default: // 0x04 - 0x07 are Indirect Indexed int indexRegister = (operand & 0x7000) >> 12; // bit pattern is 1ii, indicating R4 - R7 address = ReadMemInt16((ushort)(R[(int)source] + R[indexRegister]), dataSeg); if (isFarJump) { addressFar = ReadMemInt16((ushort)(R[(int)source] + R[indexRegister] + 2), dataSeg); addressFar |= (uint)ReadMemInt16((ushort)(R[(int)source] + R[indexRegister] + 4), dataSeg) << 16; } break; } }
private string DisassembleALU(string name, ushort operand, ushort nextword, ushort address, bool showMemoryContents, out ushort instructionSize) { int addressingmode = (operand & 0x7000) >> 12; RegGeneral regDest = (RegGeneral)(operand & 0x0007); RegGeneral regSrc = (RegGeneral)((operand & 0x0E00) >> 9); bool isEightBit = (operand & 0x0100) != 0; SegmentIndex segData = (operand & 0x8000) != 0 ? SegmentIndex.ES : SegmentIndex.DS; switch (addressingmode) { case 0: if (regSrc == 0) // immediate { if (name == "STO") { instructionSize = 2; return("???"); } instructionSize = 4; string disasm = $"{name + (isEightBit ? ".8" : string.Empty),-8}{NameOfRegGP(regDest)}, ${nextword:X4}"; if (showMemoryContents) { disasm = AppendMemoryContents(disasm, nextword); } return(disasm); } if ((int)regSrc == 1) // absolute { instructionSize = 4; string disasm = $"{name + (isEightBit ? ".8" : string.Empty),-8}{NameOfRegGP(regDest)}, [${nextword:X4}]"; if (showMemoryContents) { disasm = AppendMemoryContents(disasm, DebugReadMemory(nextword, segData)); } return(disasm); } else // control register { instructionSize = 2; RegControl cr = (RegControl)((operand & 0x0700) >> 8); string disasm = $"{name,-8}{NameOfRegGP(regDest)}, {NameOfRegSP(cr)}"; if (showMemoryContents) { disasm = AppendMemoryContents(disasm, nextword); } return(disasm); } case 1: // Register instructionSize = 2; return ($"{name + (isEightBit ? ".8" : string.Empty),-8}{NameOfRegGP(regDest)}, {NameOfRegGP(regSrc),-12}(${R[(int)regSrc]:X4})"); case 2: // Indirect instructionSize = 2; return ($"{name + (isEightBit ? ".8" : string.Empty),-8}{NameOfRegGP(regDest)}, [{NameOfRegGP(regSrc)}] (${DebugReadMemory(R[(int)regSrc], segData):X4})"); case 3: // Indirect Offset (also Absolute Offset) instructionSize = 4; return ($"{name + (isEightBit ? ".8" : string.Empty),-8}{NameOfRegGP(regDest)}, [{NameOfRegGP(regSrc)},${nextword:X4}] (${DebugReadMemory((ushort)(R[(int)regSrc] + nextword), segData):X4})"); default: // $4 - $7 are Indirect Indexed instructionSize = 2; RegGeneral regIndex = (RegGeneral)((operand & 0x7000) >> 12); return ($"{name + (isEightBit ? ".8" : string.Empty),-8}{NameOfRegGP(regDest)}, [{NameOfRegGP(regSrc)},{NameOfRegGP(regIndex)}] (${DebugReadMemory((ushort)(R[(int)regSrc] + R[(int)regIndex]), segData):X4})"); } }
private Segment GetSegment(SegmentIndex segment) { Segment s = null; if (PS_I && segment == SegmentIndex.CS) segment = SegmentIndex.IS; switch (segment) { case SegmentIndex.CS: s = PS_M ? (PS_S ? m_CSS : m_CSU) : m_CS_NoMMU; break; case SegmentIndex.DS: s = PS_M ? (PS_S ? m_DSS : m_DSU) : m_DS_NoMMU; break; case SegmentIndex.ES: s = PS_M ? (PS_S ? m_ESS : m_ESU) : m_ES_NoMMU; break; case SegmentIndex.SS: s = PS_M ? (PS_S ? m_SSS : m_SSU) : m_SS_NoMMU; break; case SegmentIndex.IS: s = PS_M ? m_IS : m_IS_NoMMU; break; } return s; }
/// <summary> /// Retrieves a reference to a segment stored in the runtime asset. /// </summary> /// <param name="index">The segment index to retrieve the reference for.</param> /// <returns>Segment reference that corresponds to the index passed as argument.</returns> public ref Segment GetSegment(SegmentIndex index) { Assert.IsTrue(index < numSegments); return(ref segments[index]); }
/// <summary> /// Determines whether two segment indices are equal. /// </summary> /// <param name="segmentIndex">The index to compare against the current index.</param> /// <returns>True if the specified index is equal to the current index; otherwise, false.</returns> public bool Equals(SegmentIndex segmentIndex) { return(value == segmentIndex.value); }
public void WriteMemInt16(ushort address, ushort value, SegmentIndex segment) { Segment s = GetSegment(segment); if (s == null) throw new Exception("Unknown segment referenced in DebugReadMemory"); if ((address & 0x0001) == 0x0001) { // This read is not 16-bit aligned. Two memory accesses needed. Cycles += 2; s[address] = (byte)(value & 0x00ff); s[(ushort)(address + 1)] = (byte)(value >> 8); } else { // This read is 16-bit aligned. Only one memory access is needed. Cycles += 1; s[address] = (byte)(value & 0x00ff); s[(ushort)(address + 1)] = (byte)(value >> 8); } }