Compare commits

..
Author SHA1 Message Date
Nick Gasson cb1d4fd278 Amend inaccurate comment 2008-08-18 16:15:05 +01:00
Nick Gasson e1deba51ab Handle BUFIF logic when vector inputs 2008-08-18 15:48:07 +01:00
Nick Gasson d53014a07f Fix leading comma it expression only has "others" part
Stop syntax errors caused by things like this:
  (, others => '1')
2008-08-18 15:36:11 +01:00
Nick Gasson 7865264de0 Implement IVL_LPM_REPEAT 2008-08-18 15:34:58 +01:00
Nick Gasson 86661c1538 Add a few more `unsupported' messages 2008-08-18 15:29:30 +01:00
Nick Gasson e2dd7425bd Add error messages for unsupported statement types 2008-08-18 15:24:38 +01:00
Nick Gasson e01b16e586 Merge branch 'master' of git://icarus.com/~steve-icarus/verilog into vhdl 2008-08-18 15:16:02 +01:00
Nick Gasson 6adc3c9f13 Add short section on VHDL to man page 2008-08-17 19:42:07 +01:00
Martin Whitaker 2c1426a44d Patch to ensure functions are evaluated immediately.
This patch causes a thread that is created to evaluate a function
to be executed immediately. The parent thread is resumed when the
function thread terminates.
2008-08-16 14:42:17 -07:00
Cary R 1f5b11246e Correctly pass a concatenation elaboration error.
Because Icarus tries to elaborate as much as it can even after
an error has occurred we need to check for these errors during
elaboration. This patch prevent an undefined identifier from
crashing the compiler.
2008-08-15 17:26:08 -07:00
Cary R d3caa547ba Print an error for automatic tasks or functions.
This patch adds code to recognize and report that automatic
task or functions are not currently supported.
2008-08-15 17:10:59 -07:00
Nick Gasson 026d941734 Avoid printing field widths in $display/$write output
This removes some unwanted artifacts from the output.
2008-08-15 19:43:16 +01:00
Nick Gasson a577ee447b Generate process for sequential UDPs 2008-08-13 17:03:03 +01:00
Nick Gasson d7b85c42a0 Split sequential and combinatorial UDPs into separate functions 2008-08-13 11:57:05 +01:00
Nick Gasson dea54df71b Catch possibly NULL return value
This is caused by using a hierarchical reference (which can't
be translated to VHDL). The result of get_decl is NULL since
the signal has been declared in a different VHDL architecture.
Adding the assert is cleaner than having it segfault, for the
moment, until a nicer error message can be added.
2008-08-12 09:47:03 +01:00
Nick Gasson a3929330b0 Fix regression caused by UDP delay patch
translate_time_expr cannot be passed a NULL ivl_expr_t.
2008-08-11 20:53:13 +01:00
Nick Gasson c404b761b7 Change out' ports to buffer' when the signal is read
Previously this was handled by creating an internal
signal that was connected to the output and could also
be read inside the entity. The correct solution is to
make the output `buffer' rather than `out'. However, this
does not work in the case when an output is connected to
an output of a child entity, and that values is read
in the parent. In this case *both* the outputs of the child
and the parent need to be made `buffer'.
2008-08-11 20:48:28 +01:00
Nick Gasson 9b1f2d5971 Remove UDP debug messages from output 2008-08-11 20:37:10 +01:00
Nick Gasson 9d7e4ac15f Allow delays in combinatorial UDPs
Add a `after' clause to the `with .. select' statement.
2008-08-11 20:36:09 +01:00
Nick Gasson d55a3a073a Handle '?' in vl_to_vhdl_bit
The rough translation is '-', although the semantics are incompatible
in some cases (e.g. '-' = '1' is false)
2008-08-11 13:53:42 +01:00
Nick Gasson 01bf741983 Implement combinatorial UDPs
Using a `with .. select' statement
2008-08-11 13:23:50 +01:00
Nick Gasson bf3734110e Add VHDL syntax element for `with .. select' statement
This will be used to implement combinatorial UDPs
2008-08-11 13:09:52 +01:00
Nick Gasson 6dcf936807 Generate combined input for UDP devices
Combinatorial UDPs will be implemented with a `with ... select'
statemetnt. However the input to this must be "locally static".
This patch joins the inputs into a vector which can be used as
the select expression.
2008-08-11 12:58:46 +01:00
Nick Gasson 8e0bf3ebff Add conversion from std_logic to (un)signed types
Implemented using the expression (0 => X, others => '0')
2008-08-10 11:22:23 +01:00
Nick Gasson 380e3a8121 Merge branch 'master' of git://icarus.com/~steve-icarus/verilog into vhdl 2008-08-10 09:51:20 +01:00
Cary R 1f8ff7ff8d Pass a NULL expression when parameter expression elaboration fails
When elaborating a parameter expression fails we need to set the
expression to 0 since it has already been partially allocated.
Doing this allows us to not evaluate the dummy expression later.
2008-08-09 19:27:14 -07:00
Cary R b1f1c11441 User task and function arguments can be time or realtime
This patch adds the time and realtime properties for user
task and function arguments. It also make a common rule
for real and realtime since they are the same.
2008-08-09 19:10:09 -07:00
Cary R c918cf4a46 User task and function arguments can take an optional reg.
User task and function arguments can take an optional reg
property. This property is completely ignored by Icarus.
2008-08-09 19:04:17 -07:00
Cary R f835c7569e Check for a possible corrupt function definition and return.
If a function definition has no ports and no return type it is
assumed to be a bad definition so we don't check it further.
2008-08-09 18:46:18 -07:00
Martin Whitaker 5aecd044c5 Patch to fix pr2043585.
This patch fixes a bug in the VVP code generator that causes syntactically
incorrect code to be generated if an event expression contains a memory or
array port.
2008-08-09 18:22:46 -07:00
Cary R 2a389a9abe Display signal array size when using -delaborate.
This patch modifies one of the debug_elaborate messages to display
the array information when needed.
2008-08-09 18:10:59 -07:00
Nick Gasson 6527262348 Add correct file/line information to signals
This patch adds a FILE_NAME function for signals to extract
the file/line information from the net's LineInfo, replacing
the dummy values.
2008-08-09 16:57:26 -07:00
Stephen Williams 79e1273814 Do not consome pform defparams in module definition.
The list of defparams in the pform module definitions (in class Module)
should not be consumed when they are used. The module may be instantiated
moltiple times, so consuming the defparams during elaboration will cause
subsequent instantiations to not have the defparams. That's wrong.
2008-08-09 16:45:20 -07:00
Nick Gasson 709c850e69 Add correct file/line information to signals
This patch adds a FILE_NAME function for signals to extract
the file/line information from the net's LineInfo, replacing
the dummy values.
2008-08-08 20:35:27 +01:00
Nick Gasson 7ed8c0915d Add file/line comments to signal declarations 2008-08-08 20:28:16 +01:00
Nick Gasson eef1c968dc Add message that casex cannot be translated
...with the correct behavior. It would be possible to
just translate it as a regular VHDL case statement (as
it was before this patch). But the behavior is not
correct as VHDL only does the equivalent of case-equality
in case statements and this can be confusing when debugging
the output. An alternative might be to emit a warning rather
than an error.
2008-08-08 20:09:40 +01:00
Nick Gasson 0985158090 Handle %% in $display 2008-08-08 20:07:22 +01:00
Nick Gasson 090ae5fa56 Catch case where signal with same name in task and module
This fixes task3.14C
2008-08-08 19:47:20 +01:00
Nick Gasson 13cb81f4bb Add task signals to containing architecture
This is necessary to support the in-line expansion of tasks
2008-08-08 19:31:45 +01:00
Cary R ef66ca6498 Do a part select of the array selection result not the base array.
When doing the part select of an array selection you need to use
the result from the array selection to do the part select not the
base array signal.
2008-08-07 20:45:58 -07:00
Cary R d43452f88d Check all generate expressions for failure.
This patch adds code to check that the various generate expressions
evaluate correctly.
2008-08-07 20:41:24 -07:00
Cary R e719dc250a %load/av now matches %load/v for truncating/extension.
This patch adds code to make %load/av extend or truncate
a value like %load/v.
2008-08-07 20:34:20 -07:00
Nick Gasson bb0efda526 Make make_safe_name case insensitive 2008-08-07 17:58:42 +01:00
Nick Gasson e4d0a92d7c Division and modulus operators 2008-08-07 14:18:26 +01:00
Nick Gasson 28d782e13c Remove redundant verilog_support.vhd file 2008-08-07 13:10:53 +01:00
Nick Gasson 6f5f700cb9 Very minimal implementation of tasks
This expands the task in-line inside the process to avoid
problems with global variables (VHDL processes cannot
reference globals)
2008-08-07 10:54:39 +01:00
Nick Gasson a17924f819 Merge branch 'master' of git://icarus.com/~steve-icarus/verilog into vhdl 2008-08-07 09:19:13 +01:00
Stephen Williams 893aae2ca4 Add BUFZ to input ports when necessary.
When driving an input port to a module, watch out for the case where
the net is also driven within the instance. If this is the case, take
pains to make sure what goes on in the instance doesn't leak out
through the input port. Add a BUFZ (continuous assignment) to isolate
the context from internal driving.
2008-08-06 21:04:52 -07:00
Nick Gasson 4cbec1c817 Add XNOR binary operand 2008-08-06 11:18:01 +01:00
Holger Wächtler d84771428a need to decrement string len if we have a '-' sign 2008-08-05 15:26:29 -07:00
Holger Wächtler 484d3ea36b this patch adds support for conversion of negative vpiDecStrVal in vpip_dec_str_to_vec4() 2008-08-05 15:26:22 -07:00
Holger Wächtler c71e930ffa $fscanf("%s"): accept '-' and '_' chars. 2008-08-05 15:26:16 -07:00
Holger Wächtler 15584a4f81 fix $fscan("%d") for values > 32 bit
The old code returns a vpiIntVal for $fscanf("%d") format strings. This
limits the maximum input range arbitrarily to 32 bit.

This patch implements %d parsing similiar to %b and %x.

'?' and 'X' chars are not accepted for %d format.
2008-08-05 15:26:09 -07:00
Nick Gasson f86f454956 Apply the last patch to if/case statements too
This further cleans up the output by removing more
useless `wait for 0ns' statements.
2008-08-05 11:09:51 +01:00
Nick Gasson e01e038cf9 Avoid generating useless `wait for 0ns' statements
If the final statement in a process is a non-blocking
assignment then there is no point adding a `wait for 0ns'
after it since it will be immediately followed by another
wait. This case is suprisingly common, so this patch helps
generate much cleaner output without breaking the cases
where the 0ns wait is actually required (e.g. to implement
non-blocking assignment properly).
2008-08-05 11:02:36 +01:00
Nick Gasson c849dfeec4 Add XNOR logic device 2008-08-05 10:45:01 +01:00
Nick Gasson 8d7b03576c Correctly implement unary XNOR
Forgot to negate the output.
2008-08-05 10:38:43 +01:00
Nick Gasson 72019959a8 Translate some ternary expressions to if statements
This re-implements some earlier functionality where
ternary expressions on an assignment RHS are translated
to an if statement.
2008-08-03 15:47:32 +01:00
Nick Gasson 9565ea1034 Add some whitespace above component instantiations 2008-08-03 14:50:13 +01:00
Nick Gasson 49a2693357 Add file / line number information to functions 2008-08-03 14:46:57 +01:00
Nick Gasson 10a5ca199d Add file / line number comments to instantiations 2008-08-03 14:38:08 +01:00
Nick Gasson c2f622327f Use ivl_scope_def_* for definition file/line numbers 2008-08-03 14:34:41 +01:00
Nick Gasson 0e2628a3fb Minimal implementation of IVL_LPM_MUX
This handles the (common) case of the select being only
1 bit wide. Implemented as a concurrent assignment with
a `when' clause.
2008-08-03 12:46:50 +01:00
Nick Gasson 45dfa28dba Remember signal pin a nexus was attached to
Also modify nexus_to_var_ref to set the correct array
offset when the signal is an array (the offset comes
from the pin).
2008-08-03 11:41:26 +01:00
Nick Gasson c8cbac58f5 Add forward declarations for functions
This patch adds a forward declaration for every user funciton.
This fixes VHDL compile problems if a function calls another
before it has been declared.
2008-08-03 10:50:31 +01:00
Nick Gasson c1b5424ca6 Implement assignment with multiple lvals
Multiple lvals are implemented by first assigning the complete
RHS to a temporary, and then assigning each lval in turn as
bit-selects of the temporary
2008-08-02 18:40:24 +01:00
Nick Gasson c706c94e38 Generate a vhdl_var_ref for every assignment lval
This completes the refactoring of make_assignment
necessary to implement multiple lvals.
2008-08-02 18:20:18 +01:00
Nick Gasson fad8abee34 Start refactoring make_assignment for multiple lvals
This patch lifts the RHS generating code out of the
lval-specific code and sticks a loop around the lvals.
2008-08-02 16:38:44 +01:00
Nick Gasson 9448c5939c Always user Ternary_* support functions for ternary assignments
Previously the code generator expanded ternary assignments to
and `if' statement. This patch replaces that with a single assignment
and a call to a Ternary_* support function. This will make it
much easier to support multiple lvals later.
2008-08-02 15:46:36 +01:00
Nick Gasson 752a90dc2f Insert blank line before VHDL process in output 2008-08-02 10:45:38 +01:00
Nick Gasson a60216ec15 Use ivl_process_* functions for file/line number information 2008-08-02 10:44:03 +01:00
Nick Gasson 5d0df8d880 Change format of line file/line numbers 2008-08-02 10:42:00 +01:00
Nick Gasson 1cd13ecdbd Merge branch 'master' of git://icarus.com/~steve-icarus/verilog into vhdl 2008-08-02 10:37:22 +01:00
Cary R aeec93a322 $time, $stime and $simtime return an integer rounded value for %f
The $time, $stime, $simtime (integer time) system functions should
return a rounded integer value in a real context.
2008-08-01 20:37:41 -07:00
Cary R 61930c3b6e Add file and line information to processes.
This patch adds file and line information to processes
(initial and always).
2008-08-01 20:13:29 -07:00
Cary R 296f1bacc1 vvp_vector4_t words are unsigned long.
The double to vvp_vector4_t constructor was not using the correct
declaration for the bit words. This worked as long as unsigned and
unsigned long were the same size (usually).
2008-08-01 20:10:52 -07:00
Nick Gasson bb80b432e6 Add comments file/line number comments
Added to entities, architectures, and processes
2008-08-01 21:21:42 +01:00
Stephen Williams be551a6b68 Add a stub vvp_net_t::delete method
Some compilers reference the delete method for the vvp_net_t object
even though it is never used. So provide a stub with an assert.
2008-08-01 09:48:59 -07:00
Nick Gasson e0834f7f38 Add NAND and NOR logic devices 2008-08-01 17:46:04 +01:00
Nick Gasson a26d91557b Add binary NAND and NOR operators 2008-08-01 17:42:26 +01:00
Nick Gasson 3f73c9bb54 Make sure argument to unary - is signed 2008-08-01 16:35:47 +01:00
Nick Gasson 09f3eb4a36 Don't bother calling reduction function if argument is std_logic 2008-08-01 16:27:55 +01:00
Nick Gasson 33885ed891 Merge branch 'master' of git://icarus.com/~steve-icarus/verilog into vhdl 2008-08-01 08:25:38 +01:00
Nick Gasson d21277f1b9 Tidy up whitespace in output 2008-07-31 21:17:49 +01:00
Nick Gasson 7b0f675785 Add check for sequential UDPs 2008-07-31 21:08:59 +01:00
Nick Gasson db339b8fc3 Stub for UDP logic devices 2008-07-31 20:59:20 +01:00
Stephen Williams 4ca7f2a9bd Merge branch 'master' of ssh://[email protected]/~steve-icarus/git/verilog 2008-07-30 18:05:43 -07:00
Cary R 3191b3efcb An included file should start at line 1.
The preprocessor was incorrectly setting the line when starting
an include file to the line it was called from instead of 1.
This would give incorrect line numbers for errors/warnings in
the included file.
2008-07-30 15:04:19 -07:00
Cary R 1a41ac3145 Update real to int conversion: -inf is 'b0 not 'b1 like +inf.
The new real to int conversion was incorrectly setting the
bits for minus infinity to all ones. This is incorrect in a
two's complement encoding where the largest negative number
would be a leading 1 followed by an infinite number of zeros.
2008-07-30 14:59:13 -07:00
nog 6d4dd5ae3b Fix macro argument replacements
When searching for macro arguments to replace, make sure that the
argument is not the begining of another identifier.
2008-07-30 14:52:04 -07:00
Cary R 6cb3d86d15 Update %cvt/vr to use new double to vector conversion (constructor).
This patch updates the %cvt/vr command to use the new double to vector
constructor. This allows the resulting bit pattern to be larger than
a long. The old method was producing incorrect results without a
warning for large bit values.
2008-07-30 14:40:14 -07:00
Cary R 7a4f85d382 Make .part/pv strength aware and resolv vec8_pv aware.
This patch makes .part/pv strength aware, resolv vec8_pv
aware. vvp_net_fun_t adds vec8_pv as a virtual function
with an appropriate error default. vvp_fun_signal should
full support vec8_pv (not tested and may not be needed).
2008-07-30 14:31:33 -07:00
Cary R 5207be0778 Use ivl_signal_dimensions to find arrays not ivl_signal_array_count
ivl_signal_dimensions() is the correct call to use to determine
if a signal is part of an array. If it is greater than zero the
signal is an array.
2008-07-30 14:25:29 -07:00
Cary R 2ceb0539af IVL_VT_LOGIC is default localparam type not IVL_VT_NO_TYPE
This patch fixes a bug where a local parameter with only a range
was incorrectly setting the default parameter type to IVL_VT_NO_TYPE.
This would create a compile time assert for any untyped
parameter/localparam immediately following it.
2008-07-30 14:16:18 -07:00
Cary R f9c67e21b2 Some variable part select arguments must be drawn before the part select.
Some variable part selects need to draw the select argument before the
variable part select is printed e.g.(.array/port).
2008-07-30 14:07:03 -07:00
Nick Gasson baa2363e85 Split logic device code into separate file 2008-07-30 10:13:08 +01:00
Nick Gasson e5b8abfb23 Remove debugging output 2008-07-29 21:15:51 +01:00
Nick Gasson 9f6f711f8d Remove unused variable 2008-07-29 21:08:50 +01:00
Nick Gasson 9a5b7bb0b0 Connect signals together if joined in a nexus 2008-07-29 21:03:00 +01:00
Nick Gasson eaf1cc9120 Fix assertion failure with arrayed signals 2008-07-29 19:47:17 +01:00
Nick Gasson 3bcd42dc8f Fix case where logic device has no valid output 2008-07-29 19:39:20 +01:00
Nick Gasson 744fbed783 Finish re-writing nexus code 2008-07-29 19:33:40 +01:00
Nick Gasson c9454b346e Fix module3.12B 2008-07-29 19:04:41 +01:00
Nick Gasson 5ec2c37e7e Get functions working again 2008-07-29 15:29:49 +01:00
Nick Gasson 25602e487d Comment 2008-07-29 15:12:51 +01:00
Nick Gasson e037ffd952 Create temporaries for LPM outputs 2008-07-29 15:09:58 +01:00
Nick Gasson 48c1a7982c Make seen_nexus private 2008-07-29 14:24:04 +01:00
Nick Gasson a842b327c7 Generate constant drivers as concurrent assignments 2008-07-29 14:02:05 +01:00
Nick Gasson f8034d69ef Fix constants in nexuses 2008-07-29 13:30:54 +01:00
Nick Gasson d94dac28a8 Remove redundant lpm_output 2008-07-29 13:08:13 +01:00
Nick Gasson 680c6f0503 Make sure LPMs have valid inputs/outputs 2008-07-29 13:06:21 +01:00
Nick Gasson 39717989a8 Call set_active_entity in the right places 2008-07-29 13:04:29 +01:00
Nick Gasson c26b7ce675 Port maps 2008-07-29 13:02:55 +01:00
Nick Gasson c6f6ea7358 Instantiation working again 2008-07-29 12:21:19 +01:00
Nick Gasson c0c838f1bc Logic devices now working again 2008-07-29 12:11:44 +01:00
Nick Gasson 1a45e9164f Find signal a logic device is connected to 2008-07-29 12:04:40 +01:00
Nick Gasson 8a5f129e56 Draw nexus in multiple passes 2008-07-29 12:00:26 +01:00
Nick Gasson 65c2ceb89d Build entity hierarchy in separate stages 2008-07-29 11:01:02 +01:00
Nick Gasson 7a2e9c02cd Simplify support function emitting code 2008-07-28 22:48:21 +01:00
Nick Gasson f88415b1d7 Conversion of std_logic to integer 2008-07-28 22:46:39 +01:00
Nick Gasson 1250010696 Merge branch 'vhdl' of [email protected]:nickg/iverilog into vhdl
Conflicts:

	tgt-vhdl/support.cc
