private static string DisassembleEmulatorBusSource(MicroInstruction instruction, out bool loadS) { EmulatorBusSource bs = (EmulatorBusSource)instruction.BS; switch (bs) { case EmulatorBusSource.ReadSLocation: loadS = false; if (instruction.RSELECT == 0) { return("M"); } else { return(String.Format("$S{0}", Conversion.ToOctal((int)instruction.RSELECT))); } case EmulatorBusSource.LoadSLocation: loadS = true; return(String.Empty); default: loadS = false; throw new InvalidOperationException(String.Format("Unhandled Emulator BS {0}", bs)); } }
protected override ushort GetBusSource(MicroInstruction instruction) { EmulatorBusSource ebs = (EmulatorBusSource)instruction.BS; switch (ebs) { case EmulatorBusSource.ReadSLocation: if (instruction.RSELECT != 0) { return(_cpu._s[_rb][instruction.RSELECT]); } else { // "...when reading data from the S registers onto the processor bus, // the RSELECT value 0 causes the current value of the M register to // appear on the bus..." return(_cpu._m); } case EmulatorBusSource.LoadSLocation: // "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); // Technically this is an "undefined value," we're defining it as -1. default: throw new InvalidOperationException(String.Format("Unhandled bus source {0}", instruction.BS)); } }
protected override void ExecuteSpecialFunction2(MicroInstruction instruction) { DisplayHorizontalF2 dh2 = (DisplayHorizontalF2)instruction.F2; switch (dh2) { case DisplayHorizontalF2.EVENFIELD: _nextModifier |= (ushort)(_displayController.EVENFIELD ? 1 : 0); break; case DisplayHorizontalF2.SETMODE: // "If bit 0 = 1, the bit clock rate is set to 100ns period (at the start of the next scan line), // and a 1 is merged into NEXT[9]." _displayController.SETMODE(_busData); if ((_busData & 0x8000) != 0) { _nextModifier |= 1; } break; default: throw new InvalidOperationException(String.Format("Unhandled display word F2 {0}.", dh2)); } }
private static void CacheMicrocodeROM() { for (int i = 0; i < _uCodeRom.Length; i++) { _decodeCache[i] = new MicroInstruction(_uCodeRom[i]); } }
protected override void ExecuteSpecialFunction2PostBusSource(MicroInstruction instruction) { TridentF2 tf2 = (TridentF2)instruction.F2; switch (tf2) { case TridentF2.ReadKDTA: // // <-KDTA is actually MD<- (SF 6), repurposed to gate disk data onto the bus // iff BS is None. Otherwise it behaves like a normal MD<-. We'll let // the normal Task implementation handle the actual MD<- operation. // if (instruction.BS == BusSource.None) { // _busData at this point should be 0xffff. We could technically // just directly assign the bits... _busData &= _tridentController.KDTA; } break; case TridentF2.STATUS: _busData &= _tridentController.STATUS; break; case TridentF2.EMPTY: _tridentController.WaitForEmpty(); break; } }
private static string DisassembleOrbitSpecialFunction2(MicroInstruction instruction) { OrbitF2 of2 = (OrbitF2)instruction.F2; switch (of2) { case OrbitF2.OrbitDBCWidthSet: return("OrbitDBCWidthSet<- "); case OrbitF2.OrbitXY: return("OrbitXY<- "); case OrbitF2.OrbitHeight: return("OrbitHeight<- "); case OrbitF2.OrbitFontData: return("OrbitFontData<- "); case OrbitF2.OrbitInk: return("OrbitInk<- "); case OrbitF2.OrbitControl: return("OrbitControl<- "); case OrbitF2.OrbitROSCommand: return("OrbitROSCommand<- "); default: return(String.Format("Orbit F2 {0}", Conversion.ToOctal((int)of2))); } }
private static string DisassembleTridentSpecialFunction2(MicroInstruction instruction) { TridentF2 tf2 = (TridentF2)instruction.F2; switch (tf2) { case TridentF2.EMPTY: return("EMPTY "); case TridentF2.KTAG: return("KTAG<- "); case TridentF2.ReadKDTA: return("<-KDTA "); case TridentF2.RESET: return("RESET "); case TridentF2.STATUS: return("STATUS "); case TridentF2.WAIT: case TridentF2.WAIT2: return("WAIT "); case TridentF2.WriteKDTA: return("KDTA<- "); default: return(String.Format("Trident F2 {0}", Conversion.ToOctal((int)tf2))); } }
protected override void ExecuteSpecialFunction1(MicroInstruction instruction) { EthernetF1 ef1 = (EthernetF1)instruction.F1; switch (ef1) { case EthernetF1.EILFCT: // Nothing; handled in Early handler. break; case EthernetF1.EPFCT: // Post Function. Gates interface status to BUS[8-15]. Resets the interface at // the end of the cycle and removes wakeup for this task. _busData &= _ethernetController.Status; _ethernetController.ResetInterface(); _wakeup = false; Log.Write(LogComponent.EthernetController, "EPFCT: Status {0}, bus now {1}", Conversion.ToOctal(_ethernetController.Status), Conversion.ToOctal(_busData)); break; case EthernetF1.EWFCT: // Countdown Wakeup Function. Sets a flip flop in the interface that will // cause a wakeup to the Ether task on the next tick of SWAKMRT. This // function must be issued in the instruction after a TASK. The resulting // wakeup is cleared when the Ether task next runs. Log.Write(LogComponent.EthernetController, "Enabling countdown wakeups."); _ethernetController.CountdownWakeup = true; break; default: throw new NotImplementedException(String.Format("Unimplemented Ethernet F1 {0}", ef1)); } }
protected override ushort GetBusSource(MicroInstruction instruction) { // // The Trident tasks are wired to be RAM-enabled tasks so they can use // S registers. // This code is stolen from the Emulator task; we should REALLY refactor this // since both this and the Orbit Task need it. // EmulatorBusSource ebs = (EmulatorBusSource)instruction.BS; switch (ebs) { case EmulatorBusSource.ReadSLocation: if (instruction.RSELECT != 0) { return(_cpu._s[_rb][instruction.RSELECT]); } else { // "...when reading data from the S registers onto the processor bus, // the RSELECT value 0 causes the current value of the M register to // appear on the bus..." return(_cpu._m); } case EmulatorBusSource.LoadSLocation: // "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); // Technically this is an "undefined value," we're defining it as -1. default: throw new InvalidOperationException(String.Format("Unhandled bus source {0}", instruction.BS)); } }
protected override void ExecuteSpecialFunction2(MicroInstruction instruction) { TridentF2 tf2 = (TridentF2)instruction.F2; switch (tf2) { case TridentF2.KTAG: _tridentController.TagInstruction(_busData); break; case TridentF2.WriteKDTA: _tridentController.KDTA = _busData; break; case TridentF2.WAIT: case TridentF2.WAIT2: // Identical to BLOCK this.BlockTask(); break; case TridentF2.RESET: _tridentController.ControllerReset(); break; case TridentF2.STATUS: case TridentF2.EMPTY: // Handled in PostBusSource override. break; default: throw new InvalidOperationException(String.Format("Unhandled trident special function 2 {0}", tf2)); } }
private static string DisassembleEmulatorSpecialFunction1(MicroInstruction instruction) { EmulatorF1 ef1 = (EmulatorF1)instruction.F1; switch (ef1) { case EmulatorF1.SWMODE: return("SWMODE "); case EmulatorF1.WRTRAM: return("WRTRAM "); case EmulatorF1.RDRAM: return("RDRAM "); case EmulatorF1.LoadRMR: return("RMR← "); case EmulatorF1.LoadESRB: return("ESRB← "); case EmulatorF1.RSNF: return("RSNF "); case EmulatorF1.STARTF: return("STARTF "); default: return(String.Format("F1 {0}", Conversion.ToOctal((int)ef1))); } }
private static string DisassembleEmulatorSpecialFunction2(MicroInstruction instruction) { EmulatorF2 ef2 = (EmulatorF2)instruction.F2; switch (ef2) { case EmulatorF2.ACDEST: return("ACDEST "); case EmulatorF2.ACSOURCE: return("ACSOURCE "); case EmulatorF2.MAGIC: return("MAGIC "); case EmulatorF2.LoadDNS: return("DNS← "); case EmulatorF2.BUSODD: return("BUSODD "); case EmulatorF2.LoadIR: return("IR← "); case EmulatorF2.IDISP: return("IDISP "); default: return(String.Format("F2 {0}", Conversion.ToOctal((int)ef2))); } }
protected override void ExecuteSpecialFunction1Early(MicroInstruction instruction) { OrbitF1 of1 = (OrbitF1)instruction.F1; switch (of1) { case OrbitF1.OrbitDeltaWC: _busData &= _cpu._system.OrbitController.GetDeltaWC(); break; case OrbitF1.OrbitDBCWidthRead: _busData &= _cpu._system.OrbitController.GetDBCWidth(); break; case OrbitF1.OrbitOutputData: _busData &= _cpu._system.OrbitController.GetOutputDataAlto(); break; case OrbitF1.OrbitStatus: _busData &= _cpu._system.OrbitController.GetOrbitStatus(); // branch: // "OrbitStatus sets NEXT[7] of IACS os *not* on, i.e. if Orbit is // not in a character segment." // if (!_cpu._system.OrbitController.IACS) { _nextModifier |= 0x4; } break; } }
protected override void ExecuteSpecialFunction2Early(MicroInstruction instruction) { EmulatorF2 ef2 = (EmulatorF2)instruction.F2; switch (ef2) { case EmulatorF2.ACSOURCE: // Early: modify R select field: // "...it replaces the two-low order bits of the R select field with // the complement of the SrcAC field of IR, (IR[1-2] XOR 3), allowing the emulator // to address its accumulators (which are assigned to R0-R3)." _rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x6000) >> 13) ^ 3); break; case EmulatorF2.ACDEST: // "...causes (IR[3-4] XOR 3) to be used as the low-order two bits of the RSELECT field. // This address the accumulators from the destination field of the instruction. The selected // register may be loaded or read." case EmulatorF2.LoadDNS: // // "...DNS also addresses R from (3-IR[3 - 4])..." // _rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x1800) >> 11) ^ 3); break; } }
private static string DisassembleSpecialFunction2(MicroInstruction instruction, TaskType task) { switch (task) { case TaskType.Emulator: return(DisassembleEmulatorSpecialFunction2(instruction)); default: return(String.Format("F2 {0}", Conversion.ToOctal((int)instruction.F2))); } }
/// <summary> /// Executes a single microinstruction. /// </summary> /// <returns>An InstructionCompletion indicating whether this instruction calls for a task switch or not.</returns> public InstructionCompletion ExecuteNext() { MicroInstruction instruction = UCodeMemory.GetInstruction(_mpc, _taskType); /* * if (_taskType == TaskType.Emulator && UCodeMemory.GetBank(_taskType) == MicrocodeBank.RAM0) * { * Console.WriteLine("{0}: {1}", Conversion.ToOctal(_mpc), UCodeDisassembler.DisassembleInstruction(instruction, _taskType)); * }*/ return(ExecuteInstruction(instruction)); }
private static string DisassembleBusSource(MicroInstruction instruction, TaskType task, out bool loadS) { switch (task) { case TaskType.Emulator: return(DisassembleEmulatorBusSource(instruction, out loadS)); default: loadS = false; return(String.Format("BS {0}", Conversion.ToOctal((int)instruction.BS))); } }
protected override void ExecuteSpecialFunction1(MicroInstruction instruction) { DiskF1 df1 = (DiskF1)instruction.F1; switch (df1) { case DiskF1.LoadKDATA: // "The KDATA register is loaded from BUS[0-15]." _diskController.KDATA = _busData; break; case DiskF1.LoadKADR: // "This causes the KADR register to be loaded from BUS[8-14]. // in addition, it causes the head address bit to be loaded from KDATA[13]." // (the latter is done by DiskController) _diskController.KADR = (ushort)((_busData & 0xff)); break; case DiskF1.LoadKCOMM: _diskController.KCOM = (ushort)((_busData & 0x7c00) >> 10); break; case DiskF1.CLRSTAT: _diskController.ClearStatus(); break; case DiskF1.INCRECNO: _diskController.IncrementRecord(); break; case DiskF1.LoadKSTAT: // "KSTAT[12-15] are loaded from BUS[12-15]. (Actually BUS[13] is ORed onto // KSTAT[13].)" // From the schematic (and ucode source, based on the values it actually uses for BUS[13]), BUS[13] // is also inverted. So there's that, too. // build BUS[12-15] with bit 13 flipped. int modifiedBusData = (_busData & 0xb) | ((~_busData) & 0x4); // OR in BUS[12-15] after masking in KSTAT[13] so it is ORed in properly. _diskController.KSTAT = (ushort)(((_diskController.KSTAT & 0xfff4)) | modifiedBusData); break; case DiskF1.STROBE: _diskController.Strobe(); break; default: throw new InvalidOperationException(String.Format("Unhandled disk special function 1 {0}", df1)); } }
protected override void ExecuteSpecialFunction1Early(MicroInstruction instruction) { EthernetF1 ef1 = (EthernetF1)instruction.F1; switch (ef1) { case EthernetF1.EILFCT: // Early: Input Look Function. Gates the contents of the FIFO to BUS[0-15] but does // not increment the read pointer. _busData &= _ethernetController.ReadInputFifo(true /* do not increment read pointer */); break; } }
protected override InstructionCompletion ExecuteInstruction(MicroInstruction instruction) { // The Ethernet task only remains awake if there are pending data wakeups if (_ethernetController.CountdownWakeup) { // // The resulting [Countdown] wakeup is cleared when the Ether task next runs. _ethernetController.CountdownWakeup = false; _wakeup = false; } return(base.ExecuteInstruction(instruction)); }
protected override void ExecuteSpecialFunction2(MicroInstruction instruction) { DisplayWordF2 dw2 = (DisplayWordF2)instruction.F2; switch (dw2) { case DisplayWordF2.LoadDDR: _displayController.LoadDDR(_busData); break; default: throw new InvalidOperationException(String.Format("Unhandled display word F2 {0}.", dw2)); } }
protected override void ExecuteSpecialFunction2(MicroInstruction instruction) { DisplayVerticalF2 dv2 = (DisplayVerticalF2)instruction.F2; switch (dv2) { case DisplayVerticalF2.EVENFIELD: _nextModifier |= (ushort)(_displayController.EVENFIELD ? 1 : 0); break; default: throw new InvalidOperationException(String.Format("Unhandled display vertical F2 {0}.", dv2)); } }
protected override ushort GetBusSource(MicroInstruction instruction) { EthernetBusSource ebs = (EthernetBusSource)instruction.BS; switch (ebs) { case EthernetBusSource.EIDFCT: // Input Data Function. Gates the contents of the FIFO to BUS[0-15], and // increments the read pointer at the end of the cycle. return(_ethernetController.ReadInputFifo(false /* increment read pointer */)); default: throw new NotImplementedException(String.Format("Unimplemented Ethernet BS {0}", ebs)); } }
protected override ushort GetBusSource(MicroInstruction instruction) { DiskBusSource dbs = (DiskBusSource)instruction.BS; switch (dbs) { case DiskBusSource.ReadKSTAT: return(_diskController.KSTAT); case DiskBusSource.ReadKDATA: return(_diskController.KDATA); default: throw new InvalidOperationException(String.Format("Unhandled bus source {0}", instruction.BS)); } }
protected override void ExecuteSpecialFunction2(MicroInstruction instruction) { OrbitF2 of2 = (OrbitF2)instruction.F2; switch (of2) { case OrbitF2.OrbitDBCWidthSet: _cpu._system.OrbitController.SetDBCWidth(_busData); break; case OrbitF2.OrbitXY: _cpu._system.OrbitController.SetXY(_busData); break; case OrbitF2.OrbitHeight: _cpu._system.OrbitController.SetHeight(_busData); // branch: // "OrbitHeight sets NEXT[7] if the refresh timer has expired, i.e. // if the image buffer needs refreshing." // if (_cpu._system.OrbitController.RefreshTimerExpired) { _nextModifier |= 0x4; } break; case OrbitF2.OrbitFontData: _cpu._system.OrbitController.WriteFontData(_busData); break; case OrbitF2.OrbitInk: _cpu._system.OrbitController.WriteInkData(_busData); break; case OrbitF2.OrbitControl: _cpu._system.OrbitController.Control(_busData); break; case OrbitF2.OrbitROSCommand: _cpu._system.OrbitController.SendROSCommand(_busData); break; default: throw new InvalidOperationException(String.Format("Unhandled orbit F2 {0}.", of2)); } }
protected override void ExecuteSpecialFunction1Early(MicroInstruction instruction) { EmulatorF1 ef1 = (EmulatorF1)instruction.F1; switch (ef1) { case EmulatorF1.RSNF: // // Early: // "...decoded by the Ethernet interface, which gates the host address wired on the // backplane onto BUS[8-15]. BUS[0-7] is not driven and will therefore be -1. If // no Ethernet interface is present, BUS will be -1. // _busData &= (ushort)((0xff00 | _cpu._system.EthernetController.Address)); break; } }
protected override void ExecuteSpecialFunction2(MicroInstruction instruction) { CursorF2 cf2 = (CursorF2)instruction.F2; switch (cf2) { case CursorF2.LoadXPREG: // Load cursor X-position register from bus _cpu._system.DisplayController.LoadXPREG(_busData); break; case CursorF2.LoadCSR: // Load cursor shift register from bus _cpu._system.DisplayController.LoadCSR(_busData); break; default: throw new InvalidOperationException(String.Format("Unhandled cursor F2 {0}.", cf2)); } }
private static string DisassembleOrbitSpecialFunction1(MicroInstruction instruction) { OrbitF1 of1 = (OrbitF1)instruction.F1; switch (of1) { case OrbitF1.OrbitBlock: return("OrbitBlock "); case OrbitF1.OrbitDeltaWC: return("<-OrbitDeltaWC "); case OrbitF1.OrbitDBCWidthRead: return("<-OrbitDBCWidthRead "); case OrbitF1.OrbitStatus: return("<-OrbitStatus "); default: return(String.Format("Orbit F1 {0}", Conversion.ToOctal((int)of1))); } }
private static void Init() { // // Max 3 banks of microcode RAM _uCodeRam = new UInt32[1024 * 3]; if (Configuration.SystemType == SystemType.AltoI) { LoadAltoIMicrocode(_uCodeRomsAltoI); } else { LoadAltoIIMicrocode(_uCodeRomsAltoII); } // // Cache 5k of instructions: max 2K ROM, 3K RAM. _decodeCache = new MicroInstruction[1024 * 5]; // Precache ROM CacheMicrocodeROM(); // Precache (empty) RAM for (ushort i = 0; i < _uCodeRam.Length; i++) { UpdateRAMCache(i); } // Start in ROM0 _microcodeBank = new MicrocodeBank[16]; _ramAddr = 0; _ramBank = 0; _ramSelect = true; _lowHalfsel = true; // Cache the system type from the configuration _systemType = Configuration.SystemType; }
protected override void ExecuteSpecialFunction2(MicroInstruction instruction) { DiskF2 df2 = (DiskF2)instruction.F2; switch (df2) { case DiskF2.INIT: _nextModifier |= GetInitModifier(); break; case DiskF2.RWC: // "NEXT<-NEXT OR (IF current record to be written THEN 3 ELSE IF // current record to be checked THEN 2 ELSE 0.") // Current record is in bits 8-9 of the command register; this is shifted // by INCREC by the microcode to present the next set of bits. int command = (_diskController.KADR & 0x00c0) >> 6; _nextModifier |= GetInitModifier(); switch (command) { case 0: // read, no modification. break; case 1: // check, OR in 2 _nextModifier |= 0x2; break; case 2: case 3: // write, OR in 3 _nextModifier |= 0x3; break; } break; case DiskF2.XFRDAT: // "NEXT <- NEXT OR (IF current command wants data transfer THEN 1 ELSE 0) _nextModifier |= GetInitModifier(); if (_diskController.DataXfer) { _nextModifier |= 0x1; } break; case DiskF2.RECNO: _nextModifier |= GetInitModifier(); _nextModifier |= _diskController.RECNO; break; case DiskF2.NFER: // "NEXT <- NEXT OR (IF fatal error in latches THEN 0 ELSE 1)" _nextModifier |= GetInitModifier(); if (!_diskController.FatalError) { _nextModifier |= 0x1; } break; case DiskF2.STROBON: // "NEXT <- NEXT OR (IF seek strobe still on THEN 1 ELSE 0)" _nextModifier |= GetInitModifier(); if ((_diskController.KSTAT & DiskController.STROBE) != 0) { _nextModifier |= 0x1; } break; case DiskF2.SWRNRDY: // "NEXT <- NEXT OR (IF disk not ready to accept command THEN 1 ELSE 0) _nextModifier |= GetInitModifier(); if (!_diskController.Ready) { _nextModifier |= 0x1; } break; default: throw new InvalidOperationException(String.Format("Unhandled disk special function 2 {0}", df2)); } }