I'm trying to use the SPI connector from this commit in Renode. The connector itself is here. It hasn't been merged yet, so I have to include the files directly to get it to run. Here's my Renode script file, mostly taken directly from the tests in the commit:
include @SPISlaveModeController.cs
include @SPIMasterModeController.cs
include @SPIConnector.cs
emulation CreateSPIConnector "spi-con"
mach create "Peripheral"
machine LoadPlatformDescriptionFromString "spis: SPI.SPISlaveModeController @ sysbus 0x00000000"
connector Connect sysbus.spis "spi-con"
mach create "Controller"
machine LoadPlatformDescriptionFromString "spim: SPI.SPIMasterModeController @ sysbus 0x00000000"
connector Connect sysbus.spim "spi-con"
start
Now, using the SPIMasterModeController.cs from the example above everything works. My problem comes when I try to do anything with the Connector outside the constructor. I want to have the master call Transmit
when I write to an address in it. Here's my minimal example code:
using Antmicro.Renode.Core;
using Antmicro.Renode.Core.Structure;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Time;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.Timers;
namespace Antmicro.Renode.Peripherals.SPI
{
public class SPIMasterModeController :
NullRegistrationPointPeripheralContainer<ISPIPeripheral>,
IBytePeripheral,
IKnownSize
{
public SPIMasterModeController(Machine machine) : base(machine)
{
timer = new LimitTimer(machine.ClockSource, 1000, this,
"master_clk", workMode: WorkMode.Periodic,
eventEnabled: true, limit: 1, enabled: true);
timer.LimitReached += () =>
{
var output = RegisteredPeripheral.Transmit(0xa5);
this.Log(LogLevel.Info, "Master sent:{0} received:{1}", 0xa5,
output);
RegisteredPeripheral.FinishTransmission();
timer.Enabled = false;
};
}
public byte ReadByte(long offset)
{
return 0x0;
}
public void WriteByte(long offset, byte value)
{
// if (offset == 0)
// {
// timer.Enabled = true;
// }
// if (offset == 1)
// {
// timer.Enabled = false;
// }
if (offset == 0)
{
RegisteredPeripheral.Transmit(value);
}
else
{
RegisteredPeripheral.FinishTransmission();
}
}
public override void Reset()
{
}
public long Size => 0x100;
private LimitTimer timer;
}
}
If I swap the implementation of WriteByte
here, by uncommenting the commented code and commenting out the uncommented code, things work. I can send sysbus.spim WriteByte 0 0
and I get the messages from the slave about the transmission succeeding. However, as it is, when I send sysbus.spim WriteByte 0 0
, Renode crashes with the following error.
[ERROR] FATAL UNHANDLED EXCEPTION: System.ArgumentException: Tried to obtain a virtual time stamp of an unregistered thread: 'Shell thread'/7
at Antmicro.Renode.Time.TimeDomainsManager.get_VirtualTimeStamp () [0x0003c] in <b05710e063024506ba998245a09a24f0>:0
at Antmicro.Renode.Peripherals.SPI.SPIConnector.Transmit (System.Byte data) [0x0004d] in <df90037be0e74203ae6fcba2643fcb70>:0
at Antmicro.Renode.Peripherals.SPI.SPIMasterModeController.WriteByte (System.Int64 offset, System.Byte value) [0x00008] in <311068778e6543b9b3f5b2c22a93fb55>:0
at (wrapper dynamic-method) System.Object.CallSite.Target(System.Runtime.CompilerServices.Closure,System.Runtime.CompilerServices.CallSite,object,object,object)
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid3[T0,T1,T2] (System.Runtime.CompilerServices.CallSite site, T0 arg0, T1 arg1, T2 arg2) [0x00141] in <d22af090bceb4be792f53595cf074724>:0
at Dynamitey.Internal.Optimization.InvokeHelper.InvokeMemberAction (System.Runtime.CompilerServices.CallSite& callsite, System.Type binderType, System.Int32 knownType, Dynamitey.Internal.Optimization.InvokeHelper+LazyBinder binder, Dynamitey.InvokeMemberName name, System.Boolean staticContext, System.Type context, System.String[] argNames, System.Object target, System.Object[] args) [0x000df] in <1d0e1ef63ad2470a9ccec81105ee1302>:0
at Dynamitey.Internal.Optimization.InvokeHelper.InvokeMemberActionCallSite (System.Object target, Dynamitey.InvokeMemberName name, System.Object[] args, System.String[] tArgNames, System.Type tContext, System.Boolean tStaticContext, System.Runtime.CompilerServices.CallSite& callSite) [0x0004f] in <1d0e1ef63ad2470a9ccec81105ee1302>:0
at Dynamitey.Dynamic.InvokeMemberAction (System.Object target, Dynamitey.String_OR_InvokeMemberName name, System.Object[] args) [0x00018] in <1d0e1ef63ad2470a9ccec81105ee1302>:0
at Antmicro.Renode.UserInterface.Monitor.InvokeWithContext (Dynamitey.InvokeContext context, System.Reflection.MethodInfo method, System.Object[] parameters) [0x00023] in <11d556aecc3649618ce70f6971350082>:0
at Antmicro.Renode.UserInterface.Monitor.InvokeMethod (System.String name, System.Reflection.MethodInfo method, System.Collections.Generic.List`1[T] parameters) [0x0001a] in <11d556aecc3649618ce70f6971350082>:0
at Antmicro.Renode.UserInterface.Monitor.ExecuteDeviceAction (System.Type type, System.String name, System.Collections.Generic.IEnumerable`1[T] p) [0x00216] in <11d556aecc3649618ce70f6971350082>:0
at Antmicro.Renode.UserInterface.Monitor.ProcessDeviceAction (System.Type device, System.String name, System.Collections.Generic.IEnumerable`1[T] p, AntShell.Commands.ICommandInteraction writer) [0x00023] in <11d556aecc3649618ce70f6971350082>:0
at Antmicro.Renode.UserInterface.Monitor.ProcessDeviceActionByName (System.String name, System.Collections.Generic.IEnumerable`1[T] p, AntShell.Commands.ICommandInteraction writer) [0x00060] in <11d556aecc3649618ce70f6971350082>:0
at Antmicro.Renode.UserInterface.Monitor.ExecuteCommand (Antmicro.Renode.UserInterface.Tokenizer.Token[] com, AntShell.Commands.ICommandInteraction writer) [0x00165] in <11d556aecc3649618ce70f6971350082>:0
at Antmicro.Renode.UserInterface.Monitor.ParseTokens (System.Collections.Generic.IEnumerable`1[T] tokensToParse, AntShell.Commands.ICommandInteraction writer) [0x001df] in <11d556aecc3649618ce70f6971350082>:0
at Antmicro.Renode.UserInterface.Monitor.Parse (System.String cmd, AntShell.Commands.ICommandInteraction writer) [0x0019d] in <11d556aecc3649618ce70f6971350082>:0
at Antmicro.Renode.UserInterface.Monitor.HandleCommand (System.String cmd, AntShell.Commands.ICommandInteraction ci) [0x00000] in <11d556aecc3649618ce70f6971350082>:0
at AntShell.Shell.HandleCommand (System.String cmd, AntShell.Commands.ICommandInteraction ic) [0x000bd] in <12b5ceac888f4387a227ffd402a29e15>:0
at AntShell.CommandLine.HandleControlSequence (AntShell.Helpers.ControlSequence seq) [0x00aa1] in <12b5ceac888f4387a227ffd402a29e15>:0
at AntShell.Terminal.NavigableTerminalEmulator.HandleInput (System.Object input) [0x0002e] in <12b5ceac888f4387a227ffd402a29e15>:0
at AntShell.Terminal.NavigableTerminalEmulator.Run (System.Boolean stopOnError) [0x00017] in <12b5ceac888f4387a227ffd402a29e15>:0
at AntShell.Shell.Start (System.Boolean stopOnError) [0x00102] in <12b5ceac888f4387a227ffd402a29e15>:0
at Antmicro.Renode.UI.CommandLineInterface+<>c__DisplayClass0_1.<Run>b__3 (System.Object x) [0x00000] in <eb0d5c6c2ada4750b5c3a3c345d7e4f8>:0
at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x0002c] in <12b418a7818c4ca0893feeaaf67f1e7f>:0
at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x0008d] in <12b418a7818c4ca0893feeaaf67f1e7f>:0
at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <12b418a7818c4ca0893feeaaf67f1e7f>:0
at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x00031] in <12b418a7818c4ca0893feeaaf67f1e7f>:0
at System.Threading.ThreadHelper.ThreadStart (System.Object obj) [0x00012] in <12b418a7818c4ca0893feeaaf67f1e7f>:0
I'm not sufficiently familiar with C# in general or how Renode in particular works to know why this is happening. It seems like RegisteredPeripheral is only available in the constructor, but when I print it inside WriteByte
it looks decidedly non-null.