2008-07-28 21:47:37 +01:00
Nick Gasson 506a0ba7d6 Support repeat in concatenation 2008-07-28 21:46:19 +01:00
Nick Gasson 1d4914c590 Undo last commit 2008-07-28 13:04:30 +01:00
Nick Gasson 3e28a10676 Compress support function names a bit 2008-07-28 13:02:04 +01:00
Nick Gasson 78028a3310 Fully support ternary expressions 2008-07-28 12:59:10 +01:00
Nick Gasson b9cecbef64 Make sure LPM comparison result is std_logic not Boolean 2008-07-27 19:05:49 +01:00
Nick Gasson 8b32096e2a Convert std_logic to Boolean in loop tests 2008-07-27 18:39:16 +01:00
Nick Gasson ba462eb8b7 Merge branch 'vhdl' of [email protected]:nickg/iverilog into vhdl 2008-07-25 20:00:26 +01:00
Nick Gasson 5a09819729 Catch case of select expression on non-variable 2008-07-24 16:00:12 +01:00
Nick Gasson d3296d4895 Refactor while/for loop code to use common base 2008-07-24 15:22:25 +01:00
Nick Gasson 39c9c54760 Add repeat statement 2008-07-24 14:52:06 +01:00
Nick Gasson 8bee5b1108 Add `forever' statement type 2008-07-24 14:30:10 +01:00
Nick Gasson e4c2400eb2 Refactor the expression->time code into a single function 2008-07-23 16:18:49 +01:00
Nick Gasson 1409207def Correctly indent case statements 2008-07-23 14:31:41 +01:00
Nick Gasson 30fdadc525 Support delays in logic devices 2008-07-23 13:40:42 +01:00
Nick Gasson a5db0297b0 Unary minus 2008-07-22 15:44:29 +01:00
Nick Gasson e25f946ac0 Merge branch 'vhdl' of file:///media/disk/data/iverilog/ into vhdl 2008-07-21 15:20:42 +01:00
Nick Gasson 2f4f075005 Typo 2008-07-21 15:20:40 +01:00
Nick Gasson 3ca85491ee Unary AND and XOR 2008-07-20 16:41:57 +01:00
Nick Gasson d8351ec1b2 Fix reduction OR in procedural code 2008-07-20 15:13:20 +01:00
Nick Gasson 77508b9afa Reduction OR operator 2008-07-20 15:10:00 +01:00
Nick Gasson 38de6ebf3a Compress support function definitions a bit 2008-07-19 21:04:52 +01:00
Nick Gasson af3ee49f57 Refactor support function code a bit 2008-07-19 20:49:55 +01:00
Nick Gasson 0cb6ea34d7 Move type conversion code into a separate file 2008-07-19 15:23:47 +01:00
Nick Gasson b6df73d3b9 Support functions for converting (un)signed -> boolean 2008-07-19 15:15:16 +01:00
Nick Gasson 2d79e1a2e0 Store the currently active entity 2008-07-19 14:45:00 +01:00
Nick Gasson 7b311b6adb Translate internal delays in assignments 2008-07-18 14:47:35 +01:00
Nick Gasson df4a380e42 Fix implementation of IVL_LPM_UFUNC
Function name was not correct.
2008-07-18 14:31:12 +01:00
Nick Gasson 6ff80e80a4 Catch case where (un)signed is converted to boolean 2008-07-18 12:30:24 +01:00
Nick Gasson 8b6b111541 Add IVL_LPM_CMP_EQ 2008-07-18 11:58:26 +01:00
Nick Gasson fd8f01e317 Add IVL_LPM_CMP_GE 2008-07-18 11:56:00 +01:00
Nick Gasson 00317dd47f Dummy implementation of $time 2008-07-18 11:50:05 +01:00
Nick Gasson e9637f6d11 Generate synthesisable code for sequential processes
Whilst adding `wait until ...' at the end of every
process is a valid translation of the input, it is not
actually synthesisable in at least one commercial
synthesiser (XST). According to the XST manual the
correct template is to use `wait until ...' at the
start of sequential processes and `wait on ...'
(equivalent to `wait until ...' with 'Event on all
the signals) at the end of combinatorial processes.
This patch implements that.
2008-07-17 17:36:42 +01:00
Nick Gasson 1f9ed2c5ec VHDL AST element for `wait on' statement 2008-07-17 17:23:21 +01:00
Nick Gasson 7677b59650 Make sure offset of IVL_LPM_ARRAY is integer 2008-07-17 16:41:34 +01:00
Nick Gasson 9cf4792d53 Translate array references in expressions 2008-07-17 14:47:10 +01:00
Nick Gasson 4d9f029000 Generate correct array bounds 2008-07-17 14:38:07 +01:00
Nick Gasson 9916686c24 Convert constant bits to integers 2008-07-17 14:29:56 +01:00
Nick Gasson c86377790f Automatically convert constant bit strings to integers 2008-07-17 14:26:35 +01:00
Nick Gasson 2a791bfb38 Assignment to arrays 2008-07-17 13:41:44 +01:00
Nick Gasson 1d3ac6bc1f Generate VHDL array type declarations of Verilog arrays 2008-07-17 13:08:55 +01:00
Nick Gasson 3fa5a04947 Merge branch 'vhdl' into array 2008-07-17 12:01:09 +01:00
Nick Gasson 7c5b0f737c Class for VHDL type declarations 2008-07-17 11:59:02 +01:00
Nick Gasson c116808fdb Remove duplicated code 2008-07-17 11:46:36 +01:00
Nick Gasson 553f3d77a9 Code for VHDL array type 2008-07-17 11:43:59 +01:00
Nick Gasson 642fbe9fc5 Correct check for arrays 2008-07-17 11:31:06 +01:00
Nick Gasson 395a2248d8 Make sure 1-bit constants are std_logic not (un)signed 2008-07-16 16:52:15 +01:00
Nick Gasson be67cae29f Add translation for IVL_ST_CASEX 2008-07-16 16:42:44 +01:00
Nick Gasson f62a00bedb Fix LPM binop with different signedness
Need to explicitly cast between signed/unsigned to
make sure both arguments have the same type or the
VHDL won't compile.
2008-07-16 16:20:08 +01:00
Nick Gasson 646a6056a2 Add IVL_LPM_CMP_EEQ support 2008-07-16 12:50:55 +01:00
Nick Gasson 4504c2bceb Fix initialisation order bug with `if' statements
If an assignment appears inside an if statement branch
it could be incorrectly used as the signal's initial
value.
2008-07-16 12:11:00 +01:00
Nick Gasson d343db34fd Fix initialisation order
Initial processes set a magic flag in the code generator
which allows it to push constant assignments into the
VHDL signal initialisation and omit the assignment.
However, it should only do this if the signal has not
already been read (otherwise the previous read would
not get the undefined value as expected)
2008-07-16 12:00:11 +01:00
Nick Gasson b5e12077b2 Fix assignment to lval slice
It was broken in yeserday's refactoring
2008-07-15 18:40:30 +01:00
Nick Gasson f3753ea9ad Add warning that arrays are not yet implemented 2008-07-15 18:09:18 +01:00
Nick Gasson 45e289d32d Implement IVL_LPM_SHIFTL/R 2008-07-15 18:01:37 +01:00
Nick Gasson 40cabff44f Leave blank line at end of function 2008-07-15 16:30:50 +01:00
Nick Gasson a9c98ad5f2 Handle `if' with empty cond_true part
Fixes assertion failure with following statement:

if (foo)
  begin
  end
else
  ...
2008-07-15 14:26:19 +01:00
Nick Gasson b8e758edf0 Refactor LPM code 2008-07-15 14:09:24 +01:00
Nick Gasson 0b48f69b4e Tidy up blocking assignment code 2008-07-15 10:44:48 +01:00
Nick Gasson d1e7e325b7 Remove redundant edge_detector function 2008-07-14 21:34:48 +01:00
Nick Gasson 75b1db0add Fix assignment with ternary RHS
This was also broken in the last commit
2008-07-14 21:27:21 +01:00
Nick Gasson 6e965523a1 Fix PV assignment (was broken in last commit) 2008-07-14 21:09:19 +01:00
Nick Gasson 8589c0691b Refactor assignment code 2008-07-14 21:04:09 +01:00
Nick Gasson 99ef8ec4f1 Simplify edge detector code
Now generates a `wait until' statement rather than a
sensitivity list.
2008-07-14 20:29:49 +01:00
Nick Gasson d22c9a8b05 Simplify blocking assignment
Now generates 'wait for 0 ns' after non-blocking assignment
2008-07-14 19:54:45 +01:00
Nick Gasson f84f50842c Support bufif for tri1 nets 2008-07-14 19:13:11 +01:00
Nick Gasson 65720f49fe Simple bufif cases 2008-07-14 19:00:58 +01:00
Nick Gasson 6243736481 Pull-up/pull-down logic devices 2008-07-14 12:04:20 +01:00
Nick Gasson e331e4831b Fix nexus_to_expr where nexus has IVL_LPM_SELECT_PV 2008-07-14 11:53:38 +01:00
Nick Gasson 78ee61558d Remove redundant test
Signal is guaranteed to appear in arch_scope or its parent
by the surrounding `if' statement.
2008-07-13 15:27:07 +01:00
Nick Gasson 07c4ff7ea7 Add assertion about result of lpm_to_expr 2008-07-13 15:26:03 +01:00
Nick Gasson e5422dddd2 Remove useless `ignore' param to nexus_to_expr 2008-07-13 15:24:35 +01:00
Nick Gasson 6af201ea03 Refactor nexus expansion functions.
Now a single function nexus_to_expr
2008-07-13 15:17:14 +01:00
Nick Gasson 27a40cfdcd Constant assignments to outputs
If the Verilog source contained a continuous assignment
of a constant to an output, it would not be present in
the VHDL output. This patch generates a VHDL continous
assignment in these cases.
2008-07-13 13:02:17 +01:00
Nick Gasson 3bd480a375 Allow ouput to be read if connected to child output
If output P of A is connected to output Q of B (and A is
instantiated inside B) then VHDL does not allow B to read
the value of Q (also P), but Verilog does. To get around
this the output Q is mapped to P_Sig which is then connected
to P, this allows B to read the value of P/Q via P_Sig.
2008-07-13 12:41:02 +01:00
Nick Gasson aa951af2b7 Change 'signdness' to 'signdness' 2008-07-10 19:27:17 +01:00
Nick Gasson 55747bf79d Refactor signdness changing code into a single function
This is the code that generated calls to signed/unsigned in
the VHDL output.
2008-07-08 13:07:11 +01:00
Nick Gasson 1cd7689d03 Fix casting with signed/unsigned expressions
Previously the code generator tried to infer the VHDL types. Now it
takes a much more dumb approach and forces the VHDL type to be
the same as the ivl type (derived from ivl_expr_signed and
ivl_expr_width) in the expression tree. This works much better :-)
2008-07-08 12:58:50 +01:00
Nick Gasson bd5cc96956 Correct vector sizes for bit select 2008-07-08 00:20:31 +01:00
Nick Gasson a0dbb1aa5d Fix more bugs in part selects 2008-07-07 21:45:27 +01:00
Nick Gasson 4777966b4c Bit select bug fixes 2008-07-07 21:19:59 +01:00
Nick Gasson 860a74ddd8 Allow LPMs in port maps 2008-07-07 20:41:29 +01:00
Nick Gasson 2bb645e0bc Refactor LPM code to allow lpm->expr function 2008-07-07 19:46:18 +01:00
Nick Gasson 47db80315c Add sign extension LPM 2008-07-07 19:27:52 +01:00
Nick Gasson 0348664512 Correctly determine VHDL type of LHS of part select 2008-07-07 16:35:39 +01:00
Nick Gasson 3987e0753d Fix case where booleans are compared against vectors 2008-07-07 16:31:27 +01:00
Nick Gasson 6b73cc39a5 Add Active_High support func and fix LPM part select 2008-07-07 16:17:54 +01:00
Nick Gasson b0de1a8d7e Implement part select for LHS of assignment 2008-07-07 16:11:45 +01:00
Nick Gasson 37fe6e4219 Dummy implementation of IVL_LO_BUF* 2008-07-07 15:49:51 +01:00
Nick Gasson 89cdbf63be Reduction LPM types 2008-07-07 15:45:20 +01:00
Nick Gasson 7f955cc070 Move the VHDL support package 2008-07-07 15:36:13 +01:00
Nick Gasson 4db5b9d7ed Add unary OR/NOR
These are currently implemented with reference to an external
Reduce_OR function
2008-07-07 15:23:57 +01:00
Nick Gasson dadd145d09 Add message for unsupported LPM nexus pointer 2008-07-07 15:04:28 +01:00
Nick Gasson bdf5ee7ab7 Concat LPM 2008-07-07 14:48:57 +01:00
Nick Gasson ebaa4c7d5d Implement assignment to part select properly
Previously the base of the lval was ignored, this ensures
the correct assignment is generated.
2008-07-07 11:00:27 +01:00
Nick Gasson c33600bcc3 Add concatenation operator 2008-07-06 18:21:34 +01:00
Nick Gasson 85d2cc78d6 Finish ternary operator expansion 2008-07-06 17:56:48 +01:00
Nick Gasson 18071562ba Partially implement ternary expressions
This handles the case where the expression appears as the
right hand side of an assignment. The expression is converted
into a regular if statement.
2008-07-04 21:55:51 +01:00
Nick Gasson 5aeff6d47d Merge blocking and non-blocking assignment code 2008-07-04 20:07:38 +01:00
Nick Gasson a298b03735 Add bitwise OR 2008-07-04 12:05:49 +01:00
Nick Gasson 3d0a2b55ce Avoid declaring same function multiple times
If it appears in multiple places in the hierarchy
2008-07-04 12:03:37 +01:00
Nick Gasson 19871efd5a Fix bug where sensitivity might reference undefined signals 2008-07-04 11:58:33 +01:00
Nick Gasson 1410c339de Make sure any calls to numeric_std Resize have correct type
The signed/unsigned-ness of an expression needs to be
preserved over any call to Resize. Also add a sanity
check to make sure non-vector types are not resized.
2008-07-04 11:36:11 +01:00
Nick Gasson 96d32b29c9 Translate logical expressions correctly.
For logical AND/OR in VHDL both operands must be of the
same type (Boolean)
2008-07-04 11:23:32 +01:00
Nick Gasson 88816e150a Properly parenthesise unary operators 2008-07-04 11:17:24 +01:00
Nick Gasson 409fc4dc19 Check if case expression variable is already defined
Verilog_Case_Ex is used as a temporary to store the result of
any non-static case expression. This fixes a bug where it would
be declared multiple times if there were multiple case statements
in a block.
2008-07-04 11:15:34 +01:00
Nick Gasson c54b36c902 Add logical AND operator 2008-07-04 11:10:20 +01:00
Nick Gasson 19cbab78b2 Tidy up code to generate default branch of case 2008-07-03 20:04:47 +01:00
Nick Gasson 1736cd9bc8 Fix uneccessarily complicated generated case statement
No need to generate separate case test variable if the
test in the VL source is a simple variable reference.
2008-07-03 16:27:36 +01:00
Nick Gasson a5264e9995 Make sure all choices are covered in case statement 2008-07-03 16:17:56 +01:00
Nick Gasson 6868127ba3 Make sure case expression has the correct type 2008-07-03 16:14:17 +01:00
Nick Gasson dbbadbc309 Make sure the renamed signal is used in the sensitivity list 2008-07-03 16:13:02 +01:00
Nick Gasson fb08164cbc List some more illegal VHDL names 2008-07-03 15:20:43 +01:00
Nick Gasson 7e999c5496 Fix continuous assignment of constants
E.g. in assign p = 1 the RHS signal in the generated LPM now
has a correct intial value (and it will never be written to
elsewhere)
2008-07-03 15:13:12 +01:00
Nick Gasson 4fac825457 Add PV part select type 2008-07-03 14:45:54 +01:00
Nick Gasson 35c66744db Cleanup and remove debug output 2008-07-01 11:31:00 +01:00
Nick Gasson 930e04f6c7 Ensure port map expressions are globally static 2008-07-01 11:28:02 +01:00
Nick Gasson 37756b8d06 Avoid mapping a signal to itself 2008-07-01 11:13:02 +01:00
Nick Gasson 596c93ce7e Rename instance if it has the same name as the type 2008-07-01 11:05:24 +01:00
Nick Gasson edfae1abfb PV LPM part select type 2008-07-01 11:02:49 +01:00
Nick Gasson 624943b3ca Simplify port map generation code 2008-07-01 10:59:31 +01:00
Nick Gasson ef89a760d6 Add vhdl_element::print method for debugging 2008-07-01 10:44:20 +01:00
Nick Gasson 050aa277ae Make vhdl_element::emit a little more generic 2008-07-01 10:37:22 +01:00
Nick Gasson f03dfb50ad Refactor nexus_to_var_ref 2008-07-01 10:33:46 +01:00
Nick Gasson 6e8474f584 Fix bug where func had to be declared before use 2008-06-30 17:58:15 +01:00
Nick Gasson 4e73b1b133 Fix bug when resolving nexus to VHDL signal 2008-06-30 17:47:45 +01:00
Nick Gasson e08e29c8b4 Add UFUNC LPM type 2008-06-30 16:35:29 +01:00
Nick Gasson b82ca28190 Add XOR logic type and fix part select 2008-06-30 16:18:55 +01:00
Stephen Williams e02d186946 Handle multiple passes of scope and defparam elaboration.
When generate schems and instance arrays are nested, it takes
multiple iterations of elaborate scope, defparams and evaluate
parameters before everything is worked out. Rework the work item
processing so that the loop elaborates scopes and runs defparams
in phases. The phases are needed so that we can tell when the
remaining defparams are orphaned.
2008-06-30 03:46:46 +02:00
Stephen Williams d9b02657a7 Modules within generate schemes are not default roots.
Modules mentioned within generate schemes are not candidates for
defaults guesses at root modules. They are, obviously, used within
the generate schem.
2008-06-28 13:34:46 -05:00
Stephen Williams d761a2273c Run generate schemes after defparams.
We must run generate schemes after running defparams because the
defparams may define the results of the generate schemes. So put
the generate schemes for a module scope into elaborator work items.
2008-06-28 13:06:14 -05:00
Stephen Williams e3d9cc30a8 Checkin some developer convenience scripts. 2008-06-28 09:51:42 -07:00
Stephen Williams 1ef7994ae2 Handle indexed defparams.
The l-value of a defparam assignment is a hierarchical name that may
include array selects to select scopes from module arrays. Therefore
it makes no sense to store parsed defparams in a map. Instead, they
should go into an ordered list. This also maked more sense because later
defparams *may* have the same name as a previous defparam, and will
override the previous defparam. So replace the map of parsed defparams
with a list of parsed defparams.

Also, as soon as the defparam expression is elaborated, the list entry
is no longer needed, so delete it. Save memory.
2008-06-28 09:30:09 -07:00
Nick Gasson 081f397460 Implement LPM part select 2008-06-27 14:58:03 +01:00
Nick Gasson f800298d01 Fix memory leak 2008-06-27 12:29:50 +01:00
Nick Gasson 301a25303f Remove useless assertion 2008-06-27 12:21:53 +01:00
Nick Gasson b24eb6ce88 Handle local variables in functions 2008-06-27 12:21:27 +01:00
Nick Gasson fd60bfd3d2 Rewrite function parameter finding code 2008-06-27 12:18:39 +01:00
Stephen Williams da2c4b0fa1 Multiple passes for run_defparams.
It is possible for defparams to not find their target the first time
around, because the elaboration of the target scope is not yet done.
So retry the defparams once for each scope by putting it on a work
item in the elaborator_work_items list.
2008-06-25 22:02:22 -07:00
Stephen Williams 4251979e8b Merge branch 'master' into defparam-rework 2008-06-25 20:26:01 -07:00
Cary R 12783674cb Clean up compiler warning. 2008-06-25 16:34:54 -07:00
Cary R c17ffcae2c Rework previous patch to use the correct method. 2008-06-25 15:42:41 -07:00
Cary R 897f14e60a Fix memory leak in recent patch. 2008-06-25 15:42:34 -07:00
Cary R 4163eb28d0 Copy file and line info during a macro expansion.
The file and line number information needs to be copied when
doing a macro expansion. This prevents a macro that expands to
an `ifdef of other construct that needs to push the stack
from core dumping.
2008-06-25 15:42:29 -07:00
Nick Gasson 500442e5c5 Working function calls 2008-06-25 22:15:57 +01:00
Stephen Williams 8c54803094 vpi_get_value of integer values replaces x/z bits with 0.
In arithmetic expressions, vectors with x/z are replaced with 0,
but vpi_get_value replaces x/z bits with 0 bits without replacing
the whole vector.
2008-06-25 13:59:39 -07:00
Nick Gasson 2baf31dff8 Fix bug with $display and integer literals 2008-06-25 21:54:11 +01:00
Nick Gasson d997397c38 Generate function calls with parameters 2008-06-25 21:49:22 +01:00
Nick Gasson 7773000c36 Generate function declarations 2008-06-25 21:40:35 +01:00
Nick Gasson 042f7ccbcd Generate a return type for functions 2008-06-25 18:43:50 +01:00
Nick Gasson 44aa8a6b91 Associate signals with scopes rather than entities 2008-06-25 18:12:57 +01:00
Nick Gasson 43c671cb5c Emit VHDL for function declarations 2008-06-25 18:00:48 +01:00
Nick Gasson a3df37b851 Initial code to generate function calls
Also catch a few null-pointer issues
2008-06-25 17:29:09 +01:00
Nick Gasson c01c2bd742 Dummy code for handling function scopes 2008-06-25 12:48:46 +01:00
Stephen Williams 533ee87bb1 Delay elaborate of instance array scopes to allow defparams to propagate.
When we detect that a module instance is an array of instances, delay
the elaboration of the array until after the first defparam processing
is complete. This allows for defparam statements to control the
instantiation of module instance arrays.
2008-06-24 22:03:28 -07:00
Stephen Williams c810406195 run scope elaboration as queued work items.
Putting scope elaboration into work queue items allows for handling
more complex processing order. The elaboration_work_list queue drives
the processing of elaborate_scope and parameter evaluation.
2008-06-24 20:28:08 -07:00
Larry Doolittle 3ec8a867db Spelling fixes
comments, documentation, a variable name, and a couple of messages
2008-06-24 17:01:45 -07:00
Nick Gasson 899a70908e Fix small bug with initialisation and ammend comments 2008-06-24 20:13:18 +01:00
Nick Gasson bf95d77562 Finish replacing vhdl_process with vhdl_procedural 2008-06-24 20:01:06 +01:00
Nick Gasson db992e808f Start using vhdl_procedural instead of vhdl_process 2008-06-24 19:54:22 +01:00
Nick Gasson f2aca68b82 Add new vhdl_procedural superclass for process/task/func 2008-06-24 19:50:57 +01:00
Nick Gasson 12b448ef01 Merge branch 'vhdl' of [email protected]:nickg/iverilog into vhdl
Conflicts:

	tgt-vhdl/vhdl_syntax.cc
2008-06-24 19:42:35 +01:00
Nick Gasson e77bb0157e Remove redundant methods from vhdl_arch 2008-06-24 19:39:05 +01:00
Nick Gasson 75631bd8f1 Move is_inital code out of vhdl_process into vhdl_scope
Part of tidy up before implementing functions
2008-06-24 19:06:06 +01:00
Nick Gasson 63b1887ff2 Refactor code to use the new vhdl_scope class 2008-06-24 18:52:25 +01:00
Nick Gasson ba36e47575 Add new vhdl_scope class and refactor 2008-06-24 18:12:00 +01:00
Nick Gasson 3866c4526e Simplify code to emit operators 2008-06-24 14:58:58 +01:00
Nick Gasson cb08f02de1 Resize signed/unsigned bit vectors correctly 2008-06-24 10:58:21 +01:00
Nick Gasson 4188fbecee Add XOR operator and catch default case branch 2008-06-24 10:55:45 +01:00
Nick Gasson f261bf7e97 Fix bug where variables could be declared twice 2008-06-23 15:13:10 +01:00
Nick Gasson 88dc9b6b63 Remove debugging information from the output 2008-06-23 15:02:26 +01:00
Nick Gasson 632a265e14 Fix casting/resizing order bug 2008-06-23 15:00:55 +01:00
Nick Gasson 449cd0a76e Correctly generate signed/unsigned types 2008-06-23 14:28:27 +01:00
Nick Gasson 181a53d3ed Merge branch 'master' of git://github.com/steveicarus/iverilog into vhdl 2008-06-23 13:48:56 +01:00
Nick Gasson 44958409f5 A slightly smarter $display 2008-06-23 13:45:24 +01:00
Nick Gasson f81129aa68 Fix some bugs with blocking assignment 2008-06-23 13:36:28 +01:00
Nick Gasson e5ef0d97bd Fix signed/unsigned resizing 2008-06-23 13:04:28 +01:00
Nick Gasson 469036990a Output blocking assignments in the right place 2008-06-23 12:30:48 +01:00
Nick Gasson d06f5c7c54 Emit loop statements with the correct indent 2008-06-23 12:27:30 +01:00
Nick Gasson 9911939576 Simplify casting code 2008-06-23 12:21:10 +01:00
Nick Gasson c9ace14c40 Shift operators working correctly 2008-06-23 12:14:12 +01:00
Nick Gasson d5cdb91d55 Handle complex expressions in case statement 2008-06-23 11:36:12 +01:00
Stephen Williams 360be597a8 Minor cleanup and comments.
The initial elaboration needs better comments/documentation.
2008-06-21 18:36:46 -07:00
Nick Gasson 75f7c9ae0c Only move constant assignments into initialisation 2008-06-21 16:40:18 +01:00
Nick Gasson c926454a41 Statements might be emitted in wrong order 2008-06-21 16:33:05 +01:00
Nick Gasson 5cfe7ea0aa Tidy up output 2008-06-21 16:28:07 +01:00
Nick Gasson c70fb4ba08 Simple implementation of IVL_EX_SELECT 2008-06-21 16:17:44 +01:00
Nick Gasson 7cba9f3cb2 Shift left/right 2008-06-21 15:19:33 +01:00
Nick Gasson d6acb8d059 Less than / greater than 2008-06-21 15:16:22 +01:00
Nick Gasson ec23b70bb7 While loops 2008-06-21 15:13:44 +01:00
Nick Gasson 58f2f5007d Bitwise AND 2008-06-21 15:05:48 +01:00
Nick Gasson 0caf4fd9d0 Add case statement 2008-06-21 15:03:36 +01:00
Nick Gasson 037ce08f72 Fix tiny bug in $display code 2008-06-21 14:42:54 +01:00
Cary R 27cdd27889 Add .cast/int and update .cast/real.
This patch adds .cast/int and updates .cast/real to act as a local
(temporary) net and to support either a signed or unsigned input.
The vvp_vector4_t class not can convert an arbitrarily sized double
to a vector value. This removes the restriction of lround().

Also document the new statements.
2008-06-20 19:45:18 -07:00
Larry Doolittle f60a6561bb Cast strlen to int for printf field width
strlen is a size_t, and the * field width takes an int.
Make this an explicit cast.  It's good for 64-bit machines
and squelches warnings from gcc-4.3.
2008-06-20 15:54:32 -07:00
Nick Gasson 204862ac3c Implement $write 2008-06-20 19:00:07 +01:00
Nick Gasson 0f50849fbb Add call to To_Integer when printing signed/unsigned 2008-06-20 18:26:39 +01:00
Nick Gasson 404c22ac86 Improved implementation of $display 2008-06-20 11:51:13 +01:00
Stephen Williams fe555e4539 Merge branch 'master' of ssh://[email protected]/~steve-icarus/git/verilog 2008-06-19 21:32:18 -07:00
Stephen Williams c87e629150 Better handle nesting of scopes inside generate blocks.
Within generate schemes it is possible to have nested scopes, even
more liberally then outside generate blocks. So see to it that the
scopes properly stack with the generate blocks, and that wires and
behaviors are put in the right scopes.
2008-06-19 21:31:53 -07:00
Stephen Williams b9d6c816f1 Properly evaluate a unary ! with logic argument and real result. 2008-06-19 19:14:19 -07:00
Stephen Williams 0153a25061 Elaborate nets with real-valued parameters. 2008-06-19 19:13:50 -07:00
Cary R 476a4c7bc4 Add a script to manually build the version.h file.
This script is used to manually build a version.h file.
It is needed when building with MinGW using a cygwin
hosted repository.
2008-06-19 16:59:22 -07:00
Nick Gasson 08d80b35cb Rename signals that would be illegal VHDL names 2008-06-19 16:15:47 +01:00
Nick Gasson 6622b5fe3a Compare logic values for === and !== 2008-06-19 16:08:33 +01:00
Nick Gasson d7bb5658f2 Translate IVL_ST_DELAYX statements 2008-06-19 12:16:19 +01:00
Stephen Williams 2f3627cd6d Allow generate schemes to generate task/function definitions.
Generating task/function definitions involves getting the functions
to put themselves into the generate scheme instead of the module,
and getting elaboration to elaborate those definitions in the
generate scheme.
2008-06-18 21:54:58 -07:00
Stephen Williams ce9fd0147f Detect and warn about anachronistic use of begin/end in generate.
Verilog-2001 only allows a single generate item within a generate-
endgenerate region, but allowed one to collect generate schemes with
begin/end blocks. Verilog-2005 cleaned up that mess, and it is the
2005 syntax that Icarus Verilog implements. This patch detects the
anachronistic use of begin/end within the generate region, ignores
the begin/end words, and prints a warning that the user is using an
obsolete syntax.
2008-06-18 20:33:30 -07:00
Nick Gasson be12f56856 Document blocking assignment behaviour 2008-06-18 14:04:16 +01:00
Nick Gasson e0f41198d6 Blocking assignment working correctly 2008-06-18 13:49:03 +01:00
Nick Gasson fb31a88c51 Blocking assignment nearly working 2008-06-18 13:30:19 +01:00
Nick Gasson 254ccb9ccb First passing at blocking assignment 2008-06-18 13:06:27 +01:00
Nick Gasson d2bebee9d9 Refactor before adding blocking assignment 2008-06-18 12:51:11 +01:00
Stephen Williams b2c9352bb5 Merge branch 'master' of ssh://[email protected]/~steve-icarus/git/verilog 2008-06-17 21:45:58 -07:00
Stephen Williams 15481a9520 Elaborate block scopes burried in generate schemes.
Named begin/end blocks burried within generate schemes need to be
elaborated. Handle this by remembering to elaborate_scope on the
statements within the generate scheme.

In the process, clean up/regularize some of the member names and
methods.
2008-06-17 21:45:37 -07:00
Stephen Williams 37723698dc Handle non-real operands to real division.
This handles the general case of a non-real operand to a real-valued
division. This can turn up if only 1 operand of a divide is real. In
this case the division as a whole is real and the other operand must
be cast to real.

This method creates an extra node, but it should be a very compact
node and this node does no evaluation tricks so in the run time should
be no more expensive then folding the cast into the .arith/div.r itself.
2008-06-17 17:07:19 -07:00
Nick Gasson af8c08e6a7 Allow optional VHPI $finish implementation 2008-06-17 20:16:16 +01:00
Nick Gasson 01249000c3 Temporarily treat blocking assignment as non-blocking 2008-06-17 14:07:36 +01:00
Cary R f6edd098a9 More file name and mode checks for $fopen{a,r,w}?.
This patch adds checks that $fopen is only called with a valid
mode argument. It also checks that the file name for $fopen{a,r,w}?
is a valid looking file name (all characters satisfy isprint()).
The later should prevent creating weird file names because of
Verilog bugs.
2008-06-16 18:00:31 -07:00
Cary R 6321fb6a92 Pad Octal string value correctly.
This patch changes the base oct to string converter to correctly
pad the top digit. x or xx should display as a single lower case
x when they are located in the top bits. Before these were being
interpreted as 00x or 0xx and displayed X. Also modified the hex
conversion to use this same scheme instead of a loop.
2008-06-16 17:58:16 -07:00
Stephen Williams 69ba009439 Cleanup the resolver function.
First, handle the trivial (but possibly common) resolution cases in
inlined code, and only call the complete function for the complicated
cases. Then clean up the complex function for readability, and account
for the constraints that the front-end function established.
2008-06-16 17:45:08 -07:00
Stephen Williams 86e5762b1c Compact of vvp_vector4_t in arrays.
Arrays of vvp_vector4_t values redundantly store some fields in every
word. Create a special type that stores vvp_vector4_t values in a form
that does not duplicate the width of all the items. This can save a lot
of space when big memories are simulated.
2008-06-16 15:02:07 -07:00
Stephen Williams 49363c660c Remove the duplicate schedule_assign_vector.
The schedule_assign_plucked_vector is a better way to implement the
schedule_assign_vector, or at least no worse, so remove the now
redundent schedule_assign_vector.
2008-06-16 13:40:20 -07:00
Nick Gasson 1debbc3100 Simplify edge_detector() a bit 2008-06-16 20:06:06 +01:00
Nick Gasson ae0b09dd3a Don't bother emitting else part if it's empty 2008-06-16 19:53:42 +01:00
Nick Gasson 8d0afa632d Subtraction and multiplication LPM devices 2008-06-16 19:49:24 +01:00
Nick Gasson 561953e494 Minial LPM to support continuous assignments 2008-06-16 19:41:01 +01:00
Nick Gasson 83a7796b74 Make sure signal names conform to VHDL rules 2008-06-16 17:37:17 +01:00
Nick Gasson ce72eb4eb4 Fix Valgrind warnings 2008-06-16 14:26:38 +01:00
Nick Gasson 7cde5f247e Add translation for not-equals operator 2008-06-16 12:47:41 +01:00
Nick Gasson 849e7cb4d5 Add equality operator 2008-06-16 12:20:28 +01:00
Nick Gasson 92c823680a Fix crash when if' statement had no else' 2008-06-16 12:13:01 +01:00
Stephen Williams 05f1541903 Make reg initializations account for generated scope.
During parse, reg initialization may be in generated scopes. Handle
that properly.
2008-06-14 21:50:48 -07:00
Stephen Williams 30d42e2806 Allow l-value part select to be out of bounds.
It is legal (though worthy of a warning, I think) for the part select
of an l-value to me out of bounds, so replace the error message with
a warning, and generate the appropriate code. In the process, clean
up some of the code for signal l-values to divide out the various kinds
of processing that can be done. This cleans things up a bit.
2008-06-14 21:22:55 -07:00
Cary R ebdf4e478a Rework more compiletf and calltf routines in the vpi directory.
This is a major rework on the sys_fileio routines. They now have
improved compiletf routines and the calltf routines are now
standardized. Along the way a few bug were fixed as well. Some
updates to other vpi files as well.

I changed the order of the $fputc() arguments to match C and the
rest of the system functions like it ($fungetc, etc.). I recently
fixed $fungetc() so I'm assuming the $fputc() needs the same fix.
It's an Icarus specific function.
2008-06-14 20:13:52 -07:00
Stephen Williams f6bc1afcbb Merge branch 'master' of ssh://[email protected]/home/u/icarus/steve/git/verilog 2008-06-14 20:00:51 -07:00
Stephen Williams 9013dcb527 Signed load-and-add for arrays.
The load-and-add for vectors %load/vp0/s can be combined with the
load-and-add for array words, and the %load/avp0/s added to round
out the combinations. This can make for fewer instructions when
words are padded in arithmetic expressions.
2008-06-14 19:59:57 -07:00
Stephen Williams dbe13aecea Signed load-and-add for arrays.
The load-and-add for vectors %load/vp0/s can be combined with the
load-and-add for array words, and the %load/avp0/s added to round
out the combinations. This can make for fewer instructions when
words are padded in arithmetic expressions.
2008-06-14 18:16:23 -07:00
Stephen Williams 6521ceaf92 Union scope and parent pointers for signals.
If a signal is part of an array, then it can get its scope from its
parent, so the scope and parent pointers can go into a union.
2008-06-14 16:17:25 -07:00
Stephen Williams f497dbf01e Created too mane vvp_net_t objects?
The functor_ref_lookup() function fills its argument in with the
vvp_net_t* pointer that matches the var name, so there is no need
to create the vvp_net_t object before then.
2008-06-14 15:31:48 -07:00
Nick Gasson 8a9486eb49 Eliminate useless Resize() call 2008-06-14 18:11:10 +01:00
Nick Gasson 2fb57805ea Use signed rather than std_logic_vector
Arithmetic operators now working correctly
2008-06-14 18:03:25 +01:00
Nick Gasson 919c1d695c Adding binary + 2008-06-14 17:09:31 +01:00
Stephen Williams 1530594b4b Implement vpiIndex for vpiMemoryWord objects.
The vpiIndex is really just a different view into the same object,
so implement the trickery needed to support a vpiIndex with the
absolute minimum memory cost.
2008-06-13 22:05:19 -07:00
Stephen Williams 6f0d8e8dda Load_add_immediate to work with signed expressions
The %load/vp0 instruction adds a signed value to the signal value being
loaded, but it doesn't allow for a signed source vector. Add the
%load/vp0/s instruction that pads the loaded vector, and add the code
generator details to properly use it.
2008-06-13 20:23:40 -07:00
Stephen Williams 62d7c081dc Sign extend signed vectors when getting vpiIntVal.
When getting values using vpi_get_value, the vpiIntVal is the integer
value and should be sign-extended if the source value is signed.
2008-06-13 19:47:48 -07:00
Cary R f78994b66c Allow &PV<> to reference a VPI object (signal) for the base.
This patch adds code to allow &PV<> to access a VPI object
(signal) for the base of an indexed part select. This
mirrors the code added to &A<>.
2008-06-13 18:42:08 -07:00
Cary R 50a8c17cf8 Comparison arguments are in a self determined context.
This patch makes comparison arguments be evaluated in a self
determined context. It also cleans up some other code items.
2008-06-13 18:05:46 -07:00
Stephen Williams 6f9643df79 Better array statistics.
Allocation counters for arrays and array words of various types.
2008-06-13 17:41:24 -07:00
Stephen Williams aeaf8e8433 Permalloc vvp_net_fun_t objects.
The vvp_net_fun_t objects, and derived objects, are small, and are
created in large quantities. Tightly pack them into permanently
allocated space in order to save on system allocation overhead, and
thus save overall on memory.
2008-06-13 17:08:11 -07:00
Stephen Williams 7afb280990 Allow that sum immediate values can be signed.
Actually, the immediate value handling is a little chaotic and should
be cleaned up. This patch opens the door for allowing signed immediate
values, and uses them in a few places where they are explicitly handled.
We must go through the opcodes that can take immediate values and make
explicit whether they are signed/unsigned/etc, and what their size
limits are.
2008-06-13 13:32:06 -07:00
Cary R 99a46fd5af Fix incorrect typecast.
This patch fixes an incorrect typecast in vvp/main.cc.
2008-06-13 11:38:18 -07:00
Larry Doolittle eed4ff7e2d Spelling fixes
Mostly comments, but includes quite a few
user-visible error, debug, and help messages.
2008-06-13 08:51:28 -07:00
Stephen Williams 659714f45d Merge branch 'master' of ssh://[email protected]/home/u/icarus/steve/git/verilog 2008-06-13 08:41:40 -07:00
Larry Doolittle 8f70c5ca35 Add missing include to vvp/vvp_net.h
Fixes FTBFS under gcc-4.3
2008-06-13 08:40:26 -07:00
Nick Gasson 0ea64ad8ab Correct misleading comment 2008-06-13 14:47:06 +01:00
Nick Gasson 9fbb449e06 Optimise away empty (VHDL) processes 2008-06-13 14:17:24 +01:00
Nick Gasson be3c4cf268 Generate signal initial values from `initial' processes 2008-06-13 14:10:28 +01:00
Nick Gasson 0a8fd50c4a Find assignments that could be initializers 2008-06-13 13:59:48 +01:00
Nick Gasson 70db096b6d Clean up the edge detector code a bit 2008-06-13 12:52:20 +01:00
Nick Gasson 005df31a0d Use renamed signal in expressions, if there is one 2008-06-13 12:39:18 +01:00
Nick Gasson d6193c1622 Add _Reg internal signal if output is registered 2008-06-13 12:34:27 +01:00
Stephen Williams a74f2827b2 Part select of signals is always unsigned.
Part select of an entire signal returns just the NetESignal itself,
but since part selects are always unsigned, even if the selected
signal is signed, we need to cast the NetESignal to unsigned first.
2008-06-12 21:56:46 -07:00
Stephen Williams 392b162024 Allow canonical part select of net vectors to be larger then the vector
The part select of a vector is converted by the compiler during
elaboration to a 0-based canonical address. But since it is legal
to address bits below the LSB, the canonical address can be negative.
So make the part select base for selecting from signals work with
signed arithmetic and make the code generator generate negative
indices when needed.
2008-06-12 21:41:11 -07:00
Stephen Williams 4af4c8cca9 Permallocate scheduler cells in chunks
Scheduler cells are small objects that come and go in great quantities.
Even though they are allocated and deallocated a lot, they tend to a
steady state quantity, so put together a heap that is unique for each
cell type.

This heap actually saves memory overall because cells are allocated in
chunks, thus eliminating allocator overhead, and they are pulled/pushed
from/to a heap very quickly so that what overhead remains is slight and
bounded.
2008-06-12 19:55:53 -07:00
Stephen Williams 3c4346acb2 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.(cherry picked from commit d0f303463d)
2008-06-12 13:00:31 -07:00
Nick Gasson b8c1f9ab67 A system for linking ivl_signal_t to entities 2008-06-12 20:26:23 +01:00
Stephen Williams 2e9970a98c Have vvp_vector8_t avoid allocating tiny scalar arrays.(cherry picked from commit 35fe8fae00) 2008-06-12 12:10:58 -07:00
Stephen Williams 4914b734dc 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 have the islands take more care not to perform resolution if the
inputs aren't really different.

NOTE: This is a port of commit 2f4e5bf5b6
from the "performance" branch, without the resolver scheduling changes.
This was causing test suite variances with pr1820472.v. It looks like
there might be a race in that program anyhow, but for now leave out the
resolver scheduling changes so that the rest of this commit can go in.
2008-06-12 12:08:02 -07:00
Nick Gasson 0df3eabe26 Convert if (foo) ..' to if foo = '1' then ..' 2008-06-12 11:36:21 +01:00
Nick Gasson 8fe2211e2b Generate after' modifier instead of wait' statements 2008-06-12 11:24:43 +01:00
Nick Gasson 645ee2003f Translation for unary not 2008-06-12 10:56:28 +01:00
Nick Gasson d6f1162547 Generate correct VHDL signal values 2008-06-12 10:50:46 +01:00
Nick Gasson 46991aa65c Generate process bodies in the right place 2008-06-12 10:47:52 +01:00
Nick Gasson 7eb41304e6 Generate rising/falling edge detectors 2008-06-12 10:36:38 +01:00
Stephen Williams 24da00bd5a Add value change callback for vpiPartSelect.
The __vpiPV objects express themselves as vpiPartSelect objects.
Add support for value change callbacks by attaching the callback
to the signal that we part select from.
2008-06-11 21:28:21 -07:00
Cary R 34efc7db51 Add parameter time/realtime types and other fixes.
This patch adds the time and realtime types to parameters
and local parameters. It also makes the width (range) of
an integer parameter match the variable "integer_width"
(normally 32 bits). It also converts a real value to
an integer when a range is implicitly or explicitly
given. This all matches what the standard specifies.

Fixed an error in converting -1 to a unsized verinum.
2008-06-11 19:48:15 -07:00
Cary R acf010326c Remove the signed/unsigned comparison warning 2008-06-11 19:44:21 -07:00
Stephen Williams d7814ed767 Better handle some vector size matters for %load/v
The %load/v instruction was doing some spurious resizes of the vector
that comes from the signal. Eliminate those resizes that can be
removed, and optimize some that remain.
2008-06-11 14:38:35 -07:00
Nick Gasson 19e60b698f Translate if statements 2008-06-11 14:20:05 +01:00
Nick Gasson a7cfdc3a87 Add VHDL if statement to AST types 2008-06-11 14:11:37 +01:00
Nick Gasson b010b8e3ca Use `assert false' as initial translation of $finish 2008-06-11 13:37:21 +01:00
Nick Gasson 26a2c69c2e Change architecture name to `FromVerilog' 2008-06-11 11:31:43 +01:00
Stephen Williams 608bad26cf Allow &A<> argument syntax to take a reference to a VPI object.
This allows the array index to be evaluated when the word is accessed,
and that in turn allows access in the ROSYNC scheduler phase to work
properly.
2008-06-10 20:36:31 -07:00
Stephen Williams 70768176f9 Change bit select instruction to a part select.
There is no point in having a bit select instruction and running it in
a loop (always) when we can simply turn it into a part select instruction.
2008-06-10 17:29:47 -07:00
Stephen Williams 694a6ed4a1 Remove some unused opcodes.
Codes from a dfiferent era.
2008-06-10 16:33:34 -07:00
Cary R dc15fa965b Remove MinGW unused variable warning
This patch moves the definition of rtn into the non-MinGW
branch since that is the only place it is used.
2008-06-10 15:42:56 -07:00
Cary R d78739d163 Make &PV<> put_value work correctly.
This patch finishes the put_value routine for &PV<>. It should
now work as expected.
2008-06-10 15:07:52 -07:00
Larry Doolittle d90ce68f5d Spelling fixes
No code changes.
2008-06-10 15:02:18 -07:00
Larry Doolittle d2c52ff35b Spelling fixes
No code changes.
2008-06-10 15:00:54 -07:00
Larry Doolittle 813b4cf74c Add explicit parentheses to elaborate_expr_param_part_
Removes gcc-4.3 warning: suggest parentheses around && within ||
2008-06-10 14:57:50 -07:00
Larry Doolittle a437b38270 Fix vpip_make_vthr_A prototype with duplicate parameters
Causes FTBFS with gcc-4.3
2008-06-10 14:56:55 -07:00
Stephen Williams f9d060146c Merge branch 'master' of ssh://[email protected]/~steve-icarus/git/verilog 2008-06-10 14:18:30 -07:00
Stephen Williams 7f0c6b9c21 Fix access to deleted memory.
When parameters are replaced, the expression that is replaced is deleted
so make sure the pointer in the map is properly updated. Also, make sure
the defparam expression itself is not deleted because it is used to
print messages, such as design dumps.
2008-06-10 13:25:40 -07:00
Nick Gasson 5a7cfd8c02 Clean up vhdl_comp_inst 2008-06-10 14:00:15 +01:00
Nick Gasson babe694366 Generate port mappings 2008-06-10 13:58:41 +01:00
Nick Gasson 7560b29fb9 Find signals to map together 2008-06-10 12:21:48 +01:00
Nick Gasson f6753a9013 Add ports to component declarations 2008-06-10 11:24:16 +01:00
Cary R 647e53bcbb Make &A<> use the same thread access syntax as &PV<>.
This patch makes &A<> use the same thread access syntax as
&PV<> this is two unsigned numbers separated by a space
instead of a single number.
2008-06-09 21:26:36 -07:00
Cary R 8439fc6c19 Remove two memory leaks.
This patch removes two memory leaks. One in the driver and one
in the runtime.
2008-06-09 21:23:27 -07:00
Cary R 6f61cf2e4e A memory word is a number
This will be cleaned up more once I finish all the compiletf
routines, but for now this allows the test to pass.
2008-06-09 20:00:03 -07:00
Nick Gasson 191187ed1b Cosmetic change to avoid useless `null' statement after delay 2008-06-09 16:40:32 +01:00
Nick Gasson 1fb01d4d98 Emit port declarations 2008-06-09 16:37:05 +01:00
Nick Gasson 3106fe0ed6 Generate port declarations for entities.
But doesn't emit them yet!
2008-06-09 16:27:04 +01:00
Nick Gasson e29954e03f Generate concurrent assignments from logic gates 2008-06-09 15:05:32 +01:00
Nick Gasson 3b5d56e087 Allow n-ary expressions 2008-06-09 14:53:50 +01:00
Nick Gasson aa91186119 Add AST elements for unary/binary expressions to model logic gates 2008-06-09 14:39:58 +01:00
Nick Gasson d08f5af9c6 Add concurrent assignments 2008-06-09 14:21:55 +01:00
Nick Gasson b96e471fa2 Stub code for handling logic gates 2008-06-09 14:08:27 +01:00
Nick Gasson 7120ab7b13 Expression type might be null in some cases 2008-06-09 12:54:21 +01:00
Nick Gasson 2f5dcda3b6 Delay statements now translated correctly 2008-06-09 12:49:38 +01:00
Nick Gasson 120b5dc80e Add constant integers 2008-06-09 12:46:55 +01:00
Nick Gasson d762253f74 Wait statements 2008-06-09 12:40:59 +01: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
Nick Gasson 1d28b935e8 Split vhdl_element.cc into multiple files 2008-06-08 13:27:48 +01:00
Nick Gasson 4b4a1c6cac Tidy up type casting 2008-06-08 12:55:18 +01:00
Nick Gasson 110a1b2ac7 Replace type classes with enumeration 2008-06-08 12:48:56 +01:00
Nick Gasson 79558910d1 Catch case where NULL return wasn't detected 2008-06-07 16:44:01 +01:00
Nick Gasson fbf85398da Support converting bit strings to std_logic 2008-06-07 16:19:10 +01:00
Nick Gasson 1e4b96aa0a Simplify code a bit as rval type is never needed 2008-06-07 14:57:20 +01:00
Nick Gasson c064ae6bc3 Generate VHDL for non-blocking assignments 2008-06-07 14:54:00 +01:00
Nick Gasson 39228f3495 VHDL AST element for non-blocking assignment 2008-06-07 14:31:33 +01:00
Nick Gasson 12e2237131 Add Type'Image cast to $display parameters 2008-06-07 14:21:50 +01:00
Nick Gasson 066a9b7a61 Add AST element for function call expressions 2008-06-07 13:29:27 +01:00
Nick Gasson cdb180e1d4 Associate a type with each VHDL expression node 2008-06-07 13:23:21 +01:00
Nick Gasson a8ecce7421 Make sure all declarations have a type 2008-06-07 12:15:46 +01:00
Nick Gasson 8c3461f0ff Generate sensitivity lists properly and add signal declarations 2008-06-07 11:48:38 +01:00
Nick Gasson 305f448d05 Generate code for signal references 2008-06-07 11:24:09 +01: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
Nick Gasson 5f90a3e48c Translate sub-statement of @{..} 2008-06-06 18:22:03 +01:00
Nick Gasson 96cf190720 Generate signals and sensitivity list for @(..) statement 2008-06-06 17:56:52 +01:00
Nick Gasson 373832ba22 Specify correct sensitivity list 2008-06-06 17:36:15 +01:00
Nick Gasson 4f472e451e Stubs for statement types in mux2.v test 2008-06-06 16:55:45 +01: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
Nick Gasson d36bbec5b5 Generate VHDL for no-op statements 2008-06-05 13:16:35 +01: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
Nick Gasson e258058cf1 Fully qualify std.textio.Output to avoid name collisions 2008-06-04 21:58:51 +01:00
Nick Gasson c3ac1aac8c Remove debugging messages from output 2008-06-04 21:07:50 +01:00
Nick Gasson 234f73e7bf Don't generate any output if there were errors 2008-06-04 21:03:36 +01:00
Nick Gasson f49dd97d24 Add support for blocks and make hello1.v test pass 2008-06-04 20:57:15 +01:00
Nick Gasson 7bd1565cfb $display now (mostly) working 2008-06-04 20:42:44 +01: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
Nick Gasson 6e448da90d Emit Write() calls for parameters of $display 2008-06-04 15:19:44 +01:00
Nick Gasson 9f035108e1 Stub code for translating expressions 2008-06-04 14:59:04 +01:00
Nick Gasson 4bf2e1669d Store packages required with entity rather than globally
Add parent link to architecture and process so code generators can push things higher up
$display now prints blank lines
2008-06-04 13:52:56 +01:00
Nick Gasson dd30c1b39d Support procedure call generation for $display 2008-06-04 13:27:42 +01: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
Nick Gasson 94006cb44c Working on code generation for $display task 2008-06-03 19:46:10 +01:00
Nick Gasson 2e6ec91ce0 Scalar types 2008-06-03 19:20:45 +01: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
Nick Gasson fe80da362c Collect required packages as compilation progresses 2008-06-03 19:14:47 +01:00
Nick Gasson 82aca1b02e Stub code for handling $display 2008-06-03 18:44:17 +01:00
Nick Gasson 4211e651d0 Stub file for processing statements 2008-06-03 18:26:36 +01:00
Nick Gasson f9e1289463 Tidy up vhdl_element.cc 2008-06-03 17:43:54 +01:00
Nick Gasson a09b4e3b92 Initial process have wait at the end
(do it properly this time rather than a hack :-)
2008-06-03 17:39:24 +01: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
Nick Gasson ab6ae621cb Remove useless comments in output 2008-06-02 20:24:25 +01:00
Nick Gasson 17ae0a6a09 Fix a bug where the same instantiation appeared multiple times 2008-06-02 18:05:39 +01:00
Nick Gasson 041925c123 Component instantiation to replicate Verilog hierarchy 2008-06-02 17:45:58 +01:00
Nick Gasson 9292a087e8 Generate VHDL processes from Verilog processes 2008-06-02 16:17:01 +01: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
Nick Gasson fef0fd82ff Comments 2008-06-02 00:12:47 +01: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
Nick Gasson 5cbd587833 Clean up generated objects 2008-05-31 16:08:57 +01:00
Nick Gasson 7c9d154461 Forgot source files for entity generation 2008-05-31 15:31:48 +01:00
Nick Gasson 8189c4ee43 Generate VHDL entities and architectures for all module scopes 2008-05-31 15:28:25 +01: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
Nick Gasson 05de2f56b4 Dummy code for processes 2008-05-30 01:04:47 +01: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
Nick Gasson e38494a10c Pretty-print VHDL output 2008-05-29 16:24:16 +01: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
Nick Gasson e178baefbd Merge branch 'master' of git://github.com/steveicarus/iverilog into vhdl 2008-05-28 17:23:12 +01:00
Nick Gasson bfa2bfc8ae Makefile and autoconf changes to build VHDL code generator 2008-05-28 17:17:39 +01: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
194 changed files with 17907 additions and 5654 deletions
+15 -31
View File
@@ -1,7 +1,7 @@
#ifndef __HName_H
#define __HName_H
/*
* Copyright (c) 2001-2007 Stephen Williams ([email protected])
* Copyright (c) 2001-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
@@ -18,11 +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: HName.h,v 1.7 2007/06/02 03:42:12 steve Exp $"
#endif
# include <iostream>
# include <list>
# include "StringHeap.h"
#ifdef __GNUC__
#if __GNUC__ > 2
@@ -57,7 +55,7 @@ class hname_t {
private:
perm_string name_;
// If the number is anything other then INT_MIN, then this is
// If the number is anything other than INT_MIN, then this is
// the numeric part of the name. Otherwise, it is not part of
// the name at all.
int number_;
@@ -70,30 +68,16 @@ extern bool operator == (const hname_t&, const hname_t&);
extern bool operator != (const hname_t&, const hname_t&);
extern ostream& operator<< (ostream&, const hname_t&);
/*
* $Log: HName.h,v $
* Revision 1.7 2007/06/02 03:42:12 steve
* Properly evaluate scope path expressions.
*
* Revision 1.6 2007/05/16 19:12:33 steve
* Fix hname_t use of space for 1 perm_string.
*
* Revision 1.5 2007/04/26 03:06:21 steve
* Rework hname_t to use perm_strings.
*
* Revision 1.4 2002/11/02 03:27:51 steve
* Allow named events to be referenced by
* hierarchical names.
*
* Revision 1.3 2002/08/12 01:34:58 steve
* conditional ident string using autoconfig.
*
* Revision 1.2 2002/06/14 03:25:51 steve
* Compiler portability.
*
* Revision 1.1 2001/12/03 04:47:14 steve
* Parser and pform use hierarchical names as hname_t
* objects instead of encoded strings.
*
*/
inline ostream& operator<< (ostream&out, const list<hname_t>&ll)
{
list<hname_t>::const_iterator cur = ll.begin();
out << *cur;
cur ++;
while (cur != ll.end()) {
out << "." << *cur;
cur ++;
}
return out;
}
#endif
+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
+1 -11
View File
@@ -26,7 +26,7 @@
/* n is a permallocated string. */
Module::Module(perm_string n)
: PScope(n, 0)
: PScope(n)
{
library_flag = false;
default_nettype = NetNet::NONE;
@@ -41,16 +41,6 @@ void Module::add_gate(PGate*gate)
gates_.push_back(gate);
}
void Module::add_task(perm_string name, PTask*task)
{
tasks_[name] = task;
}
void Module::add_function(perm_string name, PFunction *func)
{
funcs_[name] = func;
}
unsigned Module::port_count() const
{
return ports.count();
+32 -12
View File
@@ -22,6 +22,7 @@
# include <list>
# include <map>
# include <utility>
# include "svector.h"
# include "StringHeap.h"
# include "HName.h"
@@ -75,16 +76,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 constraints, list them here
range_t*range;
};
map<perm_string,param_expr_t>parameters;
map<perm_string,param_expr_t>localparams;
@@ -99,7 +119,8 @@ class Module : public PScope, public LineInfo {
new parameters within the module, but may be used to set
values within this module (when instantiated) or in other
instantiated modules. */
map<pform_name_t,PExpr*>defparms;
typedef pair<pform_name_t,PExpr*> named_expr_t;
list<named_expr_t>defparms;
/* Parameters may be overridden at instantiation time;
the overrides do not contain explicit parameter names,
@@ -119,6 +140,10 @@ class Module : public PScope, public LineInfo {
set by the `timescale directive. */
int time_unit, time_precision;
/* Task definitions within this module */
map<perm_string,PTask*> tasks;
map<perm_string,PFunction*> funcs;
/* The module has a list of genvars that may be used in
various generate schemes. */
map<perm_string,LineInfo*> genvars;
@@ -133,8 +158,6 @@ class Module : public PScope, public LineInfo {
perm_string mod_name() const { return pscope_name(); }
void add_gate(PGate*gate);
void add_task(perm_string name, PTask*def);
void add_function(perm_string name, PFunction*def);
unsigned port_count() const;
const svector<PEIdent*>& get_port(unsigned idx) const;
@@ -148,18 +171,15 @@ class Module : public PScope, public LineInfo {
bool elaborate(Design*, NetScope*scope) const;
typedef map<perm_string,NetExpr*> replace_t;
bool elaborate_scope(Design*, NetScope*scope, const replace_t&rep) const;
bool elaborate_scope(Design*, NetScope*scope, const replace_t&rep);
bool elaborate_sig(Design*, NetScope*scope) const;
private:
list<PGate*> gates_;
map<perm_string,PTask*> tasks_;
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&);
+18
View File
@@ -306,10 +306,16 @@ 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:
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const;
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
index_component_t::ctype_t) const;
@@ -321,6 +327,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,
+3 -4
View File
@@ -1,7 +1,7 @@
#ifndef __PGate_H
#define __PGate_H
/*
* Copyright (c) 1998-2004 Stephen Williams ([email protected])
* Copyright (c) 1998-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
@@ -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: PGate.h,v 1.32 2006/04/10 00:37:42 steve Exp $"
#endif
# include "svector.h"
# include "StringHeap.h"
@@ -232,9 +229,11 @@ class PGModule : public PGate {
PExpr*msb_;
PExpr*lsb_;
friend class delayed_elaborate_scope_mod_instances;
void elaborate_mod_(Design*, Module*mod, NetScope*scope) const;
void elaborate_udp_(Design*, PUdp *udp, NetScope*scope) const;
void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const;
void elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const;
bool elaborate_sig_mod_(Design*des, NetScope*scope, Module*mod) const;
bool elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const;
+1 -14
View File
@@ -27,27 +27,14 @@ PGenerate::PGenerate(unsigned id)
: id_number(id)
{
parent = 0;
lexical_scope = 0;
}
PGenerate::~PGenerate()
{
}
PWire* PGenerate::get_wire(perm_string name) const
{
map<perm_string,PWire*>::const_iterator obj = wires.find(name);
if (obj == wires.end())
return 0;
else
return (*obj).second;
}
void PGenerate::add_gate(PGate*gate)
{
gates.push_back(gate);
}
void PGenerate::add_behavior(PProcess*proc)
{
behaviors.push_back(proc);
}
+16 -11
View File
@@ -1,7 +1,7 @@
#ifndef __PGenerate_H
#define __PGenerate_H
/*
* Copyright (c) 2006 Stephen Williams ([email protected])
* Copyright (c) 2006-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
@@ -18,13 +18,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: PGenerate.h,v 1.4 2007/06/02 03:42:12 steve Exp $"
#endif
# include "LineInfo.h"
# include "StringHeap.h"
# include "HName.h"
# include "PScope.h"
# include <list>
# include <map>
# include "pform_types.h"
@@ -32,7 +30,9 @@
class Design;
class NetScope;
class PExpr;
class PFunction;
class PProcess;
class PTask;
class PGate;
class PWire;
@@ -49,10 +49,10 @@ class PWire;
* The parent points to the GS_CASE that contains this item.
* the loop_test is compared with the parent->loop_test expression.
*/
class PGenerate : public LineInfo {
class PGenerate : public LineInfo, public LexicalScope {
public:
PGenerate(unsigned id_number);
explicit PGenerate(unsigned id_number);
~PGenerate();
// Generate schemes have an ID number, for when the scope is
@@ -60,6 +60,10 @@ class PGenerate : public LineInfo {
const unsigned id_number;
perm_string scope_name;
// This is used during parsing to stack lexical scopes within
// this generate scheme.
PScope*lexical_scope;
enum scheme_t {GS_NONE, GS_LOOP, GS_CONDIT, GS_ELSE,
GS_CASE, GS_CASE_ITEM};
scheme_t scheme_type;
@@ -71,16 +75,17 @@ class PGenerate : public LineInfo {
PExpr*loop_test;
PExpr*loop_step;
map<perm_string,PWire*>wires;
PWire* get_wire(perm_string name) const;
list<PGate*> gates;
void add_gate(PGate*);
list<PProcess*> behaviors;
void add_behavior(PProcess*behave);
list<PGenerate*> generates;
// Tasks instantiated within this scheme.
map<perm_string,PTask*> tasks;
map<perm_string,PFunction*>funcs;
// Generate schemes can contain further generate schemes.
list<PGenerate*> generate_schemes;
PGenerate*parent;
// This method is called by the elaboration of a module to
+8 -3
View File
@@ -19,8 +19,13 @@
# include "PScope.h"
PScope::PScope(perm_string n, PScope*p)
: name_(n), parent_(p)
PScope::PScope(perm_string n, PScope*parent)
: name_(n), parent_(parent)
{
}
PScope::PScope(perm_string n)
: name_(n), parent_(0)
{
}
@@ -28,7 +33,7 @@ PScope::~PScope()
{
}
PWire* PScope::wires_find(perm_string name)
PWire* LexicalScope::wires_find(perm_string name)
{
map<perm_string,PWire*>::const_iterator cur = wires.find(name);
if (cur == wires.end())
+17 -5
View File
@@ -38,7 +38,22 @@ class NetScope;
* NOTE: This is note the same concept as the "scope" of an elaborated
* hierarchy. That is represented by NetScope objects after elaboration.
*/
class PScope {
class LexicalScope {
public:
explicit LexicalScope() { }
// A virtual destructor is so that dynamic_cast can work.
virtual ~LexicalScope() { }
// Nets an variables (wires) in the scope
map<perm_string,PWire*>wires;
PWire* wires_find(perm_string name);
private:
};
class PScope : public LexicalScope {
public:
// When created, a scope has a name and a parent. The name is
@@ -50,15 +65,12 @@ class PScope {
// modules. Scopes for tasks and functions point to their
// containing module.
PScope(perm_string name, PScope*parent);
PScope(perm_string name);
virtual ~PScope();
perm_string pscope_name() const { return name_; }
PScope* pscope_parent() { return parent_; }
// Nets an variables (wires) in the scope
map<perm_string,PWire*>wires;
PWire* wires_find(perm_string name);
// Named events in the scope.
map<perm_string,PEvent*>events;
+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
@@ -92,7 +92,7 @@ PBlock::PBlock(perm_string n, PScope*parent, BL_TYPE t)
}
PBlock::PBlock(BL_TYPE t)
: PScope(perm_string(),0), bl_type_(t)
: PScope(perm_string()), bl_type_(t)
{
}
+2 -2
View File
@@ -9,11 +9,11 @@
echo "Autoconf in root..."
autoconf -f
for dir in vpip vpi vvp tgt-vvp tgt-fpga tgt-stub libveriuser cadpli
for dir in vpip vpi vvp tgt-vvp tgt-fpga tgt-stub tgt-vhdl libveriuser cadpli
do
echo "Autoconf in $dir..."
( cd ./$dir ; autoconf -f --include=.. )
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;
+5 -2
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 ""
@@ -119,6 +122,6 @@ AX_C_UNDERSCORES_TRAILING
AX_CPP_IDENT
# XXX disable tgt-fpga for the moment
AC_CONFIG_SUBDIRS(vvp vpi tgt-stub tgt-null tgt-vvp libveriuser cadpli)
AC_CONFIG_SUBDIRS(vvp vpi tgt-stub tgt-null tgt-vvp tgt-vhdl libveriuser cadpli)
AC_OUTPUT(Makefile ivlpp/Makefile driver/Makefile driver-vpi/Makefile tgt-null/Makefile tgt-verilog/Makefile tgt-pal/Makefile)
AC_OUTPUT(Makefile ivlpp/Makefile driver/Makefile driver-vpi/Makefile tgt-null/Makefile tgt-verilog/Makefile tgt-pal/Makefile tgt-vhdl/Makefile)
+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;
}
}
/*
+101 -10
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()) {
@@ -274,6 +302,22 @@ void NetArrayDq::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetCastInt::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Cast to int. (NetCastInt): " <<
name() << " width=" << width() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetCastReal::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Cast to real (NetCastReal): " <<
name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetCLShift::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " <<
@@ -493,9 +537,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 +652,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 +1021,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()
@@ -979,7 +1063,7 @@ void NetScope::dump(ostream&o) const
/* Dump the saved defparam assignments here. */
{
map<pform_name_t,NetExpr*>::const_iterator pp;
list<pair<pform_name_t,NetExpr*> >::const_iterator pp;
for (pp = defparams.begin()
; pp != defparams.end() ; pp ++ ) {
o << " defparam " << (*pp).first << " = " <<
@@ -987,6 +1071,15 @@ void NetScope::dump(ostream&o) const
}
}
{
list<pair<list<hname_t>,NetExpr*> >::const_iterator pp;
for (pp = defparams_later.begin()
; pp != defparams_later.end() ; pp ++ ) {
o << " defparam(later) " << pp->first << " = " <<
*(pp->second) << ";" << endl;
}
}
/* Dump the events in this scope. */
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) {
o << " event " << cur->name() << "; nprobe="
@@ -1261,11 +1354,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
+6
View File
@@ -223,6 +223,12 @@ mostly by EDIF format output. The Icarus Verilog fpga code generator
can generate complete designs or EDIF macros that can in turn be
imported into larger designs by other tools. The \fBfpga\fP target
implies the synthesis \fB-S\fP flag.
.TP 8
.B vhdl
This target produces a VHDL translation of the Verilog netlist. The
output is a single file containing VHDL entities corresponding to
the modules in the Verilog source code. Note that only a subset of
the Verilog language is supported. See the wiki for more information.
.SH "WARNING TYPES"
These are the types of warnings that can be selected by the \fB-W\fP
+17 -13
View File
@@ -327,21 +327,26 @@ 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! */
free(cmd);
return rc;
#else
int rtn = 0;
if (rc != 0) {
if (rc == 127) {
fprintf(stderr, "Failed to execute: %s\n", cmd);
return 1;
}
if (WIFEXITED(rc))
return WEXITSTATUS(rc);
fprintf(stderr, "Command signaled: %s\n", cmd);
return -1;
rtn = 1;
} else if (WIFEXITED(rc)) {
rtn = WEXITSTATUS(rc);
} else {
fprintf(stderr, "Command signaled: %s\n", cmd);
rtn = -1;
}
}
return 0;
free(cmd);
return rtn;
#endif
}
@@ -501,7 +506,7 @@ int process_generation(const char*name)
" 2005 -- IEEE1364-2005\n"
"Other generation flags:\n"
" specify | no-specify\n"
" verilog-ams | no-verinlog-ams\n"
" verilog-ams | no-verilog-ams\n"
" std-include | no-std-include\n"
" xtypes | no-xtypes\n"
" icarus-misc | no-icarus-misc\n"
@@ -867,6 +872,7 @@ int main(int argc, char **argv)
}
fprintf(stderr, "Command signaled: %s\n", cmd);
free(cmd);
return -1;
}
@@ -885,6 +891,4 @@ int main(int argc, char **argv)
fclose(iconfig_file);
return t_default(cmd, ncmd);
return 0;
}
+214 -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 in this function other
// than 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();
@@ -1249,7 +1373,7 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
par_mv = par_me->value().as_long();
par_lv = par_le->value().as_long();
}
/* Convert the index to cannonical bit address. */
/* Convert the index to canonical bit address. */
long ridx = rv.as_long();
if (par_mv >= par_lv) {
ridx -= par_lv;
@@ -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,26 +1562,29 @@ 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())
// signal itself, casting to unsigned if necessary.
if (sb_lsb == 0 && wid == net->vector_width()) {
net->cast_signed(false);
return net;
}
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
// If the part select covers NONE of the vector, then return a
// constant X.
if ((sb_lsb >= (signed) net->vector_width()) || (sb_msb < 0)) {
NetEConst*tmp = make_const_x(wid);
tmp->set_line(*this);
return tmp;
}
NetExpr*ex = new NetEConst(verinum(sb_lsb));
NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this);
return ss;
}
@@ -1477,14 +1594,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 +1719,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 ["
+71 -102
View File
@@ -208,101 +208,18 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
return 0;
}
long msb, lsb;
NetExpr*mux;
if (use_sel == index_component_t::SEL_BIT) {
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
/* If there is only a single select expression, it is a
bit select. Evaluate the constant value and treat it
as a part select with a bit width of 1. If the
expression it not constant, then return the
expression as a mux. */
NetExpr*index_expr = elab_and_eval(des, scope, index_tail.msb, -1);
if (NetEConst*index_con = dynamic_cast<NetEConst*> (index_expr)) {
msb = index_con->value().as_long();
lsb = index_con->value().as_long();
mux = 0;
} else {
msb = 0;
lsb = 0;
mux = index_expr;
}
} else {
/* No select expressions, so presume a part select the
width of the register. */
msb = reg->msb();
lsb = reg->lsb();
mux = 0;
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_bit_(des, scope, lv);
return lv;
}
ivl_assert(*this, use_sel == index_component_t::SEL_NONE);
NetAssign_*lv;
if (mux) {
/* If there is a non-constant bit select, make a
NetAssign_ to the target reg and attach a
bmux to select the target bit. */
lv = new NetAssign_(reg);
/* Correct the mux for the range of the vector. */
if (reg->msb() < reg->lsb())
mux = make_sub_expr(reg->lsb(), mux);
else if (reg->lsb() != 0)
mux = make_add_expr(mux, - reg->lsb());
lv->set_part(mux, 1);
} else if (msb == reg->msb() && lsb == reg->lsb()) {
/* No bit select, and part select covers the entire
vector. Simplest case. */
lv = new NetAssign_(reg);
} else {
/* If the bit/part select is constant, then make the
NetAssign_ only as wide as it needs to be and connect
only to the selected bits of the reg. */
unsigned loff = reg->sb_to_idx(lsb);
unsigned moff = reg->sb_to_idx(msb);
unsigned wid = moff - loff + 1;
if (moff < loff) {
cerr << get_fileline() << ": error: part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is reversed." << endl;
des->errors += 1;
return 0;
}
/* If the part select extends beyond the extreme of the
variable, then report an error. Note that loff is
converted to normalized form so is relative the
variable pins. */
if ((wid + loff) > reg->vector_width()) {
cerr << get_fileline() << ": error: bit/part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
des->errors += 1;
return 0;
}
lv = new NetAssign_(reg);
lv->set_part(new NetEConst(verinum(loff)), wid);
}
/* No select expressions. */
NetAssign_*lv = new NetAssign_(reg);
return lv;
}
@@ -374,10 +291,67 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
return lv;
}
bool PEIdent::elaborate_lval_net_bit_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
const name_component_t&name_tail = path_.back();
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
NetNet*reg = lv->sig();
// Bit selects have a single select expression. Evaluate the
// constant value and treat it as a part select with a bit
// width of 1.
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1);
long lsb = 0;
if (NetEConst*index_con = dynamic_cast<NetEConst*> (mux)) {
lsb = index_con->value().as_long();
mux = 0;
}
if (mux) {
// Non-constant bit mux. Correct the mux for the range
// of the vector, then set the l-value part select expression.
if (reg->msb() < reg->lsb())
mux = make_sub_expr(reg->lsb(), mux);
else if (reg->lsb() != 0)
mux = make_add_expr(mux, - reg->lsb());
lv->set_part(mux, 1);
} else if (lsb == reg->msb() && lsb == reg->lsb()) {
// Constant bit mux that happens to select the only bit
// of the l-value. Don't bother with any select at all.
} else {
// Constant bit select that does something useful.
long loff = reg->sb_to_idx(lsb);
if (loff < 0 || loff >= (long)reg->vector_width()) {
cerr << get_fileline() << ": error: bit select "
<< reg->name() << "[" <<lsb<<"]"
<< " is out of range." << endl;
des->errors += 1;
return 0;
}
lv->set_part(new NetEConst(verinum(loff)), 1);
}
return true;
}
bool PEIdent::elaborate_lval_net_part_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
// The range expressions of a part select must be
// constant. The calculate_parts_ function calculates the
// values into msb and lsb.
long msb, lsb;
bool flag = calculate_parts_(des, scope, msb, lsb);
if (!flag)
@@ -388,17 +362,14 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
if (msb == reg->msb() && lsb == reg->lsb()) {
/* No bit select, and part select covers the entire
vector. Simplest case. */
/* Part select covers the entire vector. Simplest case. */
} else {
/* If the bit/part select is constant, then make the
NetAssign_ only as wide as it needs to be and connect
only to the selected bits of the reg. */
unsigned loff = reg->sb_to_idx(lsb);
unsigned moff = reg->sb_to_idx(msb);
unsigned wid = moff - loff + 1;
/* Get the canonical offsets into the vector. */
long loff = reg->sb_to_idx(lsb);
long moff = reg->sb_to_idx(msb);
long wid = moff - loff + 1;
if (moff < loff) {
cerr << get_fileline() << ": error: part select "
@@ -408,17 +379,15 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
return false;
}
/* If the part select extends beyond the extreme of the
/* If the part select extends beyond the extremes of the
variable, then report an error. Note that loff is
converted to normalized form so is relative the
variable pins. */
if ((wid + loff) > reg->vector_width()) {
cerr << get_fileline() << ": error: bit/part select "
if (loff < 0 || moff >= (signed)reg->vector_width()) {
cerr << get_fileline() << ": warning: Part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
des->errors += 1;
return false;
}
lv->set_part(new NetEConst(verinum(loff)), wid);
+116 -47
View File
@@ -137,7 +137,7 @@ NetNet* PEBinary::elaborate_net_add_(Design*des, NetScope*scope,
const NetExpr* decay) const
{
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0 || rsig == 0) return 0;
@@ -449,26 +449,21 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
const NetExpr* fall,
const NetExpr* decay) const
{
/* Elaborate the operands of the compare first as expressions
(so that the eval_tree method can reduce constant
expressions, including parameters) then turn those results
into synthesized nets. */
NetExpr*lexp = elab_and_eval(des, scope, left_, lwidth),
*rexp = elab_and_eval(des, scope, right_, lwidth);
NetExpr*lexp = elab_and_eval(des, scope, left_, -1),
*rexp = elab_and_eval(des, scope, right_, -1);
if (lexp == 0 || rexp == 0) return 0;
unsigned operand_width;
bool real_arg = false;
if (lexp->expr_type() == IVL_VT_REAL ||
rexp->expr_type() == IVL_VT_REAL) {
operand_width = 1;
real_arg = true;
} else {
bool real_arg = true;
if (lexp->expr_type() != IVL_VT_REAL &&
rexp->expr_type() != IVL_VT_REAL) {
/* Choose the operand width to be the width of the widest
self-determined operand. */
operand_width = lexp->expr_width();
unsigned operand_width = lexp->expr_width();
if (rexp->expr_width() > operand_width)
operand_width = rexp->expr_width();
@@ -476,6 +471,8 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
lexp = pad_to_width(lexp, operand_width);
rexp->set_width(operand_width);
rexp = pad_to_width(rexp, operand_width);
real_arg = false;
}
NetNet*lsig = 0;
@@ -719,6 +716,16 @@ NetNet* PEBinary::elaborate_net_div_(Design*des, NetScope*scope,
unsigned rwidth = lwidth;
// If either operand is IVL_VT_REAL, then cast the other to
// IVL_VT_REAL so that the division can become IVL_VT_REAL.
if (lsig->data_type()==IVL_VT_REAL || rsig->data_type()==IVL_VT_REAL) {
if (lsig->data_type() != IVL_VT_REAL)
lsig = cast_to_real(des, scope, lsig);
if (rsig->data_type() != IVL_VT_REAL)
rsig = cast_to_real(des, scope, rsig);
}
if (rwidth == 0) {
rwidth = lsig->vector_width();
if (rsig->vector_width() > rwidth)
@@ -790,8 +797,8 @@ NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope,
const NetExpr* fall,
const NetExpr* decay) const
{
NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0);
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0 || rsig == 0) return 0;
@@ -1578,6 +1585,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()
@@ -1779,8 +1794,32 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
that connects to a signal with the correct name. */
if (par != 0) {
// Detect and handle the special case that we have a
// real valued parameter. Return a NetLiteral and a
// properly typed net.
if (const NetECReal*pc = dynamic_cast<const NetECReal*>(par)) {
NetLiteral*tmp = new NetLiteral(scope, scope->local_symbol(),
pc->value());
des->add_node(tmp);
tmp->set_line(*par);
sig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT);
sig->set_line(*tmp);
sig->data_type(tmp->data_type());
sig->local_flag(true);
connect(tmp->pin(0), sig->pin(0));
return sig;
}
const NetEConst*pc = dynamic_cast<const NetEConst*>(par);
assert(pc);
if (pc == 0) {
cerr << get_fileline() << ": internal error: "
<< "Non-consant parameter value?: " << *par << endl;
cerr << get_fileline() << ": : "
<< "Expression type is " << par->expr_type() << endl;
}
ivl_assert(*this, pc);
verinum pvalue = pc->value();
/* If the parameter has declared dimensions, then apply
@@ -2288,7 +2327,7 @@ NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope,
} while (0);
#else
if (name_tail.index.size() > sig->array_dimensions())
tmp = process_select_(des, scope, sig);
tmp = process_select_(des, scope, tmp);
#endif
return tmp;
@@ -2367,30 +2406,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 +2805,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 +2821,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;
}
+269 -80
View File
@@ -22,6 +22,7 @@
# include "netmisc.h"
# include <cstring>
# include <iostream>
# include <cstdlib>
# include <stdio.h>
/*
@@ -43,16 +44,16 @@
# 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);
NetExpr*val = ex->elaborate_pexpr(des, scope);
if (val == 0) return;
NetExpr*msb = 0;
NetExpr*lsb = 0;
bool signed_flag = cur.signed_flag;
@@ -63,9 +64,53 @@ 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);
}
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;
}
/* Set the parameter expression to 0 if the evaluation failed. */
if (val == 0) {
val = scope->set_parameter(name, val, cur.type, msb, lsb,
signed_flag, range_list, cur);
delete val;
return;
}
if (signed_flag) {
@@ -81,14 +126,103 @@ 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);
assert(val);
val = scope->set_parameter(name, val, cur.type, msb, lsb, signed_flag,
range_list, cur);
delete val;
}
static void elaborate_scope_tasks(Design*des, NetScope*scope,
const LineInfo&loc,
const map<perm_string,PTask*>&tasks)
{
typedef map<perm_string,PTask*>::const_iterator tasks_it_t;
for (tasks_it_t cur = tasks.begin()
; cur != tasks.end() ; cur ++ ) {
hname_t use_name( (*cur).first );
if (scope->child(use_name)) {
cerr << loc.get_fileline() << ": error: task/scope name "
<< use_name << " already used in this context."
<< endl;
des->errors += 1;
continue;
}
NetScope*task_scope = new NetScope(scope, use_name,
NetScope::TASK);
task_scope->set_line((*cur).second);
if (debug_scopes)
cerr << cur->second->get_fileline() << ": debug: "
<< "Elaborate task scope " << scope_path(task_scope) << endl;
(*cur).second->elaborate_scope(des, task_scope);
}
}
static void elaborate_scope_funcs(Design*des, NetScope*scope,
const LineInfo&loc,
const map<perm_string,PFunction*>&funcs)
{
typedef map<perm_string,PFunction*>::const_iterator funcs_it_t;
for (funcs_it_t cur = funcs.begin()
; cur != funcs.end() ; cur ++ ) {
hname_t use_name( (*cur).first );
if (scope->child(use_name)) {
cerr << loc.get_fileline() << ": error: function/scope name "
<< use_name << " already used in this context."
<< endl;
des->errors += 1;
continue;
}
NetScope*func_scope = new NetScope(scope, use_name,
NetScope::FUNC);
func_scope->set_line((*cur).second);
if (debug_scopes)
cerr << cur->second->get_fileline() << ": debug: "
<< "Elaborate function scope " << scope_path(func_scope) << endl;
(*cur).second->elaborate_scope(des, func_scope);
}
}
class generate_schemes_work_item_t : public elaborator_work_item_t {
public:
generate_schemes_work_item_t(Design*des, NetScope*scope, Module*mod)
: elaborator_work_item_t(des), scope_(scope), mod_(mod)
{ }
void elaborate_runrun()
{
if (debug_scopes)
cerr << mod_->get_fileline() << ": debug: "
<< "Processing generate schemes for "
<< scope_path(scope_) << endl;
// Generate schemes can create new scopes in the form of
// generated code. Scan the generate schemes, and *generate*
// new scopes, which is slightly different from simple
// elaboration.
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = mod_->generate_schemes.begin()
; cur != mod_->generate_schemes.end() ; cur ++ ) {
(*cur) -> generate_scope(des, scope_);
}
}
private:
// The scope_ is the scope that contains the generate scheme
// we are to work on. the mod_ is the Module definition for
// that scope, and contains the parsed generate schemes.
NetScope*scope_;
Module*mod_;
};
bool Module::elaborate_scope(Design*des, NetScope*scope,
const replace_t&replacements) const
const replace_t&replacements)
{
if (debug_scopes) {
cerr << get_fileline() << ": debug: Elaborate scope "
@@ -107,8 +241,6 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
// place of the elaborated expression.
typedef map<perm_string,param_expr_t>::const_iterator mparm_it_t;
typedef map<pform_name_t,PExpr*>::const_iterator pform_parm_it_t;
// This loop scans the parameters in the module, and creates
// stub parameter entries in the scope for the parameter name.
@@ -120,8 +252,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 +264,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 +277,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 +297,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 +311,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
@@ -192,15 +324,17 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
// here because the parameter receiving the assignment may be
// in a scope not discovered by this pass.
for (pform_parm_it_t cur = defparms.begin()
; cur != defparms.end() ; cur ++ ) {
typedef list<Module::named_expr_t>::const_iterator defparms_iter_t;
for (defparms_iter_t cur = defparms.begin()
; cur != defparms.end() ; cur ++) {
PExpr*ex = (*cur).second;
PExpr*ex = cur->second;
assert(ex);
NetExpr*val = ex->elaborate_pexpr(des, scope);
if (val == 0) continue;
scope->defparams[(*cur).first] = val;
scope->defparams.push_back(make_pair(cur->first, val));
}
// Evaluate the attributes. Evaluate them in the scope of the
@@ -213,66 +347,29 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
delete[]attr;
// Generate schemes can create new scopes in the form of
// generated code. Scan the generate schemes, and *generate*
// new scopes, which is slightly different from simple
// elaboration.
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++ ) {
(*cur) -> generate_scope(des, scope);
}
// Generate schemes need to have their scopes elaborated, but
// we cannot do that until defparams are run, so push it off
// into an elaborate work item.
if (debug_scopes)
cerr << get_fileline() << ": debug: "
<< "Schedule generates within " << scope_path(scope)
<< " for elaboration after defparams." << endl;
des->elaboration_work_list.push_back(new generate_schemes_work_item_t(des, scope, this));
// Tasks introduce new scopes, so scan the tasks in this
// module. Create a scope for the task and pass that to the
// elaborate_scope method of the PTask for detailed
// processing.
typedef map<perm_string,PTask*>::const_iterator tasks_it_t;
for (tasks_it_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++ ) {
hname_t use_name( (*cur).first );
if (scope->child(use_name)) {
cerr << get_fileline() << ": error: task/scope name "
<< use_name << " already used in this context."
<< endl;
des->errors += 1;
continue;
}
NetScope*task_scope = new NetScope(scope, use_name,
NetScope::TASK);
task_scope->set_line((*cur).second);
(*cur).second->elaborate_scope(des, task_scope);
}
elaborate_scope_tasks(des, scope, *this, tasks);
// Functions are very similar to tasks, at least from the
// perspective of scopes. So handle them exactly the same
// way.
typedef map<perm_string,PFunction*>::const_iterator funcs_it_t;
for (funcs_it_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++ ) {
hname_t use_name( (*cur).first );
if (scope->child(use_name)) {
cerr << get_fileline() << ": error: function/scope name "
<< use_name << " already used in this context."
<< endl;
des->errors += 1;
continue;
}
NetScope*func_scope = new NetScope(scope, use_name,
NetScope::FUNC);
func_scope->set_line((*cur).second);
(*cur).second->elaborate_scope(des, func_scope);
}
elaborate_scope_funcs(des, scope, *this, funcs);
// Gates include modules, which might introduce new scopes, so
// scan all of them to create those scopes.
@@ -386,7 +483,12 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
container->genvar_tmp_val = genvar;
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
NetEConst*test = dynamic_cast<NetEConst*>(test_ex);
assert(test);
if (test == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar"
<< " conditional expression: " << *loop_test << endl;
des->errors += 1;
return false;
}
while (test->value().as_long()) {
// The actual name of the scope includes the genvar so
@@ -421,9 +523,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 "
@@ -435,7 +535,12 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
// Calculate the step for the loop variable.
NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1);
NetEConst*step = dynamic_cast<NetEConst*>(step_ex);
assert(step);
if (step == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar"
<< " step expression: " << *loop_step << endl;
des->errors += 1;
return false;
}
if (debug_scopes)
cerr << get_fileline() << ": debug: genvar step from "
<< genvar << " to " << step->value().as_long() << endl;
@@ -460,7 +565,12 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
{
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
NetEConst*test = dynamic_cast<NetEConst*> (test_ex);
assert(test);
if (test == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar"
<< " conditional expression: " << *loop_test << endl;
des->errors += 1;
return false;
}
// If the condition evaluates as false, then do not create the
// scope.
@@ -502,7 +612,12 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
{
NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1);
NetEConst*case_value_co = dynamic_cast<NetEConst*>(case_value_ex);
assert(case_value_co);
if (case_value_co == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar case"
<< " expression: " << *loop_test << endl;
des->errors += 1;
return false;
}
// The name of the scope to generate, whatever that item is.
hname_t use_name (scope_name);
@@ -514,8 +629,8 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
PGenerate*default_item = 0;
typedef list<PGenerate*>::const_iterator generator_it_t;
generator_it_t cur = generates.begin();
while (cur != generates.end()) {
generator_it_t cur = generate_schemes.begin();
while (cur != generate_schemes.end()) {
PGenerate*item = *cur;
assert( item->scheme_type == PGenerate::GS_CASE_ITEM );
@@ -544,7 +659,7 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
delete case_value_co;
case_value_co = 0;
PGenerate*item = (cur == generates.end())? default_item : *cur;
PGenerate*item = (cur == generate_schemes.end())? default_item : *cur;
if (item == 0) {
cerr << get_fileline() << ": debug: "
<< "No generate items found" << endl;
@@ -571,11 +686,14 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
// from simple elaboration.
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generates.begin()
; cur != generates.end() ; cur ++ ) {
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++ ) {
(*cur) -> generate_scope(des, scope);
}
elaborate_scope_tasks(des, scope, *this, tasks);
elaborate_scope_funcs(des, scope, *this, funcs);
// Scan the generated scope for gates that may create
// their own scopes.
typedef list<PGate*>::const_iterator pgate_list_it_t;
@@ -584,10 +702,51 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
(*cur) ->elaborate_scope(des, scope);
}
typedef list<PProcess*>::const_iterator proc_it_t;
for (proc_it_t cur = behaviors.begin()
; cur != behaviors.end() ; cur ++ ) {
(*cur) -> statement() -> elaborate_scope(des, scope);
}
// Save the scope that we created, for future use.
scope_list_.push_back(scope);
}
class delayed_elaborate_scope_mod_instances : public elaborator_work_item_t {
public:
delayed_elaborate_scope_mod_instances(Design*des,
const PGModule*obj,
Module*mod,
NetScope*sc)
: elaborator_work_item_t(des), obj_(obj), mod_(mod), sc_(sc)
{ }
~delayed_elaborate_scope_mod_instances() { }
virtual void elaborate_runrun();
private:
const PGModule*obj_;
Module*mod_;
NetScope*sc_;
};
void delayed_elaborate_scope_mod_instances::elaborate_runrun()
{
if (debug_scopes)
cerr << obj_->get_fileline() << ": debug: "
<< "Resume scope elaboration of instances of "
<< mod_->mod_name() << "." << endl;
obj_->elaborate_scope_mod_instances_(des, mod_, sc_);
}
/*
* Here we handle the elaborate scope of a module instance. The caller
* has already figured out that this "gate" is a module, and has found
* the module definition. The "sc" argument is the scope that will
* contain this instance.
*/
void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
{
if (get_name() == "") {
@@ -634,6 +793,36 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
return;
}
if (msb_ || lsb_) {
// If there are expressions to evaluate in order to know
// the actual number of instances that will be
// instantiated, then we have to delay further scope
// elaboration until after defparams (above me) are
// run. Do that by appending a work item to the
// elaboration work list.
if (debug_scopes)
cerr << get_fileline() << ": debug: delay elaborate_scope"
<< " of array of " << get_name()
<< " in scope " << scope_path(sc) << "." << endl;
elaborator_work_item_t*tmp
= new delayed_elaborate_scope_mod_instances(des, this, mod, sc);
des->elaboration_work_list.push_back(tmp);
} else {
// If there are no expressions that need to be evaluated
// to elaborate the scope of this next instances, then
// get right to it.
elaborate_scope_mod_instances_(des, mod, sc);
}
}
/*
* This method is called to process a module instantiation after basic
* sanity testing is already complete.
*/
void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const
{
NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0;
NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0;
NetEConst*msb = dynamic_cast<NetEConst*> (mse);
+61 -37
View File
@@ -108,6 +108,42 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const
return flag;
}
static void elaborate_sig_funcs(Design*des, NetScope*scope,
const map<perm_string,PFunction*>&funcs)
{
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
for (mfunc_it_t cur = funcs.begin()
; cur != funcs.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*fscope = scope->child(use_name);
if (scope == 0) {
cerr << (*cur).second->get_fileline() << ": internal error: "
<< "Child scope for function " << (*cur).first
<< " missing in " << scope_path(scope) << "." << endl;
des->errors += 1;
continue;
}
(*cur).second->elaborate_sig(des, fscope);
}
}
static void elaborate_sig_tasks(Design*des, NetScope*scope,
const map<perm_string,PTask*>&tasks)
{
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
for (mtask_it_t cur = tasks.begin()
; cur != tasks.end() ; cur ++) {
NetScope*tscope = scope->child( hname_t((*cur).first) );
assert(tscope);
(*cur).second->elaborate_sig(des, tscope);
}
}
bool Module::elaborate_sig(Design*des, NetScope*scope) const
{
bool flag = true;
@@ -182,38 +218,12 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
flag &= (*gt)->elaborate_sig(des, scope);
}
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
for (mfunc_it_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*fscope = scope->child(use_name);
if (scope == 0) {
cerr << (*cur).second->get_fileline() << ": internal error: "
<< "Child scope for function " << (*cur).first
<< " missing in " << scope_path(scope) << "." << endl;
des->errors += 1;
continue;
}
(*cur).second->elaborate_sig(des, fscope);
}
// After all the wires are elaborated, we are free to
// elaborate the ports of the tasks defined within this
// module. Run through them now.
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
for (mtask_it_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++) {
NetScope*tscope = scope->child( hname_t((*cur).first) );
assert(tscope);
(*cur).second->elaborate_sig(des, tscope);
}
elaborate_sig_funcs(des, scope, funcs);
elaborate_sig_tasks(des, scope, tasks);
// initial and always blocks may contain begin-end and
// fork-join blocks that can introduce scopes. Therefore, I
@@ -415,8 +425,8 @@ bool PGenerate::elaborate_sig(Design*des, NetScope*container) const
<< scope_path(container) << "." << endl;
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generates.begin()
; cur != generates.end() ; cur ++) {
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++) {
PGenerate*item = *cur;
if (! item->scope_list_.empty()) {
flag &= item->elaborate_sig(des, container);
@@ -461,9 +471,12 @@ bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const
cur->elaborate_sig(des, scope);
}
elaborate_sig_funcs(des, scope, funcs);
elaborate_sig_tasks(des, scope, tasks);
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generates.begin()
; cur != generates.end() ; cur ++ ) {
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++ ) {
(*cur) -> elaborate_sig(des, scope);
}
@@ -576,9 +589,17 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
break;
default:
cerr << get_fileline() << ": internal error: I don't know how "
<< "to deal with return type of function "
<< scope->basename() << "." << endl;
if (ports_) {
cerr << get_fileline() << ": internal error: I don't know "
<< "how to deal with return type of function "
<< scope->basename() << "." << endl;
} else {
/* If we do not have any ports or a return type this
* is probably a bad function definition. */
cerr << get_fileline() << ": error: Bad definition for "
<< "function " << scope->basename() << "?" << endl;
return;
}
}
svector<NetNet*>ports (ports_? ports_->count() : 0);
@@ -990,8 +1011,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal "
<< wtype << " ["<<msb<<":"<<lsb<<"] " << name_
<< " in scope " << scope_path(scope) << endl;
<< wtype << " ["<<msb<<":"<<lsb<<"] " << name_;
if (array_dimensions > 0) {
cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl;
}
cerr << " in scope " << scope_path(scope) << endl;
}
+315 -87
View File
@@ -94,7 +94,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
assert(lval->pin_count() == 1);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGassign: elaborated l-value"
cerr << get_fileline() << ": debug: PGAssign: elaborated l-value"
<< " width=" << lval->vector_width()
<< ", type=" << lval->data_type() << endl;
}
@@ -113,14 +113,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
return;
}
/* If either lval or rid are real then both must be real. */
if ((lval->data_type() == IVL_VT_REAL ||
rid->data_type() == IVL_VT_REAL) &&
lval->data_type() != rid->data_type()) {
cerr << get_fileline() << ": sorry: Both the r-value and "
"the l-value must be real in this context." << endl;
des->errors += 1;
return;
/* Cast the right side when needed. */
if ((lval->data_type() == IVL_VT_REAL &&
rid->data_type() != IVL_VT_REAL)) {
rid = cast_to_real(des, scope, rid);
} else if ((lval->data_type() != IVL_VT_REAL &&
rid->data_type() == IVL_VT_REAL)) {
rid = cast_to_int(des, scope, rid, lval->vector_width());
}
ivl_assert(*this, rid);
@@ -287,14 +286,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
assert(lval && rval);
assert(rval->pin_count() == 1);
/* If either lval or rval are real then both must be real. */
if ((lval->data_type() == IVL_VT_REAL ||
rval->data_type() == IVL_VT_REAL) &&
lval->data_type() != rval->data_type()) {
cerr << get_fileline() << ": sorry: Both the r-value and "
"the l-value must be real in this context." << endl;
des->errors += 1;
return;
/* Cast the right side when needed. */
if ((lval->data_type() == IVL_VT_REAL &&
rval->data_type() != IVL_VT_REAL)) {
rval = cast_to_real(des, scope, rval);
} else if ((lval->data_type() != IVL_VT_REAL &&
rval->data_type() == IVL_VT_REAL)) {
rval = cast_to_int(des, scope, rval, lval->vector_width());
}
/* If the r-value insists on being smaller then the l-value
@@ -386,7 +384,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
high = msb.as_long();
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGBuiltin: Make arrray "
cerr << get_fileline() << ": debug: PGBuiltin: Make array "
<< "[" << high << ":" << low << "]"
<< " of " << count << " gates for " << name << endl;
}
@@ -419,7 +417,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 +657,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 +729,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 +862,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 +879,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 +932,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:
@@ -860,6 +944,17 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
return tmp;
}
static bool need_bufz_for_input_port(const svector<NetNet*>&prts)
{
if (prts[0]->port_type() != NetNet::PINPUT)
return false;
if (prts[0]->pin(0).nexus()->drivers_present())
return true;
return false;
}
/*
* Instantiate a module by recursively elaborating it. Set the path of
* the recursive elaboration so that signal names get properly
@@ -1074,11 +1169,11 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
/* Input to module. elaborate the expression to
the desired width. If this in an instance
array, then let the net determine it's own
array, then let the net determine its own
width. We use that, then, to decide how to hook
it up.
NOTE that this also handles the case that the
v NOTE that this also handles the case that the
port is actually empty on the inside. We assume
in that case that the port is input. */
@@ -1092,6 +1187,21 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
continue;
}
if (need_bufz_for_input_port(prts)) {
NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(),
sig->vector_width());
des->add_node(tmp);
connect(tmp->pin(1), sig->pin(0));
NetNet*tmp2 = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, sig->vector_width());
tmp2->local_flag(true);
tmp2->set_line(*this);
tmp2->data_type(sig->data_type());
connect(tmp->pin(0), tmp2->pin(0));
sig = tmp2;
}
} else if (prts[0]->port_type() == NetNet::PINOUT) {
/* Inout to/from module. This is a more
@@ -1103,8 +1213,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
identifier elaborates to the same NetNet in
both cases so the extra elaboration has no
effect. But if the expression passed to the
inout port is a part select, aspecial part
select must be created that can paqss data in
inout port is a part select, a special part
select must be created that can pass data in
both directions.
Use the elaborate_bi_net method to handle all
@@ -1866,7 +1976,7 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
if (nscope == 0) {
cerr << get_fileline() << ": internal error: "
"unable to find block scope " << scope_path(scope)
<< "<" << pscope_name() << ">" << endl;
<< "." << pscope_name() << endl;
des->errors += 1;
return 0;
}
@@ -2539,8 +2649,8 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
}
NexusSet*nset = enet->nex_input(rem_out);
if (nset == 0) {
cerr << get_fileline() << ": internal error: No NexusSet"
<< " from statement." << endl;
cerr << get_fileline() << ": error: Unable to elaborate:"
<< endl;
enet->dump(cerr, 6);
des->errors += 1;
return enet;
@@ -2870,7 +2980,7 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
dev = new NetForce(lval, rexp);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: ELaborate force,"
cerr << get_fileline() << ": debug: Elaborate force,"
<< " lval width=" << lval->lwidth()
<< " rval width=" << rexp->expr_width()
<< " rval=" << *rexp
@@ -2969,7 +3079,7 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
sig = des->find_signal(scope, id2->path());
if (sig == 0) {
cerr << get_fileline() << ": error: Unable to find variable "
<< id2->path() << " in for-loop increment expressin." << endl;
<< id2->path() << " in for-loop increment expression." << endl;
des->errors += 1;
return body;
}
@@ -3470,6 +3580,34 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
}
static void elaborate_functions(Design*des, NetScope*scope,
const map<perm_string,PFunction*>&funcs)
{
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
for (mfunc_it_t cur = funcs.begin()
; cur != funcs.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*fscope = scope->child(use_name);
assert(fscope);
(*cur).second->elaborate(des, fscope);
}
}
static void elaborate_tasks(Design*des, NetScope*scope,
const map<perm_string,PTask*>&tasks)
{
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
for (mtask_it_t cur = tasks.begin()
; cur != tasks.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*tscope = scope->child(use_name);
assert(tscope);
(*cur).second->elaborate(des, tscope);
}
}
/*
* When a module is instantiated, it creates the scope then uses this
* method to elaborate the contents of the module.
@@ -3529,28 +3667,12 @@ bool Module::elaborate(Design*des, NetScope*scope) const
}
// Elaborate functions.
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
for (mfunc_it_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*fscope = scope->child(use_name);
assert(fscope);
(*cur).second->elaborate(des, fscope);
}
elaborate_functions(des, scope, funcs);
// Elaborate the task definitions. This is done before the
// behaviors so that task calls may reference these, and after
// the signals so that the tasks can reference them.
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
for (mtask_it_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*tscope = scope->child(use_name);
assert(tscope);
(*cur).second->elaborate(des, tscope);
}
elaborate_tasks(des, scope, tasks);
// Get all the gates of the module and elaborate them by
// connecting them to the signals. The gate may be simple or
@@ -3595,8 +3717,8 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
<< scope_path(container) << "." << endl;
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generates.begin()
; cur != generates.end() ; cur ++) {
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++) {
PGenerate*item = *cur;
if (! item->scope_list_.empty()) {
flag &= item->elaborate(des, container);
@@ -3638,6 +3760,9 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
bool PGenerate::elaborate_(Design*des, NetScope*scope) const
{
elaborate_functions(des, scope, funcs);
elaborate_tasks(des, scope, tasks);
typedef list<PGate*>::const_iterator gates_it_t;
for (gates_it_t cur = gates.begin() ; cur != gates.end() ; cur ++ )
(*cur)->elaborate(des, scope);
@@ -3647,8 +3772,8 @@ bool PGenerate::elaborate_(Design*des, NetScope*scope) const
(*cur)->elaborate(des, scope);
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generates.begin()
; cur != generates.end() ; cur ++ ) {
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++ ) {
(*cur)->elaborate(des, scope);
}
@@ -3676,6 +3801,82 @@ struct root_elem {
NetScope *scope;
};
class elaborate_root_scope_t : public elaborator_work_item_t {
public:
elaborate_root_scope_t(Design*des, NetScope*scope, Module*rmod)
: elaborator_work_item_t(des), scope_(scope), rmod_(rmod)
{ }
~elaborate_root_scope_t() { }
virtual void elaborate_runrun()
{
Module::replace_t stub;
if (! rmod_->elaborate_scope(des, scope_, stub))
des->errors += 1;
}
private:
NetScope*scope_;
Module*rmod_;
};
class top_defparams : public elaborator_work_item_t {
public:
top_defparams(Design*des)
: elaborator_work_item_t(des)
{ }
~top_defparams() { }
virtual void elaborate_runrun()
{
// This method recurses through the scopes, looking for
// defparam assignments to apply to the parameters in the
// various scopes. This needs to be done after all the scopes
// and basic parameters are taken care of because the defparam
// can assign to a parameter declared *after* it.
des->run_defparams();
// At this point, all parameter overrides are done. Scan the
// scopes and evaluate the parameters all the way down to
// constants.
des->evaluate_parameters();
}
};
class later_defparams : public elaborator_work_item_t {
public:
later_defparams(Design*des)
: elaborator_work_item_t(des)
{ }
~later_defparams() { }
virtual void elaborate_runrun()
{
list<NetScope*>tmp_list;
for (set<NetScope*>::iterator cur = des->defparams_later.begin()
; cur != des->defparams_later.end() ; cur ++ )
tmp_list.push_back(*cur);
des->defparams_later.clear();
while (! tmp_list.empty()) {
NetScope*cur = tmp_list.front();
tmp_list.pop_front();
cur->run_defparams_later(des);
}
des->evaluate_parameters();
}
};
/*
* This function is the root of all elaboration. The input is the list
* of root module names. The function locates the Module definitions
* for each root, does the whole elaboration sequence, and fills in
* the resulting Design.
*/
Design* elaborate(list<perm_string>roots)
{
svector<root_elem*> root_elems(roots.size());
@@ -3686,7 +3887,7 @@ Design* elaborate(list<perm_string>roots)
// module and elaborate what I find.
Design*des = new Design;
// Scan the root modules, and elaborate their scopes.
// Scan the root modules by name, and elaborate their scopes.
for (list<perm_string>::const_iterator root = roots.begin()
; root != roots.end()
; root++) {
@@ -3705,47 +3906,74 @@ Design* elaborate(list<perm_string>roots)
// Get the module definition for this root instance.
Module *rmod = (*mod).second;
// Make the root scope.
// Make the root scope. This makes a NetScoep object and
// pushes it into the list of root scopes in the Design.
NetScope*scope = des->make_root_scope(*root);
// Collect some basic properties of this scope from the
// Module definition.
scope->set_line(rmod);
scope->time_unit(rmod->time_unit);
scope->time_precision(rmod->time_precision);
scope->default_nettype(rmod->default_nettype);
des->set_precision(rmod->time_precision);
Module::replace_t stub;
// Recursively elaborate from this root scope down. This
// does a lot of the grunt work of creating sub-scopes, etc.
if (! rmod->elaborate_scope(des, scope, stub)) {
delete des;
return 0;
}
// Save this scope, along with its defintion, in the
// "root_elems" list for later passes.
struct root_elem *r = new struct root_elem;
r->mod = rmod;
r->scope = scope;
root_elems[i++] = r;
// Arrange for these scopes to be elaborated as root
// scopes. Create an "elaborate_root_scope" object to
// contain the work item, and append it to the scope
// elaborations work list.
elaborator_work_item_t*es = new elaborate_root_scope_t(des, scope, rmod);
des->elaboration_work_list.push_back(es);
}
// After the work items for the root scope elaboration, push a
// work item to process the defparams.
des->elaboration_work_list.push_back(new top_defparams(des));
// Run the work list of scope elaborations until the list is
// empty. This list is initially populated above where the
// initial root scopes are primed.
while (! des->elaboration_work_list.empty()) {
// Transfer the queue to a temporary queue.
list<elaborator_work_item_t*> cur_queue;
while (! des->elaboration_work_list.empty()) {
cur_queue.push_back(des->elaboration_work_list.front());
des->elaboration_work_list.pop_front();
}
// Run from the temporary queue. If the temporary queue
// items create new work queue items, they will show up
// in the elaboration_work_list and then we get to run
// through them in the next pass.
while (! cur_queue.empty()) {
elaborator_work_item_t*tmp = cur_queue.front();
cur_queue.pop_front();
tmp->elaborate_runrun();
delete tmp;
}
if (! des->elaboration_work_list.empty()) {
des->elaboration_work_list.push_back(new later_defparams(des));
}
}
// Look for residual defparams (that point to a non-existent
// scope) and clean them out.
des->residual_defparams();
// Errors already? Probably missing root modules. Just give up
// now and return nothing.
if (des->errors > 0)
return des;
// This method recurses through the scopes, looking for
// defparam assignments to apply to the parameters in the
// various scopes. This needs to be done after all the scopes
// and basic parameters are taken care of because the defparam
// can assign to a parameter declared *after* it.
des->run_defparams();
// At this point, all parameter overrides are done. Scan the
// scopes and evaluate the parameters all the way down to
// constants.
des->evaluate_parameters();
// With the parameters evaluated down to constants, we have
// what we need to elaborate signals and memories. This pass
// creates all the NetNet and NetMemory objects for declared
+16 -1
View File
@@ -72,6 +72,16 @@ bool NetCaseCmp::emit_node(struct target_t*tgt) const
return true;
}
bool NetCastInt::emit_node(struct target_t*tgt) const
{
return tgt->lpm_cast_int(this);
}
bool NetCastReal::emit_node(struct target_t*tgt) const
{
return tgt->lpm_cast_real(this);
}
bool NetCLShift::emit_node(struct target_t*tgt) const
{
tgt->lpm_clshift(this);
@@ -165,6 +175,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);
@@ -357,7 +372,7 @@ void NetScope::emit_scope(struct target_t*tgt) const
/* Run the signals again, but this time to connect the
delay paths. This is done as a second pass because
the paths reference other signals that may be later
in the list. We can do it here becase delay paths are
in the list. We can do it here because delay paths are
always connected within the scope. */
cur = signals_->sig_next_;
do {
+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;
}
+1 -1
View File
@@ -154,7 +154,7 @@
*
* The POST_MAP compiler directive causes the GSR manipulations
* included in the test bench to be compiled in, to simulate the chip
* startup. Other then that, the test bench runs the post-map design
* startup. Other than that, the test bench runs the post-map design
* the same way the pre-synthesis design works.
*
* Run this design with the command:
+1 -1
View File
@@ -459,7 +459,7 @@ NetNet* NetEBDiv::synthesize(Design*des)
default: {
cerr << get_fileline() << ": internal error: "
<< "NetEBDiv has unexpeced op() code: "
<< "NetEBDiv has unexpected op() code: "
<< op() << endl;
des->errors += 1;
+21
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
@@ -185,6 +191,8 @@ ivl_path_source
ivl_process_attr_cnt
ivl_process_attr_val
ivl_process_file
ivl_process_lineno
ivl_process_scope
ivl_process_stmt
ivl_process_type
@@ -216,6 +224,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
+89 -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,11 +238,24 @@ 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,
IVL_LPM_ADD = 0,
IVL_LPM_ARRAY = 30,
IVL_LPM_CAST_INT = 34,
IVL_LPM_CAST_REAL = 33,
IVL_LPM_CONCAT = 16,
IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */
IVL_LPM_CMP_EQ = 10,
@@ -243,7 +268,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 +724,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 +1348,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 +1537,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);
@@ -1657,6 +1695,9 @@ extern ivl_statement_t ivl_process_stmt(ivl_process_t net);
extern unsigned ivl_process_attr_cnt(ivl_process_t net);
extern ivl_attribute_t ivl_process_attr_val(ivl_process_t net, unsigned idx);
extern const char* ivl_process_file(ivl_process_t net);
extern unsigned ivl_process_lineno(ivl_process_t net);
/*
* These functions manage statements of various type. This includes
* all the different kinds of statements (as enumerated in
@@ -1826,6 +1867,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
+15 -6
View File
@@ -115,7 +115,7 @@ static void ifdef_enter(void)
struct ifdef_stack_t*cur;
cur = (struct ifdef_stack_t*) calloc(1, sizeof(struct ifdef_stack_t));
cur->path = strdup(istack->path);
if (istack->path) cur->path = strdup(istack->path);
cur->lineno = istack->lineno;
cur->next = ifdef_stack;
@@ -131,8 +131,10 @@ static void ifdef_leave(void)
cur = ifdef_stack;
ifdef_stack = cur->next;
if (strcmp(istack->path,cur->path) != 0)
{
/* If either path is from a non-file context e.g.(macro expansion)
* we assume that the non-file part is from this file. */
if (istack->path != NULL && cur->path != NULL &&
strcmp(istack->path,cur->path) != 0) {
fprintf
(
stderr,
@@ -856,6 +858,7 @@ static int define_continue_flag = 0;
static char *find_arg(char*ptr, char*head, char*arg)
{
char *cp = ptr;
size_t len = strlen(arg);
while (1) {
/* Look for a candidate match, just return if none is found. */
@@ -866,7 +869,8 @@ static char *find_arg(char*ptr, char*head, char*arg)
* match is not in the middle of another identifier.
*/
if (cp != head &&
(isalnum(*(cp-1)) || *(cp-1) == '_' || *(cp-1) == '$')) {
(isalnum(*(cp-1)) || *(cp-1) == '_' || *(cp-1) == '$' ||
isalnum(*(cp+len)) || *(cp+len) == '_' || *(cp+len) == '$')) {
cp++;
continue;
}
@@ -941,7 +945,7 @@ static void do_define()
}
/* Detect the continuation sequence. If I find it, remove it
* and the white space that preceeds it, then replace all that
* and the white space that precedes it, then replace all that
* with a single newline.
*/
if ((cp > yytext) && (cp[-1] == '\\'))
@@ -1468,7 +1472,7 @@ static void do_include()
fprintf(depend_file, "%s\n", standby->path);
if (line_direct_flag)
fprintf(yyout, "\n`line %u \"%s\" 1\n", istack->lineno+1, standby->path);
fprintf(yyout, "\n`line 1 \"%s\" 1\n", standby->path);
standby->next = istack;
standby->stringify_flag = 0;
@@ -1616,7 +1620,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 +1749,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;
+15 -1
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;
}
@@ -829,7 +843,7 @@ static verinum*make_unsized_dec(const char*ptr)
if (ptr[0] == '\'') {
/* The number has decorations of the form 'sd<digits>,
possibly with space between the d and the <digits>.
Also, the 's' is optional, and markes the number as
Also, the 's' is optional, and marks the number as
signed. */
ptr += 1;
+21
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
@@ -22,6 +25,7 @@ assign, GN_KEYWORDS_1364_1995, K_assign
atan, GN_KEYWORDS_VAMS_2_3, K_atan
atan2, GN_KEYWORDS_VAMS_2_3, K_atan2
atanh, GN_KEYWORDS_VAMS_2_3, K_atanh
automatic, GN_KEYWORDS_1364_2001, K_automatic
begin, GN_KEYWORDS_1364_1995, K_begin
bool, GN_KEYWORDS_ICARUS, K_bool
buf, GN_KEYWORDS_1364_1995, K_buf
@@ -32,38 +36,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 +97,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 +109,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 +135,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 +154,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
+63 -9
View File
@@ -54,9 +54,11 @@ const char NOTICE[] =
#endif
# include "pform.h"
# include "parse_api.h"
# include "PGenerate.h"
# 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 +125,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.
*/
@@ -269,6 +273,9 @@ static void parm_to_flagmap(const string&flag)
flags[key] = value;
}
static void find_module_mention(map<perm_string,bool>&check_map, Module*m);
static void find_module_mention(map<perm_string,bool>&check_map, PGenerate*s);
/*
* Read the contents of a config file. This file is a temporary
* configuration file made by the compiler driver to carry the bulky
@@ -390,6 +397,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 +693,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()
@@ -713,15 +733,7 @@ int main(int argc, char*argv[])
for (mod = pform_modules.begin()
; mod != pform_modules.end()
; mod++) {
list<PGate*> gates = (*mod).second->get_gates();
list<PGate*>::const_iterator gate;
for (gate = gates.begin(); gate != gates.end(); gate++) {
PGModule *mod = dynamic_cast<PGModule*>(*gate);
if (mod) {
// Note that this module has been instantiated
mentioned_p[mod->get_type()] = true;
}
}
find_module_mention(mentioned_p, mod->second);
}
for (mod = pform_modules.begin()
@@ -809,6 +821,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;
@@ -886,3 +903,40 @@ int main(int argc, char*argv[])
return des? des->errors : 1;
}
static void find_module_mention(map<perm_string,bool>&check_map, Module*mod)
{
list<PGate*> gates = mod->get_gates();
list<PGate*>::const_iterator gate;
for (gate = gates.begin(); gate != gates.end(); gate++) {
PGModule*tmp = dynamic_cast<PGModule*>(*gate);
if (tmp) {
// Note that this module has been instantiated
check_map[tmp->get_type()] = true;
}
}
list<PGenerate*>::const_iterator cur;
for (cur = mod->generate_schemes.begin()
; cur != mod->generate_schemes.end() ; cur ++) {
find_module_mention(check_map, *cur);
}
}
static void find_module_mention(map<perm_string,bool>&check_map, PGenerate*schm)
{
list<PGate*>::const_iterator gate;
for (gate = schm->gates.begin(); gate != schm->gates.end(); gate++) {
PGModule*tmp = dynamic_cast<PGModule*>(*gate);
if (tmp) {
// Note that this module has been instantiated
check_map[tmp->get_type()] = true;
}
}
list<PGenerate*>::const_iterator cur;
for (cur = schm->generate_schemes.begin()
; cur != schm->generate_schemes.end() ; cur ++) {
find_module_mention(check_map, *cur);
}
}
+398 -154
View File
@@ -20,6 +20,8 @@
# include "config.h"
# include <iostream>
# include <set>
# include <cstdlib>
/*
* This source file contains all the implementations of the Design
@@ -31,6 +33,7 @@
# include "compiler.h"
# include "netmisc.h"
# include <sstream>
# include "ivl_assert.h"
Design:: Design()
: errors(0), nodes_(0), procs_(0), lcounter_(0)
@@ -206,10 +209,12 @@ void NetScope::run_defparams(Design*des)
}
}
map<pform_name_t,NetExpr*>::const_iterator pp;
for (pp = defparams.begin() ; pp != defparams.end() ; pp ++ ) {
NetExpr*val = (*pp).second;
pform_name_t path = (*pp).first;
while (! defparams.empty()) {
pair<pform_name_t,NetExpr*> pp = defparams.front();
defparams.pop_front();
pform_name_t path = pp.first;
NetExpr*val = pp.second;
perm_string perm_name = peek_tail_name(path);
path.pop_back();
@@ -220,11 +225,20 @@ void NetScope::run_defparams(Design*des)
is the current scope. */
NetScope*targ_scope = des->find_scope(this, eval_path);
if (targ_scope == 0) {
cerr << val->get_fileline() << ": warning: scope of " <<
path << "." << perm_name << " not found." << endl;
// Push the defparam onto a list for retry
// later. It is possible for the scope lookup to
// fail if the scope being defparam'd into is
// generated by an index array for generate.
eval_path.push_back(hname_t(perm_name));
defparams_later.push_back(make_pair(eval_path,val));
continue;
}
// Once placed in the parameter map, the expression may
// be deleted when evaluated, so give it a copy of this
// expression, not the original.
val = val->dup_expr();
bool flag = targ_scope->replace_parameter(perm_name, val);
if (! flag) {
cerr << val->get_fileline() << ": warning: parameter "
@@ -233,6 +247,66 @@ void NetScope::run_defparams(Design*des)
}
}
// If some of the defparams didn't find a scope in the name,
// then try again later. It may be that the target scope is
// created later by generate scheme or instance array.
if (! defparams_later.empty())
des->defparams_later.insert(this);
}
void NetScope::run_defparams_later(Design*des)
{
set<NetScope*> target_scopes;
list<pair<list<hname_t>,NetExpr*> > defparams_even_later;
while (! defparams_later.empty()) {
pair<list<hname_t>,NetExpr*> cur = defparams_later.front();
defparams_later.pop_front();
list<hname_t>eval_path = cur.first;
perm_string name = eval_path.back().peek_name();
eval_path.pop_back();
NetExpr*val = cur.second;
NetScope*targ_scope = des->find_scope(this, eval_path);
if (targ_scope == 0) {
// If a scope in the target path is not found,
// then push this defparam for handling even
// later. Maybe a later generate scheme or
// instance array will create the scope.
defparams_even_later.push_back(cur);
continue;
}
// Once placed in the parameter map, the expression may
// be deleted when evaluated, so give it a copy of this
// expression, not the original.
val = val->dup_expr();
bool flag = targ_scope->replace_parameter(name, val);
if (! flag) {
cerr << val->get_fileline() << ": warning: parameter "
<< name << " not found in "
<< scope_path(targ_scope) << "." << endl;
}
// We'll need to re-evaluate parameters in this scope
target_scopes.insert(targ_scope);
}
// All the scopes that this defparam set touched should have
// their parameters re-evaluated.
for (set<NetScope*>::iterator cur = target_scopes.begin()
; cur != target_scopes.end() ; cur ++ )
(*cur)->evaluate_parameters(des);
// If there are some scopes that still have missing scopes,
// then sav them back into the defparams_later list for a
// later pass.
defparams_later = defparams_even_later;
if (! defparams_later.empty())
des->defparams_later.insert(this);
}
void Design::evaluate_parameters()
@@ -242,6 +316,268 @@ 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;
if (expr == NULL) return; // This is an invalid parameter so return.
eval_expr(expr);
/* The eval_expr may delete and 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;
/* If we have a real value convert it to an integer. */
if(NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
verinum nval(tmp->value().as_long64());
expr = new NetEConst(nval);
expr->set_line(*((*cur).second.expr));
(*cur).second.expr = expr;
}
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);
(*cur).second.expr = 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_;
@@ -250,172 +586,69 @@ void NetScope::evaluate_parameters(Design*des)
cur = cur->sib_;
}
if (debug_scopes)
cerr << ":0" << ": debug: "
<< "Evaluate parameters in " << scope_path(this) << endl;
// Evaluate the parameter values. The parameter expressions
// have already been elaborated and replaced by the scope
// 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;
}
}
}
void Design::residual_defparams()
{
for (list<NetScope*>::const_iterator scope = root_scopes_.begin();
scope != root_scopes_.end(); scope++)
(*scope)->residual_defparams(this);
}
void NetScope::residual_defparams(Design*des)
{
// Clean out the list of defparams that never managed to match
// a scope. Print a warning for each.
while (! defparams_later.empty()) {
pair<list<hname_t>,NetExpr*> cur = defparams_later.front();
defparams_later.pop_front();
cerr << cur.second->get_fileline() << ": warning: "
<< "Scope of " << cur.first << " not found." << endl;
}
NetScope*cur = sub_;
while (cur) {
cur->residual_defparams(des);
cur = cur->sib_;
}
}
const char* Design::get_flag(const string&key) const
{
map<string,const char*>::const_iterator tmp = flags_.find(key);
@@ -553,3 +786,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;
}
+35
View File
@@ -247,6 +247,41 @@ verinum::V Nexus::get_init() const
return verinum::Vz;
}
bool Nexus::drivers_present() const
{
assert(list_);
for (Link*cur = list_ ; cur ; cur = cur->next_) {
if (cur->get_dir() == Link::OUTPUT)
return true;
if (cur->get_dir() == Link::INPUT)
continue;
// Must be PASSIVE, so if it is some kind of net, see if
// it is the sort that might drive the nexus.
const NetObj*obj;
unsigned pin;
cur->cur_link(obj, pin);
if (const NetNet*net = dynamic_cast<const NetNet*>(obj))
switch (net->type()) {
case NetNet::SUPPLY0:
case NetNet::SUPPLY1:
case NetNet::TRI0:
case NetNet::TRI1:
case NetNet::WAND:
case NetNet::WOR:
case NetNet::TRIAND:
case NetNet::TRIOR:
case NetNet::REG:
return true;
default:
break;
}
}
return false;
}
void Nexus::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay)
{
for (Link*cur = list_ ; cur ; cur = cur->next_) {
+10 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2007 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
@@ -53,8 +53,13 @@ NexusSet* NetEBinary::nex_input(bool rem_out)
NexusSet* NetEConcat::nex_input(bool rem_out)
{
if (parms_[0] == NULL) return NULL;
NexusSet*result = parms_[0]->nex_input(rem_out);
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
if (parms_[idx] == NULL) {
delete result;
return NULL;
}
NexusSet*tmp = parms_[idx]->nex_input(rem_out);
result->add(*tmp);
delete tmp;
@@ -98,6 +103,10 @@ NexusSet* NetESelect::nex_input(bool rem_out)
{
NexusSet*result = base_? base_->nex_input(rem_out) : new NexusSet();
NexusSet*tmp = expr_->nex_input(rem_out);
if (tmp == NULL) {
delete result;
return NULL;
}
result->add(*tmp);
delete tmp;
return result;
@@ -381,4 +390,3 @@ NexusSet* NetWhile::nex_input(bool rem_out)
delete tmp;
return result;
}
+30 -8
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;
}
@@ -157,10 +166,10 @@ bool NetScope::replace_parameter(perm_string key, NetExpr*expr)
/*
* This is not really complete (msb, lsb, sign). It is currently only
* used to add a genver to the local parameter list.
* used to add a genvar 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
{
@@ -253,7 +275,7 @@ const NetFuncDef* NetScope::func_def() const
void NetScope::set_module_name(perm_string n)
{
assert(type_ == MODULE);
module_name_ = n; /* NOTE: n mus have been permallocated. */
module_name_ = n; /* NOTE: n must have been permallocated. */
}
perm_string NetScope::module_name() 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 that 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 branch 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 island 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);
}
}
+23 -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);
@@ -857,6 +849,24 @@ const NetScope* NetProcTop::scope() const
return scope_;
}
NetCastInt::NetCastInt(NetScope*scope, perm_string n, unsigned width)
: NetNode(scope, n, 2), width_(width)
{
pin(0).set_dir(Link::OUTPUT);
pin(0).set_name(perm_string::literal("O"), 0);
pin(1).set_dir(Link::INPUT);
pin(1).set_name(perm_string::literal("I"), 0);
}
NetCastReal::NetCastReal(NetScope*scope, perm_string n, bool signed_flag)
: NetNode(scope, n, 2), signed_flag_(signed_flag)
{
pin(0).set_dir(Link::OUTPUT);
pin(0).set_name(perm_string::literal("O"), 0);
pin(1).set_dir(Link::INPUT);
pin(1).set_name(perm_string::literal("I"), 0);
}
NetConcat::NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt)
: NetNode(scope, n, cnt+1), width_(wid)
{
@@ -1504,6 +1514,11 @@ NetLiteral::~NetLiteral()
{
}
ivl_variable_type_t NetLiteral::data_type() const
{
return IVL_VT_REAL;
}
const verireal& NetLiteral::value_real() const
{
return real_;
+356 -206
View File
@@ -29,6 +29,8 @@
# include <map>
# include <list>
# include <vector>
# include <set>
# include <utility>
# include "ivl_target.h"
# include "pform_types.h"
# include "config.h"
@@ -49,8 +51,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 +64,7 @@ class NetExpr;
class NetESignal;
class NetFuncDef;
class NetRamDq;
class NetTaskDef;
class NetEvTrig;
class NetEvWait;
@@ -69,6 +74,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 +136,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&);
@@ -269,6 +290,10 @@ class Nexus {
NetNet* pick_any_net();
/* This method returns true if there are any drivers
(including variables) attached to this nexus. */
bool drivers_present() const;
/* This method returns true if all the possible drivers of
this nexus are constant. It will also return true if there
are no drivers at all. */
@@ -578,9 +603,243 @@ 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 run_defparams_later(class Design*);
void evaluate_parameters(class Design*);
// Look for defparams that never matched, and print warnings.
void residual_defparams(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. */
list<pair<pform_name_t,NetExpr*> > defparams;
list<pair<list<hname_t>,NetExpr*> > defparams_later;
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
* input, a signed expression, that it converts to the absolute
* value. The gate is simple: pin(0) is the output and pin(1) is the input.
*/
class NetAbs : public NetNode {
@@ -669,6 +928,44 @@ class NetArrayDq : public NetNode {
};
/*
* Convert an IVL_VT_REAL input to a logical value with the
* given width. The input is pin(1) and the output is pin(0).
*/
class NetCastInt : public NetNode {
public:
NetCastInt(NetScope*s, perm_string n, unsigned width);
unsigned width() const { return width_; }
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
unsigned width_;
};
/*
* Convert an input to IVL_VT_REAL. The input is pin(1), which can be
* any vector type (VT_BOOL or VT_LOGIC) and the output is pin(0),
* which is IVL_VT_REAL. The conversion interprets the input as an
* unsigned value unless the signed_flag is true.
*/
class NetCastReal : public NetNode {
public:
NetCastReal(NetScope*s, perm_string n, bool signed_flag);
bool signed_flag() const { return signed_flag_; }
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
bool signed_flag_;
};
/*
* This type represents the LPM_CLSHIFT device.
*/
@@ -1129,6 +1426,33 @@ class NetSysFunc : public NetNode {
const struct sfunc_return_type*def_;
};
class NetTran : public NetNode, public IslandBranch {
public:
// Tran devices other than 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 +1667,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 +1678,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 +1685,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 +3326,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 +3335,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);
};
@@ -3286,205 +3610,17 @@ class NetESignal : public NetExpr {
NetExpr*word_;
};
/*
* 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.
* The Design object keeps a list of work items for processing
* elaboration. This is the type of those work items.
*/
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_;
struct elaborator_work_item_t {
explicit elaborator_work_item_t(Design*d)
: des(d) { }
virtual ~elaborator_work_item_t() { }
virtual void elaborate_runrun() =0;
protected:
Design*des;
};
/*
@@ -3535,10 +3671,23 @@ class Design {
NetScope* find_scope(NetScope*, const std::list<hname_t>&path,
NetScope::TYPE type = NetScope::MODULE) const;
/* These members help manage elaboration of scopes. When we
get to a point in scope elaboration where we want to put
off a scope elaboration, an object of scope_elaboration_t
is pushed onto the scope_elaborations list. The scope
elaborator will go through this list elaborating scopes
until the list is empty. */
list<elaborator_work_item_t*>elaboration_work_list;
void run_elaboration_work(void);
set<NetScope*> defparams_later;
// PARAMETERS
void run_defparams();
void evaluate_parameters();
// Look for defparams that never matched, and print warnings.
void residual_defparams();
/* This method locates a signal, starting at a given
scope. The name parameter may be partially hierarchical, so
@@ -3564,6 +3713,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
+114 -24
View File
@@ -76,6 +76,46 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val)
#endif
}
NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid)
{
if (src->data_type() != IVL_VT_REAL)
return src;
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid);
tmp->data_type(IVL_VT_LOGIC);
tmp->set_line(*src);
tmp->local_flag(true);
NetCastInt*cast = new NetCastInt(scope, scope->local_symbol(), wid);
cast->set_line(*src);
des->add_node(cast);
connect(cast->pin(0), tmp->pin(0));
connect(cast->pin(1), src->pin(0));
return tmp;
}
NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
{
if (src->data_type() == IVL_VT_REAL)
return src;
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE);
tmp->data_type(IVL_VT_REAL);
tmp->set_line(*src);
tmp->local_flag(true);
NetCastReal*cast = new NetCastReal(scope, scope->local_symbol(), src->get_signed());
cast->set_line(*src);
des->add_node(cast);
connect(cast->pin(0), tmp->pin(0));
connect(cast->pin(1), src->pin(0));
return tmp;
}
/*
* Add a signed constant to an existing expression. Generate a new
* NetEBAdd node that has the input expression and an expression made
@@ -123,6 +163,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 +229,72 @@ 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;
}
/*
* At the parser level, a name component it a name with a collection
* of expressions. For example foo[N] is the name "foo" and the index
* expression "N". This function takes as input the name component and
* returns the path component name. It will evaulate the index
* expression if it is present.
*/
hname_t eval_path_component(Design*des, NetScope*scope,
const name_component_t&comp)
{
// No index exression, so the path component is an undecorated
// name, for example "foo".
if (comp.index.empty())
return hname_t(comp.name);
// The parser will assure that path components will have only
// one index. For example, foo[N] is one index, foo[n][m] is two.
assert(comp.index.size() == 1);
const index_component_t&index = comp.index.front();
// The parser will assure that path components will have only
// bit select index expressions. For example, "foo[n]" is OK,
// but "foo[n:m]" is not.
assert(index.sel == index_component_t::SEL_BIT);
// Evaluate the bit select to get a number.
NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1);
ivl_assert(*index.msb, tmp);
// Now we should have a constant value for the bit select
// expression, and we can use it to make the final hname_t
// value, for example "foo[5]".
if (NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp)) {
hname_t res(comp.name, ctmp->value().as_long());
delete ctmp;
return res;
}
// Darn, the expression doesn't evaluate to a constant. That's
// and error to be reported. And make up a fake index value to
// return to the caller.
cerr << index.msb->get_fileline() << ": error: "
<< "Scope index expression is not constant: "
<< *index.msb << endl;
des->errors += 1;
delete tmp;
return hname_t (comp.name, 0);
}
std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
const pform_name_t&path)
{
@@ -191,30 +304,7 @@ std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
for (pform_path_it cur = path.begin() ; cur != path.end(); cur++) {
const name_component_t&comp = *cur;
if (comp.index.empty()) {
res.push_back(hname_t(comp.name));
continue;
}
assert(comp.index.size() == 1);
const index_component_t&index = comp.index.front();
assert(index.sel == index_component_t::SEL_BIT);
NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1);
ivl_assert(*index.msb, tmp);
if (NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp)) {
res.push_back(hname_t(comp.name, ctmp->value().as_long()));
delete ctmp;
continue;
} else {
cerr << index.msb->get_fileline() << ": error: "
<< "Scope index expression is not constant: "
<< *index.msb << endl;
des->errors += 1;
}
return res;
res.push_back( eval_path_component(des,scope,comp) );
}
return res;
+23
View File
@@ -64,6 +64,13 @@ extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w);
extern NetNet*pad_to_width_signed(Design*des, NetNet*n, unsigned w);
/*
* Generate the nodes necessary to cast an expression (a net) to a
* real value.
*/
extern NetNet*cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid);
extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src);
/*
* Take the input expression and return a variation that assures that
* the expression is 1-bit wide and logical. This reflects the needs
@@ -102,6 +109,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,7 +150,18 @@ 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);
/*
* Evaluate the component of a scope path to get an hname_t value. Do
* the evaluation in the context of the given scope.
*/
extern hname_t eval_path_component(Design*des, NetScope*scope,
const name_component_t&comp);
/*
* Evaluate an entire scope path in the context of the given scope.
*/
extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
const pform_name_t&path);
+518 -178
View File
File diff suppressed because it is too large Load Diff
+11 -8
View File
@@ -30,6 +30,15 @@ unsigned error_count = 0;
unsigned warn_count = 0;
unsigned long based_size = 0;
std::ostream& operator << (std::ostream&o, const YYLTYPE&loc)
{
if (loc.text)
o << loc.text << ":";
o << loc.first_line;
return o;
}
void VLerror(const char*msg)
{
error_count += 1;
@@ -39,20 +48,14 @@ void VLerror(const char*msg)
void VLerror(const YYLTYPE&loc, const char*msg)
{
error_count += 1;
if (loc.text)
cerr << loc.text << ":";
cerr << loc.first_line << ": " << msg << endl;
cerr << loc << ": " << msg << endl;
based_size = 0; /* Clear the base information if we have an error. */
}
void yywarn(const YYLTYPE&loc, const char*msg)
{
warn_count += 1;
if (loc.text)
cerr << loc.text << ":";
cerr << loc.first_line << ": warning: " << msg << endl;
cerr << loc << ": warning: " << msg << endl;
}
int VLwrap()
+11
View File
@@ -23,6 +23,8 @@
#endif
# include <list>
# include <ostream>
# include "compiler.h"
# include "pform.h"
/*
@@ -39,6 +41,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
@@ -54,6 +63,8 @@ extern void VLerror(const YYLTYPE&loc, const char*msg);
#define yywarn VLwarn
extern void VLwarn(const YYLTYPE&loc, const char*msg);
extern ostream& operator << (ostream&, const YYLTYPE&loc);
extern unsigned error_count, warn_count;
extern unsigned long based_size;
+136 -75
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
@@ -99,54 +93,103 @@ static PScope* lexical_scope = 0;
void pform_pop_scope()
{
lexical_scope = lexical_scope->pscope_parent();
if (pform_cur_generate) {
assert(pform_cur_generate->lexical_scope);
PScope*cur = pform_cur_generate->lexical_scope;
pform_cur_generate->lexical_scope = cur->pscope_parent();
} else {
assert(lexical_scope);
lexical_scope = lexical_scope->pscope_parent();
}
}
PTask* pform_push_task_scope(char*name)
{
perm_string task_name = lex_strings.make(name);
PTask*task = new PTask(task_name, pform_cur_module);
// Add the task to the current module
pform_cur_module->add_task(task->pscope_name(), task);
// Make this the current lexical scope
lexical_scope = task;
PTask*task;
if (pform_cur_generate) {
task = new PTask(task_name, pform_cur_generate->lexical_scope);
pform_cur_generate->tasks[task->pscope_name()] = task;
pform_cur_generate->lexical_scope = task;
} else {
task = new PTask(task_name, lexical_scope);
pform_cur_module->tasks[task->pscope_name()] = task;
lexical_scope = task;
}
return task;
}
PFunction* pform_push_function_scope(char*name)
{
perm_string func_name = lex_strings.make(name);
PFunction*func = new PFunction(func_name, lexical_scope);
// Add the task to the current module
pform_cur_module->add_function(func->pscope_name(), func);
// Make this the current lexical scope
lexical_scope = func;
PFunction*func;
if (pform_cur_generate) {
func = new PFunction(func_name, pform_cur_generate->lexical_scope);
pform_cur_generate->funcs[func->pscope_name()] = func;
pform_cur_generate->lexical_scope = func;
} else {
func = new PFunction(func_name, lexical_scope);
pform_cur_module->funcs[func->pscope_name()] = func;
lexical_scope = func;
}
return func;
}
PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
{
perm_string block_name = lex_strings.make(name);
PBlock*block = new PBlock(block_name, lexical_scope, bt);
// Make this the current lexical scope
lexical_scope = block;
PBlock*block;
if (pform_cur_generate) {
block = new PBlock(block_name, pform_cur_generate->lexical_scope, bt);
pform_cur_generate->lexical_scope = block;
} else {
block = new PBlock(block_name, lexical_scope, bt);
lexical_scope = block;
}
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
cannot be within sub-scopes. Only directly in
modules. */
if (pform_cur_generate)
return pform_cur_generate->get_wire(name);
if (pform_cur_generate->lexical_scope)
return pform_cur_generate->lexical_scope->wires_find(name);
else
return pform_cur_generate->wires_find(name);
else
return lexical_scope->wires_find(name);
}
return lexical_scope->wires_find(name);
static void pform_put_wire_in_scope(perm_string name, PWire*net)
{
if (pform_cur_generate)
if (pform_cur_generate->lexical_scope)
pform_cur_generate->lexical_scope->wires[name] = net;
else
pform_cur_generate->wires[name] = net;
else
lexical_scope->wires[name] = net;
}
static void pform_put_behavior_in_scope(PProcess*pp)
{
if (pform_cur_generate)
if (pform_cur_generate->lexical_scope)
pform_cur_generate->lexical_scope->behaviors.push_back(pp);
else
pform_cur_generate->behaviors.push_back(pp);
else
lexical_scope->behaviors.push_back(pp);
}
void pform_set_default_nettype(NetNet::Type type,
@@ -514,7 +557,7 @@ void pform_endgenerate()
if (pform_cur_generate != 0) {
assert(cur->scheme_type == PGenerate::GS_CASE_ITEM
|| pform_cur_generate->scheme_type != PGenerate::GS_CASE);
pform_cur_generate->generates.push_back(cur);
pform_cur_generate->generate_schemes.push_back(cur);
} else {
assert(cur->scheme_type != PGenerate::GS_CASE_ITEM);
pform_cur_module->generate_schemes.push_back(cur);
@@ -925,7 +968,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;
@@ -1242,7 +1285,7 @@ void pform_make_pgassign_list(svector<PExpr*>*alist,
void pform_make_reginit(const struct vlltype&li,
perm_string name, PExpr*expr)
{
PWire*cur = lexical_scope->wires_find(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
VLerror(li, "internal error: reginit to non-register?");
delete expr;
@@ -1256,7 +1299,7 @@ void pform_make_reginit(const struct vlltype&li,
PProcess*top = new PProcess(PProcess::PR_INITIAL, ass);
FILE_NAME(top, li);
lexical_scope->behaviors.push_back(top);
pform_put_behavior_in_scope(top);
}
/*
@@ -1277,7 +1320,7 @@ void pform_module_define_port(const struct vlltype&li,
svector<PExpr*>*range,
svector<named_pexpr_t*>*attr)
{
PWire*cur = lexical_scope->wires_find(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur) {
ostringstream msg;
msg << name << " definition conflicts with "
@@ -1311,7 +1354,7 @@ void pform_module_define_port(const struct vlltype&li,
cur->attributes[tmp->name] = tmp->parm;
}
}
lexical_scope->wires[name] = cur;
pform_put_wire_in_scope(name, cur);
}
/*
@@ -1344,7 +1387,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.
@@ -1394,12 +1437,8 @@ void pform_makewire(const vlltype&li, perm_string name,
}
}
if (new_wire_flag) {
if (pform_cur_generate)
pform_cur_generate->wires[name] = cur;
else
lexical_scope->wires[name] = cur;
}
if (new_wire_flag)
pform_put_wire_in_scope(name, cur);
}
/*
@@ -1458,7 +1497,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);
@@ -1475,11 +1514,11 @@ void pform_makewire(const vlltype&li,
void pform_set_port_type(perm_string name, NetNet::PortType pt,
const char*file, unsigned lineno)
{
PWire*cur = lexical_scope->wires_find(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE);
FILE_NAME(cur, file, lineno);
lexical_scope->wires[name] = cur;
pform_put_wire_in_scope(name, cur);
}
switch (cur->get_port_type()) {
@@ -1561,13 +1600,13 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
/* Look for a preexisting wire. If it exists, set the
port direction. If not, create it. */
PWire*curw = lexical_scope->wires_find(name);
PWire*curw = pform_get_wire_in_scope(name);
if (curw) {
curw->set_port_type(pt);
} else {
curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype);
FILE_NAME(curw, file, lineno);
lexical_scope->wires[name] = curw;
pform_put_wire_in_scope(name, curw);
}
curw->set_signed(signed_flag);
@@ -1628,7 +1667,7 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
{
PWire*cur = 0;
if (pform_cur_generate) {
cur = pform_cur_generate->get_wire(name);
cur = pform_cur_generate->wires_find(name);
} else {
cur = lexical_scope->wires_find(name);
}
@@ -1640,50 +1679,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)
@@ -1695,7 +1760,7 @@ void pform_set_specparam(perm_string name, PExpr*expr)
void pform_set_defparam(const pform_name_t&name, PExpr*expr)
{
assert(expr);
pform_cur_module->defparms[name] = expr;
pform_cur_module->defparms.push_back(make_pair(name,expr));
}
/*
@@ -1785,13 +1850,13 @@ void pform_set_port_type(const struct vlltype&li,
static void pform_set_reg_integer(perm_string name)
{
PWire*cur = lexical_scope->wires_find(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::INTEGER,
NetNet::NOT_A_PORT,
IVL_VT_LOGIC);
cur->set_signed(true);
lexical_scope->wires[name] = cur;
pform_put_wire_in_scope(name, cur);
} else {
bool rc = cur->set_wire_type(NetNet::INTEGER);
assert(rc);
@@ -1819,10 +1884,10 @@ void pform_set_reg_integer(list<perm_string>*names)
static void pform_set_reg_time(perm_string name)
{
PWire*cur = lexical_scope->wires_find(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
lexical_scope->wires[name] = cur;
pform_put_wire_in_scope(name, cur);
} else {
bool rc = cur->set_wire_type(NetNet::REG);
assert(rc);
@@ -1881,11 +1946,7 @@ PProcess* pform_make_behavior(PProcess::Type type, Statement*st,
delete attr;
}
if (pform_cur_generate)
pform_cur_generate->add_behavior(pp);
else
pform_cur_module->behaviors.push_back(pp);
pform_put_behavior_in_scope(pp);
return pp;
}
+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);
}
}
}
+82 -10
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>";
@@ -912,8 +937,8 @@ void PGenerate::dump(ostream&out, unsigned indent) const
(*idx)->dump(out, indent+2);
}
for (list<PGenerate*>::const_iterator idx = generates.begin()
; idx != generates.end() ; idx++) {
for (list<PGenerate*>::const_iterator idx = generate_schemes.begin()
; idx != generate_schemes.end() ; idx++) {
(*idx)->dump(out, indent+2);
}
@@ -966,10 +991,9 @@ void Module::dump(ostream&out) const
}
typedef map<perm_string,param_expr_t>::const_iterator parm_iter_t;
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 +1001,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()
@@ -1014,6 +1067,7 @@ void Module::dump(ostream&out) const
<< *(*cur).second << ";" << endl;
}
typedef list<Module::named_expr_t>::const_iterator parm_hiter_t;
for (parm_hiter_t cur = defparms.begin()
; cur != defparms.end() ; cur ++) {
out << " defparam " << (*cur).first << " = ";
@@ -1035,8 +1089,8 @@ void Module::dump(ostream&out) const
// Dump the task definitions.
typedef map<perm_string,PTask*>::const_iterator task_iter_t;
for (task_iter_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++) {
for (task_iter_t cur = tasks.begin()
; cur != tasks.end() ; cur ++) {
out << " task " << (*cur).first << ";" << endl;
(*cur).second->dump(out, 6);
out << " endtask;" << endl;
@@ -1044,8 +1098,8 @@ void Module::dump(ostream&out) const
// Dump the function definitions.
typedef map<perm_string,PFunction*>::const_iterator func_iter_t;
for (func_iter_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++) {
for (func_iter_t cur = funcs.begin()
; cur != funcs.end() ; cur ++) {
out << " function " << (*cur).first << ";" << endl;
(*cur).second->dump(out, 6);
out << " endfunction;" << endl;
@@ -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;
}
+1 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2007 Stephen Williams (steve@icarus.com)
* 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
@@ -16,17 +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: pform_types.cc,v 1.1 2007/05/24 04:07:12 steve Exp $"
#endif
# include "pform_types.h"
bool operator < (const name_component_t&lef, const name_component_t&rig)
{
if (lef.name < rig.name)
return true;
return false;
}
+26 -6
View File
@@ -1,7 +1,7 @@
#ifndef __pform_types_H
#define __pform_types_H
/*
* Copyright (c) 2007 Stephen Williams (steve@icarus.com)
* 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
@@ -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: pform_types.h,v 1.2 2007/06/04 02:19:07 steve Exp $"
#endif
// This for the perm_string type.
# include "StringHeap.h"
@@ -50,13 +47,36 @@ struct name_component_t {
std::list<index_component_t>index;
};
extern bool operator < (const name_component_t&lef, const name_component_t&rig);
/*
* The pform_name_t is the general form for a hierarchical identifier.
* The pform_name_t is the general form for a hierarchical
* identifier. It is an ordered list of name components. Each name
* component is an identifier and an optional list of bit/part
* selects. The simplest name component is a simple identifier:
*
* foo
*
* The bit/part selects come from the source and are made part of the
* name component. A bit select is a single number that may be a bit
* select of a vector or a word select of an array:
*
* foo[5] -- a bit select/word index
* foo[6:4] -- a part select
*
* The index components of a name component are collected into an
* ordered list, so there may be many, for example:
*
* foo[5][6:4] -- a part select of an array word
*
* The pform_name_t, then, is an ordered list of these name
* components. The list of names comes from a hierarchical name in the
* source, like this:
*
* foo[5].bar[6:4] -- a part select of a vector in sub-scope foo[5].
*/
typedef std::list<name_component_t> pform_name_t;
inline perm_string peek_head_name(const pform_name_t&that)
{
return that.front().name;
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
# This script manually creates a version.h file.
#
# It is used when creating a MinGW executable from a Cygwin
# hosted git repository. It assumes that git is available.
#
# sh scripts/CREATE_VERSION.sh
#
echo "Building version.h with git describe"
tmp=`git describe | sed -e 's;\(.*\);#define VERSION_TAG "\1";'`
echo "$tmp" > version.h
+1 -1
View File
@@ -7,7 +7,7 @@
# sh scripts/MAKE_SNAPSHOT.sh 20080428 ~/tmp
#
# The above assumes that there is a tag "s20080428" at the point
# to be snaphot. (The tag has the "s", but the argument to this
# to be snapshot. (The tag has the "s", but the argument to this
# script does not have the "s"). This script extracts based on the
# tag, uses the temporary directory to stage intermediate results,
# and finally creates a file called verilog-20080428.tar.gz that
+23
View File
@@ -0,0 +1,23 @@
#
# This is a debug conf file that the scripts/devel-stub.sh script uses
# to control the ivl core. The contents of this file are normally written
# to a temporary file by the driver program, but for devel purposes, where
# the driver program is not used, this config substitutes.
#
# NOTE: DO NOT INSTALL THIS FILE!
#
generation:2005
generation:specify
generation:xtypes
generation:verilog-ams
iwidth:32
sys_func:vpi/system.sft
sys_func:vpi/va_math.sft
warnings:implicit
debug:eval_tree
debug:elaborate
debug:scopes
debug:synth2
out:a.out
ivlpp:./ivlpp/ivlpp -D__ICARUS__ -L -Pfoo.pp
sys_func:scripts/devel-stub.sft
+5
View File
@@ -0,0 +1,5 @@
# This is an example function table.
$realtime vpiSysFuncReal
$verywide vpiSysFuncSized 128 signed
+14
View File
@@ -0,0 +1,14 @@
# This is a little developer convenience script to run the ivl core program
# in place with the stub target. It runs the ivl core verbose, with diagnostic
# output files enable, and without the driver program or preprocessor.
# It is useful only for development of the ivl core program.
#
# Run this script in the source directory for the ivl core program so that
# the patch to the other components is correct.
#
# NOTE: DO NOT INSTALL THIS FILE.
./ivl -v -Ctgt-stub/stub.conf -C./scripts/devel-stub.conf -Pa.pf -Na.net -fDLL=tgt-stub/stub.tgt foo.vl
echo "*** ivl command completed, rc=$?"
+1 -1
View File
@@ -598,7 +598,7 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*ff,
delete expr_input;
/* Detect the case that this is a *synchronous* set/reset. It
is not asyncronous because we know the condition is not
is not asynchronous because we know the condition is not
included in the sensitivity list, but if the if_ case is
constant (has no inputs) then we can model this as a
synchronous set/reset.
+127 -12
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);
@@ -865,6 +886,8 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
assert(net);
switch (net->type) {
case IVL_LPM_ABS:
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL:
assert(idx == 0);
return net->u_.arith.a;
@@ -918,7 +941,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;
@@ -1008,20 +1030,19 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
switch (net->type) {
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_MULT:
case IVL_LPM_POW:
case IVL_LPM_SUB:
assert(idx == 0);
return net->u_.arith.q;
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL:
case IVL_LPM_CMP_GE:
case IVL_LPM_CMP_GT:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_NE:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_NEE:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_MULT:
case IVL_LPM_POW:
case IVL_LPM_SUB:
assert(idx == 0);
return net->u_.arith.q;
@@ -1061,7 +1082,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;
@@ -1125,6 +1145,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
return 0;
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_CAST_REAL:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_GE:
@@ -1147,6 +1168,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
return net->u_.shift.signed_flag;
case IVL_LPM_CAST_INT:
case IVL_LPM_SIGN_EXT: // Sign extend is always signed.
return 1;
case IVL_LPM_SFUNC:
@@ -1157,7 +1179,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 +1359,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);
@@ -1408,6 +1438,18 @@ extern int ivl_path_source_negedge(ivl_delaypath_t net)
return net->negedge ? 1 : 0;
}
extern "C" const char*ivl_process_file(ivl_process_t net)
{
assert(net);
return net->file.str();
}
extern "C" unsigned ivl_process_lineno(ivl_process_t net)
{
assert(net);
return net->lineno;
}
extern "C" ivl_process_type_t ivl_process_type(ivl_process_t net)
{
return net->type_;
@@ -1627,6 +1669,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 +2198,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;
}
+2 -5
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
@@ -17,9 +17,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: $"
#endif
# include "config.h"
@@ -50,6 +47,7 @@ bool dll_target::process(const NetProcTop*net)
default:
assert(0);
}
FILE_NAME(obj, net);
/* Save the scope of the process. */
obj->scope_ = lookup_scope_(net->scope());
@@ -745,4 +743,3 @@ void dll_target::proc_while(const NetWhile*net)
net->emit_proc_recurse(this);
stmt_cur_ = save_cur_;
}
+155 -34
View File
@@ -30,6 +30,7 @@
# include <malloc.h>
#endif
# include <stdlib.h>
# include "ivl_assert.h"
#if defined(__WIN32__)
@@ -380,6 +381,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 +445,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 +489,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 +503,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);
@@ -520,6 +539,13 @@ void dll_target::make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp)
}
if (expr_ == 0) {
cerr << etmp->get_fileline() << ": internal error: "
<< "Parameter expression not reduced to constant? "
<< *etmp << endl;
}
ivl_assert(*etmp, expr_);
cur_par->value = expr_;
expr_ = 0;
}
@@ -621,6 +647,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 +1041,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;
@@ -1475,6 +1558,71 @@ void dll_target::lpm_clshift(const NetCLShift*net)
scope_add_lpm(obj->scope, obj);
}
bool dll_target::lpm_cast_int(const NetCastInt*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_CAST_INT;
obj->name = net->name(); // NetCastInt names are permallocated
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
obj->width = net->width();
const Nexus*nex;
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->u_.arith.q = nex->t_cookie();
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->u_.arith.a = nex->t_cookie();
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
make_lpm_delays_(obj, net);
scope_add_lpm(obj->scope, obj);
return true;
}
bool dll_target::lpm_cast_real(const NetCastReal*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_CAST_REAL;
obj->name = net->name(); // NetCastReal names are permallocated
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
obj->width = 0;
obj->u_.arith.signed_flag = net->signed_flag()? 1 : 0;
const Nexus*nex;
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->u_.arith.q = nex->t_cookie();
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->u_.arith.a = nex->t_cookie();
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
make_lpm_delays_(obj, net);
scope_add_lpm(obj->scope, obj);
return true;
}
/*
* Make out of the NetCompare object an ivl_lpm_s object. The
* comparators in ivl_target do not support < or <=, but they can be
@@ -1806,7 +1954,7 @@ void dll_target::lpm_mux(const NetMux*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_MUX;
obj->name = net->name(); // The NetMux perallocates its name.
obj->name = net->name(); // The NetMux permallocates its name.
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
@@ -1930,9 +2078,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 +2131,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)
@@ -2252,8 +2374,7 @@ void dll_target::signal(const NetNet*net)
object, or creating the sigs_ array if this is the first
signal. */
obj->scope_ = find_scope(des_, net->scope());
obj->file = perm_string::literal("N/A");
obj->lineno = 0;
FILE_NAME(obj, net);
assert(obj->scope_);
if (obj->scope_->nsigs_ == 0) {
+48 -1
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,12 +69,15 @@ 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*);
void lpm_abs(const NetAbs*);
void lpm_add_sub(const NetAddSub*);
bool lpm_array_dq(const NetArrayDq*);
bool lpm_cast_int(const NetCastInt*);
bool lpm_cast_real(const NetCastReal*);
void lpm_clshift(const NetCLShift*);
void lpm_compare(const NetCompare*);
void lpm_divide(const NetDivide*);
@@ -146,6 +151,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 +451,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 +504,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.
@@ -514,7 +539,7 @@ struct ivl_parameter_s {
unsigned lineno;
};
/*
* All we know about a process it its type (initial or always) and the
* All we know about a process is its type (initial or always) and the
* single statement that is it. A process also has a scope, although
* that generally only matters for VPI calls.
*/
@@ -522,6 +547,8 @@ struct ivl_process_s {
ivl_process_type_t type_;
ivl_scope_t scope_;
ivl_statement_t stmt_;
perm_string file;
unsigned lineno;
struct ivl_attribute_s*attr;
unsigned nattr;
@@ -567,6 +594,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 +759,22 @@ 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();
}
static inline void FILE_NAME(ivl_process_t net, const LineInfo*info)
{
net->file = info->get_file();
net->lineno = info->get_lineno();
}
static inline void FILE_NAME(ivl_signal_t net, const LineInfo*info)
{
net->file = info->get_file();
net->lineno = info->get_lineno();
}
#endif
+21
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() << "): "
@@ -100,6 +107,20 @@ bool target_t::lpm_array_dq(const NetArrayDq*)
return false;
}
bool target_t::lpm_cast_int(const NetCastInt*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetCastInt." << endl;
return false;
}
bool target_t::lpm_cast_real(const NetCastReal*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetCastReal." << endl;
return false;
}
void target_t::lpm_clshift(const NetCLShift*)
{
cerr << "target (" << typeid(*this).name() << "): "
+3
View File
@@ -72,6 +72,8 @@ struct target_t {
virtual void lpm_add_sub(const NetAddSub*);
virtual bool lpm_array_dq(const NetArrayDq*);
virtual void lpm_clshift(const NetCLShift*);
virtual bool lpm_cast_int(const NetCastInt*);
virtual bool lpm_cast_real(const NetCastReal*);
virtual void lpm_compare(const NetCompare*);
virtual void lpm_divide(const NetDivide*);
virtual void lpm_modulo(const NetModulo*);
@@ -86,6 +88,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*);
+1 -1
View File
@@ -160,7 +160,7 @@ device pins are connected.
.SH EXAMPLES
.TB 8
.I COMPILING WITH XILINX FOUNDATION/iSE
.I COMPILING WITH XILINX FOUNDATION/ISE
Compile a single-file design with command line tools like so:
.nf
+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
+5
View File
@@ -178,6 +178,11 @@ void show_unary_expression(ivl_expr_t net, unsigned ind)
break;
}
if (ivl_expr_opcode(net) == '!' && ivl_expr_type(net)==IVL_VT_REAL) {
fprintf(out, "%*sERROR: Real argument to unary ! !?\n", ind,"");
stub_errors += 1;
}
fprintf(out, "%*s<unary \"%s\" width=%u, %s, type=%s>\n", ind, "",
name, width, sign, vt);
show_expression(ivl_expr_oper1(net), ind+4);
+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;
+67 -37
View File
@@ -240,6 +240,56 @@ static void show_lpm_array(ivl_lpm_t net)
}
}
static void show_lpm_cast_int(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
fprintf(out, " LPM_CAST_INT %s: <width=%u>\n",
ivl_lpm_basename(net), width);
ivl_nexus_t q = ivl_lpm_q(net,0);
ivl_nexus_t a = ivl_lpm_data(net,0);
fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0)));
fprintf(out, " A: %s\n", ivl_nexus_name(ivl_lpm_data(net,0)));
if (type_of_nexus(q) == IVL_VT_REAL) {
fprintf(out, " ERROR: Data type of Q is %s, expecting !real\n",
data_type_string(type_of_nexus(q)));
stub_errors += 1;
}
if (type_of_nexus(a) != IVL_VT_REAL) {
fprintf(out, " ERROR: Data type of A is %s, expecting real\n",
data_type_string(type_of_nexus(a)));
stub_errors += 1;
}
}
static void show_lpm_cast_real(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
fprintf(out, " LPM_CAST_REAL %s: <width=%u>\n",
ivl_lpm_basename(net), width);
ivl_nexus_t q = ivl_lpm_q(net,0);
ivl_nexus_t a = ivl_lpm_data(net,0);
fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0)));
fprintf(out, " A: %s\n", ivl_nexus_name(ivl_lpm_data(net,0)));
if (type_of_nexus(q) != IVL_VT_REAL) {
fprintf(out, " ERROR: Data type of Q is %s, expecting real\n",
data_type_string(type_of_nexus(q)));
stub_errors += 1;
}
if (type_of_nexus(a) == IVL_VT_REAL) {
fprintf(out, " ERROR: Data type of A is %s, expecting !real\n",
data_type_string(type_of_nexus(a)));
stub_errors += 1;
}
}
static void show_lpm_divide(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
@@ -555,38 +605,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.
@@ -834,6 +852,14 @@ static void show_lpm(ivl_lpm_t net)
show_lpm_array(net);
break;
case IVL_LPM_CAST_INT:
show_lpm_cast_int(net);
break;
case IVL_LPM_CAST_REAL:
show_lpm_cast_real(net);
break;
case IVL_LPM_DIVIDE:
show_lpm_divide(net);
break;
@@ -905,11 +931,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 +1080,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 +1114,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 +1505,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));
}
}
}
+92
View File
@@ -0,0 +1,92 @@
#
# This source code is free software; you can redistribute it
# and/or modify it in source code form under the terms of the GNU
# Library 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 Library General Public License for more details.
#
# You should have received a copy of the GNU Library 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
#
SHELL = /bin/sh
VERSION = 0.0
prefix = @prefix@
prefix = @prefix@
exec_prefix = @exec_prefix@
srcdir = @srcdir@
VPATH = $(srcdir)
bindir = @bindir@
libdir = @libdir@
includedir = $(prefix)/include
CXX = @CXX@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@
CXXFLAGS = -Wall @CXXFLAGS@
LDFLAGS = @LDFLAGS@
all: dep vhdl.tgt vhdl.conf
dep:
mkdir dep
%.o: %.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = vhdl.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \
stmt.o expr.o lpm.o display.o support.o cast.o logic.o
ifeq (@WIN32@,yes)
TGTLDFLAGS=-L.. -livl
TGTDEPLIBS=../libivl.a
else
TGTLDFLAGS=
TGTDEPLIBS=
endif
vhdl.tgt: $O $(TGTDEPLIBS)
$(CXX) @shared@ -o $@ $O $(TGTLDFLAGS)
Makefile: Makefile.in config.status
./config.status
clean:
rm -rf $(O) dep vhdl.tgt
distclean: clean
rm -f Makefile config.status config.log config.cache vhdl_config.h
check: all
install: all installdirs $(libdir)/ivl/vhdl.tgt $(libdir)/ivl/vhdl.conf
$(libdir)/ivl/vhdl.tgt: ./vhdl.tgt
$(INSTALL_PROGRAM) ./vhdl.tgt $(libdir)/ivl/vhdl.tgt
$(libdir)/ivl/vhdl.conf: vhdl.conf
$(INSTALL_DATA) $< $(libdir)/ivl/vhdl.conf
installdirs: ../mkinstalldirs
$(srcdir)/../mkinstalldirs $(libdir)/ivl
uninstall:
rm -f $(libdir)/ivl/vhdl.tgt $(libdir)/ivl/vhdl.conf
-include $(patsubst %.o, dep/%.d, $O)
+211
View File
@@ -0,0 +1,211 @@
/*
* Generate code to convert between VHDL types.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_syntax.hh"
#include "vhdl_target.h"
#include "support.hh"
#include <cassert>
#include <iostream>
vhdl_expr *vhdl_expr::cast(const vhdl_type *to)
{
//std::cout << "Cast: from=" << type_->get_string()
// << " (" << type_->get_width() << ") "
// << " to=" << to->get_string() << " ("
// << to->get_width() << ")" << std::endl;
if (to->get_name() == type_->get_name()) {
if (to->get_width() == type_->get_width())
return this; // Identical
else
return resize(to->get_width());
}
else if (to->get_name() == VHDL_TYPE_BOOLEAN) {
if (type_->get_name() == VHDL_TYPE_STD_LOGIC) {
// '1' is true all else are false
vhdl_const_bit *one = new vhdl_const_bit('1');
return new vhdl_binop_expr
(this, VHDL_BINOP_EQ, one, vhdl_type::boolean());
}
else if (type_->get_name() == VHDL_TYPE_UNSIGNED) {
// Need to use a support function for this conversion
require_support_function(SF_UNSIGNED_TO_BOOLEAN);
vhdl_fcall *conv =
new vhdl_fcall(support_function::function_name(SF_UNSIGNED_TO_BOOLEAN),
vhdl_type::boolean());
conv->add_expr(this);
return conv;
}
else if (type_->get_name() == VHDL_TYPE_SIGNED) {
require_support_function(SF_SIGNED_TO_BOOLEAN);
vhdl_fcall *conv =
new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_BOOLEAN),
vhdl_type::boolean());
conv->add_expr(this);
return conv;
}
else {
assert(false);
}
}
else if (to->get_name() == VHDL_TYPE_INTEGER) {
vhdl_fcall *conv;
if (type_->get_name() == VHDL_TYPE_STD_LOGIC) {
require_support_function(SF_LOGIC_TO_INTEGER);
conv = new vhdl_fcall(support_function::function_name(SF_LOGIC_TO_INTEGER),
vhdl_type::integer());
}
else
conv = new vhdl_fcall("To_Integer", new vhdl_type(*to));
conv->add_expr(this);
return conv;
}
else if ((to->get_name() == VHDL_TYPE_UNSIGNED
|| to->get_name() == VHDL_TYPE_SIGNED
|| to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) &&
type_->get_name() == VHDL_TYPE_STD_LOGIC) {
vhdl_expr *others = to->get_width() == 1 ? NULL : new vhdl_const_bit('0');
vhdl_bit_spec_expr *bs =
new vhdl_bit_spec_expr(new vhdl_type(*to), others);
bs->add_bit(0, this);
return bs;
}
else if (to->get_name() == VHDL_TYPE_STD_LOGIC &&
type_->get_name() == VHDL_TYPE_BOOLEAN) {
require_support_function(SF_BOOLEAN_TO_LOGIC);
vhdl_fcall *ah =
new vhdl_fcall(support_function::function_name(SF_BOOLEAN_TO_LOGIC),
vhdl_type::std_logic());
ah->add_expr(this);
return ah;
}
else {
// We have to cast the expression before resizing or the
// wrong sign bit may be extended (i.e. when casting between
// signed/unsigned *and* resizing)
vhdl_fcall *conv =
new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to));
conv->add_expr(this);
if (to->get_width() != type_->get_width())
return conv->resize(to->get_width());
else
return conv;
}
}
vhdl_expr *vhdl_expr::resize(int newwidth)
{
vhdl_type *rtype;
assert(type_);
if (type_->get_name() == VHDL_TYPE_SIGNED)
rtype = vhdl_type::nsigned(newwidth);
else if (type_->get_name() == VHDL_TYPE_UNSIGNED)
rtype = vhdl_type::nunsigned(newwidth);
else
return this; // Doesn't make sense to resize non-vector type
vhdl_fcall *resize = new vhdl_fcall("Resize", rtype);
resize->add_expr(this);
resize->add_expr(new vhdl_const_int(newwidth));
return resize;
}
vhdl_expr *vhdl_const_int::cast(const vhdl_type *to)
{
if (to->get_name() == VHDL_TYPE_SIGNED
|| to->get_name() == VHDL_TYPE_UNSIGNED) {
const char *fname = to->get_name() == VHDL_TYPE_SIGNED
? "To_Signed" : "To_Unsigned";
vhdl_fcall *conv = new vhdl_fcall(fname, new vhdl_type(*to));
conv->add_expr(this);
conv->add_expr(new vhdl_const_int(to->get_width()));
return conv;
}
else
return vhdl_expr::cast(to);
}
int vhdl_const_bits::bits_to_int() const
{
char msb = value_[value_.size() - 1];
int result = 0, bit;
for (int i = sizeof(int)*8 - 1; i >= 0; i--) {
if (i > (int)value_.size() - 1)
bit = msb == '1' ? 1 : 0;
else
bit = value_[i] == '1' ? 1 : 0;
result = (result << 1) | bit;
}
return result;
}
vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to)
{
if (to->get_name() == VHDL_TYPE_STD_LOGIC) {
// VHDL won't let us cast directly between a vector and
// a scalar type
// But we don't need to here as we have the bits available
// Take the least significant bit
char lsb = value_[0];
return new vhdl_const_bit(lsb);
}
else if (to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) {
// Don't need to do anything
return this;
}
else if (to->get_name() == VHDL_TYPE_SIGNED
|| to->get_name() == VHDL_TYPE_UNSIGNED) {
// Extend with sign bit
value_.resize(to->get_width(), value_[0]);
return this;
}
else if (to->get_name() == VHDL_TYPE_INTEGER)
return new vhdl_const_int(bits_to_int());
else
return vhdl_expr::cast(to);
}
vhdl_expr *vhdl_const_bit::cast(const vhdl_type *to)
{
if (to->get_name() == VHDL_TYPE_INTEGER)
return new vhdl_const_int(bit_ == '1' ? 1 : 0);
else if (to->get_name() == VHDL_TYPE_BOOLEAN)
return new vhdl_const_bool(bit_ == '1');
else
return vhdl_expr::cast(to);
}
+30
View File
@@ -0,0 +1,30 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(vhdl.cc)
AC_CONFIG_HEADER(vhdl_config.h)
dnl Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_CANONICAL_HOST
# $host
# Combined check for Microsoft-related bogosities; sets WIN32 if found
AX_WIN32
AC_CHECK_HEADERS(malloc.h stdint.h inttypes.h)
# may modify CPPFLAGS and CFLAGS
AX_CPP_PRECOMP
# Compiler option for position independent code, needed when making shared objects.
AX_C_PICFLAG
# linker options when building a shared library
AX_LD_SHAREDLIB_OPTS
AX_CPP_IDENT
AC_OUTPUT(Makefile)
+188
View File
@@ -0,0 +1,188 @@
/*
* VHDL implementation of $display.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_target.h"
#include <iostream>
#include <cstring>
#include <cassert>
#include <cctype>
#include <sstream>
static const char *DISPLAY_LINE = "Verilog_Display_Line";
/*
* Write a VHDL expression into the current display line.
*/
static void display_write(stmt_container *container, vhdl_expr *expr)
{
vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write");
vhdl_var_ref *ref =
new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
write->add_expr(ref);
vhdl_type_name_t type = expr->get_type()->get_name();
if (type == VHDL_TYPE_SIGNED || type == VHDL_TYPE_UNSIGNED) {
vhdl_type integer(VHDL_TYPE_INTEGER);
write->add_expr(expr->cast(&integer));
}
else if (type != VHDL_TYPE_STRING) {
// Need to add a call to Type'Image for types not
// supported by std.textio
std::string name(expr->get_type()->get_string());
name += "'Image";
vhdl_fcall *cast
= new vhdl_fcall(name.c_str(), vhdl_type::string());
cast->add_expr(expr);
write->add_expr(cast);
}
else
write->add_expr(expr);
container->add_stmt(write);
}
/*
* Write the value of DISPLAY_LINE to the output.
*/
static void display_line(stmt_container *container)
{
vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine");
vhdl_var_ref *output_ref =
new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE));
write_line->add_expr(output_ref);
vhdl_var_ref *ref =
new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
write_line->add_expr(ref);
container->add_stmt(write_line);
}
/*
* Parse an octal escape sequence.
*/
static char parse_octal(const char *p)
{
assert(*p && *(p+1) && *(p+2));
assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1)));
return (*p - '0') * 64
+ (*(p+1) - '0') * 8
+ (*(p+2) - '0') * 1;
}
static void flush_string(std::ostringstream &ss, stmt_container *container)
{
display_write(container, new vhdl_const_string(ss.str().c_str()));
// Clear the stream
ss.str("");
}
/*
* Generate VHDL for the $display system task.
* This is implemented using the functions in std.textio. Each
* parameter is written to a line variable in the process and
* then the line is written to the special variable `Output'
* (which represents the console). Subsequent $displays will
* use the same line variable.
*
* It's possible, although quite unlikely, that there will be
* name collision with an existing variable called
* `Verilog_Display_Line' -- do something about this?
*/
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool newline)
{
if (!proc->get_scope()->have_declared(DISPLAY_LINE)) {
vhdl_var_decl *line_var =
new vhdl_var_decl(DISPLAY_LINE, vhdl_type::line());
line_var->set_comment("For generating $display output");
proc->get_scope()->add_decl(line_var);
}
// Write the data into the line
int count = ivl_stmt_parm_count(stmt), i = 0;
while (i < count) {
// $display may have an empty parameter, in which case
// the expression will be null
// The behaviour here seems to be to output a space
ivl_expr_t net = ivl_stmt_parm(stmt, i++);
if (net == NULL) {
display_write(container, new vhdl_const_string(" "));
continue;
}
if (ivl_expr_type(net) == IVL_EX_STRING) {
ostringstream ss;
for (const char *p = ivl_expr_string(net); *p; p++) {
if (*p == '\\') {
// Octal escape
char ch = parse_octal(p+1);
if (ch == '\n') {
flush_string(ss, container);
display_line(container);
}
else
ss << ch;
p += 3;
}
else if (*p == '%' && *(++p) != '%') {
flush_string(ss, container);
// Skip over width for now
while (isdigit(*p)) ++p;
// TODO: This needs to be re-written
// ...it does not handle format codes at all!
// Unfortunately, there is no printf-like
// function in VHDL
assert(i < count);
ivl_expr_t net = ivl_stmt_parm(stmt, i++);
assert(net);
vhdl_expr *base = translate_expr(net);
if (NULL == base)
return 1;
display_write(container, base);
}
else
ss << *p;
}
display_write(container, new vhdl_const_string(ss.str().c_str()));
}
else {
vhdl_expr *base = translate_expr(net);
if (NULL == base)
return 1;
display_write(container, base);
}
}
if (newline)
display_line(container);
return 0;
}
+560
View File
@@ -0,0 +1,560 @@
/*
* VHDL code generation for expressions.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_target.h"
#include "support.hh"
#include <iostream>
#include <cassert>
#include <cstring>
/*
* Change the signedness of a vector.
*/
static vhdl_expr *change_signedness(vhdl_expr *e, bool issigned)
{
int msb = e->get_type()->get_msb();
int lsb = e->get_type()->get_lsb();
vhdl_type u(issigned ? VHDL_TYPE_SIGNED : VHDL_TYPE_UNSIGNED, msb, lsb);
return e->cast(&u);
}
/*
* Convert a constant Verilog string to a constant VHDL string.
*/
static vhdl_expr *translate_string(ivl_expr_t e)
{
// TODO: May need to inspect or escape parts of this
const char *str = ivl_expr_string(e);
return new vhdl_const_string(str);
}
/*
* A reference to a signal in an expression. It's assumed that the
* signal has already been defined elsewhere.
*/
static vhdl_var_ref *translate_signal(ivl_expr_t e)
{
ivl_signal_t sig = ivl_expr_signal(e);
const vhdl_scope *scope = find_scope_for_signal(sig);
assert(scope);
const char *renamed = get_renamed_signal(sig).c_str();
vhdl_decl *decl = scope->get_decl(renamed);
assert(decl);
// Can't generate a constant initialiser for this signal
// later as it has already been read
if (scope->initializing())
decl->set_initial(NULL);
vhdl_var_ref *ref =
new vhdl_var_ref(renamed, new vhdl_type(*decl->get_type()));
ivl_expr_t off;
if (ivl_signal_array_count(sig) > 0 && (off = ivl_expr_oper1(e))) {
// Select from an array
vhdl_expr *vhd_off = translate_expr(off);
if (NULL == vhd_off)
return NULL;
vhdl_type integer(VHDL_TYPE_INTEGER);
ref->set_slice(vhd_off->cast(&integer));
}
return ref;
}
/*
* A numeric literal ends up as std_logic bit string.
*/
static vhdl_expr *translate_number(ivl_expr_t e)
{
if (ivl_expr_width(e) == 1)
return new vhdl_const_bit(ivl_expr_bits(e)[0]);
else
return new vhdl_const_bits(ivl_expr_bits(e), ivl_expr_width(e),
ivl_expr_signed(e) != 0);
}
static vhdl_expr *translate_ulong(ivl_expr_t e)
{
return new vhdl_const_int(ivl_expr_uvalue(e));
}
static vhdl_expr *translate_reduction(support_function_t f, bool neg,
vhdl_expr *operand)
{
vhdl_expr *result;
if (operand->get_type()->get_name() == VHDL_TYPE_STD_LOGIC)
result = operand;
else {
require_support_function(f);
vhdl_fcall *fcall =
new vhdl_fcall(support_function::function_name(f),
vhdl_type::std_logic());
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR);
fcall->add_expr(operand->cast(&std_logic_vector));
result = fcall;
}
if (neg)
return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, result,
vhdl_type::std_logic());
else
return result;
}
static vhdl_expr *translate_unary(ivl_expr_t e)
{
vhdl_expr *operand = translate_expr(ivl_expr_oper1(e));
if (NULL == operand)
return NULL;
bool should_be_signed = ivl_expr_signed(e) != 0;
if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED
&& should_be_signed) {
//operand->print();
//std::cout << "^ should be signed but is not" << std::endl;
operand = change_signedness(operand, true);
}
else if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED
&& !should_be_signed) {
//operand->print();
//std::cout << "^ should be unsigned but is not" << std::endl;
operand = change_signedness(operand, false);
}
char opcode = ivl_expr_opcode(e);
switch (opcode) {
case '!':
case '~':
return new vhdl_unaryop_expr
(VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type()));
case '-':
operand = change_signedness(operand, true);
return new vhdl_unaryop_expr
(VHDL_UNARYOP_NEG, operand, new vhdl_type(*operand->get_type()));
case 'N': // NOR
return translate_reduction(SF_REDUCE_OR, true, operand);
case '|':
return translate_reduction(SF_REDUCE_OR, false, operand);
case 'A': // NAND
return translate_reduction(SF_REDUCE_AND, true, operand);
case '&':
return translate_reduction(SF_REDUCE_AND, false, operand);
default:
error("No translation for unary opcode '%c'\n",
ivl_expr_opcode(e));
delete operand;
return NULL;
}
}
/*
* Translate a numeric binary operator (+, -, etc.) to
* a VHDL equivalent using the numeric_std package.
*/
static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs,
vhdl_binop_t op)
{
// May need to make either side Boolean for operators
// to work
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
if (lhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN)
rhs = rhs->cast(&boolean);
else if (rhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN)
lhs = lhs->cast(&boolean);
vhdl_type *rtype = new vhdl_type(*lhs->get_type());
return new vhdl_binop_expr(lhs, op, rhs, rtype);
}
static vhdl_expr *translate_relation(vhdl_expr *lhs, vhdl_expr *rhs,
vhdl_binop_t op)
{
// Generate any necessary casts
// Arbitrarily, the RHS is casted to the type of the LHS
vhdl_expr *r_cast = rhs->cast(lhs->get_type());
return new vhdl_binop_expr(lhs, op, r_cast, vhdl_type::boolean());
}
/*
* Like translate_relation but both operands must be Boolean.
*/
static vhdl_expr *translate_logical(vhdl_expr *lhs, vhdl_expr *rhs,
vhdl_binop_t op)
{
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
return translate_relation(lhs->cast(&boolean), rhs->cast(&boolean), op);
}
static vhdl_expr *translate_shift(vhdl_expr *lhs, vhdl_expr *rhs,
vhdl_binop_t op)
{
// The RHS must be an integer
vhdl_type integer(VHDL_TYPE_INTEGER);
vhdl_expr *r_cast = rhs->cast(&integer);
vhdl_type *rtype = new vhdl_type(*lhs->get_type());
return new vhdl_binop_expr(lhs, op, r_cast, rtype);
}
static vhdl_expr *translate_binary(ivl_expr_t e)
{
vhdl_expr *lhs = translate_expr(ivl_expr_oper1(e));
if (NULL == lhs)
return NULL;
vhdl_expr *rhs = translate_expr(ivl_expr_oper2(e));
if (NULL == rhs)
return NULL;
int lwidth = lhs->get_type()->get_width();
int rwidth = rhs->get_type()->get_width();
int result_width = ivl_expr_width(e);
// For === and !== we need to compare std_logic_vectors
// rather than signeds
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, result_width-1, 0);
vhdl_type_name_t ltype = lhs->get_type()->get_name();
vhdl_type_name_t rtype = rhs->get_type()->get_name();
bool vectorop =
(ltype == VHDL_TYPE_SIGNED || ltype == VHDL_TYPE_UNSIGNED) &&
(rtype == VHDL_TYPE_SIGNED || rtype == VHDL_TYPE_UNSIGNED);
// May need to resize the left or right hand side
if (vectorop) {
if (lwidth < rwidth)
lhs = lhs->resize(rwidth);
else if (rwidth < lwidth)
rhs = rhs->resize(lwidth);
}
vhdl_expr *result;
switch (ivl_expr_opcode(e)) {
case '+':
result = translate_numeric(lhs, rhs, VHDL_BINOP_ADD);
break;
case '-':
result = translate_numeric(lhs, rhs, VHDL_BINOP_SUB);
break;
case '*':
result = translate_numeric(lhs, rhs, VHDL_BINOP_MULT);
break;
case '/':
result = translate_numeric(lhs, rhs, VHDL_BINOP_DIV);
break;
case '%':
result = translate_numeric(lhs, rhs, VHDL_BINOP_MOD);
break;
case 'e':
result = translate_relation(lhs, rhs, VHDL_BINOP_EQ);
break;
case 'E':
if (vectorop)
result = translate_relation(lhs->cast(&std_logic_vector),
rhs->cast(&std_logic_vector), VHDL_BINOP_EQ);
else
result = translate_relation(lhs, rhs, VHDL_BINOP_EQ);
break;
case 'n':
result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ);
break;
case 'N':
if (vectorop)
result = translate_relation(lhs->cast(&std_logic_vector),
rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ);
else
result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ);
break;
case '&': // Bitwise AND
result = translate_numeric(lhs, rhs, VHDL_BINOP_AND);
break;
case 'a': // Logical AND
result = translate_logical(lhs, rhs, VHDL_BINOP_AND);
break;
case 'A': // Bitwise NAND
result = translate_numeric(lhs, rhs, VHDL_BINOP_NAND);
break;
case 'O': // Bitwise NOR
result = translate_numeric(lhs, rhs, VHDL_BINOP_NOR);
break;
case 'X': // Bitwise XNOR
result = translate_numeric(lhs, rhs, VHDL_BINOP_XNOR);
break;
case '|': // Bitwise OR
result = translate_numeric(lhs, rhs, VHDL_BINOP_OR);
break;
case 'o': // Logical OR
result = translate_logical(lhs, rhs, VHDL_BINOP_OR);
break;
case '<':
result = translate_relation(lhs, rhs, VHDL_BINOP_LT);
break;
case 'L':
result = translate_relation(lhs, rhs, VHDL_BINOP_LEQ);
break;
case '>':
result = translate_relation(lhs, rhs, VHDL_BINOP_GT);
break;
case 'G':
result = translate_relation(lhs, rhs, VHDL_BINOP_GEQ);
break;
case 'l':
result = translate_shift(lhs, rhs, VHDL_BINOP_SL);
break;
case 'r':
result = translate_shift(lhs, rhs, VHDL_BINOP_SR);
break;
case '^':
result = translate_numeric(lhs, rhs, VHDL_BINOP_XOR);
break;
default:
error("No translation for binary opcode '%c'\n",
ivl_expr_opcode(e));
delete lhs;
delete rhs;
return NULL;
}
if (NULL == result)
return NULL;
if (vectorop) {
bool should_be_signed = ivl_expr_signed(e) != 0;
if (result->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) {
//result->print();
//std::cout << "^ should be signed but is not" << std::endl;
result = change_signedness(result, true);
}
else if (result->get_type()->get_name() == VHDL_TYPE_SIGNED && !should_be_signed) {
//result->print();
//std::cout << "^ should be unsigned but is not" << std::endl;
result = change_signedness(result, false);
}
int actual_width = result->get_type()->get_width();
if (actual_width != result_width) {
//result->print();
//std::cout << "^ should be " << result_width << " but is " << actual_width << std::endl;
}
}
return result;
}
static vhdl_expr *translate_select(ivl_expr_t e)
{
vhdl_var_ref *from =
dynamic_cast<vhdl_var_ref*>(translate_expr(ivl_expr_oper1(e)));
if (NULL == from) {
error("Can only select from variable reference");
return NULL;
}
ivl_expr_t o2 = ivl_expr_oper2(e);
if (o2) {
vhdl_expr *base = translate_expr(ivl_expr_oper2(e));
if (NULL == base)
return NULL;
vhdl_type integer(VHDL_TYPE_INTEGER);
from->set_slice(base->cast(&integer), ivl_expr_width(e) - 1);
return from;
}
else
return from->resize(ivl_expr_width(e));
}
static vhdl_type *expr_to_vhdl_type(ivl_expr_t e)
{
if (ivl_expr_signed(e))
return vhdl_type::nsigned(ivl_expr_width(e));
else
return vhdl_type::nunsigned(ivl_expr_width(e));
}
template <class T>
static T *translate_parms(T *t, ivl_expr_t e)
{
int nparams = ivl_expr_parms(e);
for (int i = 0; i < nparams; i++) {
vhdl_expr *param = translate_expr(ivl_expr_parm(e, i));
if (NULL == param)
return NULL;
t->add_expr(param);
}
return t;
}
static vhdl_expr *translate_ufunc(ivl_expr_t e)
{
ivl_scope_t defscope = ivl_expr_def(e);
ivl_scope_t parentscope = ivl_scope_parent(defscope);
assert(ivl_scope_type(parentscope) == IVL_SCT_MODULE);
// A function is always declared in a module, which should have
// a corresponding entity by this point: so we can get type
// information, etc. from the declaration
vhdl_entity *parent_ent = find_entity(ivl_scope_name(parentscope));
assert(parent_ent);
const char *funcname = ivl_scope_tname(defscope);
vhdl_type *rettype = expr_to_vhdl_type(e);
vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype);
return translate_parms<vhdl_fcall>(fcall, e);
}
static vhdl_expr *translate_ternary(ivl_expr_t e)
{
support_function_t sf;
int width = ivl_expr_width(e);
bool issigned = ivl_expr_signed(e) != 0;
if (width == 1)
sf = SF_TERNARY_LOGIC;
else if (issigned)
sf = SF_TERNARY_SIGNED;
else
sf = SF_TERNARY_UNSIGNED;
require_support_function(sf);
vhdl_expr *test = translate_expr(ivl_expr_oper1(e));
vhdl_expr *true_part = translate_expr(ivl_expr_oper2(e));
vhdl_expr *false_part = translate_expr(ivl_expr_oper3(e));
if (!test || !true_part || !false_part)
return NULL;
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
test = test->cast(&boolean);
vhdl_fcall *fcall =
new vhdl_fcall(support_function::function_name(sf),
vhdl_type::type_for(width, issigned));
fcall->add_expr(test);
fcall->add_expr(true_part);
fcall->add_expr(false_part);
return fcall;
}
static vhdl_expr *translate_concat(ivl_expr_t e)
{
vhdl_type *rtype = expr_to_vhdl_type(e);
vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, rtype);
int nrepeat = ivl_expr_repeat(e);
while (nrepeat--)
translate_parms<vhdl_binop_expr>(concat, e);
return concat;
}
vhdl_expr *translate_sfunc_time(ivl_expr_t e)
{
cerr << "warning: no translation for time (returning 0)" << endl;
return new vhdl_const_int(0);
}
vhdl_expr *translate_sfunc(ivl_expr_t e)
{
const char *name = ivl_expr_name(e);
if (strcmp(name, "$time") == 0)
return translate_sfunc_time(e);
else {
error("No translation for system function %s", name);
return NULL;
}
}
/*
* Generate a VHDL expression from a Verilog expression.
*/
vhdl_expr *translate_expr(ivl_expr_t e)
{
assert(e);
ivl_expr_type_t type = ivl_expr_type(e);
switch (type) {
case IVL_EX_STRING:
return translate_string(e);
case IVL_EX_SIGNAL:
return translate_signal(e);
case IVL_EX_NUMBER:
return translate_number(e);
case IVL_EX_ULONG:
return translate_ulong(e);
case IVL_EX_UNARY:
return translate_unary(e);
case IVL_EX_BINARY:
return translate_binary(e);
case IVL_EX_SELECT:
return translate_select(e);
case IVL_EX_UFUNC:
return translate_ufunc(e);
case IVL_EX_TERNARY:
return translate_ternary(e);
case IVL_EX_CONCAT:
return translate_concat(e);
case IVL_EX_SFUNC:
return translate_sfunc(e);
default:
error("No VHDL translation for expression at %s:%d (type = %d)",
ivl_expr_file(e), ivl_expr_lineno(e), type);
return NULL;
}
}
/*
* Translate an expression into a time. This is achieved simply
* by multiplying the expression by 1ns.
*/
vhdl_expr *translate_time_expr(ivl_expr_t e)
{
vhdl_expr *time = translate_expr(e);
if (NULL == time)
return NULL;
vhdl_type integer(VHDL_TYPE_INTEGER);
time = time->cast(&integer);
vhdl_expr *ns1 = new vhdl_const_time(1, TIME_UNIT_NS);
return new vhdl_binop_expr(time, VHDL_BINOP_MULT, ns1,
vhdl_type::time());
}
+289
View File
@@ -0,0 +1,289 @@
/*
* VHDL code generation for logic devices.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_target.h"
#include "vhdl_element.hh"
#include <cassert>
#include <sstream>
#include <iostream>
/*
* Convert the inputs of a logic gate to a binary expression.
*/
static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op,
ivl_net_logic_t log)
{
// Not always std_logic but this is probably OK since
// the program has already been type checked
vhdl_binop_expr *gate =
new vhdl_binop_expr(op, vhdl_type::std_logic());
int npins = ivl_logic_pins(log);
for (int i = 1; i < npins; i++) {
ivl_nexus_t input = ivl_logic_pin(log, i);
gate->add_expr(nexus_to_var_ref(scope, input));
}
return gate;
}
/*
* Convert a gate intput to an unary expression.
*/
static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op,
ivl_net_logic_t log)
{
ivl_nexus_t input = ivl_logic_pin(log, 1);
assert(input);
vhdl_expr *operand = nexus_to_var_ref(scope, input);
return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic());
}
static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0)
{
ivl_nexus_t output = ivl_logic_pin(log, 0);
vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
assert(lhs);
vhdl_expr *val = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
assert(val);
vhdl_expr *sel = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 2));
assert(val);
vhdl_expr *cmp;
if (ivl_logic_width(log) == 1) {
vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1');
cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL);
}
else {
vhdl_expr *zero = (new vhdl_const_int(0))->cast(sel->get_type());
vhdl_binop_t op = if0 ? VHDL_BINOP_EQ : VHDL_BINOP_NEQ;
cmp = new vhdl_binop_expr(sel, op, zero, NULL);
}
ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope());
char zbit;
switch (ivl_signal_type(sig)) {
case IVL_SIT_TRI0:
zbit = '0';
break;
case IVL_SIT_TRI1:
zbit = '1';
break;
case IVL_SIT_TRI:
default:
zbit = 'Z';
}
vhdl_expr *z = new vhdl_const_bit(zbit);
if (ivl_logic_width(log) > 1)
z = new vhdl_bit_spec_expr(NULL, z);
vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z);
cass->add_condition(val, cmp);
arch->add_stmt(cass);
}
static void comb_udp_logic(vhdl_arch *arch, ivl_net_logic_t log)
{
ivl_udp_t udp = ivl_logic_udp(log);
// As with regular case statements, the expression in a
// `with .. select' statement must be "locally static".
// This is achieved by first combining the inputs into
// a temporary
ostringstream ss;
ss << ivl_logic_basename(log) << "_Tmp";
int msb = ivl_udp_nin(udp) - 1;
vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0);
vhdl_signal_decl *tmp_decl =
new vhdl_signal_decl(ss.str().c_str(), tmp_type);
arch->get_scope()->add_decl(tmp_decl);
int nin = ivl_udp_nin(udp);
vhdl_expr *tmp_rhs;
if (nin == 1) {
tmp_rhs = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
tmp_rhs = tmp_rhs->cast(tmp_type);
}
else
tmp_rhs = inputs_to_expr(arch->get_scope(), VHDL_BINOP_CONCAT, log);
ss.str("");
ss << "Input to " << ivl_logic_basename(log) << " "
<< ivl_udp_name(udp) << " UDP";
tmp_decl->set_comment(ss.str());
vhdl_var_ref *tmp_ref =
new vhdl_var_ref(tmp_decl->get_name().c_str(), NULL);
arch->add_stmt(new vhdl_cassign_stmt(tmp_ref, tmp_rhs));
// Now we can implement the UDP as a `with .. select' statement
// by reading values out of the table
ivl_nexus_t output_nex = ivl_logic_pin(log, 0);
vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), output_nex);
vhdl_with_select_stmt *ws =
new vhdl_with_select_stmt(new vhdl_var_ref(*tmp_ref), out);
int nrows = ivl_udp_rows(udp);
for (int i = 0; i < nrows; i++) {
const char *row = ivl_udp_row(udp, i);
vhdl_expr *value = new vhdl_const_bit(row[nin]);
vhdl_expr *cond = new vhdl_const_bits(row, nin, false);
ivl_expr_t delay_ex = ivl_logic_delay(log, 1);
vhdl_expr *delay = NULL;
if (delay_ex)
delay = translate_time_expr(delay_ex);
ws->add_condition(value, cond, delay);
}
ss.str("");
ss << "UDP " << ivl_udp_name(udp);
ws->set_comment(ss.str());
arch->add_stmt(ws);
}
static void seq_udp_logic(vhdl_arch *arch, ivl_net_logic_t log)
{
ivl_udp_t udp = ivl_logic_udp(log);
// These will be translated to a process with a single
// case statement
vhdl_process *proc = new vhdl_process(ivl_logic_basename(log));
ostringstream ss;
ss << "Generated from UDP " << ivl_udp_name(udp);
proc->set_comment(ss.str().c_str());
// Create a variable to hold the concatenation of the inputs
int msb = ivl_udp_nin(udp) - 1;
vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0);
proc->get_scope()->add_decl(new vhdl_var_decl("UDP_Inputs", tmp_type));
// Concatenate the inputs into a single expression that can be
// used as the test in a case statement (this can't be inserted
// directly into the case statement due to the requirement that
// the test expression be "locally static")
int nin = ivl_udp_nin(udp);
vhdl_expr *tmp_rhs = NULL;
if (nin == 1) {
vhdl_var_ref *ref =
nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
tmp_rhs = ref->cast(tmp_type);
proc->add_sensitivity(ref->get_name());
}
else {
vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, NULL);
for (int i = 1; i < nin; i++) {
vhdl_var_ref *ref =
nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, i));
concat->add_expr(ref);
proc->add_sensitivity(ref->get_name());
}
tmp_rhs = concat;
}
proc->get_container()->add_stmt
(new vhdl_assign_stmt(new vhdl_var_ref("UDP_Inputs", NULL), tmp_rhs));
arch->add_stmt(proc);
}
static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log)
{
if (ivl_udp_sequ(ivl_logic_udp(log)))
seq_udp_logic(arch, log);
else
comb_udp_logic(arch, log);
}
static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log)
{
switch (ivl_logic_type(log)) {
case IVL_LO_NOT:
return input_to_expr(scope, VHDL_UNARYOP_NOT, log);
case IVL_LO_AND:
return inputs_to_expr(scope, VHDL_BINOP_AND, log);
case IVL_LO_OR:
return inputs_to_expr(scope, VHDL_BINOP_OR, log);
case IVL_LO_NAND:
return inputs_to_expr(scope, VHDL_BINOP_NAND, log);
case IVL_LO_NOR:
return inputs_to_expr(scope, VHDL_BINOP_NOR, log);
case IVL_LO_XOR:
return inputs_to_expr(scope, VHDL_BINOP_XOR, log);
case IVL_LO_XNOR:
return inputs_to_expr(scope, VHDL_BINOP_XNOR, log);
case IVL_LO_BUF:
case IVL_LO_BUFZ:
return nexus_to_var_ref(scope, ivl_logic_pin(log, 1));
case IVL_LO_PULLUP:
return new vhdl_const_bit('1');
case IVL_LO_PULLDOWN:
return new vhdl_const_bit('0');
default:
error("Don't know how to translate logic type = %d to expression",
ivl_logic_type(log));
return NULL;
}
}
void draw_logic(vhdl_arch *arch, ivl_net_logic_t log)
{
switch (ivl_logic_type(log)) {
case IVL_LO_BUFIF0:
bufif_logic(arch, log, true);
break;
case IVL_LO_BUFIF1:
bufif_logic(arch, log, false);
break;
case IVL_LO_UDP:
udp_logic(arch, log);
break;
default:
{
// The output is always pin zero
ivl_nexus_t output = ivl_logic_pin(log, 0);
vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
vhdl_expr *rhs = translate_logic_inputs(arch->get_scope(), log);
vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs);
ivl_expr_t delay = ivl_logic_delay(log, 1);
if (delay)
ass->set_after(translate_time_expr(delay));
arch->add_stmt(ass);
}
}
}
+330
View File
@@ -0,0 +1,330 @@
/*
* VHDL code generation for LPM devices.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_target.h"
#include <iostream>
#include <cassert>
/*
* Return the base of a part select.
*/
static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm)
{
vhdl_expr *off;
ivl_nexus_t base = ivl_lpm_data(lpm, 1);
if (base != NULL)
off = nexus_to_var_ref(scope, base);
else
off = new vhdl_const_int(ivl_lpm_base(lpm));
// Array indexes must be integers
vhdl_type integer(VHDL_TYPE_INTEGER);
return off->cast(&integer);
}
static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
vhdl_type *result_type =
vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0);
vhdl_binop_expr *expr =
new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type);
for (int i = ivl_lpm_selects(lpm) - 1; i >= 0; i--) {
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
if (NULL == e)
return NULL;
expr->add_expr(e);
}
return expr;
}
static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
{
unsigned out_width = ivl_lpm_width(lpm);
vhdl_type *result_type =
vhdl_type::type_for(out_width, ivl_lpm_signed(lpm) != 0);
vhdl_binop_expr *expr = new vhdl_binop_expr(op, result_type);
for (int i = 0; i < 2; i++) {
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
if (NULL == e)
return NULL;
expr->add_expr(e->cast(result_type));
}
if (op == VHDL_BINOP_MULT) {
// Need to resize the output to the desired size,
// as this does not happen automatically in VHDL
vhdl_fcall *resize =
new vhdl_fcall("Resize", vhdl_type::nsigned(out_width));
resize->add_expr(expr);
resize->add_expr(new vhdl_const_int(out_width));
return resize;
}
else
return expr;
}
static vhdl_expr *rel_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
{
vhdl_binop_expr *expr = new vhdl_binop_expr(op, vhdl_type::boolean());
for (int i = 0; i < 2; i++) {
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
if (NULL == e)
return NULL;
expr->add_expr(e);
}
// Need to make sure output is std_logic rather than Boolean
vhdl_type std_logic(VHDL_TYPE_STD_LOGIC);
return expr->cast(&std_logic);
}
static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
if (NULL == selfrom)
return NULL;
vhdl_expr *off = part_select_base(scope, lpm);;
if (NULL == off)
return NULL;
selfrom->set_slice(off, ivl_lpm_width(lpm) - 1);
return selfrom;
}
static vhdl_expr *part_select_pv_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
return nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
}
static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
ivl_scope_t f_scope = ivl_lpm_define(lpm);
vhdl_fcall *fcall = new vhdl_fcall(ivl_scope_basename(f_scope), NULL);
for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) {
vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
if (NULL == ref)
return NULL;
fcall->add_expr(ref);
}
return fcall;
}
static vhdl_expr *reduction_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm,
support_function_t f, bool invert)
{
vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
if (NULL == ref)
return NULL;
vhdl_expr *result;
if (ref->get_type()->get_name() == VHDL_TYPE_STD_LOGIC)
result = ref;
else {
require_support_function(f);
vhdl_fcall *fcall = new vhdl_fcall(support_function::function_name(f),
vhdl_type::std_logic());
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR);
fcall->add_expr(ref->cast(&std_logic_vector));
result = fcall;
}
if (invert)
return new vhdl_unaryop_expr
(VHDL_UNARYOP_NOT, result, vhdl_type::std_logic());
else
return result;
}
static vhdl_expr *sign_extend_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
vhdl_expr *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
if (ref)
return ref->resize(ivl_lpm_width(lpm));
else
return NULL;
}
static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
ivl_signal_t array = ivl_lpm_array(lpm);
if (!seen_signal_before(array))
return NULL;
const char *renamed = get_renamed_signal(array).c_str();
vhdl_decl *adecl = scope->get_decl(renamed);
assert(adecl);
vhdl_type *atype = new vhdl_type(*adecl->get_type());
vhdl_expr *select = nexus_to_var_ref(scope, ivl_lpm_select(lpm));
if (NULL == select)
return NULL;
vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype);
vhdl_type integer(VHDL_TYPE_INTEGER);
ref->set_slice(select->cast(&integer));
return ref;
}
static vhdl_expr *shift_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm,
vhdl_binop_t shift_op)
{
vhdl_expr *lhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
vhdl_expr *rhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1));
if (!lhs || !rhs)
return NULL;
// The RHS must be an integer
vhdl_type integer(VHDL_TYPE_INTEGER);
vhdl_expr *r_cast = rhs->cast(&integer);
vhdl_type *rtype = new vhdl_type(*lhs->get_type());
return new vhdl_binop_expr(lhs, shift_op, r_cast, rtype);
}
static vhdl_expr *repeat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
vhdl_expr *in = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
return new vhdl_bit_spec_expr(NULL, in);
}
static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
switch (ivl_lpm_type(lpm)) {
case IVL_LPM_ADD:
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_ADD);
case IVL_LPM_SUB:
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_SUB);
case IVL_LPM_MULT:
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MULT);
case IVL_LPM_DIVIDE:
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_DIV);
case IVL_LPM_MOD:
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MOD);
case IVL_LPM_CONCAT:
return concat_lpm_to_expr(scope, lpm);
case IVL_LPM_CMP_GE:
return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_GEQ);
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_EEQ:
return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_EQ);
case IVL_LPM_PART_VP:
return part_select_vp_lpm_to_expr(scope, lpm);
case IVL_LPM_PART_PV:
return part_select_pv_lpm_to_expr(scope, lpm);
case IVL_LPM_UFUNC:
return ufunc_lpm_to_expr(scope, lpm);
case IVL_LPM_RE_AND:
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, false);
case IVL_LPM_RE_NAND:
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, true);
case IVL_LPM_RE_NOR:
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, true);
case IVL_LPM_RE_OR:
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, false);
case IVL_LPM_RE_XOR:
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, false);
case IVL_LPM_RE_XNOR:
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, true);
case IVL_LPM_SIGN_EXT:
return sign_extend_lpm_to_expr(scope, lpm);
case IVL_LPM_ARRAY:
return array_lpm_to_expr(scope, lpm);
case IVL_LPM_SHIFTL:
return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SL);
case IVL_LPM_SHIFTR:
return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SR);
case IVL_LPM_REPEAT:
return repeat_lpm_to_expr(scope, lpm);
default:
error("Unsupported LPM type: %d", ivl_lpm_type(lpm));
return NULL;
}
}
static int draw_mux_lpm(vhdl_arch *arch, ivl_lpm_t lpm)
{
int nselects = ivl_lpm_selects(lpm);
if (nselects > 1) {
error("Only 1 LPM select bit supported at the moment");
return 1;
}
vhdl_scope *scope = arch->get_scope();
vhdl_expr *s0 = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
vhdl_expr *s1 = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1));
vhdl_expr *sel = nexus_to_var_ref(scope, ivl_lpm_select(lpm));
vhdl_expr *b1 = new vhdl_const_bit('1');
vhdl_expr *t1 =
new vhdl_binop_expr(sel, VHDL_BINOP_EQ, b1, vhdl_type::boolean());
vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0));
vhdl_cassign_stmt *s = new vhdl_cassign_stmt(out, s0);
s->add_condition(s1, t1);
arch->add_stmt(s);
return 0;
}
int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm)
{
if (ivl_lpm_type(lpm) == IVL_LPM_MUX)
return draw_mux_lpm(arch, lpm);
vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm);
if (NULL == f)
return 1;
vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0));
if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) {
vhdl_expr *off = part_select_base(arch->get_scope(), lpm);
assert(off);
out->set_slice(off, ivl_lpm_width(lpm) - 1);
}
arch->add_stmt(new vhdl_cassign_stmt(out, f));
return 0;
}
+91
View File
@@ -0,0 +1,91 @@
/*
* VHDL code generation for processes.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_target.h"
#include "vhdl_element.hh"
#include <iostream>
#include <cassert>
#include <sstream>
/*
* Convert a Verilog process to VHDL and add it to the architecture
* of the given entity.
*/
static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc)
{
set_active_entity(ent);
// Create a new process and store it in the entity's
// architecture. This needs to be done first or the
// parent link won't be valid (and draw_stmt needs this
// to add information to the architecture)
vhdl_process *vhdl_proc = new vhdl_process();
ent->get_arch()->add_stmt(vhdl_proc);
// If this is an initial process, push signal initialisation
// into the declarations
vhdl_proc->get_scope()->set_initializing
(ivl_process_type(proc) == IVL_PR_INITIAL);
ivl_statement_t stmt = ivl_process_stmt(proc);
int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt);
if (rc != 0)
return rc;
// Initial processes are translated to VHDL processes with
// no sensitivity list and and indefinite wait statement at
// the end
// However, if no statements were added to the container
// by draw_stmt, don't bother adding a wait as `emit'
// will optimise the process out of the output
if (ivl_process_type(proc) == IVL_PR_INITIAL
&& !vhdl_proc->get_container()->empty()) {
vhdl_wait_stmt *wait = new vhdl_wait_stmt();
vhdl_proc->get_container()->add_stmt(wait);
}
// Add a comment indicating where it came from
ivl_scope_t scope = ivl_process_scope(proc);
const char *type = ivl_process_type(proc) == IVL_PR_INITIAL
? "initial" : "always";
std::ostringstream ss;
ss << "Generated from " << type << " process in "
<< ivl_scope_tname(scope) << " ("
<< ivl_process_file(proc) << ":"
<< ivl_process_lineno(proc) << ")";
vhdl_proc->set_comment(ss.str());
set_active_entity(NULL);
return 0;
}
int draw_process(ivl_process_t proc, void *cd)
{
ivl_scope_t scope = ivl_process_scope(proc);
// A process should occur in a module scope, therefore it
// should have already been assigned a VHDL entity
assert(ivl_scope_type(scope) == IVL_SCT_MODULE);
vhdl_entity *ent = find_entity(ivl_scope_name(scope));
assert(ent != NULL);
return generate_vhdl_process(ent, proc);
}
+819
View File
@@ -0,0 +1,819 @@
/*
* VHDL code generation for scopes.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_target.h"
#include "vhdl_element.hh"
#include <iostream>
#include <sstream>
#include <cassert>
#include <cstring>
static string make_safe_name(ivl_signal_t sig);
static vhdl_entity *g_active_entity = NULL;
vhdl_entity *get_active_entity()
{
return g_active_entity;
}
void set_active_entity(vhdl_entity *ent)
{
g_active_entity = ent;
}
/*
* This represents the portion of a nexus that is visible within
* a VHDL scope. If that nexus portion does not contain a signal,
* then `tmpname' gives the name of the temporary that will be
* used when this nexus is used in `scope' (e.g. for LPMs that
* appear in instantiations). The list `connect' lists all the
* signals that should be joined together to re-create the net.
*/
struct scope_nexus_t {
vhdl_scope *scope;
ivl_signal_t sig; // A real signal
unsigned pin; // The pin this signal is connected to
string tmpname; // A new temporary signal
list<ivl_signal_t> connect; // Other signals to wire together
};
/*
* This structure is stored in the private part of each nexus.
* It stores a scope_nexus_t for each VHDL scope which is
* connected to that nexus. It's stored as a list so we can use
* contained_within to allow several nested scopes to reference
* the same signal.
*/
struct nexus_private_t {
list<scope_nexus_t> signals;
vhdl_expr *const_driver;
};
/*
* Returns the scope_nexus_t of this nexus visible within scope.
*/
static scope_nexus_t *visible_nexus(nexus_private_t *priv, vhdl_scope *scope)
{
list<scope_nexus_t>::iterator it;
for (it = priv->signals.begin(); it != priv->signals.end(); ++it) {
if (scope->contained_within((*it).scope))
return &*it;
}
return NULL;
}
/*
* Remember that a signal in `scope' is part of this nexus. The
* first signal passed to this function for a scope will be used
* as the canonical representation of this nexus when we need to
* convert it to a variable reference (e.g. in a LPM input/output).
*/
static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope,
ivl_signal_t sig, unsigned pin)
{
scope_nexus_t *sn;
if ((sn = visible_nexus(priv, scope))) {
assert(sn->tmpname == "");
sn->connect.push_back(sig);
}
else {
scope_nexus_t new_sn = { scope, sig, pin, "" };
priv->signals.push_back(new_sn);
}
}
/*
* Make a temporary the representative of this nexus in scope.
*/
static void link_scope_to_nexus_tmp(nexus_private_t *priv, vhdl_scope *scope,
const string &name)
{
scope_nexus_t new_sn = { scope, NULL, 0, name };
priv->signals.push_back(new_sn);
}
/*
* Finds the name of the nexus signal within this scope.
*/
static string visible_nexus_signal_name(nexus_private_t *priv, vhdl_scope *scope,
unsigned *pin)
{
scope_nexus_t *sn = visible_nexus(priv, scope);
assert(sn);
*pin = sn->pin;
return sn->sig ? get_renamed_signal(sn->sig) : sn->tmpname;
}
/*
* Generates VHDL code to fully represent a nexus.
*/
void draw_nexus(ivl_nexus_t nexus)
{
nexus_private_t *priv = new nexus_private_t;
priv->const_driver = NULL;
int nptrs = ivl_nexus_ptrs(nexus);
// First pass through connect all the signals up
for (int i = 0; i < nptrs; i++) {
ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i);
ivl_signal_t sig;
if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
vhdl_scope *scope = find_scope_for_signal(sig);
unsigned pin = ivl_nexus_ptr_pin(nexus_ptr);
link_scope_to_nexus_signal(priv, scope, sig, pin);
}
}
// Second pass through make sure logic/LPMs have signal
// inputs and outputs
for (int i = 0; i < nptrs; i++) {
ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i);
ivl_net_logic_t log;
ivl_lpm_t lpm;
ivl_net_const_t con;
if ((log = ivl_nexus_ptr_log(nexus_ptr))) {
ivl_scope_t log_scope = ivl_logic_scope(log);
vhdl_scope *vhdl_scope =
find_entity(ivl_scope_name(log_scope))->get_arch()->get_scope();
if (visible_nexus(priv, vhdl_scope)) {
// Already seen this signal in vhdl_scope
}
else {
// Create a temporary signal to connect it to the nexus
vhdl_type *type =
vhdl_type::type_for(ivl_logic_width(log), false);
ostringstream ss;
ss << "LO" << ivl_logic_basename(log);
vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type));
link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str());
}
}
else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) {
ivl_scope_t lpm_scope = ivl_lpm_scope(lpm);
vhdl_scope *vhdl_scope =
find_entity(ivl_scope_name(lpm_scope))->get_arch()->get_scope();
if (visible_nexus(priv, vhdl_scope)) {
// Already seen this signal in vhdl_scope
}
else {
// Create a temporary signal to connect the nexus
// TODO: we could avoid this for IVL_LPM_PART_PV
vhdl_type *type = vhdl_type::type_for(ivl_lpm_width(lpm),
ivl_lpm_signed(lpm) != 0);
ostringstream ss;
ss << "LPM" << ivl_lpm_basename(lpm);
vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type));
link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str());
}
}
else if ((con = ivl_nexus_ptr_con(nexus_ptr))) {
if (ivl_const_width(con) == 1)
priv->const_driver = new vhdl_const_bit(ivl_const_bits(con)[0]);
else
priv->const_driver =
new vhdl_const_bits(ivl_const_bits(con), ivl_const_width(con),
ivl_const_signed(con) != 0);
}
}
// Save the private data in the nexus
ivl_nexus_set_private(nexus, priv);
}
/*
* Ensure that a nexus has been initialised. I.e. all the necessary
* statements, declarations, etc. have been generated.
*/
static void seen_nexus(ivl_nexus_t nexus)
{
if (ivl_nexus_get_private(nexus) == NULL)
draw_nexus(nexus);
}
/*
* Translate a nexus to a variable reference. Given a nexus and a
* scope, this function returns a reference to a signal that is
* connected to the nexus and within the given scope. This signal
* might not exist in the original Verilog source (even as a
* compiler-generated temporary). If this nexus hasn't been
* encountered before, the necessary code to connect up the nexus
* will be generated.
*/
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus)
{
seen_nexus(nexus);
nexus_private_t *priv =
static_cast<nexus_private_t*>(ivl_nexus_get_private(nexus));
unsigned pin;
string renamed(visible_nexus_signal_name(priv, scope, &pin));
vhdl_decl *decl = scope->get_decl(renamed);
assert(decl);
vhdl_type *type = new vhdl_type(*(decl->get_type()));
vhdl_var_ref *ref = new vhdl_var_ref(renamed.c_str(), type);
if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY)
ref->set_slice(new vhdl_const_int(pin), 0);
return ref;
}
/*
* Translate all the primitive logic gates into concurrent
* signal assignments.
*/
static void declare_logic(vhdl_arch *arch, ivl_scope_t scope)
{
int nlogs = ivl_scope_logs(scope);
for (int i = 0; i < nlogs; i++)
draw_logic(arch, ivl_scope_log(scope, i));
}
/*
* Make sure a signal name conforms to VHDL naming rules.
*/
static string make_safe_name(ivl_signal_t sig)
{
const char *base = ivl_signal_basename(sig);
if (base[0] == '_')
return string("VL") + base;
const char *vhdl_reserved[] = {
"in", "out", "entity", "architecture", "inout", "array",
"is", "not", "and", "or", "bus", "bit", "line", // Etc...
NULL
};
for (const char **p = vhdl_reserved; *p != NULL; p++) {
if (strcasecmp(*p, base) == 0) {
return string("VL_") + base;
break;
}
}
return string(base);
}
/*
* Declare all signals and ports for a scope.
*/
static void declare_signals(vhdl_entity *ent, ivl_scope_t scope)
{
int nsigs = ivl_scope_sigs(scope);
for (int i = 0; i < nsigs; i++) {
ivl_signal_t sig = ivl_scope_sig(scope, i);
remember_signal(sig, ent->get_arch()->get_scope());
string name(make_safe_name(sig));
rename_signal(sig, name);
vhdl_type *sig_type;
unsigned dimensions = ivl_signal_dimensions(sig);
if (dimensions > 0) {
// Arrays are implemented by generating a separate type
// declaration for each array, and then declaring a
// signal of that type
if (dimensions > 1) {
error("> 1 dimension arrays not implemented yet");
return;
}
string type_name = name + "_Type";
vhdl_type *base_type =
vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0);
int lsb = ivl_signal_array_base(sig);
int msb = lsb + ivl_signal_array_count(sig) - 1;
vhdl_type *array_type =
vhdl_type::array_of(base_type, type_name, msb, lsb);
vhdl_decl *array_decl = new vhdl_type_decl(type_name.c_str(), array_type);
ent->get_arch()->get_scope()->add_decl(array_decl);
sig_type = new vhdl_type(*array_type);
}
else
sig_type =
vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0);
ivl_signal_port_t mode = ivl_signal_port(sig);
switch (mode) {
case IVL_SIP_NONE:
{
vhdl_decl *decl = new vhdl_signal_decl(name.c_str(), sig_type);
ostringstream ss;
ss << "Declared at " << ivl_signal_file(sig) << ":"
<< ivl_signal_lineno(sig);
decl->set_comment(ss.str().c_str());
ent->get_arch()->get_scope()->add_decl(decl);
}
break;
case IVL_SIP_INPUT:
ent->get_scope()->add_decl
(new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_IN));
break;
case IVL_SIP_OUTPUT:
{
vhdl_port_decl *decl =
new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT);
ent->get_scope()->add_decl(decl);
}
if (ivl_signal_type(sig) == IVL_SIT_REG) {
// A registered output
// In Verilog the output and reg can have the
// same name: this is not valid in VHDL
// Instead a new signal foo_Reg is created
// which represents the register
std::string newname(name);
newname += "_Reg";
rename_signal(sig, newname.c_str());
vhdl_type *reg_type = new vhdl_type(*sig_type);
ent->get_arch()->get_scope()->add_decl
(new vhdl_signal_decl(newname.c_str(), reg_type));
// Create a concurrent assignment statement to
// connect the register to the output
ent->get_arch()->add_stmt
(new vhdl_cassign_stmt
(new vhdl_var_ref(name.c_str(), NULL),
new vhdl_var_ref(newname.c_str(), NULL)));
}
break;
case IVL_SIP_INOUT:
ent->get_scope()->add_decl
(new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_INOUT));
break;
default:
assert(false);
}
}
}
/*
* Generate VHDL for LPM instances in a module.
*/
static void declare_lpm(vhdl_arch *arch, ivl_scope_t scope)
{
int nlpms = ivl_scope_lpms(scope);
for (int i = 0; i < nlpms; i++) {
ivl_lpm_t lpm = ivl_scope_lpm(scope, i);
if (draw_lpm(arch, lpm) != 0)
error("Failed to translate LPM %s", ivl_lpm_name(lpm));
}
}
/*
* Map two signals together in an instantiation.
* The signals are joined by a nexus.
*/
static void map_signal(ivl_signal_t to, vhdl_entity *parent,
vhdl_comp_inst *inst)
{
// TODO: Work for multiple words
ivl_nexus_t nexus = ivl_signal_nex(to, 0);
seen_nexus(nexus);
vhdl_scope *arch_scope = parent->get_arch()->get_scope();
nexus_private_t *priv =
static_cast<nexus_private_t*>(ivl_nexus_get_private(nexus));
assert(priv);
if (!visible_nexus(priv, arch_scope)) {
// This nexus isn't attached to anything in the parent
return;
}
vhdl_var_ref *ref = nexus_to_var_ref(parent->get_arch()->get_scope(), nexus);
string name = make_safe_name(to);
// If we're mapping an output of this entity to an output of
// the child entity, then VHDL will not let us read the value
// of the signal (i.e. it must pass straight through).
// However, Verilog allows the signal to be read in the parent.
// The VHDL equivalent of this is to make *both* output ports
// a `buffer'.
vhdl_decl *decl =
parent->get_arch()->get_scope()->get_decl(ref->get_name());
vhdl_port_decl *pdecl;
if ((pdecl = dynamic_cast<vhdl_port_decl*>(decl))
&& pdecl->get_mode() == VHDL_PORT_OUT) {
// First change the mode in the parent entity
pdecl->set_mode(VHDL_PORT_BUFFER);
// Now change the mode in the child entity
vhdl_port_decl *to_pdecl =
dynamic_cast<vhdl_port_decl*>(find_scope_for_signal(to)->get_decl(name));
assert(to_pdecl);
to_pdecl->set_mode(VHDL_PORT_BUFFER);
}
inst->map_port(name.c_str(), ref);
}
/*
* Find all the port mappings of a module instantiation.
*/
static void port_map(ivl_scope_t scope, vhdl_entity *parent,
vhdl_comp_inst *inst)
{
// Find all the port mappings
int nsigs = ivl_scope_sigs(scope);
for (int i = 0; i < nsigs; i++) {
ivl_signal_t sig = ivl_scope_sig(scope, i);
ivl_signal_port_t mode = ivl_signal_port(sig);
switch (mode) {
case IVL_SIP_NONE:
// Internal signals don't appear in the port map
break;
case IVL_SIP_INPUT:
case IVL_SIP_OUTPUT:
case IVL_SIP_INOUT:
map_signal(sig, parent, inst);
break;
default:
assert(false);
}
}
}
/*
* Create a VHDL function from a Verilog function definition.
*/
static int draw_function(ivl_scope_t scope, ivl_scope_t parent)
{
assert(ivl_scope_type(scope) == IVL_SCT_FUNCTION);
// Find the containing entity
vhdl_entity *ent = find_entity(ivl_scope_name(parent));
assert(ent);
const char *funcname = ivl_scope_tname(scope);
assert(!ent->get_arch()->get_scope()->have_declared(funcname));
// The return type is worked out from the output port
vhdl_function *func = new vhdl_function(funcname, NULL);
int nsigs = ivl_scope_sigs(scope);
for (int i = 0; i < nsigs; i++) {
ivl_signal_t sig = ivl_scope_sig(scope, i);
vhdl_type *sigtype =
vhdl_type::type_for(ivl_signal_width(sig),
ivl_signal_signed(sig) != 0);
string signame(make_safe_name(sig));
switch (ivl_signal_port(sig)) {
case IVL_SIP_INPUT:
func->add_param(new vhdl_param_decl(signame.c_str(), sigtype));
break;
case IVL_SIP_OUTPUT:
// The magic variable Verilog_Result holds the return value
signame = "Verilog_Result";
func->set_type(new vhdl_type(*sigtype));
default:
func->get_scope()->add_decl
(new vhdl_var_decl(signame.c_str(), sigtype));
}
remember_signal(sig, func->get_scope());
rename_signal(sig, signame);
}
// Non-blocking assignment not allowed in functions
func->get_scope()->set_allow_signal_assignment(false);
set_active_entity(ent);
{
draw_stmt(func, func->get_container(), ivl_scope_def(scope));
}
set_active_entity(NULL);
// Add a forward declaration too in case it is called by
// another function that has already been added
ent->get_arch()->get_scope()->add_forward_decl
(new vhdl_forward_fdecl(func));
ostringstream ss;
ss << "Generated from function " << funcname << " at "
<< ivl_scope_def_file(scope) << ":" << ivl_scope_def_lineno(scope);
func->set_comment(ss.str().c_str());
ent->get_arch()->get_scope()->add_decl(func);
return 0;
}
/*
* Create the signals necessary to expand this task later.
*/
static int draw_task(ivl_scope_t scope, ivl_scope_t parent)
{
assert(ivl_scope_type(scope) == IVL_SCT_TASK);
// Find the containing entity
vhdl_entity *ent = find_entity(ivl_scope_name(parent));
assert(ent);
const char *taskname = ivl_scope_tname(scope);
int nsigs = ivl_scope_sigs(scope);
for (int i = 0; i < nsigs; i++) {
ivl_signal_t sig = ivl_scope_sig(scope, i);
vhdl_type *sigtype =
vhdl_type::type_for(ivl_signal_width(sig),
ivl_signal_signed(sig) != 0);
string signame(make_safe_name(sig));
// Check this signal isn't declared in the outer scope
if (ent->get_arch()->get_scope()->have_declared(signame)) {
signame += "_";
signame += taskname;
}
vhdl_signal_decl *decl = new vhdl_signal_decl(signame.c_str(), sigtype);
ostringstream ss;
ss << "Declared at " << ivl_signal_file(sig) << ":"
<< ivl_signal_lineno(sig) << " (in task " << taskname << ")";
decl->set_comment(ss.str().c_str());
ent->get_arch()->get_scope()->add_decl(decl);
remember_signal(sig, ent->get_arch()->get_scope());
rename_signal(sig, signame);
}
return 0;
}
/*
* Create an empty VHDL entity for a Verilog module.
*/
static void create_skeleton_entity_for(ivl_scope_t scope)
{
assert(ivl_scope_type(scope) == IVL_SCT_MODULE);
// The type name will become the entity name
const char *tname = ivl_scope_tname(scope);
// Remember the scope name this entity was derived from so
// the correct processes can be added later
const char *derived_from = ivl_scope_name(scope);
// Verilog does not have the entity/architecture distinction
// so we always create a pair and associate the architecture
// with the entity for convenience (this also means that we
// retain a 1-to-1 mapping of scope to VHDL element)
vhdl_arch *arch = new vhdl_arch(tname, "FromVerilog");
vhdl_entity *ent = new vhdl_entity(tname, derived_from, arch);
// Build a comment to add to the entity/architecture
ostringstream ss;
ss << "Generated from Verilog module " << ivl_scope_tname(scope)
<< " (" << ivl_scope_def_file(scope) << ":"
<< ivl_scope_def_lineno(scope) << ")";
arch->set_comment(ss.str());
ent->set_comment(ss.str());
remember_entity(ent);
}
/*
* A first pass through the hierarchy: create VHDL entities for
* each unique Verilog module type.
*/
static int draw_skeleton_scope(ivl_scope_t scope, void *_parent)
{
if (ivl_scope_type(scope) == IVL_SCT_MODULE)
create_skeleton_entity_for(scope);
return ivl_scope_children(scope, draw_skeleton_scope, scope);
}
static int draw_all_signals(ivl_scope_t scope, void *_parent)
{
if (ivl_scope_type(scope) == IVL_SCT_MODULE) {
vhdl_entity *ent = find_entity(ivl_scope_name(scope));
assert(ent);
declare_signals(ent, scope);
}
return ivl_scope_children(scope, draw_all_signals, scope);
}
/*
* Draw all tasks and functions in the hierarchy.
*/
static int draw_functions(ivl_scope_t scope, void *_parent)
{
ivl_scope_t parent = static_cast<ivl_scope_t>(_parent);
if (ivl_scope_type(scope) == IVL_SCT_FUNCTION) {
if (draw_function(scope, parent) != 0)
return 1;
}
else if (ivl_scope_type(scope) == IVL_SCT_TASK) {
if (draw_task(scope, parent) != 0)
return 1;
}
return ivl_scope_children(scope, draw_functions, scope);
}
/*
* Make concurrent assignments for constants in nets. This works
* bottom-up so that the driver is in the lowest instance it can.
* This also has the side effect of generating all the necessary
* nexus code.
*/
static int draw_constant_drivers(ivl_scope_t scope, void *_parent)
{
ivl_scope_children(scope, draw_constant_drivers, scope);
if (ivl_scope_type(scope) == IVL_SCT_MODULE) {
vhdl_entity *ent = find_entity(ivl_scope_name(scope));
assert(ent);
int nsigs = ivl_scope_sigs(scope);
for (int i = 0; i < nsigs; i++) {
ivl_signal_t sig = ivl_scope_sig(scope, i);
for (unsigned i = ivl_signal_array_base(sig);
i < ivl_signal_array_count(sig);
i++) {
// Make sure the nexus code is generated
ivl_nexus_t nex = ivl_signal_nex(sig, i);
seen_nexus(nex);
nexus_private_t *priv =
static_cast<nexus_private_t*>(ivl_nexus_get_private(nex));
assert(priv);
vhdl_scope *arch_scope = ent->get_arch()->get_scope();
if (priv->const_driver) {
assert(i == 0); // TODO: Make work for more words
vhdl_var_ref *ref = nexus_to_var_ref(arch_scope, nex);
ent->get_arch()->add_stmt
(new vhdl_cassign_stmt(ref, priv->const_driver));
priv->const_driver = NULL;
}
scope_nexus_t *sn = visible_nexus(priv, arch_scope);
for (list<ivl_signal_t>::const_iterator it = sn->connect.begin();
it != sn->connect.end();
++it) {
vhdl_var_ref *rref =
new vhdl_var_ref(get_renamed_signal(sn->sig).c_str(), NULL);
vhdl_var_ref *lref =
new vhdl_var_ref(get_renamed_signal(*it).c_str(), NULL);
ent->get_arch()->add_stmt(new vhdl_cassign_stmt(lref, rref));
}
sn->connect.clear();
}
}
}
return 0;
}
static int draw_all_logic_and_lpm(ivl_scope_t scope, void *_parent)
{
if (ivl_scope_type(scope) == IVL_SCT_MODULE) {
vhdl_entity *ent = find_entity(ivl_scope_name(scope));
assert(ent);
set_active_entity(ent);
{
declare_logic(ent->get_arch(), scope);
declare_lpm(ent->get_arch(), scope);
}
set_active_entity(NULL);
}
return ivl_scope_children(scope, draw_all_logic_and_lpm, scope);
}
static int draw_hierarchy(ivl_scope_t scope, void *_parent)
{
if (ivl_scope_type(scope) == IVL_SCT_MODULE && _parent) {
ivl_scope_t parent = static_cast<ivl_scope_t>(_parent);
vhdl_entity *ent = find_entity(ivl_scope_name(scope));
assert(ent);
vhdl_entity *parent_ent = find_entity(ivl_scope_name(parent));
assert(parent_ent);
vhdl_arch *parent_arch = parent_ent->get_arch();
assert(parent_arch != NULL);
// Create a forward declaration for it
if (!parent_arch->get_scope()->have_declared(ent->get_name())) {
vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent);
parent_arch->get_scope()->add_decl(comp_decl);
}
// And an instantiation statement
string inst_name(ivl_scope_basename(scope));
if (inst_name == ent->get_name()) {
// Cannot have instance name the same as type in VHDL
inst_name += "_Inst";
}
// Need to replace any [ and ] characters that result
// from generate statements
string::size_type loc = inst_name.find('[', 0);
if (loc != string::npos)
inst_name.erase(loc, 1);
loc = inst_name.find(']', 0);
if (loc != string::npos)
inst_name.erase(loc, 1);
vhdl_comp_inst *inst =
new vhdl_comp_inst(inst_name.c_str(), ent->get_name().c_str());
port_map(scope, parent_ent, inst);
ostringstream ss;
ss << "Generated from instantiation at "
<< ivl_scope_file(scope) << ":" << ivl_scope_lineno(scope);
inst->set_comment(ss.str().c_str());
parent_arch->add_stmt(inst);
}
return ivl_scope_children(scope, draw_hierarchy, scope);
}
int draw_scope(ivl_scope_t scope, void *_parent)
{
int rc = draw_skeleton_scope(scope, _parent);
if (rc != 0)
return rc;
rc = draw_all_signals(scope, _parent);
if (rc != 0)
return rc;
rc = draw_all_logic_and_lpm(scope, _parent);
if (rc != 0)
return rc;
rc = draw_hierarchy(scope, _parent);
if (rc != 0)
return rc;
rc = draw_functions(scope, _parent);
if (rc != 0)
return rc;
rc = draw_constant_drivers(scope, _parent);
if (rc != 0)
return rc;
return 0;
}
+697
View File
@@ -0,0 +1,697 @@
/*
* VHDL code generation for statements.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_target.h"
#include <iostream>
#include <cstring>
#include <cassert>
#include <sstream>
#include <typeinfo>
/*
* VHDL has no real equivalent of Verilog's $finish task. The
* current solution is to use `assert false ...' to terminate
* the simulator. This isn't great, as the simulator will
* return a failure exit code when in fact it completed
* successfully.
*
* An alternative is to use the VHPI interface supported by
* some VHDL simulators and implement the $finish funcitonality
* in C. This function can be enabled with the flag
* -puse-vhpi-finish=1.
*/
static int draw_stask_finish(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt)
{
const char *use_vhpi = ivl_design_flag(get_vhdl_design(), "use-vhpi-finish");
if (strcmp(use_vhpi, "1") == 0) {
//get_active_entity()->requires_package("work.Verilog_Support");
container->add_stmt(new vhdl_pcall_stmt("work.Verilog_Support.Finish"));
}
else {
container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED"));
}
return 0;
}
/*
* Generate VHDL for system tasks (like $display). Not all of
* these are supported.
*/
static int draw_stask(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt)
{
const char *name = ivl_stmt_name(stmt);
if (strcmp(name, "$display") == 0)
return draw_stask_display(proc, container, stmt, true);
else if (strcmp(name, "$write") == 0)
return draw_stask_display(proc, container, stmt, false);
else if (strcmp(name, "$finish") == 0)
return draw_stask_finish(proc, container, stmt);
else {
error("No VHDL translation for system task %s", name);
return 0;
}
}
/*
* Generate VHDL for a block of Verilog statements. This doesn't
* actually do anything, other than recursively translate the
* block's statements and add them to the process. This is OK as
* the stmt_container class behaves like a Verilog block.
*/
static int draw_block(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool is_last)
{
int count = ivl_stmt_block_count(stmt);
for (int i = 0; i < count; i++) {
ivl_statement_t stmt_i = ivl_stmt_block_stmt(stmt, i);
if (draw_stmt(proc, container, stmt_i, is_last && i == count - 1) != 0)
return 1;
}
return 0;
}
/*
* A no-op statement. This corresponds to a `null' statement in VHDL.
*/
static int draw_noop(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt)
{
container->add_stmt(new vhdl_null_stmt());
return 0;
}
static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope)
{
ivl_signal_t sig = ivl_lval_sig(lval);
if (!sig) {
error("Only signals as lvals supported at the moment");
return NULL;
}
vhdl_expr *base = NULL;
ivl_expr_t e_off = ivl_lval_part_off(lval);
if (NULL == e_off)
e_off = ivl_lval_idx(lval);
if (e_off) {
if ((base = translate_expr(e_off)) == NULL)
return NULL;
vhdl_type integer(VHDL_TYPE_INTEGER);
base = base->cast(&integer);
}
unsigned lval_width = ivl_lval_width(lval);
string signame(get_renamed_signal(sig));
vhdl_decl *decl = scope->get_decl(signame);
assert(decl);
vhdl_type *ltype = new vhdl_type(*decl->get_type());
vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype);
if (base) {
if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY)
lval_ref->set_slice(base, 0);
else
lval_ref->set_slice(base, lval_width - 1);
}
return lval_ref;
}
static bool assignment_lvals(ivl_statement_t stmt, vhdl_procedural *proc,
list<vhdl_var_ref*> &lvals)
{
int nlvals = ivl_stmt_lvals(stmt);
for (int i = 0; i < nlvals; i++) {
ivl_lval_t lval = ivl_stmt_lval(stmt, i);
vhdl_var_ref *lhs = make_assign_lhs(lval, proc->get_scope());
if (NULL == lhs)
return false;
lvals.push_back(lhs);
}
return true;
}
/*
* Generate an assignment of type T for the Verilog statement stmt.
*/
template <class T>
void make_assignment(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool blocking)
{
list<vhdl_var_ref*> lvals;
if (!assignment_lvals(stmt, proc, lvals))
return;
vhdl_expr *rhs, *rhs2 = NULL;
ivl_expr_t rval = ivl_stmt_rval(stmt);
if (ivl_expr_type(rval) == IVL_EX_TERNARY) {
rhs = translate_expr(ivl_expr_oper2(rval));
rhs2 = translate_expr(ivl_expr_oper3(rval));
}
else
rhs = translate_expr(rval);
if (rhs == NULL)
return;
if (lvals.size() == 1) {
vhdl_var_ref *lhs = lvals.front();
rhs = rhs->cast(lhs->get_type());
ivl_expr_t i_delay;
vhdl_expr *after = NULL;
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL)
after = translate_time_expr(i_delay);
// A small optimisation is to expand ternary RHSs into an
// if statement (eliminates a function call and produces
// more idiomatic code)
if (ivl_expr_type(rval) == IVL_EX_TERNARY) {
rhs2 = rhs2->cast(lhs->get_type());
vhdl_var_ref *lhs2 =
make_assign_lhs(ivl_stmt_lval(stmt, 0), proc->get_scope());
vhdl_expr *test = translate_expr(ivl_expr_oper1(rval));
if (NULL == test)
return;
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
// True part
{
T *a = new T(lhs, rhs);
if (after)
a->set_after(after);
vhdif->get_then_container()->add_stmt(a);
}
// False part
{
T *a = new T(lhs2, rhs2);
if (after)
a->set_after(translate_time_expr(i_delay));
vhdif->get_else_container()->add_stmt(a);
}
container->add_stmt(vhdif);
return;
}
// Where possible, move constant assignments into the
// declaration as initializers. This optimisation is only
// performed on assignments of constant values to prevent
// ordering problems.
// This also has another application: If this is an `inital'
// process and we haven't yet generated a `wait' statement then
// moving the assignment to the initialization preserves the
// expected Verilog behaviour: VHDL does not distinguish
// `initial' and `always' processes so an `always' process might
// be activatated before an `initial' process at time 0. The
// `always' process may then use the uninitialized signal value.
// The second test ensures that we only try to initialise
// internal signals not ports
ivl_lval_t lval = ivl_stmt_lval(stmt, 0);
vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name());
if (proc->get_scope()->initializing()
&& ivl_signal_port(ivl_lval_sig(lval)) == IVL_SIP_NONE
&& !decl->has_initial()
&& rhs->constant()
&& decl->get_type()->get_name() != VHDL_TYPE_ARRAY) {
// If this assignment is not in the top-level container
// it will not be made on all paths through the code
// This precludes any future extraction of an initialiser
if (container != proc->get_container())
decl->set_initial(NULL); // Default initial value
else {
decl->set_initial(rhs);
delete lhs;
return;
}
}
T *a = new T(lhs, rhs);
container->add_stmt(a);
if (after != NULL)
a->set_after(after);
}
else {
// Multiple lvals are implemented by first assigning the complete
// RHS to a temporary, and then assigning each lval in turn as
// bit-selects of the temporary
static int tmp_count = 0;
ostringstream ss;
ss << "Verilog_Assign_Tmp_" << tmp_count++;
string tmpname = ss.str();
proc->get_scope()->add_decl
(new vhdl_var_decl(tmpname.c_str(), new vhdl_type(*rhs->get_type())));
vhdl_var_ref *tmp_ref =
new vhdl_var_ref(tmpname.c_str(), new vhdl_type(*rhs->get_type()));
container->add_stmt(new vhdl_assign_stmt(tmp_ref, rhs));
list<vhdl_var_ref*>::iterator it;
int width_so_far = 0;
for (it = lvals.begin(); it != lvals.end(); ++it) {
vhdl_var_ref *tmp_rhs =
new vhdl_var_ref(tmpname.c_str(), new vhdl_type(*rhs->get_type()));
int lval_width = (*it)->get_type()->get_width();
vhdl_expr *slice_base = new vhdl_const_int(width_so_far);
tmp_rhs->set_slice(slice_base, lval_width - 1);
ivl_expr_t i_delay;
vhdl_expr *after = NULL;
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL)
after = translate_time_expr(i_delay);
T *a = new T(*it, tmp_rhs);
if (after)
a->set_after(after);
container->add_stmt(a);
width_so_far += lval_width;
}
}
}
/*
* A non-blocking assignment inside a process. The semantics for
* this are essentially the same as VHDL's non-blocking signal
* assignment.
*/
static int draw_nbassign(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt)
{
assert(proc->get_scope()->allow_signal_assignment());
make_assignment<vhdl_nbassign_stmt>(proc, container, stmt, false);
return 0;
}
static int draw_assign(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool is_last)
{
if (proc->get_scope()->allow_signal_assignment()) {
// Blocking assignment is implemented as non-blocking assignment
// followed by a zero-time wait
// This follows the Verilog semantics fairly closely.
make_assignment<vhdl_nbassign_stmt>(proc, container, stmt, false);
// Don't generate a zero-wait if this is the last statement in
// the process
if (!is_last)
container->add_stmt
(new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0)));
}
else
make_assignment<vhdl_assign_stmt>(proc, container, stmt, true);
return 0;
}
/*
* Delay statements are equivalent to the `wait for' form of the
* VHDL wait statement.
*/
static int draw_delay(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt)
{
// This currently ignores the time units and precision
// of the enclosing scope
// A neat way to do this would be to make these values
// constants in the scope (type is Time), and have the
// VHDL wait statement compute the value from that.
// The other solution is to add them as parameters to
// the vhdl_process class
vhdl_expr *time;
if (ivl_statement_type(stmt) == IVL_ST_DELAY) {
uint64_t value = ivl_stmt_delay_val(stmt);
time = new vhdl_const_time(value, TIME_UNIT_NS);
}
else {
time = translate_time_expr(ivl_stmt_delay_expr(stmt));
if (NULL == time)
return 1;
}
ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt);
vhdl_wait_stmt *wait =
new vhdl_wait_stmt(VHDL_WAIT_FOR, time);
container->add_stmt(wait);
// Expand the sub-statement as well
// Often this would result in a useless `null' statement which
// is caught here instead
if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP)
draw_stmt(proc, container, sub_stmt);
// Any further assignments occur after simulation time 0
// so they cannot be used to initialize signal declarations
// (if this scope is an initial process)
proc->get_scope()->set_initializing(false);
return 0;
}
/*
* A wait statement waits for a level change on a @(..) list of
* signals. Purely combinatorial processes (i.e. no posedge/negedge
* events) produce a `wait on' statement at the end of the process.
* Sequential processes produce a `wait until' statement at the
* start of the process.
*/
static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
ivl_statement_t stmt)
{
// Wait statements only occur in processes
vhdl_process *proc = dynamic_cast<vhdl_process*>(_proc);
assert(proc); // Catch not process
vhdl_binop_expr *test =
new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean());
int nevents = ivl_stmt_nevent(stmt);
bool combinatorial = true; // True if no negedge/posedge events
for (int i = 0; i < nevents; i++) {
ivl_event_t event = ivl_stmt_events(stmt, i);
if (ivl_event_npos(event) > 0 || ivl_event_nneg(event) > 0)
combinatorial = false;
}
if (combinatorial) {
vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_ON);
for (int i = 0; i < nevents; i++) {
ivl_event_t event = ivl_stmt_events(stmt, i);
int nany = ivl_event_nany(event);
for (int i = 0; i < nany; i++) {
ivl_nexus_t nexus = ivl_event_any(event, i);
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
wait->add_sensitivity(ref->get_name());
delete ref;
}
}
draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt), true);
container->add_stmt(wait);
}
else {
for (int i = 0; i < nevents; i++) {
ivl_event_t event = ivl_stmt_events(stmt, i);
int nany = ivl_event_nany(event);
for (int i = 0; i < nany; i++) {
ivl_nexus_t nexus = ivl_event_any(event, i);
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
ref->set_name(ref->get_name() + "'Event");
test->add_expr(ref);
}
int nneg = ivl_event_nneg(event);
for (int i = 0; i < nneg; i++) {
ivl_nexus_t nexus = ivl_event_neg(event, i);
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
vhdl_fcall *detect =
new vhdl_fcall("falling_edge", vhdl_type::boolean());
detect->add_expr(ref);
test->add_expr(detect);
}
int npos = ivl_event_npos(event);
for (int i = 0; i < npos; i++) {
ivl_nexus_t nexus = ivl_event_pos(event, i);
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
vhdl_fcall *detect =
new vhdl_fcall("rising_edge", vhdl_type::boolean());
detect->add_expr(ref);
test->add_expr(detect);
}
}
container->add_stmt(new vhdl_wait_stmt(VHDL_WAIT_UNTIL, test));
draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt), true);
}
return 0;
}
static int draw_if(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool is_last)
{
vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
if (NULL == test)
return 1;
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
ivl_statement_t cond_true_stmt = ivl_stmt_cond_true(stmt);
if (cond_true_stmt)
draw_stmt(proc, vhdif->get_then_container(), cond_true_stmt, is_last);
ivl_statement_t cond_false_stmt = ivl_stmt_cond_false(stmt);
if (cond_false_stmt)
draw_stmt(proc, vhdif->get_else_container(), cond_false_stmt, is_last);
container->add_stmt(vhdif);
return 0;
}
static int draw_case(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool is_last)
{
vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
if (NULL == test)
return 1;
// VHDL case expressions are required to be quite simple: variable
// references or slices. So we may need to create a temporary
// variable to hold the result of the expression evaluation
if (typeid(*test) != typeid(vhdl_var_ref)) {
const char *tmp_name = "Verilog_Case_Ex";
vhdl_type *test_type = new vhdl_type(*test->get_type());
if (!proc->get_scope()->have_declared(tmp_name)) {
proc->get_scope()->add_decl
(new vhdl_var_decl(tmp_name, new vhdl_type(*test_type)));
}
vhdl_var_ref *tmp_ref = new vhdl_var_ref(tmp_name, NULL);
container->add_stmt(new vhdl_assign_stmt(tmp_ref, test));
test = new vhdl_var_ref(tmp_name, test_type);
}
vhdl_case_stmt *vhdlcase = new vhdl_case_stmt(test);
container->add_stmt(vhdlcase);
// VHDL is more strict than Verilog about covering every
// possible case. So make sure we add an 'others' branch
// if there isn't a default one.
bool have_others = false;
int nbranches = ivl_stmt_case_count(stmt);
for (int i = 0; i < nbranches; i++) {
vhdl_expr *when;
ivl_expr_t net = ivl_stmt_case_expr(stmt, i);
if (net) {
when = translate_expr(net)->cast(test->get_type());
if (NULL == when)
return 1;
}
else {
when = new vhdl_var_ref("others", NULL);
have_others = true;
}
vhdl_case_branch *branch = new vhdl_case_branch(when);
vhdlcase->add_branch(branch);
ivl_statement_t stmt_i = ivl_stmt_case_stmt(stmt, i);
draw_stmt(proc, branch->get_container(), stmt_i, is_last);
}
if (!have_others) {
vhdl_case_branch *others =
new vhdl_case_branch(new vhdl_var_ref("others", NULL));
others->get_container()->add_stmt(new vhdl_null_stmt());
vhdlcase->add_branch(others);
}
return 0;
}
int draw_while(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt)
{
vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
if (NULL == test)
return 1;
// The test must be a Boolean (and std_logic and (un)signed types
// must be explicitly cast unlike in Verilog)
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
test = test->cast(&boolean);
vhdl_while_stmt *loop = new vhdl_while_stmt(test);
container->add_stmt(loop);
draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt));
return 0;
}
int draw_forever(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt)
{
vhdl_loop_stmt *loop = new vhdl_loop_stmt;
container->add_stmt(loop);
draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt));
return 0;
}
int draw_repeat(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt)
{
vhdl_expr *times = translate_expr(ivl_stmt_cond_expr(stmt));
if (NULL == times)
return 1;
vhdl_type integer(VHDL_TYPE_INTEGER);
times = times->cast(&integer);
const char *it_name = "Verilog_Repeat";
vhdl_for_stmt *loop =
new vhdl_for_stmt(it_name, new vhdl_const_int(1), times);
container->add_stmt(loop);
draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt));
return 0;
}
/*
* Tasks are difficult to translate to VHDL since they allow things
* not allowed by VHDL's corresponding procedures (e.g. updating
* global variables. The solution here is to expand tasks in-line.
*/
int draw_utask(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt)
{
ivl_scope_t tscope = ivl_stmt_call(stmt);
// TODO: adding some comments to the output would be helpful
// TOOD: this completely ignores paremeters!
draw_stmt(proc, container, ivl_scope_def(tscope), false);
return 0;
}
/*
* Generate VHDL statements for the given Verilog statement and
* add them to the given VHDL process. The container is the
* location to add statements: e.g. the process body, a branch
* of an if statement, etc.
*
* The flag is_last should be set if this is the final statement
* in a block or process. It avoids generating useless `wait for 0ns'
* statements if the next statement would be a wait anyway.
*/
int draw_stmt(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool is_last)
{
assert(stmt);
switch (ivl_statement_type(stmt)) {
case IVL_ST_STASK:
return draw_stask(proc, container, stmt);
case IVL_ST_BLOCK:
return draw_block(proc, container, stmt, is_last);
case IVL_ST_NOOP:
return draw_noop(proc, container, stmt);
case IVL_ST_ASSIGN:
return draw_assign(proc, container, stmt, is_last);
case IVL_ST_ASSIGN_NB:
return draw_nbassign(proc, container, stmt);
case IVL_ST_DELAY:
case IVL_ST_DELAYX:
return draw_delay(proc, container, stmt);
case IVL_ST_WAIT:
return draw_wait(proc, container, stmt);
case IVL_ST_CONDIT:
return draw_if(proc, container, stmt, is_last);
case IVL_ST_CASE:
return draw_case(proc, container, stmt, is_last);
case IVL_ST_WHILE:
return draw_while(proc, container, stmt);
case IVL_ST_FOREVER:
return draw_forever(proc, container, stmt);
case IVL_ST_REPEAT:
return draw_repeat(proc, container, stmt);
case IVL_ST_UTASK:
return draw_utask(proc, container, stmt);
case IVL_ST_FORCE:
case IVL_ST_RELEASE:
error("force/release statements cannot be translated to VHDL");
return 1;
case IVL_ST_DISABLE:
error("disable statement cannot be translated to VHDL");
return 1;
case IVL_ST_CASEX:
error("casex statement cannot be translated to VHDL");
return 1;
case IVL_ST_FORK:
error("fork statement cannot be translated to VHDL");
return 1;
case IVL_ST_CASSIGN:
case IVL_ST_DEASSIGN:
error("continuous procedural assignment cannot be translated to VHDL");
return 1;
default:
error("No VHDL translation for statement at %s:%d (type = %d)",
ivl_stmt_file(stmt), ivl_stmt_lineno(stmt),
ivl_statement_type(stmt));
return 1;
}
}
+157
View File
@@ -0,0 +1,157 @@
/*
* Support functions for VHDL output.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_target.h"
#include "support.hh"
#include <cassert>
#include <iostream>
void require_support_function(support_function_t f)
{
vhdl_scope *scope = get_active_entity()->get_arch()->get_scope();
if (!scope->have_declared(support_function::function_name(f)))
scope->add_decl(new support_function(f));
}
const char *support_function::function_name(support_function_t type)
{
switch (type) {
case SF_UNSIGNED_TO_BOOLEAN: return "Unsigned_To_Boolean";
case SF_SIGNED_TO_BOOLEAN: return "Signed_To_Boolean";
case SF_BOOLEAN_TO_LOGIC: return "Boolean_To_Logic";
case SF_REDUCE_OR: return "Reduce_OR";
case SF_REDUCE_AND: return "Reduce_AND";
case SF_REDUCE_XOR: return "Reduce_XOR";
case SF_TERNARY_LOGIC: return "Ternary_Logic";
case SF_TERNARY_UNSIGNED: return "Ternary_Unsigned";
case SF_TERNARY_SIGNED: return "Ternary_Signed";
case SF_LOGIC_TO_INTEGER: return "Logic_To_Integer";
default:
assert(false);
}
}
vhdl_type *support_function::function_type(support_function_t type)
{
switch (type) {
case SF_UNSIGNED_TO_BOOLEAN:
case SF_SIGNED_TO_BOOLEAN:
return vhdl_type::boolean();
case SF_BOOLEAN_TO_LOGIC:
case SF_REDUCE_OR:
case SF_REDUCE_AND:
case SF_REDUCE_XOR:
case SF_TERNARY_LOGIC:
return vhdl_type::std_logic();
case SF_TERNARY_SIGNED:
return new vhdl_type(VHDL_TYPE_SIGNED);
case SF_TERNARY_UNSIGNED:
return new vhdl_type(VHDL_TYPE_UNSIGNED);
case SF_LOGIC_TO_INTEGER:
return vhdl_type::integer();
default:
assert(false);
}
}
void support_function::emit_ternary(std::ostream &of, int level) const
{
of << nl_string(level) << "begin" << nl_string(indent(level))
<< "if T then return X; else return Y; end if;";
}
void support_function::emit(std::ostream &of, int level) const
{
of << nl_string(level) << "function " << function_name(type_);
switch (type_) {
case SF_UNSIGNED_TO_BOOLEAN:
of << "(X : unsigned) return Boolean is" << nl_string(level)
<< "begin" << nl_string(indent(level))
<< "return X /= To_Unsigned(0, X'Length);";
break;
case SF_SIGNED_TO_BOOLEAN:
of << "(X : signed) return Boolean is" << nl_string(level)
<< "begin" << nl_string(indent(level))
<< "return X /= To_Signed(0, X'Length);";
break;
case SF_BOOLEAN_TO_LOGIC:
of << "(B : Boolean) return std_logic is" << nl_string(level)
<< "begin" << nl_string(indent(level))
<< "if B then" << nl_string(indent(indent(level)))
<< "return '1';" << nl_string(indent(level))
<< "else" << nl_string(indent(indent(level)))
<< "return '0';" << nl_string(indent(level))
<< "end if;";
break;
case SF_REDUCE_OR:
of << "(X : std_logic_vector) return std_logic is" << nl_string(level)
<< "begin" << nl_string(indent(level))
<< "for I in X'Range loop" << nl_string(indent(indent(level)))
<< "if X(I) = '1' then" << nl_string(indent(indent(indent(level))))
<< "return '1';" << nl_string(indent(indent(level)))
<< "end if;" << nl_string(indent(level))
<< "end loop;" << nl_string(indent(level))
<< "return '0';";
break;
case SF_REDUCE_AND:
of << "(X : std_logic_vector) return std_logic is" << nl_string(level)
<< "begin" << nl_string(indent(level))
<< "for I in X'Range loop" << nl_string(indent(indent(level)))
<< "if X(I) = '0' then" << nl_string(indent(indent(indent(level))))
<< "return '0';" << nl_string(indent(indent(level)))
<< "end if;" << nl_string(indent(level))
<< "end loop;" << nl_string(indent(level))
<< "return '1';";
break;
case SF_REDUCE_XOR:
of << "(X : std_logic_vector) return std_logic is"
<< nl_string(indent(level))
<< "variable R : std_logic := '0';" << nl_string(level)
<< "begin" << nl_string(indent(level))
<< "for I in X'Range loop" << nl_string(indent(indent(level)))
<< "R := X(I) xor R;" << nl_string(indent(level))
<< "end loop;" << nl_string(indent(level))
<< "return R;";
break;
case SF_TERNARY_LOGIC:
of << "(T : Boolean; X, Y : std_logic) return std_logic is";
emit_ternary(of, level);
break;
case SF_TERNARY_SIGNED:
of << "(T : Boolean; X, Y : signed) return signed is";
emit_ternary(of, level);
break;
case SF_TERNARY_UNSIGNED:
of << "(T : Boolean; X, Y : unsigned) return unsigned is";
emit_ternary(of, level);
break;
case SF_LOGIC_TO_INTEGER:
of << "(X : std_logic) return integer is" << nl_string(level)
<< "begin" << nl_string(indent(level))
<< "if X = '1' then return 1; else return 0; end if;";
break;
default:
assert(false);
}
of << nl_string(level) << "end function;";
}
+54
View File
@@ -0,0 +1,54 @@
/*
* Support functions for VHDL output.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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.
*/
#ifndef INC_SUPPORT_HH
#define INC_SUPPORT_HH
#include "vhdl_syntax.hh"
enum support_function_t {
SF_UNSIGNED_TO_BOOLEAN = 0,
SF_SIGNED_TO_BOOLEAN,
SF_BOOLEAN_TO_LOGIC,
SF_REDUCE_OR,
SF_REDUCE_AND,
SF_REDUCE_XOR,
SF_TERNARY_LOGIC,
SF_TERNARY_UNSIGNED,
SF_TERNARY_SIGNED,
SF_LOGIC_TO_INTEGER,
};
class support_function : public vhdl_function {
public:
support_function(support_function_t type)
: vhdl_function(function_name(type), function_type(type)),
type_(type) {}
void emit(std::ostream &of, int level) const;
static const char *function_name(support_function_t type);
static vhdl_type *function_type(support_function_t type);
private:
void emit_ternary(std::ostream &of, int level) const;
support_function_t type_;
};
#endif
+193
View File
@@ -0,0 +1,193 @@
/*
* VHDL code generator for Icarus Verilog.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_target.h"
#include "vhdl_element.hh"
#include <iostream>
#include <fstream>
#include <cstdarg>
#include <cstdio>
#include <cassert>
#include <cstring>
#include <list>
#include <map>
#include <set>
/*
* Maps a signal to the scope it is defined within. Also
* provides a mechanism for renaming signals -- i.e. when
* an output has the same name as register: valid in Verilog
* but not in VHDL, so two separate signals need to be
* defined.
*/
struct signal_defn_t {
std::string renamed; // The name of the VHDL signal
vhdl_scope *scope; // The scope where it is defined
};
typedef std::map<ivl_signal_t, signal_defn_t> signal_defn_map_t;
static int g_errors = 0; // Total number of errors encountered
static entity_list_t g_entities; // All entities to emit
static signal_defn_map_t g_known_signals;
static ivl_design_t g_design;
/*
* Called when an unrecoverable problem is encountered.
*/
void error(const char *fmt, ...)
{
std::va_list args;
va_start(args, fmt);
std::printf("VHDL conversion error: "); // Source/line number?
std::vprintf(fmt, args);
std::putchar('\n');
va_end(args);
g_errors++;
}
/*
* Find an entity given a scope name.
*/
vhdl_entity *find_entity(const std::string &sname)
{
entity_list_t::const_iterator it;
for (it = g_entities.begin(); it != g_entities.end(); ++it) {
if ((*it)->get_derived_from() == sname)
return *it;
}
return NULL;
}
/*
* Add an entity/architecture pair to the list of entities
* to emit.
*/
void remember_entity(vhdl_entity* ent)
{
assert(find_entity(ent->get_derived_from()) == NULL);
g_entities.push_back(ent);
}
bool seen_signal_before(ivl_signal_t sig)
{
return g_known_signals.find(sig) != g_known_signals.end();
}
/*
* Remeber the association of signal to entity.
*/
void remember_signal(ivl_signal_t sig, vhdl_scope *scope)
{
assert(!seen_signal_before(sig));
signal_defn_t defn = { ivl_signal_basename(sig), scope };
g_known_signals[sig] = defn;
}
/*
* Change the VHDL name of a Verilog signal.
*/
void rename_signal(ivl_signal_t sig, const std::string &renamed)
{
assert(seen_signal_before(sig));
g_known_signals[sig].renamed = renamed;
}
vhdl_scope *find_scope_for_signal(ivl_signal_t sig)
{
assert(seen_signal_before(sig));
return g_known_signals[sig].scope;
}
const std::string &get_renamed_signal(ivl_signal_t sig)
{
assert(seen_signal_before(sig));
return g_known_signals[sig].renamed;
}
ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope)
{
signal_defn_map_t::const_iterator it;
for (it = g_known_signals.begin(); it != g_known_signals.end(); ++it) {
if (((*it).second.scope == scope
|| (*it).second.scope == scope->get_parent())
&& (*it).second.renamed == name)
return (*it).first;
}
assert(false);
}
ivl_design_t get_vhdl_design()
{
return g_design;
}
extern "C" int target_design(ivl_design_t des)
{
ivl_scope_t *roots;
unsigned int nroots;
ivl_design_roots(des, &roots, &nroots);
g_design = des;
for (unsigned int i = 0; i < nroots; i++)
draw_scope(roots[i], NULL);
ivl_design_process(des, draw_process, NULL);
// Write the generated elements to the output file
// only if there are no errors
if (0 == g_errors) {
const char *ofname = ivl_design_flag(des, "-o");
ofstream outfile(ofname);
// Make sure we only emit one example of each type of entity
set<string> seen_entities;
for (entity_list_t::iterator it = g_entities.begin();
it != g_entities.end();
++it) {
if (seen_entities.find((*it)->get_name()) == seen_entities.end()) {
(*it)->emit(outfile);
seen_entities.insert((*it)->get_name());
}
}
outfile.close();
}
// Clean up
for (entity_list_t::iterator it = g_entities.begin();
it != g_entities.end();
++it)
delete (*it);
g_entities.clear();
return g_errors;
}
+4
View File
@@ -0,0 +1,4 @@
functor:cprop
functor:nodangle
-t:dll
flag:DLL=vhdl.tgt
+49
View File
@@ -0,0 +1,49 @@
/* vhdl_config.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <malloc.h> header file. */
#undef HAVE_MALLOC_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
+87
View File
@@ -0,0 +1,87 @@
/*
* VHDL abstract syntax elements.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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 "vhdl_element.hh"
#include <algorithm>
#include <cassert>
#include <cstring>
#include <typeinfo>
#include <iostream>
#include <sstream>
static const int VHDL_INDENT = 2; // Spaces to indent
int indent(int level)
{
return level + VHDL_INDENT;
}
std::string nl_string(int level)
{
std::ostringstream ss;
newline(ss, level);
return ss.str();
}
/*
* Emit a newline and indent to the correct level.
*/
void newline(std::ostream &of, int level)
{
of << std::endl;
while (level--)
of << ' ';
}
void blank_line(std::ostream &of, int level)
{
of << std::endl;
newline(of, level);
}
void vhdl_element::set_comment(std::string comment)
{
comment_ = comment;
}
/*
* Draw the comment for any element. The comment is either on
* a line before the element (end_of_line is false) or at the
* end of the line containing the element (end_of_line is true).
*/
void vhdl_element::emit_comment(std::ostream &of, int level,
bool end_of_line) const
{
if (comment_.size() > 0) {
if (end_of_line)
of << " ";
of << "-- " << comment_;
if (!end_of_line)
newline(of, level);
}
}
void vhdl_element::print() const
{
emit(std::cout, 0);
std::cout << std::endl;
}
+56
View File
@@ -0,0 +1,56 @@
/*
* VHDL abstract syntax elements.
*
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
*
* 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.
*/
#ifndef INC_VHDL_ELEMENT_HH
#define INC_VHDL_ELEMENT_HH
#include <fstream>
#include <list>
#include <string>
typedef std::list<std::string> string_list_t;
/*
* Any VHDL syntax element. Each element can also contain a comment.
*/
class vhdl_element {
public:
virtual ~vhdl_element() {}
virtual void emit(std::ostream &of, int level=0) const = 0;
void print() const;
void set_comment(std::string comment);
protected:
void emit_comment(std::ostream &of, int level,
bool end_of_line=false) const;
private:
std::string comment_;
};
typedef std::list<vhdl_element*> element_list_t;
int indent(int level);
void newline(std::ostream &of, int level);
std::string nl_string(int level);
void blank_line(std::ostream &of, int level);
#endif

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