Merge "testing: Unify the platform names to be more programmatic."
diff --git a/shodan_infrastructure/MatchaI2S.cs b/shodan_infrastructure/MatchaI2S.cs
index 037ab35..d6fc044 100644
--- a/shodan_infrastructure/MatchaI2S.cs
+++ b/shodan_infrastructure/MatchaI2S.cs
@@ -67,12 +67,18 @@
public bool Empty()
{
- return count == 0;
+ lock (synclock)
+ {
+ return count == 0;
+ }
}
public bool Full()
{
- return count == FIFO_SIZE;
+ lock (synclock)
+ {
+ return count == FIFO_SIZE;
+ }
}
public void Flush()
@@ -87,13 +93,15 @@
}
}
- const uint FIFO_SIZE = 64 * 2;
+ public uint Count { get { lock(synclock) { return count; } } }
+
+ const uint FIFO_SIZE = 63;
const uint FIFO_MASK = FIFO_SIZE - 1;
- public uint cursor_r = 0;
- public uint cursor_w = 0;
- public uint count = 0;
- public ulong[] fifo = new ulong[FIFO_SIZE];
+ private uint cursor_r = 0;
+ private uint cursor_w = 0;
+ private uint count = 0;
+ private ulong[] fifo = new ulong[FIFO_SIZE];
private readonly object synclock = new object();
}
@@ -175,12 +183,15 @@
decoder.LoadFile(InputFile);
this.Log(LogLevel.Info, "Starting recording.");
- rxThread = machine.ObtainManagedThread(InputFrames, SampleFrequencyHz);
+ rxThread = machine.ObtainManagedThread(ReceiveFrame, SampleFrequencyHz);
rxThread.Start();
}
private void StartTx()
{
+ this.Log(LogLevel.Info, "Starting playback.");
+ txThread = machine.ObtainManagedThread(TransmitFrame, SampleFrequencyHz);
+ txThread.Start();
}
private void StopThread(ref IManagedThread thread)
@@ -189,39 +200,65 @@
thread = null;
}
- private void OutputFrames()
+ // Note: this is not a real thread! This is simply a function that is
+ // called at a known frequency from the machine simulation. It must
+ // always complete and never loop!
+ private void TransmitFrame()
{
- }
-
- private void InputFrames()
- {
- while (!rxBuffer.Full())
- {
- // Decode left on the upper half of the sample
- ulong sample = (decoder.GetSingleSample() << 16);
- sample |= decoder.GetSingleSample();
-
- if (!rxBuffer.Full()) {
- rxBuffer.Write(sample);
-
- if ((rxBuffer.count == mappedRxTriggerLevel) && (rxWatermarkIrqEnabled.Value))
- {
- this.Log(LogLevel.Debug, "I2S RX FIFO Watermark.");
- Connections[(int)Events.RxWatermarkIRQ].Blink();
- }
- }
+ if (txBuffer.Empty()) {
+ // FIFO is empty -- nothing to do except set the IRQ and return.
+ this.Log(LogLevel.Debug, "I2S TX FIFO Empty.", txBuffer.Count, mappedTxTriggerLevel);
+ TxEmptyIRQ.Set(txEmptyIrqEnabled.Value);
+ return;
}
- if (rxOverflowIrqEnabled.Value) {
- Connections[(int)Events.RxOverflowIRQ].Blink();
+ txBuffer.Read();
+ this.Log(LogLevel.Noisy, "Removed sample. Level: {0}", txBuffer.Count);
+
+ if (txBuffer.Count < mappedTxTriggerLevel)
+ {
+ this.Log(LogLevel.Debug, "I2S TX FIFO Watermark (count {0} < {1}).", txBuffer.Count, mappedTxTriggerLevel);
+ TxWatermarkIRQ.Set(txWatermarkIrqEnabled.Value);
+ }
+ }
+
+ // Note: this is not a real thread! This is simply a function that is
+ // called at a known frequency from the machine simulation. It must
+ // always complete and never loop!
+ private void ReceiveFrame()
+ {
+ // Decode left on the upper half of the sample
+ ulong sample = (decoder.GetSingleSample() << 16);
+ sample |= decoder.GetSingleSample();
+
+ if (rxBuffer.Full())
+ {
+ this.Log(LogLevel.Noisy, "RX buffer full");
+ if (rxOverflowIrqEnabled.Value)
+ {
+ this.Log(LogLevel.Debug, "I2S RX FIFO Overflow (count {0}).", rxBuffer.Count);
+ RxOverflowIRQ.Set(rxOverflowIrqEnabled.Value);
+ }
+
+ // FIFO is full -- drop the sample
+ return;
+ }
+
+ rxBuffer.Write(sample);
+ this.Log(LogLevel.Noisy, "Added sample. Level: {0}", rxBuffer.Count);
+
+ if (rxBuffer.Count >= mappedRxTriggerLevel)
+ {
+ this.Log(LogLevel.Debug, "I2S RX FIFO Watermark (count {0} == {1}).", rxBuffer.Count, mappedRxTriggerLevel);
+ RxWatermarkIRQ.Set(rxWatermarkIrqEnabled.Value);
}
}
private void CreateRegisters()
{
Registers.IrqState.Define(this)
- .WithFlag(0, name: "TX_WATERMARK", valueProviderCallback: _ => { return txBuffer.count >= mappedTxTriggerLevel; })
- .WithFlag(1, name: "RX_WATERMARK", valueProviderCallback: _ => { return rxBuffer.count >= mappedRxTriggerLevel; })
+ .WithFlag(0, name: "TX_WATERMARK", valueProviderCallback: _ => { return txBuffer.Count >= mappedTxTriggerLevel; })
+ .WithFlag(1, name: "RX_WATERMARK", valueProviderCallback: _ => { return rxBuffer.Count >= mappedRxTriggerLevel; })
.WithFlag(2, name: "TX_EMPTY", valueProviderCallback: _ => { return txBuffer.Empty(); })
.WithFlag(3, name: "RX_OVERFLOW", valueProviderCallback: _ => { return rxBuffer.Full(); });
@@ -233,13 +270,13 @@
Registers.IrqTest.Define(this)
.WithFlag(0, name: "TEST_TX_WATERMARK",
- writeCallback: (_, __) => { Connections[(int)Events.TxWatermarkIRQ].Blink(); })
+ writeCallback: (_, val) => { TxWatermarkIRQ.Set(val); })
.WithFlag(1, name: "TEST_RX_WATERMARK",
- writeCallback: (_, __) => { Connections[(int)Events.RxWatermarkIRQ].Blink(); })
+ writeCallback: (_, val) => { RxWatermarkIRQ.Set(val); })
.WithFlag(2, name: "TEST_TX_EMPTY",
- writeCallback: (_, __) => { Connections[(int)Events.TxEmptyIRQ].Blink(); })
+ writeCallback: (_, val) => { TxEmptyIRQ.Set(val); })
.WithFlag(3, name: "TEST_RX_OVERFLOW",
- writeCallback: (_, __) => { Connections[(int)Events.RxOverflowIRQ].Blink(); });
+ writeCallback: (_, val) => { RxOverflowIRQ.Set(val); });
Registers.Control.Define(this)
.WithFlag(0, out txEnable, name: "TX",
@@ -271,12 +308,30 @@
.WithReservedBits(4, 27);
Registers.ReadData.Define32(this)
- .WithValueField(0, 31, FieldMode.Read, name: "RDATA",
- valueProviderCallback: _ => { return rxBuffer.Read(); });
+ .WithValueField(0, 32, FieldMode.Read, name: "RDATA",
+ valueProviderCallback: _ => {
+ ulong sample = rxBuffer.Read();
+ if (rxBuffer.Count < mappedRxTriggerLevel) {
+ RxWatermarkIRQ.Set(false);
+ this.Log(LogLevel.Noisy, "RX Watermark cleared");
+ }
+ RxOverflowIRQ.Set(false);
+ this.Log(LogLevel.Noisy, "Removed sample. Level: {0}", rxBuffer.Count);
+
+ return sample;
+ });
Registers.WriteData.Define32(this)
- .WithValueField(0, 31, name: "WDATA",
- writeCallback: (_, val) => { txBuffer.Write(val); });
+ .WithValueField(0, 32, name: "WDATA",
+ writeCallback: (_, val) => {
+ txBuffer.Write(val);
+ if (txBuffer.Count > mappedTxTriggerLevel) {
+ TxWatermarkIRQ.Set(false);
+ this.Log(LogLevel.Noisy, "TX Watermark cleared");
+ }
+ TxEmptyIRQ.Set(false);
+ this.Log(LogLevel.Noisy, "Added sample. Level: {0}", txBuffer.Count);
+ });
Registers.FifoControl.Define32(this)
.WithFlag(0, name: "RXRST", writeCallback: (_, val) => { if (val) ResetRx(); })
@@ -316,10 +371,10 @@
Registers.FifoStatus.Define32(this)
.WithValueField(0, 6, name: "TXLVL",
- valueProviderCallback: _ => { return txBuffer.count; })
+ valueProviderCallback: _ => { return txBuffer.Count; })
.WithReservedBits(7, 9)
.WithValueField(16, 6, name: "RXLVL",
- valueProviderCallback: _ => { return rxBuffer.count; })
+ valueProviderCallback: _ => { return rxBuffer.Count; })
.WithReservedBits(22, 10);
}