private void DataWrite(uint oldValue, uint newValue) { //moved from WriteByte byteTransferFinished.Value = false; Update(); switch (state) { case State.AwaitingAddress: startBit.Value = false; willReadOnSelectedSlave = (newValue & 1) == 1; //LSB is 1 for read and 0 for write var address = (int)(newValue >> 1); if (ChildCollection.ContainsKey(address)) { selectedSlave = ChildCollection[address]; addressSentOrMatched.Value = true; //Note: ADDR is not set after a NACK reception - from documentation transmitterReceiver.Value = !willReadOnSelectedSlave; //true when transmitting if (willReadOnSelectedSlave) { dataToReceive = new Queue <byte>(selectedSlave.Read()); dataRegister.Value = 0u; if (dataToReceive.Any()) { dataRegister.Value = dataToReceive.Dequeue(); dataRegisterNotEmpty.Value = true; } state = State.HasDataToRead; } else { state = State.AwaitingData; dataToTransfer = new List <byte>(); } } else { state = State.Idle; acknowledgeFailed.Value = true; } machine.ExecuteIn(Update); break; case State.AwaitingData: dataToTransfer.Add((byte)newValue); dataRegisterEmpty.Value = true; machine.ExecuteIn(() => { byteTransferFinished.Value = true; state = State.AwaitingRestartOrStop; Update(); }); Update(); break; default: this.Log(LogLevel.Warning, "Writing {0} to DataRegister in unsupported state {1}.", newValue, state); break; } }
public virtual void Register(T peripheral, NumberRegistrationPoint <int> registrationPoint) { if (ChildCollection.ContainsKey(registrationPoint.Address)) { throw new RegistrationException("The specified registration point is already in use."); } ChildCollection.Add(registrationPoint.Address, peripheral); }
public void Register(ICFU cfu, NumberRegistrationPoint <int> registrationPoint) { var isRegistered = ChildCollection.Where(x => x.Value.Equals(cfu)).Select(x => x.Key).ToList(); if (isRegistered.Count != 0) { throw new RegistrationException("Can't register the same CFU twice."); } else if (ChildCollection.ContainsKey(registrationPoint.Address)) { throw new RegistrationException("The specified registration point is already in use."); } ChildCollection.Add(registrationPoint.Address, cfu); machine.RegisterAsAChildOf(this, cfu, registrationPoint); cfu.ConnectedCpu = this; }
public HiFive_SPI(Machine machine, bool isFlashEnabled = false, int numberOfSupportedSlaves = 1) : base(machine) { if (numberOfSupportedSlaves < 1 || numberOfSupportedSlaves > 32) { throw new ConstructionException($"Wrong number of supported slaves: {numberOfSupportedSlaves}. Provide a value in range from 1 to 32."); } this.csWidth = numberOfSupportedSlaves; receiveQueue = new Queue <byte>(); IRQ = new GPIO(); var registersMap = new Dictionary <long, DoubleWordRegister>() { { (long)Registers.ChipSelectId, new DoubleWordRegister(this) .WithValueField(0, 32, out selectedSlave, name: "csid", writeCallback: (previousValue, value) => { if (!ChildCollection.ContainsKey(checked ((int)value))) { this.Log(LogLevel.Warning, "Selected pin {0}, but there is no device connected to it.", value); } if (previousValue != value) { FinishTransmission(); } else { ClearReceiveQueue(); } }) }, { (long)Registers.ChipSelectDefault, new DoubleWordRegister(this, (1u << numberOfSupportedSlaves) - 1) // this field's width and reset value depend on a constructor parameter `numberOfSupportedSlaves` .WithValueField(0, numberOfSupportedSlaves, name: "csdef") }, { (long)Registers.ChipSelectMode, new DoubleWordRegister(this) .WithEnumField <DoubleWordRegister, ChipSelectMode>(0, 2, name: "csmode", writeCallback: (_, val) => { // means off if (val == ChipSelectMode.Auto) { FinishTransmission(); } }) }, { (long)Registers.TxFifoData, new DoubleWordRegister(this, 0x0) .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, value) => HandleFifoWrite((byte)value), name: "data") .WithReservedBits(8, 23) .WithFlag(31, FieldMode.Read, valueProviderCallback: _ => false, name: "full") }, { (long)Registers.RxFifoData, new DoubleWordRegister(this, 0x0) // According to the documentation this registers is divided into two fields and a reserved block. // I decided not to split it because the value of both fields must be evaluated IN PROPER ORDER // (flag before dequeuing) and currently the API does not guarantee that. .WithValueField(0, 32, FieldMode.Read, name: "data+empty", valueProviderCallback: _ => { var result = (receiveQueue.Count == 0) ? FifoEmptyMarker : receiveQueue.Dequeue(); UpdateInterrupts(); return(result); }) }, { (long)Registers.TxFifoWatermark, new DoubleWordRegister(this, isFlashEnabled ? 0x1 : 0x0u) .WithValueField(0, 3, out transmitWatermark, writeCallback: (_, __) => UpdateInterrupts(), name: "txmark") .WithReservedBits(3, 29) }, { (long)Registers.RxFifoWatermark, new DoubleWordRegister(this, 0x0) .WithValueField(0, 3, out receiveWatermark, writeCallback: (_, __) => UpdateInterrupts(), name: "rxmark") .WithReservedBits(3, 29) }, { (long)Registers.InterruptEnable, new DoubleWordRegister(this, 0x0) .WithFlag(0, out transmitWatermarkInterruptEnable, writeCallback: (_, __) => UpdateInterrupts(), name: "txwm") .WithFlag(1, out receiveWatermarkInterruptEnable, writeCallback: (_, __) => UpdateInterrupts(), name: "rxwm") .WithReservedBits(2, 30) }, { (long)Registers.InterruptPending, new DoubleWordRegister(this, 0x0) .WithFlag(0, out transmitWatermarkPending, FieldMode.Read, name: "txwm") .WithFlag(1, out receiveWatermarkPending, FieldMode.Read, name: "rxwm") .WithReservedBits(2, 30) } }; registers = new DoubleWordRegisterCollection(this, registersMap); }
private void DataWrite(uint oldValue, uint newValue) { //moved from WriteByte writeLock = true; byteTransferFinished.Value = false; Update(); this.Log(LogLevel.Noisy, "Entered DataWrite with oldValue 0x{0:X} and newValue 0x{1:X}. State: {2}", oldValue, newValue, state); switch (state) { case State.AwaitingAddress: startBit.Value = false; willReadOnSelectedSlave = (newValue & 1) == 1; //LSB is 1 for read and 0 for write var address = (int)(newValue >> 1); if (ChildCollection.ContainsKey(address)) { selectedSlave = ChildCollection[address]; addressSentOrMatched.Value = true; //Note: ADDR is not set after a NACK reception - from documentation transmitterReceiver.Value = !willReadOnSelectedSlave; //true when transmitting if (willReadOnSelectedSlave) { this.Log(LogLevel.Noisy, "Data will be read from slave {0} at address 0x{1:X}", selectedSlave, address); dataToReceive = new Queue <byte>(selectedSlave.Read()); byteTransferFinished.Value = true; } else { this.Log(LogLevel.Noisy, "Data will be written to slave {0} at address 0x{1:X}", selectedSlave, address); state = State.AwaitingData; dataToTransfer = new List <byte>(); dataRegisterEmpty.Value = true; addressSentOrMatched.Value = true; } } else { this.Log(LogLevel.Warning, "No slave device on address 0x{0:X}", address); state = State.Idle; acknowledgeFailed.Value = true; } machine.LocalTimeSource.ExecuteInNearestSyncedState(_ => Update()); break; case State.AwaitingData: dataToTransfer.Add((byte)newValue); machine.LocalTimeSource.ExecuteInNearestSyncedState(_ => { dataRegisterEmpty.Value = true; Update(); writeLock = false; machine.LocalTimeSource.ExecuteInNearestSyncedState(__ => { if (!writeLock) { this.Log(LogLevel.Noisy, "Setting BTF to true!"); // Moved setting BTF to inside another "Synced State" since it got set too soon otherwise // Firmware, hardware or emulation problem? byteTransferFinished.Value = true; Update(); } }); }); break; default: this.Log(LogLevel.Warning, "Writing {0} to DataRegister in unsupported state {1}.", newValue, state); break; } }