intel / rohd

The Rapid Open Hardware Development (ROHD) framework is a framework for describing and verifying hardware in the Dart programming language.
https://intel.github.io/rohd-website
BSD 3-Clause "New" or "Revised" License
370 stars 65 forks source link

Simulator upgrades for rohme compatibility (registering now and cancelling) #468

Closed AdamRose66 closed 6 months ago

AdamRose66 commented 6 months ago

Description & Motivation

The intention of these changes is to enable Rohme / Rohd interoperability by Layering Rohme on top of the Rohd simulator.

Rohd needs three kinds of callback:

  1. Post to a future time ( Timer( SimDuration(...) , callback )
  2. Post to the next delta ( Timer( SimDuration.zero , callback )
  3. Post to "end of this delta" ( scheduleMicrotask )

Statistically speaking, (1) and (2) are common while (3) is rare.

As a result of (2), one time slot may have many delta cycles. Each time slot looks like this:

delta 0:

The timeslot finishes when there have been no zero delay ( type (2) ) callbacks posted.

The following Rohme code uses type (2) zero time delays:

await Future.delayed( SimDuration.zero );
print('a');
await Future.delayed( SimDuration.zero );
print('b');
await Future.delayed( SimDuration.zero );
print('c');

Each call to Future.delayed( t ) above actually creates a Timer( current_time + t ).

Conceptually, it is very similar to the following SV code:

#0;
$display("a");
#0;
$display("b");
#0;
$display("c");

These zero delays are used for example to create mutexs which are fair and deterministic.

Mapping from Rohme to Rohd

  1. Posting to the future is mapped to registerAction( timestamp ) , where timestamps > Simulator.time
    • added a cancelAction( timestamp , action ) to support cancel ( and therefore suspend / resume )
  2. Posting to the next delta is done using registerAction( Simulator.time )
    • this creates another complete tickExecute at the current time
  3. End of delta ( ie, microtask ) callbacks are mapped to injectAction

Testing

All existing Rohd tests pass as previously. A few new tests have been added in test/simulator_test.dart.

Backwards-compatibility

Given that all current tests pass, there should be no backward compatibility issues.

Documentation

The small number of changes to the Simulator class have been documented inline.

Further Work

Package Organisation

For Rohme to use the Rohd simulator, it has to pull in the entire Rohd package. It would be easier for Rohme if the Rohd simulator was split out into its own package. We could also consider putting the Rohme simulator in this shared package. An external simulator might be useful for other packages which want to share the underlying timing with Rohme and Rohd.

Incremental execution

A feature of the Rohme simulator is that it can run for some time and then run again for a little more time. This might be useful in the future tool integrations where the simulator needs to be started and stopped. It isn't obvious if this feature is supported, or whether it is viable in Rohd ( since there are end-of-simulation events etc ).

Time zero reset

I ran a few experiments with doing Simulator.reset() before running a simulation. It seems that Simulator.reset() only works after a simulation has been run ( eg in a teardown method ). The reason I would like to run it before the simulation runs is that the Rohme simulator is an actual class with a constuctor, so it would be nice to put the reset in the constructor rather than a teardown method. That way a single test.dart can instantiate many Rohme simulators as it moves though the different tests. This might be as simple as doing nothing if a simulation has never been run. Alternatively, we could introduce a 'hasBeenRun' getter into the Rohd simulator so that Rohme could check for it before attempting to call Simulator.reset().

mkorbel1 commented 6 months ago

@AdamRose66

Incremental execution

These two issues might be related: https://github.com/intel/rohd/issues/451 https://github.com/intel/rohd/issues/450

Time zero reset

I tried a test like this and it passed:

  test('simulator reset immediately works ok', () async {
    await Simulator.reset();

    var actionTaken = false;
    Simulator.registerAction(100, () => actionTaken = true);

    await Simulator.run();
    expect(actionTaken, equals(true));

    await Simulator.reset();
  });

What symptoms were you seeing? Would you have expected this test to fail?

AdamRose66 commented 6 months ago

Ah ! It's quite likely I was just doing Simulator.reset(); rather than await Simulator.reset();

mkorbel1 commented 6 months ago

Ah ! It's quite likely I was just doing Simulator.reset(); rather than await Simulator.reset();

Ah I see, yes that might not work right. Fortunately, Dart lint rules can catch this.

I would like to run it before the simulation runs is that the Rohme simulator is an actual class with a constuctor, so it would be nice to put the reset in the constructor rather than a teardown method.

I don't believe you can make a constructor async in Dart, so it sounds like you still may run into an issue there with your goals. Perhaps there's another place to reset it at the start of execution in your package rather than relying on a tearDown, which is really testing specific.