Compare commits

..
Author SHA1 Message Date
Stephen Williams afa2478801 Merge branch 'master' of ssh://[email protected]/home/u/icarus/steve/git/verilog 2008-06-09 16:58:21 -07:00
Stephen Williams 79feb44f10 Turn of concat output scheduling.
We really want lazy processing of concatenation because it has multiple
inputs and lazy processing should (in theory) prevent redundant and
useless propagations through the net.

But enabling it seems to cause many tests in the regression test suite
to fail to compare their results. There are races in many tests that
are interacting badly with this feature. So for now, ifdef it out.
2008-06-09 16:57:51 -07:00
Stephen Williams c03d76a0d7 Do not do lazy processing of part selects.
It doesn't really make any sense to do lazy processing of part selects,
but it is possible to use the part select position to more toroughly
check for changes in output and suppress non-changes. In particular,
we only need to check that the output part actually changes, and by the
way we only need to save those bits for the next go-round.

We do want to make sure that the very first input causes an output,
though, so that time-0 values get propagated.
2008-06-09 16:46:06 -07:00
Stephen Williams a2dc1e0a29 Add means for &A<> to index using a calculated index.
This is not a solution to all the problems, but is a better catch-all
then what is currently there. Allow the index field to be a T<> that
accesses the thread to get the address index.

Note that the lexor.lex currently returns the T<> as a T_SYMBOL, and the
users of T_SYMBOL objects need to interpret the meaning. This is
probably not the best idea, in light of all the other *<> formats that
now exist.
2008-06-08 21:38:35 -07:00
Stephen Williams 6a1235ac28 Rework parameter indexed part select up.
Indexed part select reworked to be more compact and more like the
part select.
2008-06-08 19:29:00 -07:00
Stephen Williams 7aebff2a86 Fix up parameter name part select
Part select of parameter names is fixed up to be structurally similar
to part select of signals, and also to behave similarly. (Though not
identically, for reason.)
2008-06-08 07:34:45 -07:00
Stephen Williams b31124983a Allow part selects to fall off the ends of the selected identifier
Part selects to signals are allowed to be off the ends of the signal
itself. The bits that are beyond the vector return X. This may mean
creating constant X bits on one or both ends of the result.
2008-06-06 22:05:17 -07:00
Larry Doolittle f256dfe16e Add missing include to vvp_island.cc
Add # include <string.h>, needed for compilation with gcc-4.3
2008-06-06 20:48:23 -07:00
Cary R 7c152685dc Clean up more compiletf routines, etc.
This patch cleans up some of the code to use common compiletf
routines where appropriate. It also adds code to print the
number of extra arguments and cleans up the messages a bit.
2008-06-06 20:44:21 -07:00
Stephen Williams 5d86dd0bbd Merge branch 'verilog-ams' 2008-06-06 20:39:42 -07:00
Cary R 4f97321c75 Add more array word properties.
This patch adds more array word properties.
2008-06-06 20:36:55 -07:00
Stephen Williams d0f303463d ASSIGN transfer data to scheduler efficiently/permalloc vvp_net_t objects.
The vvp_net_t objects are never deleted, so overload the new operator
to do a more space efficient permanent allocation.

The %assign/v instruction copied the vvp_vector4_t object needlessly
on its way to the scheduler. Eliminate that duplication.
2008-06-06 19:50:44 -07:00
Stephen Williams 35fe8fae00 Have vvp_vector8_t avoid allocating tiny scalar arrays. 2008-06-06 16:36:43 -07:00
Stephen Williams 2e95a740da Rework scheduling of concat, part, buf/not and resolv for efficiency.
The concat and resolv functors are best evaluated lazily, because each
evaluation is costly and there is a high probability that an evaluation
will be invalidated when new input comes in.

Also optimization the recv_vec4_pv method of the resolver, which is
commonly used, and adjust the order of handling of vvp_fun_part to
work more efficiently.
2008-06-06 15:31:22 -07:00
Stephen Williams 2f4e5bf5b6 Obvious optimizations of vvp_vector8_t handling.
The vvp_vector8_t constructor and destructor involve memory allocation
so it is best to pass these objects by reference as much as possible.

Also rework the resolver functor to only perform resolution after inputs
are in so that it doesn't get needlessly repeated. This eliminates many
resolve function calls, as well as activations throughout the net.

Also have the islands take more care not to perform resolution if the
inputs aren't really different.
2008-06-06 11:12:07 -07:00
Stephen Williams 7e478cdeb8 Merge branch 'master' into verilog-ams 2008-06-05 21:52:12 -07:00
Stephen Williams 2576543bb5 Add support for exclude of a point
Parameter value ranges support the exclude of a point as well as
range, so add the syntax to support that case. Internally it is
handled as a degenerate range, but the parse and initial elaboration
need to know about it.
2008-06-05 21:49:49 -07:00
Cary R e453b347f4 Add missing functions to ivl.def
This patch adds ivl_island_flag_set and ivl_island_flag_test
to the ivl.def file. This is needed by both Cygwin and MinGW.
2008-06-05 14:41:49 -07:00
Stephen Williams f132e09475 Fix default parameter type if localparams are present.
localparam declarations were messing up the state of parser variables
so that the default types of following parameters got messed up.
2008-06-05 14:38:56 -07:00
Stephen Williams 2ee976d1c0 Compile problems after merge with verilog-ams
The NetPartSelect::BI enumeration value does not exist any more.
2008-06-05 11:06:54 -07:00
Stephen Williams 30570adf31 Merge branch 'master' into verilog-ams 2008-06-05 10:52:58 -07:00
Cary R 1c51ac4ac0 For undefined memory words (size == 0) return an X vector.
If a memory word was accessed before it was defined the
code was returning a zero width vector result. Now it
returns an appropriately sized vector of 'x'.
2008-06-05 10:34:18 -07:00
Cary R 17a1358eb6 Remove documentation for memory opcodes.
The memory opcodes %assign/mv, %load/mv and %set/mv
were removed by a previous patch. This one removes
the documentation from opcodes.txt. It also removes
the documentation for the .mem* statements for the
same reason.
2008-06-05 10:31:38 -07:00
Stephen Williams 04a7f7054a Fix problem linking a-side and b-side tran branches.
Tran devices linked in series were not getting properly joined up
due to a problem with the add_branch method.
2008-06-04 20:34:04 -07:00
Stephen Williams e97a1ad610 Try to eliminate excessive processing recursions.
After calculating the A side of a tran[if/vp], the B side is usually
fully specified, so make an effort to push the calculated value through.
2008-06-04 16:10:43 -07:00
Stephen Williams e872310e4b Optimize recursive branch resolution
Recursive branch resolution was scanning every branch end, even though
many branch ends share ports and need not be repeatedly scanned. Handle
marks and flags to cut off recursion where it is not needed so as to
save much run time.
2008-06-04 11:34:26 -07:00
Stephen Williams 95850ac112 Merge branch 'master' into verilog-ams
Conflicts:

	tgt-vvp/vvp_scope.c

Note that the draw_net_input.c takes in a lot of the codes that used
to be in vvp_scope.c, so some changes may have been lost.
2008-06-03 21:17:57 -07:00
Cary R d0e154b830 Clean up dump routines and support of MemoryWord dump.
This patch cleans up the dump routines and adds file and
line number information for errors. It also adds some of
the missing MemoryWord properties so they can now be
dumped and monitored correctly.
2008-06-03 21:04:22 -07:00
Cary R 4010f6e710 Add $simparam and other fixes.
This patch adds $simparam and $simparam$str from Verilog-A.
The analog simulator parameters return 0.0 or N/A. The
vvp_cpu_wordsize system function has been moved into the
$simparam call and is now named CPUWordSize.

This patch also starts the factoring of common code in the
vpi directory. Some routines were renamed.

The priv.c file was renamed to sys_priv.c to match the
include file.

System functions can now have strings put to their output.
2008-06-03 20:56:37 -07:00
Larry Doolittle d74f2fe38d Don't duplicate Makefile shell code
Smaller, and conceptually easier to keep in sync,
way of handling build machines with and without git.
2008-06-03 20:52:41 -07:00
Stephen Williams db642e3850 Merge branch 'master' of ssh://[email protected]/~steve-icarus/git/verilog 2008-06-03 20:51:04 -07:00
Larry Doolittle 523dff7ae7 Fix probable precedence bug
and at least get rid of a compiler warning
2008-06-03 20:50:36 -07:00
Stephen Williams db09f2fa7e More cost effective and reliable island joining algorithm.
Rather then join islands while branches are initially created, save the
island creating for the end. This way, the process is actually recursive
and greedy, reliably collecting branches into islands without conflict.
2008-06-03 20:21:39 -07:00
Stephen Williams c2061e8199 Island ports can accept vector parts. 2008-06-03 17:31:15 -07:00
Stephen Williams ff9166d4a5 Got sense of tranvp wrong in connections to module ports. 2008-06-03 17:23:01 -07:00
Stephen Williams 73e2b297df Replace the NetPartSelect:BI with NetTran(VP).
Fold the bi-directional part select into the pass switch (tran) support
so that it can be really bi-directional. This involves adding a new
tranvp device that does part select in tran islands, and reworking the
tran island resolution to handle non-identical nodes. This will be needed
for resistive tran devices anyhow.
2008-06-03 11:16:25 -07:00
Stephen Williams 6e5373c87e Add part select support to vvp_vector8_t
Need a convenient way to handle part selects of vvp_vector8_t objects.
2008-06-03 08:52:42 -07:00
Stephen Williams 782bfab29e Add support for tranif devices in the vvp code generator.
The draw_net_input function is modified to account for nexus that is
a port of an island. Draw the ports (and the islands if necessary)
to the island and use the port output for the nexus instead of the
port input. This allows the bi-directional behavior of the port to
interpose itself in the data flow.

In this process of these changes, the draw_net_input function was
reorganized, and all the considerable amount of code for it was
moved to a file of its own. (vvp_scope.c is pretty unruly.)
2008-06-01 21:08:31 -07:00
Stephen Williams df15a0368c Collect NetTran devices into islands.
NetTran devices must be collected into islands because they are all
a bi-directional mass. This is how vvp will process them and the code
generator will need a head start organizing them.
2008-06-01 19:45:12 -07:00
Stephen Williams 916f300448 Assert some island port constraints. 2008-06-01 19:42:44 -07:00
Stephen Williams 7898f4e402 Account for swithes linked to nexus in ivl_target.h API.
Switches can connect to a nexus too, so add the missing nexus support
for that in the ivl_target.h API.
2008-06-01 14:29:27 -07:00
Stephen Williams 6f8bf90dc4 Add basic the .tran device.
The .tran device is simply a .tranif0 without the enable. It is
always enabled.
2008-06-01 10:37:41 -07:00
Stephen Williams 052870c0e5 And the vvp_island infrastructure to the vvp runtime.
The vvp_island classes are added, as well as support for tranif nodes
that use this concept. The result is a working implementation for
tranif0 and tranif1.

In the process, the symbol table functions were cleaned up and made
into templates for better type safety, and the vvp_net_ptr_t was
generalized so that it can be used by the branches in the island
implementation.

Also fix up the array handling to use the better symbol table support,
and to remember to clear its own table when linking is done.
2008-05-31 21:45:55 -07:00
Stephen Williams 1be1f65f33 Merge branch 'master' into verilog-ams 2008-05-29 20:11:00 -07:00
Stephen Williams fd6f017435 Get very subtle handling of part select into ports correct.
The code generator was reading the wrong node of a bi-directional
part select. This happens exclusively with part selects passed to
bi-directional ports, so was rare. The result was that the non-part
selected part may get an incorrect value.
2008-05-29 17:28:12 -07:00
Stephen Williams dfa6471227 Merge branch 'master' of ssh://[email protected]/home/u/icarus/steve/git/verilog 2008-05-29 14:00:51 -07:00
Stephen Williams a8f492776a Check range of immediate value. 2008-05-29 14:00:32 -07:00
Stephen Williams 6f0d98cf18 Constrain multiply word to prevent overflow.
The multiply runs does not need to do all the combinations of digit
products, because the higher ones cannot add into the result. Fix the
iteration to limit the scan.
2008-05-29 14:00:03 -07:00
Stephen Williams 6f30813102 Prevent overflow when parsing 32bit values
The source can carry 32bit numbers. Watch out that they are handled
all the way through to the compiled results on 32bit systems.
2008-05-29 13:52:12 -07:00
Cary R 2fab3159dd Add smart part select for system functions &PV<>.
This patch adds a smart part select that allows system functions
to have full access to the real bits of the part select.
2008-05-29 09:40:12 -07:00
Cary R f04fb0fc45 System functions have a default return value.
If a system function does not call vpi_put_value it is
supposed to have a default return value of 0. This patch
adds this functionality.
2008-05-28 09:53:27 -07:00
Cary R 7a1180868a Remove definition for non-existent routines.
ivl_switch_scope, ivl_switch_attr_cnt and ivl_switch_attr_val
are non-existent routines and should not be in ivl.def. I also
removed them from ivl_target.h. Cygwin expects that if a routine
is listed in ivl.def that it will find a real implementation.
2008-05-28 09:45:27 -07:00
Cary R b2bdce98ab It is an error for the concatenation repeat to be undefined.
Print an error message if the concatenation repeat expression
is undefined.
2008-05-28 09:39:57 -07:00
Cary R 653e2661b2 The no git code also check for an existing version.h
My previous patch always used an empty file if git was not
available. This patch extends this to use the existing
version.h file if it exists (snapshot, etc.)
2008-05-28 09:09:33 -07:00
Stephen Williams 9aa610f489 Fix handling of 32bit IMM in %addi on 32bit machines
The handling of immediate add used to do 16bits at a time. When it went
up to 32bits, the need to work in chunks vanished, but the chunk handling
was still there, this time shifting by 32, which causes problems on 32bit
machines. Simplify the %addi handling to avoid this.
2008-05-28 08:47:28 -07:00
Stephen Williams de7fff8ac6 Elaborate tran devices (switches)
This takes the support for switch modeling to the code generator.
Add error messages in the vvp code generator for lack of support.
2008-05-27 20:06:58 -07:00
Stephen Williams 2179797763 Do not allow unknows to be handled as logic immediate. 2008-05-27 19:48:31 -07:00
Cary R b5e9e44e07 Fix error in of_SUBI with wide results.
This patch fixes an error in the recent rework of of_SUBI.
It was doing a double bit inversion.
2008-05-27 19:42:20 -07:00
Stephen Williams 5a0fe9ff83 Better use of immediate operands.
Clarify that operands are typically 32bits, and have the code generator
make better use of this.

Also improve the %movi implementation to work well with marger vectors.

Add the %andi instruction to use immediate operands.
2008-05-27 17:51:28 -07:00
Stephen Williams f6fede5aae Merge branch 'master' of ssh://[email protected]/home/u/icarus/steve/git/verilog 2008-05-27 11:55:45 -07:00
Stephen Williams 0fa3099ded Optimize %div and %div/s
Use high radix long division to take advantage of the divide hardware
of the host computer. It looks brute force at first glance, but since
it is using the optimized arithmetic of the host processor, it is much
faster then implementing "fast" algorithms the hard way.
2008-05-27 11:54:39 -07:00
Stephen Williams 6987d16bd3 Optimize the %load/vp0 to use subarrays.
This instruction adds an integer value to the value being loaded. This
optimization uses subarrays instead of the += operator. This is faster
because the value is best loaded into the vector as a subarray anyhow.
2008-05-26 16:44:58 -07:00
Stephen Williams 5cc376ebd4 Optimize ADD and MUL instructions
Make better use of the CPU word in ADD and MUL instructions.
2008-05-26 16:00:16 -07:00
Stephen Williams 8190307dd3 Optimize/inline vvp_bit4_r AND, OR and vector set bit.
The AND and OR operators for vvp_bit4_t are slightly tweaked to be
lighter and inlinable.

The vvp_vector4_t::set_bit is optimized to do less silly mask fiddling.
2008-05-26 11:09:33 -07:00
Stephen Williams 3575f68c9f Merge branch 'master' into verilog-ams 2008-05-23 21:23:16 -07:00
Stephen Williams c1268d04fc Merge branch 'verilog-ams' of ssh://[email protected]/~steve-icarus/git/verilog into verilog-ams
Conflicts:

	ivl_target.h
	t-dll.h
2008-05-23 20:55:46 -07:00
Stephen Williams ca756f3ec3 Bring switch information out to the ivl_target API.
This involves defining the API for switches and cleaning up the
elaborated form to match the defined ivl_target API. Also add t-dll
code to support the ivl_switch_t functions, and add stub code that
checks the results.
2008-05-23 20:53:10 -07:00
Stephen Williams 9af459f95b Vectorize AND/OR/NAND/NOR/INV instructions when reasonable.
When processing wide vectors of these operations, it pays to process
them as vectors. This improves run-time performance. Have the run time
select vectorized or not based on the vector width.
2008-05-23 17:52:43 -07:00
Stephen Williams 492b240304 Optimize vvp_vector4 vector handling.
Improve vvp_vector4_t methods copy_bits and the part selecting constructor
to make better use of vector words. Eliminate bit-by-bit processing by
these methods to take advantage of host processor words.

Improve vthread_bits_to_vector to use these improved methods and Update
the %load/av and %set/v instructions to take advantage of these changes.
2008-05-23 14:30:32 -07:00
Stephen Williams d2106a3d3a Fix botched processing of MUX with constant select.
If the select input was constant, the code then tried to look at the
constant data input. Just plain wrong.
2008-05-23 10:29:44 -07:00
Stephen Williams cf2f4dd0af Merge branch 'master' of ssh://[email protected]/~steve-icarus/git/verilog 2008-05-22 20:36:18 -07:00
Cary R 608c2574bd Add $finish_and_return.
This new system task can be used to set the vvp return value
and finish the simulation.
2008-05-22 20:34:38 -07:00
Larry Doolittle f17db21bf0 Make sure stringify_flag is always initialized.
Put in one last initialization of stringify_flag,
that Cary missed in add84b153c
and Steve missed in 73dcace781.
Found the long, hard way.
2008-05-22 20:32:26 -07:00
Cary R b26bdd3c19 MinGW fixes (development)
The MinGW system() implementation appears to return the straight
return value instead of the waitpid() like result that more
normal systems return. Because of this just return the system()
result without processing for MinGW compilations.

Older version of the MinGW runtime (pre 3.14) just used the
underlying vsnprintf(). Which has some problems. The 3.14 version
has some nice improvements, but it has a sever bug when processing
"%*.*f", -1, -1, <some_real_value>.  Because of this we need to use
the underlying version without the enhancements for now.

snprintf prints %p differently than the other printf routines
so use _snprintf to get consistent results.

Only build the PDF files if both man and ps2pdf exist.

MinGW does not know about the z modifier for %d, %u, etc.

Add some missing Makefile check targets.
2008-05-22 20:24:21 -07:00
Larry Doolittle 6a9c5d8f7e Use standard for printing uint64_t
Ugly, but pedantically correct according to c99 7.8.1.
Maybe not as ugly as the compile-time warning it replaces.
2008-05-22 18:42:56 -07:00
Stephen Williams e59f28d659 work interrupted 2008-05-22 18:40:29 -07:00
Stephen Williams 07ae300e0c Rework %cmpi/u, %cmp/u and %ix/get for speed
These instructions can take advantage of the much optimized
vector_to_array function to do their arithmetic work quickly and
punt on X very quickly if needed. This helps some benchmarks.
2008-05-22 18:19:40 -07:00
Stephen Williams 4c5f24c7a7 Simplify MUXZ if the select is constant.
If the select of a MUXZ is constant 0 or 1, then we can elide the MUX
in place of a simple BUFZ. This should allow the dead code on the
unused side to be removed as well.
2008-05-21 10:25:44 -07:00
Stephen Williams be810c5ba6 Merge branch 'var-array-rework' 2008-05-21 07:01:07 -07:00
Stephen Williams 5ec3b590bf Clear up some poor pointer management.
The expression for a paramter value was not well managed, given that
the eval_expr() function replaces pointers. Clear things up a bit.
2008-05-20 20:36:41 -07:00
Stephen Williams 88313670c0 Clear up some poor pointer management.
The expression for a paramter value was not well managed, given that
the eval_expr() function replaces pointers. Clear things up a bit.
2008-05-20 20:32:42 -07:00
Stephen Williams f9f68236bc Make sure expressions of value_ranges are initialized. 2008-05-20 10:46:08 -07:00
Stephen Williams dadb3a68d3 Fix possible error choosing default discipline domain.
Recent gcc warns about code that turns out to be incorrect.
2008-05-20 10:41:24 -07:00
Larry Doolittle 6121c06f15 Reconcile autoconf.sh to new gperf usage
gperf command line changed in Makefile.in as of
commit cde87ed4a3
this patch propagates that change to autoconf.sh
2008-05-20 10:36:26 -07:00
Larry Doolittle b289d740e2 Drop two unused variables
eval_tree.cc:eval_tree()'s expr_msb and expr_lsb became unused after
commit c76e88cad5
which triggered warnings from gcc-4.3
2008-05-20 10:32:18 -07:00
Stephen Williams ec266ff52e Make sure expressions of value_ranges are initialized. 2008-05-19 21:55:53 -07:00
Stephen Williams ec773fe8cf Elaborate tran devices
The tran devices include tran, rtran, tranif0/1 and rtranif0/1. These
are all elaborated as options on a NetTran device. It is still not
clear the best way to present tran devices via the ivl_target.h API.
2008-05-19 21:42:52 -07:00
Cary R a412149e2c Don't let -I block -ivl!
When -I was added it was blocking -ivl since the string comparison
is case insensitive.
2008-05-19 18:32:09 -07:00
Larry Doolittle deb7b01717 Compatibility with gcc-4.3
Add include statements (<cstdlib> for abort()) and a cast.
Necessary and sufficient for successful compilation with
gcc-4.3 (Debian 4.3.0-4) 4.3.1 20080501 (prerelease)
2008-05-19 18:31:08 -07:00
Stephen Williams 6966c26f27 Merge branch 'master' into verilog-ams 2008-05-17 17:04:57 -07:00
Stephen Williams a5e3d06412 Skip value range processing for parameters with no value ranges.
Classing parameter declarations do not need value range processing,
and in fact it can get in the way.
2008-05-17 16:55:00 -07:00
Stephen Williams eb3dcc2786 Dump verinum value as decimal if possible, even if sized. 2008-05-17 16:26:32 -07:00
Stephen Williams c76e88cad5 Add support for explicit parameter types, including real.
Before this, the types of parameters were always logic, only the
width and signed-ness could be controlled. A parameter may take
on implicit real values if the expression were real.

