From 13b28aa1f465420e28d101413ad433455d684410 Mon Sep 17 00:00:00 2001 From: Stephen McGinty Date: Thu, 31 Dec 2020 13:17:16 +0000 Subject: [PATCH 1/2] Added drive_clk method and infrastructure --- Gemfile.lock | 2 +- ext/bridge.c | 143 +++++++++++++++++++++++++++++- lib/origen_sim/origen/pins/pin.rb | 15 ++++ lib/origen_sim/simulator.rb | 46 ++++++++-- lib/origen_sim_dev/dut.rb | 3 +- templates/rtl_v/origen.v.erb | 104 +++++++++++++++++++++- 6 files changed, 302 insertions(+), 11 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index cb90229..a5f3dfa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -173,4 +173,4 @@ DEPENDENCIES origen_sim! BUNDLED WITH - 1.17.1 + 1.17.2 diff --git a/ext/bridge.c b/ext/bridge.c index 5a9bc4f..9678ea4 100644 --- a/ext/bridge.c +++ b/ext/bridge.c @@ -81,6 +81,7 @@ static void define_pin(char*, char*, char*, char*); static void define_wave(char*, char*, char*); static void cycle(void); static void drive_pin(char*, char*); +static void drive_clk(char*, char*, char*); static void compare_pin(char*, char*); static void capture_pin(char*); static void stop_capture_pin(char*); @@ -303,8 +304,22 @@ static void clear_waves_and_pins() { static void set_period(char * p_in_simtime_units_str) { uint64_t p = (uint64_t) strtol(p_in_simtime_units_str, NULL, 10); + period_in_simtime_units = p; clear_waves_and_pins(); + + //vpiHandle handle; + //s_vpi_value v; + + //handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("timing.cycle_period"), NULL); + //v.format = vpiDecStrVal; + //v.value.str = p_in_simtime_units_str; + //vpi_put_value(handle, &v, NULL, vpiNoDelay); + + //handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("timing.period_set"), NULL); + //v.format = vpiIntVal; + //v.value.integer = 1; + //vpi_put_value(handle, &v, NULL, vpiNoDelay); } @@ -363,6 +378,94 @@ static void drive_pin(char * index, char * val) { } +/// Drive a clk with the given timing on the given pin +static void drive_clk(char * index, char * on_str, char * off_str) { + Pin *pin = &pins[atoi(index)]; + double on = strtod(on_str, NULL); + double off = strtod(off_str, NULL); + vpiHandle handle; + s_vpi_value v = {vpiIntVal, {0}}; + + if ((*pin).present) { + // Make sure the pin is in drive mode + drive_pin(index, "0"); + + // Connect the async driver + char * driver = (char *) malloc(strlen((*pin).name) + 30); + strcpy(driver, ORIGEN_SIM_TESTBENCH_CAT("pins.")); + strcat(driver, (*pin).name); + + char * async_enable = (char *) malloc(strlen(driver) + 30); + strcpy(async_enable, driver); + strcat(async_enable, ".async_enable"); + handle = vpi_handle_by_name(async_enable, NULL); + free(async_enable); + v.value.integer = 1; + vpi_put_value(handle, &v, NULL, vpiNoDelay); + + // Now configure it for the requested clk wave + char * async_driver = (char *) malloc(strlen(driver) + 18); + strcpy(async_driver, driver); + strcat(async_driver, ".async_wave_driver"); + free(driver); + + char * edge_enable = (char *) malloc(strlen(async_driver) + 20); + strcpy(edge_enable, async_driver); + strcat(edge_enable, ".edge_enable"); + handle = vpi_handle_by_name(edge_enable, NULL); + free(edge_enable); + v.value.integer = 3; + vpi_put_value(handle, &v, NULL, vpiNoDelay); + + char * edge_drive_data = (char *) malloc(strlen(async_driver) + 20); + strcpy(edge_drive_data, async_driver); + strcat(edge_drive_data, ".edge_drive_data"); + handle = vpi_handle_by_name(edge_drive_data, NULL); + free(edge_drive_data); + v.value.integer = 2; + vpi_put_value(handle, &v, NULL, vpiNoDelay); + + char * drive_data_select = (char *) malloc(strlen(async_driver) + 20); + strcpy(drive_data_select, async_driver); + strcat(drive_data_select, ".drive_data_select"); + handle = vpi_handle_by_name(drive_data_select, NULL); + free(drive_data_select); + v.value.integer = 3; + vpi_put_value(handle, &v, NULL, vpiNoDelay); + + char * t0 = (char *) malloc(strlen(async_driver) + 3); + strcpy(t0, async_driver); + strcat(t0, ".t0"); + handle = vpi_handle_by_name(t0, NULL); + free(t0); + v.format = vpiRealVal; + v.value.real = on; + vpi_put_value(handle, &v, NULL, vpiNoDelay); + + char * t1 = (char *) malloc(strlen(async_driver) + 3); + strcpy(t1, async_driver); + strcat(t1, ".t1"); + handle = vpi_handle_by_name(t1, NULL); + free(t1); + v.format = vpiRealVal; + v.value.real = off; + vpi_put_value(handle, &v, NULL, vpiNoDelay); + + // Write to go bit to start the driver + char * go = (char *) malloc(strlen(async_driver) + 3); + strcpy(go, async_driver); + strcat(go, ".go"); + handle = vpi_handle_by_name(go, NULL); + free(go); + v.format = vpiIntVal; + v.value.integer = 1; + vpi_put_value(handle, &v, NULL, vpiNoDelay); + + free(async_driver); + } +} + + /// Immediately sets the given pin to compare against the given value static void compare_pin(char * index, char * val) { Pin *pin = &pins[atoi(index)]; @@ -863,7 +966,7 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) { type = atoi(arg1); origen_log(type, arg2); break; - // Get timescale, returns a number that maps as follows: + // Get timeunit, returns a number that maps as follows: // -15 - fs // -14 - 10fs // -13 - 100fs @@ -884,7 +987,8 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) { // 2 - 100s // l^ case 'l' : - timescale = vpi_get(vpiTimeUnit, 0); + handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("pins"), NULL); + timescale = vpi_get(vpiTimeUnit, handle); sprintf(msg, "%d\n", timescale); client_put(msg); break; @@ -981,6 +1085,41 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) { vpi_put_value(handle, &v, NULL, vpiReleaseFlag); } break; + // Drive clock on pin + // t^pin_index^on_time^off_time + case 't' : + arg1 = strtok(NULL, "^"); + arg2 = strtok(NULL, "^"); + arg3 = strtok(NULL, "^"); + //DEBUG("Define Wave: %s, %s, %s\n", arg1, arg2, arg3); + drive_clk(arg1, arg2, arg3); + break; + // Get timeprecision, returns a number that maps as follows: + // -15 - fs + // -14 - 10fs + // -13 - 100fs + // -12 - ps + // -11 - 10ps + // -10 - 100ps + // -9 - ns + // -8 - 10ns + // -7 - 100ns + // -6 - us + // -5 - 10us + // -4 - 100us + // -3 - ms + // -2 - 10ms + // -1 - 100ms + // 0 - s + // 1 - 10s + // 2 - 100s + // l^ + case 'u' : + handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("pins"), NULL); + timescale = vpi_get(vpiTimePrecision, handle); + sprintf(msg, "%d\n", timescale); + client_put(msg); + break; default : origen_log(LOG_ERROR, "Illegal message received from Origen: %s", orig_msg); runtime_errors += 1; diff --git a/lib/origen_sim/origen/pins/pin.rb b/lib/origen_sim/origen/pins/pin.rb index d943300..c897d72 100644 --- a/lib/origen_sim/origen/pins/pin.rb +++ b/lib/origen_sim/origen/pins/pin.rb @@ -32,6 +32,21 @@ def state=(val) ret end + def drive_clk(on_in_s, off_in_s) + if simulation_running? + if simulator.dut_version > '0.20.7' + # The pin has to be in drive mode for this, the data is ignored + drive(0) + time_factor = simulator.send(:time_factor) + on = (on_in_s / 1E-09) * time_factor + off = (off_in_s / 1E-09) * time_factor + simulator.put("t^#{simulation_index}^#{on}^#{off}") + else + Origen.log.warning 'This DUT was compiled with an earlier version of OrigenSim which does not support .drive_clk()' + end + end + end + def simulation_running? tester && tester.is_a?(OrigenSim::Tester) end diff --git a/lib/origen_sim/simulator.rb b/lib/origen_sim/simulator.rb index e6cacbb..8e27cf7 100644 --- a/lib/origen_sim/simulator.rb +++ b/lib/origen_sim/simulator.rb @@ -1112,7 +1112,7 @@ def dut_version end end - # Get the timescale of the current simulation, returns a number that maps as follows: + # Get the timeunit of the current simulation, returns a number that maps as follows: # -15 - fs # -14 - 10fs # -13 - 100fs @@ -1131,10 +1131,35 @@ def dut_version # 0 - s # 1 - 10s # 2 - 100s - def timescale + def timeunit put('l^') get.strip.to_i end + alias_method :timescale, :timeunit + + # Get the timeprecision of the current simulation, returns a number that maps as follows: + # -15 - fs + # -14 - 10fs + # -13 - 100fs + # -12 - ps + # -11 - 10ps + # -10 - 100ps + # -9 - ns + # -8 - 10ns + # -7 - 100ns + # -6 - us + # -5 - 10us + # -4 - 100us + # -3 - ms + # -2 - 10ms + # -1 - 100ms + # 0 - s + # 1 - 10s + # 2 - 100s + def timeprecision + put('u^') + get.strip.to_i + end # Any vectors executed within the given block will increment the match_errors counter # rather than the errors counter. @@ -1232,7 +1257,11 @@ def max_error_abort end def ns_to_simtime_units(time_in_ns) - if dut_version > '0.15.0' + # This needs to be given in the number precision units, but before this version there + # is no way to get that and so previously it is effectively hardcoded for 1ns precision + if dut_version > '0.20.7' + (time_in_ns * precision_factor).to_i + elsif dut_version > '0.15.0' (time_in_ns * time_factor).to_i else time_in_ns * time_conversion_factor * (config[:time_factor] || 1) @@ -1248,9 +1277,9 @@ def time_factor if config[:time_factor] Origen.log.warning 'Your simulation environment setup defines a :time_factor, however this is no longer used by OrigenSim' end - t = timescale + t = timeunit if t > -9 - msg = "The simulation is running with a timescale of #{TIMESCALES[timescale]}, this is greater than OrigenSim's min resolution of 1ns" + msg = "The simulation is running with a timeunit of #{TIMESCALES[timeunit]}, this is greater than OrigenSim's min resolution of 1ns" OrigenSim.error(msg) exit 1 end @@ -1258,6 +1287,13 @@ def time_factor end end + def precision_factor + @precision_factor ||= begin + t = timeprecision + "1e#{-9 - t}".to_f.to_i + end + end + # Pre 0.8.0 the simulator represented the time in ns instead of ps def time_conversion_factor @time_conversion_factor ||= dut_version < '0.8.0' ? 1 : 1000 diff --git a/lib/origen_sim_dev/dut.rb b/lib/origen_sim_dev/dut.rb index f8d92b2..6632e5e 100644 --- a/lib/origen_sim_dev/dut.rb +++ b/lib/origen_sim_dev/dut.rb @@ -28,6 +28,7 @@ def initialize(options = {}) add_pin :not_present add_power_pin :vdd add_pin :ana, type: :analog + add_pin :osc timeset :func do |t| # Generate a clock pulse on TCK @@ -106,7 +107,7 @@ def simulation_startup def startup(options = {}) # tester.simulator.log_messages = true tester.set_timeset('func', 100) - + pin(:osc).drive_clk(4.ns, 8.ns) dut.pin(:rstn).drive!(1) 10.cycles dut.pin(:rstn).drive!(0) diff --git a/templates/rtl_v/origen.v.erb b/templates/rtl_v/origen.v.erb index 3fd500f..963fdd4 100644 --- a/templates/rtl_v/origen.v.erb +++ b/templates/rtl_v/origen.v.erb @@ -2,7 +2,28 @@ // To create the big fonts - http://patorjk.com/software/taag/#p=display&f=Big -`timescale 1ns/1ns +`timescale 1ps/1ps + +//module timing(cycle_beat); +// output reg cycle_beat = 0; +// +// time cycle_period = 100; +// reg period_set = 0; +// +// initial begin +// forever begin +// if (period_set && cycle_period > 0) begin +// cycle_beat = 1; +// #($ceil(cycle_period / 2)); +// cycle_beat = 0; +// #($ceil(cycle_period / 2)); +// end else begin +// #(100); +// end +// end +// end +//endmodule + // _____ _ _ _ _ _____ _ _____ _ // | __ \(_) (_) | | | | __ (_) | __ \ (_) @@ -40,16 +61,20 @@ module pin_driver(pin, sync); reg compare = 0; reg drive = 0; reg capture = 0; + reg async_enable = 0; //reg [1023:0] memory = 0; reg [127:0] memory = 0; reg [127:0] memory_reversed = 0; reg [127:0] sync_memory = 0; + wire async_data; + + async_wave_driver async_wave_driver(.dout(async_data)); wire drive_data = force_data[0] ? 0 : (force_data[1] ? 1 : data[0]); wire contention = drive ? (pin !== drive_data ? 1 : 0) : 0; if (init_drive != -1) begin - assign pin = drive ? drive_data : 1'bz; + assign pin = drive ? (async_enable ? async_data : drive_data) : 1'bz; end // Debug signal to show the expected data in the waves @@ -103,6 +128,79 @@ module pin_driver(pin, sync); endmodule +module async_wave_driver(dout); + output reg dout; + + // The duration of each edge. The values held here only apply if the + // corresponding enable is set, otherwise they are ignored + time t0 = 0; + time t1 = 0; + time t2 = 0; + time t3 = 0; + time t4 = 0; + time t5 = 0; + time t6 = 0; + time t7 = 0; + + // Data value to be applied to the pin, typically corresponds to the + // "D" value during a drive cycle + reg drive_data = 0; + + // Enables for each timing edge + reg [7:0] edge_enable = 0; + + // Optional edge-specific data values + reg [7:0] edge_drive_data = 0; + + // Selects the data source for the edge, 0 means apply 'drive_data' while a 1 + // means apply the edge-specific value from 'edge_drive_data' + reg [7:0] drive_data_select = 0; + + // Tell the driver to start. Once started it will run indefinitely until all + // edge enables are disabled (edge_enable == 0). + // It can be re-started by writing go=1 after enabling at least one edge. + reg go = 0; + + always @(posedge go) begin + go = 0; + while (edge_enable != 0) begin + if (edge_enable[0]) begin + #(t0); + dout = drive_data_select[0] ? edge_drive_data[0] : drive_data; + end + if (edge_enable[1]) begin + #(t1); + dout = drive_data_select[1] ? edge_drive_data[1] : drive_data; + end + if (edge_enable[2]) begin + #(t2); + dout = drive_data_select[2] ? edge_drive_data[2] : drive_data; + end + if (edge_enable[3]) begin + #(t3); + dout = drive_data_select[3] ? edge_drive_data[3] : drive_data; + end + if (edge_enable[4]) begin + #(t4); + dout = drive_data_select[4] ? edge_drive_data[4] : drive_data; + end + if (edge_enable[5]) begin + #(t5); + dout = drive_data_select[5] ? edge_drive_data[5] : drive_data; + end + if (edge_enable[6]) begin + #(t6); + dout = drive_data_select[6] ? edge_drive_data[6] : drive_data; + end + if (edge_enable[7]) begin + #(t7); + dout = drive_data_select[7] ? edge_drive_data[7] : drive_data; + end + end + end +endmodule + + `ifdef ORIGEN_WREAL // _ _____ _ _____ _ // /\ | | | __ (_) | __ \ (_) @@ -305,6 +403,8 @@ module <%= options[:testbench_name] || 'origen' %>; debug debug (); + //timing timing (); + initial begin `ifdef ORIGEN_VCS From 52995264f2f49345175b11cd3254fc4564826711 Mon Sep 17 00:00:00 2001 From: Stephen McGinty Date: Thu, 31 Dec 2020 13:41:38 +0000 Subject: [PATCH 2/2] Added net arg to timeunit/precision methods and added docs --- Gemfile.lock | 96 ++++++++++--------- ext/bridge.c | 10 +- lib/origen_sim/simulator.rb | 38 ++++++-- .../origen_guides/simulation/patterns.md.erb | 16 ++++ 4 files changed, 103 insertions(+), 57 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a5f3dfa..00ce8ed 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,24 +9,24 @@ PATH GEM remote: https://rubygems.org/ specs: - activesupport (4.2.11.1) + activesupport (4.2.11.3) i18n (~> 0.7) minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - ast (2.4.0) + ast (2.4.1) astrolabe (1.3.1) parser (~> 2.2) atp (1.1.3) ast (~> 2) origen (>= 0.2.3) sexpistol (~> 0.0) - builder (3.2.3) - byebug (11.0.1) - coderay (1.1.2) + builder (3.2.4) + byebug (11.1.3) + coderay (1.1.3) colored (1.2) colorize (0.8.1) - concurrent-ruby (1.1.5) + concurrent-ruby (1.1.7) coveralls (0.8.23) json (>= 1.8, < 3) simplecov (~> 0.16.1) @@ -36,33 +36,33 @@ GEM cri (2.10.1) colored (~> 1.2) dentaku (2.0.11) - diff-lcs (1.3) - docile (1.3.2) - dry-inflector (0.1.2) + diff-lcs (1.4.4) + docile (1.3.4) + dry-inflector (0.2.0) gems (0.8.3) highline (1.7.10) - httparty (0.17.0) + httparty (0.18.1) mime-types (~> 3.0) multi_xml (>= 0.5.2) i18n (0.9.5) concurrent-ruby (~> 1.0) - json (2.2.0) + json (2.5.1) kramdown (1.17.0) - method_source (0.9.2) - mime-types (3.3) + method_source (1.0.0) + mime-types (3.3.1) mime-types-data (~> 3.2015) - mime-types-data (3.2019.0904) + mime-types-data (3.2020.1104) mini_portile2 (2.4.0) - minitest (5.11.3) + minitest (5.14.2) multi_xml (0.6.0) nanoc (3.7.5) cri (~> 2.3) - net-ldap (0.16.1) - nokogiri (1.10.5) + net-ldap (0.17.0) + nokogiri (1.10.10) mini_portile2 (~> 2.4.0) - origen (0.54.0) + origen (0.55.1) activesupport (~> 4.1) - bundler (~> 1.7) + bundler (> 1.7) coderay (~> 1.1) colored (~> 1.2) colorize (~> 0.8.1) @@ -87,14 +87,14 @@ GEM yard (~> 0.8) origen_doc_helpers (0.8.2) origen (>= 0.7.15) - origen_jtag (0.22.0) + origen_jtag (0.22.1) origen (~> 0.7, >= 0.7.35) origen_testers (>= 0.13.2) - origen_stil (0.2.1) + origen_stil (0.3.0) ast (~> 2) origen (>= 0.33.3) treetop - origen_testers (0.42.0) + origen_testers (0.47.0) ast (~> 2) atp (~> 1.1, >= 1.1.3) origen (>= 0.44.0) @@ -106,44 +106,44 @@ GEM ast (~> 2) origen (>= 0.41.0) treetop - parser (2.6.4.1) - ast (~> 2.4.0) + parser (2.7.2.0) + ast (~> 2.4.1) polyglot (0.3.5) - powerpack (0.1.2) - pry (0.12.2) - coderay (~> 1.1.0) - method_source (~> 0.9.0) + powerpack (0.1.3) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) rainbow (2.2.2) rake rake (10.5.0) require_all (1.5.0) - rodf (1.1.0) + rodf (1.1.1) builder (>= 3.0) dry-inflector (~> 0.1) rubyzip (>= 1.0) - rspec (3.8.0) - rspec-core (~> 3.8.0) - rspec-expectations (~> 3.8.0) - rspec-mocks (~> 3.8.0) - rspec-core (3.8.2) - rspec-support (~> 3.8.0) - rspec-expectations (3.8.4) + rspec (3.10.0) + rspec-core (~> 3.10.0) + rspec-expectations (~> 3.10.0) + rspec-mocks (~> 3.10.0) + rspec-core (3.10.1) + rspec-support (~> 3.10.0) + rspec-expectations (3.10.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-legacy_formatters (1.0.1) + rspec-support (~> 3.10.0) + rspec-legacy_formatters (1.0.2) rspec (~> 3.0) - rspec-mocks (3.8.1) + rspec-mocks (3.10.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-support (3.8.2) + rspec-support (~> 3.10.0) + rspec-support (3.10.1) rubocop (0.30.0) astrolabe (~> 1.3) parser (>= 2.2.0.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.4) - ruby-progressbar (1.10.1) - rubyzip (1.2.4) + ruby-progressbar (1.11.0) + rubyzip (2.3.0) scrub_rb (1.0.1) sexpistol (0.0.7) simplecov (0.16.1) @@ -151,16 +151,18 @@ GEM json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.2) + sync (0.5.0) term-ansicolor (1.7.1) tins (~> 1.0) thor (0.20.3) thread_safe (0.3.6) - tins (1.21.1) - treetop (1.6.10) + tins (1.26.0) + sync + treetop (1.6.11) polyglot (~> 0.3) - tzinfo (1.2.5) + tzinfo (1.2.9) thread_safe (~> 0.1) - yard (0.9.20) + yard (0.9.26) PLATFORMS ruby diff --git a/ext/bridge.c b/ext/bridge.c index 9678ea4..c65d20e 100644 --- a/ext/bridge.c +++ b/ext/bridge.c @@ -985,9 +985,10 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) { // 0 - s // 1 - 10s // 2 - 100s - // l^ + // l^origen.dut.some.net case 'l' : - handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("pins"), NULL); + arg1 = strtok(NULL, "^"); + handle = vpi_handle_by_name(arg1, NULL); timescale = vpi_get(vpiTimeUnit, handle); sprintf(msg, "%d\n", timescale); client_put(msg); @@ -1113,9 +1114,10 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) { // 0 - s // 1 - 10s // 2 - 100s - // l^ + // u^origen.dut.some.net case 'u' : - handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("pins"), NULL); + arg1 = strtok(NULL, "^"); + handle = vpi_handle_by_name(arg1, NULL); timescale = vpi_get(vpiTimePrecision, handle); sprintf(msg, "%d\n", timescale); client_put(msg); diff --git a/lib/origen_sim/simulator.rb b/lib/origen_sim/simulator.rb index 8e27cf7..7dd99fa 100644 --- a/lib/origen_sim/simulator.rb +++ b/lib/origen_sim/simulator.rb @@ -513,6 +513,8 @@ def simulation_open? # Starts up the simulator process def start @simulation_open = true + @timeunits = {} + @timeprecisions = {} @pattern_starting_error_count = nil @simulation = Simulation.new(wave_file_basename, view_wave_command) simulations << @simulation @@ -1131,9 +1133,21 @@ def dut_version # 0 - s # 1 - 10s # 2 - 100s - def timeunit - put('l^') - get.strip.to_i + # + # A net can be given to get the timeunit that applies to a specific module, defaults to + # .pins + def timeunit(net = nil) + if dut_version > '0.20.7' + net ||= "#{testbench_top}.pins" + @timeunits[net] ||= begin + put("l^#{net}") + get.strip.to_i + end + @timeunits[net] + else + put('l') + get.strip.to_i + end end alias_method :timescale, :timeunit @@ -1156,9 +1170,21 @@ def timeunit # 0 - s # 1 - 10s # 2 - 100s - def timeprecision - put('u^') - get.strip.to_i + # + # A net can be given to get the timeunit that applies to a specific module, defaults to + # .pins + def timeprecision(net = nil) + if dut_version > '0.20.7' + net ||= "#{testbench_top}.pins" + @timeprecisions[net] ||= begin + put("u^#{net}") + get.strip.to_i + end + @timeprecisions[net] + else + Origen.log.warning 'This DUT was compiled with an earlier version of OrigenSim which does not support timeprecision fetching, returning 1ns as a best guess' + -9 + end end # Any vectors executed within the given block will increment the match_errors counter diff --git a/templates/origen_guides/simulation/patterns.md.erb b/templates/origen_guides/simulation/patterns.md.erb index 0924e21..8bbbfed 100644 --- a/templates/origen_guides/simulation/patterns.md.erb +++ b/templates/origen_guides/simulation/patterns.md.erb @@ -228,4 +228,20 @@ end See the [Direct DUT Manipulation](<%= path "guides/simulation/direct" %>) guide for more details on these APIs. +#### Driving Clocks + +Clock waveforms can be driven on pins via the following API: + +~~~ruby +pin(:my_pin).drive_clk(4.ns, 8.ns) # On duration, Off duration +~~~ + +This will produce a free-running clock with the given wave characteristics which is completely indepedent +from the pattern timing/period of the current simulation. +Such a clock can not be produced by a vector pattern and this method is ignored when targetting an +ATE environment. + +This feature is most useful when running an IP-level simulation where the IP has a clk input which would +be supplied by the SoC (rather than the tester) in the final integration. + % end