public void LoadSample(uint sample) { var croppedSample = BitHelper.GetMaskedValue(sample, 0, (int)sampleWidthBits); if (croppedSample != sample) { loggingParent?.Log(LogLevel.Warning, "Cropping the sample from 0x{0:X} to 0x{1:X} to fit to the sample width ({2} bits)", sample, croppedSample, sampleWidthBits); } lock (samples) { samples.Enqueue(croppedSample); } }
private void DefineRegisters() { Registers.Control.Define(this) .WithFlag(0, writeCallback: (_, value) => { if (value) { ticker.Enabled = true; } }, valueProviderCallback: _ => ticker.Enabled, name: "Start/Running") .WithFlag(1, writeCallback: (_, value) => { if (value) { ticker.Enabled = false; } }, valueProviderCallback: _ => ticker.Enabled, name: "Stop/Running") .WithFlag(2, writeCallback: (_, value) => { if (value) { alarmEnabled = true; } }, valueProviderCallback: _ => alarmEnabled, name: "Alarm_on/Alarm_enabled") .WithFlag(3, writeCallback: (_, value) => { if (value) { alarmEnabled = false; } }, valueProviderCallback: _ => alarmEnabled, name: "Alarm_off/Alarm_enabled") .WithFlag(4, FieldMode.Set, writeCallback: (_, value) => { if (value) { ResetInnerTimer(); } }, name: "Reset") .WithFlag(5, writeCallback: (_, value) => { if (value) { currentTime = timeToUpload; } ; }, name: "Upload") .WithFlag(6, writeCallback: (_, value) => { if (value) { timeToUpload = currentTime; } ; }, name: "Download") .WithFlag(7, out match, FieldMode.Read, name: "Match") .WithFlag(8, out wakeup, FieldMode.Read | FieldMode.WriteOneToClear, writeCallback: (_, value) => { if (value) { WakeupIRQ.Set(false); } }, name: "Wakeup_clear/Wakeup") .WithFlag(9, FieldMode.Write, writeCallback: (_, value) => { if (value) { wakeup.Value = true; WakeupIRQ.Set(true); } }, name: "Wakeup_set") .WithFlag(10, out updated, FieldMode.Read | FieldMode.WriteOneToClear, name: "Updated") ; Registers.Mode.Define(this) .WithEnumField <DoubleWordRegister, ClockMode>(0, 1, out clockMode, changeCallback: (_, __) => UpdateState(), name: "clock_mode") .WithFlag(1, out wakeEnable, name: "wake_enable") .WithFlag(2, out wakeReset, name: "wake_reset") .WithFlag(3, out wakeContinue, name: "wake_continue") .WithTag("wake_reset_ps", 4, 1) // we don't support prescaler at all ; Registers.AlarmLow.Define(this) .WithValueField(0, 32, out alarmLow, changeCallback: (_, __) => UpdateState(), name: "alarm Lower") ; Registers.AlarmHigh.Define(this) .WithValueField(0, 32, out alarmHigh, changeCallback: (_, __) => UpdateState(), name: "alarm Upper") ; Registers.CompareLow.Define(this) .WithValueField(0, 32, out compareLow, changeCallback: (_, __) => UpdateState(), name: "compare Lower") ; Registers.CompareHigh.Define(this) .WithValueField(0, 32, out compareHigh, changeCallback: (_, __) => UpdateState(), name: "compare Higher") ; Registers.DateTimeLow.Define(this) .WithValueField(0, 32, name: "datetime Lower", valueProviderCallback: _ => { switch (clockMode.Value) { case ClockMode.BinaryCounter: return((uint)CalculateElapsedSeconds(currentTime)); case ClockMode.DateTimeCounter: return(GetDateTimeAlarmCompareLower().Bits.AsUInt32()); default: throw new ArgumentException("Unexpected clock mode"); } }, writeCallback: (_, value) => { switch (clockMode.Value) { case ClockMode.BinaryCounter: var currentValue = CalculateElapsedSeconds(timeToUpload); var newValue = currentValue.ReplaceBits(source: value, width: 32); timeToUpload = ResetTimeValue.AddSeconds(newValue); break; case ClockMode.DateTimeCounter: timeToUpload = timeToUpload.With( second: (int)BitHelper.GetMaskedValue(value, 0, 8), minute: (int)BitHelper.GetMaskedValue(value, 8, 8), hour: (int)BitHelper.GetMaskedValue(value, 16, 8), day: (int)BitHelper.GetMaskedValue(value, 24, 8) ); break; default: throw new ArgumentException("Unexpected clock mode"); } }) ; Registers.DateTimeHigh.Define(this) .WithValueField(0, 32, name: "datetime Higher", valueProviderCallback: _ => { switch (clockMode.Value) { case ClockMode.BinaryCounter: return((uint)(CalculateElapsedSeconds(currentTime) >> 32)); case ClockMode.DateTimeCounter: return(GetDateTimeAlarmCompareUpper().Bits.AsUInt32()); default: throw new ArgumentException("Unexpected clock mode"); } }, writeCallback: (_, value) => { switch (clockMode.Value) { case ClockMode.BinaryCounter: var currentValue = CalculateElapsedSeconds(timeToUpload); var newValue = currentValue.ReplaceBits(source: value, width: 11, destinationPosition: 32); timeToUpload = ResetTimeValue.AddSeconds(newValue); break; case ClockMode.DateTimeCounter: timeToUpload = timeToUpload.With( month: (int)BitHelper.GetMaskedValue(value, 0, 8), year: (int)BitHelper.GetMaskedValue(value, 8, 8) // WARNING // ------- // The rest of bits: // bits 16-23: weekday, // bits 24-29: week // are intentionally *ignored* as those values can be inferred from day+month+year. // This might lead to an inconsistency between Renode and actual hardware. ); break; default: throw new ArgumentException("Unexpected clock mode"); } }) ; Registers.DateTimeSynchronizedSeconds.Define(this) .WithValueField(0, 6, name: "Second", valueProviderCallback: _ => { // an excerpt from the documentation: // "The complete RTC data is read and stored internally when the second value is read, // reads of minutes etc returns the value when seconds was read." bufferedCurrentTime = currentTime; return((uint)bufferedCurrentTime.Second); }, writeCallback: (_, value) => timeToUpload = timeToUpload.With(second: (int)value)) ; Registers.DateTimeSynchronizedMinutes.Define(this) .WithValueField(0, 6, name: "Minute", valueProviderCallback: _ => (uint)bufferedCurrentTime.Minute, writeCallback: (_, value) => timeToUpload = timeToUpload.With(minute: (int)value)) ; Registers.DateTimeSynchronizedHours.Define(this) .WithValueField(0, 5, name: "Hour", valueProviderCallback: _ => (uint)bufferedCurrentTime.Hour, writeCallback: (_, value) => timeToUpload = timeToUpload.With(hour: (int)value)) ; Registers.DateTimeSynchronizedDay.Define(this) .WithValueField(0, 5, name: "Day", valueProviderCallback: _ => (uint)bufferedCurrentTime.Day, writeCallback: (_, value) => timeToUpload = timeToUpload.With(day: (int)value)) ; Registers.DateTimeSynchronizedMonth.Define(this) .WithValueField(0, 4, name: "Month", valueProviderCallback: _ => (uint)bufferedCurrentTime.Month, writeCallback: (_, value) => timeToUpload = timeToUpload.With(month: (int)value)) ; Registers.DateTimeSynchronizedYear.Define(this) .WithValueField(0, 8, name: "Year", valueProviderCallback: _ => CalculateYear(bufferedCurrentTime), writeCallback: (_, value) => timeToUpload = timeToUpload.With(year: CalculateYear(value))) ; Registers.DateTimeSynchronizedWeekday.Define(this) .WithValueField(0, 3, valueProviderCallback: _ => CalculateWeekday(bufferedCurrentTime), name: "Weekday") // WARNING // ------- // The write to this register intentionally *ignored* as the weekday can be inferred from day+month+year. // This might lead to an inconsistency between Renode and actual hardware. ; Registers.DateTimeSynchronizedWeek.Define(this) .WithValueField(0, 6, valueProviderCallback: _ => CalculateWeek(bufferedCurrentTime), name: "Week") // WARNING // ------- // The write to this register intentionally *ignored* as the week number can be inferred from day+month+year. // This might lead to an inconsistency between Renode and actual hardware. ; Registers.DateTimeSeconds.Define(this) .WithValueField(0, 6, name: "Second", valueProviderCallback: _ => (uint)currentTime.Second, writeCallback: (_, value) => timeToUpload = timeToUpload.With(second: (int)value)) ; Registers.DateTimeMinutes.Define(this) .WithValueField(0, 6, name: "Minute", valueProviderCallback: _ => (uint)currentTime.Minute, writeCallback: (_, value) => timeToUpload = timeToUpload.With(minute: (int)value)) ; Registers.DateTimeHours.Define(this) .WithValueField(0, 5, name: "Hour", valueProviderCallback: _ => (uint)currentTime.Hour, writeCallback: (_, value) => timeToUpload = timeToUpload.With(hour: (int)value)) ; Registers.DateTimeDay.Define(this) .WithValueField(0, 5, name: "Day", valueProviderCallback: _ => (uint)currentTime.Day, writeCallback: (_, value) => timeToUpload = timeToUpload.With(day: (int)value)) ; Registers.DateTimeMonth.Define(this) .WithValueField(0, 4, name: "Month", valueProviderCallback: _ => (uint)currentTime.Month, writeCallback: (_, value) => timeToUpload = timeToUpload.With(month: (int)value)) ; Registers.DateTimeYear.Define(this) // year 0 means 2000 .WithValueField(0, 8, name: "Year", valueProviderCallback: _ => CalculateYear(currentTime), writeCallback: (_, value) => timeToUpload = timeToUpload.With(year: CalculateYear(value))) ; Registers.DateTimeWeekday.Define(this) .WithValueField(0, 3, valueProviderCallback: _ => CalculateWeekday(currentTime), name: "Weekday") // WARNING // ------- // The write to this register intentionally *ignored* as the weekday can be inferred from day+month+year. // This might lead to an inconsistency between Renode and actual hardware. ; Registers.DateTimeWeek.Define(this) .WithValueField(0, 6, valueProviderCallback: _ => CalculateWeek(currentTime), name: "Week") // WARNING // ------- // The write to this register intentionally *ignored* as the week number can be inferred from day+month+year. // This might lead to an inconsistency between Renode and actual hardware. ; }
public PSE_SPI(Machine machine) : base(machine) { locker = new object(); receiveBuffer = new Queue <byte>(); transmitBuffer = new Queue <byte>(); IRQ = new GPIO(); controlRegister = new DoubleWordRegister(this, 0x80000102) .WithFlag(0, out coreEnabled, changeCallback: (_, val) => { if (!val) { frameCounter.Value = 0; } }, name: "ENABLE") .WithFlag(1, out master, name: "MASTER") .WithTag("MODE", 2, 2) .WithFlag(4, out enableIrqOnReceive, name: "INTRXDATA") .WithFlag(5, out enableIrqOnTransmit, name: "INTTXDATA") .WithFlag(6, out enableIrqOnOverflow, name: "INTRCVOVFLOW") .WithFlag(7, out enableIrqOnUnderrun, name: "INTTXTURUN") .WithValueField(8, 16, out frameCounter, writeCallback: (_, val) => { framesReceived = 0; framesTransmitted = 0; }, name: "FRAMECNT") .WithTag("SPO", 24, 1) .WithTag("SPH", 25, 1) .WithTag("SPS", 26, 1) .WithTag("FRAMEURUN", 27, 1) .WithTag("CLKMODE", 28, 1) .WithFlag(29, changeCallback: (_, val) => { if (val) { if (frameSize.Value <= 8) { fifoSize = 32; } else if (frameSize.Value >= 9 && frameSize.Value <= 16) { fifoSize = 16; } else if (frameSize.Value >= 17) { fifoSize = 8; } } else { fifoSize = 4; } }, name: "BIGFIFO") .WithTag("OENOFF", 30, 1) .WithFlag(31, FieldMode.WriteOneToClear | FieldMode.Read, changeCallback: (_, __) => Reset(), name: "RESET"); maskedInterruptRegister = new DoubleWordRegister(this) .WithFlag(0, FieldMode.Read, valueProviderCallback: (_) => enableIrqOnReceive.Value && transmitDone.Value, name: "TXDONE") .WithFlag(1, FieldMode.Read, valueProviderCallback: (_) => enableIrqOnTransmit.Value && receiveDone.Value, name: "RXDONE") .WithFlag(2, FieldMode.Read, valueProviderCallback: (_) => enableIrqOnOverflow.Value && receiveOverflow.Value, name: "RXOVERFLOW") .WithFlag(3, FieldMode.Read, valueProviderCallback: (_) => enableIrqOnUnderrun.Value && transmitUnderrun.Value, name: "TXUNDERRUN") .WithFlag(4, FieldMode.Read, valueProviderCallback: (_) => fullCommandReceived.Value, name: "CMDINT") .WithFlag(5, FieldMode.Read, valueProviderCallback: (_) => false, name: "SSEND"); var registersMap = new Dictionary <long, DoubleWordRegister> { { (long)Registers.Control, controlRegister }, { (long)Registers.FrameSize, new DoubleWordRegister(this, 0x4) .WithValueField(0, 6, out frameSize, name: "FRAMESIZE") }, { (long)Registers.Status, new DoubleWordRegister(this, 0x2440) .WithFlag(0, out dataSent, FieldMode.Read, name: "TXDATASENT") .WithFlag(1, out dataReceived, FieldMode.Read, name: "RXDATARCVD") .WithFlag(2, FieldMode.Read, valueProviderCallback: (_) => receiveOverflow.Value, name: "RXOVERFLOW") .WithFlag(3, FieldMode.Read, valueProviderCallback: (_) => transmitUnderrun.Value, name: "TXUNDERRUN") .WithFlag(4, FieldMode.Read, valueProviderCallback: (_) => receiveBuffer.Count == frameSize.Value, name: "RXFIFOFULL") .WithFlag(5, FieldMode.Read, valueProviderCallback: (_) => (receiveBuffer.Count + 1) == frameSize.Value, name: "RXFIFOFULLNEXT") .WithFlag(6, FieldMode.Read, valueProviderCallback: (_) => receiveBuffer.Count == 0, name: "RXFIFOEMPTY") .WithFlag(7, FieldMode.Read, valueProviderCallback: (_) => receiveBuffer.Count == 1, name: "RXFIFOEMPTYNEXT") .WithFlag(8, FieldMode.Read, valueProviderCallback: (_) => transmitBuffer.Count == frameSize.Value, name: "TXFIFOFULL") .WithFlag(9, FieldMode.Read, valueProviderCallback: (_) => (transmitBuffer.Count + 1) == frameSize.Value, name: "TXFIFOFULLNEXT") .WithFlag(10, FieldMode.Read, valueProviderCallback: (_) => transmitBuffer.Count == 0, name: "TXFIFOEMPTY") .WithFlag(11, FieldMode.Read, valueProviderCallback: (_) => transmitBuffer.Count == 1, name: "TXFIFOEMPTYNEXT") .WithTag("FRAMESTART", 12, 1) .WithTag("SSEL", 13, 1) .WithTag("ACTIVE", 14, 1) }, { (long)Registers.InterruptClear, new DoubleWordRegister(this) .WithFlag(0, FieldMode.WriteOneToClear, writeCallback: (_, __) => transmitDone.Value = false, name: "TXDONE") .WithFlag(1, FieldMode.WriteOneToClear, writeCallback: (_, __) => receiveDone.Value = false, name: "RXDONE") .WithFlag(2, FieldMode.WriteOneToClear, writeCallback: (_, __) => receiveOverflow.Value = false, name: "RXOVERFLOW") .WithFlag(3, FieldMode.WriteOneToClear, writeCallback: (_, __) => transmitUnderrun.Value = false, name: "TXUNDERRUN") .WithFlag(4, FieldMode.WriteOneToClear, writeCallback: (_, __) => fullCommandReceived.Value = false, name: "CMDINT") .WithTag("SSEND", 5, 1) }, { (long)Registers.ReceiveData, new DoubleWordRegister(this) .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => { dataReceived.Value = false; return(receiveBuffer.Count > 0 ? receiveBuffer.Dequeue() : (byte)0x00); }, name: "RXDATA") }, { (long)Registers.TransmitData, new DoubleWordRegister(this) .WithValueField(0, 32, FieldMode.Write, writeCallback: (_, val) => { if (coreEnabled.Value) { dataSent.Value = false; if (master.Value == true) { this.Log(LogLevel.Noisy, $"Writing 0x{val:X} to slave."); //TODO: should probably enqueue data if frame counter is enabled and the frameTransmitted reached the threshold. // We do not handle TXFIFO as its handling is not clear from the documentation. TryReceive(RegisteredPeripheral.Transmit((byte)val)); if (framesTransmitted == frameCounter.Value) { dataSent.Value = true; transmitDone.Value = true; } } else { this.Log(LogLevel.Noisy, $"Writing 0x{val:X} to transmit buffer in slave mode."); transmitBuffer.Enqueue((byte)val); } } }, name: "TXDATA") }, { (long)Registers.ClockRate, new DoubleWordRegister(this) .WithValueField(0, 8, name: "CLKRATE") }, { (long)Registers.SlaveSelect, new DoubleWordRegister(this) .WithValueField(0, 8, name: "SSEL") }, { (long)Registers.InterruptMasked, maskedInterruptRegister }, { (long)Registers.InterruptRaw, new DoubleWordRegister(this) .WithFlag(0, out transmitDone, name: "TXDONE") .WithFlag(1, out receiveDone, name: "RXDONE") .WithFlag(2, out receiveOverflow, name: "RXOVERFLOW") .WithFlag(3, out transmitUnderrun, name: "TXUNDERRUN") .WithFlag(4, out fullCommandReceived, name: "CMDINT") .WithTag("SSEND", 5, 1) }, { (long)Registers.ControlBitsForEnhancedModes, new DoubleWordRegister(this) .WithTag("AUTOSTATUS", 0, 1) .WithTag("AUTOPOLL", 1, 1) .WithFlag(2, out disableFrameCount, name: "DISFRMCNT") // bit 3 reserved .WithFlag(4, out enableIrqOnCmd, name: "INTEN_CMD") .WithTag("INTEN_SSEND", 5, 1) }, { (long)Registers.CommandRegister, new DoubleWordRegister(this) .WithFlag(0, FieldMode.Read, writeCallback: (_, val) => { if (val) { while (transmitBuffer.Count < (frameSize.Value * frameCounter.Value)) { transmitBuffer.Enqueue(0); } } }, name: "AUTOFILL") .WithTag("AUTOEMPTY", 1, 1) .WithFlag(2, FieldMode.WriteOneToClear | FieldMode.Read, changeCallback: (_, __) => receiveBuffer.Clear(), name: "RXFIFORST") .WithFlag(3, FieldMode.WriteOneToClear | FieldMode.Read, changeCallback: (_, __) => transmitBuffer.Clear(), name: "TXFIFORST") .WithFlag(4, FieldMode.WriteOneToClear | FieldMode.Read, changeCallback: (_, __) => { frameCounter.Value = 0; framesReceived = 0; framesTransmitted = 0; }, name: "CLRFRAMECNT") .WithTag("AUTOSTALL", 5, 1) .WithTag("TXNOW", 6, 1) }, { (long)Registers.CommandSize, new DoubleWordRegister(this) .WithValueField(0, 6, out commandSize, name: "CMDSIZE") }, { (long)Registers.Status8, new DoubleWordRegister(this) .WithTag("FIRSTFRAME", 0, 1) .WithFlag(1, FieldMode.Read, valueProviderCallback: (_) => dataSent.Value && dataReceived.Value, name: "DONE") .WithFlag(2, FieldMode.Read, valueProviderCallback: (_) => receiveBuffer.Count == 0, name: "RXEMPTY") .WithFlag(3, FieldMode.Read, valueProviderCallback: (_) => transmitBuffer.Count == frameSize.Value, name: "TXFULL") .WithFlag(4, FieldMode.Read, valueProviderCallback: (_) => receiveOverflow.Value, name: "RXOVFLOW") .WithFlag(5, FieldMode.Read, valueProviderCallback: (_) => transmitUnderrun.Value, name: "TXUNDERRUN") .WithTag("SSEL", 6, 1) .WithTag("ACTIVE", 7, 1) }, { (long)Registers.AliasedControlRegister0, new DoubleWordRegister(this) .WithValueField(0, 8, writeCallback: (_, newVal) => controlRegister.Write(0, BitHelper.SetBitsFrom(controlRegister.Value, newVal, 0, 8)), valueProviderCallback: (_) => BitHelper.GetMaskedValue(controlRegister.Value, 0, 8), name: "CTRL0") }, { (long)Registers.AliasedControlRegister1, new DoubleWordRegister(this) .WithValueField(0, 8, writeCallback: (_, newVal) => controlRegister.Write(0, BitHelper.SetBitsFrom(controlRegister.Value, newVal, 8, 8)), valueProviderCallback: (_) => BitHelper.GetMaskedValue(controlRegister.Value, 8, 8), name: "CTRL1") }, { (long)Registers.AliasedControlRegister2, new DoubleWordRegister(this) .WithValueField(0, 8, writeCallback: (_, newVal) => controlRegister.Write(0, BitHelper.SetBitsFrom(controlRegister.Value, newVal, 16, 8)), valueProviderCallback: (_) => BitHelper.GetMaskedValue(controlRegister.Value, 16, 8), name: "CTRL2") }, { (long)Registers.AliasedControlRegister3, new DoubleWordRegister(this) .WithValueField(0, 8, writeCallback: (_, newVal) => controlRegister.Write(0, BitHelper.SetBitsFrom(controlRegister.Value, newVal, 24, 8)), valueProviderCallback: (_) => BitHelper.GetMaskedValue(controlRegister.Value, 24, 8), name: "CTRL3") } }; registers = new DoubleWordRegisterCollection(this, registersMap); }