With this patch, the type for the parameter can be explicitly set
to logic or real. This also means that the parameter real valued
expressions need to be more crefully treated, possibly with casting
integral expressions to real values, or real expressions to integral
values.
2008-05-17 16:25:58 -07:00
Stephen Williams f588656dd5 Merge branch 'master' into verilog-ams 2008-05-14 20:21:08 -07:00
Stephen Williams 35e48fb7b7 Merge branch 'master' into verilog-ams 2008-05-14 20:12:41 -07:00
Stephen Williams a069b6dbe1 Basic test of the range for logic/bool parameters.
If there is a value range for a logic/bool parameter, then test the
configured value with the range and report an error if the range is
out of bounds.
2008-05-13 21:56:57 -07:00
Stephen Williams 48f934abf7 Get parameter ranges as far as the netlist form.
The pform is now translated/elaborated into NetScope objects. All that
remains is to check the parameter values against the ranges. This is
to be done in the evaluate_parameters() method.
2008-05-13 21:22:52 -07:00
Stephen Williams 2172c8a503 Parse parameter value ranges into pform.
Handle parameter value ranges as far as the pform. The +-inf expressions
are not handled yet, nor is the single value exclude, but the other
cases are handled.
2008-05-12 21:26:38 -07:00
Stephen Williams cbf96d73ee Make semi-colon after discipline/nature name optional.
The VAMS-2.2 LRM syntax does not include a semicolon after the nature/
discipline name, but the 2.3 LRM does. Effectively, that means that
the simicolon is option from now on.
2008-05-12 17:31:59 -07:00
Stephen Williams 7166aea1d7 Attach natures to disciplines
Pform parse enough of the natures that they can be mapped and the
disciplines can bind to them. Since Verilog-AMS expects natures to
be declared before use, we can do the binding early.
2008-05-11 18:52:27 -07:00
Stephen Williams 93b400c4d7 Attach disciplines to wires
Allow discipline declaration of nets that attaches the discipline to
a new wire or a wire that is already declared.
2008-05-11 17:30:33 -07:00
Stephen Williams a506a18970 Nature and discipline declarations syntax
The VAMS-2.3 specification says that discipline and nature declarations
have a semi-colon after the identifier, but the disciplines.vams in
the appendix does not. Initial guess what that the disciplines.vams
is correct, but I've been told that the syntax is correct and the
disciplines.vams file is not.
2008-05-11 12:13:58 -07:00
Stephen Williams 5b273178f5 Parse disciplines and contribution statements
Parse discipline declarations, net discipline declarations, and
analog contribution statements. Don't yet do anything useful with
these, just give a sorry message where they are encountered.
2008-05-11 12:00:11 -07:00
Stephen Williams cde87ed4a3 Add disciplines.vams and enough syntax to parse it.
This is part of the standard disciplines header file, with enough
syntax to part the natures and disciplines included. Don't do anything
with the parse results yet.
2008-05-10 10:37:33 -07:00
123 changed files with 8162 additions and 3960 deletions
+33 -16
View File
@@ -16,9 +16,6 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.181 2007/05/24 04:07:11 steve Exp $"
#
#
SHELL = /bin/sh
# This version string is only used in the version message printed
@@ -51,6 +48,9 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
LEX = @LEX@
YACC = @YACC@
MAN = @MAN@
PS2PDF = @PS2PDF@
GIT = @GIT@
CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) @CPPFLAGS@
CXXFLAGS = -Wall @CXXFLAGS@
@@ -65,7 +65,7 @@ all: dep version.h ivl@EXEEXT@
# In the windows world, the installer will need a dosify program to
# dosify text files.
ifeq (@MING32@,yes)
ifeq (@MINGW32@,yes)
all: dep dosify.exe
dosify.exe: dosify.c
$(CC) -o dosify.exe dosify.c
@@ -99,15 +99,15 @@ distclean: clean
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o
FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o
O = main.o async.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o elab_expr.o \
elab_lval.o elab_net.o elab_pexpr.o elab_scope.o \
elab_sig.o emit.o eval.o eval_attrib.o \
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
load_module.o netlist.o netmisc.o net_assign.o \
net_design.o net_event.o net_expr.o net_force.o net_func.o \
net_link.o net_modulo.o net_nex_input.o net_nex_output.o \
net_proc.o net_scope.o net_udp.o pad_to_width.o \
parse.o parse_misc.o pform.o pform_dump.o pform_types.o \
net_proc.o net_scope.o net_tran.o net_udp.o pad_to_width.o \
parse.o parse_misc.o pform.o pform_disciplines.o pform_dump.o pform_types.o \
set_width.o symbol_search.o sync.o sys_funcs.o \
verinum.o verireal.o target.o targets.o \
Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o \
@@ -174,22 +174,28 @@ lexor.cc: $(srcdir)/lexor.lex
lexor_keyword.o: lexor_keyword.cc parse.h
lexor_keyword.cc: lexor_keyword.gperf
gperf -o -i 7 -C -k 1-3,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
gperf -o -i 7 -C -k 1-4,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
iverilog-vpi.ps: $(srcdir)/iverilog-vpi.man
man -t $(srcdir)/iverilog-vpi.man > iverilog-vpi.ps
$(MAN) -t $(srcdir)/iverilog-vpi.man > iverilog-vpi.ps
iverilog-vpi.pdf: iverilog-vpi.ps
ps2pdf iverilog-vpi.ps iverilog-vpi.pdf
$(PS2PDF) iverilog-vpi.ps iverilog-vpi.pdf
# For VERSION_TAG in driver/main.c, first try git-describe, then look for a
# version.h file in the source tree (included in snapshots and releases), and
# finally use nothing.
.PHONY: version.h
# "true" and "false" in the next few lines are Unix shell command names
ifeq ($(GIT),none)
GIT_PRESENT = false
else
GIT_PRESENT = true
endif
version.h:
@if test -d $(srcdir)/.git; then \
@if $(GIT_PRESENT) && test -d $(srcdir)/.git; then \
echo "Using git-describe for VERSION_TAG"; \
tmp=`git --git-dir $(srcdir)/.git describe \
tmp=`$(GIT) --git-dir $(srcdir)/.git describe \
| sed -e 's;\(.*\);#define VERSION_TAG "\1";'`; \
echo "$$tmp" | diff - $@ > /dev/null 2>&1 || echo "$$tmp" > $@ || exit 1; \
elif test -r $(srcdir)/$@; then \
@@ -200,10 +206,18 @@ version.h:
echo '#define VERSION_TAG ""' > $@; \
fi
ifeq (@MING32@,yes)
ifeq (@MINGW32@,yes)
ifeq ($(MAN),none)
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
else
ifeq ($(PS2PDF),none)
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
else
INSTALL_DOC = $(prefix)/iverilog-vpi.pdf $(mandir)/man1/iverilog-vpi.1
INSTALL_DOCDIR = $(mandir)/man1
all: dep iverilog-vpi.pdf
endif
endif
INSTALL_DOCDIR = $(mandir)/man1
else
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
INSTALL_DOCDIR = $(mandir)/man1
@@ -217,7 +231,7 @@ endif
XNF_INSTALL = $(libdir)/ivl/xnf.conf $(libdir)/ivl/xnf-s.conf
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/include/constants.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC)
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/include/constants.vams $(libdir)/ivl/include/disciplines.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC)
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
for dir in vpi ivlpp driver; \
do (cd $$dir ; $(MAKE) $@); done
@@ -231,6 +245,9 @@ $(libdir)/ivl/ivl@EXEEXT@: ./ivl@EXEEXT@
$(libdir)/ivl/include/constants.vams: $(srcdir)/constants.vams
$(INSTALL_DATA) $(srcdir)/constants.vams $@
$(libdir)/ivl/include/disciplines.vams: $(srcdir)/disciplines.vams
$(INSTALL_DATA) $(srcdir)/disciplines.vams $@
$(libdir)/ivl/xnf-s.conf: $(srcdir)/xnf-s.conf
$(INSTALL_DATA) $(srcdir)/xnf-s.conf $(DESTDIR)$(libdir)/ivl/xnf-s.conf
@@ -286,7 +303,7 @@ uninstall:
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
for dir in vpi ivlpp driver; \
do (cd $$dir ; $(MAKE) $@); done
for f in xnf.conf xnf-s.conf ivl@EXEEXT@ include/constants.vams; \
for f in xnf.conf xnf-s.conf ivl@EXEEXT@ include/constants.vams include/disciplines.vams; \
do rm -f $(DESTDIR)$(libdir)/ivl/$$f; done
-rmdir $(DESTDIR)$(libdir)/ivl/include
-rmdir $(DESTDIR)$(libdir)/ivl
+24 -6
View File
@@ -75,16 +75,35 @@ class Module : public PScope, public LineInfo {
NetNet::Type default_nettype;
struct range_t {
// True if this is an exclude
bool exclude_flag;
// lower bound
// If low_open_flag is false and low_expr=0, then use -inf
bool low_open_flag;
PExpr*low_expr;
// upper bound
// If high_open_flag is false and high_expr=0, then use +inf
bool high_open_flag;
PExpr*high_expr;
// Next range description in list
struct range_t*next;
};
/* The module has parameters that are evaluated when the
module is elaborated. During parsing, I put the parameters
into this map. */
struct param_expr_t {
PExpr*expr;
struct param_expr_t : public LineInfo {
param_expr_t() : type(IVL_VT_NO_TYPE), msb(0), lsb(0), signed_flag(false), expr(0), range(0) { }
// Type information
ivl_variable_type_t type;
PExpr*msb;
PExpr*lsb;
perm_string file;
unsigned lineno;
bool signed_flag;
// Value expression
PExpr*expr;
// If there are range constrants, list them here
range_t*range;
};
map<perm_string,param_expr_t>parameters;
map<perm_string,param_expr_t>localparams;
@@ -158,8 +177,7 @@ class Module : public PScope, public LineInfo {
map<perm_string,PFunction*> funcs_;
static void elaborate_parm_item_(perm_string name, const param_expr_t&cur,
Design*des, NetScope*scope,
perm_string file, unsigned lineno);
Design*des, NetScope*scope);
private: // Not implemented
Module(const Module&);
+17
View File
@@ -306,6 +306,11 @@ class PEIdent : public PExpr {
private:
// Common functions to calculate parts of part/bit selects.
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb) const;
NetExpr* calculate_up_do_base_(Design*, NetScope*) const;
bool calculate_param_range_(Design*, NetScope*,
const NetExpr*msb_ex, long&msb,
const NetExpr*lsb_ex, long&lsb) const;
bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const;
private:
@@ -321,6 +326,18 @@ class PEIdent : public PExpr {
NetScope*found,
const NetExpr*par_msb,
const NetExpr*par_lsb) const;
NetExpr*elaborate_expr_param_part_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found,
const NetExpr*par_msb,
const NetExpr*par_lsb) const;
NetExpr*elaborate_expr_param_idx_up_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found,
const NetExpr*par_msb,
const NetExpr*par_lsb) const;
NetExpr*elaborate_expr_net(Design*des,
NetScope*scope,
NetNet*net,
+11 -14
View File
@@ -30,7 +30,7 @@ PWire::PWire(perm_string n,
signed_(false), isint_(false),
port_msb_(0), port_lsb_(0), port_set_(false),
net_msb_(0), net_lsb_(0), net_set_(false), error_cnt_(0),
lidx_(0), ridx_(0)
lidx_(0), ridx_(0), discipline_(0)
{
if (t == NetNet::INTEGER) {
type_ = NetNet::REG;
@@ -135,19 +135,6 @@ bool PWire::get_isint() const
return isint_;
}
/*
* Since implicitly defined list of port declarations are no longer
* considered fully defined we no longer need this routine to force
* them to be fully defined.
*
void PWire::set_net_range()
{
net_msb_ = port_msb_;
net_lsb_ = port_lsb_;
net_set_ = true;
}
*/
void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
{
switch (type) {
@@ -211,3 +198,13 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
}
}
void PWire::set_discipline(discipline_t*d)
{
assert(discipline_ == 0);
discipline_ = d;
}
discipline_t* PWire::get_discipline(void) const
{
return discipline_;
}
+6 -1
View File
@@ -36,6 +36,7 @@ class ostream;
class PExpr;
class Design;
class discipline_t;
/*
* The different type of PWire::set_range() calls.
@@ -78,10 +79,12 @@ class PWire : public LineInfo {
ivl_variable_type_t get_data_type() const;
void set_range(PExpr*msb, PExpr*lsb, PWSRType type);
void set_net_range();
void set_memory_idx(PExpr*ldx, PExpr*rdx);
void set_discipline(discipline_t*);
discipline_t* get_discipline(void) const;
map<perm_string,PExpr*> attributes;
// Write myself to the specified stream.
@@ -112,6 +115,8 @@ class PWire : public LineInfo {
PExpr*lidx_;
PExpr*ridx_;
discipline_t*discipline_;
private: // not implemented
PWire(const PWire&);
PWire& operator= (const PWire&);
+1 -1
View File
@@ -16,4 +16,4 @@ do
done
echo "Precompiling lexor_keyword.gperf"
gperf -o -i 7 -C -k 1-3,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc
gperf -o -i 7 -C -k 1-4,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc
+2 -5
View File
@@ -16,12 +16,9 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.13 2007/02/06 05:07:31 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.0
VERSION = 0.9.devel
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -63,7 +60,7 @@ dep:
O = cadpli.o
SYSTEM_VPI_LDFLAGS = -L../vvp -lvpi
ifeq (@MING32@,yes)
ifeq (@MINGW32@,yes)
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
endif
+1
View File
@@ -86,6 +86,7 @@ extern bool debug_scopes;
extern bool debug_eval_tree;
extern bool debug_elaborate;
extern bool debug_synth2;
extern bool debug_optimizer;
/* Path to a directory useful for finding subcomponents. */
extern const char*basedir;
+3
View File
@@ -9,6 +9,9 @@ AC_PROG_CC
AC_PROG_CXX
AC_CHECK_TOOL(STRIP, strip, true)
AC_CHECK_PROGS(XGPERF,gperf,none)
AC_CHECK_PROGS(MAN,man,none)
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
AC_CHECK_PROGS(GIT,git,none)
if test "$XGPERF" = "none"
then
echo ""
+27
View File
@@ -23,6 +23,7 @@
# include "netlist.h"
# include "netmisc.h"
# include "functor.h"
# include "compiler.h"
# include "ivl_assert.h"
@@ -828,6 +829,32 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
count += 1;
return;
}
/* If the select input is constant, then replace with a BUFZ */
flag = obj->pin_Sel().nexus()->drivers_constant();
verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx;
if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) {
NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width());
tmp->set_line(*obj);
if (debug_optimizer)
cerr << obj->get_fileline() << ": debug: "
<< "Replace binary MUX with constant select=" << sel_val
<< " with a BUFZ to the selected input." << endl;
tmp->rise_time(obj->rise_time());
tmp->fall_time(obj->fall_time());
tmp->decay_time(obj->decay_time());
connect(tmp->pin(0), obj->pin_Result());
if (sel_val == verinum::V1)
connect(tmp->pin(1), obj->pin_Data(1));
else
connect(tmp->pin(1), obj->pin_Data(0));
delete obj;
des->add_node(tmp);
count += 1;
}
}
/*
+75 -9
View File
@@ -88,6 +88,34 @@ ostream& operator << (ostream&o, ivl_variable_type_t val)
return o;
}
ostream& operator << (ostream&o, ivl_switch_type_t val)
{
switch (val) {
case IVL_SW_TRAN:
o << "tran";
break;
case IVL_SW_TRANIF0:
o << "tranif0";
break;
case IVL_SW_TRANIF1:
o << "tranif1";
break;
case IVL_SW_RTRAN:
o << "rtran";
break;
case IVL_SW_RTRANIF0:
o << "rtranif0";
break;
case IVL_SW_RTRANIF1:
o << "rtranif1";
break;
case IVL_SW_TRAN_VP:
o << "tran(VP)";
break;
}
return o;
}
static inline void dump_scope_path(ostream&o, const NetScope*scope)
{
if (const NetScope*parent = scope->parent()) {
@@ -493,9 +521,6 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const
case PV:
pt = "PV";
break;
case BI:
pt = "BI";
break;
}
o << setw(ind) << "" << "NetPartSelect(" << pt << "): "
<< name();
@@ -611,6 +636,20 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const
o << setw(ind) << "" << "endtask" << endl;
}
void NetTran::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << type_ << " " << name()
<< " island " << island;
if (type_ == IVL_SW_TRAN_VP) {
o << " width=" << vector_width()
<< " part=" << part_width()
<< " offset=" << part_offset();
}
o << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetUDP::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "UDP (" << udp_name() << "): ";
@@ -966,8 +1005,37 @@ void NetScope::dump(ostream&o) const
o << "[" << *(*pp).second.msb
<< ":" << *(*pp).second.lsb << "] ";
o << (*pp).first << " = " <<
*(*pp).second.expr << ";" << endl;
o << (*pp).first << " = " << *(*pp).second.expr;
for (range_t*ran = (*pp).second.range ; ran ; ran = ran->next) {
if (ran->exclude_flag)
o << " exclude ";
else
o << " from ";
if (ran->low_open_flag)
o << "(";
else
o << "[";
if (ran->low_expr)
o << *ran->low_expr;
else if (ran->low_open_flag==false)
o << "-inf";
else
o << "<?>";
if (ran->high_expr)
o << ":" << *ran->high_expr;
else if (ran->high_open_flag==false)
o << ":inf";
else
o << ":<?>";
if (ran->high_open_flag)
o << ")";
else
o << "]";
}
o << ";" << endl;
}
for (pp = localparams.begin()
@@ -1261,11 +1329,9 @@ void NetESignal::dump(ostream&o) const
void NetEParam::dump(ostream&o) const
{
if (scope_ != 0)
o << "<" << scope_path(scope_) << "." << name_ << ">";
else if (name_)
o << "<" << name_ << ">";
o << "<" << scope_path(scope_) << "." << (*reference_).first << ">";
else
o << "<" "???" ">";
o << "<" << (*reference_).first << ">";
}
void NetETernary::dump(ostream&o) const
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2008 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "discipline.h"
nature_t::nature_t(perm_string name, perm_string access)
: name_(name), access_(access)
{
}
nature_t::~nature_t()
{
}
discipline_t::discipline_t(perm_string name, ddomain_t domain,
nature_t*pot, nature_t*flow)
: name_(name), domain_(domain), potential_(pot), flow_(flow)
{
}
discipline_t::~discipline_t()
{
}
+75
View File
@@ -0,0 +1,75 @@
#ifndef __discipline_H
#define __discipline_H
/*
* Copyright (c) 2008 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/*
* The discipline types include the discipline, nature and other
* related types for managing declared and used disciplines in a
* Verilog-AMS program.
*/
# include "StringHeap.h"
# include <iostream>
# include <map>
# include "LineInfo.h"
typedef enum { DD_NONE, DD_DISCRETE, DD_CONTINUOUS } ddomain_t;
extern std::ostream& operator << (std::ostream&, ddomain_t);
class nature_t : public LineInfo {
public:
explicit nature_t(perm_string name, perm_string access);
~nature_t();
perm_string name() const { return name_; }
// Identifier for the access function for this nature
perm_string access() const { return access_; }
private:
perm_string name_;
perm_string access_;
};
class discipline_t : public LineInfo {
public:
explicit discipline_t (perm_string name, ddomain_t dom,
nature_t*pot, nature_t*flow);
~discipline_t();
perm_string name() const { return name_; }
ddomain_t domain() const { return domain_; }
const nature_t*potential() const { return potential_; }
const nature_t*flow() const { return flow_; }
private:
perm_string name_;
ddomain_t domain_;
nature_t*potential_;
nature_t*flow_;
private: // not implemented
discipline_t(const discipline_t&);
discipline_t& operator = (const discipline_t&);
};
extern map<perm_string,nature_t*> natures;
extern map<perm_string,discipline_t*> disciplines;
#endif
+72
View File
@@ -0,0 +1,72 @@
// Standard definitions for Verilog-AMS
`ifdef DISCIPLINES_VAMS
`else
`define DISCIPLINES_VAMS 1
discipline \logic ;
domain discrete;
enddiscipline
discipline ddiscrete;
domain discrete;
enddiscipline
nature Current;
units = "A";
access = I;
idt_nature = Charge;
`ifdef CURRENT_ABSTOL
abstol = `CURRENT_ABSTOL
`else
abstol = 1e-12;
`endif
endnature
nature Charge;
units = "coul";
access = Q;
ddt_nature = Current;
`ifdef CHARGE_ABSTOL
abstol = `CHARGE_ABSTOL;
`else
abstol = 1e-14;
`endif
endnature
nature Voltage;
units = "V";
access = V;
idt_nature = Flux;
`ifdef VOLTAGE_ABSTOL
abstol = `VOLTAGE_ABSTOL;
`else
abstol = 1e-6;
`endif
endnature
nature Flux;
units = "Wb";
access = Phi;
ddt_nature = Voltage;
`ifdef FLUX_ABSTOL
abstol = `flux_ABSTOL;
`else
abstol = 1e-9;
`endif
endnature
discipline electrical;
potential Voltage;
flow Current;
enddiscipline
discipline voltage;
potential Voltage;
enddiscipline
discipline current;
flow Current;
enddiscipline
`endif // !`ifdef DISCIPLINES_VAMS
+3 -4
View File
@@ -16,12 +16,9 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.7.2.1 2006/10/04 17:08:59 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.8.3
VERSION = 0.9.devel
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -48,6 +45,8 @@ LDFLAGS = @LDFLAGS@
all: iverilog-vpi@EXEEXT@
check: all
clean:
rm -f *.o config.h
rm -f iverilog-vpi@EXEEXT@
+8 -8
View File
@@ -336,6 +336,14 @@ static int parse(int argc, char *argv[])
assignn(&gstr.pOUT, argv[idx],
strlen(argv[idx])-strlen(dot_o_ext));
}
/* Check for the -mingw option */
else if (startsWith(mingw_option, argv[idx]))
assignn(&gstr.pMINGW, argv[idx]+sizeof(mingw_option)-1,
strlen(argv[idx])-(sizeof(mingw_option)-1));
/* Check for the -ivl option */
else if (startsWith(ivl_option, argv[idx]))
assignn(&gstr.pIVL, argv[idx]+sizeof(ivl_option)-1,
strlen(argv[idx])-(sizeof(ivl_option)-1));
/* Check for the --name option */
else if (startsWith(name_option, argv[idx])) {
assignn(&gstr.pOUT, argv[idx]+sizeof(name_option)-1,
@@ -356,14 +364,6 @@ static int parse(int argc, char *argv[])
append(&gstr.pDEFS, " ");
append(&gstr.pDEFS, argv[idx]);
}
/* Check for the -mingw option */
else if (startsWith(mingw_option, argv[idx]))
assignn(&gstr.pMINGW, argv[idx]+sizeof(mingw_option)-1,
strlen(argv[idx])-(sizeof(mingw_option)-1));
/* Check for the -ivl option */
else if (startsWith(ivl_option, argv[idx]))
assignn(&gstr.pIVL, argv[idx]+sizeof(ivl_option)-1,
strlen(argv[idx])-(sizeof(ivl_option)-1));
/* Check for the --cflags option */
else if (stricmp("--cflags", argv[idx]) == 0) {
setup_ivl_environment();
+14 -7
View File
@@ -16,9 +16,6 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.26 2007/02/06 05:07:31 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.9.devel
@@ -41,6 +38,8 @@ CC = @CC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
MAN = @MAN@
PS2PDF = @PS2PDF@
CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@
CFLAGS = -Wall @CFLAGS@
@@ -76,15 +75,23 @@ cflexor.o: cflexor.c cfparse.h cfparse_misc.h globals.h
cfparse.o: cfparse.c globals.h cfparse_misc.h
iverilog.ps: $(srcdir)/iverilog.man
man -t $(srcdir)/iverilog.man > iverilog.ps
$(MAN) -t $(srcdir)/iverilog.man > iverilog.ps
iverilog.pdf: iverilog.ps
ps2pdf iverilog.ps iverilog.pdf
$(PS2PDF) iverilog.ps iverilog.pdf
ifeq (@MING32@,yes)
ifeq (@MINGW32@,yes)
ifeq ($(MAN),none)
INSTALL_DOC = $(mandir)/man1/iverilog.1
else
ifeq ($(PS2PDF),none)
INSTALL_DOC = $(mandir)/man1/iverilog.1
else
INSTALL_DOC = $(prefix)/iverilog.pdf $(mandir)/man1/iverilog.1
INSTALL_DOCDIR = $(mandir)/man1
all: iverilog.pdf
endif
endif
INSTALL_DOCDIR = $(mandir)/man1
else
INSTALL_DOC = $(mandir)/man1/iverilog.1
INSTALL_DOCDIR = $(mandir)/man1
+4
View File
@@ -327,6 +327,9 @@ static int t_default(char*cmd, unsigned ncmd)
remove(defines_path);
remove(compiled_defines_path);
}
#ifdef __MINGW32__ /* MinGW just returns the exit status, so return it! */
return rc;
#else
if (rc != 0) {
if (rc == 127) {
@@ -342,6 +345,7 @@ static int t_default(char*cmd, unsigned ncmd)
}
return 0;
#endif
}
+263 -105
View File
@@ -716,6 +716,15 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
des->errors += 1;
}
if (!rep->value().is_defined()) {
cerr << get_fileline() << ": error: Concatenation repeat "
<< "may not be undefined (" << rep->value()
<< ")." << endl;
des->errors += 1;
concat_depth -= 1;
return 0;
}
if (rep->value().is_negative()) {
cerr << get_fileline() << ": error: Concatenation repeat "
<< "may not be negative (" << rep->value().as_long()
@@ -873,6 +882,51 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope,
return flag;
}
/*
* When we know that this is an indexed part select (up or down) this
* method calculates the up/down base, as far at it can be calculated.
*/
NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope) const
{
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.lsb != 0);
ivl_assert(*this, index_tail.msb != 0);
NetExpr*tmp = elab_and_eval(des, scope, index_tail.msb, -1);
return tmp;
}
bool PEIdent::calculate_param_range_(Design*des, NetScope*scope,
const NetExpr*par_msb, long&par_msv,
const NetExpr*par_lsb, long&par_lsv) const
{
if (par_msb == 0) {
// If the parameter doesn't have an explicit range, then
// just return range values of 0:0. The par_msv==0 is
// correct. The par_msv is not necessarily correct, but
// clients of this function don't need a correct value.
ivl_assert(*this, par_lsb == 0);
par_msv = 0;
par_lsv = 0;
return true;
}
const NetEConst*tmp = dynamic_cast<const NetEConst*> (par_msb);
ivl_assert(*this, tmp);
par_msv = tmp->value().as_long();
tmp = dynamic_cast<const NetEConst*> (par_lsb);
ivl_assert(*this, tmp);
par_lsv = tmp->value().as_long();
return true;
}
unsigned PEIdent::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
bool&unsized_flag) const
@@ -1085,6 +1139,131 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
static verinum param_part_select_bits(const verinum&par_val, long wid,
long lsv, long par_lsv)
{
verinum result (verinum::Vx, wid, true);
for (long idx = 0 ; idx < wid ; idx += 1) {
long off = idx + lsv - par_lsv;
if (off < 0)
result.set(idx, verinum::Vx);
else if (off < (long)par_val.len())
result.set(idx, par_val.get(off));
else if (par_val.is_string()) // Pad strings with nulls.
result.set(idx, verinum::V0);
else if (par_val.has_len()) // Pad sized parameters with X
result.set(idx, verinum::Vx);
else // Unsized parameters are "infinite" width.
result.set(idx, sign_bit(par_val));
}
// If the input is a string, and the part select is working on
// byte boundaries, then make the result into a string.
if (par_val.is_string() && (labs(lsv-par_lsv)%8 == 0) && (wid%8 == 0))
return result.as_string();
return result;
}
NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb) const
{
long msv, lsv;
bool flag = calculate_parts_(des, scope, msv, lsv);
if (!flag)
return 0;
long par_msv, par_lsv;
flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
if (!flag)
return 0;
// Notice that the par_msv is not used is this function other
// then for this test. It is used to tell the direction that
// the bits are numbers, so that we can make sure the
// direction matches the part select direction. After that,
// we only need the par_lsv.
if (msv>lsv && par_msv<par_lsv || msv<lsv && par_msv>=par_lsv) {
cerr << get_fileline() << ": error: Part select "
<< "[" << msv << ":" << lsv << "] is out of order." << endl;
des->errors += 1;
return 0;
}
long wid = 1 + labs(msv-lsv);
if (debug_elaborate)
cerr << get_fileline() << ": debug: Calculate part select "
<< "[" << msv << ":" << lsv << "] from range "
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
ivl_assert(*this, par_ex);
verinum result = param_part_select_bits(par_ex->value(), wid, lsv, par_lsv);
NetEConst*result_ex = new NetEConst(result);
result_ex->set_line(*this);
return result_ex;
}
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb) const
{
long par_msv, par_lsv;
bool flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
if (!flag)
return 0;
NetExpr*base = calculate_up_do_base_(des, scope);
if (base == 0)
return 0;
unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid);
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
ivl_assert(*this, par_ex);
if (debug_elaborate)
cerr << get_fileline() << ": debug: Calculate part select "
<< "[" << *base << "+:" << wid << "] from range "
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
// Handle the special case that the base is constant. In this
// case, just precalculate the entire constant result.
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
long lsv = base_c->value().as_long();
// Watch out for reversed bit numbering. We're making
// the part select from LSB to MSB.
if (par_msv < par_lsv)
lsv = lsv - wid + 1;
verinum result = param_part_select_bits(par_ex->value(), wid,
lsv, par_lsv);
NetEConst*result_ex = new NetEConst(result);
result_ex->set_line(*this);
return result_ex;
}
if ((par_msb < par_lsb) && (wid>1))
base = make_add_expr(base, 1-(long)wid);
NetExpr*tmp = par->dup_expr();
tmp = new NetESelect(tmp, base, wid);
tmp->set_line(*this);
return tmp;
}
/*
* Handle the case that the identifier is a parameter reference. The
* parameter expression has already been located for us (as the par
@@ -1097,84 +1276,29 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
const NetExpr*par_msb,
const NetExpr*par_lsb) const
{
NetExpr*tmp = par->dup_expr();
const name_component_t&name_tail = path_.back();
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;
if (use_sel == index_component_t::SEL_PART) {
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb);
ivl_assert(*this, index_tail.lsb);
// NOTE TO SELF: This is the way I want to see this code
// structured. This closely follows the structure of the
// elaborate_expr_net_ code, which splits all the various
// selects to different methods.
if (use_sel == index_component_t::SEL_PART)
return elaborate_expr_param_part_(des, scope, par, found_in,
par_msb, par_lsb);
/* If the identifier has a part select, we support
it by pulling the right bits out and making a
sized unsigned constant. This code assumes the
lsb of a parameter is 0 and the msb is the
width of the parameter. */
if (use_sel == index_component_t::SEL_IDX_UP)
return elaborate_expr_param_idx_up_(des, scope, par, found_in,
par_msb, par_lsb);
verinum*lsn = index_tail.lsb->eval_const(des, scope);
verinum*msn = index_tail.msb->eval_const(des, scope);
if ((lsn == 0) || (msn == 0)) {
cerr << get_fileline() << ": error: "
"Part select expressions must be "
"constant expressions." << endl;
des->errors += 1;
return 0;
}
// NOTE TO SELF (continued): The code below should be
// rewritten in the above format, as I get to it.
long lsb = lsn->as_long();
long msb = msn->as_long();
if ((lsb < 0) || (msb < lsb)) {
cerr << get_fileline() << ": error: invalid part "
<< "select: " << path_
<< "["<<msb<<":"<<lsb<<"]" << endl;
des->errors += 1;
return 0;
}
unsigned long ulsb=lsb;
unsigned long umsb=msb;
NetExpr*tmp = par->dup_expr();
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
assert(le);
verinum result (verinum::V0, msb-lsb+1, true);
verinum exl = le->value();
/* Pull the bits from the parameter, one at a
time. If the bit is within the range, simply
copy it to the result. If the bit is outside
the range, we sign extend signed unsized
numbers, zero extend unsigned unsigned numbers,
and X extend sized numbers. */
for (unsigned long idx = ulsb ; idx <= umsb ; idx += 1) {
if (idx < exl.len())
result.set(idx-lsb, exl.get(idx));
else if (exl.is_string())
result.set(idx-lsb, verinum::V0);
else if (exl.has_len())
result.set(idx-lsb, verinum::Vx);
else if (exl.has_sign())
result.set(idx-lsb, exl.get(exl.len()-1));
else
result.set(idx-lsb, verinum::V0);
}
/* If the input is a string, and the part select
is working on byte boundaries, then the result
can be made into a string. */
if (exl.is_string()
&& (lsb%8 == 0)
&& (result.len()%8 == 0))
result = verinum(result.as_string());
delete tmp;
tmp = new NetEConst(result);
} else if (use_sel == index_component_t::SEL_IDX_UP || use_sel == index_component_t::SEL_IDX_DO) {
if (use_sel == index_component_t::SEL_IDX_DO) {
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
@@ -1361,8 +1485,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
// Special case: The index is out of range, so the value
// of this expression is a 'bx vector the width of a word.
if (!net->array_index_is_valid(addr)) {
verinum xxx (verinum::Vx, net->vector_width());
NetEConst*resx = new NetEConst(xxx);
NetEConst*resx = make_const_x(net->vector_width());
resx->set_line(*this);
delete word_index;
return resx;
@@ -1428,16 +1551,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
negative values. However, the width that they represent is
unsigned. Remember that any order is possible,
i.e., [1:0], [-4:6], etc. */
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
if (wid > net->vector_width()) {
cerr << get_fileline() << ": error: part select ["
<< msv << ":" << lsv << "] out of range." << endl;
des->errors += 1;
//delete lsn;
//delete msn;
return net;
}
ivl_assert(*this, wid <= net->vector_width());
unsigned long wid = 1 + labs(msv-lsv);
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
cerr << get_fileline() << ": error: part select ["
@@ -1448,27 +1562,79 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
return net;
}
if (net->sig()->sb_to_idx(msv) >= (signed) net->vector_width()) {
cerr << get_fileline() << ": error: part select ["
<< msv << ":" << lsv << "] out of range." << endl;
des->errors += 1;
//delete lsn;
//delete msn;
return net;
}
long sb_lsb = net->sig()->sb_to_idx(lsv);
long sb_msb = net->sig()->sb_to_idx(msv);
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
if (sb_lsb == 0 && wid == net->vector_width())
return net;
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this);
// If the part select covers NONE of the vector, then return a
// constant X.
return ss;
if ((sb_lsb >= (signed) net->vector_width()) || (sb_msb < 0)) {
NetEConst*tmp = make_const_x(wid);
tmp->set_line(*this);
return tmp;
}
// If the part select is entirely within the vector, then make
// a simple part select.
if (sb_lsb >= 0 && sb_msb < (signed)net->vector_width()) {
NetExpr*ex = new NetEConst(verinum(sb_lsb));
NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this);
return ss;
}
// Now the hard stuff. The part select is falling off at least
// one end. We're going to need a NetEConcat to mix the
// selection with overrun.
NetEConst*bot = 0;
if (sb_lsb < 0) {
bot = make_const_x( 0-sb_lsb );
bot->set_line(*this);
sb_lsb = 0;
}
NetEConst*top = 0;
if (sb_msb >= (signed)net->vector_width()) {
top = make_const_x( 1+sb_msb-net->vector_width() );
top->set_line(*this);
sb_msb = net->vector_width()-1;
}
unsigned concat_count = 1;
if (bot) concat_count += 1;
if (top) concat_count += 1;
NetEConcat*concat = new NetEConcat(concat_count);
concat->set_line(*this);
if (bot) {
concat_count -= 1;
concat->set(concat_count, bot);
}
if (sb_lsb == 0 && sb_msb+1 == (signed)net->vector_width()) {
concat_count -= 1;
concat->set(concat_count, net);
} else {
NetExpr*ex = new NetEConst(verinum(sb_lsb));
ex->set_line(*this);
NetESelect*ss = new NetESelect(net, ex, 1+sb_msb-sb_lsb);
ss->set_line(*this);
concat_count -= 1;
concat->set(concat_count, ss);
}
if (top) {
concat_count -= 1;
concat->set(concat_count, top);
}
ivl_assert(*this, concat_count==0);
return concat;
}
/*
@@ -1477,14 +1643,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
NetESignal*net, NetScope*found_in) const
{
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.lsb != 0);
ivl_assert(*this, index_tail.msb != 0);
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
NetExpr*base = calculate_up_do_base_(des, scope);
unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid);
@@ -1609,8 +1768,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
/* The bit select is out of range of the
vector. This is legal, but returns a
constant 1'bx value. */
verinum x (verinum::Vx);
NetEConst*tmp = new NetEConst(x);
NetEConst*tmp = make_const_x(1);
tmp->set_line(*this);
cerr << get_fileline() << ": warning: Bit select ["
+69 -31
View File
@@ -1578,6 +1578,14 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
return 0;
}
if (!erep->value().is_defined()) {
cerr << get_fileline() << ": error: Concatenation repeat "
<< "may not be undefined (" << erep->value()
<< ")." << endl;
des->errors += 1;
return 0;
}
if (erep->value().is_negative()) {
cerr << get_fileline() << ": error: Concatenation repeat "
<< "may not be negative (" << erep->value().as_long()
@@ -2367,30 +2375,53 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
osig->local_flag(true);
osig->set_line(*this);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Generating part selects "
<< "to connect input l-value to subexpressions."
<< endl;
if (bidirectional_flag) {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Generating tran(VP) "
<< "to connect input l-value to subexpressions."
<< endl;
}
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
unsigned wid = nets[idx]->vector_width();
unsigned off = width - wid;
NetTran*ps = new NetTran(scope, scope->local_symbol(),
osig->vector_width(), wid, off);
des->add_node(ps);
ps->set_line(*this);
connect(ps->pin(0), osig->pin(0));
connect(ps->pin(1), nets[idx]->pin(0));
ivl_assert(*this, wid <= width);
width -= wid;
}
} else {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Generating part selects "
<< "to connect input l-value to subexpressions."
<< endl;
}
NetPartSelect::dir_t part_dir = NetPartSelect::VP;
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
unsigned wid = nets[idx]->vector_width();
unsigned off = width - wid;
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
des->add_node(ps);
ps->set_line(*this);
connect(ps->pin(1), osig->pin(0));
connect(ps->pin(0), nets[idx]->pin(0));
assert(wid <= width);
width -= wid;
}
assert(width == 0);
}
NetPartSelect::dir_t part_dir = bidirectional_flag
? NetPartSelect::BI
: NetPartSelect::VP;
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
unsigned wid = nets[idx]->vector_width();
unsigned off = width - wid;
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
des->add_node(ps);
connect(ps->pin(1), osig->pin(0));
connect(ps->pin(0), nets[idx]->pin(0));
assert(wid <= width);
width -= wid;
}
assert(width == 0);
osig->data_type(nets[0]->data_type());
osig->local_flag(true);
return osig;
@@ -2743,11 +2774,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
/* If we are processing a tran or inout, then the
partselect is bi-directional. Otherwise, it is a
Part-to-Vector select. */
NetPartSelect::dir_t part_dir;
if (bidirectional_flag)
part_dir = NetPartSelect::BI;
else
part_dir = NetPartSelect::PV;
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
@@ -2764,11 +2790,23 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
subsig->local_flag(true);
subsig->set_line(*this);
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
part_dir);
des->add_node(sub);
connect(sub->pin(0), subsig->pin(0));
if (bidirectional_flag) {
// Make a tran(VP)
NetTran*sub = new NetTran(scope, scope->local_symbol(),
sig->vector_width(),
subnet_wid, lidx);
sub->set_line(*this);
des->add_node(sub);
connect(sub->pin(0), sig->pin(0));
connect(sub->pin(1), subsig->pin(0));
} else {
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
NetPartSelect::PV);
des->add_node(sub);
sub->set_line(*this);
connect(sub->pin(0), subsig->pin(0));
}
sig = subsig;
}
+49 -15
View File
@@ -22,6 +22,7 @@
# include "netmisc.h"
# include <cstring>
# include <iostream>
# include <cstdlib>
# include <stdio.h>
/*
@@ -43,10 +44,10 @@
# include "util.h"
# include <typeinfo>
# include <assert.h>
# include "ivl_assert.h"
void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
Design*des, NetScope*scope,
perm_string file, unsigned lineno)
Design*des, NetScope*scope)
{
PExpr*ex = cur.expr;
assert(ex);
@@ -63,9 +64,11 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
parameter value is coerced to have the correct
and defined width. */
if (cur.msb) {
assert(cur.lsb);
msb = cur.msb ->elaborate_pexpr(des, scope);
assert(msb);
lsb = cur.lsb ->elaborate_pexpr(des, scope);
assert(lsb);
}
if (signed_flag) {
@@ -81,8 +84,41 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
signed_flag = val->has_sign();
}
val = scope->set_parameter(name, val,
msb, lsb, signed_flag, file, lineno);
NetScope::range_t*range_list = 0;
for (Module::range_t*range = cur.range ; range ; range = range->next) {
NetScope::range_t*tmp = new NetScope::range_t;
tmp->exclude_flag = range->exclude_flag;
tmp->low_open_flag = range->low_open_flag;
tmp->high_open_flag = range->high_open_flag;
if (range->low_expr) {
tmp->low_expr = elab_and_eval(des, scope, range->low_expr, -1);
ivl_assert(*range->low_expr, tmp->low_expr);
} else {
tmp->low_expr = 0;
}
if (range->high_expr && range->high_expr==range->low_expr) {
// Detect the special case of a "point"
// range. These are called out by setting the high
// and low expression ranges to the same
// expression. The exclude_flags should be false
// in this case
ivl_assert(*range->high_expr, tmp->low_open_flag==false && tmp->high_open_flag==false);
tmp->high_expr = tmp->low_expr;
} else if (range->high_expr) {
tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1);
ivl_assert(*range->high_expr, tmp->high_expr);
} else {
tmp->high_expr = 0;
}
tmp->next = range_list;
range_list = tmp;
}
val = scope->set_parameter(name, val, cur.type, msb, lsb, signed_flag, range_list, cur);
assert(val);
delete val;
}
@@ -120,8 +156,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
tmp->set_line(*((*cur).second.expr));
tmp->cast_signed( (*cur).second.signed_flag );
scope->set_parameter((*cur).first, tmp, 0, 0, false,
(*cur).second.file, (*cur).second.lineno);
scope->set_parameter((*cur).first, tmp, (*cur).second.type,
0, 0, false, 0, (*cur).second);
}
for (mparm_it_t cur = localparams.begin()
@@ -132,8 +168,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
if ((*cur).second.msb)
tmp->cast_signed( (*cur).second.signed_flag );
scope->set_parameter((*cur).first, tmp, 0, 0, false,
(*cur).second.file, (*cur).second.lineno);
scope->set_parameter((*cur).first, tmp, (*cur).second.type,
0, 0, false, 0, (*cur).second);
}
@@ -145,8 +181,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
for (mparm_it_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
elaborate_parm_item_((*cur).first, (*cur).second, des, scope,
(*cur).second.file, (*cur).second.lineno);
elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
}
/* run parameter replacements that were collected from the
@@ -166,6 +201,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
<< "Replace " << (*cur).first
<< " with expression " << *val
<< " from " << val->get_fileline() << "." << endl;
cerr << get_fileline() << ": : "
<< "Type=" << val->expr_type() << endl;
}
bool flag = scope->replace_parameter((*cur).first, val);
if (! flag) {
@@ -178,8 +215,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
for (mparm_it_t cur = localparams.begin()
; cur != localparams.end() ; cur ++) {
elaborate_parm_item_((*cur).first, (*cur).second, des, scope,
(*cur).second.file, (*cur).second.lineno);
elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
}
// Run through the defparams for this module, elaborate the
@@ -421,9 +457,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
genvar_verinum);
// The file and line information should really come
// from the genvar statement, not the for loop.
scope->set_localparam(loop_index, gp, get_file(),
get_lineno());
scope->set_localparam(loop_index, gp, *this);
if (debug_scopes)
cerr << get_fileline() << ": debug: "
<< "Create implicit localparam "
+101 -15
View File
@@ -419,7 +419,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
}
/* Allocate all the netlist nodes for the gates. */
NetLogic**cur = new NetLogic*[count];
NetNode**cur = new NetNode*[count];
assert(cur);
/* Calculate the gate delays from the delay expressions
@@ -659,6 +659,67 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::XOR, instance_width);
break;
case TRAN:
if (pin_count() != 2) {
cerr << get_fileline() << ": error: Pin count for "
<< "tran device." << endl;
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, IVL_SW_TRAN);
}
break;
case RTRAN:
if (pin_count() != 2) {
cerr << get_fileline() << ": error: Pin count for "
<< "rtran device." << endl;
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRAN);
return;
}
break;
case TRANIF0:
if (pin_count() != 3) {
cerr << get_fileline() << ": error: Pin count for "
<< "tranif0 device." << endl;
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF0);
}
break;
case RTRANIF0:
if (pin_count() != 3) {
cerr << get_fileline() << ": error: Pin count for "
<< "rtranif0 device." << endl;
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF0);
}
break;
case TRANIF1:
if (pin_count() != 3) {
cerr << get_fileline() << ": error: Pin count for "
<< "tranif1 device." << endl;
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF1);
}
break;
case RTRANIF1:
if (pin_count() != 3) {
cerr << get_fileline() << ": error: Pin count for "
<< "rtranif1 device." << endl;
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF1);
}
break;
default:
cerr << get_fileline() << ": internal error: unhandled "
"gate type." << endl;
@@ -670,13 +731,18 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
cur[idx]->attribute(attrib_list[adx].key,
attrib_list[adx].val);
cur[idx]->rise_time(rise_time);
cur[idx]->fall_time(fall_time);
cur[idx]->decay_time(decay_time);
/* The logic devices have some uniform processing. Then
all may have output delays and output drive strength. */
if (NetLogic*log = dynamic_cast<NetLogic*> (cur[idx])) {
log->rise_time(rise_time);
log->fall_time(fall_time);
log->decay_time(decay_time);
cur[idx]->pin(0).drive0(drive_type(strength0()));
cur[idx]->pin(0).drive1(drive_type(strength1()));
log->pin(0).drive0(drive_type(strength0()));
log->pin(0).drive1(drive_type(strength1()));
}
cur[idx]->set_line(*this);
des->add_node(cur[idx]);
}
@@ -798,6 +864,9 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
}
}
// "cur" is an array of pointers, and we don't need it any more.
delete[]cur;
}
NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
@@ -812,6 +881,31 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
tmp->local_flag(true);
tmp->set_line(*sig);
// Handle the special case of a bi-directional part
// select. Create a NetTran(VP) instead of a uni-directional
// NetPartSelect node.
if (dir == NetNet::PINOUT) {
unsigned wida = sig->vector_width();
unsigned widb = tmp->vector_width();
bool part_b = widb < wida;
NetTran*node = new NetTran(scope, scope->local_symbol(),
part_b? wida : widb,
part_b? widb : wida,
0);
if (part_b) {
connect(node->pin(0), sig->pin(0));
connect(node->pin(1), tmp->pin(0));
} else {
connect(node->pin(0), tmp->pin(0));
connect(node->pin(1), sig->pin(0));
}
node->set_line(*this);
des->add_node(node);
return tmp;
}
NetPartSelect*node = 0;
switch (dir) {
@@ -840,15 +934,7 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
break;
case NetNet::PINOUT:
if (sig->vector_width() > tmp->vector_width()) {
node = new NetPartSelect(sig, 0, tmp->vector_width(),
NetPartSelect::BI);
connect(node->pin(0), tmp->pin(0));
} else {
node = new NetPartSelect(tmp, 0, sig->vector_width(),
NetPartSelect::BI);
connect(node->pin(0), sig->pin(0));
}
ivl_assert(*this, 0);
break;
default:
+5
View File
@@ -165,6 +165,11 @@ bool NetUserFunc::emit_node(struct target_t*tgt) const
return tgt->net_function(this);
}
bool NetTran::emit_node(struct target_t*tgt) const
{
return tgt->tran(this);
}
bool NetBUFZ::emit_node(struct target_t*tgt) const
{
return tgt->bufz(this);
+12 -20
View File
@@ -1171,17 +1171,9 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
}
assert(scope_);
const NetExpr*expr_msb;
const NetExpr*expr_lsb;
const NetExpr*expr = scope_->get_parameter(name_, expr_msb, expr_lsb);
if (expr == 0) {
cerr << get_fileline() << ": internal error: Unable to match "
<< "parameter " << name_ << " in scope "
<< scope_path(scope_) << endl;
return 0;
}
assert(expr);
perm_string name = (*reference_).first;
const NetExpr*expr = (*reference_).second.expr;
ivl_assert(*this, expr);
NetExpr*nexpr = expr->dup_expr();
assert(nexpr);
@@ -1190,7 +1182,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
// return the constant value.
if (NetEConst*tmp = dynamic_cast<NetEConst*>(nexpr)) {
verinum val = tmp->value();
NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val);
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
ptmp->set_line(*this);
delete nexpr;
return ptmp;
@@ -1198,7 +1190,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
if (NetECReal*tmp = dynamic_cast<NetECReal*>(nexpr)) {
verireal val = tmp->value();
NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val);
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
ptmp->set_line(*this);
delete nexpr;
return ptmp;
@@ -1209,7 +1201,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
NetExpr*res = nexpr->eval_tree();
if (res == 0) {
cerr << get_fileline() << ": internal error: Unable to evaluate "
<< "parameter " << name_ << " expression: "
<< "parameter " << name << " expression: "
<< *nexpr << endl;
delete nexpr;
return 0;
@@ -1217,10 +1209,10 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
// The result can be saved as the value of the parameter for
// future reference, and return a copy to the caller.
bool flag = scope_->replace_parameter(name_, res);
bool flag = scope_->replace_parameter(name, res);
if (!flag) {
cerr << get_fileline() << ": internal error: Could not "
<< "replace parameter expression for " << name_ << endl;
<< "replace parameter expression for " << name << endl;
return 0;
}
@@ -1234,7 +1226,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
{ NetEConst*tmp = dynamic_cast<NetEConst*>(res);
if (tmp == 0) {
cerr << get_fileline() << ": internal error: parameter "
<< name_ << " evaluates to incomprehensible "
<< name << " evaluates to incomprehensible "
<< *res << "." << endl;
return 0;
}
@@ -1242,7 +1234,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
assert(tmp);
verinum val = tmp->value();
NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val);
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
return ptmp;
}
@@ -1251,7 +1243,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
{ NetECReal*tmp = dynamic_cast<NetECReal*>(res);
if (tmp == 0) {
cerr << get_fileline() << ": internal error: parameter "
<< name_ << " evaluates to incomprehensible "
<< name << " evaluates to incomprehensible "
<< *res << "." << endl;
return 0;
}
@@ -1259,7 +1251,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
assert(tmp);
verireal val = tmp->value();
NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val);
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
return ptmp;
}
+19
View File
@@ -53,6 +53,9 @@ ivl_file_table_index
ivl_file_table_item
ivl_file_table_size
ivl_island_flag_set
ivl_island_flag_test
ivl_logic_attr
ivl_logic_attr_cnt
ivl_logic_attr_val
@@ -115,6 +118,7 @@ ivl_nexus_ptr_pin
ivl_nexus_ptr_lpm
ivl_nexus_ptr_log
ivl_nexus_ptr_sig
ivl_nexus_ptr_switch
ivl_parameter_basename
ivl_parameter_expr
@@ -152,6 +156,8 @@ ivl_scope_port
ivl_scope_ports
ivl_scope_sigs
ivl_scope_sig
ivl_scope_switch
ivl_scope_switches
ivl_scope_time_precision
ivl_scope_time_units
ivl_scope_type
@@ -216,6 +222,19 @@ ivl_stmt_parm_count
ivl_stmt_rval
ivl_stmt_sub_stmt
ivl_switch_a
ivl_switch_b
ivl_switch_basename
ivl_switch_enable
ivl_switch_file
ivl_switch_island
ivl_switch_lineno
ivl_switch_offset
ivl_switch_part
ivl_switch_scope
ivl_switch_type
ivl_switch_width
ivl_udp_init
ivl_udp_name
ivl_udp_nin
+84 -1
View File
@@ -80,6 +80,13 @@ _BEGIN_DECL
* processes. Structural expressions are instead treated as logic
* gates.
*
* ivl_island_t
* Certain types of objects may belong to islands. The island that
* they belong to is represented by the ivl_island_t cookie. To
* know if object belong to the same island, it is sufficient to
* compare island cookies. If a==b, then island a is the same as
* island b.
*
* ivl_lpm_t
* This object is the base class for all the various LPM type
* device nodes. This object carries a few base properties
@@ -123,6 +130,9 @@ _BEGIN_DECL
* ivl_process_t object holds one of these, but a statement may in
* turn contain other statements.
*
* ivl_switch_t
* Switches are the tran/tranif devices in the design.
*
* -- A Note About Bit Sets --
* Some objects hold a value as an array of bits. In these cases there
* is some method that retrieves the width of the value and another
@@ -143,6 +153,7 @@ typedef struct ivl_delaypath_s*ivl_delaypath_t;
typedef struct ivl_design_s *ivl_design_t;
typedef struct ivl_event_s *ivl_event_t;
typedef struct ivl_expr_s *ivl_expr_t;
typedef struct ivl_island_s *ivl_island_t;
typedef struct ivl_lpm_s *ivl_lpm_t;
typedef struct ivl_lval_s *ivl_lval_t;
typedef struct ivl_net_const_s*ivl_net_const_t;
@@ -155,6 +166,7 @@ typedef struct ivl_parameter_s*ivl_parameter_t;
typedef struct ivl_process_s *ivl_process_t;
typedef struct ivl_scope_s *ivl_scope_t;
typedef struct ivl_signal_s *ivl_signal_t;
typedef struct ivl_switch_s *ivl_switch_t;
typedef struct ivl_memory_s *ivl_memory_t; /* DEPRECATED */
typedef struct ivl_statement_s*ivl_statement_t;
@@ -226,6 +238,17 @@ typedef enum ivl_logic_e {
IVL_LO_UDP = 21
} ivl_logic_t;
/* This is the type of a ivl_switch_t object */
typedef enum ivl_switch_type_e {
IVL_SW_TRAN = 0,
IVL_SW_TRANIF0 = 1,
IVL_SW_TRANIF1 = 2,
IVL_SW_RTRAN = 3,
IVL_SW_RTRANIF0 = 4,
IVL_SW_RTRANIF1 = 5,
IVL_SW_TRAN_VP = 6
} ivl_switch_type_t;
/* This is the type of an LPM object. */
typedef enum ivl_lpm_type_e {
IVL_LPM_ABS = 32,
@@ -243,7 +266,7 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_MOD = 13,
IVL_LPM_MULT = 4,
IVL_LPM_MUX = 5,
IVL_LPM_PART_BI= 28, /* part select: bi-directional (part on 0) */
/* IVL_LPM_PART_BI= 28, / obsolete */
IVL_LPM_PART_VP= 15, /* part select: vector to part */
IVL_LPM_PART_PV= 17, /* part select: part written to vector */
IVL_LPM_POW = 31,
@@ -699,6 +722,16 @@ extern unsigned ivl_file_table_index(const char *);
extern unsigned ivl_file_table_size(void);
/* ISLAND
*
* ivl_island_flag_set
* ivl_island_flag_test
* Allow the user to test or set a boolean flag associated with the
* island.
*/
extern int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value);
extern int ivl_island_flag_test(ivl_island_t net, unsigned flag);
/* LOGIC
* These types and functions support manipulation of logic gates. The
* ivl_logic_t enumeration identifies the various kinds of gates that
@@ -1313,6 +1346,7 @@ extern unsigned ivl_nexus_ptr_pin(ivl_nexus_ptr_t net);
extern ivl_net_const_t ivl_nexus_ptr_con(ivl_nexus_ptr_t net);
extern ivl_net_logic_t ivl_nexus_ptr_log(ivl_nexus_ptr_t net);
extern ivl_lpm_t ivl_nexus_ptr_lpm(ivl_nexus_ptr_t net);
extern ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net);
extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net);
/* PARAMETER
@@ -1501,6 +1535,8 @@ extern unsigned ivl_scope_ports(ivl_scope_t net);
extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx);
extern unsigned ivl_scope_sigs(ivl_scope_t net);
extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx);
extern unsigned ivl_scope_switches(ivl_scope_t net);
extern ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx);
extern ivl_scope_type_t ivl_scope_type(ivl_scope_t net);
extern const char* ivl_scope_tname(ivl_scope_t net);
extern int ivl_scope_time_precision(ivl_scope_t net);
@@ -1826,6 +1862,53 @@ extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net);
IVL_ST_WAIT, IVL_ST_WHILE */
extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
/* SWITCHES
*
* The switches represent the tran devices in the design.
*
* FUNCTION SUMMARY
*
* ivl_switch_type
* Return the enumerated value that is the type of the switch.
*
* ivl_switch_basename
* This is the name given to the device in the source code.
*
* ivl_switch_a
* ivl_switch_b
* The a and b ports are the two ports of the switch.
*
* ivl_switch_enable
* If the device has an enable (tranifX) then this is the enable
* port.
*
* SEMANTIC NOTES
* The a/b ports can be any type, but the types must exactly
* match, including vector widths. The enable must be a scalar.
*
* The IVL_SW_TRAN_VP is an exception to the above. In this case,
* the B side may be a different size, and the a side will have a
* a fixed width. The unused bits are padded to Z on the A side.
*/
extern ivl_switch_type_t ivl_switch_type(ivl_switch_t net);
extern ivl_scope_t ivl_switch_scope(ivl_switch_t net);
extern const char*ivl_switch_basename(ivl_switch_t net);
extern ivl_nexus_t ivl_switch_a(ivl_switch_t net);
extern ivl_nexus_t ivl_switch_b(ivl_switch_t net);
extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net);
extern ivl_island_t ivl_switch_island(ivl_switch_t net);
/* These are only support for IVL_SW_TRAN_VP switches. */
extern unsigned ivl_switch_width(ivl_switch_t net);
extern unsigned ivl_switch_part(ivl_switch_t net);
extern unsigned ivl_switch_offset(ivl_switch_t net);
/* Not implemented yet
extern unsigned ivl_switch_attr_cnt(ivl_switch_t net);
extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx);
*** */
extern const char* ivl_switch_file(ivl_switch_t net);
extern unsigned ivl_switch_lineno(ivl_switch_t net);
#if defined(__MINGW32__) || defined (__CYGWIN32__)
# define DLLEXPORT __declspec(dllexport)
+44
View File
@@ -0,0 +1,44 @@
#ifndef __ivl_target_priv_H
#define __ivl_target_H
/*
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include <inttypes.h>
/*
* This deader has declarations related to the ivl_target.h API that
* are not to be exported outside of the core via the ivl_target.h
* interface.
*/
/*
* Information about islands. Connected branches within a net are
* collected into islands. Branches that are purely ddiscrete do not
* have disciplines and do not belong to islands.
*/
class discipline_t;
struct ivl_island_s {
discipline_t*discipline;
// user accessible flags. They are initially false, always.
vector<bool> flags;
};
#endif
+5
View File
@@ -1616,7 +1616,11 @@ static int load_next_input()
static void do_dump_precompiled_defines(FILE* out, struct define_t* table)
{
if (!table->keyword)
#ifdef __MINGW32__ /* MinGW does not know about z. */
fprintf(out, "%s:%d:%d:%s\n", table->name, table->argc, strlen(table->value), table->value);
#else
fprintf(out, "%s:%d:%zd:%s\n", table->name, table->argc, strlen(table->value), table->value);
#endif
if (table->left)
do_dump_precompiled_defines(out, table->left);
@@ -1741,6 +1745,7 @@ void reset_lexor(FILE* out, char* paths[])
isp->ebs = 0;
isp->next = 0;
isp->lineno = 0;
isp->stringify_flag = 0;
if (tail)
tail->next = isp;
+14
View File
@@ -34,6 +34,7 @@
# include <ctype.h>
# include <string.h>
# include "lexor_keyword.h"
# include "discipline.h"
# include <list>
# define YY_USER_INIT reset_lexor();
@@ -152,6 +153,7 @@ S [afpnumkKMGT]
"->" { return K_TRIGGER; }
"+:" { return K_PO_POS; }
"-:" { return K_PO_NEG; }
"<+" { return K_CONTRIBUTE; }
/* Watch out for the tricky case of (*). Cannot parse this as "(*"
and ")", but since I know that this is really ( * ), replace it
@@ -230,6 +232,18 @@ S [afpnumkKMGT]
break;
}
/* If this identifier names a discipline, then return this as
a DISCIPLINE_IDENTIFIER and return the discipline as the
value instead. */
if (rc == IDENTIFIER && gn_verilog_ams_flag) {
perm_string tmp = lex_strings.make(yylval.text);
map<perm_string,discipline_t*>::iterator cur = disciplines.find(tmp);
if (cur != disciplines.end()) {
yylval.discipline = (*cur).second;
rc = DISCIPLINE_IDENTIFIER;
}
}
return rc;
}
+20
View File
@@ -12,9 +12,12 @@
struct lexor_keyword { const char*name; int mask; int tokenType; };
%%
abs, GN_KEYWORDS_VAMS_2_3, K_abs
abstol, GN_KEYWORDS_VAMS_2_3, K_abstol
access, GN_KEYWORDS_VAMS_2_3, K_access
acos, GN_KEYWORDS_VAMS_2_3, K_acos
acosh, GN_KEYWORDS_VAMS_2_3, K_acosh
always, GN_KEYWORDS_1364_1995, K_always
analog, GN_KEYWORDS_VAMS_2_3, K_analog
and, GN_KEYWORDS_1364_1995, K_and
asin, GN_KEYWORDS_VAMS_2_3, K_asin
asinh, GN_KEYWORDS_VAMS_2_3, K_asinh
@@ -32,38 +35,51 @@ casex, GN_KEYWORDS_1364_1995, K_casex
casez, GN_KEYWORDS_1364_1995, K_casez
ceil, GN_KEYWORDS_VAMS_2_3, K_ceil
cmos, GN_KEYWORDS_1364_1995, K_cmos
continuous, GN_KEYWORDS_VAMS_2_3, K_continuous
cos, GN_KEYWORDS_VAMS_2_3, K_cos
cosh, GN_KEYWORDS_VAMS_2_3, K_cosh
ddt_nature, GN_KEYWORDS_VAMS_2_3, K_ddt_nature
deassign, GN_KEYWORDS_1364_1995, K_deassign
default, GN_KEYWORDS_1364_1995, K_default
defparam, GN_KEYWORDS_1364_1995, K_defparam
disable, GN_KEYWORDS_1364_1995, K_disable
discipline, GN_KEYWORDS_VAMS_2_3, K_discipline
discrete, GN_KEYWORDS_VAMS_2_3, K_discrete
domain, GN_KEYWORDS_VAMS_2_3, K_domain
edge, GN_KEYWORDS_1364_1995, K_edge
else, GN_KEYWORDS_1364_1995, K_else
end, GN_KEYWORDS_1364_1995, K_end
endcase, GN_KEYWORDS_1364_1995, K_endcase
enddiscipline, GN_KEYWORDS_VAMS_2_3, K_enddiscipline
endfunction, GN_KEYWORDS_1364_1995, K_endfunction
endgenerate, GN_KEYWORDS_1364_1995, K_endgenerate
endmodule, GN_KEYWORDS_1364_1995, K_endmodule
endnature, GN_KEYWORDS_VAMS_2_3, K_endnature
endprimitive, GN_KEYWORDS_1364_1995, K_endprimitive
endspecify, GN_KEYWORDS_1364_1995, K_endspecify
endtable, GN_KEYWORDS_1364_1995, K_endtable
endtask, GN_KEYWORDS_1364_1995, K_endtask
event, GN_KEYWORDS_1364_1995, K_event
exclude, GN_KEYWORDS_VAMS_2_3, K_exclude
exp, GN_KEYWORDS_VAMS_2_3, K_exp
floor, GN_KEYWORDS_VAMS_2_3, K_floor
flow, GN_KEYWORDS_VAMS_2_3, K_flow
for, GN_KEYWORDS_1364_1995, K_for
force, GN_KEYWORDS_1364_1995, K_force
forever, GN_KEYWORDS_1364_1995, K_forever
fork, GN_KEYWORDS_1364_1995, K_fork
from, GN_KEYWORDS_VAMS_2_3, K_from
function, GN_KEYWORDS_1364_1995, K_function
generate, GN_KEYWORDS_1364_2001, K_generate
genvar, GN_KEYWORDS_1364_2001, K_genvar
ground, GN_KEYWORDS_VAMS_2_3, K_ground
highz0, GN_KEYWORDS_1364_1995, K_highz0
highz1, GN_KEYWORDS_1364_1995, K_highz1
hypot, GN_KEYWORDS_VAMS_2_3, K_hypot
idt_nature, GN_KEYWORDS_VAMS_2_3, K_idt_nature
if, GN_KEYWORDS_1364_1995, K_if
ifnone, GN_KEYWORDS_1364_1995, K_ifnone
inf, GN_KEYWORDS_VAMS_2_3, K_inf
initial, GN_KEYWORDS_1364_1995, K_initial
inout, GN_KEYWORDS_1364_1995, K_inout
input, GN_KEYWORDS_1364_1995, K_input
@@ -80,6 +96,7 @@ medium, GN_KEYWORDS_1364_1995, K_medium
min, GN_KEYWORDS_VAMS_2_3, K_min
module, GN_KEYWORDS_1364_1995, K_module
nand, GN_KEYWORDS_1364_1995, K_nand
nature, GN_KEYWORDS_VAMS_2_3, K_nature
negedge, GN_KEYWORDS_1364_1995, K_negedge
nmos, GN_KEYWORDS_1364_1995, K_nmos
nor, GN_KEYWORDS_1364_1995, K_nor
@@ -91,6 +108,7 @@ output, GN_KEYWORDS_1364_1995, K_output
parameter, GN_KEYWORDS_1364_1995, K_parameter
pmos, GN_KEYWORDS_1364_1995, K_pmos
posedge, GN_KEYWORDS_1364_1995, K_posedge
potential, GN_KEYWORDS_VAMS_2_3, K_potential
pow, GN_KEYWORDS_VAMS_2_3, K_pow
primitive, GN_KEYWORDS_1364_1995, K_primitive
pull0, GN_KEYWORDS_1364_1995, K_pull0
@@ -116,6 +134,7 @@ small, GN_KEYWORDS_1364_1995, K_small
specify, GN_KEYWORDS_1364_1995, K_specify
specparam, GN_KEYWORDS_1364_1995, K_specparam
sqrt, GN_KEYWORDS_VAMS_2_3, K_sqrt
string, GN_KEYWORDS_VAMS_2_3, K_string
strong0, GN_KEYWORDS_1364_1995, K_strong0
strong1, GN_KEYWORDS_1364_1995, K_strong1
supply0, GN_KEYWORDS_1364_1995, K_supply0
@@ -134,6 +153,7 @@ tri1, GN_KEYWORDS_1364_1995, K_tri1
triand, GN_KEYWORDS_1364_1995, K_triand
trior, GN_KEYWORDS_1364_1995, K_trior
trireg, GN_KEYWORDS_1364_1995, K_trireg
units, GN_KEYWORDS_VAMS_2_3, K_units
vectored, GN_KEYWORDS_1364_1995, K_vectored
wait, GN_KEYWORDS_1364_1995, K_wait
wand, GN_KEYWORDS_1364_1995, K_wand
+21
View File
@@ -57,6 +57,7 @@ const char NOTICE[] =
# include "netlist.h"
# include "target.h"
# include "compiler.h"
# include "discipline.h"
#if defined(__MINGW32__) && !defined(HAVE_GETOPT_H)
extern "C" int getopt(int argc, char*argv[], const char*fmt);
@@ -123,6 +124,8 @@ bool debug_scopes = false;
bool debug_eval_tree = false;
bool debug_elaborate = false;
bool debug_synth2 = false;
bool debug_optimizer = false;
/*
* Verbose messages enabled.
*/
@@ -390,6 +393,9 @@ static void read_iconfig_file(const char*ipath)
} else if (strcmp(cp,"synth2") == 0) {
debug_synth2 = true;
cerr << "debug: Enable synth2 debug" << endl;
} else if (strcmp(cp,"optimizer") == 0) {
debug_optimizer = true;
cerr << "debug: Enable optimizer debug" << endl;
} else {
}
@@ -683,6 +689,16 @@ int main(int argc, char*argv[])
if (pf_path) {
ofstream out (pf_path);
out << "PFORM DUMP NATURES:" << endl;
for (map<perm_string,nature_t*>::iterator cur = natures.begin()
; cur != natures.end() ; cur ++ ) {
pform_dump(out, (*cur).second);
}
out << "PFORM DUMP DISCIPLINES:" << endl;
for (map<perm_string,discipline_t*>::iterator cur = disciplines.begin()
; cur != disciplines.end() ; cur ++ ) {
pform_dump(out, (*cur).second);
}
out << "PFORM DUMP MODULES:" << endl;
for (map<perm_string,Module*>::iterator mod = pform_modules.begin()
; mod != pform_modules.end()
@@ -809,6 +825,11 @@ int main(int argc, char*argv[])
func(des);
}
if (verbose_flag) {
cout << "CALCULATING ISLANDS" << endl;
}
des->join_islands();
if (net_path) {
if (verbose_flag)
cerr<<" dumping netlist to " <<net_path<< "..." <<endl;
+283 -148
View File
@@ -20,6 +20,7 @@
# include "config.h"
# include <iostream>
# include <cstdlib>
/*
* This source file contains all the implementations of the Design
@@ -31,6 +32,7 @@
# include "compiler.h"
# include "netmisc.h"
# include <sstream>
# include "ivl_assert.h"
Design:: Design()
: errors(0), nodes_(0), procs_(0), lcounter_(0)
@@ -242,6 +244,260 @@ void Design::evaluate_parameters()
(*scope)->evaluate_parameters(this);
}
void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
{
long msb = 0;
long lsb = 0;
bool range_flag = false;
/* Evaluate the msb expression, if it is present. */
if ((*cur).second.msb) {
eval_expr((*cur).second.msb);
if (! eval_as_long(msb, (*cur).second.msb)) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate msb expression "
<< "for parameter " << (*cur).first << ": "
<< *(*cur).second.msb << endl;
des->errors += 1;
return;
}
range_flag = true;
}
/* Evaluate the lsb expression, if it is present. */
if ((*cur).second.lsb) {
eval_expr((*cur).second.lsb);
if (! eval_as_long(lsb, (*cur).second.lsb)) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate lsb expression "
<< "for parameter " << (*cur).first << ": "
<< *(*cur).second.lsb << endl;
des->errors += 1;
return;
}
range_flag = true;
}
/* Evaluate the parameter expression, if necessary. */
NetExpr*expr = (*cur).second.expr;
assert(expr);
eval_expr(expr);
/* The eval_expr may delete any replace the expr pointer, so the
second.expr value cannot be relied on. Might as well replace
it now with the expression that we evaluated. */
(*cur).second.expr = expr;
switch (expr->expr_type()) {
case IVL_VT_REAL:
if (! dynamic_cast<const NetECReal*>(expr)) {
cerr << expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate real parameter value: "
<< *expr << endl;
des->errors += 1;
return;
}
break;
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
if (! dynamic_cast<const NetEConst*>(expr)) {
cerr << expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate parameter "
<< (*cur).first
<< " value: " << *expr << endl;
des->errors += 1;
return;
}
break;
default:
cerr << expr->get_fileline()
<< ": internal error: "
<< "unhandled expression type?" << endl;
des->errors += 1;
return;
}
/* If the parameter has range information, then make
sure the value is set right. Note that if the
parameter doesn't have an explicit range, then it
will get the signedness from the expression itself. */
if (range_flag) {
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
wid += 1;
NetEConst*val = dynamic_cast<NetEConst*>(expr);
assert(val);
verinum value = val->value();
if (! (value.has_len()
&& (value.len() == wid)
&& (value.has_sign() == (*cur).second.signed_flag))) {
verinum tmp (value, wid);
tmp.has_sign ( (*cur).second.signed_flag );
delete val;
val = new NetEConst(tmp);
expr = val;
}
}
// If there are no value ranges to test the value against,
// then we are done.
if ((*cur).second.range == 0) {
return;
}
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr);
ivl_assert(*(*cur).second.expr, (*cur).second.expr);
ivl_assert(*(*cur).second.expr, val);
verinum value = val->value();
bool from_flag = (*cur).second.range == 0? true : false;
for (range_t*value_range = (*cur).second.range
; value_range ; value_range = value_range->next) {
// If we already know that the value is
// within a "from" range, then do not test
// any more of the from ranges.
if (from_flag && value_range->exclude_flag==false)
continue;
if (value_range->low_expr) {
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->low_expr);
ivl_assert(*value_range->low_expr, tmp);
if (value_range->low_open_flag && value <= tmp->value())
continue;
else if (value < tmp->value())
continue;
}
if (value_range->high_expr) {
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->high_expr);
ivl_assert(*value_range->high_expr, tmp);
if (value_range->high_open_flag && value >= tmp->value())
continue;
else if (value > tmp->value())
continue;
}
// Within the range. If this is a "from"
// range, then set the from_flag and continue.
if (value_range->exclude_flag == false) {
from_flag = true;
continue;
}
// OH NO! In an excluded range. signal an error.
from_flag = false;
break;
}
// If we found no from range that contains the
// value, then report an error.
if (! from_flag) {
cerr << val->get_fileline() << ": error: "
<< "Parameter value " << value
<< " is out of range for parameter " << (*cur).first
<< "." << endl;
des->errors += 1;
}
}
void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
{
NetExpr*expr = (*cur).second.expr;
assert(expr);
NetECReal*res = 0;
eval_expr(expr);
switch (expr->expr_type()) {
case IVL_VT_REAL:
if (NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
res = tmp;
} else {
ivl_assert(*expr, 0);
}
break;
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
verireal val (tmp->value().as_long());
res = new NetECReal(val);
res->set_line(*tmp);
} else {
ivl_assert(*expr, 0);
}
break;
default:
ivl_assert(*expr, 0);
break;
}
(*cur).second.expr = res;
double value = res->value().as_double();
bool from_flag = (*cur).second.range == 0? true : false;
for (range_t*value_range = (*cur).second.range
; value_range ; value_range = value_range->next) {
if (from_flag && value_range->exclude_flag==false)
continue;
if (value_range->low_expr) {
double tmp;
bool flag = eval_as_double(tmp, value_range->low_expr);
ivl_assert(*value_range->low_expr, flag);
if (value_range->low_open_flag && value <= tmp)
continue;
else if (value < tmp)
continue;
}
if (value_range->high_expr) {
double tmp;
bool flag = eval_as_double(tmp, value_range->high_expr);
ivl_assert(*value_range->high_expr, flag);
if (value_range->high_open_flag && value >= tmp)
continue;
else if (value > tmp)
continue;
}
if (value_range->exclude_flag == false) {
from_flag = true;
continue;
}
// All the above tests failed, so we must have tripped
// an exclude rule.
from_flag = false;
break;
}
if (! from_flag) {
cerr << res->get_fileline() << ": error: "
<< "Parameter value " << value
<< " is out of range for parameter " << (*cur).first
<< "." << endl;
des->errors += 1;
}
}
void NetScope::evaluate_parameters(Design*des)
{
NetScope*cur = sub_;
@@ -256,161 +512,29 @@ void NetScope::evaluate_parameters(Design*des)
// scanning code. Now the parameter expression can be fully
// evaluated, or it cannot be evaluated at all.
typedef map<perm_string,param_expr_t>::iterator mparm_it_t;
for (mparm_it_t cur = parameters.begin()
for (param_ref_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
long msb = 0;
long lsb = 0;
bool range_flag = false;
NetExpr*expr;
/* Evaluate the msb expression, if it is present. */
expr = (*cur).second.msb;
if (expr) {
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
if (! tmp) {
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate msb expression "
<< "for parameter " << (*cur).first << ": "
<< *expr << endl;
des->errors += 1;
continue;
}
assert(nexpr);
delete expr;
(*cur).second.msb = nexpr;
tmp = dynamic_cast<NetEConst*>(nexpr);
}
assert(tmp);
msb = tmp->value().as_long();
range_flag = true;
}
/* Evaluate the lsb expression, if it is present. */
expr = (*cur).second.lsb;
if (expr) {
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
if (! tmp) {
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate lsb expression "
<< "for parameter " << (*cur).first << ": "
<< *expr << endl;
des->errors += 1;
continue;
}
assert(nexpr);
delete expr;
(*cur).second.lsb = nexpr;
tmp = dynamic_cast<NetEConst*>(nexpr);
}
assert(tmp);
lsb = tmp->value().as_long();
assert(range_flag);
}
/* Evaluate the parameter expression, if necessary. */
expr = (*cur).second.expr;
assert(expr);
switch (expr->expr_type()) {
case IVL_VT_REAL:
if (! dynamic_cast<const NetECReal*>(expr)) {
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate real parameter value: "
<< *expr << endl;
des->errors += 1;
continue;
}
assert(nexpr);
delete expr;
(*cur).second.expr = nexpr;
}
switch ((*cur).second.type) {
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
evaluate_parameter_logic_(des, cur);
break;
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
if (! dynamic_cast<const NetEConst*>(expr)) {
// Try to evaluate the expression.
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate parameter "
<< (*cur).first
<< " value: " <<
*expr << endl;
des->errors += 1;
continue;
}
// The evaluate worked, replace the old
// expression with this constant value.
assert(nexpr);
delete expr;
(*cur).second.expr = nexpr;
}
case IVL_VT_REAL:
evaluate_parameter_real_(des, cur);
break;
default:
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unhandled expression type?" << endl;
des->errors += 1;
continue;
}
/* If the parameter has range information, then make
sure the value is set right. Note that if the
parameter doesn't have an explicit range, then it
will get the signedness from the expression itself. */
if (range_flag) {
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
wid += 1;
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr);
assert(val);
verinum value = val->value();
if (! (value.has_len()
&& (value.len() == wid)
&& (value.has_sign() == (*cur).second.signed_flag))) {
verinum tmp (value, wid);
tmp.has_sign ( (*cur).second.signed_flag );
delete val;
val = new NetEConst(tmp);
(*cur).second.expr = val;
}
cerr << (*cur).second.get_fileline() << ": internal error: "
<< "Unexpected expression type " << (*cur).second.type
<< "." << endl;
cerr << (*cur).second.get_fileline() << ": : "
<< "Parameter name: " << (*cur).first << endl;
cerr << (*cur).second.get_fileline() << ": : "
<< "Expression is: " << *(*cur).second.expr << endl;
ivl_assert((*cur).second, 0);
break;
}
}
@@ -553,3 +677,14 @@ void Design::delete_process(NetProcTop*top)
delete top;
}
void Design::join_islands(void)
{
if (nodes_ == 0)
return;
NetNode*cur = nodes_->node_next_;
do {
join_island(cur);
cur = cur->node_next_;
} while (cur != nodes_->node_next_);
}
+12 -2
View File
@@ -476,7 +476,12 @@ NetEParam::NetEParam()
}
NetEParam::NetEParam(Design*d, NetScope*s, perm_string n)
: des_(d), scope_(s), name_(n)
: des_(d), scope_(s), reference_(scope_->find_parameter(n))
{
}
NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref)
: des_(d), scope_(s), reference_(ref)
{
}
@@ -489,9 +494,14 @@ bool NetEParam::has_width() const
return false;
}
ivl_variable_type_t NetEParam::expr_type() const
{
return (*reference_).second.type;
}
NetEParam* NetEParam::dup_expr() const
{
NetEParam*tmp = new NetEParam(des_, scope_, name_);
NetEParam*tmp = new NetEParam(des_, scope_, reference_);
tmp->set_line(*this);
return tmp;
}
+28 -6
View File
@@ -22,7 +22,9 @@
# include "netlist.h"
# include <cstring>
# include <cstdlib>
# include <sstream>
# include "ivl_assert.h"
/*
* The NetScope class keeps a scope tree organized. Each node of the
@@ -104,17 +106,24 @@ void NetScope::set_line(perm_string file, perm_string def_file,
}
NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
ivl_variable_type_t type,
NetExpr*msb, NetExpr*lsb, bool signed_flag,
perm_string file, unsigned lineno)
NetScope::range_t*range_list,
const LineInfo&file_line)
{
param_expr_t&ref = parameters[key];
NetExpr* res = ref.expr;
ref.expr = expr;
ref.type = type;
ref.msb = msb;
ref.lsb = lsb;
ref.signed_flag = signed_flag;
ref.file = file;
ref.lineno = lineno;
ivl_assert(file_line, ref.range == 0);
ref.range = range_list;
ref.set_line(file_line);
ivl_assert(file_line, type != IVL_VT_NO_TYPE);
return res;
}
@@ -160,7 +169,7 @@ bool NetScope::replace_parameter(perm_string key, NetExpr*expr)
* used to add a genver to the local parameter list.
*/
NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr,
perm_string file, unsigned lineno)
const LineInfo&file_line)
{
param_expr_t&ref = localparams[key];
NetExpr* res = ref.expr;
@@ -168,8 +177,7 @@ NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr,
ref.msb = 0;
ref.lsb = 0;
ref.signed_flag = false;
ref.file = file;
ref.lineno = lineno;
ref.set_line(file_line);
return res;
}
@@ -202,6 +210,20 @@ const NetExpr* NetScope::get_parameter(const char* key,
return 0;
}
map<perm_string,NetScope::param_expr_t>::iterator NetScope::find_parameter(perm_string key)
{
map<perm_string,param_expr_t>::iterator idx;
idx = parameters.find(key);
if (idx != parameters.end())
return idx;
idx = localparams.find(perm_string::literal(key));
if (idx != localparams.end())
return idx;
return (map<perm_string,param_expr_t>::iterator) 0;
}
NetScope::TYPE NetScope::type() const
{
+160
View File
@@ -0,0 +1,160 @@
/*
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include <iostream>
# include <typeinfo>
# include <cstdlib>
# include "compiler.h"
# include "netlist.h"
# include "netmisc.h"
# include "ivl_target_priv.h"
# include "ivl_assert.h"
static bool has_enable(ivl_switch_type_t tt)
{
switch (tt) {
case IVL_SW_TRANIF0:
case IVL_SW_TRANIF1:
case IVL_SW_RTRANIF0:
case IVL_SW_RTRANIF1:
return true;
default:
return false;
}
}
NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt)
: NetNode(scope, n, has_enable(tt)? 3 : 2), type_(tt)
{
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
if (pin_count() == 3) {
pin(2).set_dir(Link::INPUT);
pin(2).set_name(perm_string::literal("E"), 0);
}
}
NetTran::NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off)
: NetNode(scope, n, 2), type_(IVL_SW_TRAN_VP), wid_(wid), part_(part), off_(off)
{
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
}
NetTran::~NetTran()
{
}
unsigned NetTran::vector_width() const
{
return wid_;
}
unsigned NetTran::part_width() const
{
return part_;
}
unsigned NetTran::part_offset() const
{
return off_;
}
void join_island(NetObj*obj)
{
IslandBranch*branch = dynamic_cast<IslandBranch*> (obj);
// If this is not even a branch, then stop now.
if (branch == 0)
return;
// If this is a branch, but already given to an island, then
// stop.
if (branch->island)
return;
list<NetObj*> uncommitted_neighbors;
// Look for neighboring objects that might already be in
// islands. If we find something, then join that island.
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
Nexus*nex = obj->pin(idx).nexus();
for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) {
unsigned pin;
NetObj*tmp;
cur->cur_link(tmp, pin);
// Skip self.
if (tmp == obj)
continue;
// If tmb is not a branch, then skip it.
IslandBranch*tmp_branch = dynamic_cast<IslandBranch*> (tmp);
if (tmp_branch == 0)
continue;
// If that is an uncommitted branch, then save
// it. When I finally choose an island for self,
// these branches will be scanned so tha they join
// this island as well.
if (tmp_branch->island == 0) {
uncommitted_neighbors.push_back(tmp);
continue;
}
ivl_assert(*obj, branch->island==0 || branch->island==tmp_branch->island);
// We found an existing island to join. Join it
// now. Keep scanning in order to find more neighbors.
if (branch->island == 0) {
if (debug_elaborate)
cerr << obj->get_fileline() << ": debug: "
<< "Join brach to existing island." << endl;
branch->island = tmp_branch->island;
} else if (branch->island != tmp_branch->island) {
cerr << obj->get_fileline() << ": internal error: "
<< "Oops, Found 2 neighboring islands." << endl;
ivl_assert(*obj, 0);
}
}
}
// If after all that we did not find an idland to join, then
// start the island not and join it.
if (branch->island == 0) {
branch->island = new ivl_island_s;
branch->island->discipline = 0;
if (debug_elaborate)
cerr << obj->get_fileline() << ": debug: "
<< "Create new island for this branch" << endl;
}
// Now scan all the uncommitted neighbors I found. Calling
// join_island() on them will cause them to notice me in the
// process, and thus they will join my island. This process
// will recurse until all the connected branches join this island.
for (list<NetObj*>::iterator cur = uncommitted_neighbors.begin()
; cur != uncommitted_neighbors.end() ; cur ++ ) {
join_island(*cur);
}
}
-8
View File
@@ -761,10 +761,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid,
pin(0).set_dir(Link::INPUT);
pin(1).set_dir(Link::OUTPUT);
break;
case NetPartSelect::BI:
pin(0).set_dir(Link::OUTPUT);
pin(1).set_dir(Link::OUTPUT);
break;
}
pin(0).set_name(perm_string::literal("Part"), 0);
pin(1).set_name(perm_string::literal("Vect"), 0);
@@ -787,10 +783,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel,
pin(0).set_dir(Link::INPUT);
pin(1).set_dir(Link::OUTPUT);
break;
case NetPartSelect::BI:
pin(0).set_dir(Link::PASSIVE);
pin(1).set_dir(Link::PASSIVE);
break;
}
pin(2).set_dir(Link::INPUT);
+283 -208
View File
@@ -49,8 +49,10 @@ class ostream;
class Design;
class Link;
class Nexus;
class NetEvent;
class NetNet;
class NetNode;
class NetObj;
class NetProc;
class NetProcTop;
class NetRelease;
@@ -60,6 +62,7 @@ class NetExpr;
class NetESignal;
class NetFuncDef;
class NetRamDq;
class NetTaskDef;
class NetEvTrig;
class NetEvWait;
@@ -69,6 +72,8 @@ struct functor_t;
ostream& operator << (ostream&o, ivl_variable_type_t val);
extern void join_island(NetObj*obj);
/* =========
* A NetObj is anything that has any kind of behavior in the
* netlist. Nodes can be gates, registers, etc. and are linked
@@ -129,6 +134,20 @@ class NetObj : public Attrib, public virtual LineInfo {
const NetExpr* delay3_;
};
/*
* Objects that can be island branches are derived from this. (It is
* possible for an object to be a NetObj and an IslandBranch.) This is
* used to collect island information about the node.
*/
class IslandBranch {
public:
IslandBranch() : island(0) { }
public:
struct ivl_island_s* island;
};
class Link {
friend void connect(Link&, Link&);
@@ -578,6 +597,234 @@ class NetNet : public NetObj {
vector<class NetDelaySrc*> delay_paths_;
};
/*
* This object type is used to contain a logical scope within a
* design. The scope doesn't represent any executable hardware, but is
* just a handle that netlist processors can use to grab at the design.
*/
class NetScope : public Attrib {
public:
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
/* Create a new scope, and attach it to the given parent. The
name is expected to have been permallocated. */
NetScope(NetScope*up, const hname_t&name, TYPE t);
~NetScope();
/* Rename the scope using the name generated by inserting as
many pad characters as required between prefix and suffix
to make the name unique in the parent scope. Return false
if a unique name couldn't be generated. */
bool auto_name(const char* prefix, char pad, const char* suffix);
/* Parameters exist within a scope, and these methods allow
one to manipulate the set. In these cases, the name is the
*simple* name of the parameter, the hierarchy is implicit in
the scope. The return value from set_parameter is the
previous expression, if there was one. */
struct range_t;
NetExpr* set_parameter(perm_string name, NetExpr*val,
ivl_variable_type_t type,
NetExpr*msb, NetExpr*lsb, bool signed_flag,
NetScope::range_t*range_list,
const LineInfo&file_line);
NetExpr* set_localparam(perm_string name, NetExpr*val,
const LineInfo&file_line);
const NetExpr*get_parameter(const char* name,
const NetExpr*&msb,
const NetExpr*&lsb) const;
/* These are used by defparam elaboration to replace the
expression with a new expression, without affecting the
range or signed_flag. Return false if the name does not
exist. */
bool replace_parameter(perm_string name, NetExpr*val);
/* These methods set or access events that live in this
scope. */
void add_event(NetEvent*);
void rem_event(NetEvent*);
NetEvent*find_event(perm_string name);
/* These methods manage signals. The add_ and rem_signal
methods are used by the NetNet objects to make themselves
available to the scope, and the find_signal method can be
used to locate signals within a scope. */
void add_signal(NetNet*);
void rem_signal(NetNet*);
NetNet* find_signal(perm_string name);
/* The parent and child() methods allow users of NetScope
objects to locate nearby scopes. */
NetScope* parent();
NetScope* child(const hname_t&name);
const NetScope* parent() const;
const NetScope* child(const hname_t&name) const;
TYPE type() const;
void set_task_def(NetTaskDef*);
void set_func_def(NetFuncDef*);
void set_module_name(perm_string);
NetTaskDef* task_def();
NetFuncDef* func_def();
void set_line(perm_string file, perm_string def_file,
unsigned lineno, unsigned def_lineno);
void set_line(perm_string file, unsigned lineno);
void set_line(const LineInfo *info);
perm_string get_file() const { return file_; };
perm_string get_def_file() const { return def_file_; };
unsigned get_lineno() const { return lineno_; };
unsigned get_def_lineno() const { return def_lineno_; };
bool in_func();
const NetTaskDef* task_def() const;
const NetFuncDef* func_def() const;
/* If the scope represents a module instance, the module_name
is the name of the module itself. */
perm_string module_name() const;
/* Scopes have their own time units and time precision. The
unit and precision are given as power of 10, i.e., -3 is
units of milliseconds.
If a NetScope is created with a parent scope, the new scope
will initially inherit the unit and precision of the
parent scope. */
void time_unit(int);
void time_precision(int);
int time_unit() const;
int time_precision() const;
void default_nettype(NetNet::Type);
NetNet::Type default_nettype() const;
/* The fullname of the scope is the hierarchical name
component (which includes the name and array index) whereas
the basename is just my name. */
perm_string basename() const;
const hname_t& fullname() const { return name_; }
void run_defparams(class Design*);
void evaluate_parameters(class Design*);
/* This method generates a non-hierarchical name that is
guaranteed to be unique within this scope. */
perm_string local_symbol();
void dump(ostream&) const;
void emit_scope(struct target_t*tgt) const;
bool emit_defs(struct target_t*tgt) const;
/* This method runs the functor on me. Recurse through the
children of this node as well. */
void run_functor(Design*des, functor_t*fun);
/* This member is used during elaboration to pass defparam
assignments from the scope pass to the parameter evaluation
step. After that, it is not used. */
map<pform_name_t,NetExpr*>defparams;
public:
struct range_t {
bool exclude_flag;
// Lower bound
bool low_open_flag;
NetExpr*low_expr;
// Upper bound
bool high_open_flag;
NetExpr*high_expr;
// Link to the next range specification
struct range_t*next;
};
/* After everything is all set up, the code generators like
access to these things to make up the parameter lists. */
struct param_expr_t : public LineInfo {
param_expr_t() : type(IVL_VT_NO_TYPE), range(0) { }
// Type information
ivl_variable_type_t type;
bool signed_flag;
NetExpr*msb;
NetExpr*lsb;
// range constraints
struct range_t*range;
// Expression value
NetExpr*expr;
};
map<perm_string,param_expr_t>parameters;
map<perm_string,param_expr_t>localparams;
typedef map<perm_string,param_expr_t>::iterator param_ref_t;
param_ref_t find_parameter(perm_string name);
struct spec_val_t {
ivl_variable_type_t type;
union {
double real_val; // type == IVL_VT_REAL
long integer; // type == IVL_VT_BOOL
};
};
map<perm_string,spec_val_t>specparams;
/* Module instance arrays are collected here for access during
the multiple elaboration passes. */
typedef svector<NetScope*> scope_vec_t;
map<perm_string, scope_vec_t>instance_arrays;
/* Loop generate uses this as scratch space during
elaboration. Expression evaluation can use this to match
names. */
perm_string genvar_tmp;
long genvar_tmp_val;
private:
void evaluate_parameter_logic_(Design*des, param_ref_t cur);
void evaluate_parameter_real_(Design*des, param_ref_t cur);
private:
TYPE type_;
hname_t name_;
perm_string file_;
perm_string def_file_;
unsigned lineno_;
unsigned def_lineno_;
signed char time_unit_, time_prec_;
NetNet::Type default_nettype_;
NetEvent *events_;
NetNet *signals_;
perm_string module_name_;
union {
NetTaskDef*task_;
NetFuncDef*func_;
};
NetScope*up_;
NetScope*sib_;
NetScope*sub_;
unsigned lcounter_;
};
/*
* This class implements the LPM_ABS component. The node has a single
* input, a signe expression, that it converts to the absolute
@@ -1129,6 +1376,33 @@ class NetSysFunc : public NetNode {
const struct sfunc_return_type*def_;
};
class NetTran : public NetNode, public IslandBranch {
public:
// Tran devices other then TRAN_VP
NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type);
// Create a TRAN_VP
NetTran(NetScope*scope, perm_string n, unsigned wid,
unsigned part, unsigned off);
~NetTran();
ivl_switch_type_t type() const { return type_; }
// These are only used for IVL_SW_TRAN_PV
unsigned vector_width() const;
unsigned part_width() const;
unsigned part_offset() const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
ivl_switch_type_t type_;
unsigned wid_;
unsigned part_;
unsigned off_;
};
/* =========
* There are cases where expressions need to be represented. The
* NetExpr class is the root of a hierarchy that serves that purpose.
@@ -1343,8 +1617,8 @@ class NetECRealParam : public NetECReal {
* selector as the input.
*
* The NetPartSelect can be output from the signal (i.e. reading a
* part), input into the signal, or bi-directional. The DIR method
* gives the type of the node.
* part) or input into the signal. The DIR method gives the type of
* the node.
*
* VP (Vector-to-Part)
* Output pin 0 is the part select, and input pin 1 is connected to
@@ -1354,10 +1628,6 @@ class NetECRealParam : public NetECReal {
* Output pin 1 is connected to the NetNet, and input pin 0 is the
* part select. In this case, the node is driving the NetNet.
*
* BI (BI-directional)
* Pin 0 is the part select and pin 1 is connected to the NetNet, but
* the ports are intended to be bi-directional.
*
* Note that whatever the direction that data is intended to flow,
* pin-0 is the part select and pin-1 is connected to the NetNet.
*/
@@ -1365,7 +1635,7 @@ class NetPartSelect : public NetNode {
public:
// enum for the device direction
enum dir_t { VP, PV, BI };
enum dir_t { VP, PV};
explicit NetPartSelect(NetNet*sig,
unsigned off, unsigned wid, dir_t dir);
@@ -3006,6 +3276,7 @@ class NetEParam : public NetExpr {
virtual bool set_width(unsigned w, bool last_chance);
virtual bool has_width() const;
virtual void expr_scan(struct expr_scan_t*) const;
virtual ivl_variable_type_t expr_type() const;
virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetEParam* dup_expr() const;
@@ -3014,7 +3285,10 @@ class NetEParam : public NetExpr {
private:
Design*des_;
NetScope*scope_;
perm_string name_;
typedef map<perm_string,NetScope::param_expr_t>::iterator ref_t;
ref_t reference_;
NetEParam(class Design*des, NetScope*scope, ref_t ref);
};
@@ -3287,206 +3561,6 @@ class NetESignal : public NetExpr {
};
/*
* This object type is used to contain a logical scope within a
* design. The scope doesn't represent any executable hardware, but is
* just a handle that netlist processors can use to grab at the design.
*/
class NetScope : public Attrib {
public:
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
/* Create a new scope, and attach it to the given parent. The
name is expected to have been permallocated. */
NetScope(NetScope*up, const hname_t&name, TYPE t);
~NetScope();
/* Rename the scope using the name generated by inserting as
many pad characters as required between prefix and suffix
to make the name unique in the parent scope. Return false
if a unique name couldn't be generated. */
bool auto_name(const char* prefix, char pad, const char* suffix);
/* Parameters exist within a scope, and these methods allow
one to manipulate the set. In these cases, the name is the
*simple* name of the parameter, the hierarchy is implicit in
the scope. The return value from set_parameter is the
previous expression, if there was one. */
NetExpr* set_parameter(perm_string name, NetExpr*val,
NetExpr*msb, NetExpr*lsb, bool signed_flag,
perm_string file, unsigned lineno);
NetExpr* set_localparam(perm_string name, NetExpr*val,
perm_string file, unsigned lineno);
const NetExpr*get_parameter(const char* name,
const NetExpr*&msb,
const NetExpr*&lsb) const;
/* These are used by defparam elaboration to replace the
expression with a new expression, without affecting the
range or signed_flag. Return false if the name does not
exist. */
bool replace_parameter(perm_string name, NetExpr*val);
/* These methods set or access events that live in this
scope. */
void add_event(NetEvent*);
void rem_event(NetEvent*);
NetEvent*find_event(perm_string name);
/* These methods manage signals. The add_ and rem_signal
methods are used by the NetNet objects to make themselves
available to the scope, and the find_signal method can be
used to locate signals within a scope. */
void add_signal(NetNet*);
void rem_signal(NetNet*);
NetNet* find_signal(perm_string name);
/* The parent and child() methods allow users of NetScope
objects to locate nearby scopes. */
NetScope* parent();
NetScope* child(const hname_t&name);
const NetScope* parent() const;
const NetScope* child(const hname_t&name) const;
TYPE type() const;
void set_task_def(NetTaskDef*);
void set_func_def(NetFuncDef*);
void set_module_name(perm_string);
NetTaskDef* task_def();
NetFuncDef* func_def();
void set_line(perm_string file, perm_string def_file,
unsigned lineno, unsigned def_lineno);
void set_line(perm_string file, unsigned lineno);
void set_line(const LineInfo *info);
perm_string get_file() const { return file_; };
perm_string get_def_file() const { return def_file_; };
unsigned get_lineno() const { return lineno_; };
unsigned get_def_lineno() const { return def_lineno_; };
bool in_func();
const NetTaskDef* task_def() const;
const NetFuncDef* func_def() const;
/* If the scope represents a module instance, the module_name
is the name of the module itself. */
perm_string module_name() const;
/* Scopes have their own time units and time precision. The
unit and precision are given as power of 10, i.e., -3 is
units of milliseconds.
If a NetScope is created with a parent scope, the new scope
will initially inherit the unit and precision of the
parent scope. */
void time_unit(int);
void time_precision(int);
int time_unit() const;
int time_precision() const;
void default_nettype(NetNet::Type);
NetNet::Type default_nettype() const;
/* The fullname of the scope is the hierarchical name
component (which includes the name and array index) whereas
the basename is just my name. */
perm_string basename() const;
const hname_t& fullname() const { return name_; }
void run_defparams(class Design*);
void evaluate_parameters(class Design*);
/* This method generates a non-hierarchical name that is
guaranteed to be unique within this scope. */
perm_string local_symbol();
void dump(ostream&) const;
void emit_scope(struct target_t*tgt) const;
bool emit_defs(struct target_t*tgt) const;
/* This method runs the functor on me. Recurse through the
children of this node as well. */
void run_functor(Design*des, functor_t*fun);
/* This member is used during elaboration to pass defparam
assignments from the scope pass to the parameter evaluation
step. After that, it is not used. */
map<pform_name_t,NetExpr*>defparams;
public:
/* After everything is all set up, the code generators like
access to these things to make up the parameter lists. */
struct param_expr_t {
NetExpr*expr;
NetExpr*msb;
NetExpr*lsb;
perm_string file;
unsigned lineno;
bool signed_flag;
};
map<perm_string,param_expr_t>parameters;
map<perm_string,param_expr_t>localparams;
struct spec_val_t {
ivl_variable_type_t type;
union {
double real_val; // type == IVL_VT_REAL
long integer; // type == IVL_VT_BOOL
};
};
map<perm_string,spec_val_t>specparams;
/* Module instance arrays are collected here for access during
the multiple elaboration passes. */
typedef svector<NetScope*> scope_vec_t;
map<perm_string, scope_vec_t>instance_arrays;
/* Loop generate uses this as scratch space during
elaboration. Expression evaluation can use this to match
names. */
perm_string genvar_tmp;
long genvar_tmp_val;
private:
TYPE type_;
hname_t name_;
perm_string file_;
perm_string def_file_;
unsigned lineno_;
unsigned def_lineno_;
signed char time_unit_, time_prec_;
NetNet::Type default_nettype_;
NetEvent *events_;
NetNet *signals_;
perm_string module_name_;
union {
NetTaskDef*task_;
NetFuncDef*func_;
};
NetScope*up_;
NetScope*sib_;
NetScope*sub_;
unsigned lcounter_;
};
/*
* This class contains an entire design. It includes processes and a
* netlist, and can be passed around from function to function.
@@ -3564,6 +3638,7 @@ class Design {
// Iterate over the design...
void dump(ostream&) const;
void functor(struct functor_t*);
void join_islands(void);
int emit(struct target_t*) const;
// This is incremented by elaboration when an error is
+22
View File
@@ -123,6 +123,13 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
return res;
}
NetEConst* make_const_x(unsigned long wid)
{
verinum xxx (verinum::Vx, wid);
NetEConst*resx = new NetEConst(xxx);
return resx;
}
NetExpr* condition_reduce(NetExpr*expr)
{
if (expr->expr_width() == 1)
@@ -182,6 +189,21 @@ bool eval_as_long(long&value, NetExpr*expr)
return false;
}
bool eval_as_double(double&value, NetExpr*expr)
{
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr) ) {
value = tmp->value().as_long();
return true;
}
if (NetECReal*rtmp = dynamic_cast<NetECReal*>(expr)) {
value = rtmp->value().as_double();
return true;
}
return false;
}
std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
const pform_name_t&path)
{
+6
View File
@@ -102,6 +102,11 @@ extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
extern NetExpr*make_add_expr(NetExpr*expr, long val);
extern NetExpr*make_sub_expr(long val, NetExpr*expr);
/*
* Make a NetEConst object that contains only X bits.
*/
extern NetEConst*make_const_x(unsigned long wid);
/*
* In some cases the lval is accessible as a pointer to the head of
* a list of NetAssign_ objects. This function returns the width of
@@ -138,6 +143,7 @@ void eval_expr(NetExpr*&expr, int prune_width =-1);
* down to a constant) then return false and leave value unchanged.
*/
bool eval_as_long(long&value, NetExpr*expr);
bool eval_as_double(double&value, NetExpr*expr);
extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
const pform_name_t&path);
+262 -104
View File
@@ -35,8 +35,9 @@ class PSpecPath;
extern void lex_start_table();
extern void lex_end_table();
static svector<PExpr*>* active_range = 0;
static bool active_signed = false;
static svector<PExpr*>* param_active_range = 0;
static bool param_active_signed = false;
static ivl_variable_type_t param_active_type = IVL_VT_LOGIC;
/* Port declaration lists use this structure for context. */
static struct {
@@ -94,12 +95,6 @@ static list<perm_string>* list_from_identifier(list<perm_string>*tmp, char*id)
return tmp;
}
static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
{
tmp->set_lineno(where.first_line);
tmp->set_file(filename_strings.make(where.text));
}
static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
{
svector<PExpr*>*copy = 0;
@@ -147,6 +142,8 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
list<perm_string>*perm_strings;
pform_name_t*pform_name;
discipline_t*discipline;
hname_t*hier;
list<string>*strings;
@@ -160,6 +157,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
svector<lgate>*gates;
Module::port_t *mport;
Module::range_t* value_range;
svector<Module::port_t*>*mports;
named_pexpr_t*named_pexpr;
@@ -196,40 +194,50 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
};
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING
%token <discipline> DISCIPLINE_IDENTIFIER
%token <text> PATHPULSE_IDENTIFIER
%token <number> BASED_NUMBER DEC_NUMBER
%token <realtime> REALTIME
%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_RSS K_SG
/* K_CONTRIBUTE is <+, the contribution assign. */
%token K_CONTRIBUTE
%token K_PO_POS K_PO_NEG K_POW
%token K_PSTAR K_STARP
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER
%token K_abs K_acos K_acosh K_asin K_asinh K_atan K_atanh K_atan2
%token K_abs K_abstol K_access K_acos K_acosh K_asin K_analog K_asinh
%token K_atan K_atanh K_atan2
%token K_always K_and K_assign K_begin K_bool K_buf K_bufif0 K_bufif1 K_case
%token K_casex K_casez K_ceil K_cmos K_cos K_cosh
%token K_deassign K_default K_defparam K_disable
%token K_edge K_edge_descriptor
%token K_else K_end K_endcase K_endfunction K_endgenerate K_endmodule
%token K_endprimitive K_endspecify K_endtable K_endtask K_event K_exp K_floor
%token K_casex K_casez K_ceil K_cmos K_continuous K_cos K_cosh
%token K_ddt_nature K_deassign K_default K_defparam K_disable K_discrete
%token K_domain K_edge K_edge_descriptor K_discipline
%token K_else K_end K_endcase K_enddiscipline K_endfunction K_endgenerate
%token K_endmodule K_endnature
%token K_endprimitive K_endspecify K_endtable K_endtask K_event
%token K_exclude K_exp K_floor K_flow K_from
%token K_for K_force K_forever K_fork K_function K_generate K_genvar
%token K_highz0 K_highz1 K_hypot K_if K_ifnone
%token K_ground K_highz0 K_highz1 K_hypot K_idt_nature K_if K_ifnone K_inf
%token K_initial K_inout K_input K_integer K_join K_large K_ln K_localparam
%token K_log K_logic K_macromodule K_max
%token K_medium K_min K_module K_nand K_negedge K_nmos K_nor K_not K_notif0
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_pow K_primitive
%token K_medium K_min K_module K_nand K_nature K_negedge
%token K_nmos K_nor K_not K_notif0
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_potential
%token K_pow K_primitive
%token K_pull0 K_pull1 K_pulldown K_pullup K_rcmos K_real K_realtime
%token K_reg K_release K_repeat
%token K_rnmos K_rpmos K_rtran K_rtranif0 K_rtranif1 K_scalared
%token K_signed K_sin K_sinh K_small K_specify
%token K_specparam K_sqrt K_strong0 K_strong1 K_supply0 K_supply1 K_table
%token K_specparam K_sqrt K_string K_strong0 K_strong1 K_supply0 K_supply1
%token K_table
%token K_tan K_tanh K_task
%token K_time K_tran K_tranif0 K_tranif1 K_tri K_tri0 K_tri1 K_triand
%token K_trior K_trireg K_vectored K_wait K_wand K_weak0 K_weak1
%token K_trior K_trireg K_units K_vectored K_wait K_wand K_weak0 K_weak1
%token K_while K_wire
%token K_wone K_wor K_xnor K_xor
%token K_Shold K_Speriod K_Srecovery K_Srecrem K_Ssetup K_Swidth K_Ssetuphold
%token KK_attribute
%type <flag> from_exclude
%type <number> number
%type <flag> signed_opt udp_reg_opt edge_operator
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
@@ -251,6 +259,9 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
%type <mport> port port_opt port_reference port_reference_list
%type <mport> port_declaration
%type <mports> list_of_ports module_port_list_opt list_of_port_declarations
%type <value_range> parameter_value_range parameter_value_ranges
%type <value_range> parameter_value_ranges_opt
%type <expr> value_range_expression
%type <wires> task_item task_item_list task_item_list_opt
%type <wires> task_port_item task_port_decl task_port_decl_list
@@ -312,10 +323,15 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
%left K_POW
%left UNARY_PREC
/* to resolve dangling else ambiguity. */
%nonassoc less_than_K_else
%nonassoc K_else
/* to resolve exclude (... ambiguity */
%nonassoc '('
%nonassoc K_exclude
%%
/* A degenerate source file can be completely empty. */
@@ -655,15 +671,71 @@ delay_value_simple
;
description
: module
| udp_primitive
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')'
{ perm_string tmp3 = lex_strings.make($3);
pform_set_type_attrib(tmp3, $5, $7);
delete[]$3;
delete $5;
}
;
: module
| udp_primitive
| nature_declaration
| discipline_declaration
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')'
{ perm_string tmp3 = lex_strings.make($3);
pform_set_type_attrib(tmp3, $5, $7);
delete[]$3;
delete $5;
}
;
/* The discipline and nature declarations used to take no ';' after
the identifier. The 2.3 LRM adds the ';', but since there are
programs written to the 2.1 and 2.2 standard that don't, we
choose to make the ';' optional in this context. */
optional_semicolon : ';' | ;
discipline_declaration
: K_discipline IDENTIFIER optional_semicolon
{ pform_start_discipline($2); }
discipline_items K_enddiscipline
{ pform_end_discipline(@1); delete[] $2; }
;
discipline_items
: discipline_items discipline_item
| discipline_item
;
discipline_item
: K_domain K_discrete ';'
{ pform_discipline_domain(@1, DD_DISCRETE); }
| K_domain K_continuous ';'
{ pform_discipline_domain(@1, DD_CONTINUOUS); }
| K_potential IDENTIFIER ';'
{ pform_discipline_potential(@1, $2); delete[] $2; }
| K_flow IDENTIFIER ';'
{ pform_discipline_flow(@1, $2); delete[] $2; }
;
nature_declaration
: K_nature IDENTIFIER optional_semicolon
{ pform_start_nature($2); }
nature_items
K_endnature
{ pform_end_nature(@1); delete[] $2; }
;
nature_items
: nature_items nature_item
| nature_item
;
nature_item
: K_units '=' STRING ';'
{ delete[] $3; }
| K_abstol '=' expression ';'
| K_access '=' IDENTIFIER ';'
{ pform_nature_access(@1, $3); delete[] $3; }
| K_idt_nature '=' IDENTIFIER ';'
{ delete[] $3; }
| K_ddt_nature '=' IDENTIFIER ';'
{ delete[] $3; }
;
drive_strength
: '(' dr_strength0 ',' dr_strength1 ')'
@@ -773,6 +845,15 @@ event_expression
}
;
/* A branch probe expression applies a probe function (potential or
flow) to a branch. The branch may be implicit as a pair of nets
or explicit as a named branch. Elaboration will check that the
function name really is a nature attribute identifier. */
branch_probe_expression
: IDENTIFIER '(' IDENTIFIER ',' IDENTIFIER ')'
| IDENTIFIER '(' IDENTIFIER ')'
;
expression
: expr_primary
{ $$ = $1; }
@@ -1902,6 +1983,12 @@ module_item
yyerrok;
}
/* Maybe this is a discipline declaration? If so, then the lexor
will see the discipline name as an identifier. We match it to the
discipline or type name semantically. */
| DISCIPLINE_IDENTIFIER list_of_identifiers ';'
{ pform_attach_discipline(@1, $1, $2); }
/* block_item_decl rule is shared with task blocks and named
begin/end. */
@@ -1981,16 +2068,16 @@ module_item
/* Always and initial items are behavioral processes. */
| attribute_list_opt K_always statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS,
$3, $1);
FILE_NAME(tmp, @2);
}
| attribute_list_opt K_initial statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_INITIAL,
$3, $1);
FILE_NAME(tmp, @2);
}
| attribute_list_opt K_always statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $3, $1);
FILE_NAME(tmp, @2);
}
| attribute_list_opt K_initial statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_INITIAL, $3, $1);
FILE_NAME(tmp, @2);
}
| attribute_list_opt K_analog analog_statement
/* The task declaration rule matches the task declaration
header, then pushes the function scope. This causes the
@@ -2275,23 +2362,48 @@ var_type
generates a type (optional) and a list of assignments. */
parameter_assign_decl
: parameter_assign_list
| range { active_range = $1; active_signed = false; }
parameter_assign_list
{ active_range = 0;
active_signed = false;
}
| K_signed range { active_range = $2; active_signed = true; }
parameter_assign_list
{ active_range = 0;
active_signed = false;
}
| K_integer { active_range = 0; active_signed = true; }
parameter_assign_list
{ active_range = 0;
active_signed = false;
}
;
: parameter_assign_list
| range
{ param_active_range = $1;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
parameter_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_signed range
{ param_active_range = $2;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
}
parameter_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_integer
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
}
parameter_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_real
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_REAL;
}
parameter_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
;
parameter_assign_list
: parameter_assign
@@ -2299,22 +2411,44 @@ parameter_assign_list
;
parameter_assign
: IDENTIFIER '=' expression
{ PExpr*tmp = $3;
if (!pform_expression_is_constant(tmp)) {
yyerror(@3, "error: parameter value "
"must be a constant expression.");
delete tmp;
tmp = 0;
} else {
pform_set_parameter(lex_strings.make($1),
active_signed,
active_range, tmp,
@1.text, @1.first_line);
}
delete[]$1;
}
;
: IDENTIFIER '=' expression parameter_value_ranges_opt
{ PExpr*tmp = $3;
pform_set_parameter(@1, lex_strings.make($1), param_active_type,
param_active_signed, param_active_range, tmp, $4);
delete[]$1;
}
;
parameter_value_ranges_opt : parameter_value_ranges { $$ = $1; } | { $$ = 0; } ;
parameter_value_ranges
: parameter_value_ranges parameter_value_range
{ $$ = $2; $$->next = $1; }
| parameter_value_range
{ $$ = $1; $$->next = 0; }
;
parameter_value_range
: from_exclude '[' value_range_expression ':' value_range_expression ']'
{ $$ = pform_parameter_value_range($1, false, $3, false, $5); }
| from_exclude '[' value_range_expression ':' value_range_expression ')'
{ $$ = pform_parameter_value_range($1, false, $3, true, $5); }
| from_exclude '(' value_range_expression ':' value_range_expression ']'
{ $$ = pform_parameter_value_range($1, true, $3, false, $5); }
| from_exclude '(' value_range_expression ':' value_range_expression ')'
{ $$ = pform_parameter_value_range($1, true, $3, true, $5); }
| K_exclude expression
{ $$ = pform_parameter_value_range(true, false, $2, false, $2); }
;
value_range_expression
: expression { $$ = $1; }
| K_inf { $$ = 0; }
| '+' K_inf { $$ = 0; }
| '-' K_inf { $$ = 0; }
;
from_exclude : K_from { $$ = false; } | K_exclude { $$ = true; } ;
/* Localparam assignments and assignment lists are broken into
separate BNF so that I can call slightly different parameter
@@ -2322,41 +2456,59 @@ parameter_assign
behave differently when someone tries to override them. */
localparam_assign
: IDENTIFIER '=' expression
{ PExpr*tmp = $3;
if (!pform_expression_is_constant(tmp)) {
yyerror(@3, "error: parameter value "
"must be constant.");
delete tmp;
tmp = 0;
} else {
pform_set_localparam(lex_strings.make($1),
active_signed,
active_range, tmp,
@1.text, @1.first_line);
}
delete[]$1;
}
;
: IDENTIFIER '=' expression
{ PExpr*tmp = $3;
pform_set_localparam(@1, lex_strings.make($1),
param_active_type,
param_active_signed,
param_active_range, tmp);
delete[]$1;
}
;
localparam_assign_decl
: localparam_assign_list
| range { active_range = $1; active_signed = false; }
localparam_assign_list
{ active_range = 0;
active_signed = false;
}
| K_signed range { active_range = $2; active_signed = true; }
localparam_assign_list
{ active_range = 0;
active_signed = false;
}
| K_integer { active_range = 0; active_signed = true; }
localparam_assign_list
{ active_range = 0;
active_signed = false;
}
;
: localparam_assign_list
| range
{ param_active_range = $1;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
localparam_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_NO_TYPE;
}
| K_signed range
{ param_active_range = $2;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
}
localparam_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_integer
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
}
localparam_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_real
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_REAL;
}
localparam_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
;
localparam_assign_list
: localparam_assign
@@ -3492,6 +3644,12 @@ statement_or_null
| ';' { $$ = 0; }
;
analog_statement
: branch_probe_expression K_CONTRIBUTE expression ';'
{ yyerror(@1, "sorry: Analog contribution statements not supported."); }
;
/* Task items are, other than the statement, task port items and
other block items. */
task_item
+8
View File
@@ -23,6 +23,7 @@
#endif
# include <list>
# include "compiler.h"
# include "pform.h"
/*
@@ -39,6 +40,13 @@ struct vlltype {
};
# define YYLTYPE struct vlltype
class LineInfo;
inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
{
tmp->set_lineno(where.first_line);
tmp->set_file(filename_strings.make(where.text));
}
/* This for compatibility with new and older bison versions. */
#ifndef yylloc
# define yylloc VLlloc
+53 -33
View File
@@ -27,6 +27,7 @@
# include "PUdp.h"
# include "PGenerate.h"
# include "PSpec.h"
# include "discipline.h"
# include <list>
# include <map>
# include <assert.h>
@@ -38,7 +39,6 @@
# include "ivl_assert.h"
map<perm_string,Module*> pform_modules;
map<perm_string,PUdp*> pform_primitives;
@@ -82,12 +82,6 @@ static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno)
obj->set_file(filename_strings.make(file));
}
static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
{
tmp->set_lineno(where.first_line);
tmp->set_file(filename_strings.make(where.text));
}
/*
* The lexical_scope keeps track of the current lexical scope that is
* being parsed. The lexical scope may stack, so the current scope may
@@ -137,7 +131,7 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
return block;
}
static PWire*get_wire_in_scope(perm_string name)
PWire*pform_get_wire_in_scope(perm_string name)
{
/* Note that if we are processing a generate, then the
scope depth will be empty because generate schemes
@@ -925,7 +919,7 @@ static void pform_set_net_range(perm_string name,
ivl_variable_type_t dt,
PWSRType rt)
{
PWire*cur = get_wire_in_scope(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
VLerror("error: name is not a valid net.");
return;
@@ -1344,7 +1338,7 @@ void pform_makewire(const vlltype&li, perm_string name,
ivl_variable_type_t dt,
svector<named_pexpr_t*>*attr)
{
PWire*cur = get_wire_in_scope(name);
PWire*cur = pform_get_wire_in_scope(name);
// If this is not implicit ("implicit" meaning we don't know
// what the type is yet) then set the type now.
@@ -1458,7 +1452,7 @@ void pform_makewire(const vlltype&li,
SR_NET);
}
PWire*cur = get_wire_in_scope(first->name);
PWire*cur = pform_get_wire_in_scope(first->name);
if (cur != 0) {
PEIdent*lval = new PEIdent(first->name);
FILE_NAME(lval, li.text, li.first_line);
@@ -1640,50 +1634,76 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
cur->set_memory_idx(l, r);
}
void pform_set_parameter(perm_string name, bool signed_flag,
svector<PExpr*>*range, PExpr*expr,
const char*file, unsigned lineno)
Module::range_t* pform_parameter_value_range(bool exclude_flag,
bool low_open, PExpr*low_expr,
bool hig_open, PExpr*hig_expr)
{
// Detect +-inf and make the the *_open flags false to force
// the range interpretation as inf.
if (low_expr == 0) low_open = false;
if (hig_expr == 0) hig_open = false;
Module::range_t*tmp = new Module::range_t;
tmp->exclude_flag = exclude_flag;
tmp->low_open_flag = low_open;
tmp->low_expr = low_expr;
tmp->high_open_flag = hig_open;
tmp->high_expr = hig_expr;
tmp->next = 0;
return tmp;
}
void pform_set_parameter(const struct vlltype&loc,
perm_string name, ivl_variable_type_t type,
bool signed_flag, svector<PExpr*>*range, PExpr*expr,
Module::range_t*value_range)
{
assert(expr);
pform_cur_module->parameters[name].expr = expr;
Module::param_expr_t&parm = pform_cur_module->parameters[name];
FILE_NAME(&parm, loc);
parm.expr = expr;
parm.type = type;
if (range) {
assert(range->count() == 2);
assert((*range)[0]);
assert((*range)[1]);
pform_cur_module->parameters[name].msb = (*range)[0];
pform_cur_module->parameters[name].lsb = (*range)[1];
parm.msb = (*range)[0];
parm.lsb = (*range)[1];
} else {
pform_cur_module->parameters[name].msb = 0;
pform_cur_module->parameters[name].lsb = 0;
parm.msb = 0;
parm.lsb = 0;
}
pform_cur_module->parameters[name].signed_flag = signed_flag;
pform_cur_module->parameters[name].file = filename_strings.make(file);
pform_cur_module->parameters[name].lineno = lineno;
parm.signed_flag = signed_flag;
parm.range = value_range;
pform_cur_module->param_names.push_back(name);
}
void pform_set_localparam(perm_string name, bool signed_flag,
svector<PExpr*>*range, PExpr*expr,
const char*file, unsigned lineno)
void pform_set_localparam(const struct vlltype&loc,
perm_string name, ivl_variable_type_t type,
bool signed_flag, svector<PExpr*>*range, PExpr*expr)
{
assert(expr);
pform_cur_module->localparams[name].expr = expr;
Module::param_expr_t&parm = pform_cur_module->localparams[name];
FILE_NAME(&parm, loc);
parm.expr = expr;
parm.type = type;
if (range) {
assert(range->count() == 2);
assert((*range)[0]);
assert((*range)[1]);
pform_cur_module->localparams[name].msb = (*range)[0];
pform_cur_module->localparams[name].lsb = (*range)[1];
parm.msb = (*range)[0];
parm.lsb = (*range)[1];
} else {
pform_cur_module->localparams[name].msb = 0;
pform_cur_module->localparams[name].lsb = 0;
parm.msb = 0;
parm.lsb = 0;
}
pform_cur_module->localparams[name].signed_flag = signed_flag;
pform_cur_module->localparams[name].file = filename_strings.make(file);
pform_cur_module->localparams[name].lineno = lineno;
parm.signed_flag = signed_flag;
parm.range = 0;
}
void pform_set_specparam(perm_string name, PExpr*expr)
+45 -6
View File
@@ -30,6 +30,7 @@
# include "PUdp.h"
# include "PWire.h"
# include "verinum.h"
# include "discipline.h"
# include <iostream>
# include <string>
# include <list>
@@ -115,11 +116,19 @@ struct lgate {
unsigned lineno;
};
/* The lexor calls this function to change the default nettype. */
extern void pform_set_default_nettype(NetNet::Type net,
const char*file,
unsigned lineno);
/*
* Look for the given wire in the current lexical scope. If the wire
* (including variables of any type) cannot be found in the current
* scope, then return 0.
*/
extern PWire* pform_get_wire_in_scope(perm_string name);
/*
* The parser uses startmodule and endmodule together to build up a
* module as it parses it. The startmodule tells the pform code that a
@@ -257,16 +266,22 @@ extern void pform_set_attrib(perm_string name, perm_string key,
extern void pform_set_type_attrib(perm_string name, const string&key,
char*value);
extern void pform_set_parameter(perm_string name,
extern Module::range_t* pform_parameter_value_range(bool exclude_flag,
bool low_open, PExpr*low_expr,
bool hig_open, PExpr*hig_expr);
extern void pform_set_parameter(const struct vlltype&loc,
perm_string name,
ivl_variable_type_t type,
bool signed_flag,
svector<PExpr*>*range,
PExpr*expr,
const char*file, unsigned lineno);
extern void pform_set_localparam(perm_string name,
PExpr*expr, Module::range_t*value_range);
extern void pform_set_localparam(const struct vlltype&loc,
perm_string name,
ivl_variable_type_t type,
bool signed_flag,
svector<PExpr*>*range,
PExpr*expr,
const char*file, unsigned lineno);
PExpr*expr);
extern void pform_set_defparam(const pform_name_t&name, PExpr*expr);
/*
@@ -350,4 +365,28 @@ extern void pform_dump(ostream&out, Module*mod);
*/
extern void pform_error_nested_modules();
/* ** pform_discipline.cc
* Functions for handling the parse of natures and disciplines. These
* functions are in pform_disciplines.cc
*/
class discipline_t;
extern void pform_start_nature(const char*name);
extern void pform_end_nature(const struct vlltype&loc);
extern void pform_nature_access(const struct vlltype&loc, const char*name);
extern void pform_start_discipline(const char*name);
extern void pform_end_discipline(const struct vlltype&loc);
extern void pform_discipline_domain(const struct vlltype&loc, ddomain_t use_domain);
extern void pform_discipline_potential(const struct vlltype&loc, const char*name);
extern void pform_discipline_flow(const struct vlltype&loc, const char*name);
extern void pform_attach_discipline(const struct vlltype&loc,
discipline_t*discipline, list<perm_string>*names);
extern void pform_dump(ostream&out, const nature_t*);
extern void pform_dump(ostream&out, const discipline_t*);
#endif
+195
View File
@@ -0,0 +1,195 @@
/*
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include "compiler.h"
# include "pform.h"
# include "parse_misc.h"
# include "discipline.h"
map<perm_string,nature_t*> natures;
map<perm_string,discipline_t*> disciplines;
static perm_string nature_name = perm_string::perm_string();
static perm_string nature_access = perm_string::perm_string();
void pform_start_nature(const char*name)
{
nature_name = lex_strings.make(name);
}
void pform_nature_access(const struct vlltype&loc, const char*name)
{
if (nature_access) {
cerr << loc.text << ":" << loc.first_line << ": error: "
<< "Too many access names for nature "
<< nature_name << "." << endl;
error_count += 1;
return;
}
nature_access = lex_strings.make(name);
}
void pform_end_nature(const struct vlltype&loc)
{
// The nature access function is required. If it is missing,
// then signal an error. For a temporary expedient, we can set
// the nature name as the access function, but don't expect it
// to work.
if (! nature_access) {
cerr << loc.text << ":" << loc.first_line << ": error: "
<< "Missing access name for nature "
<< nature_name << "." << endl;
error_count += 1;
nature_access = nature_name;
}
nature_t*tmp = new nature_t(nature_name, nature_access);
natures[nature_name] = tmp;
FILE_NAME(tmp, loc);
nature_name = perm_string::perm_string();
nature_access = perm_string::perm_string();
}
static perm_string discipline_name;
static ddomain_t discipline_domain = DD_NONE;
static nature_t* discipline_potential = 0;
static nature_t* discipline_flow = 0;
void pform_start_discipline(const char*name)
{
discipline_name = lex_strings.make(name);
discipline_domain = DD_NONE;
}
void pform_discipline_domain(const struct vlltype&loc, ddomain_t use_domain)
{
assert(use_domain != DD_NONE);
if (discipline_domain != DD_NONE) {
cerr << loc.text << ":" << loc.first_line << ": error: "
<< "Too many domain attributes for discipline "
<< discipline_name << "." << endl;
error_count += 1;
return;
}
discipline_domain = use_domain;
}
void pform_discipline_potential(const struct vlltype&loc, const char*name)
{
if (discipline_potential) {
cerr << loc.text << ":" << loc.first_line << ": error: "
<< "Too many potential natures for discipline "
<< discipline_name << "." << endl;
error_count += 1;
return;
}
perm_string key = lex_strings.make(name);
discipline_potential = natures[key];
if (discipline_potential == 0) {
cerr << loc.text << ":" << loc.first_line << ": error: "
<< "nature " << key << " is not declared." << endl;
error_count += 1;
return;
}
}
void pform_discipline_flow(const struct vlltype&loc, const char*name)
{
if (discipline_flow) {
cerr << loc.text << ":" << loc.first_line << ": error: "
<< "Too many flow natures for discipline "
<< discipline_name << "." << endl;
error_count += 1;
return;
}
perm_string key = lex_strings.make(name);
discipline_flow = natures[key];
if (discipline_flow == 0) {
cerr << loc.text << ":" << loc.first_line << ": error: "
<< "nature " << key << " is not declared." << endl;
error_count += 1;
return;
}
}
void pform_end_discipline(const struct vlltype&loc)
{
// If the domain is not otherwise specified, then take it to
// be continuous if potential or flow natures are given.
if (discipline_domain == DD_NONE && (discipline_potential||discipline_flow))
discipline_domain = DD_CONTINUOUS;
discipline_t*tmp = new discipline_t(discipline_name, discipline_domain,
discipline_potential, discipline_flow);
disciplines[discipline_name] = tmp;
FILE_NAME(tmp, loc);
/* Clear the static variables for the next item. */
discipline_name = perm_string::perm_string();
discipline_domain = DD_NONE;
discipline_potential = 0;
discipline_flow = 0;
}
/*
* The parser uses this function to attach a discipline to a wire. The
* wire may be declared by now, or will be declared further later. If
* it is already declared, we just attach the discipline. If it is not
* declared yet, then this is the declaration and we create the signal
* in the current lexical scope.
*/
void pform_attach_discipline(const struct vlltype&loc,
discipline_t*discipline, list<perm_string>*names)
{
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; cur ++ ) {
PWire* cur_net = pform_get_wire_in_scope(*cur);
if (cur_net == 0) {
/* Not declared yet, declare it now. */
pform_makewire(loc, *cur, NetNet::WIRE,
NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
cur_net = pform_get_wire_in_scope(*cur);
assert(cur_net);
}
if (discipline_t*tmp = cur_net->get_discipline()) {
cerr << loc.text << ":" << loc.first_line << ": error: "
<< "discipline " << discipline->name()
<< " cannot override existing discipline " << tmp->name()
<< " on net " << cur_net->basename() << endl;
error_count += 1;
} else {
cur_net->set_discipline(discipline);
}
}
}
+75 -3
View File
@@ -29,6 +29,7 @@
# include "PEvent.h"
# include "PGenerate.h"
# include "PSpec.h"
# include "discipline.h"
# include <iostream>
# include <iomanip>
# include <typeinfo>
@@ -128,6 +129,26 @@ ostream& operator<< (ostream&o, const pform_name_t&that)
return o;
}
std::ostream& operator << (std::ostream&out, ddomain_t dom)
{
switch (dom) {
case DD_NONE:
out << "no-domain";
break;
case DD_DISCRETE:
out << "discrete";
break;
case DD_CONTINUOUS:
out << "continuous";
break;
default:
assert(0);
break;
}
return out;
}
void PExpr::dump(ostream&out) const
{
out << typeid(*this).name();
@@ -300,6 +321,10 @@ void PWire::dump(ostream&out, unsigned ind) const
out << " signed";
}
if (discipline_) {
out << " discipline<" << discipline_->name() << ">";
}
if (port_set_) {
if (port_msb_ == 0) {
out << " port<scalar>";
@@ -969,7 +994,7 @@ void Module::dump(ostream&out) const
typedef map<pform_name_t,PExpr*>::const_iterator parm_hiter_t;
for (parm_iter_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
out << " parameter ";
out << " parameter " << (*cur).second.type << " ";
if ((*cur).second.signed_flag)
out << "signed ";
if ((*cur).second.msb)
@@ -977,9 +1002,38 @@ void Module::dump(ostream&out) const
<< *(*cur).second.lsb << "] ";
out << (*cur).first << " = ";
if ((*cur).second.expr)
out << *(*cur).second.expr << ";" << endl;
out << *(*cur).second.expr;
else
out << "/* ERROR */;" << endl;
out << "/* ERROR */";
for (Module::range_t*tmp = (*cur).second.range
; tmp ; tmp = tmp->next) {
if (tmp->exclude_flag)
out << " exclude ";
else
out << " from ";
if (tmp->low_open_flag)
out << "(";
else
out << "[";
if (tmp->low_expr)
out << *(tmp->low_expr);
else if (tmp->low_open_flag==false)
out << "-inf";
else
out << "<nil>";
out << ":";
if (tmp->high_expr)
out << *(tmp->high_expr);
else if (tmp->high_open_flag==false)
out << "inf";
else
out << "<nil>";
if (tmp->high_open_flag)
out << ")";
else
out << "]";
}
out << ";" << endl;
}
for (parm_iter_t cur = localparams.begin()
@@ -1123,3 +1177,21 @@ void PUdp::dump(ostream&out) const
out << "endprimitive" << endl;
}
void pform_dump(std::ostream&out, const nature_t*nat)
{
out << "nature " << nat->name() << endl;
out << " access " << nat->access() << ";" << endl;
out << "endnature" << endl;
}
void pform_dump(std::ostream&out, const discipline_t*dis)
{
out << "discipline " << dis->name() << endl;
out << " domain " << dis->domain() << ";" << endl;
if (const nature_t*tmp = dis->potential())
out << " potential " << tmp->name() << ";" << endl;
if (const nature_t*tmp = dis->flow())
out << " flow " << tmp->name() << ";" << endl;
out << "enddiscipline" << endl;
}
+104 -4
View File
@@ -555,6 +555,28 @@ extern "C" unsigned ivl_file_table_size()
return fn_vector.size();
}
extern "C" int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value)
{
if (flag >= net->flags.size()) {
if (value == 0)
return 0;
else
net->flags.resize(flag+1, false);
}
int old_flag = net->flags[flag];
net->flags[flag] = value != 0;
return old_flag;
}
extern "C" int ivl_island_flag_test(ivl_island_t net, unsigned flag)
{
if (flag >= net->flags.size())
return 0;
else
return net->flags[flag];
}
extern "C" const char* ivl_logic_attr(ivl_net_logic_t net, const char*key)
{
assert(net);
@@ -782,7 +804,6 @@ extern "C" unsigned ivl_lpm_base(ivl_lpm_t net)
switch (net->type) {
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
case IVL_LPM_PART_BI:
return net->u_.part.base;
default:
assert(0);
@@ -918,7 +939,6 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
case IVL_LPM_PART_BI:
assert(idx <= 1);
if (idx == 0)
return net->u_.part.a;
@@ -1061,7 +1081,6 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
case IVL_LPM_PART_BI:
assert(idx == 0);
return net->u_.part.q;
@@ -1157,7 +1176,6 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
return 0;
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
case IVL_LPM_PART_BI:
return net->u_.part.signed_flag;
case IVL_LPM_REPEAT:
return 0;
@@ -1338,6 +1356,15 @@ extern "C" ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net)
return net->l.sig;
}
extern "C" ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net)
{
if (net == 0)
return 0;
if (net->type_ != __NEXUS_PTR_SWI)
return 0;
return net->l.swi;
}
extern "C" const char* ivl_parameter_basename(ivl_parameter_t net)
{
assert(net);
@@ -1627,6 +1654,19 @@ extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx)
return net->sigs_[idx];
}
extern "C" unsigned ivl_scope_switches(ivl_scope_t net)
{
assert(net);
return net->switches.size();
}
extern "C" ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx)
{
assert(net);
assert(idx < net->switches.size());
return net->switches[idx];
}
extern "C" int ivl_scope_time_precision(ivl_scope_t net)
{
assert(net);
@@ -2143,3 +2183,63 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
return 0;
}
extern "C" const char*ivl_switch_basename(ivl_switch_t net)
{
return net->name;
}
extern "C" ivl_scope_t ivl_switch_scope(ivl_switch_t net)
{
return net->scope;
}
extern "C" ivl_switch_type_t ivl_switch_type(ivl_switch_t net)
{
return net->type;
}
extern "C" ivl_nexus_t ivl_switch_a(ivl_switch_t net)
{
return net->pins[0];
}
extern "C" ivl_nexus_t ivl_switch_b(ivl_switch_t net)
{
return net->pins[1];
}
extern "C" ivl_nexus_t ivl_switch_enable(ivl_switch_t net)
{
return net->pins[2];
}
extern "C" unsigned ivl_switch_width(ivl_switch_t net)
{
return net->width;
}
extern "C" unsigned ivl_switch_part(ivl_switch_t net)
{
return net->part;
}
extern "C" unsigned ivl_switch_offset(ivl_switch_t net)
{
return net->offset;
}
extern "C" const char* ivl_switch_file(ivl_switch_t net)
{
return net->file;
}
extern "C" ivl_island_t ivl_switch_island(ivl_switch_t net)
{
return net->island;
}
extern "C" unsigned ivl_switch_lineno(ivl_switch_t net)
{
return net->lineno;
}
+80 -31
View File
@@ -380,6 +380,19 @@ static void nexus_lpm_add(ivl_nexus_t nex, ivl_lpm_t net, unsigned pin,
nex->ptrs_[top-1].l.lpm= net;
}
static void nexus_switch_add(ivl_nexus_t nex, ivl_switch_t net, unsigned pin)
{
unsigned top = nex->nptr_ + 1;
nex->ptrs_ = (struct ivl_nexus_ptr_s*)
realloc(nex->ptrs_, top*sizeof(struct ivl_nexus_ptr_s));
nex->nptr_ = top;
nex->ptrs_[top-1].type_= __NEXUS_PTR_SWI;
nex->ptrs_[top-1].drive0 = IVL_DR_HiZ;
nex->ptrs_[top-1].drive1 = IVL_DR_HiZ;
nex->ptrs_[top-1].pin_ = pin;
nex->ptrs_[top-1].l.swi= net;
}
void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net)
{
@@ -431,6 +444,11 @@ static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net)
}
}
static void scope_add_switch(ivl_scope_t scope, ivl_switch_t net)
{
scope->switches.push_back(net);
}
ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope,
const char*name)
{
@@ -470,8 +488,8 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
ivl_parameter_t cur_par = scope->param_ + idx;
cur_par->basename = (*cur_pit).first;
cur_par->scope = scope;
cur_par->file = (*cur_pit).second.file;
cur_par->lineno = (*cur_pit).second.lineno;
cur_par->file = (*cur_pit).second.get_file();
cur_par->lineno = (*cur_pit).second.get_lineno();
NetExpr*etmp = (*cur_pit).second.expr;
make_scope_param_expr(cur_par, etmp);
@@ -484,8 +502,8 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
ivl_parameter_t cur_par = scope->param_ + idx;
cur_par->basename = (*cur_pit).first;
cur_par->scope = scope;
cur_par->file = (*cur_pit).second.file;
cur_par->lineno = (*cur_pit).second.lineno;
cur_par->file = (*cur_pit).second.get_file();
cur_par->lineno = (*cur_pit).second.get_lineno();
NetExpr*etmp = (*cur_pit).second.expr;
make_scope_param_expr(cur_par, etmp);
@@ -621,6 +639,13 @@ int dll_target::end_design(const Design*)
return rc;
}
void dll_target::switch_attributes(struct ivl_switch_s *obj,
const NetNode*net)
{
obj->nattr = net->attr_cnt();
obj->attr = fill_in_attributes(net);
}
void dll_target::logic_attributes(struct ivl_net_logic_s *obj,
const NetNode*net)
{
@@ -1008,6 +1033,56 @@ void dll_target::logic(const NetLogic*net)
scope_add_logic(scope, obj);
}
bool dll_target::tran(const NetTran*net)
{
struct ivl_switch_s*obj = new struct ivl_switch_s;
obj->type = net->type();
obj->width = 0;
obj->part = 0;
obj->offset = 0;
obj->name = net->name();
obj->scope = find_scope(des_, net->scope());
obj->island = net->island;
assert(obj->scope);
assert(obj->island);
const Nexus*nex;
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->pins[0] = nex->t_cookie();
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->pins[1] = nex->t_cookie();
nexus_switch_add(obj->pins[0], obj, 0);
nexus_switch_add(obj->pins[1], obj, 1);
if (net->pin_count() > 2) {
nex = net->pin(2).nexus();
assert(nex->t_cookie());
obj->pins[2] = nex->t_cookie();
nexus_switch_add(obj->pins[2], obj, 2);
} else {
obj->pins[2] = 0;
}
if (obj->type == IVL_SW_TRAN_VP) {
obj->width = net->vector_width();
obj->part = net->part_width();
obj->offset= net->part_offset();
}
obj->file = net->get_file();
obj->lineno = net->get_lineno();
switch_attributes(obj, net);
scope_add_switch(obj->scope, obj);
return true;
}
bool dll_target::sign_extend(const NetSignExtend*net)
{
struct ivl_lpm_s*obj = new struct ivl_lpm_s;
@@ -1930,9 +2005,6 @@ bool dll_target::part_select(const NetPartSelect*net)
case NetPartSelect::PV:
obj->type = IVL_LPM_PART_PV;
break;
case NetPartSelect::BI:
obj->type = IVL_LPM_PART_BI;
break;
}
obj->name = net->name(); // NetPartSelect names are permallocated.
assert(net->scope());
@@ -1986,35 +2058,12 @@ bool dll_target::part_select(const NetPartSelect*net)
obj->u_.part.a = nex->t_cookie();
break;
case IVL_LPM_PART_BI:
/* For now, handle this exactly the same as a PV */
/* NetPartSelect:pin(0) is the output pin. */
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->u_.part.q = nex->t_cookie();
/* NetPartSelect:pin(1) is the input pin. */
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->u_.part.a = nex->t_cookie();
break;
default:
assert(0);
}
nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
/* If the device is a PART_BI, then the "input" is also a
strength aware output, so attach it to the nexus with
strong driver. */
if (obj->type == IVL_LPM_PART_BI)
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
else
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
/* The select input is optional. */
if (obj->u_.part.s)
+31
View File
@@ -21,8 +21,10 @@
# include "target.h"
# include "ivl_target.h"
# include "ivl_target_priv.h"
# include "StringHeap.h"
# include "netlist.h"
# include <vector>
#if defined(__MINGW32__)
#include <windows.h>
@@ -67,6 +69,7 @@ struct dll_target : public target_t, public expr_scan_t {
bool bufz(const NetBUFZ*);
void event(const NetEvent*);
void logic(const NetLogic*);
bool tran(const NetTran*);
bool ureduce(const NetUReduce*);
void net_case_cmp(const NetCaseCmp*);
void udp(const NetUDP*);
@@ -146,6 +149,7 @@ struct dll_target : public target_t, public expr_scan_t {
ivl_scope_t lookup_scope_(const NetScope*scope);
ivl_attribute_s* fill_in_attributes(const Attrib*net);
void switch_attributes(struct ivl_switch_s *obj, const NetNode*net);
void logic_attributes(struct ivl_net_logic_s *obj, const NetNode*net);
private:
@@ -445,6 +449,23 @@ struct ivl_net_logic_s {
ivl_expr_t delay[3];
};
struct ivl_switch_s {
ivl_switch_type_t type;
unsigned width;
unsigned part;
unsigned offset;
perm_string name;
ivl_scope_t scope;
ivl_island_t island;
struct ivl_attribute_s*attr;
unsigned nattr;
ivl_nexus_t pins[3];
perm_string file;
unsigned lineno;
};
/*
* UDP definition.
@@ -481,12 +502,14 @@ struct ivl_nexus_ptr_s {
ivl_net_logic_t log; /* type 1 */
ivl_net_const_t con; /* type 2 */
ivl_lpm_t lpm; /* type 3 */
ivl_switch_t swi; /* type 4 */
} l;
};
# define __NEXUS_PTR_SIG 0
# define __NEXUS_PTR_LOG 1
# define __NEXUS_PTR_CON 2
# define __NEXUS_PTR_LPM 3
# define __NEXUS_PTR_SWI 4
/*
* NOTE: ONLY allocate ivl_nexus_s objects with the included "new" operator.
@@ -567,6 +590,8 @@ struct ivl_scope_s {
unsigned ports;
ivl_signal_t*port;
std::vector<ivl_switch_t>switches;
signed int time_precision :8;
signed int time_units :8;
@@ -730,4 +755,10 @@ static inline void FILE_NAME(ivl_scope_t scope, const NetScope*info)
scope->def_lineno = info->get_def_lineno();
}
static inline void FILE_NAME(ivl_switch_t net, const LineInfo*info)
{
net->file = info->get_file();
net->lineno = info->get_lineno();
}
#endif
+7
View File
@@ -61,6 +61,13 @@ void target_t::logic(const NetLogic*)
"Unhandled logic gate" << endl;
}
bool target_t::tran(const NetTran*)
{
cerr << "target (" << typeid(*this).name() << "): "
<< "TRAN devices not supported." << endl;
return false;
}
bool target_t::bufz(const NetBUFZ*)
{
cerr << "target (" << typeid(*this).name() << "): "
+1
View File
@@ -86,6 +86,7 @@ struct target_t {
/* Output a gate (called for each gate) */
virtual void logic(const NetLogic*);
virtual bool tran(const NetTran*);
virtual bool ureduce(const NetUReduce*); /* unary reduction operator */
virtual bool bufz(const NetBUFZ*);
virtual void udp(const NetUDP*);
+3 -4
View File
@@ -16,12 +16,9 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.11 2004/02/10 19:25:01 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.0
VERSION = 0.9.devel
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -44,6 +41,8 @@ LDFLAGS = @LDFLAGS@
all: dep null.tgt
check: all
dep:
mkdir dep
+4 -5
View File
@@ -16,12 +16,9 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.20 2007/02/06 05:07:32 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.0
VERSION = 0.9.devel
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -44,6 +41,8 @@ LDFLAGS = @LDFLAGS@
all: dep stub.tgt
check: all
dep:
mkdir dep
@@ -51,7 +50,7 @@ dep:
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = stub.o expression.o statement.o
O = stub.o expression.o statement.o switches.o
ifeq (@WIN32@,yes)
TGTLDFLAGS=-L.. -livl
+11
View File
@@ -35,6 +35,15 @@ extern FILE*out;
*/
extern int stub_errors;
/*
* This function finds the vector width of a signal. It relies on the
* assumption that all the signal inputs to the nexus have the same
* width. The ivl_target API should assert that condition.
*/
extern unsigned width_of_nexus(ivl_nexus_t nex);
extern ivl_variable_type_t type_of_nexus(ivl_nexus_t nex);
/*
* Show the details of the expression.
*/
@@ -45,6 +54,8 @@ extern void show_expression(ivl_expr_t net, unsigned ind);
*/
extern void show_statement(ivl_statement_t net, unsigned ind);
extern void show_switch(ivl_switch_t net);
/*
*/
extern const char*data_type_string(ivl_variable_type_t vtype);
+1 -1
View File
@@ -288,7 +288,7 @@ void show_statement(ivl_statement_t net, unsigned ind)
break;
case IVL_ST_DELAY:
fprintf(out, "%*s#%llu\n", ind, "", ivl_stmt_delay_val(net));
fprintf(out, "%*s#%" PRIu64 "\n", ind, "", ivl_stmt_delay_val(net));
show_statement(ivl_stmt_sub_stmt(net), ind+2);
break;
+9 -37
View File
@@ -555,38 +555,6 @@ static void show_lpm_part(ivl_lpm_t net)
}
}
static void show_lpm_part_bi(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
unsigned base = ivl_lpm_base(net);
ivl_nexus_t port_p = ivl_lpm_q(net,0);
ivl_nexus_t port_v = ivl_lpm_data(net,0);
fprintf(out, " LPM_PART_BI %s: <width=%u, base=%u, signed=%d>\n",
ivl_lpm_basename(net), width, base, ivl_lpm_signed(net));
fprintf(out, " P: %s\n", ivl_nexus_name(port_p));
fprintf(out, " V: %s <width=%u>\n", ivl_nexus_name(port_v),
width_of_nexus(port_v));
/* The data(0) port must be large enough for the part select. */
if (width_of_nexus(ivl_lpm_data(net,0)) < (width+base)) {
fprintf(out, " ERROR: Part select is out of range."
" Data nexus width=%u, width+base=%u\n",
width_of_nexus(ivl_lpm_data(net,0)), width+base);
stub_errors += 1;
}
/* The Q vector must be exactly the width of the part select. */
if (width_of_nexus(ivl_lpm_q(net,0)) != width) {
fprintf(out, " ERROR: Part select input mismatch."
" Nexus width=%u, expect width=%u\n",
width_of_nexus(ivl_lpm_q(net,0)), width);
stub_errors += 1;
}
}
/*
* The reduction operators have similar characteristics and are
* displayed here.
@@ -905,11 +873,6 @@ static void show_lpm(ivl_lpm_t net)
show_lpm_part(net);
break;
/* The BI part select is slightly special. */
case IVL_LPM_PART_BI:
show_lpm_part_bi(net);
break;
case IVL_LPM_REPEAT:
show_lpm_repeat(net);
break;
@@ -1059,6 +1022,7 @@ static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
ivl_net_logic_t log;
ivl_lpm_t lpm;
ivl_signal_t sig;
ivl_switch_t swt;
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
const char*dr0 = str_tab[ivl_nexus_ptr_drive0(ptr)];
@@ -1092,6 +1056,11 @@ static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
ivl_scope_name(ivl_lpm_scope(lpm)),
ivl_lpm_basename(lpm), dr0, dr1);
} else if ((swt = ivl_nexus_ptr_switch(ptr))) {
fprintf(out, " SWITCH %s.%s\n",
ivl_scope_name(ivl_switch_scope(swt)),
ivl_switch_basename(swt));
} else if ((con = ivl_nexus_ptr_con(ptr))) {
signal_nexus_const(net, ptr, con);
@@ -1478,6 +1447,9 @@ static int show_scope(ivl_scope_t net, void*x)
for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1)
show_lpm(ivl_scope_lpm(net, idx));
for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1)
show_switch(ivl_scope_switch(net, idx));
switch (ivl_scope_type(net)) {
case IVL_SCT_FUNCTION:
case IVL_SCT_TASK:
+124
View File
@@ -0,0 +1,124 @@
/*
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include "priv.h"
# include <stdlib.h>
# include <inttypes.h>
# include <assert.h>
void show_switch(ivl_switch_t net)
{
const char*name = ivl_switch_basename(net);
int has_enable = 0;
switch (ivl_switch_type(net)) {
case IVL_SW_TRAN:
fprintf(out, " tran %s", name);
break;
case IVL_SW_RTRAN:
fprintf(out, " rtran %s", name);
break;
case IVL_SW_TRANIF0:
fprintf(out, " tranif0 %s", name);
has_enable = 1;
break;
case IVL_SW_RTRANIF0:
fprintf(out, " rtranif0 %s", name);
has_enable = 1;
break;
case IVL_SW_TRANIF1:
fprintf(out, " tranif1 %s", name);
has_enable = 1;
break;
case IVL_SW_RTRANIF1:
fprintf(out, " rtranif1 %s", name);
has_enable = 1;
break;
case IVL_SW_TRAN_VP:
fprintf(out, " tran(VP wid=%u, part=%u, off=%u) %s",
ivl_switch_width(net), ivl_switch_part(net),
ivl_switch_offset(net), name);
break;
}
fprintf(out, " island=%p\n", ivl_switch_island(net));
ivl_nexus_t nexa = ivl_switch_a(net);
const char*nex_name = nexa? ivl_nexus_name(nexa) : "";
ivl_variable_type_t nex_type_a = nexa? type_of_nexus(nexa) : IVL_VT_NO_TYPE;
fprintf(out, " A: %s <type=%s>\n", nex_name, data_type_string(nex_type_a));
ivl_nexus_t nexb = ivl_switch_b(net);
nex_name = nexb? ivl_nexus_name(nexb) : "";
ivl_variable_type_t nex_type_b = nexb? type_of_nexus(nexb) : IVL_VT_NO_TYPE;
fprintf(out, " B: %s <type=%s>\n", nex_name, data_type_string(nex_type_b));
/* The A/B pins of the switch must be present, and must match. */
if (nex_type_a == IVL_VT_NO_TYPE) {
fprintf(out, " A: ERROR: Type missing for pin A\n");
stub_errors += 1;
}
if (nex_type_b == IVL_VT_NO_TYPE) {
fprintf(out, " B: ERROR: Type missing for pin B\n");
stub_errors += 1;
}
if (nex_type_a != nex_type_b) {
fprintf(out, " A/B: ERROR: Type mismatch between pins A and B\n");
stub_errors += 1;
}
if (ivl_switch_type(net) == IVL_SW_TRAN_VP) {
/* The TRAN_VP nodes are special in that the specific
width matters for each port and should be exactly
right for both. */
if (width_of_nexus(nexa) != ivl_switch_width(net)) {
fprintf(out, " A: ERROR: part vector nexus "
"width=%u, expecting width=%u\n",
width_of_nexus(nexa), ivl_switch_width(net));
stub_errors += 1;
}
if (width_of_nexus(nexb) != ivl_switch_part(net)) {
fprintf(out, " B: ERROR: part select nexus "
"width=%u, expecting width=%u\n",
width_of_nexus(nexb), ivl_switch_part(net));
stub_errors += 1;
}
} else {
/* All other TRAN nodes will have matching vector
widths, but the actual value doesn't matter. */
if (width_of_nexus(nexa) != width_of_nexus(nexb)) {
fprintf(out, " A/B: ERROR: Width of ports don't match"
": A=%u, B=%u\n",
width_of_nexus(nexa), width_of_nexus(nexb));
stub_errors += 1;
}
}
if (has_enable) {
ivl_nexus_t nexe = ivl_switch_enable(net);
nex_name = nexe? ivl_nexus_name(nexe) : "";
fprintf(out, " E: %s\n", nex_name);
if (width_of_nexus(nexe) != 1) {
fprintf(out, " E: ERROR: Nexus width is %u\n",
width_of_nexus(nexe));
}
}
}
+2 -1
View File
@@ -51,7 +51,8 @@ dep:
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = vvp.o draw_mux.o draw_ufunc.o draw_vpi.o eval_bool.o eval_expr.o \
O = vvp.o draw_mux.o draw_net_input.o draw_switch.o draw_ufunc.o draw_vpi.o \
eval_bool.o eval_expr.o \
eval_real.o modpath.o vector.o \
vvp_process.o vvp_scope.o
+687
View File
@@ -0,0 +1,687 @@
/*
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "vvp_priv.h"
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <stdlib.h>
# include <math.h>
# include <string.h>
# include <inttypes.h>
# include <assert.h>
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
#define snprintf _snprintf
#endif
static ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex)
{
unsigned idx;
ivl_signal_type_t out = IVL_SIT_TRI;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_signal_type_t stype;
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
if (sig == 0)
continue;
stype = ivl_signal_type(sig);
if (stype == IVL_SIT_REG)
continue;
if (stype == IVL_SIT_TRI)
continue;
if (stype == IVL_SIT_NONE)
continue;
out = stype;
}
return out;
}
static void draw_C4_repeated_constant(char bit_char, unsigned width)
{
unsigned idx;
fprintf(vvp_out, "C4<");
for (idx = 0 ; idx < width ; idx += 1)
fprintf(vvp_out, "%c", bit_char);
fprintf(vvp_out, ">");
}
static char* draw_C4_to_string(ivl_net_const_t cptr)
{
const char*bits = ivl_const_bits(cptr);
unsigned idx;
size_t result_len = 5 + ivl_const_width(cptr);
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
char bitchar = bits[ivl_const_width(cptr)-idx-1];
*dp++ = bitchar;
assert((dp - result) < result_len);
}
strcpy(dp, ">");
return result;
}
static char* draw_C8_to_string(ivl_net_const_t cptr,
ivl_drive_t dr0, ivl_drive_t dr1)
{
size_t nresult = 5 + 3*ivl_const_width(cptr);
char*result = malloc(nresult);
const char*bits = ivl_const_bits(cptr);
unsigned idx;
char dr0c = "01234567"[dr0];
char dr1c = "01234567"[dr1];
char*dp = result;
strcpy(dp, "C8<");
dp += strlen(dp);
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
switch (bits[ivl_const_width(cptr)-idx-1]) {
case '0':
*dp++ = dr0c;
*dp++ = dr0c;
*dp++ = '0';
break;
case '1':
*dp++ = dr1c;
*dp++ = dr1c;
*dp++ = '1';
break;
case 'x':
case 'X':
*dp++ = dr0c;
*dp++ = dr1c;
*dp++ = 'x';
break;
case 'z':
case 'Z':
*dp++ = '0';
*dp++ = '0';
*dp++ = 'z';
break;
default:
assert(0);
break;
}
assert(dp - result < nresult);
}
strcpy(dp, ">");
return result;
}
static struct vvp_nexus_data*new_nexus_data()
{
struct vvp_nexus_data*data = calloc(1, sizeof(struct vvp_nexus_data));
return data;
}
static int nexus_drive_is_strength_aware(ivl_nexus_ptr_t nptr)
{
if (ivl_nexus_ptr_drive0(nptr) != IVL_DR_STRONG)
return 1;
if (ivl_nexus_ptr_drive1(nptr) != IVL_DR_STRONG)
return 1;
ivl_net_logic_t log = ivl_nexus_ptr_log(nptr);
if (log != 0) {
/* These logic gates are able to generate unusual
strength values and so their outputs are considered
strength aware. */
if (ivl_logic_type(log) == IVL_LO_BUFIF0)
return 1;
if (ivl_logic_type(log) == IVL_LO_BUFIF1)
return 1;
if (ivl_logic_type(log) == IVL_LO_PMOS)
return 1;
if (ivl_logic_type(log) == IVL_LO_NMOS)
return 1;
if (ivl_logic_type(log) == IVL_LO_CMOS)
return 1;
}
return 0;
}
/*
* Given a nexus, look for a signal that has module delay
* paths. Return that signal. (There should be no more than 1.) If we
* don't find any, then return nil.
*/
static ivl_signal_t find_modpath(ivl_nexus_t nex)
{
unsigned idx;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx);
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
if (sig == 0)
continue;
if (ivl_signal_npath(sig) == 0)
continue;
return sig;
}
return 0;
}
static void str_repeat(char*buf, const char*str, unsigned rpt)
{
unsigned idx;
size_t len = strlen(str);
for (idx = 0 ; idx < rpt ; idx += 1) {
strcpy(buf, str);
buf += len;
}
}
/*
* This function takes a nexus and looks for an input functor. It then
* draws to the output a string that represents that functor. What we
* are trying to do here is find the input to the net that is attached
* to this nexus.
*/
static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
{
unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
ivl_net_const_t cptr;
ivl_net_logic_t lptr;
ivl_signal_t sptr;
ivl_lpm_t lpm;
lptr = ivl_nexus_ptr_log(nptr);
if (lptr && (ivl_logic_type(lptr) == IVL_LO_BUFZ) && (nptr_pin == 0))
do {
if (! can_elide_bufz(lptr, nptr))
break;
return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
} while(0);
/* If this is a pulldown device, then there is a single pin
that drives a constant value to the entire width of the
vector. The driver normally drives a pull0 value, so a C8<>
constant is appropriate, but if the drive is really strong,
then we can draw a C4<> constant instead. */
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
size_t result_len = ivl_logic_width(lptr) + 5;
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
str_repeat(dp, "0", ivl_logic_width(lptr));
dp += ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
} else {
char val[4];
size_t result_len = 3*ivl_logic_width(lptr) + 5;
char*result = malloc(result_len);
char*dp = result;
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
val[1] = val[0];
val[2] = '0';
val[3] = 0;
strcpy(dp, "C8<");
dp += strlen(dp);
str_repeat(dp, val, ivl_logic_width(lptr));
dp += 3*ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
}
}
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
size_t result_len = 5 + ivl_logic_width(lptr);
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
str_repeat(dp, "1", ivl_logic_width(lptr));
dp += ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
} else {
char val[4];
size_t result_len = 5 + 3*ivl_logic_width(lptr);
char*result = malloc(result_len);
char*dp = result;
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
val[1] = val[0];
val[2] = '1';
val[3] = 0;
strcpy(dp, "C8<");
dp += strlen(dp);
str_repeat(dp, val, ivl_logic_width(lptr));
dp += 3*ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
}
}
if (lptr && (nptr_pin == 0)) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", lptr);
return strdup(tmp);
}
sptr = ivl_nexus_ptr_sig(nptr);
if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
char tmp[128];
/* Input is a .var. This device may be a non-zero pin
because it may be an array of reg vectors. */
snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);
if (ivl_signal_array_count(sptr) > 1) {
fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
sptr, nptr_pin, sptr, nptr_pin);
}
return strdup(tmp);
}
cptr = ivl_nexus_ptr_con(nptr);
if (cptr) {
/* Constants should have exactly 1 pin, with a literal value. */
assert(nptr_pin == 0);
char *result = 0;
switch (ivl_const_type(cptr)) {
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {
result = draw_C4_to_string(cptr);
} else {
result = draw_C8_to_string(cptr,
ivl_nexus_ptr_drive0(nptr),
ivl_nexus_ptr_drive1(nptr));
}
break;
case IVL_VT_REAL:
result = draw_Cr_to_string(ivl_const_real(cptr));
break;
default:
assert(0);
break;
}
ivl_expr_t d_rise = ivl_const_delay(cptr, 0);
ivl_expr_t d_fall = ivl_const_delay(cptr, 1);
ivl_expr_t d_decay = ivl_const_delay(cptr, 2);
/* We have a delayed constant, so we need to build some code. */
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64));
assert(number_is_immediate(d_fall, 64));
assert(number_is_immediate(d_decay, 64));
fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, "
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
cptr, get_number_immediate(d_rise),
get_number_immediate(d_rise),
get_number_immediate(d_rise), cptr);
free(result);
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", cptr);
result = strdup(tmp);
}
return result;
}
lpm = ivl_nexus_ptr_lpm(nptr);
if (lpm) switch (ivl_lpm_type(lpm)) {
case IVL_LPM_FF:
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_ARRAY:
case IVL_LPM_CONCAT:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_GE:
case IVL_LPM_CMP_GT:
case IVL_LPM_CMP_NE:
case IVL_LPM_CMP_NEE:
case IVL_LPM_RE_AND:
case IVL_LPM_RE_OR:
case IVL_LPM_RE_XOR:
case IVL_LPM_RE_NAND:
case IVL_LPM_RE_NOR:
case IVL_LPM_RE_XNOR:
case IVL_LPM_SFUNC:
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
case IVL_LPM_SIGN_EXT:
case IVL_LPM_SUB:
case IVL_LPM_MULT:
case IVL_LPM_MUX:
case IVL_LPM_POW:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_UFUNC:
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
case IVL_LPM_REPEAT:
if (ivl_lpm_q(lpm, 0) == nex) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", lpm);
return strdup(tmp);
}
break;
}
fprintf(stderr, "internal error: no input to nexus %s\n",
ivl_nexus_name(nex));
assert(0);
return strdup("C<z>");
}
static char* draw_island_port(ivl_island_t island,
ivl_nexus_t nex, const char*src)
{
char result[64];
if (ivl_island_flag_test(island,0) == 0) {
fprintf(vvp_out, "I%p .island tran;\n", island);
ivl_island_flag_set(island,0,1);
}
fprintf(vvp_out, "p%p .port I%p, %s;\n", nex, island, src);
snprintf(result, sizeof result, "p%p", nex);
return strdup(result);
}
/*
* This function draws the input to a net into a string. What that
* means is that it returns a static string that can be used to
* represent a resolved driver to a nexus. If there are multiple
* drivers to the nexus, then it writes out the resolver declarations
* needed to perform strength resolution.
*
* The string that this returns is malloced, and that means that the
* caller must free the string or store it permanently. This function
* does *not* check for a previously calculated string. Use the
* draw_net_input for the general case.
*/
/* Omit LPMPART_BI device pin-data(0) drivers. */
# define OMIT_PART_BI_DATA 0x0001
char* draw_net_input_x(ivl_nexus_t nex,
ivl_nexus_ptr_t omit_ptr, int omit_flags,
struct vvp_nexus_data*nex_data)
{
ivl_island_t island = 0;
ivl_signal_type_t res;
char result[512];
unsigned idx;
int level;
unsigned ndrivers = 0;
static ivl_nexus_ptr_t *drivers = 0x0;
static unsigned adrivers = 0;
const char*resolv_type;
char*nex_private = 0;
/* Accumulate nex_data flags. */
int nex_flags = 0;
res = signal_type_of_nexus(nex);
switch (res) {
case IVL_SIT_TRI:
resolv_type = "tri";
break;
case IVL_SIT_TRI0:
resolv_type = "tri0";
nex_flags |= VVP_NEXUS_DATA_STR;
break;
case IVL_SIT_TRI1:
resolv_type = "tri1";
nex_flags |= VVP_NEXUS_DATA_STR;
break;
case IVL_SIT_TRIAND:
resolv_type = "triand";
break;
case IVL_SIT_TRIOR:
resolv_type = "trior";
break;
default:
fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res);
assert(0);
resolv_type = "tri";
break;
}
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_lpm_t lpm_tmp;
ivl_switch_t sw = 0;
ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
/* If this object is part of an island, then we'll be
making a port. Save the island cookie. */
if ( (sw = ivl_nexus_ptr_switch(nptr)) ) {
island = ivl_switch_island(sw);
}
/* If we are supposed to skip LPM_PART_BI data pins,
check that this driver is that. */
if ((omit_flags&OMIT_PART_BI_DATA)
&& (lpm_tmp = ivl_nexus_ptr_lpm(nptr))
&& (nex == ivl_lpm_data(lpm_tmp,0)))
continue;
if (nptr == omit_ptr)
continue;
/* Skip input only pins. */
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
continue;
/* Mark the strength-aware flag if the driver can
generate values other than the standard "6"
strength. */
if (nexus_drive_is_strength_aware(nptr))
nex_flags |= VVP_NEXUS_DATA_STR;
/* Save this driver. */
if (ndrivers >= adrivers) {
adrivers += 4;
drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
assert(drivers);
}
drivers[ndrivers] = nptr;
ndrivers += 1;
}
/* If the caller is collecting nexus information, then save
the nexus driver count in the nex_data. */
if (nex_data) {
nex_data->drivers_count = ndrivers;
nex_data->flags |= nex_flags;
}
/* If the nexus has no drivers, then send a constant HiZ into
the net. */
if (ndrivers == 0) {
unsigned idx, wid = width_of_nexus(nex);
char*tmp = malloc(wid + 5);
nex_private = tmp;
strcpy(tmp, "C4<");
tmp += strlen(tmp);
switch (res) {
case IVL_SIT_TRI:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = 'z';
break;
case IVL_SIT_TRI0:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = '0';
break;
case IVL_SIT_TRI1:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = '1';
break;
default:
assert(0);
}
*tmp++ = '>';
*tmp = 0;
if (island) {
char*tmp = draw_island_port(island, nex, nex_private);
free(nex_private);
nex_private = tmp;
}
return nex_private;
}
/* If the nexus has exactly one driver, then simply draw
it. Note that this will *not* work if the nexus is not a
TRI type nexus. */
if (ndrivers == 1 && res == IVL_SIT_TRI) {
ivl_signal_t path_sig = find_modpath(nex);
if (path_sig) {
char*nex_str = draw_net_input_drive(nex, drivers[0]);
char modpath_label[64];
snprintf(modpath_label, sizeof modpath_label,
"V_%p/m", path_sig);
nex_private = strdup(modpath_label);
draw_modpath(path_sig, nex_str);
} else {
nex_private = draw_net_input_drive(nex, drivers[0]);
}
if (island) {
char*tmp = draw_island_port(island, nex, nex_private);
free(nex_private);
nex_private = tmp;
}
return nex_private;
}
level = 0;
while (ndrivers) {
unsigned int inst;
for (inst = 0; inst < ndrivers; inst += 4) {
if (ndrivers > 4)
fprintf(vvp_out, "RS_%p/%d/%d .resolv tri",
nex, level, inst);
else
fprintf(vvp_out, "RS_%p .resolv %s",
nex, resolv_type);
for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) {
if (level) {
fprintf(vvp_out, ", RS_%p/%d/%d",
nex, level - 1, idx*4);
} else {
char*drive = draw_net_input_drive(nex, drivers[idx]);
fprintf(vvp_out, ", %s", drive);
free(drive);
}
}
for ( ; idx < inst+4 ; idx += 1) {
fprintf(vvp_out, ", ");
draw_C4_repeated_constant('z',width_of_nexus(nex));
}
fprintf(vvp_out, ";\n");
}
if (ndrivers > 4)
ndrivers = (ndrivers+3) / 4;
else
ndrivers = 0;
level += 1;
}
snprintf(result, sizeof result, "RS_%p", nex);
if (island)
nex_private = draw_island_port(island, nex, result);
else
nex_private = strdup(result);
return nex_private;
}
/*
* Get a cached description of the nexus input, or create one if this
* nexus has not been cached yet. This is a wrapper for the common
* case call to draw_net_input_x.
*/
const char*draw_net_input(ivl_nexus_t nex)
{
struct vvp_nexus_data*nex_data = (struct vvp_nexus_data*)
ivl_nexus_get_private(nex);
/* If this nexus already has a label, then its input is
already figured out. Just return the existing label. */
if (nex_data && nex_data->net_input)
return nex_data->net_input;
if (nex_data == 0) {
nex_data = new_nexus_data();
ivl_nexus_set_private(nex, nex_data);
}
assert(nex_data->net_input == 0);
nex_data->net_input = draw_net_input_x(nex, 0, 0, nex_data);
return nex_data->net_input;
}
+81
View File
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "vvp_priv.h"
# include <assert.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <stdlib.h>
# include <string.h>
static void draw_tran_island(ivl_island_t island)
{
fprintf(vvp_out, "I%p .island tran;\n", island);
ivl_island_flag_set(island, 0, 1);
}
void draw_switch_in_scope(ivl_switch_t sw)
{
ivl_island_t island = ivl_switch_island(sw);
if (ivl_island_flag_test(island, 0) == 0)
draw_tran_island(island);
ivl_nexus_t nex_a = ivl_switch_a(sw);
assert(nex_a);
const char*str_a = draw_net_input(nex_a);
ivl_nexus_t nex_b = ivl_switch_b(sw);
assert(nex_b);
const char*str_b = draw_net_input(nex_b);
ivl_nexus_t enable = ivl_switch_enable(sw);
const char*str_e = 0;
if (enable)
str_e = draw_net_input(enable);
switch (ivl_switch_type(sw)) {
case IVL_SW_TRAN:
fprintf(vvp_out, " .tran");
break;
case IVL_SW_TRANIF0:
fprintf(vvp_out, " .tranif0");
break;
case IVL_SW_TRANIF1:
fprintf(vvp_out, " .tranif1");
break;
case IVL_SW_TRAN_VP:
fprintf(vvp_out, " .tranvp %u %u %u,",
ivl_switch_width(sw), ivl_switch_part(sw), ivl_switch_offset(sw));
break;
default:
fprintf(stderr, "%s:%u: sorry: vvp target does not support switch modeling.\n",
ivl_switch_file(sw), ivl_switch_lineno(sw));
vvp_errors += 1;
return;
}
fprintf(vvp_out, " I%p, %s %s", island, str_a, str_b);
if (enable)
fprintf(vvp_out, ", %s", str_e);
fprintf(vvp_out, ";\n");
}
+124 -4
View File
@@ -25,6 +25,86 @@
# include <stdlib.h>
# include <assert.h>
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
#define snprintf _snprintf
#endif
/*
* Check to see if the expression (number) can be correctly represented
* with a long variable.
*/
static int is_constant_number(ivl_expr_t ex)
{
/* Make sure this matches the return type of constant_number(). */
unsigned lim_wid = 8*sizeof(long);
const char*bits;
char pad_bit = '0';
unsigned idx;
unsigned nbits = ivl_expr_width(ex);
if (ivl_expr_type(ex) != IVL_EX_NUMBER
&& ivl_expr_type(ex) != IVL_EX_ULONG)
return 0;
bits = ivl_expr_bits(ex);
/* For unsigned values the effective MSB and on must be '0'. */
if (!ivl_expr_signed(ex)) lim_wid -= 1;
/* For negative values the pad bit is '1'. */
if (ivl_expr_signed(ex) && bits[nbits-1]=='1') {
pad_bit = '1';
}
/* For the number to fit in the variable all the upper bits must
* match the pad bits. */
for (idx = lim_wid ; idx < nbits ; idx += 1) {
if (bits[idx] != pad_bit) return 0;
}
return 1;
}
/*
* Convert the expression (number) to a long value.
*/
static long get_constant_number(ivl_expr_t ex)
{
long rtn = 0;
switch (ivl_expr_type(ex)) {
case IVL_EX_ULONG:
rtn = (signed)ivl_expr_value(ex);
break;
case IVL_EX_NUMBER: {
unsigned idx;
const char*bits = ivl_expr_bits(ex);
unsigned nbits = ivl_expr_width(ex);
char pad_bit = bits[nbits-1];
/* Define all the bits in the long (negative numbers). */
for (idx = 0 ; idx < 8*sizeof(long) ; idx += 1) {
char bit;
if (idx < nbits) bit = bits[idx];
else bit = pad_bit;
switch (bit) {
case '0':
break;
case '1':
rtn |= 1 << idx;
break;
default:
assert(0);
}
}
break;
}
default:
assert(0);
}
return rtn;
}
static const char* magic_sfuncs[] = {
"$time",
"$stime",
@@ -205,14 +285,54 @@ static void draw_vpi_taskfunc_args(const char*call_string,
word_ex = 0;
}
}
if (word_ex)
break;
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
if (word_ex) {
struct vector_info av;
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
snprintf(buffer, sizeof buffer,
"&A<v%p, T<%u,%u,u>>", sig, av.base, av.wid);
args[idx].vec = av;
args[idx].vec_flag = 1;
} else {
snprintf(buffer, sizeof buffer,
"&A<v%p, %u>", sig, use_word);
}
args[idx].text = strdup(buffer);
continue;
}
case IVL_EX_SELECT: {
ivl_expr_t vexpr = ivl_expr_oper1(expr);
assert(vexpr);
/* This code is only for signals. */
if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL) break;
/* The signal is part of an array. */
/* Add &APV<> code here when it is finished. */
if (ivl_expr_oper1(vexpr)) break;
ivl_expr_t bexpr = ivl_expr_oper2(expr);
assert(bexpr);
/* This is a constant bit/part select. */
if (is_constant_number(bexpr)) {
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
ivl_expr_signal(vexpr),
get_constant_number(bexpr),
ivl_expr_width(expr));
/* This is an indexed bit/part select. */
} else {
struct vector_info rv;
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>",
ivl_expr_signal(vexpr),
rv.base, rv.wid,
ivl_expr_width(expr));
}
args[idx].text = strdup(buffer);
continue;
}
/* Everything else will need to be evaluated and
passed as a constant to the vpi task. */
default:
+111 -35
View File
@@ -92,7 +92,8 @@ unsigned long get_number_immediate(ivl_expr_t ex)
case '0':
break;
case '1':
imm |= 1 << idx;
assert(idx < 8*sizeof(imm));
imm |= 1UL << idx;
break;
default:
assert(0);
@@ -909,12 +910,43 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
return lv;
}
static struct vector_info draw_logic_immediate(ivl_expr_t exp,
ivl_expr_t le,
ivl_expr_t re,
unsigned wid)
{
struct vector_info lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
unsigned long imm = get_number_immediate(re);
assert(lv.base >= 4);
switch (ivl_expr_opcode(exp)) {
case '&':
fprintf(vvp_out, " %%andi %u, %lu, %u;\n", lv.base, imm, lv.wid);
break;
default:
assert(0);
break;
}
return lv;
}
static struct vector_info draw_binary_expr_logic(ivl_expr_t exp,
unsigned wid)
{
ivl_expr_t le = ivl_expr_oper1(exp);
ivl_expr_t re = ivl_expr_oper2(exp);
if (ivl_expr_opcode(exp) == '&') {
if (number_is_immediate(re, IMM_WID) && !number_is_unknown(re))
return draw_logic_immediate(exp, le, re, wid);
if (number_is_immediate(le, IMM_WID) && !number_is_unknown(le))
return draw_logic_immediate(exp, re, le, wid);
}
struct vector_info lv;
struct vector_info rv;
@@ -1166,23 +1198,50 @@ static struct vector_info draw_add_immediate(ivl_expr_t le,
imm = get_number_immediate(re);
/* Now generate enough %addi instructions to add the entire
immediate value to the destination. The adds are done 16
bits at a time, but 17 bits are done to push the carry into
the higher bits if needed. */
{ unsigned base;
for (base = 0 ; base < lv.wid ; base += 16) {
unsigned long tmp = imm & 0xffffUL;
unsigned add_wid = lv.wid - base;
/* This shouldn't generally happen, because the elaborator
should take care of simple constant propagation like this,
but it doesn't have to and it is easy to catch here. */
if (imm == 0)
return lv;
imm >>= 16;
switch (lv.base) {
case 0: /* Left expression is 0. */
lv.base = allocate_vector(wid);
if (lv.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of addition.\n",
ivl_expr_file(re), ivl_expr_lineno(re), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid);
break;
fprintf(vvp_out, " %%addi %u, %lu, %u;\n",
lv.base+base, tmp, add_wid);
case 1: /* Left expression is 1...1 (i.e. -1) */
imm -= 1;
if (imm == 0) {
lv.base = 0;
} else {
lv.base = allocate_vector(wid);
if (lv.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of addition.\n",
ivl_expr_file(re), ivl_expr_lineno(re), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid);
}
break;
if (imm == 0)
break;
}
case 2: /* Left expression is X or Z */
case 3:
lv.base = 2;
break;
default: /* The regular case. */
fprintf(vvp_out, " %%addi %u, %lu, %u;\n", lv.base, imm, wid);
break;
}
return lv;
@@ -1203,7 +1262,8 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
assert(lv.wid == wid);
imm = get_number_immediate(re);
assert( (imm & ~0xffff) == 0 );
if (imm == 0)
return lv;
switch (lv.base) {
case 0:
@@ -1217,21 +1277,21 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid);
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid);
lv.base = tmp;
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
return lv;
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
break;
case 2:
case 3:
lv.base = 2;
return lv;
break;
default:
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
break;
}
return lv;
}
@@ -1246,8 +1306,10 @@ static struct vector_info draw_mul_immediate(ivl_expr_t le,
assert(lv.wid == wid);
imm = get_number_immediate(re);
if (imm == 0)
return lv;
fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid);
fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid);
return lv;
}
@@ -1299,13 +1361,13 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
if ((ivl_expr_opcode(exp) == '-')
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
&& (! number_is_unknown(re))
&& number_is_immediate(re, 16))
&& number_is_immediate(re, IMM_WID))
return draw_sub_immediate(le, re, wid);
if ((ivl_expr_opcode(exp) == '*')
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
&& (! number_is_unknown(re))
&& number_is_immediate(re, 16))
&& number_is_immediate(re, IMM_WID))
return draw_mul_immediate(le, re, wid);
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
@@ -1612,9 +1674,9 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
vvp_errors += 1;
}
if ((!number_is_unknown(exp)) && number_is_immediate(exp, 16)) {
int val = get_number_immediate(exp);
fprintf(vvp_out, " %%movi %u, %d, %u;\n", res.base, val, wid);
if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID)) {
unsigned long val = get_number_immediate(exp);
fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid);
return res;
}
@@ -1836,8 +1898,8 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid)
idx = 0;
while (idx < nwid) {
unsigned bits;
unsigned trans = 16;
if (nwid-idx < 16)
unsigned trans = IMM_WID;
if (nwid-idx < trans)
trans = nwid-idx;
bits = *p;
@@ -1845,6 +1907,14 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid)
if (trans > 8) {
bits |= *p << 8;
p -= 1;
if (trans > 16) {
bits |= *p << 16;
p -= 1;
if (trans > 24) {
bits |= *p << 24;
p -= 1;
}
}
}
fprintf(vvp_out, " %%movi %u, %u, %u;\n", res.base+idx,bits,trans);
@@ -1881,8 +1951,14 @@ void pad_expr_in_place(ivl_expr_t exp, struct vector_info res, unsigned swid)
res.base+idx, res.base+swid-1);
} else {
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
res.base+swid, res.wid-swid);
unsigned base = res.base+swid;
unsigned count = res.wid-swid;
/* The %movi is faster for larger widths, but for very
small counts, the %mov is faster. */
if (count > 4)
fprintf(vvp_out, " %%movi %u, 0, %u;\n", base, count);
else
fprintf(vvp_out, " %%mov %u, 0, %u;\n", base, count);
}
}
@@ -2086,7 +2162,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
for (idx = 0 ; idx < res.wid ; idx += 1) {
if (idx >= bit_wid) {
fprintf(vvp_out, " %%mov %u, 0, %u; Pad from %u to %u\n",
fprintf(vvp_out, " %%movi %u, 0, %u; Pad from %u to %u\n",
res.base+idx, res.wid-idx,
ivl_expr_width(sube), wid);
break;
@@ -2410,7 +2486,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, res.base, res.wid);
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
tmp.base+res.wid, tmp.wid-res.wid);
clr_vector(res);
res = tmp;
@@ -2460,7 +2536,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
assert(res.base);
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, res.base, res.wid);
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
tmp.base+res.wid, tmp.wid-res.wid);
clr_vector(res);
res = tmp;
+4
View File
@@ -22,6 +22,10 @@
# include <stdlib.h>
# include <assert.h>
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
#define snprintf _snprintf
#endif
static ivl_signal_t find_path_source_port(ivl_delaypath_t path)
{
int idx;
+40 -1
View File
@@ -1,7 +1,7 @@
#ifndef __vvp_priv_H
#define __vvp_priv_H
/*
* Copyright (c) 2001-2005 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -39,12 +39,20 @@ struct vector_info {
unsigned wid;
};
/*
* Convenient constants...
*/
/* Width limit for typical immediate arguments. */
# define IMM_WID 32
/*
* Mangle all non-symbol characters in an identifier, quotes in names
*/
extern const char *vvp_mangle_id(const char *);
extern const char *vvp_mangle_name(const char *);
extern char* draw_Cr_to_string(double value);
/*
* This generates a string from a signal that uniquely identifies
* that signal with letters that can be used in a label.
@@ -59,6 +67,8 @@ extern const char* vvp_signal_label(ivl_signal_t sig);
extern unsigned width_of_nexus(ivl_nexus_t nex);
extern ivl_variable_type_t data_type_of_nexus(ivl_nexus_t nex);
extern int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr);
/*
* This function draws a process (initial or always) into the output
* file. It normally returns 0, but returns !0 of there is some sort
@@ -104,6 +114,24 @@ extern struct vector_info draw_vpi_func_call(ivl_expr_t exp,
unsigned wid);
extern int draw_vpi_rfunc_call(ivl_expr_t exp);
/*
* Switches (tran)
*/
extern void draw_switch_in_scope(ivl_switch_t sw);
/* Draw_net_input and friends uses this. */
struct vvp_nexus_data {
/* draw_net_input uses this */
const char*net_input;
unsigned drivers_count;
int flags;
/* draw_net_in_scope uses these to identify the controlling word. */
ivl_signal_t net;
unsigned net_word;
};
#define VVP_NEXUS_DATA_STR 0x0001
/*
* Given a nexus, draw a string that represents the functor output
* that feeds the nexus. This function can be used to get the input to
@@ -114,6 +142,17 @@ extern int draw_vpi_rfunc_call(ivl_expr_t exp);
*/
extern const char* draw_net_input(ivl_nexus_t nex);
/*
* See draw_net_input.c for details on draw_net_input_x. (It would be
* nice if this can be made private.)
*/
/* Omit LPMPART_BI device pin-data(0) drivers. */
# define OMIT_PART_BI_DATA 0x0001
struct vvp_nexus_data;
extern char* draw_net_input_x(ivl_nexus_t nex,
ivl_nexus_ptr_t omit_ptr, int omit_flags,
struct vvp_nexus_data*nex_data);
/*
* This function is different from draw_net_input in that it will
* return a reference to a net as its first choice. This reference
+14 -731
View File
@@ -27,24 +27,11 @@
# include <inttypes.h>
# include <assert.h>
struct vvp_nexus_data {
/* draw_net_input uses this */
const char*net_input;
unsigned drivers_count;
int flags;
/* draw_net_in_scope uses these to identify the controlling word. */
ivl_signal_t net;
unsigned net_word;
};
#define VVP_NEXUS_DATA_STR 0x0001
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
#define snprintf _snprintf
#endif
static struct vvp_nexus_data*new_nexus_data()
{
struct vvp_nexus_data*data = calloc(1, sizeof(struct vvp_nexus_data));
return data;
}
/*
* Escape non-symbol characters in ids, and quotes in strings.
*/
@@ -143,27 +130,6 @@ const char *vvp_mangle_name(const char *id)
return out;
}
static void draw_C4_repeated_constant(char bit_char, unsigned width)
{
unsigned idx;
fprintf(vvp_out, "C4<");
for (idx = 0 ; idx < width ; idx += 1)
fprintf(vvp_out, "%c", bit_char);
fprintf(vvp_out, ">");
}
static void str_repeat(char*buf, const char*str, unsigned rpt)
{
unsigned idx;
size_t len = strlen(str);
for (idx = 0 ; idx < rpt ; idx += 1) {
strcpy(buf, str);
buf += len;
}
}
/* REMOVE ME: vvp_signal_label should not be used. DEAD CODE
* Given a signal, generate a string name that is suitable for use as
* a label. The only rule is that the same signal will always have the
@@ -194,31 +160,6 @@ ivl_signal_t signal_of_nexus(ivl_nexus_t nex, unsigned*word)
return 0;
}
ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex)
{
unsigned idx;
ivl_signal_type_t out = IVL_SIT_TRI;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_signal_type_t stype;
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
if (sig == 0)
continue;
stype = ivl_signal_type(sig);
if (stype == IVL_SIT_REG)
continue;
if (stype == IVL_SIT_TRI)
continue;
if (stype == IVL_SIT_NONE)
continue;
out = stype;
}
return out;
}
unsigned width_of_nexus(ivl_nexus_t nex)
{
unsigned idx;
@@ -328,7 +269,7 @@ const char*drive_string(ivl_drive_t drive)
* gate will be generated for this node. Otherwise, the code generator
* will connect its input to its output and skip the gate.
*/
static int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
{
ivl_nexus_t in_n;
unsigned idx;
@@ -376,100 +317,7 @@ static int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
return 1;
}
/*
* Given a nexus, look for a signal that has module delay
* paths. Return that signal. (There should be no more than 1.) If we
* don't find any, then return nil.
*/
static ivl_signal_t find_modpath(ivl_nexus_t nex)
{
unsigned idx;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx);
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
if (sig == 0)
continue;
if (ivl_signal_npath(sig) == 0)
continue;
return sig;
}
return 0;
}
static char* draw_C4_to_string(ivl_net_const_t cptr)
{
const char*bits = ivl_const_bits(cptr);
unsigned idx;
size_t result_len = 5 + ivl_const_width(cptr);
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
char bitchar = bits[ivl_const_width(cptr)-idx-1];
*dp++ = bitchar;
assert((dp - result) < result_len);
}
strcpy(dp, ">");
return result;
}
static char* draw_C8_to_string(ivl_net_const_t cptr,
ivl_drive_t dr0, ivl_drive_t dr1)
{
size_t nresult = 5 + 3*ivl_const_width(cptr);
char*result = malloc(nresult);
const char*bits = ivl_const_bits(cptr);
unsigned idx;
char dr0c = "01234567"[dr0];
char dr1c = "01234567"[dr1];
char*dp = result;
strcpy(dp, "C8<");
dp += strlen(dp);
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
switch (bits[ivl_const_width(cptr)-idx-1]) {
case '0':
*dp++ = dr0c;
*dp++ = dr0c;
*dp++ = '0';
break;
case '1':
*dp++ = dr1c;
*dp++ = dr1c;
*dp++ = '1';
break;
case 'x':
case 'X':
*dp++ = dr0c;
*dp++ = dr1c;
*dp++ = 'x';
break;
case 'z':
case 'Z':
*dp++ = '0';
*dp++ = '0';
*dp++ = 'z';
break;
default:
assert(0);
break;
}
assert(dp - result < nresult);
}
strcpy(dp, ">");
return result;
}
static char* draw_Cr_to_string(double value)
char* draw_Cr_to_string(double value)
{
char tmp[256];
@@ -504,488 +352,6 @@ static char* draw_Cr_to_string(double value)
return strdup(tmp);
}
/*
* This function takes a nexus and looks for an input functor. It then
* draws to the output a string that represents that functor. What we
* are trying to do here is find the input to the net that is attached
* to this nexus.
*/
static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
{
unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
ivl_net_const_t cptr;
ivl_net_logic_t lptr;
ivl_signal_t sptr;
ivl_lpm_t lpm;
lptr = ivl_nexus_ptr_log(nptr);
if (lptr && (ivl_logic_type(lptr) == IVL_LO_BUFZ) && (nptr_pin == 0))
do {
if (! can_elide_bufz(lptr, nptr))
break;
return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
} while(0);
/* If this is a pulldown device, then there is a single pin
that drives a constant value to the entire width of the
vector. The driver normally drives a pull0 value, so a C8<>
constant is appropriate, but if the drive is really strong,
then we can draw a C4<> constant instead. */
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
size_t result_len = ivl_logic_width(lptr) + 5;
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
str_repeat(dp, "0", ivl_logic_width(lptr));
dp += ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
} else {
char val[4];
size_t result_len = 3*ivl_logic_width(lptr) + 5;
char*result = malloc(result_len);
char*dp = result;
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
val[1] = val[0];
val[2] = '0';
val[3] = 0;
strcpy(dp, "C8<");
dp += strlen(dp);
str_repeat(dp, val, ivl_logic_width(lptr));
dp += 3*ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
}
}
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
size_t result_len = 5 + ivl_logic_width(lptr);
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
str_repeat(dp, "1", ivl_logic_width(lptr));
dp += ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
} else {
char val[4];
size_t result_len = 5 + 3*ivl_logic_width(lptr);
char*result = malloc(result_len);
char*dp = result;
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
val[1] = val[0];
val[2] = '1';
val[3] = 0;
strcpy(dp, "C8<");
dp += strlen(dp);
str_repeat(dp, val, ivl_logic_width(lptr));
dp += 3*ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
}
}
if (lptr && (nptr_pin == 0)) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", lptr);
return strdup(tmp);
}
sptr = ivl_nexus_ptr_sig(nptr);
if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
char tmp[128];
/* Input is a .var. This device may be a non-zero pin
because it may be an array of reg vectors. */
snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);
if (ivl_signal_array_count(sptr) > 1) {
fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
sptr, nptr_pin, sptr, nptr_pin);
}
return strdup(tmp);
}
cptr = ivl_nexus_ptr_con(nptr);
if (cptr) {
/* Constants should have exactly 1 pin, with a literal value. */
assert(nptr_pin == 0);
char *result = 0;
switch (ivl_const_type(cptr)) {
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {
result = draw_C4_to_string(cptr);
} else {
result = draw_C8_to_string(cptr,
ivl_nexus_ptr_drive0(nptr),
ivl_nexus_ptr_drive1(nptr));
}
break;
case IVL_VT_REAL:
result = draw_Cr_to_string(ivl_const_real(cptr));
break;
default:
assert(0);
break;
}
ivl_expr_t d_rise = ivl_const_delay(cptr, 0);
ivl_expr_t d_fall = ivl_const_delay(cptr, 1);
ivl_expr_t d_decay = ivl_const_delay(cptr, 2);
/* We have a delayed constant, so we need to build some code. */
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64));
assert(number_is_immediate(d_fall, 64));
assert(number_is_immediate(d_decay, 64));
fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, "
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
cptr, get_number_immediate(d_rise),
get_number_immediate(d_rise),
get_number_immediate(d_rise), cptr);
free(result);
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", cptr);
result = strdup(tmp);
}
return result;
}
lpm = ivl_nexus_ptr_lpm(nptr);
if (lpm) switch (ivl_lpm_type(lpm)) {
case IVL_LPM_FF:
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_ARRAY:
case IVL_LPM_CONCAT:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_GE:
case IVL_LPM_CMP_GT:
case IVL_LPM_CMP_NE:
case IVL_LPM_CMP_NEE:
case IVL_LPM_RE_AND:
case IVL_LPM_RE_OR:
case IVL_LPM_RE_XOR:
case IVL_LPM_RE_NAND:
case IVL_LPM_RE_NOR:
case IVL_LPM_RE_XNOR:
case IVL_LPM_SFUNC:
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
case IVL_LPM_SIGN_EXT:
case IVL_LPM_SUB:
case IVL_LPM_MULT:
case IVL_LPM_MUX:
case IVL_LPM_POW:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_UFUNC:
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
case IVL_LPM_REPEAT:
if (ivl_lpm_q(lpm, 0) == nex) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", lpm);
return strdup(tmp);
}
break;
case IVL_LPM_PART_BI:
if (ivl_lpm_q(lpm, 0) == nex) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p/P", lpm);
return strdup(tmp);
} else if (ivl_lpm_data(lpm,0) == nex) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p/V", lpm);
return strdup(tmp);
}
break;
}
fprintf(stderr, "internal error: no input to nexus %s\n",
ivl_nexus_name(nex));
assert(0);
return strdup("C<z>");
}
static int nexus_drive_is_strength_aware(ivl_nexus_ptr_t nptr)
{
if (ivl_nexus_ptr_drive0(nptr) != IVL_DR_STRONG)
return 1;
if (ivl_nexus_ptr_drive1(nptr) != IVL_DR_STRONG)
return 1;
ivl_net_logic_t log = ivl_nexus_ptr_log(nptr);
if (log != 0) {
/* These logic gates are able to generate unusual
strength values and so their outputs are considered
strength aware. */
if (ivl_logic_type(log) == IVL_LO_BUFIF0)
return 1;
if (ivl_logic_type(log) == IVL_LO_BUFIF1)
return 1;
if (ivl_logic_type(log) == IVL_LO_PMOS)
return 1;
if (ivl_logic_type(log) == IVL_LO_NMOS)
return 1;
if (ivl_logic_type(log) == IVL_LO_CMOS)
return 1;
}
return 0;
}
/*
* This function draws the input to a net into a string. What that
* means is that it returns a static string that can be used to
* represent a resolved driver to a nexus. If there are multiple
* drivers to the nexus, then it writes out the resolver declarations
* needed to perform strength resolution.
*
* The string that this returns is malloced, and that means that the
* caller must free the string or store it permanently. This function
* does *not* check for a previously calculated string. Use the
* draw_net_input for the general case.
*/
/* Omit LPMPART_BI device pin-data(0) drivers. */
# define OMIT_PART_BI_DATA 0x0001
static char* draw_net_input_x(ivl_nexus_t nex,
ivl_nexus_ptr_t omit_ptr, int omit_flags,
struct vvp_nexus_data*nex_data)
{
ivl_signal_type_t res;
char result[512];
unsigned idx;
int level;
unsigned ndrivers = 0;
static ivl_nexus_ptr_t *drivers = 0x0;
static unsigned adrivers = 0;
const char*resolv_type;
char*nex_private = 0;
/* Accumulate nex_data flags. */
int nex_flags = 0;
res = signal_type_of_nexus(nex);
switch (res) {
case IVL_SIT_TRI:
resolv_type = "tri";
break;
case IVL_SIT_TRI0:
resolv_type = "tri0";
nex_flags |= VVP_NEXUS_DATA_STR;
break;
case IVL_SIT_TRI1:
resolv_type = "tri1";
nex_flags |= VVP_NEXUS_DATA_STR;
break;
case IVL_SIT_TRIAND:
resolv_type = "triand";
break;
case IVL_SIT_TRIOR:
resolv_type = "trior";
break;
default:
fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res);
assert(0);
resolv_type = "tri";
break;
}
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_lpm_t lpm_tmp;
ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
/* If we are supposed to skip LPM_PART_BI data pins,
check that this driver is that. */
if ((omit_flags&OMIT_PART_BI_DATA)
&& (lpm_tmp = ivl_nexus_ptr_lpm(nptr))
&& (nex == ivl_lpm_data(lpm_tmp,0)))
continue;
if (nptr == omit_ptr)
continue;
/* Skip input only pins. */
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
continue;
/* Mark the strength-aware flag if the driver can
generate values other than the standard "6"
strength. */
if (nexus_drive_is_strength_aware(nptr))
nex_flags |= VVP_NEXUS_DATA_STR;
/* Save this driver. */
if (ndrivers >= adrivers) {
adrivers += 4;
drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
assert(drivers);
}
drivers[ndrivers] = nptr;
ndrivers += 1;
}
/* If the caller is collecting nexus information, then save
the nexus driver count in the nex_data. */
if (nex_data) {
nex_data->drivers_count = ndrivers;
nex_data->flags |= nex_flags;
}
/* If the nexus has no drivers, then send a constant HiZ into
the net. */
if (ndrivers == 0) {
unsigned idx, wid = width_of_nexus(nex);
char*tmp = malloc(wid + 5);
nex_private = tmp;
strcpy(tmp, "C4<");
tmp += strlen(tmp);
switch (res) {
case IVL_SIT_TRI:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = 'z';
break;
case IVL_SIT_TRI0:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = '0';
break;
case IVL_SIT_TRI1:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = '1';
break;
default:
assert(0);
}
*tmp++ = '>';
*tmp = 0;
return nex_private;
}
/* If the nexus has exactly one driver, then simply draw
it. Note that this will *not* work if the nexus is not a
TRI type nexus. */
if (ndrivers == 1 && res == IVL_SIT_TRI) {
ivl_signal_t path_sig = find_modpath(nex);
if (path_sig) {
char*nex_str = draw_net_input_drive(nex, drivers[0]);
char modpath_label[64];
snprintf(modpath_label, sizeof modpath_label,
"V_%p/m", path_sig);
nex_private = strdup(modpath_label);
draw_modpath(path_sig, nex_str);
} else {
nex_private = draw_net_input_drive(nex, drivers[0]);
}
return nex_private;
}
level = 0;
while (ndrivers) {
unsigned int inst;
for (inst = 0; inst < ndrivers; inst += 4) {
if (ndrivers > 4)
fprintf(vvp_out, "RS_%p/%d/%d .resolv tri",
nex, level, inst);
else
fprintf(vvp_out, "RS_%p .resolv %s",
nex, resolv_type);
for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) {
if (level) {
fprintf(vvp_out, ", RS_%p/%d/%d",
nex, level - 1, idx*4);
} else {
char*drive = draw_net_input_drive(nex, drivers[idx]);
fprintf(vvp_out, ", %s", drive);
free(drive);
}
}
for ( ; idx < inst+4 ; idx += 1) {
fprintf(vvp_out, ", ");
draw_C4_repeated_constant('z',width_of_nexus(nex));
}
fprintf(vvp_out, ";\n");
}
if (ndrivers > 4)
ndrivers = (ndrivers+3) / 4;
else
ndrivers = 0;
level += 1;
}
sprintf(result, "RS_%p", nex);
nex_private = strdup(result);
return nex_private;
}
/*
* Get a cached description of the nexus input, or create one if this
* nexus has not been cached yet. This is a wrapper for the common
* case call to draw_net_input_x.
*/
const char*draw_net_input(ivl_nexus_t nex)
{
struct vvp_nexus_data*nex_data = (struct vvp_nexus_data*)
ivl_nexus_get_private(nex);
/* If this nexus already has a label, then its input is
already figured out. Just return the existing label. */
if (nex_data && nex_data->net_input)
return nex_data->net_input;
if (nex_data == 0) {
nex_data = new_nexus_data();
ivl_nexus_set_private(nex, nex_data);
}
assert(nex_data->net_input == 0);
nex_data->net_input = draw_net_input_x(nex, 0, 0, nex_data);
return nex_data->net_input;
}
const char*draw_input_from_net(ivl_nexus_t nex)
{
static char result[32];
@@ -1767,7 +1133,11 @@ static void draw_lpm_add(ivl_lpm_t net)
type = "pow.s";
if (width > 8*sizeof(long)) {
fprintf(stderr, "%s:%u: sorry (vvp-tgt): Signed power "
#ifdef __MINGW32__ /* MinGW does not know about z. */
"result must be no more than %u bits.\n",
#else
"result must be no more than %zu bits.\n",
#endif
ivl_lpm_file(net), ivl_lpm_lineno(net),
8*sizeof(long));
exit(1);
@@ -2241,94 +1611,6 @@ static void draw_lpm_part_pv(ivl_lpm_t net)
fprintf(vvp_out, ", %u, %u, %u;\n", base, width, signal_width);
}
/*
* Handle the drawing of a bi-directional part select. The two ports
* are simultaneously input and output. A simple minded connect of the
* input to the output causes a functor cycle which will lock into an
* X value, so something special is needed.
*
* NOTE: The inputs of the tran device at this point need to be from
* all the drivers of the nexus *except* the tran itself. This
* function will draw three labels that can be linked:
*
* The ivl_lpm_q of a part(bi) may be a smaller vector then the
* ivl_lpm_data, the tran acts like a forward part select in that
* way.
*
* The device creates these nodes:
*
* - L_%p/i
* This is the Q port of the tran resolved and padded to the maximum
* width of the tran. The tran itself is not included in the
* resolution of this port.
*
* - L_%p/V
* This is the Q and D parts resolved together, still without the tran
* driving anything.
*
* - L_%p/P
* This is the /V node part-selected back to the dimensions of the Q
* side.
*/
static void draw_lpm_part_bi(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
unsigned base = ivl_lpm_base(net);
unsigned signal_width = width_of_nexus(ivl_lpm_data(net,0));
unsigned idx;
ivl_nexus_t nex;
ivl_nexus_ptr_t ptr = 0;
char*p_str;
char*v_str;
/* It seems implausible that the two inputs of a tran will be
connected together. So assert that this is so to simplify
the code to look for the nexus_ptr_t objects. */
assert(ivl_lpm_q(net,0) != ivl_lpm_data(net,0));
nex = ivl_lpm_q(net,0);
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ptr = ivl_nexus_ptr(nex, idx);
if (ivl_nexus_ptr_lpm(ptr) == net)
break;
}
assert(ptr != 0);
p_str = draw_net_input_x(nex, ptr, 0, 0);
nex = ivl_lpm_data(net,0);
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ptr = ivl_nexus_ptr(nex, idx);
if (ivl_nexus_ptr_lpm(ptr) == net)
break;
}
v_str = draw_net_input_x(nex, ptr, OMIT_PART_BI_DATA, 0);
/* Pad the part-sized input out to a common width...
The /i label is the Q side of the tran, resolved except for
the tran itself and padded (with z) to the larger width. */
fprintf(vvp_out, "L_%p/i .part/pv %s, %u, %u, %u;\n",
net, p_str, base, width, signal_width);
/* Resolve together the two halves of the tran...
The /V label is the ports of the tran (now the same width)
resolved together. Neither input to this resolver includes
the tran itself. */
fprintf(vvp_out, "L_%p/V .resolv tri, L_%p/i, %s;\n",
net, net, v_str);
/* The full-width side is created by the tran device, all we
have left to to is take a part select of that for the
smaller output, and this becomes the part select output of
the BI device. */
fprintf(vvp_out, "L_%p/P .part L_%p/V, %u, %u;\n", net,
net, base, width);
free(p_str);
free(v_str);
}
/*
* Draw unary reduction devices.
*/
@@ -2375,10 +1657,6 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
draw_lpm_array(net);
return;
case IVL_LPM_PART_BI:
draw_lpm_part_bi(net);
return;
case IVL_LPM_PART_VP:
draw_lpm_part(net);
return;
@@ -2561,6 +1839,11 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
draw_lpm_in_scope(lpm);
}
for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1) {
ivl_switch_t sw = ivl_scope_switch(net, idx);
draw_switch_in_scope(sw);
}
if (ivl_scope_type(net) == IVL_SCT_TASK)
draw_task_definition(net);
+1 -15
View File
@@ -564,25 +564,11 @@ ostream& operator<< (ostream&o, const verinum&v)
output. */
if (v.has_len()) {
o << v.len();
if (v.has_sign())
o << "'sb";
else
o << "'b";
if (v.len() == 0) {
o << "0";
return o;
}
for (unsigned idx = v.len() ; idx > 0 ; idx -= 1)
o << v[idx-1];
return o;
}
/* If the number is fully defined (no x or z) then print it
out as a decimal number. */
if (v.is_defined() && v.len() < sizeof(long)) {
if (v.is_defined() && v.len() < 8*sizeof(long)) {
if (v.has_sign())
o << "'sd" << v.as_long();
else
+6 -6
View File
@@ -16,12 +16,9 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.61 2007/02/06 05:07:32 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.0
VERSION = 0.9.devel
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -48,6 +45,8 @@ LDFLAGS = @LDFLAGS@
all: dep system.vpi va_math.vpi $(ALL32)
check: all
dep:
mkdir dep
@@ -60,7 +59,8 @@ O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_fileio.o \
sys_finish.o sys_icarus.o sys_plusargs.o sys_random.o sys_random_mti.o \
sys_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \
sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o \
mt19937int.o priv.o sdf_lexor.o sdf_parse.o stringheap.o
mt19937int.o sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o \
vams_simparam.o
ifeq (@HAVE_LIBZ@,yes)
ifeq (@HAVE_LIBBZ2@,yes)
@@ -75,7 +75,7 @@ V = va_math.o
LIBS = @LIBS@
SYSTEM_VPI_LDFLAGS = $(LIBS)
VA_MATH_LDFLAGS =
ifeq (@MING32@,yes)
ifeq (@MINGW32@,yes)
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
VA_MATH_LDFLAGS += @EXTRALIBS@
endif
+10 -18
View File
@@ -60,16 +60,6 @@ struct strobe_cb_info {
unsigned mcd;
};
int is_constant(vpiHandle obj)
{
if (vpi_get(vpiType, obj) == vpiConstant)
return vpiConstant;
if (vpi_get(vpiType, obj) == vpiParameter)
return vpiParameter;
return 0;
}
// The number of decimal digits needed to represent a
// nr_bits binary number is floor(nr_bits*log_10(2))+1,
// where log_10(2) = 0.30102999566398.... and I approximate
@@ -665,7 +655,7 @@ static int format_str_char(vpiHandle scope, unsigned int mcd,
return 0;
}
if (is_constant(argv[idx])
if (is_constant_obj(argv[idx])
&& (vpi_get(vpiConstType, argv[idx]) == vpiRealConst)) {
value.format = vpiRealVal;
@@ -827,6 +817,7 @@ static void do_display(unsigned int mcd, struct strobe_cb_info*info)
case vpiReg:
case vpiIntegerVar:
case vpiMemoryWord:
case vpiPartSelect:
do_display_numeric(mcd, info, item);
break;
@@ -1118,11 +1109,16 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) {
switch (vpi_get(vpiType, monitor_info.items[idx])) {
case vpiMemoryWord:
/*
* We only support constant selections. Make this
* better when we add a real compiletf routine.
*/
assert(vpi_get(vpiConstantSelect, monitor_info.items[idx]));
case vpiNet:
case vpiReg:
case vpiIntegerVar:
case vpiRealVar:
case vpiMemoryWord:
/* Monitoring reg and net values involves setting
a callback for value changes. Pass the storage
pointer for the callback itself as user_data so
@@ -1836,6 +1832,7 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info)
case vpiReg:
case vpiIntegerVar:
case vpiMemoryWord:
case vpiPartSelect:
width = get_numeric(&result, info, item);
rtn = realloc(rtn, (size+width)*sizeof(char));
memcpy(rtn+size-1, result, width);
@@ -2185,12 +2182,7 @@ static PLI_INT32 sys_printtimescale_calltf(PLI_BYTE8*xx)
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle scope;
if (!argv) {
vpiHandle parent = vpi_handle(vpiScope, sys);
scope = NULL; /* fallback value if parent is NULL */
while (parent) {
scope = parent;
parent = vpi_handle(vpiScope, scope);
}
scope = sys_func_module(sys);
} else {
scope = vpi_scan(argv);
vpi_free_object(argv);
+2 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,9 +16,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: sys_fileio.c,v 1.10 2007/03/14 04:05:51 steve Exp $"
#endif
# include "vpi_user.h"
# include "sys_priv.h"
@@ -60,7 +57,7 @@ static PLI_INT32 sys_fopen_compiletf(PLI_BYTE8*name)
return 0;
}
if (! is_constant(item)) {
if (! is_constant_obj(item)) {
vpi_printf("ERROR: %s mode argument must be a constant\n", name);
vpi_control(vpiFinish, 1);
}
@@ -918,4 +915,3 @@ void sys_fileio_register()
vpi_register_systf(&tf_data);
}
+9 -81
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,44 +16,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: sys_finish.c,v 1.11 2007/04/09 22:49:33 steve Exp $"
#endif
# include "vpi_config.h"
# include "vpi_user.h"
# include <string.h>
static PLI_INT32 sys_finish_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
/* The argument is optional. */
if (argv == 0) return 0;
arg = vpi_scan(argv);
/* A string diagnostic message level makes no sense. */
if (vpi_get(vpiType, arg) == vpiConstant &&
vpi_get(vpiConstType, arg) == vpiStringConst) {
vpi_printf("Error: %s does not take a string argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
/* These functions take at most one argument (diagnostic message). */
arg = vpi_scan(argv);
if (arg != 0) {
vpi_printf("Error: %s takes at most one argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
/* vpi_scan returning 0 (NULL) has already freed argv. */
return 0;
}
#include "vpi_config.h"
#include "vpi_user.h"
#include "sys_priv.h"
#include <string.h>
static PLI_INT32 sys_finish_calltf(PLI_BYTE8 *name)
{
@@ -88,55 +55,16 @@ void sys_finish_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$finish";
tf_data.calltf = sys_finish_calltf;
tf_data.compiletf = sys_finish_compiletf;
tf_data.compiletf = sys_one_opt_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = (PLI_BYTE8*)"$finish";
tf_data.user_data = "$finish";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$stop";
tf_data.calltf = sys_finish_calltf;
tf_data.compiletf = sys_finish_compiletf;
tf_data.compiletf = sys_one_opt_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = (PLI_BYTE8*)"$stop";
tf_data.user_data = "$stop";
vpi_register_systf(&tf_data);
}
/*
* $Log: sys_finish.c,v $
* Revision 1.11 2007/04/09 22:49:33 steve
* More strict use of PLI_BYTE8 type.
*
* Revision 1.10 2006/10/30 22:45:37 steve
* Updates for Cygwin portability (pr1585922)
*
* Revision 1.9 2004/01/21 01:22:53 steve
* Give the vip directory its own configure and vpi_config.h
*
* Revision 1.8 2003/02/21 03:24:03 steve
* Make the $stop system task really vpiStop.
*
* Revision 1.7 2002/08/12 01:35:04 steve
* conditional ident string using autoconfig.
*
* Revision 1.6 2001/07/25 03:10:50 steve
* Create a config.h.in file to hold all the config
* junk, and support gcc 3.0. (Stephan Boettcher)
*
* Revision 1.5 2001/01/01 19:33:44 steve
* Add $stop that does a finish.
*
* Revision 1.4 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/08/28 02:10:44 steve
* Call the right vpiFinish code.
*
* Revision 1.2 1999/08/19 02:51:03 steve
* Add vpi_sim_control
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
+19 -27
View File
@@ -16,38 +16,32 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "vpi_config.h"
#include <assert.h>
#include <vpi_user.h>
#include "sys_priv.h"
/*
* Routine to return the width in bits of a CPU word (long).
*/
static PLI_INT32 vvp_cpu_wordsize_calltf(PLI_BYTE8* ud)
static PLI_INT32 finish_and_return_calltf(PLI_BYTE8* name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
assert(callh != 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
s_vpi_value val;
(void) ud; /* Not used! */
(void) name; /* Not used! */
/* Calculate the result */
/* Get the return value. */
arg = vpi_scan(argv);
vpi_free_object(argv);
val.format = vpiIntVal;
val.value.integer = 8*sizeof(long);
vpi_get_value(arg, &val);
/* Return the result */
vpi_put_value(callh, &val, 0, vpiNoDelay);
/* Set the return value. */
vpip_set_return_value(val.value.integer);
/* Now finish. */
vpi_control(vpiFinish, 1);
return 0;
}
static PLI_INT32 size_32(PLI_BYTE8* ud)
{
(void) ud; /* Not used! */
return 32;
}
/*
* Register the function with Verilog.
*/
@@ -55,13 +49,11 @@ void sys_special_register(void)
{
s_vpi_systf_data tf_data;
/* Register the single argument functions. */
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc;
tf_data.calltf = vvp_cpu_wordsize_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = size_32;
tf_data.tfname = "$vvp_cpu_wordsize";
tf_data.user_data = 0;
tf_data.type = vpiSysTask;
tf_data.calltf = finish_and_return_calltf;
tf_data.compiletf = sys_one_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.tfname = "$finish_and_return";
tf_data.user_data = "$finish_and_return";
vpi_register_systf(&tf_data);
}
+28 -55
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,9 +16,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: sys_lxt.c,v 1.28 2007/03/14 04:05:51 steve Exp $"
#endif
# include "sys_priv.h"
# include "lxt_write.h"
@@ -324,9 +321,9 @@ inline static int install_dumpvars_callback(void)
return 0;
if (dumpvars_status == 2) {
vpi_mcd_printf(1, "LXT warning:" " $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
vpi_printf("LXT warning: $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
return 1;
}
@@ -431,22 +428,23 @@ static void *close_dumpfile(void)
return (dump_file = NULL);
}
static void open_dumpfile(void)
static void open_dumpfile(vpiHandle callh)
{
if (dump_path == 0) dump_path = strdup("dump.lxt");
dump_file = lt_init(dump_path);
if (dump_file == 0) {
vpi_mcd_printf(1, "LXT Error: Unable to open %s for output.\n",
dump_path);
vpi_printf("LXT Error: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Unable to open %s for output.\n", dump_path);
vpi_control(vpiFinish, 1);
return;
} else {
int prec = vpi_get(vpiTimePrecision, 0);
vpi_mcd_printf(1, "LXT info: dumpfile %s opened for output.\n",
dump_path);
vpi_printf("LXT info: dumpfile %s opened for output.\n",
dump_path);
assert(prec >= -15);
lt_set_timescale(dump_file, prec);
@@ -468,9 +466,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
/* $dumpfile must be called before $dumpvars starts! */
if (dumpvars_status != 0) {
vpi_mcd_printf(1, "LXT warning: %s called after $dumpvars started"
",\n using existing file (%s).\n",
name, dump_path);
vpi_printf("LXT warning: %s called after $dumpvars started,\n"
" using existing file (%s).\n",
name, dump_path);
return 0;
}
@@ -480,8 +478,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
path = strdup(value.value.str);
if (dump_path) {
vpi_mcd_printf(1, "LXT warning: Overriding dump file %s with"
" %s\n", dump_path, path);
vpi_printf("LXT warning: Overriding dump file %s with %s\n",
dump_path, path);
free(dump_path);
}
dump_path = path;
@@ -542,16 +540,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
switch (vpi_get(vpiType, item)) {
case vpiMemory:
/* don't know how to watch memories. */
break;
case vpiNamedEvent:
/* There is nothing in named events to dump. */
break;
case vpiNet: type = "wire"; if(0){
case vpiIntegerVar:
case vpiMemoryWord:
case vpiTimeVar:
case vpiReg: type = "reg"; }
@@ -644,18 +635,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
vpi_get_str(vpiFullName, item);
#if 0
vpi_mcd_printf(1,
"LXT info:"
" scanning scope %s, %u levels\n",
fullname, depth);
vpi_printf("LXT info: scanning scope %s, %u levels\n",
fullname, depth);
#endif
nskip = 0 != vcd_names_search(&lxt_tab, fullname);
if (!nskip)
vcd_names_add(&lxt_tab, fullname);
else
vpi_mcd_printf(1, "LXT warning: ignoring signals in"
" previously scanned scope %s\n", fullname);
vpi_printf("LXT warning: ignoring signals in "
"previously scanned scope %s\n", fullname);
name = vpi_get_str(vpiName, item);
@@ -674,8 +663,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
break;
default:
vpi_mcd_printf(1, "LXT warning: $dumpvars: Unsupported parameter"
" type (%d)\n", vpi_get(vpiType, item));
vpi_printf("LXT warning: $dumpvars: Unsupported parameter "
"type (%s)\n", vpi_get_str(vpiType, item));
}
}
@@ -684,7 +673,6 @@ static int draw_scope(vpiHandle item)
{
int depth;
const char *name;
// char *type; // Not needed, see below.
vpiHandle scope = vpi_handle(vpiScope, item);
if (!scope)
@@ -693,20 +681,6 @@ static int draw_scope(vpiHandle item)
depth = 1 + draw_scope(scope);
name = vpi_get_str(vpiName, scope);
#if 0 /* The type information is not needed by the LXT dumper. */
switch (vpi_get(vpiType, scope)) {
case vpiNamedBegin: type = "begin"; break;
case vpiTask: type = "task"; break;
case vpiFunction: type = "function"; break;
case vpiNamedFork: type = "fork"; break;
case vpiModule: type = "module"; break;
default:
vpi_mcd_printf(1, "LXT Error: $dumpvars: Unsupported scope "
"type (%d)\n", vpi_get(vpiType, item));
assert(0);
}
#endif
push_scope(name);
return depth;
@@ -721,7 +695,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
unsigned depth = 0;
if (dump_file == 0) {
open_dumpfile();
open_dumpfile(callh);
if (dump_file == 0) return 0;
}
@@ -784,7 +758,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpall";
tf_data.calltf = sys_dumpall_calltf;
tf_data.compiletf = sys_dumpall_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpall";
vpi_register_systf(&tf_data);
@@ -800,7 +774,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpflush";
tf_data.calltf = sys_dumpflush_calltf;
tf_data.compiletf = sys_dumpflush_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpflush";
vpi_register_systf(&tf_data);
@@ -808,7 +782,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
tf_data.calltf = sys_dumplimit_calltf;
tf_data.compiletf = sys_dumplimit_compiletf;
tf_data.compiletf = sys_one_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumplimit";
vpi_register_systf(&tf_data);
@@ -816,7 +790,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpoff";
tf_data.calltf = sys_dumpoff_calltf;
tf_data.compiletf = sys_dumpoff_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpoff";
vpi_register_systf(&tf_data);
@@ -824,7 +798,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpon";
tf_data.calltf = sys_dumpon_calltf;
tf_data.compiletf = sys_dumpon_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpon";
vpi_register_systf(&tf_data);
@@ -837,4 +811,3 @@ void sys_lxt_register()
tf_data.user_data = "$dumpvars";
vpi_register_systf(&tf_data);
}
+28 -55
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2004 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,9 +16,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: sys_lxt2.c,v 1.10 2007/03/14 04:05:51 steve Exp $"
#endif
# include "sys_priv.h"
# include "lxt2_write.h"
@@ -322,9 +319,9 @@ inline static int install_dumpvars_callback(void)
if (dumpvars_status == 1) return 0;
if (dumpvars_status == 2) {
vpi_mcd_printf(1, "LXT2 warning: $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
vpi_printf("LXT2 warning: $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
return 1;
}
@@ -429,22 +426,23 @@ static void *close_dumpfile(void)
return 0;
}
static void open_dumpfile(void)
static void open_dumpfile(vpiHandle callh)
{
if (dump_path == 0) dump_path = strdup("dump.lx2");
dump_file = lxt2_wr_init(dump_path);
if (dump_file == 0) {
vpi_mcd_printf(1, "LXT2 Error: Unable to open %s for output.\n",
dump_path);
vpi_printf("LXT2 Error: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Unable to open %s for output.\n", dump_path);
vpi_control(vpiFinish, 1);
return;
} else {
int prec = vpi_get(vpiTimePrecision, 0);
vpi_mcd_printf(1, "LXT2 info: dumpfile %s opened for output.\n",
dump_path);
vpi_printf("LXT2 info: dumpfile %s opened for output.\n",
dump_path);
assert(prec >= -15);
lxt2_wr_set_timescale(dump_file, prec);
@@ -468,9 +466,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
/* $dumpfile must be called before $dumpvars starts! */
if (dumpvars_status != 0) {
vpi_mcd_printf(1, "LXT2 warning: %s called after $dumpvars started"
",\n using existing file (%s).\n",
name, dump_path);
vpi_printf("LXT2 warning: %s called after $dumpvars started,\n"
" using existing file (%s).\n",
name, dump_path);
return 0;
}
@@ -480,8 +478,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
path = strdup(value.value.str);
if (dump_path) {
vpi_mcd_printf(1, "LXT2 warning: Overriding dump file %s with"
" %s.\n", dump_path, path);
vpi_printf("LXT2 warning: Overriding dump file %s with %s.\n",
dump_path, path);
free(dump_path);
}
dump_path = path;
@@ -548,16 +546,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
switch (vpi_get(vpiType, item)) {
case vpiMemory:
/* don't know how to watch memories. */
break;
case vpiNamedEvent:
/* There is nothing in named events to dump. */
break;
case vpiNet: type = "wire"; if(0){
case vpiIntegerVar:
case vpiMemoryWord:
case vpiTimeVar:
case vpiReg: type = "reg"; }
@@ -657,18 +648,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
vpi_get_str(vpiFullName, item);
#if 0
vpi_mcd_printf(1,
"LXT2 info:"
" scanning scope %s, %u levels\n",
fullname, depth);
vpi_printf("LXT2 info: scanning scope %s, %u levels\n",
fullname, depth);
#endif
nskip = 0 != vcd_names_search(&lxt_tab, fullname);
if (!nskip)
vcd_names_add(&lxt_tab, fullname);
else
vpi_mcd_printf(1, "LXT2 warning: ignoring signals in"
" previously scanned scope %s\n", fullname);
vpi_printf("LXT2 warning: ignoring signals in "
"previously scanned scope %s\n", fullname);
name = vpi_get_str(vpiName, item);
@@ -687,8 +676,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
break;
default:
vpi_mcd_printf(1, "LXT2 warning: $dumpvars: Unsupported parameter"
" type (%d)\n", vpi_get(vpiType, item));
vpi_printf("LXT2 warning: $dumpvars: Unsupported parameter "
"type (%s)\n", vpi_get_str(vpiType, item));
}
}
@@ -697,7 +686,6 @@ static int draw_scope(vpiHandle item)
{
int depth;
const char *name;
// char *type; // Not needed, see below.
vpiHandle scope = vpi_handle(vpiScope, item);
if (!scope) return 0;
@@ -705,20 +693,6 @@ static int draw_scope(vpiHandle item)
depth = 1 + draw_scope(scope);
name = vpi_get_str(vpiName, scope);
#if 0 /* The type information is not needed by the LXT2 dumper. */
switch (vpi_get(vpiType, item)) {
case vpiNamedBegin: type = "begin"; break;
case vpiTask: type = "task"; break;
case vpiFunction: type = "function"; break;
case vpiNamedFork: type = "fork"; break;
case vpiModule: type = "module"; break;
default:
vpi_mcd_printf(1, "LXT2 Error: $dumpvars: Unsupported scope "
"type (%d)\n", vpi_get(vpiType, item));
assert(0);
}
#endif
push_scope(name);
return depth;
@@ -733,7 +707,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
unsigned depth = 0;
if (dump_file == 0) {
open_dumpfile();
open_dumpfile(callh);
if (dump_file == 0) return 0;
}
@@ -799,7 +773,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpall";
tf_data.calltf = sys_dumpall_calltf;
tf_data.compiletf = sys_dumpall_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpall";
vpi_register_systf(&tf_data);
@@ -815,7 +789,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpflush";
tf_data.calltf = sys_dumpflush_calltf;
tf_data.compiletf = sys_dumpflush_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpflush";
vpi_register_systf(&tf_data);
@@ -823,7 +797,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
tf_data.calltf = sys_dumplimit_calltf;
tf_data.compiletf = sys_dumplimit_compiletf;
tf_data.compiletf = sys_one_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumplimit";
vpi_register_systf(&tf_data);
@@ -831,7 +805,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpoff";
tf_data.calltf = sys_dumpoff_calltf;
tf_data.compiletf = sys_dumpoff_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpoff";
vpi_register_systf(&tf_data);
@@ -839,7 +813,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpon";
tf_data.calltf = sys_dumpon_calltf;
tf_data.compiletf = sys_dumpon_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpon";
vpi_register_systf(&tf_data);
@@ -852,4 +826,3 @@ void sys_lxt2_register()
tf_data.user_data = "$dumpvars";
vpi_register_systf(&tf_data);
}
+237
View File
@@ -0,0 +1,237 @@
/*
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <assert.h>
#include <string.h>
#include "sys_priv.h"
PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time)
{
PLI_UINT64 tmp;
tmp = time->high;
tmp <<= 32;
tmp |= (PLI_UINT64) time->low;
return tmp;
}
/*
* This routine returns 1 if the argument is a constant value,
* otherwise it returns 0.
*/
unsigned is_constant_obj(vpiHandle obj)
{
assert(obj);
unsigned rtn = 0;
switch(vpi_get(vpiType, obj)) {
case vpiConstant:
case vpiParameter:
rtn = 1;
break;
}
return rtn;
}
/*
* This routine returns 1 if the argument supports has a numeric value,
* otherwise it returns 0.
*/
unsigned is_numeric_obj(vpiHandle obj)
{
assert(obj);
unsigned rtn = 0;
switch(vpi_get(vpiType, obj)) {
case vpiConstant:
case vpiParameter:
/* These cannot be a string constant. */
if (vpi_get(vpiConstType, obj) != vpiStringConst) rtn = 1;
break;
/* These can have a valid numeric value. */
case vpiIntegerVar:
case vpiMemoryWord:
case vpiNet:
case vpiPartSelect:
case vpiRealVar:
case vpiReg:
case vpiTimeVar:
rtn = 1;;
break;
}
return rtn;
}
/*
* This routine returns 1 if the argument supports a valid string value,
* otherwise it returns 0.
*/
unsigned is_string_obj(vpiHandle obj)
{
assert(obj);
unsigned rtn = 0;
switch(vpi_get(vpiType, obj)) {
case vpiConstant:
case vpiParameter: {
/* These must be a string or binary constant. */
PLI_INT32 ctype = vpi_get(vpiConstType, obj);
if (ctype == vpiStringConst || ctype == vpiBinaryConst) rtn = 1;
break;
}
/* These can have a valid string value. */
case vpiIntegerVar:
case vpiMemoryWord:
case vpiNet:
case vpiPartSelect:
case vpiReg:
case vpiTimeVar:
rtn = 1;;
break;
}
return rtn;
}
/*
* Find the enclosing module.
*/
vpiHandle sys_func_module(vpiHandle obj)
{
assert(obj);
while (vpi_get(vpiType, obj) != vpiModule) {
obj = vpi_handle(vpiScope, obj);
assert(obj);
}
return obj;
}
/*
* Standard compiletf routines.
*/
/* For system functions that do not take an argument. */
PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
/* Make sure there are no arguments. */
if (argv != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
unsigned argc = 0;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s %s does not take an argument.\n", msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}
/* For system functions that take a single numeric argument. */
PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
/* Check that there is an argument and that it is numeric. */
if (argv == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a single numeric argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if (! is_numeric_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
if (vpi_scan(argv) != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
unsigned argc = 1;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s %s takes a single numeric argument.\n", msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}
/* For system functions that take a single optional numeric argument. */
PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
/* The argument is optional so just return if none are found. */
if (argv == 0) return 0;
if (! is_numeric_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
if (vpi_scan(argv) != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
unsigned argc = 1;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s %s takes a single numeric argument.\n", msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}
+16 -9
View File
@@ -1,7 +1,7 @@
#ifndef __vpi_sys_priv_H
#define __vpi_sys_priv_H
/*
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,12 +18,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: sys_priv.h,v 1.8 2007/03/14 04:05:51 steve Exp $"
#endif
# include "vpi_config.h"
# include "vpi_user.h"
#include "vpi_config.h"
#include "vpi_user.h"
/*
* Context structure for PRNG in mt19937int.c
@@ -36,9 +33,6 @@ struct context_s {
extern void sgenrand(struct context_s *context, unsigned long seed);
extern unsigned long genrand(struct context_s *context);
extern int is_constant(vpiHandle obj);
extern PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time);
struct timeformat_info_s {
@@ -50,4 +44,17 @@ struct timeformat_info_s {
extern struct timeformat_info_s timeformat_info;
extern unsigned is_constant_obj(vpiHandle obj);
extern unsigned is_numeric_obj(vpiHandle obj);
extern unsigned is_string_obj(vpiHandle obj);
extern vpiHandle sys_func_module(vpiHandle obj);
/*
* The standard compiletf routines.
*/
extern PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name);
#endif
+2
View File
@@ -38,6 +38,7 @@ extern void sys_time_register();
extern void sys_vcd_register();
extern void sys_vcdoff_register();
extern void sys_special_register();
extern void vams_simparam_register();
#ifdef HAVE_LIBZ
#ifdef HAVE_LIBBZ2
@@ -180,5 +181,6 @@ void (*vlog_startup_routines[])() = {
sys_lxt_or_vcd_register,
sys_sdf_register,
sys_special_register,
vams_simparam_register,
0
};
+37 -102
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,36 +16,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: sys_time.c,v 1.12 2007/03/14 04:05:51 steve Exp $"
#endif
# include "vpi_config.h"
#include "vpi_config.h"
# include "vpi_user.h"
# include <string.h>
# include <math.h>
# include <assert.h>
static vpiHandle module_of_function(vpiHandle obj)
{
while (vpi_get(vpiType, obj) != vpiModule) {
obj = vpi_handle(vpiScope, obj);
assert(obj);
}
return obj;
}
static PLI_INT32 sys_time_sizetf(PLI_BYTE8*x)
{
return 64;
}
static PLI_INT32 sys_stime_sizetf(PLI_BYTE8*x)
{
return 32;
}
#include "vpi_user.h"
#include <string.h>
#include <math.h>
#include <assert.h>
#include <sys_priv.h>
static PLI_INT32 sys_time_calltf(PLI_BYTE8*name)
{
@@ -60,7 +38,7 @@ static PLI_INT32 sys_time_calltf(PLI_BYTE8*name)
call_handle = vpi_handle(vpiSysTfCall, 0);
assert(call_handle);
mod = module_of_function(call_handle);
mod = sys_func_module(call_handle);
now.type = vpiSimTime;
vpi_get_time(0, &now);
@@ -113,7 +91,7 @@ static PLI_INT32 sys_realtime_calltf(PLI_BYTE8*name)
call_handle = vpi_handle(vpiSysTfCall, 0);
assert(call_handle);
mod = module_of_function(call_handle);
mod = sys_func_module(call_handle);
now.type = vpiSimTime;
vpi_get_time(0, &now);
@@ -134,82 +112,39 @@ void sys_time_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysFunc;
tf_data.tfname = "$time";
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = sys_time_sizetf;
tf_data.user_data = "$time";
tf_data.type = vpiSysFunc;
tf_data.tfname = "$time";
tf_data.sysfunctype = vpiTimeFunc;
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$time";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysFunc;
tf_data.tfname = "$realtime";
tf_data.calltf = sys_realtime_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$realtime";
tf_data.type = vpiSysFunc;
tf_data.tfname = "$realtime";
tf_data.sysfunctype = vpiRealFunc;
tf_data.calltf = sys_realtime_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$realtime";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysFunc;
tf_data.tfname = "$stime";
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = sys_stime_sizetf;
tf_data.user_data = "$stime";
tf_data.type = vpiSysFunc;
tf_data.tfname = "$stime";
tf_data.sysfunctype = vpiIntFunc;
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$stime";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysFunc;
tf_data.tfname = "$simtime";
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = sys_time_sizetf;
tf_data.user_data = "$simtime";
tf_data.type = vpiSysFunc;
tf_data.tfname = "$simtime";
tf_data.sysfunctype = vpiTimeFunc;
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$simtime";
vpi_register_systf(&tf_data);
}
/*
* $Log: sys_time.c,v $
* Revision 1.12 2007/03/14 04:05:51 steve
* VPI tasks take PLI_BYTE* by the standard.
*
* Revision 1.11 2006/10/30 22:45:37 steve
* Updates for Cygwin portability (pr1585922)
*
* Revision 1.10 2004/01/21 01:22:53 steve
* Give the vip directory its own configure and vpi_config.h
*
* Revision 1.9 2003/06/18 00:54:28 steve
* Account for all 64 bits in results of $time.
*
* Revision 1.8 2003/02/07 02:44:25 steve
* Properly round inter time values from $time.
*
* Revision 1.7 2003/01/28 04:41:55 steve
* Use more precise pow function to scale time by units.
*
* Revision 1.6 2003/01/27 00:14:37 steve
* Support in various contexts the $realtime
* system task.
*
* Revision 1.5 2002/12/21 00:55:58 steve
* The $time system task returns the integer time
* scaled to the local units. Change the internal
* implementation of vpiSystemTime the $time functions
* to properly account for this. Also add $simtime
* to get the simulation time.
*
* Revision 1.4 2002/08/12 01:35:05 steve
* conditional ident string using autoconfig.
*
* Revision 1.3 2002/01/11 05:20:59 steve
* Add the stime system function.
*
* Revision 1.2 2001/07/25 03:10:50 steve
* Create a config.h.in file to hold all the config
* junk, and support gcc 3.0. (Stephan Boettcher)
*
* Revision 1.1 2000/11/01 03:19:36 steve
* Add the general $time system function.
*
*/
+37 -49
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,9 +16,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: sys_vcd.c,v 1.58 2007/03/14 04:05:51 steve Exp $"
#endif
# include "sys_priv.h"
@@ -269,9 +266,9 @@ inline static int install_dumpvars_callback(void)
if (dumpvars_status == 1) return 0;
if (dumpvars_status == 2) {
vpi_mcd_printf(1, "VCD warning: $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
vpi_printf("VCD warning: $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
return 1;
}
@@ -374,15 +371,16 @@ static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name)
return 0;
}
static void open_dumpfile(void)
static void open_dumpfile(vpiHandle callh)
{
if (dump_path == 0) dump_path = strdup("dump.vcd");
dump_file = fopen(dump_path, "w");
if (dump_file == 0) {
vpi_mcd_printf(1, "VCD Error: Unable to open %s for output.\n",
dump_path);
vpi_printf("VCD Error: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Unable to open %s for output.\n", dump_path);
vpi_control(vpiFinish, 1);
return;
} else {
@@ -391,8 +389,7 @@ static void open_dumpfile(void)
unsigned udx = 0;
time_t walltime;
vpi_mcd_printf(1, "VCD info: dumpfile %s opened for output.\n",
dump_path);
vpi_printf("VCD info: dumpfile %s opened for output.\n", dump_path);
time(&walltime);
@@ -428,9 +425,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
/* $dumpfile must be called before $dumpvars starts! */
if (dumpvars_status != 0) {
vpi_mcd_printf(1, "VCD warning: %s called after $dumpvars started"
",\n using existing file (%s).\n",
name, dump_path);
vpi_printf("VCD warning: %s called after $dumpvars started,\n"
" using existing file (%s).\n",
name, dump_path);
return 0;
}
@@ -440,8 +437,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
path = strdup(value.value.str);
if (dump_path) {
vpi_mcd_printf(1, "VCD warning: Overriding dump file %s with"
" %s\n", dump_path, path);
vpi_printf("VCD warning: Overriding dump file %s with %s\n",
dump_path, path);
free(dump_path);
}
dump_path = path;
@@ -502,16 +499,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
switch (vpi_get(vpiType, item)) {
case vpiMemory:
/* don't know how to watch memories. */
break;
case vpiNamedEvent:
/* There is nothing in named events to dump. */
break;
case vpiNet: type = "wire"; if(0){
case vpiIntegerVar:
case vpiMemoryWord:
case vpiTimeVar:
case vpiReg: type = "reg"; }
@@ -635,18 +625,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
vpi_get_str(vpiFullName, item);
#if 0
vpi_mcd_printf(1,
"VCD info:"
" scanning scope %s, %u levels\n",
fullname, depth);
vpi_printf("VCD info: scanning scope %s, %u levels\n",
fullname, depth);
#endif
nskip = 0 != vcd_names_search(&vcd_tab, fullname);
if (!nskip)
vcd_names_add(&vcd_tab, fullname);
else
vpi_mcd_printf(1, "VCD warning: ignoring signals in"
" previously scanned scope %s\n", fullname);
vpi_printf("VCD warning: ignoring signals in "
"previously scanned scope %s\n", fullname);
name = vpi_get_str(vpiName, item);
@@ -665,12 +653,12 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
break;
default:
vpi_mcd_printf(1, "VCD warning: $dumpvars: Unsupported parameter "
"type (%d)\n", vpi_get(vpiType, item));
vpi_printf("VCD warning: $dumpvars: Unsupported parameter "
"type (%s)\n", vpi_get_str(vpiType, item));
}
}
static int draw_scope(vpiHandle item)
static int draw_scope(vpiHandle item, vpiHandle callh)
{
int depth;
const char *name;
@@ -679,7 +667,7 @@ static int draw_scope(vpiHandle item)
vpiHandle scope = vpi_handle(vpiScope, item);
if (!scope) return 0;
depth = 1 + draw_scope(scope);
depth = 1 + draw_scope(scope, callh);
name = vpi_get_str(vpiName, scope);
switch (vpi_get(vpiType, scope)) {
@@ -689,8 +677,9 @@ static int draw_scope(vpiHandle item)
case vpiNamedFork: type = "fork"; break;
case vpiModule: type = "module"; break;
default:
vpi_mcd_printf(1, "VCD Error: $dumpvars: Unsupported scope "
"type (%d)\n", vpi_get(vpiType, item));
vpi_printf("VCD Error: %s line %d: $dumpvars: Unsupported scope "
"type (%d)\n", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh), vpi_get(vpiType, item));
assert(0);
}
@@ -708,7 +697,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
unsigned depth = 0;
if (dump_file == 0) {
open_dumpfile();
open_dumpfile(callh);
if (dump_file == 0) return 0;
}
@@ -739,23 +728,23 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
* been included. */
switch (vpi_get(vpiType, item)) {
case vpiIntegerVar:
/* What about MemoryWord? */
case vpiMemoryWord:
case vpiNet:
case vpiRealVar:
case vpiReg:
case vpiTimeVar:
scname = vpi_get_str(vpiFullName, vpi_handle(vpiScope, item));
if (vcd_names_search(&vcd_tab, scname)) {
vpi_mcd_printf(1, "VCD warning: skipping signal %s, "
"it was previously included.\n",
vpi_get_str(vpiFullName, item));
vpi_printf("VCD warning: skipping signal %s, "
"it was previously included.\n",
vpi_get_str(vpiFullName, item));
continue;
} else {
add_var = 1;
}
}
int dep = draw_scope(item);
int dep = draw_scope(item, callh);
scan_item(depth, item, 0);
@@ -782,7 +771,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpall";
tf_data.calltf = sys_dumpall_calltf;
tf_data.compiletf = sys_dumpall_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpall";
vpi_register_systf(&tf_data);
@@ -798,7 +787,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpflush";
tf_data.calltf = sys_dumpflush_calltf;
tf_data.compiletf = sys_dumpflush_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpflush";
vpi_register_systf(&tf_data);
@@ -806,7 +795,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
tf_data.calltf = sys_dumplimit_calltf;
tf_data.compiletf = sys_dumplimit_compiletf;
tf_data.compiletf = sys_one_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumplimit";
vpi_register_systf(&tf_data);
@@ -814,7 +803,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpoff";
tf_data.calltf = sys_dumpoff_calltf;
tf_data.compiletf = sys_dumpoff_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpoff";
vpi_register_systf(&tf_data);
@@ -822,7 +811,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpon";
tf_data.calltf = sys_dumpon_calltf;
tf_data.compiletf = sys_dumpon_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpon";
vpi_register_systf(&tf_data);
@@ -835,4 +824,3 @@ void sys_vcd_register()
tf_data.user_data = "$dumpvars";
vpi_register_systf(&tf_data);
}
+14 -18
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,9 +16,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: sys_vcdoff.c,v 1.5 2007/03/14 04:05:52 steve Exp $"
#endif
# include "sys_priv.h"
@@ -40,7 +37,7 @@
static int dump_flag = 0;
static PLI_INT32 sys_dump_calltf(PLI_BYTE8*name)
static PLI_INT32 sys_dummy_calltf(PLI_BYTE8*name)
{
return 0;
}
@@ -48,7 +45,7 @@ static PLI_INT32 sys_dump_calltf(PLI_BYTE8*name)
static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
{
if (dump_flag == 0) {
vpi_mcd_printf(1, "VCD info: dumping is suppressed.\n");
vpi_printf("VCD info: dumping is suppressed.\n");
dump_flag = 1;
}
@@ -63,15 +60,15 @@ void sys_vcdoff_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpall";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumpall_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpall";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpfile";
tf_data.calltf = sys_dump_calltf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_dumpfile_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpfile";
@@ -79,32 +76,32 @@ void sys_vcdoff_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpflush";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumpflush_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpflush";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumplimit_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_one_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumplimit";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpoff";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumpoff_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpoff";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpon";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumpon_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpon";
vpi_register_systf(&tf_data);
@@ -117,4 +114,3 @@ void sys_vcdoff_register()
tf_data.user_data = "$dumpvars";
vpi_register_systf(&tf_data);
}
+3 -1
View File
@@ -14,4 +14,6 @@ $dist_poisson vpiSysFuncInt
$dist_chi_square vpiSysFuncInt
$dist_t vpiSysFuncInt
$dist_erlang vpiSysFuncInt
$vvp_cpu_wordsize vpiSysFuncInt
$simparam vpiSysFuncReal
$simparam$str vpiSysFuncSized 1024 unsigned
+280
View File
@@ -0,0 +1,280 @@
/*
* Copyright (C) 2008 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <assert.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vpi_user.h>
#include "sys_priv.h"
/* Once we have real string objects replace this with a dynamic string. */
#define MAX_STRING_RESULT 1024
/*
* Check that the routines are called with the correct arguments.
*/
static PLI_INT32 simparam_compiletf(PLI_BYTE8* name_ext)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
assert(callh != 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
/* We must have at least one argument. */
if (argv == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("$simparam%s requires a string argument.\n", name_ext);
vpi_control(vpiFinish, 1);
return 0;
}
/* The first argument must be a string. */
arg = vpi_scan(argv);
if (! is_string_obj(arg)) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("The first argument to $simparam%s must be a string.\n",
name_ext);
vpi_control(vpiFinish, 1);
}
/* The second argument (default value) is optional. */
arg = vpi_scan(argv);
if (arg == 0) return 0;
/* For the string version the default must also be a string. */
if (strcmp(name_ext, "$str") == 0) {
if (! is_string_obj(arg)) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("When provided, the second argument to $simparam%s"
"must be a string.\n", name_ext);
vpi_control(vpiFinish, 1);
}
/* For the rest the default must be numeric. */
} else {
if (! is_numeric_obj(arg)) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("When provided, the second argument to $simparam%s"
"must be numeric.\n", name_ext);
vpi_control(vpiFinish, 1);
}
}
/* We can only have two argument. */
if (vpi_scan(argv) != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
unsigned argc = 1;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s $simparam%s takes at most two arguments.\n",
msg, name_ext);
vpi_printf("%*s Found %u extra argument%s.\n",
strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}
static PLI_INT32 simparam_calltf(PLI_BYTE8* name_ext)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
s_vpi_value val;
char *param;
unsigned have_def_val = 0;
double retval, defval = 0.0;
/* Get the parameter we are looking for. */
arg = vpi_scan(argv);
val.format = vpiStringVal;
vpi_get_value(arg, &val);
param = strdup(val.value.str);
/* See if there is a default value. */
arg = vpi_scan(argv);
if (arg != 0) {
vpi_free_object(argv);
have_def_val = 1;
val.format = vpiRealVal;
vpi_get_value(arg, &val);
defval = val.value.real;
}
/* Now check the various things we can return. */
if (strcmp(param, "gdev") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "gmin") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "imax") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "imelt") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "iteration") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "scale") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "shrink") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "simulatorSubversion") == 0) {
retval = 0.0;
} else if (strcmp(param, "simulatorVersion") == 0) {
retval = 0.9;
} else if (strcmp(param, "sourceScaleFactor") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "tnom") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "timeUnit") == 0) {
retval = pow(10, vpi_get(vpiTimeUnit, sys_func_module(callh)));
} else if (strcmp(param, "timePrecision") == 0) {
retval = pow(10, vpi_get(vpiTimePrecision, sys_func_module(callh)));
} else if (strcmp(param, "CPUWordSize") == 0) {
retval = 8.0*sizeof(long);
} else {
if (! have_def_val) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("$simparam%s unknown parameter name \"%s\".\n",
name_ext, param);
}
retval = defval;
}
free(param);
/* Return the value to the system. */
val.format = vpiRealVal;
val.value.real = retval;
vpi_put_value(callh, &val, 0, vpiNoDelay);
return 0;
}
static PLI_INT32 simparam_str_calltf(PLI_BYTE8* name_ext)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
s_vpi_value val;
char *param;
char *retval, *defval = NULL;
/* Get the parameter we are looking for. */
arg = vpi_scan(argv);
val.format = vpiStringVal;
vpi_get_value(arg, &val);
param = strdup(val.value.str);
/* See if there is a default value. */
arg = vpi_scan(argv);
if (arg != 0) {
vpi_free_object(argv);
val.format = vpiStringVal;
vpi_get_value(arg, &val);
defval = strdup(val.value.str);
}
/* Now check the various things we can return. */
/* For now we limit the result to 1024 characters. */
if (strcmp(param, "analysis_name") == 0) {
retval = strdup("N/A"); /* Nothing for now. */
} else if (strcmp(param, "analysis_type") == 0) {
retval = strdup("N/A"); /* Nothing for now. */
} else if (strcmp(param, "cwd") == 0) {
char path [MAX_STRING_RESULT];
char *ptr = getcwd(path, MAX_STRING_RESULT);
if (ptr == NULL) {
ptr = strcpy(path, "<error getting the cwd, "
"is it too long?>");
}
retval = strdup(path);
} else if (strcmp(param, "module") == 0) {
retval = strdup(vpi_get_str(vpiDefName, sys_func_module(callh)));
} else if (strcmp(param, "instance") == 0) {
retval = strdup(vpi_get_str(vpiFullName, sys_func_module(callh)));
} else if (strcmp(param, "path") == 0) {
retval = strdup(vpi_get_str(vpiFullName,
vpi_handle(vpiScope,callh)));
} else {
if (defval == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("$simparam%s unknown parameter name \"%s\".\n",
name_ext, param);
defval = strdup("<error>");
}
retval = defval;
}
free(param);
/* Return the value to the system. */
val.format = vpiStringVal;
val.value.str = retval;
vpi_put_value(callh, &val, 0, vpiNoDelay);
free(retval);
return 0;
}
static PLI_INT32 simparam_str_sizetf(PLI_BYTE8* name_ext)
{
(void) name_ext; //* Not used! */
return MAX_STRING_RESULT; // 128 characters max!
}
/*
* Register the function with Verilog.
*/
void vams_simparam_register(void)
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiRealFunc;
tf_data.calltf = simparam_calltf;
tf_data.compiletf = simparam_compiletf;
tf_data.sizetf = 0;
tf_data.tfname = "$simparam";
tf_data.user_data = "";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiSizedFunc; /* What should this be? */
tf_data.calltf = simparam_str_calltf;
tf_data.compiletf = simparam_compiletf;
tf_data.sizetf = simparam_str_sizetf; /* Only 128 characters! */
tf_data.tfname = "$simparam$str";
tf_data.user_data = "$str";
vpi_register_systf(&tf_data);
}
+50 -173
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,21 +16,19 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vcd_priv.c,v 1.6 2004/10/04 01:10:58 steve Exp $"
#endif
# include "vpi_config.h"
# include "vcd_priv.h"
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
#include "vpi_config.h"
#include "vcd_priv.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <ctype.h>
# include "stringheap.h"
#include <ctype.h>
#include "stringheap.h"
#include <sys_priv.h>
int is_escaped_id(const char *name)
{
@@ -188,92 +186,12 @@ void set_nexus_ident(int nex, const char *id)
vcd_ids[ihash(nex)] = bucket;
}
/* This is used by the compiletf routines to check if an argument
* is numeric. */
static void check_numeric_arg(vpiHandle arg, char *msg, PLI_BYTE8 *name)
{
assert(arg);
switch (vpi_get(vpiType, arg)) {
case vpiConstant:
case vpiParameter:
/* String constants are invalid numeric values. */
if (vpi_get(vpiConstType, arg) == vpiStringConst) {
vpi_mcd_printf(1, msg, name);
vpi_control(vpiFinish, 1);
}
break;
/* These have valid numeric values. */
case vpiIntegerVar:
case vpiMemoryWord:
case vpiNet:
case vpiRealVar:
case vpiReg:
case vpiTimeVar:
break;
default:
/* Anything else is not a numeric value. */
vpi_mcd_printf(1, msg, name);
vpi_control(vpiFinish, 1);
break;
}
}
/* This is used by the compiletf routines to check if an argument
* is a string value. */
static void check_string_arg(vpiHandle arg, char *msg, PLI_BYTE8 *name)
{
assert(arg);
PLI_INT32 ctype = 0;
switch (vpi_get(vpiType, arg)) {
case vpiConstant:
case vpiParameter:
/* These must be a string or binary constant. */
ctype = vpi_get(vpiConstType, arg);
if (ctype != vpiStringConst && ctype != vpiBinaryConst) {
vpi_mcd_printf(1, msg, name);
vpi_control(vpiFinish, 1);
}
break;
/* These have valid string values. */
case vpiIntegerVar:
case vpiMemoryWord:
case vpiNet:
case vpiReg:
case vpiTimeVar:
break;
default:
/* Anything else is not a string. */
vpi_mcd_printf(1, msg, name);
vpi_control(vpiFinish, 1);
break;
}
}
/*
* Since the compiletf routines are all the same they are located here,
* so we only need a single copy.
* so we only need a single copy. Some are generic enough they can use
* the ones in sys_priv.c (no arg, one numeric arg.
*/
/* $dumpall does not take an argument. */
PLI_INT32 sys_dumpall_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
if (argv != 0) {
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
vpi_control(vpiFinish, 1);
}
return 0;
}
/* $dumpfile takes a single string argument. */
PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
{
@@ -282,84 +200,32 @@ PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
/* Check that there is an argument and that it is a string. */
if (argv == 0) {
vpi_mcd_printf(1, "ERROR: %s requires an argument.\n", name);
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a single string argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
check_string_arg(vpi_scan(argv), "ERROR: %s's argument must be a"
" string.\n", name);
if (! is_string_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's argument must be a string.\n", name);
vpi_control(vpiFinish, 1);
}
/* Check that there is only a single argument. */
/* Make sure there are no extra arguments. */
if (vpi_scan(argv) != 0) {
vpi_mcd_printf(1, "ERROR: %s takes a single argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
return 0;
}
unsigned argc = 1;
while (vpi_scan(argv)) argc += 1;
/* $dumpflush does not take an argument. */
PLI_INT32 sys_dumpflush_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
if (argv != 0) {
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
vpi_control(vpiFinish, 1);
}
return 0;
}
/* $dumplimit takes a single numeric argument. */
PLI_INT32 sys_dumplimit_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
/* Check that there is an argument and that it is numeric. */
if (argv == 0) {
vpi_mcd_printf(1, "ERROR: %s requires an argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
check_numeric_arg(vpi_scan(argv), "ERROR: %s's argument must be"
" numeric.\n", name);
/* Check that there is only a single argument. */
if (vpi_scan(argv) != 0) {
vpi_mcd_printf(1, "ERROR: %s takes a single argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
return 0;
}
/* $dumpoff does not take an argument. */
PLI_INT32 sys_dumpoff_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
if (argv != 0) {
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
vpi_control(vpiFinish, 1);
}
return 0;
}
/* $dumpon does not take an argument. */
PLI_INT32 sys_dumpon_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
if (argv != 0) {
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
vpi_printf("%s %s takes a single string argument.\n", msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
@@ -374,16 +240,27 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name)
vpiHandle arg;
/* No arguments is OK, dump everything. */
if (argv == 0)
return 0;
if (argv == 0) return 0;
/* The first argument is the numeric level. */
check_numeric_arg(vpi_scan(argv), "ERROR: %s's first argument must be"
" numeric.\n", name);
if (! is_numeric_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
/* The rest of the arguments are either a module or a variable. */
while ((arg=vpi_scan(argv)) != NULL) {
switch(vpi_get(vpiType, arg)) {
case vpiMemoryWord:
if (vpi_get(vpiConstantSelect, arg) == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s cannot dump a non-constant select %s.\n", name,
vpi_get_str(vpiType, arg));
vpi_control(vpiFinish, 1);
}
/* The module types. */
case vpiModule:
case vpiTask:
@@ -393,18 +270,18 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name)
/* The variable types. */
case vpiNet:
case vpiReg:
case vpiMemoryWord:
case vpiIntegerVar:
case vpiTimeVar:
case vpiRealVar:
break;
default:
vpi_mcd_printf(1, "ERROR: %s cannot dump a %s.\n",
name, vpi_get_str(vpiType, arg));
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s cannot dump a %s.\n", name,
vpi_get_str(vpiType, arg));
vpi_control(vpiFinish, 1);
}
}
return 0;
}
+1 -9
View File
@@ -1,7 +1,7 @@
#ifndef __vcd_priv_H
#define __vcd_priv_H
/*
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,9 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vcd_priv.h,v 1.2 2003/02/13 18:13:28 steve Exp $"
#endif
#include "vpi_user.h"
@@ -47,12 +44,7 @@ extern const char*find_nexus_ident(int nex);
extern void set_nexus_ident(int nex, const char *id);
/* The compiletf routines are common for the VCD, LXT and LXT2 dumpers. */
extern PLI_INT32 sys_dumpall_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpflush_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumplimit_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpoff_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpon_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name);
#endif
+5 -2
View File
@@ -279,6 +279,7 @@ typedef struct t_vpi_delay {
#define vpiNamedFork 35
#define vpiNet 36
#define vpiParameter 41
#define vpiPartSelect 42
#define vpiPathTerm 43
#define vpiRealVar 47
#define vpiReg 48
@@ -297,6 +298,7 @@ typedef struct t_vpi_delay {
#define vpiModPathIn 95
#define vpiModPathOut 96
#define vpiVariables 100
#define vpiExpr 102
#define vpiCallback 1000
@@ -346,8 +348,8 @@ typedef struct t_vpi_delay {
# define vpiSysFuncReal vpiRealFunc
# define vpiSysFuncTime vpiTimeFunc
# define vpiSysFuncSized vpiSizedFunc
#define vpiSigned 65
#define vpiExpr 102
#define vpiConstantSelect 53
#define vpiSigned 65
/* IVL private properties */
#define _vpiNexusId 0x1000000
@@ -563,6 +565,7 @@ extern DLLEXPORT void (*vlog_startup_routines[])();
/* Format a scalar a la %v. The str points to a 4byte character
buffer. The value must be a vpiStrengthVal. */
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
extern void vpip_set_return_value(int value);
EXTERN_C_END
+14 -4
View File
@@ -43,6 +43,8 @@ INSTALL_DATA = @INSTALL_DATA@
RANLIB = @RANLIB@
LEX = @LEX@
YACC = @YACC@
MAN = @MAN@
PS2PDF = @PS2PDF@
CPPFLAGS = @ident_support@ -I. -I.. -I $(srcdir) -I$(srcdir)/.. @CPPFLAGS@ @DEFS@
CXXFLAGS = -Wall @CXXFLAGS@
@@ -77,7 +79,7 @@ O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
concat.o \
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
ufunc.o codes.o \
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o \
vthread.o schedule.o statistics.o tables.o udp.o vvp_island.o vvp_net.o \
event.o logic.o delay.o words.o $V
ifeq (@WIN32@,yes)
@@ -133,12 +135,20 @@ lexor.cc: $(srcdir)/lexor.lex
$(LEX) -s -olexor.cc $(srcdir)/lexor.lex
vvp.pdf: $(srcdir)/vvp.man
man -t $(srcdir)/vvp.man | ps2pdf - vvp.pdf
$(MAN) -t $(srcdir)/vvp.man | $(PS2PDF) - vvp.pdf
ifeq (@MING32@,yes)
ifeq (@MINGW32@,yes)
ifeq ($(MAN),none)
INSTALL_DOC = $(mandir)/man1/vvp.1
else
ifeq ($(PS2PDF),none)
INSTALL_DOC = $(mandir)/man1/vvp.1
else
INSTALL_DOC = $(prefix)/vvp.pdf $(mandir)/man1/vvp.1
INSTALL_DOCDIR = $(mandir)/man1
all: vvp.pdf
endif
endif
INSTALL_DOCDIR = $(mandir)/man1
else
INSTALL_DOC = $(mandir)/man1/vvp.1
INSTALL_DOCDIR = $(mandir)/man1
+41 -76
View File
@@ -386,82 +386,6 @@ at <src>.
<label> .array "name", <src> ;
MEMORY STATEMENTS:
Memories are arrays of words, each word a vvp_vector4_t vector of the
same width. The memory is canonically addressed as a 1-dimensional
array of words, although indices are stored with the memory for
calculating a canonical address from a multi-dimensional address.
Three types of memory statement perform (1) creation of a memory, (2)
connecting a read port to an existing memory, and (3) initializing the
memory's contents.
<label> .mem "name", <msb>,<lsb>, <last>,<first> ... ;
The pair of numbers <msb>,<lsb> defines the word width. The pair
<last>,<first> defines the address range. Multiple address ranges are
allowed for multidimensional indexing. This statement creates the
memory array and makes it available to procedural code.
Procedural access to the memory references the memory as single array
of words, with the base address==0, and the last address the size (in
words) of the memory -1. It is up to the compiler to convert Verilog
index sets to a canonical address. The multi-dimensional index set is
available for VPI use.
Structural read access is implemented in terms of address and data
ports. The addresses applied to the address port are expected to be
in canonical form.
A read port is a functor that takes a single input, the read address,
and outputs the word value at the given (canonical) address.
<label> .mem/port <memid>, <address> ;
<label> identifies the vector of output functors, to allow connections
to the data output. <memid> is the label of the memory.
Any address input change, or any change in the addressed memory
contents, is immediately propagated to the port output.
A write port is a superset of a read port. It is a 4-input functor
that accepts the word address, an event input, a write enable input,
and the data input.
<label> .mem/port <memid>, <address>, <event>, <we>, <data> ;
<event> is an event functor that triggers a write, if the <we> input
is true. <data> is the input that connect to the data input
port. For asynchronous transparent write operation, connect
<event> to C4<z>, the RAM will transparently follow any changes on
address and data lines, while <we> is true.
There is no Verilog construct that calls for a structural write port
to a memory, but synthesis may ask for lpm_ram_d[pq] objects.
To initialize a memory, use:
.mem/init <memid> <start>, val , val ... ;
<memid> is the label of the memory, and the <start> is the start
address (canonical) of the first word to be initialized. The start
address allows multiple statements be used to initialize words of a
memory.
The values are one per word.
Procedural access to the memory employs an index register to address a
bit location in the memory, via the commands:
%load/m <bit>, <memid> ;
%set/m <memid>, <bit> ;
%assign/m <memid>, <delay>, <bit> ;
The memory bit is addressed by index register 3. The value of
register 3 is the index in the memory's bit space, where each data
word occupies a multiple of four bits.
EVENT STATEMENTS
@@ -830,6 +754,47 @@ by the fork atomically joins that scope. Once the transient thread
joins the scope, it stays there until it ends. Threads never change
scopes, not even transient threads.
VPI TASK/FUNCTION CALLS
Threads call vpi tasks with the %vpi_call or %vpi_func
instructions. The formats are:
%vpi_call <file-index> <lineno> <name>, <args>... ;
%vpi_func <file-index> <lineno> <name>, <args>... ;
%vpi_func/r <file-index> <lineno> <name>, <args>... ;
The <file-index> is an index into the string table. The indexed string
is the source code file name where this call appears. The <lineno> is
the line number from the source code where this task/function appears.
The <name> is a string that is the name of the system
task/function. For example, "$display", $strobe", etc. This name is
looked up and compared with the registered system tasks/functions.
The <args>... is a comma (",") separated list of arguments. These are
made available to the VPI code as vpi handles.
* The &A<> argument
The &A<> argument is a reference to the word of a variable array. The
syntax is:
&A '<' <symbol> , <number> '>'
The <symbol> is the label for a variable array, and the <number> is
the cannonical word index as an unsigned integer.
* The T<> argument
This is the catch-all for arguments that are not otherwise
handled. This references the bits directly in the thread. The format
is:
T '<' <base>, <wid>, <su> '>'
The <base> and <wid> are the base of a vector value in the thread and
the width of the vector. The <su> is 's' or 'u' for signed or unsigned.
TRUTH TABLES
The logic that a functor represents is expressed as a truth table. The
+191 -24
View File
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2007-2008 Stephen Williams (steve@icarus.com)
*
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
@@ -30,7 +30,7 @@
# include "compile.h"
# include <assert.h>
static symbol_table_t array_table =0;
static symbol_map_s<struct __vpiArray>* array_table =0;
class vvp_fun_arrayport;
static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
@@ -40,8 +40,8 @@ vvp_array_t array_find(const char*label)
if (array_table == 0)
return 0;
symbol_value_t v = sym_get_value(array_table, label);
return (vvp_array_t)v.ptr;
vvp_array_t v = array_table->sym_get_value(label);
return v;
}
/*
@@ -55,6 +55,8 @@ struct __vpiArray {
unsigned array_count;
struct __vpiDecConst first_addr;
struct __vpiDecConst last_addr;
struct __vpiDecConst msb;
struct __vpiDecConst lsb;
// If this is a net array, nets lists the handles.
vpiHandle*nets;
// If this is a var array, then these are used instead of nets.
@@ -81,7 +83,25 @@ struct __vpiArrayIndex {
struct __vpiArrayVthrA {
struct __vpiHandle base;
struct __vpiArray*array;
// If wid==0, then address is the address into the array.
unsigned address;
// If wid >0, then the address is the base and wid the vector
// width of the index to pull from the thread.
unsigned wid;
unsigned get_address() const
{
if (wid == 0)
return address;
vvp_vector4_t tmp (wid);
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
vvp_bit4_t bit = vthread_get_bit(vpip_current_vthread, address+idx);
tmp.set_bit(idx, bit);
}
unsigned long val;
vector4_to_value(tmp, val);
return val;
}
};
/*
@@ -121,12 +141,16 @@ static vpiHandle array_index_scan(vpiHandle ref, int);
static int array_index_free_object(vpiHandle ref);
static int vpi_array_var_word_get(int code, vpiHandle);
static char*vpi_array_var_word_get_str(int code, vpiHandle);
static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value);
static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int);
static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref);
static int vpi_array_vthr_A_get(int code, vpiHandle);
static char*vpi_array_vthr_A_get_str(int code, vpiHandle);
static void vpi_array_vthr_A_get_value(vpiHandle, p_vpi_value);
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle, p_vpi_value, int);
static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref);
static const struct __vpirt vpip_arraymem_rt = {
vpiMemory,
@@ -169,10 +193,10 @@ static const struct __vpirt vpip_array_index_rt = {
static const struct __vpirt vpip_array_var_word_rt = {
vpiMemoryWord,
&vpi_array_var_word_get,
0,
&vpi_array_var_word_get_str,
&vpi_array_var_word_get_value,
&vpi_array_var_word_put_value,
0,
&vpi_array_var_word_get_handle,
0,
0,
0
@@ -181,10 +205,10 @@ static const struct __vpirt vpip_array_var_word_rt = {
static const struct __vpirt vpip_array_vthr_A_rt = {
vpiMemoryWord,
&vpi_array_vthr_A_get,
0,
&vpi_array_vthr_A_get_str,
&vpi_array_vthr_A_get_value,
&vpi_array_vthr_A_put_value,
0,
&vpi_array_vthr_A_get_handle,
0,
0,
0
@@ -340,11 +364,34 @@ static int vpi_array_var_word_get(int code, vpiHandle ref)
case vpiSize:
return (int) parent->vals_width;
case vpiLeftRange:
return parent->msb.value;
case vpiRightRange:
return parent->lsb.value;
default:
return 0;
}
}
static char*vpi_array_var_word_get_str(int code, vpiHandle ref)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
unsigned index = decode_array_word_pointer(obj, parent);
if (code == vpiFile) { // Not implemented for now!
return simple_set_rbuf_str(file_names[0]);
}
char sidx [64];
snprintf(sidx, 63, "%d", (int)index + parent->first_addr.value);
return generic_get_str(code, &parent->scope->base, parent->name, sidx);
}
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
@@ -352,9 +399,14 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
assert(obj);
unsigned index = decode_array_word_pointer(obj, parent);
unsigned width = parent->vals_width;
vpip_vec4_get_value(parent->vals[index], parent->vals_width,
false, value);
/* If we don't have a value yet just return X. */
if (parent->vals[index].size() == 0) {
vpip_vec4_get_value(vvp_vector4_t(width), width, false, value);
} else {
vpip_vec4_get_value(parent->vals[index], width, false, value);
}
}
static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags)
@@ -370,6 +422,35 @@ static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int
return ref;
}
static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
decode_array_word_pointer(obj, parent);
switch (code) {
case vpiIndex:
break; // Not implemented!
case vpiLeftRange:
return &parent->msb.base;
case vpiRightRange:
return &parent->lsb.base;
case vpiParent:
return &parent->base;
case vpiScope:
return &parent->scope->base;
}
return 0;
}
# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \
(struct __vpiArrayIterator*)ref)
@@ -453,13 +534,39 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref)
return 0; // Not implemented for now!
case vpiSize:
assert(parent->vals);
return parent->vals_width;
case vpiLeftRange:
return parent->msb.value;
case vpiRightRange:
return parent->lsb.value;
// For now &A<> is only a constant select. This will need
// to be changed when it supports variable selection.
case vpiConstantSelect:
return 1;
default:
return 0;
}
}
static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref)
{
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
if (code == vpiFile) { // Not implemented for now!
return simple_set_rbuf_str(file_names[0]);
}
char sidx [64];
snprintf(sidx, 63, "%d", (int)obj->get_address() + parent->first_addr.value);
return generic_get_str(code, &parent->scope->base, parent->name, sidx);
}
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
{
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
@@ -467,11 +574,10 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
struct __vpiArray*parent = obj->array;
assert(parent);
assert(parent->vals);
assert(obj->address < parent->array_count);
vpip_vec4_get_value(parent->vals[obj->address],
parent->vals_width, false, value);
unsigned index = obj->get_address();
vvp_vector4_t tmp = array_get_word(parent, index);
vpip_vec4_get_value(tmp, parent->vals_width, false, value);
}
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
@@ -480,10 +586,10 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
assert(obj);
struct __vpiArray*parent = obj->array;
unsigned index = obj->address;
unsigned index = obj->get_address();
assert(parent);
assert(obj->address < parent->array_count);
assert(index < parent->array_count);
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
array_set_word(parent, index, 0, val);
@@ -491,6 +597,32 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
return ref;
}
static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref)
{
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
switch (code) {
case vpiIndex:
break; // Not implemented!
case vpiLeftRange:
return &parent->msb.base;
case vpiRightRange:
return &parent->lsb.base;
case vpiParent:
return &parent->base;
case vpiScope:
return &parent->scope->base;
}
return 0;
}
void array_set_word(vvp_array_t arr,
unsigned address,
@@ -596,6 +728,8 @@ static vpiHandle vpip_make_array(char*label, const char*name,
obj->nets = 0;
obj->vals = 0;
obj->vals_width = 0;
vpip_make_dec_const(&obj->msb, 0);
vpip_make_dec_const(&obj->lsb, 0);
obj->vals_words = 0;
// Initialize (clear) the read-ports list.
@@ -604,12 +738,10 @@ static vpiHandle vpip_make_array(char*label, const char*name,
/* Add this symbol to the array_symbols table for later lookup. */
if (!array_table)
array_table = new_symbol_table();
array_table = new symbol_map_s<struct __vpiArray>;
assert(!array_find(label));
symbol_value_t v;
v.ptr = obj;
sym_set_value(array_table, label, v);
array_table->sym_set_value(label, obj);
/* Add this into the table of VPI objects. This is used for
contexts that try to look up VPI objects in
@@ -656,6 +788,8 @@ void compile_var_array(char*label, char*name, int last, int first,
/* Make the words. */
arr->vals = new vvp_vector4_t[arr->array_count];
arr->vals_width = labs(msb-lsb) + 1;
vpip_make_dec_const(&arr->msb, msb);
vpip_make_dec_const(&arr->lsb, lsb);
free(label);
free(name);
@@ -909,9 +1043,7 @@ void compile_array_alias(char*label, char*name, char*src)
assert(array_table);
assert(!array_find(label));
symbol_value_t v;
v.ptr = obj;
sym_set_value(array_table, label, v);
array_table->sym_set_value(label, obj);
compile_vpi_symbol(label, &obj->base);
vpip_attach_to_current_scope(&obj->base);
@@ -930,9 +1062,44 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
obj->array = array_find(label);
assert(obj->array);
free(label);
obj->address = addr;
obj->wid = 0;
assert(addr < obj->array->array_count);
return &(obj->base);
}
vpiHandle vpip_make_vthr_A(char*label, char*symbol)
{
struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*)
malloc(sizeof (struct __vpiArrayVthrA));
obj->base.vpi_type = &vpip_array_vthr_A_rt;
obj->array = array_find(label);
assert(obj->array);
free(label);
unsigned base;
unsigned wid;
char sflag;
int rc = sscanf(symbol, "T<%u,%u,%c>", &base, &wid, &sflag);
assert(rc == 3);
free(symbol);
obj->address = base;
obj->wid = wid;
assert(sflag == 'u');
return &(obj->base);
}
void compile_array_cleanup(void)
{
if (array_table) {
delete array_table;
array_table = 0;
}
}
+2 -1
View File
@@ -37,6 +37,7 @@ extern bool of_ADD(vthread_t thr, vvp_code_t code);
extern bool of_ADD_WR(vthread_t thr, vvp_code_t code);
extern bool of_ADDI(vthread_t thr, vvp_code_t code);
extern bool of_AND(vthread_t thr, vvp_code_t code);
extern bool of_ANDI(vthread_t thr, vvp_code_t code);
extern bool of_ANDR(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_AV(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_AVD(vthread_t thr, vvp_code_t code);
@@ -167,7 +168,7 @@ struct vvp_code_s {
};
union {
unsigned bit_idx[2];
uint32_t bit_idx[2];
vvp_net_t *net2;
vvp_code_t cptr2;
struct ufunc_core*ufunc_core_ptr;
+7 -4
View File
@@ -85,6 +85,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%addi", of_ADDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%and", of_AND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%andi", of_ANDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
@@ -644,6 +645,8 @@ void compile_cleanup(void)
delete_symbol_table(sym_functors);
sym_functors = 0;
compile_island_cleanup();
if (verbose_flag) {
fprintf(stderr, " ... Compiletf functions\n");
fflush(stderr);
@@ -1396,16 +1399,16 @@ void compile_resolver(char*label, char*type, unsigned argc, struct symb_s*argv)
vvp_net_fun_t* obj = 0;
if (strcmp(type,"tri") == 0) {
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0));
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0,0));
} else if (strncmp(type,"tri$",4) == 0) {
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0), strdup(type+4));
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0,0), strdup(type+4));
} else if (strcmp(type,"tri0") == 0) {
obj = new resolv_functor(vvp_scalar_t(BIT4_0, 5));
obj = new resolv_functor(vvp_scalar_t(BIT4_0, 5,5));
} else if (strcmp(type,"tri1") == 0) {
obj = new resolv_functor(vvp_scalar_t(BIT4_1, 5));
obj = new resolv_functor(vvp_scalar_t(BIT4_1, 5,5));
} else if (strcmp(type,"triand") == 0) {
obj = new resolv_triand;
+14
View File
@@ -335,6 +335,8 @@ extern void compile_array_port(char*label, char*name, char*addr);
/* Index is a constant address */
extern void compile_array_port(char*label, char*name, long addr);
extern void compile_array_cleanup(void);
/*
* Compile the .ufunc statement.
*/
@@ -451,4 +453,16 @@ extern void compile_aliasw(char*label, char*array_symbol,
unsigned long array_addr, int msb, int lsb,
unsigned argc, struct symb_s*argv);
extern void compile_island(char*label, char*type);
extern void compile_island_port(char*label, char*island, char*src);
extern void compile_island_import(char*label, char*island, char*src);
extern void compile_island_export(char*label, char*island);
extern void compile_island_tranif(int sense, char*island,
char*ba, char*bb, char*src);
extern void compile_island_tranvp(char*island, char*ba, char*bb,
unsigned width, unsigned part, unsigned off);
extern void compile_island_cleanup(void);
#endif
+62 -16
View File
@@ -20,6 +20,7 @@
# include "compile.h"
# include "vvp_net.h"
# include "schedule.h"
# include <stdlib.h>
# include <iostream>
#ifdef HAVE_MALLOC_H
@@ -27,18 +28,43 @@
#endif
# include <assert.h>
# define SCHEDULE_OUTPUT 0
/* vvp_fun_concat
* This node function creates vectors (vvp_vector4_t) from the
* concatenation of the inputs. The inputs (4) may be vector or
* vector8 objects, but they are reduced to vector4 values and
* strength information lost.
*
* The expected widths of the input vectors must be given up front so
* that the positions in the output vector (and also the size of the
* output vector) can be worked out. The input vectors must match the
* expected width.
*/
class vvp_fun_concat : public vvp_net_fun_t, private vvp_gen_event_s {
public:
vvp_fun_concat(unsigned w0, unsigned w1,
unsigned w2, unsigned w3);
~vvp_fun_concat();
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
private:
void run_run();
vvp_net_t*net_;
vvp_vector4_t input_[4];
};
vvp_fun_concat::vvp_fun_concat(unsigned w0, unsigned w1,
unsigned w2, unsigned w3)
: val_(w0+w1+w2+w3)
: net_(0)
{
wid_[0] = w0;
wid_[1] = w1;
wid_[2] = w2;
wid_[3] = w3;
for (unsigned idx = 0 ; idx < val_.size() ; idx += 1)
val_.set_bit(idx, BIT4_X);
input_[0] = vvp_vector4_t(w0);
input_[1] = vvp_vector4_t(w1);
input_[2] = vvp_vector4_t(w2);
input_[3] = vvp_vector4_t(w3);
}
vvp_fun_concat::~vvp_fun_concat()
@@ -49,22 +75,42 @@ void vvp_fun_concat::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
{
unsigned pdx = port.port();
if (bit.size() != wid_[pdx]) {
if (bit.size() != input_[pdx].size()) {
cerr << "internal error: port " << pdx
<< " expects wid=" << wid_[pdx]
<< " expects wid=" << input_[pdx].size()
<< ", got wid=" << bit.size() << endl;
assert(0);
}
unsigned off = 0;
for (unsigned idx = 0 ; idx < pdx ; idx += 1)
off += wid_[idx];
if (input_[pdx] .eeq(bit))
return;
for (unsigned idx = 0 ; idx < wid_[pdx] ; idx += 1) {
val_.set_bit(off+idx, bit.value(idx));
input_[pdx] = bit;
if (net_ == 0) {
net_ = port.ptr();
if (SCHEDULE_OUTPUT)
schedule_generic(this, 0, false);
else
run_run();
}
}
void vvp_fun_concat::run_run()
{
vvp_net_t*ptr = net_;
net_ = 0;
unsigned off = 0;
unsigned owid = input_[0].size() + input_[1].size() + input_[2].size() + input_[3].size();
vvp_vector4_t res (owid);
for (unsigned idx = 0 ; idx < 4 && (off<owid) ; idx += 1) {
res.set_vec(off, input_[idx]);
off += input_[idx].size();
}
vvp_send_vec4(port.ptr()->out, val_);
vvp_send_vec4(ptr->out, res);
}
void compile_concat(char*label, unsigned w0, unsigned w1,
+2
View File
@@ -5,6 +5,8 @@ AC_PROG_CC
AC_PROG_CXX
AC_PROG_RANLIB
AC_CHECK_TOOL(STRIP, strip, true)
AC_CHECK_PROGS(MAN,man,none)
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
AC_EXEEXT
AC_SUBST(EXEEXT)
+1 -1
View File
@@ -242,7 +242,7 @@ void vvp_fun_delay::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
}
}
void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit)
void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
{
assert(port.port() == 0);
+1 -1
View File
@@ -86,7 +86,7 @@ class vvp_fun_delay : public vvp_net_fun_t, private vvp_gen_event_s {
~vvp_fun_delay();
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
void recv_real(vvp_net_ptr_t port, double bit);
//void recv_long(vvp_net_ptr_t port, long bit);
+15 -5
View File
@@ -124,8 +124,11 @@
".dff" { return K_DFF; }
".event" { return K_EVENT; }
".event/or" { return K_EVENT_OR; }
".export" { return K_EXPORT; }
".extend/s" { return K_EXTEND_S; }
".functor" { return K_FUNCTOR; }
".import" { return K_IMPORT; }
".island" { return K_ISLAND; }
".modpath" { return K_MODPATH; }
".net" { return K_NET; }
".net8" { return K_NET8; }
@@ -138,6 +141,7 @@
".part" { return K_PART; }
".part/pv" { return K_PART_PV; }
".part/v" { return K_PART_V; }
".port" { return K_PORT; }
".reduce/and" { return K_REDUCE_AND; }
".reduce/or" { return K_REDUCE_OR; }
".reduce/xor" { return K_REDUCE_XOR; }
@@ -153,6 +157,10 @@
".shift/rs" { return K_SHIFTRS; }
".thread" { return K_THREAD; }
".timescale" { return K_TIMESCALE; }
".tran" { return K_TRAN; }
".tranif0" { return K_TRANIF0; }
".tranif1" { return K_TRANIF1; }
".tranvp" { return K_TRANVP; }
".ufunc" { return K_UFUNC; }
".var" { return K_VAR; }
".var/real" { return K_VAR_R; }
@@ -173,22 +181,24 @@
"%disable" { return K_disable; }
"%fork" { return K_fork; }
/* Handle the specialized variable access functions. */
"&A" { return K_A; }
"&PV" { return K_PV; }
"%"[.$_/a-zA-Z0-9]+ {
yylval.text = strdup(yytext);
assert(yylval.text);
return T_INSTR; }
[0-9][0-9]* {
yylval.numb = strtol(yytext, 0, 0);
yylval.numb = strtoul(yytext, 0, 0);
return T_NUMBER; }
"0x"[0-9a-fA-F]+ {
yylval.numb = strtol(yytext, 0, 0);
yylval.numb = strtoul(yytext, 0, 0);
return T_NUMBER; }
"&A" { return K_A; }
/* Handle some specialized constant/literals as symbols. */
"C4<"[01xz]*">" {
+5 -37
View File
@@ -140,7 +140,6 @@ void vvp_fun_eeq::run_run()
vvp_fun_buf::vvp_fun_buf()
{
net_ = 0;
count_functors_logic += 1;
}
@@ -157,25 +156,12 @@ void vvp_fun_buf::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
if (ptr.port() != 0)
return;
if (input_ .eeq( bit ))
if (input_ .eq_xz( bit ))
return;
input_ = bit;
if (net_ == 0) {
net_ = ptr.ptr();
schedule_generic(this, 0, false);
}
}
void vvp_fun_buf::run_run()
{
vvp_net_t*ptr = net_;
net_ = 0;
vvp_vector4_t tmp (input_);
tmp.change_z2x();
vvp_send_vec4(ptr->out, tmp);
input_.change_z2x();
vvp_send_vec4(ptr.ptr()->out, input_);
}
vvp_fun_bufz::vvp_fun_bufz()
@@ -394,7 +380,6 @@ void vvp_fun_muxz::run_run()
vvp_fun_not::vvp_fun_not()
{
net_ = 0;
count_functors_logic += 1;
}
@@ -411,30 +396,13 @@ void vvp_fun_not::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
if (ptr.port() != 0)
return;
if (input_ .eeq( bit ))
if (input_ .eq_xz( bit ))
return;
input_ = bit;
if (net_ == 0) {
net_ = ptr.ptr();
schedule_generic(this, 0, false);
}
vvp_send_vec4(ptr.ptr()->out, ~input_);
}
void vvp_fun_not::run_run()
{
vvp_net_t*ptr = net_;
net_ = 0;
vvp_vector4_t result (input_);
for (unsigned idx = 0 ; idx < result.size() ; idx += 1) {
vvp_bit4_t bitbit = ~ result.value(idx);
result.set_bit(idx, bitbit);
}
vvp_send_vec4(ptr->out, result);
}
vvp_fun_or::vvp_fun_or(unsigned wid, bool invert)
: vvp_fun_boolean_(wid), invert_(invert)
+2 -10
View File
@@ -69,7 +69,7 @@ class vvp_fun_eeq : public vvp_fun_boolean_ {
* The retransmitted vector has all Z values changed to X, just like
* the buf(Q,D) gate in Verilog.
*/
class vvp_fun_buf: public vvp_net_fun_t, private vvp_gen_event_s {
class vvp_fun_buf: public vvp_net_fun_t {
public:
explicit vvp_fun_buf();
@@ -77,12 +77,8 @@ class vvp_fun_buf: public vvp_net_fun_t, private vvp_gen_event_s {
void recv_vec4(vvp_net_ptr_t p, const vvp_vector4_t&bit);
private:
void run_run();
private:
vvp_vector4_t input_;
vvp_net_t*net_;
};
/*
@@ -152,7 +148,7 @@ class vvp_fun_muxr : public vvp_net_fun_t, private vvp_gen_event_s {
sel_type select_;
};
class vvp_fun_not: public vvp_net_fun_t, private vvp_gen_event_s {
class vvp_fun_not: public vvp_net_fun_t {
public:
explicit vvp_fun_not();
@@ -160,12 +156,8 @@ class vvp_fun_not: public vvp_net_fun_t, private vvp_gen_event_s {
void recv_vec4(vvp_net_ptr_t p, const vvp_vector4_t&bit);
private:
void run_run();
private:
vvp_vector4_t input_;
vvp_net_t*net_;
};
class vvp_fun_or : public vvp_fun_boolean_ {
+14 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2007 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -66,6 +66,12 @@ extern "C" long int lround(double x)
#endif
bool verbose_flag = false;
static int vvp_return_value = 0;
void vpip_set_return_value(int value)
{
vvp_return_value = value;
}
static char log_buffer[4096];
@@ -273,9 +279,11 @@ int main(int argc, char*argv[])
vpi_mcd_printf(1, " %8lu bufif\n", count_functors_bufif);
vpi_mcd_printf(1, " %8lu resolv\n",count_functors_resolv);
vpi_mcd_printf(1, " %8lu signals\n", count_functors_sig);
vpi_mcd_printf(1, " ... %8lu opcodes (%lu bytes)\n",
vpi_mcd_printf(1, " ... %8lu opcodes (%zu bytes)\n",
count_opcodes, (unsigned long)size_opcodes);
vpi_mcd_printf(1, " ... %8lu nets\n", count_vpi_nets);
vpi_mcd_printf(1, " ... %8lu vvp_nets (%zu bytes)\n",
count_vvp_nets, size_vvp_nets);
vpi_mcd_printf(1, " ... %8lu memories\n", count_vpi_memories);
vpi_mcd_printf(1, " ... %8lu scopes\n", count_vpi_scopes);
}
@@ -293,18 +301,16 @@ int main(int argc, char*argv[])
my_getrusage(cycles+2);
print_rusage(cycles+2, cycles+1);
vpi_mcd_printf(1, "Event counts: (event pool = %lu)\n",
count_event_pool);
vpi_mcd_printf(1, "Event counts:\n");
vpi_mcd_printf(1, " %8lu time steps (pool=%lu)\n",
count_time_events, count_time_pool);
vpi_mcd_printf(1, " %8lu thread schedule events\n",
count_thread_events);
vpi_mcd_printf(1, " %8lu propagation events\n",
count_prop_events);
vpi_mcd_printf(1, " %8lu assign events\n",
count_assign_events);
vpi_mcd_printf(1, " %8lu other events\n",
count_gen_events);
}
return 0;
return vvp_return_value;
}
+6 -6
View File
@@ -33,7 +33,7 @@ void vvp_fun_pmos_::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
/* Data input is processed through eh recv_vec8 method,
because the strength must be preserved. */
if (ptr.port() == 0) {
vvp_vector8_t tmp = bit;
vvp_vector8_t tmp = vvp_vector8_t(bit,6,6);
recv_vec8(ptr, tmp);
return;
}
@@ -86,7 +86,7 @@ vvp_fun_pmos::vvp_fun_pmos(bool enable_invert)
{
}
void vvp_fun_pmos::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
void vvp_fun_pmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
{
if (ptr.port() == 1) {
recv_vec4(ptr, reduce4(bit));
@@ -105,7 +105,7 @@ vvp_fun_rpmos::vvp_fun_rpmos(bool enable_invert)
{
}
void vvp_fun_rpmos::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
void vvp_fun_rpmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
{
if (ptr.port() == 1) {
recv_vec4(ptr, reduce4(bit));
@@ -133,7 +133,7 @@ void vvp_fun_cmos_::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t &bit)
/* Data input is processed through the recv_vec8 method,
because the strength must be preserved. */
if (ptr.port() == 0) {
vvp_vector8_t tmp = bit;
vvp_vector8_t tmp = vvp_vector8_t(bit,6,6);
recv_vec8(ptr, tmp);
return;
}
@@ -187,7 +187,7 @@ vvp_fun_cmos::vvp_fun_cmos()
{
}
void vvp_fun_cmos::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
void vvp_fun_cmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
{
if (ptr.port() == 1 || ptr.port() == 2) {
recv_vec4(ptr, reduce4(bit));
@@ -206,7 +206,7 @@ vvp_fun_rcmos::vvp_fun_rcmos()
{
}
void vvp_fun_rcmos::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
void vvp_fun_rcmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
{
if (ptr.port() == 1) {
recv_vec4(ptr, reduce4(bit));
+4 -4
View File
@@ -66,7 +66,7 @@ class vvp_fun_pmos : public vvp_fun_pmos_ {
public:
explicit vvp_fun_pmos(bool enable_invert);
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
};
/*
@@ -79,7 +79,7 @@ class vvp_fun_rpmos : public vvp_fun_pmos_ {
public:
explicit vvp_fun_rpmos(bool enable_invert);
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
};
/*
@@ -121,14 +121,14 @@ class vvp_fun_cmos : public vvp_fun_cmos_ {
public:
explicit vvp_fun_cmos();
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
};
class vvp_fun_rcmos : public vvp_fun_cmos_ {
public:
explicit vvp_fun_rcmos();
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
};
#endif
+2 -34
View File
@@ -80,20 +80,6 @@ is given by the <delayx> value. This should not be 0, 1 or 3, of course,
since these registers contain the vector width, base part select and
word address.
* %assign/mv <memory-label>, <delay>, <bit> (DEPRECATED)
the %assign/mv instruction assigns a vector value to a word in the
labeled memory. The <delay> is the delay in simulation time to the
assignment (0 for non-blocking assignment) and the <bit> is the base
of the vector to write.
The width of the word is retrieved from index register 0.
The base of a part select is retrieved from index register 1.
The address of the word in the memory is from index register 3. The
address is canonical form.
* %assign/v0 <var-label>, <delay>, <bit>
* %assign/v0/d <var-label>, <delayx>, <bit>
@@ -443,12 +429,6 @@ This instruction is similar to %load/av, but it loads only a single
bit, and the <index> is the selector for the bit to use. If <index> is
out of range, then x is loaded.
* %load/mv <bit>, <memory-label>, <wid>
this instruction loads a word from the specified memory. The word
address is in index register 3. The width should match the width of
the memory word.
* %load/nx <bit>, <vpi-label>, <idx>
This instruction load a value from a .net object bit. Since .net
@@ -531,7 +511,8 @@ is one of the 4 constant bits, the effect is to replicate the value
into the destination vector. This is useful for filling a vector.
The %movi variant moves a binary value, LSB first, into the
destination vector.
destination vector. The immediate value is up to 32bits, padded with
zeros to fillout the width.
* %mul <bit-l>, <bit-r>, <wid>
@@ -667,19 +648,6 @@ width is implied from the <wid> that is the argument. This is the part
The address (in canonical form) is precalculated and loaded into index
register 3. This is the address of the word within the array.
* %set/mv <memory-label>, <bit>, <wid>
This sets a thread vector to a memory word. The <memory-label>
addresses a memory device, and the <bit>,<wid> describe a vector to be
written. Index register 3 contains the address of the word within the
memory.
The base of a part select is retrieved from index register 1.
The address (in canonical form) is precalculated and loaded into index
register 3.
* %set/wr <vpi-label>, <bit>
This instruction writes a real word to the specified VPI-like object.

Some files were not shown because too many files have changed in this diff Show More