Origen-SDK / origen_sim

Plugin to enable Origen patterns to be run in a dynamic Verilog simulation
MIT License
1 stars 4 forks source link

Adds WREAL Support #34

Closed ginty closed 5 years ago

ginty commented 5 years ago

This PR adds the following:

AMS Support

OrigenSim supports analog/mixed-signal (AMS) simulations via real-number modeling (RNM), whereby top-level pins can be defined as real wire types (WREALs) and then Origen APIs can be used to drive and measure real number values from them.

By default, OrigenSim's built in simulation setups will run a digital simulation, allowing such real number inputs to be used by behavioral models within that DUT which can themselves output real numbers to be observed on the DUT's pins by Origen APIs.

The DUT could also contain full electical models which consume the real number inputs, in that case a [custom simulation configuration](<%= path "guides/simulation/environment/#Custom_Simulator_Configuration" %>) will be required to define the run command to start the simulation.

Building Support for AMS Simulation

AMS support must be added in when building the testbench, this is done by adding the --wreal switch to the sim:build command:

origen sim:build path/to/my_dut.v --wreal

By adding this switch, any pins which are defined as wreal types within the given top level will be assigned an analog pin driver by the testbench rather than a digital driver which is the default.

Pins can be defined as a wreal type either by adding the real type to their definition:

input real vddc,

or by adding a wreal wire within the module body:

wreal vddc;

Here is an example which uses both approaches to declare the vdd and ana pins as analog pins whenever the USE_WREAL define is enabled:

module my_dut(
  input tck, tdi, tms, trstn,
  input rstn,
  input [31:0] din,
  input p1,
  input p2,
  `ifdef USE_WREAL
  inout real vdd,
  `else
  inout vdd,
  `endif

  output tdo,
  output done,
  output [15:0] test_bus,
  output [31:0] dout,
  output ana
);

`ifdef USE_WREAL
  wreal ana;
`endif
endmodule

A digital testbench for this would be built via this command:

origen sim:build path/to/my_dut.v

while AMS support would be added by running:

origen sim:build path/to/my_dut.v --wreal --define USE_WREAL

Origen Application Configuration

Within the corresponding Origen DUT model of the design, the wreal pins should be declared as either an analog, power or ground pins.

From the above example, the wreal pins could be modeled like this:

add_power_pin :vdd    # Could also be a regular analog pin too, if you prefer

add_pin :ana, type: :analog

See the [Pins Guide](<%= path "guides/models/pins" %>) for more information on modeling pins in Origen.

AMS APIs

With all of the AMS configuration done, real values can now be driven and read from Origen application code during a simulation like this:

dut.power_pin(:vdd).drive(1.25)

dut.pin(:ana).read     # => 0.7

# .measure is available as an alias of read for analog pins
dut.pin(:ana).measure  # => 0.7

The peek, poke and force methods from [the Simulation Only API](<%= path "guides/simulation/api" %>) are also available to manipulate real valued nets during simulation.

The analog pin APIs will not work correctly when generating a pattern for an ATE and the application code is responsible for handling them safely, typically like this:

# Example of a simulation-only assertion
if tester.sim?
  measured = dut.pin(:ana).measure
  if measured != 0.3125
    OrigenSim.error "Expected to measure 0.3125V from the ana pin, got #{measured}V!"
  end
end

It is easy to build more complex functionality in your application code from these simple APIs, for example to ramp a vdd pin:

# Ramp up the power on VDD
v = 0
dut.power_pin(:vdd).drive!(v)
until v >= 1.25
  v += 0.05
  dut.power_pin(:vdd).drive!(v)   # Note the use of drive! here which will generate a cycle
end

It is hoped that the community will contribute plugins that contain higher-level functionality like this to make such functions available off-the-shelf in the future.

Direct DUT Manipulation

A number of methods exist to directly manipulate the state of the DUT during a simulation, in all cases these methods do not re-target to the ATE because they rely on being able to directly look inside and manipulate the DUT which is not possible in the physical world.

The user is responsible for ensuring that the use of these APIs is safely handled when generating for an ATE or other non-simulation target, normally via one of these constructs:

# Simply skip this unless simulating
unless tester.sim?
  tester.peek # ...
end

# Implement differently for ATE
if tester.sim?
  tester.poke # ...
else
  dut.do_something
end

Poke

Poking is the term commonly given to changing the value of a register or other variable, i.e. poking a new value into an existing storage element.

To use the poke method, supply the net path of the storage element to be changed and the value you want to change it to:

# Poking a register
tester.poke("dut.my_ip.user_regs.some_reg", 0x1111)

# Poking a memory
tester.poke("dut.my_ip.mem[15]", 0x1111_2222)

The poke method can be used on real variables too, in that case a float should be given as the second argument instead of an integer to indicate to Origen that a real value net is being poked. e.g. to poke the value 1 to a real value net then supply 1.0 as the value argument instead of 1.

tester.poke("dut.my_ip.my_real_var", 1.25)

Peek

Peeking allows you to read the value of an internal register or other variable.

The value returned from the peek method will be an instance of [Origen::Value](<%= path "api/Origen/Value.html" %>) which can also handle X or Z values.

Normally, if you don't care about catching Z or X cases you can simply call to_i on the value returned from peek, here are some examples:

# Peeking a register
tester.peek("dut.my_ip.user_regs.some_reg").to_i   # => 0x1111

# Peeking a memory
tester.peek("dut.my_ip.mem[15]").to_i   # => 0x1111_2222

When peeking a real number, X or Z states are not supported and a float will be returned.

You must indicate to Origen that you are peeking a real value by supplying a second argument of true, or for convenience calling peek_real instead:

tester.peek("dut.my_ip.my_real_var", true)   # => 1.25

tester.peek_real("dut.my_ip.my_real_var")    # => 1.25

Force

When poking the DUT, you are changing the value of a reg or other variable which provides drive. i.e. as soon as the poke operation is done, the responsibility for maintaining and driving the new value is down to the DUT. For this reason, you cannot just poke any net, only those which can store/drive state. In Verilog terms, you can poke a register but you can't poke a wire.

With a force, the simulator provides infinite drive/storage of the forced value and this will override any drive produced in the DUT. So when you force a value on a net, that will persist there for the entire simulation regardless of what goes on in the DUT until the force is released.

The force method has the same arguments as the peek method:

# Forcing a register
tester.force("dut.my_ip.user_regs.some_reg", 0x1111)

# Forcing a memory
tester.force("dut.my_ip.mem[15]", 0x1111_2222)

# Forcing a real value
tester.force("dut.my_ip.my_real_var", 1.25)

A force can be released by calling the release method and supplying the net reference:

# Releasing an existing force
tester.release("dut.my_ip.user_regs.some_reg")
ginty commented 5 years ago

@chrisnappi, as part of the cleanup of the bootstrapping process for VCS, I renamed the bootstrap function to origen_init. I wanted to make it clearer which functions were internal use and which could be called from outside (prefixed with origen_).

I didn't think anyone actually used the bootstrap method but its since been brought to my attention that you may have used it.

If you prefer I keep the old method around for legacy compatibility just say and I can add it bank.

Thanks!

chrisnappi commented 5 years ago

Yes, the function must be named 'bootstrap' for the ancient version of ncsim I am using on some projects. Originally the bootstrap was init() - and Corey and I added bootstrap just calling init as a work-around for this...

ginty commented 5 years ago

Yes @pderouen, no problem with reintroducing that function now that I know that bootstrap is a required name for it.