Compare commits

...
480 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
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
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
Nick Gasson d36bbec5b5 Generate VHDL for no-op statements 2008-06-05 13:16:35 +01: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
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
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
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
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
Nick Gasson fef0fd82ff Comments 2008-06-02 00:12:47 +01: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
Nick Gasson 05de2f56b4 Dummy code for processes 2008-05-30 01:04:47 +01:00
Nick Gasson e38494a10c Pretty-print VHDL output 2008-05-29 16:24:16 +01: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
153 changed files with 10485 additions and 2329 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
+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();
+9 -7
View File
@@ -22,6 +22,7 @@
# include <list>
# include <map>
# include <utility>
# include "svector.h"
# include "StringHeap.h"
# include "HName.h"
@@ -102,7 +103,7 @@ class Module : public PScope, public LineInfo {
bool signed_flag;
// Value expression
PExpr*expr;
// If there are range constrants, list them here
// If there are range constraints, list them here
range_t*range;
};
map<perm_string,param_expr_t>parameters;
@@ -118,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,
@@ -138,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;
@@ -152,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;
@@ -167,14 +171,12 @@ 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);
+1
View File
@@ -315,6 +315,7 @@ class PEIdent : public PExpr {
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;
+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;
+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)
{
}
+1 -1
View File
@@ -9,7 +9,7 @@
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=.. )
+2 -2
View File
@@ -122,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)
+26 -1
View File
@@ -302,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): " <<
@@ -1047,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 << " = " <<
@@ -1055,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="
+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
+13 -13
View File
@@ -328,23 +328,24 @@ static int t_default(char*cmd, unsigned ncmd)
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
}
@@ -505,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"
@@ -871,6 +872,7 @@ int main(int argc, char **argv)
}
fprintf(stderr, "Command signaled: %s\n", cmd);
free(cmd);
return -1;
}
@@ -889,6 +891,4 @@ int main(int argc, char **argv)
fclose(iconfig_file);
return t_default(cmd, ncmd);
return 0;
}
+12 -61
View File
@@ -1182,12 +1182,12 @@ NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
if (!flag)
return 0;
// Notice that the par_msv is not used is this function other
// then for this test. It is used to tell the direction that
// 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) {
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;
@@ -1373,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;
@@ -1567,9 +1567,11 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (sb_lsb == 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;
}
// If the part select covers NONE of the vector, then return a
// constant X.
@@ -1580,61 +1582,10 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
return tmp;
}
// If the part select is entirely within the vector, then make
// a simple part select.
if (sb_lsb >= 0 && sb_msb < (signed)net->vector_width()) {
NetExpr*ex = new NetEConst(verinum(sb_lsb));
NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this);
return ss;
}
// Now the hard stuff. The part select is falling off at least
// one end. We're going to need a NetEConcat to mix the
// selection with overrun.
NetEConst*bot = 0;
if (sb_lsb < 0) {
bot = make_const_x( 0-sb_lsb );
bot->set_line(*this);
sb_lsb = 0;
}
NetEConst*top = 0;
if (sb_msb >= (signed)net->vector_width()) {
top = make_const_x( 1+sb_msb-net->vector_width() );
top->set_line(*this);
sb_msb = net->vector_width()-1;
}
unsigned concat_count = 1;
if (bot) concat_count += 1;
if (top) concat_count += 1;
NetEConcat*concat = new NetEConcat(concat_count);
concat->set_line(*this);
if (bot) {
concat_count -= 1;
concat->set(concat_count, bot);
}
if (sb_lsb == 0 && sb_msb+1 == (signed)net->vector_width()) {
concat_count -= 1;
concat->set(concat_count, net);
} else {
NetExpr*ex = new NetEConst(verinum(sb_lsb));
ex->set_line(*this);
NetESelect*ss = new NetESelect(net, ex, 1+sb_msb-sb_lsb);
ss->set_line(*this);
concat_count -= 1;
concat->set(concat_count, ss);
}
if (top) {
concat_count -= 1;
concat->set(concat_count, top);
}
ivl_assert(*this, concat_count==0);
return concat;
NetExpr*ex = new NetEConst(verinum(sb_lsb));
NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this);
return ss;
}
/*
+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);
+47 -16
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;
@@ -1787,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
@@ -2296,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;
+234 -79
View File
@@ -53,7 +53,7 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
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;
@@ -71,19 +71,6 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
assert(lsb);
}
if (signed_flag) {
/* If explicitly signed, then say so. */
val->cast_signed(true);
} else if (cur.msb) {
/* If there is a range, then the signedness comes
from the type and not the expression. */
val->cast_signed(signed_flag);
} else {
/* otherwise, let the expression describe
itself. */
signed_flag = val->has_sign();
}
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;
@@ -118,13 +105,124 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
range_list = tmp;
}
val = scope->set_parameter(name, val, cur.type, msb, lsb, signed_flag, range_list, cur);
assert(val);
/* 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) {
/* If explicitly signed, then say so. */
val->cast_signed(true);
} else if (cur.msb) {
/* If there is a range, then the signedness comes
from the type and not the expression. */
val->cast_signed(signed_flag);
} else {
/* otherwise, let the expression describe
itself. */
signed_flag = val->has_sign();
}
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 "
@@ -143,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.
@@ -228,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
@@ -249,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.
@@ -422,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
@@ -469,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;
@@ -494,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.
@@ -536,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);
@@ -548,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 );
@@ -578,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;
@@ -605,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;
@@ -618,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() == "") {
@@ -668,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;
}
+214 -72
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;
}
@@ -946,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
@@ -1160,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. */
@@ -1178,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
@@ -1189,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
@@ -1952,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;
}
@@ -2625,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;
@@ -2956,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
@@ -3055,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;
}
@@ -3556,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.
@@ -3615,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
@@ -3681,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);
@@ -3724,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);
@@ -3733,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);
}
@@ -3762,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());
@@ -3772,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++) {
@@ -3791,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
+11 -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);
@@ -362,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 {
+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;
+2
View File
@@ -191,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
+5
View File
@@ -254,6 +254,8 @@ 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,
@@ -1693,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
+10 -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;
+1 -1
View File
@@ -843,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;
+1
View File
@@ -25,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
+42 -9
View File
@@ -54,6 +54,7 @@ const char NOTICE[] =
#endif
# include "pform.h"
# include "parse_api.h"
# include "PGenerate.h"
# include "netlist.h"
# include "target.h"
# include "compiler.h"
@@ -272,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
@@ -729,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()
@@ -907,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);
}
}
+118 -9
View File
@@ -20,6 +20,7 @@
# include "config.h"
# include <iostream>
# include <set>
# include <cstdlib>
/*
@@ -208,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();
@@ -222,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 "
@@ -235,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()
@@ -285,11 +357,11 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
/* Evaluate the parameter expression, if necessary. */
NetExpr*expr = (*cur).second.expr;
assert(expr);
if (expr == NULL) return; // This is an invalid parameter so return.
eval_expr(expr);
/* The eval_expr may delete any replace the expr pointer, so the
/* 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;
@@ -335,6 +407,14 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
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);
@@ -348,7 +428,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
tmp.has_sign ( (*cur).second.signed_flag );
delete val;
val = new NetEConst(tmp);
expr = val;
(*cur).second.expr = expr = val;
}
}
@@ -506,6 +586,9 @@ 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
@@ -540,6 +623,32 @@ void NetScope::evaluate_parameters(Design*des)
}
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);
+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;
}
+2 -2
View File
@@ -166,7 +166,7 @@ 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,
const LineInfo&file_line)
@@ -275,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
+3 -3
View File
@@ -114,7 +114,7 @@ void join_island(NetObj*obj)
// If that is an uncommitted branch, then save
// it. When I finally choose an island for self,
// these branches will be scanned so tha they join
// these branches will be scanned so that they join
// this island as well.
if (tmp_branch->island == 0) {
uncommitted_neighbors.push_back(tmp);
@@ -128,7 +128,7 @@ void join_island(NetObj*obj)
if (branch->island == 0) {
if (debug_elaborate)
cerr << obj->get_fileline() << ": debug: "
<< "Join brach to existing island." << endl;
<< "Join branch to existing island." << endl;
branch->island = tmp_branch->island;
} else if (branch->island != tmp_branch->island) {
@@ -139,7 +139,7 @@ void join_island(NetObj*obj)
}
}
// If after all that we did not find an idland to join, then
// 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;
+23
View File
@@ -849,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)
{
@@ -1496,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_;
+78 -3
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"
@@ -288,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. */
@@ -718,8 +724,13 @@ class NetScope : public Attrib {
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();
@@ -737,7 +748,8 @@ class NetScope : public Attrib {
assignments from the scope pass to the parameter evaluation
step. After that, it is not used. */
map<pform_name_t,NetExpr*>defparams;
list<pair<pform_name_t,NetExpr*> > defparams;
list<pair<list<hname_t>,NetExpr*> > defparams_later;
public:
struct range_t {
@@ -827,7 +839,7 @@ class NetScope : public Attrib {
/*
* 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 {
@@ -916,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.
*/
@@ -1379,7 +1429,7 @@ class NetSysFunc : public NetNode {
class NetTran : public NetNode, public IslandBranch {
public:
// Tran devices other then TRAN_VP
// 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,
@@ -3560,6 +3610,18 @@ class NetESignal : public NetExpr {
NetExpr*word_;
};
/*
* The Design object keeps a list of work items for processing
* elaboration. This is the type of those work items.
*/
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;
};
/*
* This class contains an entire design. It includes processes and a
@@ -3609,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
+92 -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
@@ -204,6 +244,57 @@ bool eval_as_double(double&value, NetExpr*expr)
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)
{
@@ -213,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;
+17
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
@@ -145,6 +152,16 @@ void eval_expr(NetExpr*&expr, int prune_width =-1);
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);
+262 -80
View File
@@ -205,7 +205,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
%token K_PSTAR K_STARP
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER
%token K_abs K_abstol K_access K_acos K_acosh K_asin K_analog K_asinh
%token K_atan K_atanh K_atan2
%token K_atan K_atanh K_atan2 K_automatic
%token K_always K_and K_assign K_begin K_bool K_buf K_bufif0 K_bufif1 K_case
%token K_casex K_casez K_ceil K_cmos K_continuous K_cos K_cosh
%token K_ddt_nature K_deassign K_default K_defparam K_disable K_discrete
@@ -351,6 +351,13 @@ number : BASED_NUMBER
based_size = 0; }
;
/* real and realtime are exactly the same so save some code
* with a common matching rule. */
real_or_realtime
: K_real
| K_realtime
;
/* Verilog-2001 supports attribute lists, which can be attached to a
variety of different objects. The syntax inside the (* *) is a
comma separated list of names or names with assigned values. */
@@ -432,7 +439,7 @@ block_item_decl
/* Integer declarations are simpler in that they do not have all the
trappings of a general variable declaration. All of that is
implicit in the "integer" of the declaratin. */
implicit in the "integer" of the declaration. */
| attribute_list_opt K_integer register_variable_list ';'
{ pform_set_reg_integer($3);
@@ -445,7 +452,7 @@ block_item_decl
/* real declarations are fairly simple as there is no range of
signed flag in the declaration. Create the real as a NetNet::REG
with real value. Note that real and realtime are interchangable
with real value. Note that real and realtime are interchangeable
in this context. */
| attribute_list_opt K_real real_variable_list ';'
@@ -1186,7 +1193,7 @@ expr_primary
}
/* Many of the VAMS built-in functions are available as builtin
functions with $system_function equivilents. */
functions with $system_function equivalents. */
| K_acos '(' expression ')'
{ perm_string tn = perm_string::literal("$acos");
@@ -2087,41 +2094,41 @@ module_item
statements in the task body. But we continue to accept it as an
extension. */
| K_task IDENTIFIER ';'
| K_task automatic_opt IDENTIFIER ';'
{ assert(current_task == 0);
current_task = pform_push_task_scope($2);
current_task = pform_push_task_scope($3);
FILE_NAME(current_task, @1);
}
task_item_list_opt
statement_or_null
K_endtask
{ current_task->set_ports($5);
current_task->set_statement($6);
{ current_task->set_ports($6);
current_task->set_statement($7);
pform_pop_scope();
current_task = 0;
delete[]$2;
delete[]$3;
}
| K_task IDENTIFIER
| K_task automatic_opt IDENTIFIER
{ assert(current_task == 0);
current_task = pform_push_task_scope($2);
current_task = pform_push_task_scope($3);
FILE_NAME(current_task, @1);
}
'(' task_port_decl_list ')' ';'
block_item_decls_opt
statement_or_null
K_endtask
{ current_task->set_ports($5);
current_task->set_statement($9);
{ current_task->set_ports($6);
current_task->set_statement($10);
pform_pop_scope();
current_task = 0;
delete[]$2;
delete[]$3;
}
| K_task IDENTIFIER error K_endtask
| K_task automatic_opt IDENTIFIER error K_endtask
{
pform_pop_scope();
current_task = 0;
delete[]$2;
delete[]$3;
}
/* The function declaration rule matches the function declaration
@@ -2129,42 +2136,42 @@ module_item
definitions in the func_body to take on the scope of the function
instead of the module. */
| K_function function_range_or_type_opt IDENTIFIER ';'
| K_function automatic_opt function_range_or_type_opt IDENTIFIER ';'
{ assert(current_function == 0);
current_function = pform_push_function_scope($3);
current_function = pform_push_function_scope($4);
FILE_NAME(current_function, @1);
}
function_item_list statement
K_endfunction
{ current_function->set_ports($6);
current_function->set_statement($7);
current_function->set_return($2);
{ current_function->set_ports($7);
current_function->set_statement($8);
current_function->set_return($3);
pform_pop_scope();
current_function = 0;
delete[]$3;
delete[]$4;
}
| K_function function_range_or_type_opt IDENTIFIER
| K_function automatic_opt function_range_or_type_opt IDENTIFIER
{ assert(current_function == 0);
current_function = pform_push_function_scope($3);
current_function = pform_push_function_scope($4);
FILE_NAME(current_function, @1);
}
'(' task_port_decl_list ')' ';'
block_item_decls_opt
statement
K_endfunction
{ current_function->set_ports($6);
current_function->set_statement($10);
current_function->set_return($2);
{ current_function->set_ports($7);
current_function->set_statement($11);
current_function->set_return($3);
pform_pop_scope();
current_function = 0;
delete[]$3;
delete[]$4;
}
| K_function function_range_or_type_opt IDENTIFIER error K_endfunction
| K_function automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction
{
pform_pop_scope();
current_task = 0;
delete[]$3;
delete[]$4;
}
/* A generate region can contain further module items. Actually, it
@@ -2200,6 +2207,15 @@ module_item
K_endcase
{ pform_endgenerate(); }
/* Handle some anachronistic syntax cases. */
| K_generate K_begin module_item_list_opt K_end K_endgenerate
{ /* Detect and warn about anachronistic begin/end use */
if (generation_flag > GN_VER2001) {
warn_count += 1;
cerr << @2 << ": warning: Anachronistic use of begin/end to surround generate schemes." << endl;
}
}
/* specify blocks are parsed but ignored. */
| K_specify K_endspecify
@@ -2262,6 +2278,15 @@ module_item
{ yyerror(@1, "error: Malformed $attribute parameter list."); }
;
automatic_opt
: K_automatic
{ yyerror(@1, "sorry: automatic tasks/functions are not "
"currently supported.");
yyerrok;
}
| {}
;
generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); }
generate_case_items
@@ -2384,7 +2409,14 @@ parameter_assign_decl
param_active_type = IVL_VT_LOGIC;
}
| K_integer
{ param_active_range = 0;
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
/* The default range is [31:0] */
param_active_range = range_stub;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
}
@@ -2393,7 +2425,24 @@ parameter_assign_decl
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_real
| K_time
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum((uint64_t)63, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
/* The range is [63:0] */
param_active_range = range_stub;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
parameter_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| real_or_realtime
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_REAL;
@@ -2476,7 +2525,7 @@ localparam_assign_decl
localparam_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_NO_TYPE;
param_active_type = IVL_VT_LOGIC;
}
| K_signed range
{ param_active_range = $2;
@@ -2489,7 +2538,14 @@ localparam_assign_decl
param_active_type = IVL_VT_LOGIC;
}
| K_integer
{ param_active_range = 0;
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
/* The default range is [31:0] */
param_active_range = range_stub;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
}
@@ -2498,7 +2554,24 @@ localparam_assign_decl
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_real
| K_time
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum((uint64_t)63, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
/* The range is [63:0] */
param_active_range = range_stub;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
localparam_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| real_or_realtime
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_REAL;
@@ -3657,39 +3730,43 @@ task_item
| task_port_item { $$ = $1; }
;
reg_opt
: K_reg
|
;
task_port_item
: K_input signed_opt range_opt list_of_identifiers ';'
: K_input reg_opt signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_NO_TYPE, $2,
$3, $4,
IVL_VT_NO_TYPE, $3,
$4, $5,
@1.text, @1.first_line);
$$ = tmp;
}
| K_output signed_opt range_opt list_of_identifiers ';'
| K_output reg_opt signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_LOGIC, $2,
$3, $4,
IVL_VT_LOGIC, $3,
$4, $5,
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout signed_opt range_opt list_of_identifiers ';'
| K_inout reg_opt signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT,
IVL_VT_LOGIC, $2,
$3, $4,
IVL_VT_LOGIC, $3,
$4, $5,
@1.text, @1.first_line);
$$ = tmp;
}
/* When the port is an integer, infer a signed vector of the integer
shape. Generate a range to make it work. */
shape. Generate a range ([31:0]) to make it work. */
| K_input K_integer list_of_identifiers ';'
{ svector<PExpr*>*range_stub
= new svector<PExpr*>(2);
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1,
integer_width));
@@ -3704,8 +3781,7 @@ task_port_item
$$ = tmp;
}
| K_output K_integer list_of_identifiers ';'
{ svector<PExpr*>*range_stub
= new svector<PExpr*>(2);
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1,
integer_width));
@@ -3720,8 +3796,7 @@ task_port_item
$$ = tmp;
}
| K_inout K_integer list_of_identifiers ';'
{ svector<PExpr*>*range_stub
= new svector<PExpr*>(2);
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1,
integer_width));
@@ -3736,9 +3811,54 @@ task_port_item
$$ = tmp;
}
/* Ports can be real. */
/* Ports can be time with a width of [63:0] (unsigned). */
| K_input K_real list_of_identifiers ';'
| K_input K_time list_of_identifiers ';'
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum((uint64_t)63, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, false,
range_stub, $3,
@1.text, @1.first_line);
$$ = tmp;
}
| K_output K_time list_of_identifiers ';'
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum((uint64_t)63, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_LOGIC, false,
range_stub, $3,
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout K_time list_of_identifiers ';'
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum((uint64_t)63, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT,
IVL_VT_LOGIC, false,
range_stub, $3,
@1.text, @1.first_line);
$$ = tmp;
}
/* Ports can be real or realtime. */
| K_input real_or_realtime list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_REAL, false,
@@ -3746,7 +3866,7 @@ task_port_item
@1.text, @1.first_line);
$$ = tmp;
}
| K_output K_real list_of_identifiers ';'
| K_output real_or_realtime list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_REAL, true,
@@ -3754,7 +3874,7 @@ task_port_item
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout K_real list_of_identifiers ';'
| K_inout real_or_realtime list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT,
IVL_VT_REAL, true,
@@ -3784,50 +3904,51 @@ task_item_list_opt
task_port_decl
: K_input signed_opt range_opt IDENTIFIER
: K_input reg_opt signed_opt range_opt IDENTIFIER
{ port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = $2;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($3);
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, $2,
$3, list_from_identifier($4),
IVL_VT_LOGIC, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
| K_output signed_opt range_opt IDENTIFIER
| K_output reg_opt signed_opt range_opt IDENTIFIER
{ port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = $2;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($3);
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_LOGIC, $2,
$3, list_from_identifier($4),
IVL_VT_LOGIC, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout signed_opt range_opt IDENTIFIER
| K_inout reg_opt signed_opt range_opt IDENTIFIER
{ port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = $2;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($3);
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT,
IVL_VT_LOGIC, $2,
$3, list_from_identifier($4),
IVL_VT_LOGIC, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
/* Ports can be integer with a width of [31:0]. */
| K_input K_integer IDENTIFIER
{ svector<PExpr*>*range_stub
= new svector<PExpr*>(2);
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1,
integer_width));
@@ -3848,8 +3969,7 @@ task_port_decl
$$ = tmp;
}
| K_output K_integer IDENTIFIER
{ svector<PExpr*>*range_stub
= new svector<PExpr*>(2);
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1,
integer_width));
@@ -3870,8 +3990,7 @@ task_port_decl
$$ = tmp;
}
| K_inout K_integer IDENTIFIER
{ svector<PExpr*>*range_stub
= new svector<PExpr*>(2);
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1,
integer_width));
@@ -3892,9 +4011,72 @@ task_port_decl
$$ = tmp;
}
/* Ports can be real. */
/* Ports can be time with a width of [63:0] (unsigned). */
| K_input K_time IDENTIFIER
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum((uint64_t)63, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, false,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_output K_time IDENTIFIER
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum((uint64_t)63, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_LOGIC, false,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout K_time IDENTIFIER
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum((uint64_t)63, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT,
IVL_VT_LOGIC, false,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_input K_real IDENTIFIER
/* Ports can be real or realtime. */
| K_input real_or_realtime IDENTIFIER
{ port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.var_type = IVL_VT_REAL;
port_declaration_context.sign_flag = false;
@@ -3907,7 +4089,7 @@ task_port_decl
@1.text, @1.first_line);
$$ = tmp;
}
| K_output K_real IDENTIFIER
| K_output real_or_realtime IDENTIFIER
{ port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.var_type = IVL_VT_REAL;
port_declaration_context.sign_flag = false;
@@ -3920,7 +4102,7 @@ task_port_decl
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout K_real IDENTIFIER
| K_inout real_or_realtime IDENTIFIER
{ port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.var_type = IVL_VT_REAL;
port_declaration_context.sign_flag = false;
+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()
+3
View File
@@ -23,6 +23,7 @@
#endif
# include <list>
# include <ostream>
# include "compiler.h"
# include "pform.h"
@@ -62,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;
+83 -42
View File
@@ -93,40 +93,64 @@ 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;
}
@@ -138,9 +162,34 @@ PWire*pform_get_wire_in_scope(perm_string name)
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,
@@ -508,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);
@@ -1236,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;
@@ -1250,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);
}
/*
@@ -1271,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 "
@@ -1305,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);
}
/*
@@ -1388,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);
}
/*
@@ -1469,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()) {
@@ -1555,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);
@@ -1622,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);
}
@@ -1715,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));
}
/*
@@ -1805,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);
@@ -1839,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);
@@ -1901,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;
}
+7 -7
View File
@@ -937,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);
}
@@ -991,7 +991,6 @@ 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 " << (*cur).second.type << " ";
@@ -1068,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 << " = ";
@@ -1089,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;
@@ -1098,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;
+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.
+23 -8
View File
@@ -886,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;
@@ -1028,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;
@@ -1144,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:
@@ -1166,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:
@@ -1435,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_;
+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_;
}
+75 -3
View File
@@ -30,6 +30,7 @@
# include <malloc.h>
#endif
# include <stdlib.h>
# include "ivl_assert.h"
#if defined(__WIN32__)
@@ -538,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;
}
@@ -1550,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
@@ -1881,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);
@@ -2301,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) {
+17 -1
View File
@@ -76,6 +76,8 @@ struct dll_target : public target_t, public expr_scan_t {
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*);
@@ -537,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.
*/
@@ -545,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;
@@ -761,4 +765,16 @@ static inline void FILE_NAME(ivl_switch_t net, const LineInfo*info)
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
+14
View File
@@ -107,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() << "): "
+2
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*);
+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
+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);
+58
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);
@@ -802,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;
+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
+78
View File
@@ -0,0 +1,78 @@
/*
* Helper functions for VHDL 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_HELPER_HH
#define INC_VHDL_HELPER_HH
#include <fstream>
#include <list>
#include <cassert>
template <class T>
void emit_children(std::ostream &of,
const std::list<T*> &children,
int level, const char *delim = "",
bool trailing_newline = true)
{
// Don't indent if there are no children
if (children.size() == 0)
newline(of, level);
else {
typename std::list<T*>::const_iterator it;
int sz = children.size();
for (it = children.begin(); it != children.end(); ++it) {
newline(of, indent(level));
(*it)->emit(of, indent(level));
if (--sz > 0)
of << delim;
}
if (trailing_newline)
newline(of, level);
}
}
template <class T>
void delete_children(std::list<T*> &children)
{
typename std::list<T*>::iterator it;
for (it = children.begin(); it != children.end(); ++it)
delete *it;
children.clear();
}
static inline char vl_to_vhdl_bit(char bit)
{
switch (bit) {
case '0':
case 'Z':
case '1':
return bit;
case 'z':
return 'Z';
case 'x':
case 'X':
return 'U';
case '?':
return '-';
}
assert(false);
}
#endif
+944
View File
@@ -0,0 +1,944 @@
/*
* 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_syntax.hh"
#include "vhdl_helper.hh"
#include <cassert>
#include <iostream>
#include <typeinfo>
vhdl_scope::vhdl_scope()
: parent_(NULL), init_(false), sig_assign_(true)
{
}
vhdl_scope::~vhdl_scope()
{
delete_children<vhdl_decl>(decls_);
}
void vhdl_scope::set_initializing(bool i)
{
init_ = i;
if (parent_)
parent_->set_initializing(i);
}
void vhdl_scope::add_decl(vhdl_decl *decl)
{
decls_.push_back(decl);
}
void vhdl_scope::add_forward_decl(vhdl_decl *decl)
{
decls_.push_front(decl);
}
vhdl_decl *vhdl_scope::get_decl(const std::string &name) const
{
decl_list_t::const_iterator it;
for (it = decls_.begin(); it != decls_.end(); ++it) {
if ((*it)->get_name() == name)
return *it;
}
return parent_ ? parent_->get_decl(name) : NULL;
}
bool vhdl_scope::have_declared(const std::string &name) const
{
return get_decl(name) != NULL;
}
bool vhdl_scope::contained_within(const vhdl_scope *other) const
{
if (this == other)
return true;
else if (NULL == parent_)
return false;
else
return parent_->contained_within(other);
}
vhdl_scope *vhdl_scope::get_parent() const
{
assert(parent_);
return parent_;
}
vhdl_entity::vhdl_entity(const char *name, const char *derived_from,
vhdl_arch *arch)
: name_(name), arch_(arch), derived_from_(derived_from)
{
arch->get_scope()->set_parent(&ports_);
}
vhdl_entity::~vhdl_entity()
{
delete arch_;
}
void vhdl_entity::add_port(vhdl_port_decl *decl)
{
ports_.add_decl(decl);
}
void vhdl_entity::emit(std::ostream &of, int level) const
{
// Pretty much every design will use std_logic so we
// might as well include it by default
of << "library ieee;" << std::endl;
of << "use ieee.std_logic_1164.all;" << std::endl;
of << "use ieee.numeric_std.all;" << std::endl;
of << "use std.textio.all;" << std::endl;
of << std::endl;
emit_comment(of, level);
of << "entity " << name_ << " is";
if (!ports_.empty()) {
newline(of, indent(level));
of << "port (";
emit_children<vhdl_decl>(of, ports_.get_decls(), indent(level), ";");
of << ");";
}
newline(of, level);
of << "end entity; ";
blank_line(of, level); // Extra blank line after entities
arch_->emit(of, level);
}
vhdl_arch::~vhdl_arch()
{
delete_children<vhdl_conc_stmt>(stmts_);
}
void vhdl_arch::add_stmt(vhdl_process *proc)
{
proc->get_scope()->set_parent(&scope_);
stmts_.push_back(proc);
}
void vhdl_arch::add_stmt(vhdl_conc_stmt *stmt)
{
stmts_.push_back(stmt);
}
void vhdl_arch::emit(std::ostream &of, int level) const
{
emit_comment(of, level);
of << "architecture " << name_ << " of " << entity_;
of << " is";
emit_children<vhdl_decl>(of, scope_.get_decls(), level);
of << "begin";
emit_children<vhdl_conc_stmt>(of, stmts_, level);
of << "end architecture;";
blank_line(of, level); // Extra blank line after architectures;
}
void vhdl_process::add_sensitivity(const std::string &name)
{
sens_.push_back(name);
}
void vhdl_process::emit(std::ostream &of, int level) const
{
// If there are no statements in the body, this process
// can't possibly do anything, so don't bother to emit it
if (stmts_.empty()) {
of << "-- Removed one empty process";
newline(of, level);
return;
}
newline(of, level);
emit_comment(of, level);
if (name_.size() > 0)
of << name_ << ": ";
of << "process ";
int num_sens = sens_.size();
if (num_sens > 0) {
of << "(";
string_list_t::const_iterator it;
for (it = sens_.begin(); it != sens_.end(); ++it) {
of << *it;
if (--num_sens > 0)
of << ", ";
}
of << ") ";
}
of << "is";
emit_children<vhdl_decl>(of, scope_.get_decls(), level);
of << "begin";
stmts_.emit(of, level);
of << "end process;";
}
stmt_container::~stmt_container()
{
delete_children<vhdl_seq_stmt>(stmts_);
}
void stmt_container::add_stmt(vhdl_seq_stmt *stmt)
{
stmts_.push_back(stmt);
}
void stmt_container::emit(std::ostream &of, int level, bool newline) const
{
emit_children<vhdl_seq_stmt>(of, stmts_, level, "", newline);
}
vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name)
: comp_name_(comp_name), inst_name_(inst_name)
{
}
vhdl_comp_inst::~vhdl_comp_inst()
{
port_map_list_t::iterator it;
for (it = mapping_.begin(); it != mapping_.end(); ++it) {
delete (*it).expr;
}
mapping_.clear();
}
void vhdl_comp_inst::map_port(const char *name, vhdl_expr *expr)
{
port_map_t pmap = { name, expr };
mapping_.push_back(pmap);
}
void vhdl_comp_inst::emit(std::ostream &of, int level) const
{
newline(of, level);
emit_comment(of, level);
of << inst_name_ << ": " << comp_name_;
// If there are no ports or generics we don't need to mention them...
if (mapping_.size() > 0) {
newline(of, indent(level));
of << "port map (";
int sz = mapping_.size();
port_map_list_t::const_iterator it;
for (it = mapping_.begin(); it != mapping_.end(); ++it) {
newline(of, indent(indent(level)));
of << (*it).name << " => ";
(*it).expr->emit(of, level);
if (--sz > 0)
of << ",";
}
newline(of, indent(level));
of << ")";
}
of << ";";
}
vhdl_component_decl::vhdl_component_decl(const char *name)
: vhdl_decl(name)
{
}
/*
* Create a component declaration for the given entity.
*/
vhdl_component_decl *vhdl_component_decl::component_decl_for(vhdl_entity *ent)
{
assert(ent != NULL);
vhdl_component_decl *decl = new vhdl_component_decl
(ent->get_name().c_str());
decl->ports_ = ent->get_scope()->get_decls();
return decl;
}
void vhdl_component_decl::emit(std::ostream &of, int level) const
{
newline(of, level);
emit_comment(of, level);
of << "component " << name_ << " is";
if (ports_.size() > 0) {
newline(of, indent(level));
of << "port (";
emit_children<vhdl_decl>(of, ports_, indent(level), ";");
of << ");";
}
newline(of, level);
of << "end component;";
}
vhdl_wait_stmt::~vhdl_wait_stmt()
{
if (expr_ != NULL)
delete expr_;
}
void vhdl_wait_stmt::emit(std::ostream &of, int level) const
{
of << "wait";
switch (type_) {
case VHDL_WAIT_INDEF:
break;
case VHDL_WAIT_FOR:
assert(expr_);
of << " for ";
expr_->emit(of, level);
break;
case VHDL_WAIT_UNTIL:
assert(expr_);
of << " until ";
expr_->emit(of, level);
break;
case VHDL_WAIT_ON:
{
of << " on ";
string_list_t::const_iterator it = sensitivity_.begin();
while (it != sensitivity_.end()) {
of << *it;
if (++it != sensitivity_.end())
of << ", ";
}
}
break;
}
of << ";";
}
vhdl_decl::~vhdl_decl()
{
if (type_ != NULL)
delete type_;
if (initial_ != NULL)
delete initial_;
}
const vhdl_type *vhdl_decl::get_type() const
{
assert(type_);
return type_;
}
void vhdl_decl::set_initial(vhdl_expr *initial)
{
if (!has_initial_) {
assert(initial_ == NULL);
initial_ = initial;
has_initial_ = true;
}
}
void vhdl_port_decl::emit(std::ostream &of, int level) const
{
of << name_ << " : ";
switch (mode_) {
case VHDL_PORT_IN:
of << "in ";
break;
case VHDL_PORT_OUT:
of << "out ";
break;
case VHDL_PORT_INOUT:
of << "inout ";
break;
case VHDL_PORT_BUFFER:
of << "buffer ";
break;
}
type_->emit(of, level);
}
void vhdl_var_decl::emit(std::ostream &of, int level) const
{
of << "variable " << name_ << " : ";
type_->emit(of, level);
if (initial_) {
of << " := ";
initial_->emit(of, level);
}
of << ";";
emit_comment(of, level, true);
}
void vhdl_signal_decl::emit(std::ostream &of, int level) const
{
of << "signal " << name_ << " : ";
type_->emit(of, level);
if (initial_) {
of << " := ";
initial_->emit(of, level);
}
of << ";";
emit_comment(of, level, true);
}
void vhdl_type_decl::emit(std::ostream &of, int level) const
{
of << "type " << name_ << " is ";
of << type_->get_type_decl_string() << ";";
emit_comment(of, level, true);
}
vhdl_expr::~vhdl_expr()
{
if (type_ != NULL)
delete type_;
}
void vhdl_expr_list::add_expr(vhdl_expr *e)
{
exprs_.push_back(e);
}
vhdl_expr_list::~vhdl_expr_list()
{
delete_children<vhdl_expr>(exprs_);
}
void vhdl_expr_list::emit(std::ostream &of, int level) const
{
of << "(";
int size = exprs_.size();
std::list<vhdl_expr*>::const_iterator it;
for (it = exprs_.begin(); it != exprs_.end(); ++it) {
(*it)->emit(of, level);
if (--size > 0)
of << ", ";
}
of << ")";
}
void vhdl_pcall_stmt::emit(std::ostream &of, int level) const
{
of << name_;
if (!exprs_.empty())
exprs_.emit(of, level);
of << ";";
}
vhdl_var_ref::~vhdl_var_ref()
{
if (slice_)
delete slice_;
}
void vhdl_var_ref::set_slice(vhdl_expr *s, int w)
{
assert(type_);
slice_ = s;
slice_width_ = w;
vhdl_type_name_t tname = type_->get_name();
if (tname == VHDL_TYPE_ARRAY) {
type_ = new vhdl_type(*type_->get_base());
}
else {
assert(tname == VHDL_TYPE_UNSIGNED || tname == VHDL_TYPE_SIGNED);
if (type_)
delete type_;
if (w > 0)
type_ = new vhdl_type(tname, w);
else
type_ = vhdl_type::std_logic();
}
}
void vhdl_var_ref::emit(std::ostream &of, int level) const
{
of << name_;
if (slice_) {
of << "(";
if (slice_width_ > 0) {
slice_->emit(of, level);
of << " + " << slice_width_ << " downto ";
}
slice_->emit(of, level);
of << ")";
}
}
void vhdl_const_string::emit(std::ostream &of, int level) const
{
// In some instances a string literal can be ambiguous between
// a String type and some other types (e.g. std_logic_vector)
// The explicit cast to String removes this ambiguity (although
// isn't always strictly necessary)
of << "String'(\"" << value_ << "\")";
}
void vhdl_null_stmt::emit(std::ostream &of, int level) const
{
of << "null;";
}
void vhdl_fcall::emit(std::ostream &of, int level) const
{
of << name_;
exprs_.emit(of, level);
}
vhdl_abstract_assign_stmt::~vhdl_abstract_assign_stmt()
{
delete lhs_;
delete rhs_;
if (after_)
delete after_;
}
void vhdl_nbassign_stmt::emit(std::ostream &of, int level) const
{
lhs_->emit(of, level);
of << " <= ";
rhs_->emit(of, level);
if (after_) {
of << " after ";
after_->emit(of, level);
}
of << ";";
}
void vhdl_assign_stmt::emit(std::ostream &of, int level) const
{
lhs_->emit(of, level);
of << " := ";
rhs_->emit(of, level);
of << ";";
}
vhdl_const_bits::vhdl_const_bits(const char *value, int width, bool issigned)
: vhdl_expr(issigned ? vhdl_type::nsigned(width)
: vhdl_type::nunsigned(width), true),
qualified_(false),
signed_(issigned)
{
// Can't rely on value being NULL-terminated
while (width--)
value_.push_back(*value++);
}
void vhdl_const_bits::emit(std::ostream &of, int level) const
{
if (qualified_)
of << (signed_ ? "signed" : "unsigned") << "'(\"";
else
of << "\"";
// The bits appear to be in reverse order
std::string::const_reverse_iterator it;
for (it = value_.rbegin(); it != value_.rend(); ++it)
of << vl_to_vhdl_bit(*it);
of << (qualified_ ? "\")" : "\"");
}
void vhdl_const_bit::emit(std::ostream &of, int level) const
{
of << "'" << vl_to_vhdl_bit(bit_) << "'";
}
void vhdl_const_int::emit(std::ostream &of, int level) const
{
of << value_;
}
void vhdl_const_bool::emit(std::ostream &of, int level) const
{
of << (value_ ? "True" : "False");
}
void vhdl_const_time::emit(std::ostream &of, int level) const
{
of << value_;
switch (units_) {
case TIME_UNIT_NS:
of << " ns";
}
}
vhdl_cassign_stmt::~vhdl_cassign_stmt()
{
delete lhs_;
delete rhs_;
for (std::list<when_part_t>::const_iterator it = whens_.begin();
it != whens_.end();
++it) {
delete (*it).value;
delete (*it).cond;
}
}
void vhdl_cassign_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond)
{
when_part_t when = { value, cond, NULL };
whens_.push_back(when);
}
void vhdl_cassign_stmt::emit(std::ostream &of, int level) const
{
lhs_->emit(of, level);
of << " <= ";
if (!whens_.empty()) {
for (std::list<when_part_t>::const_iterator it = whens_.begin();
it != whens_.end();
++it) {
(*it).value->emit(of, level);
of << " when ";
(*it).cond->emit(of, level);
of << " ";
}
of << "else ";
}
rhs_->emit(of, level);
if (after_) {
of << " after ";
after_->emit(of, level);
}
of << ";";
}
void vhdl_assert_stmt::emit(std::ostream &of, int level) const
{
of << "assert false"; // TODO: Allow arbitrary expression
of << " report \"" << reason_ << "\" severity failure;";
}
vhdl_if_stmt::vhdl_if_stmt(vhdl_expr *test)
{
// Need to ensure that the expression is Boolean
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
test_ = test->cast(&boolean);
}
vhdl_if_stmt::~vhdl_if_stmt()
{
delete test_;
}
void vhdl_if_stmt::emit(std::ostream &of, int level) const
{
of << "if ";
test_->emit(of, level);
of << " then";
then_part_.emit(of, level);
if (!else_part_.empty()) {
of << "else";
else_part_.emit(of, level);
}
of << "end if;";
}
vhdl_unaryop_expr::~vhdl_unaryop_expr()
{
delete operand_;
}
void vhdl_unaryop_expr::emit(std::ostream &of, int level) const
{
of << "(";
switch (op_) {
case VHDL_UNARYOP_NOT:
of << "not ";
break;
case VHDL_UNARYOP_NEG:
of << "-";
break;
}
operand_->emit(of, level);
of << ")";
}
vhdl_binop_expr::vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op,
vhdl_expr *right, vhdl_type *type)
: vhdl_expr(type), op_(op)
{
add_expr(left);
add_expr(right);
}
vhdl_binop_expr::~vhdl_binop_expr()
{
delete_children<vhdl_expr>(operands_);
}
void vhdl_binop_expr::add_expr(vhdl_expr *e)
{
operands_.push_back(e);
}
void vhdl_binop_expr::emit(std::ostream &of, int level) const
{
// Expressions are fully parenthesized to remove any
// ambiguity in the output
of << "(";
assert(operands_.size() > 0);
std::list<vhdl_expr*>::const_iterator it = operands_.begin();
(*it)->emit(of, level);
while (++it != operands_.end()) {
const char* ops[] = {
"and", "or", "=", "/=", "+", "-", "*", "<",
">", "<=", ">=", "sll", "srl", "xor", "&",
"nand", "nor", "xnor", "/", "mod", NULL
};
of << " " << ops[op_] << " ";
(*it)->emit(of, level);
}
of << ")";
}
vhdl_bit_spec_expr::~vhdl_bit_spec_expr()
{
if (others_)
delete others_;
std::list<bit_map>::iterator it;
for (it = bits_.begin(); it != bits_.end(); ++it)
delete (*it).e;
}
void vhdl_bit_spec_expr::add_bit(int bit, vhdl_expr *e)
{
bit_map bm = { bit, e };
bits_.push_back(bm);
}
void vhdl_bit_spec_expr::emit(std::ostream &of, int level) const
{
of << "(";
std::list<bit_map>::const_iterator it;
it = bits_.begin();
while (it != bits_.end()) {
of << (*it).bit << " => ";
(*it).e->emit(of, level);
if (++it != bits_.end())
of << ", ";
}
if (others_) {
of << (bits_.empty() ? "" : ", ") << "others => ";
others_->emit(of, level);
}
of << ")";
}
vhdl_case_branch::~vhdl_case_branch()
{
delete when_;
}
void vhdl_case_branch::emit(std::ostream &of, int level) const
{
of << "when ";
when_->emit(of, level);
of << " =>";
stmts_.emit(of, indent(level), false);
}
vhdl_case_stmt::~vhdl_case_stmt()
{
delete test_;
}
void vhdl_case_stmt::emit(std::ostream &of, int level) const
{
of << "case ";
test_->emit(of, level);
of << " is";
newline(of, indent(level));
case_branch_list_t::const_iterator it;
int n = branches_.size();
for (it = branches_.begin(); it != branches_.end(); ++it) {
(*it)->emit(of, level);
if (--n > 0)
newline(of, indent(level));
else
newline(of, level);
}
of << "end case;";
}
vhdl_while_stmt::~vhdl_while_stmt()
{
delete test_;
}
void vhdl_while_stmt::emit(std::ostream &of, int level) const
{
of << "while ";
test_->emit(of, level);
of << " ";
vhdl_loop_stmt::emit(of, level);
}
void vhdl_loop_stmt::emit(std::ostream &of, int level) const
{
of << "loop";
stmts_.emit(of, level);
of << "end loop;";
}
vhdl_for_stmt::~vhdl_for_stmt()
{
delete from_;
delete to_;
}
void vhdl_for_stmt::emit(std::ostream &of, int level) const
{
of << "for " << lname_ << " in ";
from_->emit(of, level);
of << " to ";
to_->emit(of, level);
of << " ";
vhdl_loop_stmt::emit(of, level);
}
vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type)
: vhdl_decl(name, ret_type)
{
// A function contains two scopes:
// scope_ = The paramters
// variables_ = Local variables
// A call to get_scope returns variables_ whose parent is scope_
variables_.set_parent(&scope_);
}
void vhdl_function::emit(std::ostream &of, int level) const
{
newline(of, level);
emit_comment(of, level);
of << "function " << name_ << " (";
emit_children<vhdl_decl>(of, scope_.get_decls(), level, ";");
of << ") ";
newline(of, level);
of << "return " << type_->get_string() << " is";
emit_children<vhdl_decl>(of, variables_.get_decls(), level);
of << "begin";
stmts_.emit(of, level);
of << " return Verilog_Result;";
newline(of, level);
of << "end function;";
}
void vhdl_forward_fdecl::emit(std::ostream &of, int level) const
{
of << "function " << f_->get_name() << " (";
emit_children<vhdl_decl>(of, f_->scope_.get_decls(), level, ";");
of << ") ";
newline(of, level);
of << "return " << f_->type_->get_string() << ";";
newline(of, level);
}
void vhdl_param_decl::emit(std::ostream &of, int level) const
{
of << name_ << " : ";
type_->emit(of, level);
}
vhdl_with_select_stmt::~vhdl_with_select_stmt()
{
delete test_;
delete out_;
for (when_list_t::const_iterator it = whens_.begin();
it != whens_.end();
++it) {
delete (*it).value;
delete (*it).cond;
if ((*it).delay)
delete (*it).delay;
}
}
void vhdl_with_select_stmt::emit(std::ostream &of, int level) const
{
of << "with ";
test_->emit(of, level);
of << " select";
emit_comment(of, level, true);
newline(of, indent(level));
out_->emit(of, level);
of << " <= ";
when_list_t::const_iterator it = whens_.begin();
while (it != whens_.end()) {
(*it).value->emit(of, level);
if ((*it).delay) {
of << " after ";
(*it).delay->emit(of, level);
}
of << " when ";
(*it).cond->emit(of, level);
if (++it != whens_.end()) {
of << ",";
newline(of, indent(level));
}
else
of << ";";
}
}
void vhdl_with_select_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond, vhdl_expr *delay)
{
when_part_t when = { value, cond, delay };
whens_.push_back(when);
}
+782
View File
@@ -0,0 +1,782 @@
/*
* 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_SYNTAX_HH
#define INC_VHDL_SYNTAX_HH
#include "vhdl_element.hh"
#include "vhdl_type.hh"
class vhdl_scope;
class vhdl_entity;
class vhdl_arch;
class vhdl_expr : public vhdl_element {
public:
vhdl_expr(vhdl_type* type, bool isconst=false)
: type_(type), isconst_(isconst) {}
virtual ~vhdl_expr();
const vhdl_type *get_type() const { return type_; }
bool constant() const { return isconst_; }
virtual vhdl_expr *cast(const vhdl_type *to);
virtual vhdl_expr *resize(int newwidth);
protected:
vhdl_type *type_;
bool isconst_;
};
/*
* A scalar or array variable reference.
*/
class vhdl_var_ref : public vhdl_expr {
public:
vhdl_var_ref(const char *name, vhdl_type *type,
vhdl_expr *slice = NULL)
: vhdl_expr(type), name_(name), slice_(slice) {}
~vhdl_var_ref();
void emit(std::ostream &of, int level) const;
const std::string &get_name() const { return name_; }
void set_name(const std::string &name) { name_ = name; }
void set_slice(vhdl_expr *s, int w=0);
private:
std::string name_;
vhdl_expr *slice_;
unsigned slice_width_;
};
enum vhdl_binop_t {
VHDL_BINOP_AND = 0,
VHDL_BINOP_OR,
VHDL_BINOP_EQ,
VHDL_BINOP_NEQ,
VHDL_BINOP_ADD,
VHDL_BINOP_SUB,
VHDL_BINOP_MULT,
VHDL_BINOP_LT,
VHDL_BINOP_GT,
VHDL_BINOP_LEQ,
VHDL_BINOP_GEQ,
VHDL_BINOP_SL,
VHDL_BINOP_SR,
VHDL_BINOP_XOR,
VHDL_BINOP_CONCAT,
VHDL_BINOP_NAND,
VHDL_BINOP_NOR,
VHDL_BINOP_XNOR,
VHDL_BINOP_DIV,
VHDL_BINOP_MOD,
};
/*
* A binary expression contains a list of operands rather
* than just two: this is to model n-input gates and the
* like. A second constructor is provided to handle the
* common case of a true binary expression.
*/
class vhdl_binop_expr : public vhdl_expr {
public:
vhdl_binop_expr(vhdl_binop_t op, vhdl_type *type)
: vhdl_expr(type), op_(op) {}
vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op,
vhdl_expr *right, vhdl_type *type);
~vhdl_binop_expr();
void add_expr(vhdl_expr *e);
void emit(std::ostream &of, int level) const;
private:
std::list<vhdl_expr*> operands_;
vhdl_binop_t op_;
};
enum vhdl_unaryop_t {
VHDL_UNARYOP_NOT,
VHDL_UNARYOP_NEG,
};
class vhdl_unaryop_expr : public vhdl_expr {
public:
vhdl_unaryop_expr(vhdl_unaryop_t op, vhdl_expr *operand,
vhdl_type *type)
: vhdl_expr(type), op_(op), operand_(operand) {}
~vhdl_unaryop_expr();
void emit(std::ostream &of, int level) const;
private:
vhdl_unaryop_t op_;
vhdl_expr *operand_;
};
/*
* An expression like (0 => '1', 2 => '0', others => 'Z')
*/
class vhdl_bit_spec_expr : public vhdl_expr {
public:
vhdl_bit_spec_expr(vhdl_type *type, vhdl_expr *others)
: vhdl_expr(type), others_(others) {}
~vhdl_bit_spec_expr();
void add_bit(int bit, vhdl_expr *e);
void emit(std::ostream &of, int level) const;
private:
vhdl_expr *others_;
struct bit_map {
int bit;
vhdl_expr *e;
};
std::list<bit_map> bits_;
};
class vhdl_const_string : public vhdl_expr {
public:
vhdl_const_string(const char *value)
: vhdl_expr(vhdl_type::string(), true), value_(value) {}
void emit(std::ostream &of, int level) const;
private:
std::string value_;
};
class vhdl_const_bits : public vhdl_expr {
public:
vhdl_const_bits(const char *value, int width, bool issigned);
void emit(std::ostream &of, int level) const;
const std::string &get_value() const { return value_; }
vhdl_expr *cast(const vhdl_type *to);
private:
int bits_to_int() const;
std::string value_;
bool qualified_, signed_;
};
class vhdl_const_bit : public vhdl_expr {
public:
vhdl_const_bit(char bit)
: vhdl_expr(vhdl_type::std_logic(), true), bit_(bit) {}
void emit(std::ostream &of, int level) const;
vhdl_expr *cast(const vhdl_type *to);
private:
char bit_;
};
enum time_unit_t {
TIME_UNIT_NS,
};
class vhdl_const_time : public vhdl_expr {
public:
vhdl_const_time(int64_t value, time_unit_t units = TIME_UNIT_NS)
: vhdl_expr(vhdl_type::time(), true), value_(value), units_(units) {}
void emit(std::ostream &of, int level) const;
private:
int64_t value_;
time_unit_t units_;
};
class vhdl_const_int : public vhdl_expr {
public:
vhdl_const_int(int64_t value)
: vhdl_expr(vhdl_type::integer(), true), value_(value) {}
void emit(std::ostream &of, int level) const;
vhdl_expr *cast(const vhdl_type *to);
private:
int64_t value_;
};
class vhdl_const_bool : public vhdl_expr {
public:
vhdl_const_bool(bool value)
: vhdl_expr(vhdl_type::boolean(), true), value_(value) {}
void emit(std::ostream &of, int level) const;
private:
bool value_;
};
class vhdl_expr_list : public vhdl_element {
public:
~vhdl_expr_list();
void emit(std::ostream &of, int level) const;
bool empty() const { return exprs_.empty(); }
void add_expr(vhdl_expr *e);
private:
std::list<vhdl_expr*> exprs_;
};
/*
* A function call within an expression.
*/
class vhdl_fcall : public vhdl_expr {
public:
vhdl_fcall(const char *name, vhdl_type *rtype)
: vhdl_expr(rtype), name_(name) {};
~vhdl_fcall() {}
void add_expr(vhdl_expr *e) { exprs_.add_expr(e); }
void emit(std::ostream &of, int level) const;
private:
std::string name_;
vhdl_expr_list exprs_;
};
/*
* A concurrent statement appears in architecture bodies/
*/
class vhdl_conc_stmt : public vhdl_element {
public:
virtual ~vhdl_conc_stmt() {}
};
typedef std::list<vhdl_conc_stmt*> conc_stmt_list_t;
/*
* A '<value> when <cond>' clause that appears in several
* statement types.
*/
struct when_part_t {
vhdl_expr *value, *cond, *delay;
};
typedef std::list<when_part_t> when_list_t;
/*
* A concurrent signal assignment (i.e. not part of a process).
* Can have any number of `when' clauses, in which case the original
* rhs becomes the `else' part.
*/
class vhdl_cassign_stmt : public vhdl_conc_stmt {
public:
vhdl_cassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs)
: lhs_(lhs), rhs_(rhs), after_(NULL) {}
~vhdl_cassign_stmt();
void emit(std::ostream &of, int level) const;
void add_condition(vhdl_expr *value, vhdl_expr *cond);
void set_after(vhdl_expr *a) { after_ = a; }
private:
vhdl_var_ref *lhs_;
vhdl_expr *rhs_;
vhdl_expr *after_;
when_list_t whens_;
};
class vhdl_with_select_stmt : public vhdl_conc_stmt {
public:
vhdl_with_select_stmt(vhdl_expr *test, vhdl_var_ref *out)
: test_(test), out_(out) {}
~vhdl_with_select_stmt();
void emit(std::ostream &of, int level) const;
void add_condition(vhdl_expr *value, vhdl_expr *cond, vhdl_expr *delay=NULL);
private:
vhdl_expr *test_;
vhdl_var_ref *out_;
when_list_t whens_;
};
/*
* Any sequential statement in a process.
*/
class vhdl_seq_stmt : public vhdl_element {
public:
virtual ~vhdl_seq_stmt() {}
};
/*
* A list of sequential statements. For example inside a
* process, loop, or if statement.
*/
class stmt_container {
public:
~stmt_container();
void add_stmt(vhdl_seq_stmt *stmt);
void emit(std::ostream &of, int level, bool newline=true) const;
bool empty() const { return stmts_.empty(); }
private:
std::list<vhdl_seq_stmt*> stmts_;
};
/*
* Shared between blocking and non-blocking assignment.
*/
class vhdl_abstract_assign_stmt : public vhdl_seq_stmt {
public:
vhdl_abstract_assign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs)
: lhs_(lhs), rhs_(rhs), after_(NULL) {}
virtual ~vhdl_abstract_assign_stmt();
void set_after(vhdl_expr *after) { after_ = after; }
protected:
vhdl_var_ref *lhs_;
vhdl_expr *rhs_, *after_;
};
/*
* Similar to Verilog non-blocking assignment, except the LHS
* must be a signal not a variable.
*/
class vhdl_nbassign_stmt : public vhdl_abstract_assign_stmt {
public:
vhdl_nbassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs)
: vhdl_abstract_assign_stmt(lhs, rhs) {}
void emit(std::ostream &of, int level) const;
};
class vhdl_assign_stmt : public vhdl_abstract_assign_stmt {
public:
vhdl_assign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs)
: vhdl_abstract_assign_stmt(lhs, rhs) {}
void emit(std::ostream &of, int level) const;
};
enum vhdl_wait_type_t {
VHDL_WAIT_INDEF, // Suspend indefinitely
VHDL_WAIT_FOR, // Wait for a constant amount of time
VHDL_WAIT_UNTIL, // Wait on an expression
VHDL_WAIT_ON, // Wait on a sensitivity list
};
/*
* Delay simulation indefinitely, until an event, or for a
* specified time.
*/
class vhdl_wait_stmt : public vhdl_seq_stmt {
public:
vhdl_wait_stmt(vhdl_wait_type_t type = VHDL_WAIT_INDEF,
vhdl_expr *expr = NULL)
: type_(type), expr_(expr) {}
~vhdl_wait_stmt();
void emit(std::ostream &of, int level) const;
void add_sensitivity(const std::string &s) { sensitivity_.push_back(s); }
private:
vhdl_wait_type_t type_;
vhdl_expr *expr_;
string_list_t sensitivity_;
};
class vhdl_null_stmt : public vhdl_seq_stmt {
public:
void emit(std::ostream &of, int level) const;
};
class vhdl_assert_stmt : public vhdl_seq_stmt {
public:
vhdl_assert_stmt(const char *reason)
: reason_(reason) {}
void emit(std::ostream &of, int level) const;
private:
std::string reason_;
};
class vhdl_if_stmt : public vhdl_seq_stmt {
public:
vhdl_if_stmt(vhdl_expr *test);
~vhdl_if_stmt();
stmt_container *get_then_container() { return &then_part_; }
stmt_container *get_else_container() { return &else_part_; }
void emit(std::ostream &of, int level) const;
private:
vhdl_expr *test_;
stmt_container then_part_, else_part_;
};
/*
* A single branch in a case statement consisting of an
* expression part and a statement container.
*/
class vhdl_case_branch : public vhdl_element {
public:
vhdl_case_branch(vhdl_expr *when) : when_(when) {}
~vhdl_case_branch();
stmt_container *get_container() { return &stmts_; }
void emit(std::ostream &of, int level) const;
private:
vhdl_expr *when_;
stmt_container stmts_;
};
typedef std::list<vhdl_case_branch*> case_branch_list_t;
class vhdl_case_stmt : public vhdl_seq_stmt {
public:
vhdl_case_stmt(vhdl_expr *test) : test_(test) {}
~vhdl_case_stmt();
void add_branch(vhdl_case_branch *b) { branches_.push_back(b); }
void emit(std::ostream &of, int level) const;
private:
vhdl_expr *test_;
case_branch_list_t branches_;
};
class vhdl_loop_stmt : public vhdl_seq_stmt {
public:
virtual ~vhdl_loop_stmt() {}
stmt_container *get_container() { return &stmts_; }
void emit(std::ostream &of, int level) const;
private:
stmt_container stmts_;
};
class vhdl_while_stmt : public vhdl_loop_stmt {
public:
vhdl_while_stmt(vhdl_expr *test) : test_(test) {}
~vhdl_while_stmt();
void emit(std::ostream &of, int level) const;
private:
vhdl_expr *test_;
};
class vhdl_for_stmt : public vhdl_loop_stmt {
public:
vhdl_for_stmt(const char *lname, vhdl_expr *from, vhdl_expr *to)
: lname_(lname), from_(from), to_(to) {}
~vhdl_for_stmt();
void emit(std::ostream &of, int level) const;
private:
const char *lname_;
vhdl_expr *from_, *to_;
};
/*
* A procedure call. Which is a statement, unlike a function
* call which is an expression.
*/
class vhdl_pcall_stmt : public vhdl_seq_stmt {
public:
vhdl_pcall_stmt(const char *name) : name_(name) {}
void emit(std::ostream &of, int level) const;
void add_expr(vhdl_expr *e) { exprs_.add_expr(e); }
private:
std::string name_;
vhdl_expr_list exprs_;
};
/*
* A declaration of some sort (variable, component, etc.).
* Declarations have names, which is the identifier of the variable,
* constant, etc. not the type.
*/
class vhdl_decl : public vhdl_element {
public:
vhdl_decl(const char *name, vhdl_type *type = NULL,
vhdl_expr *initial = NULL)
: name_(name), type_(type), initial_(initial),
has_initial_(initial != NULL) {}
virtual ~vhdl_decl();
const std::string &get_name() const { return name_; }
const vhdl_type *get_type() const;
void set_type(vhdl_type *t) { type_ = t; }
void set_initial(vhdl_expr *initial);
bool has_initial() const { return has_initial_; }
protected:
std::string name_;
vhdl_type *type_;
vhdl_expr *initial_;
bool has_initial_;
};
typedef std::list<vhdl_decl*> decl_list_t;
/*
* A forward declaration of a component. At the moment it is assumed
* that components declarations will only ever be for entities
* generated by this code generator. This is enforced by making the
* constructor private (use component_decl_for instead).
*/
class vhdl_component_decl : public vhdl_decl {
public:
static vhdl_component_decl *component_decl_for(vhdl_entity *ent);
void emit(std::ostream &of, int level) const;
private:
vhdl_component_decl(const char *name);
decl_list_t ports_;
};
class vhdl_type_decl : public vhdl_decl {
public:
vhdl_type_decl(const char *name, vhdl_type *base)
: vhdl_decl(name, base) {}
void emit(std::ostream &of, int level) const;
};
/*
* A variable declaration inside a process (although this isn't
* enforced here).
*/
class vhdl_var_decl : public vhdl_decl {
public:
vhdl_var_decl(const char *name, vhdl_type *type)
: vhdl_decl(name, type) {}
void emit(std::ostream &of, int level) const;
};
/*
* A signal declaration in architecture.
*/
class vhdl_signal_decl : public vhdl_decl {
public:
vhdl_signal_decl(const char *name, vhdl_type *type)
: vhdl_decl(name, type) {}
virtual void emit(std::ostream &of, int level) const;
};
/*
* A parameter to a function.
*/
class vhdl_param_decl : public vhdl_decl {
public:
vhdl_param_decl(const char *name, vhdl_type *type)
: vhdl_decl(name, type) {}
void emit(std::ostream &of, int level) const;
};
enum vhdl_port_mode_t {
VHDL_PORT_IN,
VHDL_PORT_OUT,
VHDL_PORT_INOUT,
VHDL_PORT_BUFFER,
};
/*
* A port declaration is like a signal declaration except
* it has a direction and appears in the entity rather than
* the architecture.
*/
class vhdl_port_decl : public vhdl_decl {
public:
vhdl_port_decl(const char *name, vhdl_type *type,
vhdl_port_mode_t mode)
: vhdl_decl(name, type), mode_(mode) {}
void emit(std::ostream &of, int level) const;
vhdl_port_mode_t get_mode() const { return mode_; }
void set_mode(vhdl_port_mode_t m) { mode_ = m; }
private:
vhdl_port_mode_t mode_;
};
/*
* A mapping from port name to an expression.
*/
struct port_map_t {
std::string name;
vhdl_expr *expr;
};
typedef std::list<port_map_t> port_map_list_t;
/*
* Instantiation of component. This is really only a placeholder
* at the moment until the port mappings are worked out.
*/
class vhdl_comp_inst : public vhdl_conc_stmt {
public:
vhdl_comp_inst(const char *inst_name, const char *comp_name);
~vhdl_comp_inst();
void emit(std::ostream &of, int level) const;
void map_port(const char *name, vhdl_expr *expr);
const std::string &get_comp_name() const { return comp_name_; }
const std::string &get_inst_name() const { return inst_name_; }
private:
std::string comp_name_, inst_name_;
port_map_list_t mapping_;
};
/*
* Contains a list of declarations in a hierarchy.
* A scope can be `initializing' where assignments automatically
* create initial values for declarations.
*/
class vhdl_scope {
public:
vhdl_scope();
~vhdl_scope();
void add_decl(vhdl_decl *decl);
void add_forward_decl(vhdl_decl *decl);
vhdl_decl *get_decl(const std::string &name) const;
bool have_declared(const std::string &name) const;
bool contained_within(const vhdl_scope *other) const;
vhdl_scope *get_parent() const;
bool empty() const { return decls_.empty(); }
const decl_list_t &get_decls() const { return decls_; }
void set_parent(vhdl_scope *p) { parent_ = p; }
bool initializing() const { return init_; }
void set_initializing(bool i);
void set_allow_signal_assignment(bool b) { sig_assign_ = b; }
bool allow_signal_assignment() const { return sig_assign_; }
private:
decl_list_t decls_;
vhdl_scope *parent_;
bool init_, sig_assign_;
};
/*
* Any sort of procedural element: process, function, or
* procedure. Roughly these map onto Verilog's processes,
* functions, and tasks.
*/
class vhdl_procedural {
public:
virtual ~vhdl_procedural() {}
virtual stmt_container *get_container() { return &stmts_; }
virtual vhdl_scope *get_scope() { return &scope_; }
protected:
stmt_container stmts_;
vhdl_scope scope_;
};
class vhdl_function : public vhdl_decl, public vhdl_procedural {
friend class vhdl_forward_fdecl;
public:
vhdl_function(const char *name, vhdl_type *ret_type);
virtual void emit(std::ostream &of, int level) const;
vhdl_scope *get_scope() { return &variables_; }
void add_param(vhdl_param_decl *p) { scope_.add_decl(p); }
private:
vhdl_scope variables_;
};
class vhdl_forward_fdecl : public vhdl_decl {
public:
vhdl_forward_fdecl(const vhdl_function *f)
: vhdl_decl((f->get_name() + "_Forward").c_str()), f_(f) {}
void emit(std::ostream &of, int level) const;
private:
const vhdl_function *f_;
};
class vhdl_process : public vhdl_conc_stmt, public vhdl_procedural {
public:
vhdl_process(const char *name = "") : name_(name) {}
void emit(std::ostream &of, int level) const;
void add_sensitivity(const std::string &name);
private:
std::string name_;
string_list_t sens_;
};
/*
* An architecture which implements an entity.
*/
class vhdl_arch : public vhdl_element {
public:
vhdl_arch(const char *entity, const char *name)
: name_(name), entity_(entity) {}
virtual ~vhdl_arch();
void emit(std::ostream &of, int level=0) const;
void add_stmt(vhdl_process *proc);
void add_stmt(vhdl_conc_stmt *stmt);
vhdl_scope *get_scope() { return &scope_; }
private:
conc_stmt_list_t stmts_;
vhdl_scope scope_;
std::string name_, entity_;
};
/*
* An entity defines the ports, parameters, etc. of a module. Each
* entity is associated with a single architecture (although
* technically this need not be the case). Entities are `derived'
* from instantiations of Verilog module scopes in the hierarchy.
*/
class vhdl_entity : public vhdl_element {
public:
vhdl_entity(const char *name, const char *derived_from,
vhdl_arch *arch);
virtual ~vhdl_entity();
void emit(std::ostream &of, int level=0) const;
void add_port(vhdl_port_decl *decl);
vhdl_arch *get_arch() const { return arch_; }
const std::string &get_name() const { return name_; }
const std::string &get_derived_from() const { return derived_from_; }
vhdl_scope *get_scope() { return &ports_; }
private:
std::string name_;
vhdl_arch *arch_; // Entity may only have a single architecture
std::string derived_from_;
vhdl_scope ports_;
};
typedef std::list<vhdl_entity*> entity_list_t;
#endif
+50
View File
@@ -0,0 +1,50 @@
#ifndef INC_VHDL_TARGET_H
#define INC_VHDL_TARGET_H
#include "vhdl_config.h"
#include "ivl_target.h"
#include "vhdl_syntax.hh"
#include "vhdl_type.hh"
#include "support.hh"
#include <string>
using namespace std;
void error(const char *fmt, ...);
int draw_scope(ivl_scope_t scope, void *_parent);
int draw_process(ivl_process_t net, void *cd);
int draw_stmt(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool is_last = false);
int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm);
void draw_logic(vhdl_arch *arch, ivl_net_logic_t log);
vhdl_expr *translate_expr(ivl_expr_t e);
vhdl_expr *translate_time_expr(ivl_expr_t e);
void remember_entity(vhdl_entity *ent);
vhdl_entity *find_entity(const string &sname);
ivl_design_t get_vhdl_design();
vhdl_entity *get_active_entity();
void set_active_entity(vhdl_entity *ent);
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus);
bool seen_signal_before(ivl_signal_t sig);
void remember_signal(ivl_signal_t sig, vhdl_scope *scope);
void rename_signal(ivl_signal_t sig, const string &renamed);
vhdl_scope *find_scope_for_signal(ivl_signal_t sig);
const string &get_renamed_signal(ivl_signal_t sig);
ivl_signal_t find_signal_named(const string &name, const vhdl_scope *scope);
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool newline = true);
void require_support_function(support_function_t f);
#endif /* #ifndef INC_VHDL_TARGET_H */
+184
View File
@@ -0,0 +1,184 @@
/*
* VHDL variable and signal 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_type.hh"
#include <cassert>
#include <sstream>
#include <iostream>
vhdl_type *vhdl_type::std_logic()
{
return new vhdl_type(VHDL_TYPE_STD_LOGIC);
}
vhdl_type *vhdl_type::string()
{
return new vhdl_type(VHDL_TYPE_STRING);
}
vhdl_type *vhdl_type::line()
{
return new vhdl_type(VHDL_TYPE_LINE);
}
vhdl_type *vhdl_type::boolean()
{
return new vhdl_type(VHDL_TYPE_BOOLEAN);
}
vhdl_type *vhdl_type::integer()
{
return new vhdl_type(VHDL_TYPE_INTEGER);
}
vhdl_type *vhdl_type::nunsigned(int width, int lsb)
{
return new vhdl_type(VHDL_TYPE_UNSIGNED, width-1+lsb, lsb);
}
vhdl_type *vhdl_type::nsigned(int width, int lsb)
{
return new vhdl_type(VHDL_TYPE_SIGNED, width-1+lsb, lsb);
}
vhdl_type *vhdl_type::time()
{
return new vhdl_type(VHDL_TYPE_TIME);
}
vhdl_type *vhdl_type::get_base() const
{
assert(name_ == VHDL_TYPE_ARRAY);
return base_;
}
/*
* This is just the name of the type, without any parameters.
*/
std::string vhdl_type::get_string() const
{
switch (name_) {
case VHDL_TYPE_STD_LOGIC:
return std::string("std_logic");
case VHDL_TYPE_STD_LOGIC_VECTOR:
return std::string("std_logic_vector");
case VHDL_TYPE_STRING:
return std::string("String");
case VHDL_TYPE_LINE:
return std::string("Line");
case VHDL_TYPE_FILE:
return std::string("File");
case VHDL_TYPE_INTEGER:
return std::string("Integer");
case VHDL_TYPE_BOOLEAN:
return std::string("Boolean");
case VHDL_TYPE_SIGNED:
return std::string("signed");
case VHDL_TYPE_UNSIGNED:
return std::string("unsigned");
case VHDL_TYPE_ARRAY:
// Each array has its own type declaration
return array_name_;
default:
return std::string("BadType");
}
}
/*
* The is the qualified name of the type.
*/
std::string vhdl_type::get_decl_string() const
{
switch (name_) {
case VHDL_TYPE_STD_LOGIC_VECTOR:
case VHDL_TYPE_UNSIGNED:
case VHDL_TYPE_SIGNED:
{
std::ostringstream ss;
ss << get_string() << "(" << msb_;
ss << " downto " << lsb_ << ")";
return ss.str();
}
default:
return get_string();
}
}
/*
* Like get_decl_string but completely expands array declarations.
*/
std::string vhdl_type::get_type_decl_string() const
{
switch (name_) {
case VHDL_TYPE_ARRAY:
{
std::ostringstream ss;
ss << "array (" << msb_ << " downto "
<< lsb_ << ") of "
<< base_->get_decl_string();
return ss.str();
}
default:
return get_decl_string();
}
}
void vhdl_type::emit(std::ostream &of, int level) const
{
of << get_decl_string();
}
vhdl_type::vhdl_type(const vhdl_type &other)
: name_(other.name_), msb_(other.msb_), lsb_(other.lsb_),
array_name_(other.array_name_)
{
if (other.base_ != NULL)
base_ = new vhdl_type(*other.base_);
else
base_ = NULL;
}
vhdl_type::~vhdl_type()
{
if (base_ != NULL)
delete base_;
}
vhdl_type *vhdl_type::std_logic_vector(int msb, int lsb)
{
return new vhdl_type(VHDL_TYPE_STD_LOGIC_VECTOR, msb, lsb);
}
vhdl_type *vhdl_type::type_for(int width, bool issigned, int lsb)
{
if (width == 1)
return vhdl_type::std_logic();
else if (issigned)
return vhdl_type::nsigned(width, lsb);
else
return vhdl_type::nunsigned(width, lsb);
}
vhdl_type *vhdl_type::array_of(vhdl_type *b, std::string &n, int m, int l)
{
return new vhdl_type(b, n, m, l);
}
+92
View File
@@ -0,0 +1,92 @@
/*
* VHDL variable and signal 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.
*/
#ifndef INC_VHDL_TYPE_HH
#define INC_VHDL_TYPE_HH
#include "vhdl_element.hh"
enum vhdl_type_name_t {
VHDL_TYPE_STD_LOGIC,
VHDL_TYPE_STD_LOGIC_VECTOR,
VHDL_TYPE_STRING,
VHDL_TYPE_LINE,
VHDL_TYPE_FILE,
VHDL_TYPE_INTEGER,
VHDL_TYPE_BOOLEAN,
VHDL_TYPE_SIGNED,
VHDL_TYPE_UNSIGNED,
VHDL_TYPE_TIME,
VHDL_TYPE_ARRAY,
};
/*
* A type at the moment is just a name. It shouldn't get
* too much more complex, as Verilog's type system is much
* simpler than VHDL's.
*/
class vhdl_type : public vhdl_element {
public:
// Scalar constructor
vhdl_type(vhdl_type_name_t name, int msb = 0, int lsb = 0)
: name_(name), msb_(msb), lsb_(lsb), base_(NULL) {}
// Array constructor
vhdl_type(vhdl_type *base, const std::string &array_name,
int msb, int lsb)
: name_(VHDL_TYPE_ARRAY), msb_(msb), lsb_(lsb), base_(base),
array_name_(array_name) {}
// Copy constructor
vhdl_type(const vhdl_type &other);
virtual ~vhdl_type();
void emit(std::ostream &of, int level) const;
vhdl_type_name_t get_name() const { return name_; }
std::string get_string() const;
std::string get_decl_string() const;
std::string get_type_decl_string() const;
vhdl_type *get_base() const;
int get_width() const { return msb_ - lsb_ + 1; }
int get_msb() const { return msb_; }
int get_lsb() const { return lsb_; }
// Common types
static vhdl_type *std_logic();
static vhdl_type *string();
static vhdl_type *line();
static vhdl_type *std_logic_vector(int msb, int lsb);
static vhdl_type *nunsigned(int width, int lsb=0);
static vhdl_type *nsigned(int width, int lsb=0);
static vhdl_type *integer();
static vhdl_type *boolean();
static vhdl_type *time();
static vhdl_type *type_for(int width, bool issigned, int lsb=0);
static vhdl_type *array_of(vhdl_type *b, std::string &n, int m, int l);
protected:
vhdl_type_name_t name_;
int msb_, lsb_;
vhdl_type *base_; // Array base type for VHDL_TYPE_ARRAY
std::string array_name_; // Type name for the array `type array_name_ is ...'
};
#endif
+6
View File
@@ -0,0 +1,6 @@
#include <stdlib.h>
void finish(void)
{
exit(0);
}
+3 -3
View File
@@ -47,9 +47,9 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
const char*dly = "";
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64));
assert(number_is_immediate(d_fall, 64));
assert(number_is_immediate(d_decay, 64));
assert(number_is_immediate(d_rise, 64, 0));
assert(number_is_immediate(d_fall, 64, 0));
assert(number_is_immediate(d_decay, 64, 0));
dly = "/d";
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
net, get_number_immediate(d_rise),
+6 -4
View File
@@ -315,7 +315,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
because it may be an array of reg vectors. */
snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);
if (ivl_signal_array_count(sptr) > 1) {
if (ivl_signal_dimensions(sptr) > 0) {
fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
sptr, nptr_pin, sptr, nptr_pin);
}
@@ -359,9 +359,9 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
/* We have a delayed constant, so we need to build some code. */
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64));
assert(number_is_immediate(d_fall, 64));
assert(number_is_immediate(d_decay, 64));
assert(number_is_immediate(d_rise, 64, 0));
assert(number_is_immediate(d_fall, 64, 0));
assert(number_is_immediate(d_decay, 64, 0));
fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, "
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
@@ -387,6 +387,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_ARRAY:
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL:
case IVL_LPM_CONCAT:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
+4 -4
View File
@@ -30,7 +30,7 @@ static void function_argument_logic(ivl_signal_t port, ivl_expr_t exp)
struct vector_info res;
/* ports cannot be arrays. */
assert(ivl_signal_array_count(port) == 1);
assert(ivl_signal_dimensions(port) == 0);
res = draw_eval_expr_wid(exp, ivl_signal_width(port), 0);
/* We could have extra bits so only select the ones we need. */
@@ -46,7 +46,7 @@ static void function_argument_real(ivl_signal_t port, ivl_expr_t exp)
int res = draw_eval_real(exp);
/* ports cannot be arrays. */
assert(ivl_signal_array_count(port) == 1);
assert(ivl_signal_dimensions(port) == 0);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", port, res);
clr_word(res);
@@ -126,7 +126,7 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid)
if (load_wid > ivl_signal_width(retval))
load_wid = ivl_signal_width(retval);
assert(ivl_signal_array_count(retval) == 1);
assert(ivl_signal_dimensions(retval) == 0);
fprintf(vvp_out, " %%load/v %u, v%p_0, %u;\n",
res.base, retval, load_wid);
@@ -157,7 +157,7 @@ int draw_ufunc_real(ivl_expr_t exp)
fprintf(vvp_out, " %%join;\n");
/* Return value signal cannot be an array. */
assert(ivl_signal_array_count(retval) == 1);
assert(ivl_signal_dimensions(retval) == 0);
/* Load the result into a word. */
res = allocate_word();
+20 -83
View File
@@ -29,82 +29,6 @@
#define snprintf _snprintf
#endif
/*
* Check to see if the expression (number) can be correctly represented
* with a long variable.
*/
static int is_constant_number(ivl_expr_t ex)
{
/* Make sure this matches the return type of constant_number(). */
unsigned lim_wid = 8*sizeof(long);
const char*bits;
char pad_bit = '0';
unsigned idx;
unsigned nbits = ivl_expr_width(ex);
if (ivl_expr_type(ex) != IVL_EX_NUMBER
&& ivl_expr_type(ex) != IVL_EX_ULONG)
return 0;
bits = ivl_expr_bits(ex);
/* For unsigned values the effective MSB and on must be '0'. */
if (!ivl_expr_signed(ex)) lim_wid -= 1;
/* For negative values the pad bit is '1'. */
if (ivl_expr_signed(ex) && bits[nbits-1]=='1') {
pad_bit = '1';
}
/* For the number to fit in the variable all the upper bits must
* match the pad bits. */
for (idx = lim_wid ; idx < nbits ; idx += 1) {
if (bits[idx] != pad_bit) return 0;
}
return 1;
}
/*
* Convert the expression (number) to a long value.
*/
static long get_constant_number(ivl_expr_t ex)
{
long rtn = 0;
switch (ivl_expr_type(ex)) {
case IVL_EX_ULONG:
rtn = (signed)ivl_expr_value(ex);
break;
case IVL_EX_NUMBER: {
unsigned idx;
const char*bits = ivl_expr_bits(ex);
unsigned nbits = ivl_expr_width(ex);
char pad_bit = bits[nbits-1];
/* Define all the bits in the long (negative numbers). */
for (idx = 0 ; idx < 8*sizeof(long) ; idx += 1) {
char bit;
if (idx < nbits) bit = bits[idx];
else bit = pad_bit;
switch (bit) {
case '0':
break;
case '1':
rtn |= 1 << idx;
break;
default:
assert(0);
}
}
break;
}
default:
assert(0);
}
return rtn;
}
static const char* magic_sfuncs[] = {
"$time",
"$stime",
@@ -138,7 +62,7 @@ static int is_fixed_memory_word(ivl_expr_t net)
if (ivl_signal_type(sig) == IVL_SIT_REG)
return 0;
if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned)))
if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned), 0))
return 1;
return 0;
@@ -258,7 +182,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
ivl_expr_t word_ex = ivl_expr_oper1(expr);
if (word_ex) {
/* Some array select have been evaluated. */
if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
if (number_is_immediate(word_ex, 8*sizeof(unsigned), 0)) {
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
@@ -280,16 +204,22 @@ static void draw_vpi_taskfunc_args(const char*call_string,
ivl_expr_t word_ex = ivl_expr_oper1(expr);
if (word_ex) {
/* Some array select have been evaluated. */
if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
if (number_is_immediate(word_ex, 8*sizeof(unsigned), 0)) {
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
}
if (word_ex) {
if (word_ex && ivl_expr_type(word_ex)==IVL_EX_SIGNAL) {
/* Special case: the index is a signal. */
snprintf(buffer, sizeof buffer,
"&A<v%p, v%p_0 >", sig,
ivl_expr_signal(word_ex));
} else if (word_ex) {
/* Fallback case: evaluate expression. */
struct vector_info av;
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
snprintf(buffer, sizeof buffer,
"&A<v%p, T<%u,%u,u>>", sig, av.base, av.wid);
"&A<v%p, %u %u>", sig, av.base, av.wid);
args[idx].vec = av;
args[idx].vec_flag = 1;
} else {
@@ -315,13 +245,20 @@ static void draw_vpi_taskfunc_args(const char*call_string,
assert(bexpr);
/* This is a constant bit/part select. */
if (is_constant_number(bexpr)) {
if (number_is_immediate(bexpr, 64, 1)) {
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
ivl_expr_signal(vexpr),
get_constant_number(bexpr),
get_number_immediate(bexpr),
ivl_expr_width(expr));
/* This is an indexed bit/part select. */
} else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL) {
/* Sepcial case: the base is a signal. */
snprintf(buffer, sizeof buffer, "&PV<v%p_0, v%p_0, %u>",
ivl_expr_signal(vexpr),
ivl_expr_signal(bexpr),
ivl_expr_width(expr));
} else {
/* Fallback case: evaluate the expression. */
struct vector_info rv;
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>",
+84 -83
View File
@@ -28,7 +28,7 @@
static void draw_eval_expr_dest(ivl_expr_t exp, struct vector_info dest,
int ok_flags);
static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
int add_index, unsigned long immediate);
int add_index, long immediate);
int number_is_unknown(ivl_expr_t ex)
{
@@ -54,9 +54,11 @@ int number_is_unknown(ivl_expr_t ex)
* above bitX. The maximum size of the immediate may vary, so use
* lim_wid at the width limit to use.
*/
int number_is_immediate(ivl_expr_t ex, unsigned lim_wid)
int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_ok_flag)
{
const char*bits;
unsigned nbits = ivl_expr_width(ex);
char pad_bit = '0';
unsigned idx;
if (ivl_expr_type(ex) != IVL_EX_NUMBER
@@ -64,20 +66,23 @@ int number_is_immediate(ivl_expr_t ex, unsigned lim_wid)
return 0;
bits = ivl_expr_bits(ex);
for (idx = lim_wid ; idx < ivl_expr_width(ex) ; idx += 1)
if (bits[idx] != '0')
return 0;
/* Negative numbers are not "immediate". */
if (ivl_expr_signed(ex) && bits[ivl_expr_width(ex)-1]=='1')
if (ivl_expr_signed(ex) && bits[nbits-1]=='1')
pad_bit = '1';
if (pad_bit == '1' && !negative_ok_flag)
return 0;
for (idx = lim_wid ; idx < nbits ; idx += 1)
if (bits[idx] != pad_bit)
return 0;
return 1;
}
unsigned long get_number_immediate(ivl_expr_t ex)
long get_number_immediate(ivl_expr_t ex)
{
unsigned long imm = 0;
long imm = 0;
unsigned idx;
switch (ivl_expr_type(ex)) {
@@ -93,11 +98,13 @@ unsigned long get_number_immediate(ivl_expr_t ex)
break;
case '1':
assert(idx < 8*sizeof(imm));
imm |= 1UL << idx;
imm |= 1L << idx;
break;
default:
assert(0);
}
if (ivl_expr_signed(ex) && bits[nbits-1]=='1' && nbits < 8*sizeof(imm))
imm |= -1L << nbits;
break;
}
@@ -112,30 +119,18 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
{
switch (ivl_expr_type(expr)) {
case IVL_EX_NUMBER: {
unsigned value = 0;
unsigned idx, nbits = ivl_expr_width(expr);
const char*bits = ivl_expr_bits(expr);
for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]) {
case '0':
break;
case '1':
assert(idx < (8*sizeof value));
value |= 1 << idx;
break;
default:
assert(0);
}
fprintf(vvp_out, " %%ix/load %u, %u;\n", ix, value);
break;
}
case IVL_EX_NUMBER:
case IVL_EX_ULONG:
fprintf(vvp_out, " %%ix/load %u, %lu;\n", ix, ivl_expr_uvalue(expr));
break;
{
long imm = get_number_immediate(expr);
if (imm >= 0) {
fprintf(vvp_out, " %%ix/load %u, %ld;\n", ix, imm);
} else {
fprintf(vvp_out, " %%ix/load %u, 0; loading %ld\n", ix, imm);
fprintf(vvp_out, " %%ix/sub %u, %ld;\n", ix, -imm);
}
}
break;
case IVL_EX_SIGNAL: {
ivl_signal_t sig = ivl_expr_signal(expr);
@@ -156,7 +151,7 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
}
ivl_expr_t ixe = ivl_expr_oper1(expr);
if (number_is_immediate(ixe, 8*sizeof(unsigned long)))
if (number_is_immediate(ixe, 8*sizeof(unsigned long), 0))
word = get_number_immediate(ixe);
else {
struct vector_info rv;
@@ -384,7 +379,7 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t exp,
return draw_binary_expr_eq_real(exp);
}
if (number_is_immediate(re,16) && !number_is_unknown(re))
if (number_is_immediate(re,16,0) && !number_is_unknown(re))
return draw_eq_immediate(exp, ewid, le, re, stuff_ok_flag);
assert(ivl_expr_value(le) == IVL_VT_LOGIC
@@ -815,7 +810,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
switch (ivl_expr_opcode(exp)) {
case 'G':
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
if (number_is_immediate(le,16) && !number_is_unknown(le)) {
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
unsigned imm = get_number_immediate(le);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
@@ -831,7 +826,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
case 'L':
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
if (number_is_immediate(re,16) && !number_is_unknown(re)) {
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
unsigned imm = get_number_immediate(re);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
@@ -847,7 +842,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
case '<':
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
if (number_is_immediate(re,16) && !number_is_unknown(re)) {
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
unsigned imm = get_number_immediate(re);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
@@ -862,7 +857,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
case '>':
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
if (number_is_immediate(le,16) && !number_is_unknown(le)) {
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
unsigned imm = get_number_immediate(le);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
@@ -941,9 +936,9 @@ static struct vector_info draw_binary_expr_logic(ivl_expr_t exp,
ivl_expr_t re = ivl_expr_oper2(exp);
if (ivl_expr_opcode(exp) == '&') {
if (number_is_immediate(re, IMM_WID) && !number_is_unknown(re))
if (number_is_immediate(re, IMM_WID, 0) && !number_is_unknown(re))
return draw_logic_immediate(exp, le, re, wid);
if (number_is_immediate(le, IMM_WID) && !number_is_unknown(le))
if (number_is_immediate(le, IMM_WID, 0) && !number_is_unknown(le))
return draw_logic_immediate(exp, re, le, wid);
}
@@ -1163,12 +1158,11 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid)
static struct vector_info draw_load_add_immediate(ivl_expr_t le,
ivl_expr_t re,
unsigned wid)
unsigned wid,
int signed_flag)
{
struct vector_info lv;
unsigned long imm;
imm = get_number_immediate(re);
long imm = get_number_immediate(re);
lv.base = allocate_vector(wid);
lv.wid = wid;
if (lv.base == 0) {
@@ -1181,7 +1175,7 @@ static struct vector_info draw_load_add_immediate(ivl_expr_t le,
/* Load the signal value with a %load that adds the index
register to the value being loaded. */
draw_signal_dest(le, lv, 0, imm);
draw_signal_dest(le, lv, signed_flag, imm);
return lv;
}
@@ -1324,25 +1318,27 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
const char*sign_string = ivl_expr_signed(le) && ivl_expr_signed(re)? "/s" : "";
int signed_flag = ivl_expr_signed(exp)? 1 : 0;
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(le) == IVL_EX_SIGNAL)
&& (ivl_expr_type(re) == IVL_EX_ULONG))
return draw_load_add_immediate(le, re, wid);
return draw_load_add_immediate(le, re, wid, signed_flag);
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(le) == IVL_EX_SIGNAL)
&& (ivl_expr_type(re) == IVL_EX_NUMBER))
return draw_load_add_immediate(le, re, wid);
return draw_load_add_immediate(le, re, wid, signed_flag);
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(re) == IVL_EX_SIGNAL)
&& (ivl_expr_type(le) == IVL_EX_ULONG))
return draw_load_add_immediate(re, le, wid);
return draw_load_add_immediate(re, le, wid, signed_flag);
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(re) == IVL_EX_SIGNAL)
&& (ivl_expr_type(le) == IVL_EX_NUMBER))
return draw_load_add_immediate(re, le, wid);
return draw_load_add_immediate(re, le, wid, signed_flag);
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(re) == IVL_EX_ULONG))
@@ -1351,7 +1347,7 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
&& (! number_is_unknown(re))
&& number_is_immediate(re, 8*sizeof(unsigned long)))
&& number_is_immediate(re, 8*sizeof(unsigned long), 0))
return draw_add_immediate(le, re, wid);
if ((ivl_expr_opcode(exp) == '-')
@@ -1361,13 +1357,13 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
if ((ivl_expr_opcode(exp) == '-')
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
&& (! number_is_unknown(re))
&& number_is_immediate(re, IMM_WID))
&& number_is_immediate(re, IMM_WID, 0))
return draw_sub_immediate(le, re, wid);
if ((ivl_expr_opcode(exp) == '*')
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
&& (! number_is_unknown(re))
&& number_is_immediate(re, IMM_WID))
&& number_is_immediate(re, IMM_WID, 0))
return draw_mul_immediate(le, re, wid);
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
@@ -1674,7 +1670,7 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
vvp_errors += 1;
}
if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID)) {
if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID,0)) {
unsigned long val = get_number_immediate(exp);
fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid);
return res;
@@ -1968,11 +1964,13 @@ void pad_expr_in_place(ivl_expr_t exp, struct vector_info res, unsigned swid)
* offsetting the read from the lsi (least significant index) of the
* signal.
*
* If the add_index is >=0, then generate a %load/vp0 to add the
* word0 value to the loaded value before storing it into the destination.
* If the add_index is 0, then generate a %load/vp0 to add the
* word0 value to the loaded value before storing it into the
* destination. If the add_index is 1, then generate a %load/vp0/s to
* do a signed load.
*/
static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
int add_index, unsigned long immediate)
int add_index, long immediate)
{
unsigned swid = ivl_expr_width(exp);
ivl_signal_t sig = ivl_expr_signal(exp);
@@ -1989,17 +1987,17 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
draw_eval_expr_into_integer(ix, 3);
if (add_index < 0) {
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
res.base, sig, swid);
pad_expr_in_place(exp, res, swid);
} else {
assert(add_index == 0);
const char*sign_flag = (add_index>0)? "/s" : "";
/* Add an immediate value to an array value. */
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
fprintf(vvp_out, " %%load/avp0 %u, v%p, %u;\n",
res.base, sig, swid);
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
fprintf(vvp_out, " %%load/avp0%s %u, v%p, %u;\n",
sign_flag, res.base, sig, res.wid);
}
pad_expr_in_place(exp, res, swid);
return;
}
@@ -2014,13 +2012,17 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
} else if (add_index >= 0) {
assert(add_index == 0);
const char*sign_flag = add_index==1? "/s" : "";
/* If this is a REG (a variable) then I can do a vector read. */
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
fprintf(vvp_out, " %%ix/load 2, %u;\n", res.wid);
fprintf(vvp_out, " %%load/vp0 %u, v%p_%u, %u;\n",
res.base, sig, word, swid);
if (immediate >= 0) {
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
} else {
fprintf(vvp_out, " %%ix/load 0, 0; immediate=%ld\n", immediate);
fprintf(vvp_out, " %%ix/sub 0, %ld;\n", -immediate);
}
fprintf(vvp_out, " %%load/vp0%s %u, v%p_%u, %u;\n", sign_flag,
res.base, sig,word, res.wid);
swid = res.wid;
} else {
@@ -2109,7 +2111,6 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
{
ivl_signal_t sig = ivl_expr_signal(sube);
struct vector_info res;
unsigned idx;
/* Use this word of the signal. */
unsigned use_word = 0;
@@ -2124,7 +2125,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
ivl_expr_t ix = ivl_expr_oper1(sube);
if (ivl_signal_type(sig)==IVL_SIT_REG
|| !number_is_immediate(ix, 8*sizeof(unsigned long)))
|| !number_is_immediate(ix, 8*sizeof(unsigned long),0))
return draw_select_array(sube, bit_idx, bit_wid, wid);
/* The index is constant, so we can return to direct
@@ -2135,7 +2136,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
/* Try the special case that the part is at the beginning of
the signal (or the entire width). Just load the early bits
in one go. */
if (number_is_immediate(bit_idx, 32)
if (number_is_immediate(bit_idx, 32, 0)
&& get_number_immediate(bit_idx) == 0
&& (ivl_expr_width(sube) >= bit_wid)) {
@@ -2153,23 +2154,23 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
return res;
}
draw_eval_expr_into_integer(bit_idx, 0);
/* Alas, do it the hard way. */
draw_eval_expr_into_integer(bit_idx, 1);
res.base = allocate_vector(wid);
res.wid = wid;
assert(res.base);
for (idx = 0 ; idx < res.wid ; idx += 1) {
if (idx >= bit_wid) {
fprintf(vvp_out, " %%movi %u, 0, %u; Pad from %u to %u\n",
res.base+idx, res.wid-idx,
ivl_expr_width(sube), wid);
break;
}
fprintf(vvp_out, " %%load/x.p %u, v%p_%u, 0;\n",
res.base+idx, sig, use_word);
}
unsigned use_wid = res.wid;
if (use_wid > bit_wid)
use_wid = bit_wid;
fprintf(vvp_out, " %%load/x1p %u, v%p_%u, %u;\n",
res.base, sig, use_word, use_wid);
if (use_wid < res.wid)
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
res.base + use_wid, res.wid - use_wid);
return res;
}
+19 -4
View File
@@ -326,9 +326,9 @@ static int draw_signal_real_real(ivl_expr_t exp)
int res = allocate_word();
unsigned long word = 0;
if (ivl_signal_array_count(sig) > 1) {
if (ivl_signal_dimensions(sig) > 0) {
ivl_expr_t ix = ivl_expr_oper1(exp);
if (!number_is_immediate(ix, 8*sizeof(word))) {
if (!number_is_immediate(ix, 8*sizeof(word), 0)) {
/* XXXX Need to generate a %load/ar instruction. */
assert(0);
return res;
@@ -441,7 +441,22 @@ static int draw_unary_real(ivl_expr_t exp)
return res;
}
if (ivl_expr_opcode(exp) == '!') {
struct vector_info vi;
vi = draw_eval_expr(exp, STUFF_OK_XZ);
int res = allocate_word();
const char*sign_flag = ivl_expr_signed(exp)? "/s" : "";
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, vi.base, vi.wid);
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
clr_vector(vi);
return res;
}
ivl_expr_t sube = ivl_expr_oper1(exp);
int sub = draw_eval_real(sube);
if (ivl_expr_opcode(exp) == '+')
@@ -461,8 +476,8 @@ static int draw_unary_real(ivl_expr_t exp)
return sub;
}
fprintf(vvp_out, "; XXXX unary (%c)\n", ivl_expr_opcode(exp));
fprintf(stderr, "XXXX evaluate unary (%c)\n", ivl_expr_opcode(exp));
fprintf(vvp_out, "; XXXX unary (%c) on sube in %d\n", ivl_expr_opcode(exp), sub);
fprintf(stderr, "XXXX evaluate unary (%c) on sube in %d\n", ivl_expr_opcode(exp), sub);
return 0;
}
+3 -3
View File
@@ -94,7 +94,7 @@ extern void pad_expr_in_place(ivl_expr_t exp, struct vector_info res, unsigned s
* draw_modpath arranges for a .modpath record to be written out.
*
* cleanup_modpath() cleans up any pending .modpath records that may
* have been scheduled by draw_modpath() but not yet writte.
* have been scheduled by draw_modpath() but not yet written.
*
* Note: draw_modpath drive_label must be malloc'ed by the
* caller. This function will free the string sometime in the future.
@@ -269,8 +269,8 @@ extern unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid,
int exclusive_flag);
extern int number_is_unknown(ivl_expr_t ex);
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid);
extern unsigned long get_number_immediate(ivl_expr_t ex);
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_is_ok);
extern long get_number_immediate(ivl_expr_t ex);
/*
* draw_eval_real evaluates real value expressions. The return code
+21 -21
View File
@@ -83,7 +83,7 @@ static void set_to_lvariable(ivl_lval_t lval,
if (part_off_ex == 0) {
part_off = 0;
} else if (number_is_immediate(part_off_ex, 64)) {
} else if (number_is_immediate(part_off_ex, 64, 0)) {
part_off = get_number_immediate(part_off_ex);
part_off_ex = 0;
}
@@ -91,7 +91,7 @@ static void set_to_lvariable(ivl_lval_t lval,
/* If the word index is a constant expression, then evaluate
it to select the word, and pay no further heed to the
expression itself. */
if (word_ix && number_is_immediate(word_ix, 8*sizeof(use_word))) {
if (word_ix && number_is_immediate(word_ix, 8*sizeof(use_word), 0)) {
use_word = get_number_immediate(word_ix);
word_ix = 0;
}
@@ -227,15 +227,15 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
unsigned part_off = 0;
if (part_off_ex == 0) {
part_off = 0;
} else if (number_is_immediate(part_off_ex, 64)) {
} else if (number_is_immediate(part_off_ex, 64, 0)) {
part_off = get_number_immediate(part_off_ex);
part_off_ex = 0;
}
if (dexp == 0) {
/* Constant delay... */
if (number_is_immediate(word_ix, 64)) {
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
if (number_is_immediate(word_ix, 64, 0)) {
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
get_number_immediate(word_ix));
} else {
/* Calculate array word index into index register 3 */
@@ -259,7 +259,7 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
/* Calculated delay... */
int delay_index = allocate_word();
draw_eval_expr_into_integer(dexp, delay_index);
if (number_is_immediate(word_ix, 64)) {
if (number_is_immediate(word_ix, 64, 0)) {
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
get_number_immediate(word_ix));
} else {
@@ -298,7 +298,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
ivl_expr_t word_ix = ivl_lval_idx(lval);
const unsigned long use_word = 0;
if (ivl_signal_array_count(sig) > 1) {
if (ivl_signal_dimensions(sig) > 0) {
assert(word_ix);
assign_to_array_word(sig, word_ix, bit, delay, dexp, part_off_ex, width);
return;
@@ -306,7 +306,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
if (part_off_ex == 0) {
part_off = 0;
} else if (number_is_immediate(part_off_ex, 64)) {
} else if (number_is_immediate(part_off_ex, 64, 0)) {
part_off = get_number_immediate(part_off_ex);
part_off_ex = 0;
}
@@ -480,7 +480,7 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
var = ivl_lval_sig(lval);
assert(var != 0);
assert(ivl_signal_array_count(var) == 1);
assert(ivl_signal_dimensions(var) == 0);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
@@ -540,10 +540,10 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
sig = ivl_lval_sig(lval);
assert(sig);
if (ivl_signal_array_count(sig) > 1) {
if (ivl_signal_dimensions(sig) > 0) {
word_ix = ivl_lval_idx(lval);
assert(word_ix);
assert(number_is_immediate(word_ix, 8*sizeof(use_word)));
assert(number_is_immediate(word_ix, 8*sizeof(use_word), 0));
use_word = get_number_immediate(word_ix);
}
@@ -700,7 +700,7 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
if ((ivl_statement_type(net) == IVL_ST_CASE)
&& (ivl_expr_type(cex) == IVL_EX_NUMBER)
&& (! number_is_unknown(cex))
&& number_is_immediate(cex, 16)) {
&& number_is_immediate(cex, 16, 0)) {
unsigned long imm = get_number_immediate(cex);
@@ -926,12 +926,12 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
if (part_off_ex == 0) {
part_off = 0;
} else {
assert(number_is_immediate(part_off_ex, 64));
assert(number_is_immediate(part_off_ex, 64, 0));
part_off = get_number_immediate(part_off_ex);
}
if (word_idx != 0) {
assert(number_is_immediate(word_idx, 8*sizeof(unsigned long)));
assert(number_is_immediate(word_idx, 8*sizeof(unsigned long), 0));
use_word = get_number_immediate(word_idx);
}
@@ -1004,16 +1004,16 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
/* At least for now, only handle force to fixed words of an array. */
if ((lword_idx = ivl_lval_idx(lval)) != 0) {
assert(number_is_immediate(lword_idx, 8*sizeof(unsigned long)));
assert(number_is_immediate(lword_idx, 8*sizeof(unsigned long), 0));
use_lword = get_number_immediate(lword_idx);
}
if ((rword_idx = ivl_expr_oper1(rval)) != 0) {
assert(number_is_immediate(rword_idx, 8*sizeof(unsigned long)));
assert(number_is_immediate(rword_idx, 8*sizeof(unsigned long), 0));
use_rword = get_number_immediate(rword_idx);
}
assert(ivl_signal_array_count(rsig) == 1);
assert(ivl_signal_dimensions(rsig) == 0);
use_rword = 0;
fprintf(vvp_out, " %s/link", command_name);
@@ -1087,12 +1087,12 @@ static int show_stmt_deassign(ivl_statement_t net)
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off = 0;
if (part_off_ex != 0) {
assert(number_is_immediate(part_off_ex, 64));
assert(number_is_immediate(part_off_ex, 64, 0));
part_off = get_number_immediate(part_off_ex);
}
if (word_idx != 0) {
assert(number_is_immediate(word_idx, 8*sizeof(use_word)));
assert(number_is_immediate(word_idx, 8*sizeof(use_word), 0));
use_word = get_number_immediate(word_idx);
}
@@ -1369,7 +1369,7 @@ static int show_stmt_release(ivl_statement_t net)
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off = 0;
if (part_off_ex != 0) {
assert(number_is_immediate(part_off_ex, 64));
assert(number_is_immediate(part_off_ex, 64, 0));
part_off = get_number_immediate(part_off_ex);
}
@@ -1383,7 +1383,7 @@ static int show_stmt_release(ivl_statement_t net)
}
if (word_idx != 0) {
assert(number_is_immediate(word_idx, 8*sizeof(use_word)));
assert(number_is_immediate(word_idx, 8*sizeof(use_word), 0));
use_word = get_number_immediate(word_idx);
}
+89 -56
View File
@@ -546,9 +546,9 @@ static void draw_delay(ivl_net_logic_t lptr)
return;
/* FIXME: Assume that the expression is a constant */
assert(number_is_immediate(d0, 64));
assert(number_is_immediate(d1, 64));
assert(number_is_immediate(d2, 64));
assert(number_is_immediate(d0, 64, 0));
assert(number_is_immediate(d1, 64, 0));
assert(number_is_immediate(d2, 64, 0));
if (d0 == d1 && d1 == d2)
fprintf(vvp_out, " (%lu)", get_number_immediate(d0));
@@ -862,9 +862,9 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
ivl_expr_t fall_exp = ivl_logic_delay(lptr,1);
ivl_expr_t decay_exp = ivl_logic_delay(lptr,2);
if (number_is_immediate(rise_exp,64)
&& number_is_immediate(fall_exp,64)
&& number_is_immediate(decay_exp,64)) {
if (number_is_immediate(rise_exp,64,0)
&& number_is_immediate(fall_exp,64,0)
&& number_is_immediate(decay_exp,64,0)) {
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
lptr, get_number_immediate(rise_exp),
@@ -879,15 +879,15 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
fprintf(vvp_out, "L_%p .delay L_%p/d", lptr, lptr);
sig = ivl_expr_signal(rise_exp);
assert(ivl_signal_array_count(sig) == 1);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0", sig);
sig = ivl_expr_signal(fall_exp);
assert(ivl_signal_array_count(sig) == 1);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0", sig);
sig = ivl_expr_signal(decay_exp);
assert(ivl_signal_array_count(sig) == 1);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0;\n", sig);
}
}
@@ -895,6 +895,10 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
static void draw_event_in_scope(ivl_event_t obj)
{
char tmp[4][32];
const unsigned ntmp = sizeof(tmp) / sizeof(tmp[0]);
unsigned nany = ivl_event_nany(obj);
unsigned nneg = ivl_event_nneg(obj);
unsigned npos = ivl_event_npos(obj);
@@ -903,13 +907,13 @@ static void draw_event_in_scope(ivl_event_t obj)
/* Figure out how many probe functors are needed. */
if (nany > 0)
cnt += (nany+3) / 4;
cnt += (nany+ntmp-1) / ntmp;
if (nneg > 0)
cnt += (nneg+3) / 4;
cnt += (nneg+ntmp-1) / ntmp;
if (npos > 0)
cnt += (npos+3) / 4;
cnt += (npos+ntmp-1) / ntmp;
if (cnt == 0) {
/* If none are needed, then this is a named event. The
@@ -923,48 +927,57 @@ static void draw_event_in_scope(ivl_event_t obj)
unsigned idx;
unsigned ecnt = 0;
for (idx = 0 ; idx < nany ; idx += 4, ecnt += 1) {
for (idx = 0 ; idx < nany ; idx += ntmp, ecnt += 1) {
unsigned sub, top;
fprintf(vvp_out, "E_%p/%u .event edge", obj, ecnt);
top = idx + 4;
top = idx + ntmp;
if (nany < top)
top = nany;
for (sub = idx ; sub < top ; sub += 1) {
ivl_nexus_t nex = ivl_event_any(obj, sub);
fprintf(vvp_out, ", %s", draw_input_from_net(nex));
strncpy(tmp[sub-idx], draw_input_from_net(nex), sizeof(tmp[0]));
}
fprintf(vvp_out, "E_%p/%u .event edge", obj, ecnt);
for (sub = idx ; sub < top ; sub += 1)
fprintf(vvp_out, ", %s", tmp[sub-idx]);
fprintf(vvp_out, ";\n");
}
for (idx = 0 ; idx < nneg ; idx += 4, ecnt += 1) {
for (idx = 0 ; idx < nneg ; idx += ntmp, ecnt += 1) {
unsigned sub, top;
fprintf(vvp_out, "E_%p/%u .event negedge", obj, ecnt);
top = idx + 4;
top = idx + ntmp;
if (nneg < top)
top = nneg;
for (sub = idx ; sub < top ; sub += 1) {
ivl_nexus_t nex = ivl_event_neg(obj, sub);
fprintf(vvp_out, ", %s", draw_input_from_net(nex));
strncpy(tmp[sub-idx], draw_input_from_net(nex), sizeof(tmp[0]));
}
fprintf(vvp_out, "E_%p/%u .event negedge", obj, ecnt);
for (sub = idx ; sub < top ; sub += 1)
fprintf(vvp_out, ", %s", tmp[sub-idx]);
fprintf(vvp_out, ";\n");
}
for (idx = 0 ; idx < npos ; idx += 4, ecnt += 1) {
for (idx = 0 ; idx < npos ; idx += ntmp, ecnt += 1) {
unsigned sub, top;
fprintf(vvp_out, "E_%p/%u .event posedge", obj, ecnt);
top = idx + 4;
top = idx + ntmp;
if (npos < top)
top = npos;
for (sub = idx ; sub < top ; sub += 1) {
ivl_nexus_t nex = ivl_event_pos(obj, sub);
fprintf(vvp_out, ", %s", draw_input_from_net(nex));
strncpy(tmp[sub-idx], draw_input_from_net(nex), sizeof(tmp[0]));
}
fprintf(vvp_out, "E_%p/%u .event posedge", obj, ecnt);
for (sub = idx ; sub < top ; sub += 1)
fprintf(vvp_out, ", %s", tmp[sub-idx]);
fprintf(vvp_out, ";\n");
}
@@ -981,20 +994,17 @@ static void draw_event_in_scope(ivl_event_t obj)
} else {
unsigned num_input_strings = nany + nneg + npos;
unsigned idx;
ivl_nexus_t input_nexa[4];
const char*edge = 0;
assert(num_input_strings <= 4);
assert(num_input_strings <= ntmp);
if (nany > 0) {
assert((nneg + npos) == 0);
assert(nany <= 4);
edge = "edge";
for (idx = 0 ; idx < nany ; idx += 1) {
ivl_nexus_t nex = ivl_event_any(obj, idx);
input_nexa[idx] = nex;
strncpy(tmp[idx], draw_input_from_net(nex), sizeof(tmp[0]));
}
} else if (nneg > 0) {
@@ -1003,7 +1013,7 @@ static void draw_event_in_scope(ivl_event_t obj)
for (idx = 0 ; idx < nneg ; idx += 1) {
ivl_nexus_t nex = ivl_event_neg(obj, idx);
input_nexa[idx] = nex;
strncpy(tmp[idx], draw_input_from_net(nex), sizeof(tmp[0]));
}
} else {
@@ -1012,14 +1022,14 @@ static void draw_event_in_scope(ivl_event_t obj)
for (idx = 0 ; idx < npos ; idx += 1) {
ivl_nexus_t nex = ivl_event_pos(obj, idx);
input_nexa[idx] = nex;
strncpy(tmp[idx], draw_input_from_net(nex), sizeof(tmp[0]));
}
}
fprintf(vvp_out, "E_%p .event %s", obj, edge);
for (idx = 0 ; idx < num_input_strings ; idx += 1)
fprintf(vvp_out, ", %s", draw_input_from_net(input_nexa[idx]));
for (idx = 0 ; idx < num_input_strings ; idx += 1) {
fprintf(vvp_out, ", %s", tmp[idx]);
}
fprintf(vvp_out, ";\n");
}
}
@@ -1055,9 +1065,9 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net)
const char*dly = "";
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64));
assert(number_is_immediate(d_fall, 64));
assert(number_is_immediate(d_decay, 64));
assert(number_is_immediate(d_rise, 64, 0));
assert(number_is_immediate(d_fall, 64, 0));
assert(number_is_immediate(d_decay, 64, 0));
dly = "/d";
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
net, get_number_immediate(d_rise),
@@ -1079,6 +1089,31 @@ static void draw_lpm_abs(ivl_lpm_t net)
net, dly, src_table[0]);
}
static void draw_lpm_cast_int(ivl_lpm_t net)
{
const char*src_table[1];
draw_lpm_data_inputs(net, 0, 1, src_table);
const char*dly = draw_lpm_output_delay(net);
fprintf(vvp_out, "L_%p%s .cast/int %u, %s;\n",
net, dly, ivl_lpm_width(net), src_table[0]);
}
static void draw_lpm_cast_real(ivl_lpm_t net)
{
const char*src_table[1];
draw_lpm_data_inputs(net, 0, 1, src_table);
const char*dly = draw_lpm_output_delay(net);
const char*is_signed = "";
if (ivl_lpm_signed(net)) is_signed = ".s";
fprintf(vvp_out, "L_%p%s .cast/real%s %s;\n",
net, dly, is_signed, src_table[0]);
}
static void draw_lpm_add(ivl_lpm_t net)
{
const char*src_table[2];
@@ -1129,20 +1164,9 @@ static void draw_lpm_add(ivl_lpm_t net)
case IVL_LPM_POW:
if (dto == IVL_VT_REAL)
type = "pow.r";
else if (ivl_lpm_signed(net)) {
else if (ivl_lpm_signed(net))
type = "pow.s";
if (width > 8*sizeof(long)) {
fprintf(stderr, "%s:%u: sorry (vvp-tgt): Signed power "
#ifdef __MINGW32__ /* MinGW does not know about z. */
"result must be no more than %u bits.\n",
#else
"result must be no more than %zu bits.\n",
#endif
ivl_lpm_file(net), ivl_lpm_lineno(net),
8*sizeof(long));
exit(1);
}
} else
else
type = "pow";
break;
default:
@@ -1550,7 +1574,7 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
else
fprintf(vvp_out, ", ");
assert(ivl_signal_array_count(psig) == 1);
assert(ivl_signal_dimensions(psig) == 0);
fprintf(vvp_out, "v%p_0", psig);
}
@@ -1560,7 +1584,7 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
result is collected. */
{ ivl_signal_t psig = ivl_scope_port(def, 0);
assert(ivl_lpm_width(net) == ivl_signal_width(psig));
assert(ivl_signal_array_count(psig) == 1);
assert(ivl_signal_dimensions(psig) == 0);
fprintf(vvp_out, " v%p_0", psig);
}
@@ -1588,9 +1612,10 @@ static void draw_lpm_part(ivl_lpm_t net)
net, dly, draw_net_input(ivl_lpm_data(net, 0)));
fprintf(vvp_out, ", %u, %u;\n", base, width);
} else {
const char*sel_symbol = draw_net_input(sel);
fprintf(vvp_out, "L_%p%s .part/v %s",
net, dly, draw_net_input(ivl_lpm_data(net,0)));
fprintf(vvp_out, ", %s", draw_net_input(sel));
fprintf(vvp_out, ", %s", sel_symbol);
fprintf(vvp_out, ", %u;\n", width);
}
}
@@ -1644,6 +1669,14 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
draw_lpm_abs(net);
return;
case IVL_LPM_CAST_INT:
draw_lpm_cast_int(net);
return;
case IVL_LPM_CAST_REAL:
draw_lpm_cast_real(net);
return;
case IVL_LPM_ADD:
case IVL_LPM_SUB:
case IVL_LPM_MULT:
+2 -2
View File
@@ -205,7 +205,7 @@ verinum::verinum(int64_t that)
bits_ = new V[nbits_];
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) {
bits_[idx] = (that & 1)? V1 : V0;
that /= 2;
that >>= 1;
}
}
@@ -508,7 +508,7 @@ verinum trim_vnum(const verinum&that)
/* Now top is the index of the highest non-zero bit. If
that turns out to the highest bit in the vector, then
tere is no trimming possible. */
there is no trimming possible. */
if (top+1 == that.len())
return that;
+1 -1
View File
@@ -139,7 +139,7 @@ static int lookup_keyword(const char*text)
}
/*
* Create a string witout the leading and trailing quotes.
* Create a string without the leading and trailing quotes.
*/
static void process_quoted_string(void)
{
+4 -3
View File
@@ -267,7 +267,7 @@ static void format_time(unsigned mcd, int fsize,
/* Fill the leading characters to make up the desired
width. This may require a '0' if the last character
written was the decimal point. This may also require a '0'
if there are no other characters at all in the ouput. */
if there are no other characters at all in the output. */
if (fusize > 0) {
while (bp > start_address) {
if (*bp == '.' || strcmp(bp, timeformat_info.suff) == 0)
@@ -1119,6 +1119,7 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
case vpiReg:
case vpiIntegerVar:
case vpiRealVar:
case vpiPartSelect:
/* Monitoring reg and net values involves setting
a callback for value changes. Pass the storage
pointer for the callback itself as user_data so
@@ -1414,7 +1415,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
fmtb);
} else {
/* If a width was not giveni, use a width of zero. */
/* If a width was not given, use a width of zero. */
if (width == -1) width = 0;
if (ljust == 0) sprintf(result, "%*c", width,
value.value.str[strlen(value.value.str)-1]);
@@ -1658,7 +1659,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
/* If a width was not given use a width of zero. */
if (width == -1) width = 0;
nbits = vpi_get(vpiSize, info->items[*idx]);
/* This is 4 chars for all but the last bit (strenght + "_")
/* This is 4 chars for all but the last bit (strength + "_")
* which only needs three chars (strength), but then you need
* space for the EOS '\0', so it is just number of bits * 4. */
rsize = nbits*4;
+525 -584
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -766,7 +766,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpfile";
tf_data.calltf = sys_dumpfile_calltf;
tf_data.compiletf = sys_dumpfile_compiletf;
tf_data.compiletf = sys_one_string_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpfile";
vpi_register_systf(&tf_data);
+1 -1
View File
@@ -781,7 +781,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpfile";
tf_data.calltf = sys_dumpfile_calltf;
tf_data.compiletf = sys_dumpfile_compiletf;
tf_data.compiletf = sys_one_string_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpfile";
vpi_register_systf(&tf_data);

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