Compare commits

..
217 Commits
Author SHA1 Message Date
steve e67952240b Installation fixes for Debian. 1999-12-03 17:43:49 +00:00
steve 22d89c5984 Update case comparison (Eric Aardoom). 1999-12-02 16:58:58 +00:00
steve 88193a369f Handle mux sel of X, if inputs are equal. 1999-12-02 04:54:11 +00:00
steve cdb99e7638 Elaborate net repeat concatenations. 1999-12-02 04:08:10 +00:00
steve 99e145da48 shiftl and shiftr take unsized second parameter. 1999-12-02 03:36:01 +00:00
steve b30b695ff0 Redo synth to use match_proc_t scanner. 1999-12-01 06:06:16 +00:00
steve 998c039fd9 Match scope names as last resort. 1999-11-30 04:54:01 +00:00
steve 5ffac8adbf Handle evaluation of ternary during elaboration. 1999-11-30 04:48:17 +00:00
steve 80b8ea95bb Put implicitly defined signals in the scope. 1999-11-30 04:33:41 +00:00
steve 68a7ce3745 include getopt if present. 1999-11-29 17:02:21 +00:00
steve bb68753bd2 Properly initialize registers. 1999-11-29 00:38:27 +00:00
steve dab47610ed Remove useless tests for NetESignal. 1999-11-28 23:59:22 +00:00
steve e96e8c62be NetESignal object no longer need to be NetNode
objects. Let them keep a pointer to NetNet objects.
1999-11-28 23:42:02 +00:00
steve fa088f8baa Set VPI_MODULE_PATH in the target code, if desired. 1999-11-28 18:05:37 +00:00
steve 48b6726cf4 gate outputs need to set signal values. 1999-11-28 01:16:18 +00:00
steve bf42be12de Build up the lists in the scope of a module,
and get $dumpvars to scan the scope for items.
1999-11-28 00:56:08 +00:00
steve 4cfa3e4047 Support the creation of scopes. 1999-11-27 19:07:57 +00:00
steve ac25dc03a8 Reduce more gate templates to use vvm_1bit_out (Eric Aardoom) 1999-11-25 01:34:04 +00:00
steve 680c35a845 LT and GT fixes from Eric Aardoom. 1999-11-24 04:38:49 +00:00
steve 26288eeeb4 Detect and list scope names. 1999-11-24 04:01:58 +00:00
steve 3a69ab8934 support line directives with the line keyword. 1999-11-23 02:49:04 +00:00
steve cd3ed1959e A file name of - means standard input. 1999-11-23 01:04:57 +00:00
steve eb72a83e5f Detemplate some and, or and nor methods. 1999-11-22 00:30:52 +00:00
steve 85ab6d160b Handle multiply in constant expressions. 1999-11-21 20:03:24 +00:00
steve b769c7781e no -fno-exceptions to the C compiler. 1999-11-21 20:02:37 +00:00
steve 7324673bd1 Fix expression width of memory references. 1999-11-21 18:03:35 +00:00
steve 4cfa715092 Memory name lookup handles scopes. 1999-11-21 17:35:37 +00:00
steve b4aade1e4c Fix coding errors handling names of logic devices,
and add support for buf device in vvm.
1999-11-21 01:16:51 +00:00
steve a81dcd7955 Support memories in continuous assignments. 1999-11-21 00:13:08 +00:00
steve fae40cf380 handle duplicate connect to a nexus. 1999-11-19 05:02:37 +00:00
steve 28149e73e3 Handle inverted clock into OUTFF. 1999-11-19 05:02:15 +00:00
steve 8b81d6e416 Detect flip-flops connected to opads and turn
them into OUTFF devices. Inprove support for
 the XNF-LCA attribute in the process.
1999-11-19 03:02:25 +00:00
steve fbf0bf1fb7 Whoops, created a signal with a duplicate name. 1999-11-19 03:00:59 +00:00
steve 9d6392fda9 Turn NetTmp objects into normal local NetNet objects,
and add the nodangle functor to clean up the local
 symbols generated by elaboration and other steps.
1999-11-18 03:52:19 +00:00
steve 23ce3a9042 Handle (with a warning) unconnected opads. 1999-11-18 02:58:37 +00:00
steve 33946e188c Add algorithm for choosing nexus name from attached signals. 1999-11-17 18:52:09 +00:00
steve 477495c648 Clean up warnings that add_sub got from Alliance 1999-11-17 01:31:28 +00:00
steve 16f7268729 notice d and D in numbers. 1999-11-17 00:50:06 +00:00
steve a4a0ba670d Allow qualified identifiers. They really do work. 1999-11-15 04:43:52 +00:00
steve e98083af15 Fixup to include right shift support. 1999-11-15 00:42:31 +00:00
steve 513ade9b95 Support combinatorial comparators. 1999-11-14 23:43:45 +00:00
steve 1624afe1ba Add support for the LPM_CLSHIFT device. 1999-11-14 20:24:28 +00:00
steve 0eb6056ea6 Fix NAND gate support to use named pins. 1999-11-14 18:22:12 +00:00
steve 2602505885 Support the LPM_MUX in vvm. 1999-11-13 03:46:52 +00:00
steve 82f3f0f741 Create the vpiMemory handle type. 1999-11-10 02:52:24 +00:00
steve 02f8099aa7 Add VCD output and related system tasks. 1999-11-07 20:33:30 +00:00
steve 43ff33cd79 Add the $monitor implementation. 1999-11-07 02:25:07 +00:00
steve 2d1ace1dbc Unify display and strobe format routines. 1999-11-06 23:32:14 +00:00
steve 8d806d538b Get the $strobe task working. 1999-11-06 22:16:50 +00:00
steve 3fe0344246 complete value retrieval for number constants. 1999-11-06 16:52:16 +00:00
steve c688d95cb8 Put number constants into a static table. 1999-11-06 16:00:17 +00:00
steve 282c58040b Support writing some XNF things into an NCF file. 1999-11-06 04:51:42 +00:00
steve c18ea61994 Catch NetTmp objects. 1999-11-06 04:51:11 +00:00
steve 5171846d72 Forgot to return the mux for use after elaboration. 1999-11-05 23:36:31 +00:00
steve 206b37e5de Fix NetConst being set to zero width, and clean
up elaborate_set_cmp_ for NetEBinary.
1999-11-05 21:45:19 +00:00
steve f7526c6c4b parse drive strengths. 1999-11-05 19:36:36 +00:00
steve f827ad8625 fix syntax of EQN record. 1999-11-05 18:43:12 +00:00
steve 93a1f4853b Include the obvious XOR gates in the adders. 1999-11-05 07:10:45 +00:00
steve 2cce0ce238 Patch to synthesize LPM_ADD_SUB from expressions,
Thanks to Larry Doolittle. Also handle constants
 in expressions.

 Synthesize adders in XNF, based on a patch from
 Larry. Accept synthesis of constants from Larry
 as is.
1999-11-05 04:40:40 +00:00
steve cb5fc54b5e Patch to synthesize unary ~ and the ternary operator.
Thanks to Larry Doolittle <[email protected]>.

 Add the LPM_MUX device, and integrate it with the
 ternary synthesis from Larry. Replace the lpm_mux
 generator in t-xnf.cc to use XNF EQU devices to
 put muxs into function units.

 Rewrite elaborate_net for the PETernary class to
 also use the LPM_MUX device.
1999-11-04 03:53:26 +00:00
steve 50e47c4173 Elaborate combinational UDP devices. 1999-11-04 01:12:41 +00:00
steve b3afc108cf XNF synthesis now uses the synth functor. 1999-11-03 05:18:18 +00:00
steve b66e7b1713 Add the synthesize method to NetExpr to handle
synthesis of expressions, and use that method
 to improve r-value handling of LPM_FF synthesis.

 Modify the XNF target to handle LPM_FF objects.
1999-11-02 04:55:34 +00:00
steve 73753f1337 repair the sense of T from bufif01 1999-11-02 04:55:01 +00:00
steve 7195d4e8f1 Fix iobuf and iobufif handling. 1999-11-02 01:43:55 +00:00
steve 89881adece Add the synth functor to do generic synthesis
and add the LPM_FF device to handle rows of
 flip-flops.
1999-11-01 02:07:40 +00:00
steve f80c4a309e The + and - operators now work. 1999-11-01 01:17:21 +00:00
steve e1bbbe5614 Include subtraction in LPM_ADD_SUB device. 1999-10-31 20:08:24 +00:00
steve 71ecf8c143 Add to netlist links pin name and instance number,
and arrange in vvm for pin connections by name
 and instance number.
1999-10-31 04:11:27 +00:00
steve 5a2015ee67 Support vpiValueChance callbacks. 1999-10-29 03:37:22 +00:00
steve 0721615345 gate output pins use vpip_bit_t (Eric Aardoom) 1999-10-28 21:51:21 +00:00
steve 2862178a6f Get rid of monitor_t and fold __vpiSignal into signal. 1999-10-28 21:36:00 +00:00
steve 162b895e1b Put strings into a single string table. 1999-10-28 04:48:29 +00:00
steve bbf15778b8 Support delay in constSync callback. 1999-10-28 04:47:57 +00:00
steve d6450599d6 Rewrite vvm VPI support to make objects more
persistent, rewrite the simulation scheduler
 in C (to interface with VPI) and add VPI support
 for callbacks.
1999-10-28 00:47:24 +00:00
steve 8bad04a020 cannonical make targets, and strip on install. 1999-10-23 16:55:51 +00:00
steve 409c8ff47d assignment to bit select is aa single bit. 1999-10-23 16:27:53 +00:00
steve 59e85dcffc Support build in different directory. 1999-10-22 23:58:13 +00:00
steve 2c774bfe75 do the <= in bits, not numbers. 1999-10-22 23:57:53 +00:00
steve 2e40152ff2 Make generated code ISO legal. 1999-10-21 02:15:06 +00:00
steve 8ab03fa90f Catch unindexed memory reference. 1999-10-18 00:02:21 +00:00
steve 07e2b2b828 ar -f flag is useless and incompatible. 1999-10-17 20:14:23 +00:00
steve 08175f5ebc VPI modules must be position-independent. 1999-10-17 20:14:05 +00:00
steve 2e15006dc0 More build instructions. 1999-10-16 21:22:06 +00:00
steve b24fa87de6 installdirs targets for what each directory installes. 1999-10-16 20:48:15 +00:00
steve a4143f8788 autoconf the verilog script to run anywhere. 1999-10-16 17:03:49 +00:00
steve 2fb754cd54 Parse empty source files. 1999-10-15 05:03:33 +00:00
steve bcbab34543 Special credit. 1999-10-15 02:55:21 +00:00
steve 475dd5760a Remove commented out do_assign. 1999-10-13 03:16:36 +00:00
steve 8f2a369588 Remove useless operator=. 1999-10-13 03:15:51 +00:00
steve 19b8615363 Support evaluating + operator at compile time. 1999-10-10 23:29:37 +00:00
steve 564f972aef Handle display of odd octal/hex widths (Eric Ardoom) 1999-10-10 14:57:38 +00:00
steve 86a2bf1961 Add Octal dump format. 1999-10-10 14:50:50 +00:00
steve 70a1236626 Structural case equals device. 1999-10-10 01:59:54 +00:00
steve 7201865554 Support parameters in continuous assignments. 1999-10-09 21:30:16 +00:00
steve a4298df776 NOR device. 1999-10-09 19:24:36 +00:00
steve aa11f57b57 Better message for combinational operators. 1999-10-09 19:24:04 +00:00
steve a4f3fa8997 support XNF OBUFT devices. 1999-10-09 17:52:27 +00:00
steve 9f860e319a Proper support for XNF synthesis. 1999-10-09 17:51:23 +00:00
steve 29abc5a69e Support + in constant expressions. 1999-10-08 17:48:08 +00:00
steve 0f919ab5f3 Add the %t formatting escape. 1999-10-08 17:47:49 +00:00
steve eb0103deb5 Start line directives with newline. 1999-10-08 17:27:56 +00:00
steve 5b7d783979 Accept adder parameters with different widths,
and simplify continuous assign construction.
1999-10-08 17:27:23 +00:00
steve 32e5eb6681 Fix too many -t with -t flag. 1999-10-08 17:27:09 +00:00
steve 213d02c4e5 support the -t switch. 1999-10-08 03:57:19 +00:00
steve 6997971884 vvm supports unary | operator. 1999-10-08 02:00:48 +00:00
steve 11eccfc033 Fix dump of sase statements. 1999-10-08 02:00:35 +00:00
steve f949f96df1 Add non-const bit select in l-value of assignment. 1999-10-07 05:25:33 +00:00
steve 1d215998b2 Move the rvalue into NetAssign_ common code. 1999-10-06 05:06:16 +00:00
steve 492d76e71d The $finish task should work immediately. 1999-10-06 01:28:18 +00:00
steve 1cc68f745a == and != connected to the wrong pins of the compare. 1999-10-06 00:39:00 +00:00
steve 4d8c0c79d6 Add support for reduction NOR. 1999-10-05 06:19:46 +00:00
steve a7f48c86e2 Relaxed width handling for <= assignment. 1999-10-05 04:02:10 +00:00
steve 35e84f15d4 null target ignore assignment nodes. 1999-10-05 03:26:37 +00:00
steve d513cf8f60 sorry message for non-constant l-value bit select. 1999-10-05 02:00:06 +00:00
steve efdc1769e6 Add some vvm operators from Eric Aardoom. 1999-10-01 15:26:28 +00:00
steve e1c697a746 More resilient assignment to memory location. 1999-10-01 03:58:36 +00:00
steve 393c9ab108 Rewrite vvm output to separateclass declarations
from method definitions. This is required to allow
 for mutual referencing, for example by tasks.
1999-10-01 03:15:00 +00:00
steve efa5222c66 Handle mutual reference of tasks by elaborating
task definitions in two passes, like functions.
1999-09-30 21:28:34 +00:00
steve f068196272 Ignore user task definitions. 1999-09-30 21:27:29 +00:00
steve 8317d8707e Remember to declare the calee_ member. 1999-09-30 21:26:59 +00:00
steve ed9aeec591 catch non-constant delays as unsupported. 1999-09-30 17:22:33 +00:00
steve 0c1c826410 Accept white after . in portname tokens. 1999-09-30 04:51:14 +00:00
steve c63a3acf93 Elaborate ~^ and ~| operators. 1999-09-30 02:43:01 +00:00
steve b37fcf3593 Handle declaration of integers (including scope) in functions. 1999-09-30 01:22:37 +00:00
steve 6e486e9bcf Cope with errors during ternary operator elaboration. 1999-09-30 00:48:49 +00:00
steve 076cecb6cd Handle null returns from function_item 1999-09-30 00:48:04 +00:00
steve 42006ec5f1 LT supports different width objects. 1999-09-29 22:57:26 +00:00
steve db7044850a Move code to elab_expr.cc 1999-09-29 22:57:10 +00:00
steve 5ee7cfb854 Fix shift/reduce warnings and ?:. ([email protected]) 1999-09-29 22:56:31 +00:00
steve 93f05306e7 Standardize error/sorry messages. 1999-09-29 21:16:32 +00:00
steve 8e21f0f363 Handle some mor missing names. 1999-09-29 21:15:58 +00:00
steve b2f7f533f7 Standardize formatting of warning messages. 1999-09-29 21:15:31 +00:00
steve 2271fc9894 Handle empty named ports in the dump. 1999-09-29 20:23:53 +00:00
steve a64a33e65a Full case support 1999-09-29 18:36:02 +00:00
steve 3a415fb04c Useless assertion. 1999-09-29 02:53:33 +00:00
steve 0c7722ce7e Hashed keyword lookup for the lexor. 1999-09-29 01:50:35 +00:00
steve 86a283b9bc Support the $write system task, and have the
vpi_scan function free iterators as needed.
1999-09-29 01:41:18 +00:00
steve 0fb4ba7907 Allow expanding of additive operators. 1999-09-29 00:42:50 +00:00
steve f274c9cade Comment on where binary operator came from. 1999-09-29 00:42:25 +00:00
steve 4882f04945 Spelling fixes from Larry. 1999-09-29 00:03:27 +00:00
steve a8a2b3e8f3 Use files instead of strstreams for delayed output,
and fix a missing ends in case output code.
1999-09-28 23:45:09 +00:00
steve 900949ab56 Get the bit widths of unary operators that return one bit. 1999-09-28 03:11:29 +00:00
steve 9f30615a91 save the thread class name so that behaviors in tasks have it. 1999-09-28 03:11:09 +00:00
steve a964e0479b Generate code for repeat concatenations. 1999-09-28 01:53:37 +00:00
steve 6d7ac5d67b Proper syntax for method pointers. 1999-09-28 01:21:27 +00:00
steve 470b0d3d34 Support in vvm > and >= behavioral operators. 1999-09-28 01:13:15 +00:00
steve bb38653654 Parse system function calls. 1999-09-25 02:57:29 +00:00
steve fb678877d7 comment about system functions. 1999-09-25 02:56:37 +00:00
steve 64cc38f0eb The <= operator takes different width operands. 1999-09-23 04:39:52 +00:00
steve 1a21d2fe9d Support shift operators. 1999-09-23 03:56:57 +00:00
steve 095995f09c internal error message for funky comparison width. 1999-09-23 02:28:27 +00:00
steve 851daff66f comparison parameter width is self determined. 1999-09-23 02:27:50 +00:00
steve 1b7261a393 Update support list. 1999-09-23 01:49:28 +00:00
steve 1c41f8ebd2 Move set_width methods into a single file,
Add the NetEBLogic class for logic expressions,
 Fix error setting with of && in if statements.
1999-09-23 00:21:54 +00:00
steve 59b1b4c7b9 Expand bits in delayed assignments. 1999-09-22 21:25:42 +00:00
steve 0955058fbe Catch parallel blocks in vvm emit. 1999-09-22 16:57:23 +00:00
steve 12b9071f49 Parse and elaborate named for/join blocks. 1999-09-22 04:30:04 +00:00
steve 357461b034 Fix solaris compatibility w/ send and getopt. 1999-09-22 02:13:57 +00:00
steve 4a0e7d56bd Document the new -x flag. 1999-09-22 02:12:15 +00:00
steve da4a7ea80a assignment with blocking event delay. 1999-09-22 02:00:48 +00:00
steve fcfa9d004a Get scope right when setting the net range. 1999-09-21 00:58:33 +00:00
steve 349f9ae302 Support parameters that reference other paramters. 1999-09-21 00:13:40 +00:00
steve 3a5e55b229 Elaborate parameters in phases. 1999-09-20 02:21:10 +00:00
steve 1f44822510 dump the repeat count, if applicable. 1999-09-19 01:06:36 +00:00
steve 6df3febada up to date wrt bugs and the verilog command. 1999-09-18 22:24:24 +00:00
steve 5fde1b3e05 Match bit widths comming out of task output ports. 1999-09-18 22:23:50 +00:00
steve fbf104bf4d report non-constant part select expressions. 1999-09-18 02:51:35 +00:00
steve dab04c221d Detect constant lessthen-equal expressions. 1999-09-18 01:53:08 +00:00
steve 251eb4f38f Remove spurious message. 1999-09-18 01:52:48 +00:00
steve 424e6a750c Handle unconnected module ports. 1999-09-17 02:06:25 +00:00
steve 4594ac1c2c elaborate concatenation repeats. 1999-09-16 04:18:15 +00:00
steve d904aceb2c More liberal matching of include and define. 1999-09-16 00:49:05 +00:00
steve a890724b40 Handle implicit !=0 in if statements. 1999-09-16 00:33:45 +00:00
steve 31bdb87c8f separate assign lval elaboration for error checking. 1999-09-15 04:17:52 +00:00
steve b04148b754 Elaborate non-blocking assignment to memories. 1999-09-15 01:55:06 +00:00
steve f36c511c2f Fix output name generation. (Stefan Peterson) 1999-09-15 01:47:39 +00:00
steve 39bc45ce67 implicitly declare wires if needed. 1999-09-14 01:50:52 +00:00
steve 3d78b558bc Handle gates without delays. 1999-09-14 01:50:35 +00:00
steve 54d38ac057 Update verilog.sh to use getopt and handle multiple files. 1999-09-14 01:50:06 +00:00
steve 7a211b9136 Clarify msb/lsb in context of netlist. Properly
handle part selects in lval and rval of expressions,
 and document where the least significant bit goes
 in NetNet objects.
1999-09-13 03:10:59 +00:00
steve 6847dac5c2 fix parsing of sized octal digits. 1999-09-13 03:08:52 +00:00
steve a3e9a7417d fix vpiHexStrVal dumping of digits to strings. 1999-09-13 03:08:10 +00:00
steve 25d6912217 Pad r-values in certain assignments. 1999-09-12 01:16:51 +00:00
steve 1c238f1948 Support ternary and <= operators in vvm. 1999-09-11 04:43:17 +00:00
steve 287d21f300 Handle integers at task parameters. 1999-09-10 05:02:09 +00:00
steve a6c6ac2191 Add ternary elaboration. 1999-09-10 04:04:06 +00:00
steve d6fbc30cd5 Allow assign to not match rvalue width. 1999-09-08 04:05:30 +00:00
steve 9d82d19d07 Empty conditionals ([email protected]) 1999-09-08 02:24:39 +00:00
steve 006a2cce83 Take multiple source files on the command line. 1999-09-05 22:33:18 +00:00
steve 8f68a07476 Add support for delayed non-blocking assignments. 1999-09-04 19:11:45 +00:00
steve 555d447180 Generate fake adder code in vvm. 1999-09-04 01:57:15 +00:00
steve 41a1c6bb02 elaborate the binary plus operator. 1999-09-03 04:28:38 +00:00
steve 6fb7120158 Parse non-blocking assignment delays. 1999-09-02 01:59:27 +00:00
steve 9f7eb4a935 Handle recursive functions and arbitrary function
references to other functions, properly pass
 function parameters and save function results.
1999-09-01 20:46:19 +00:00
steve 5ee83fce70 Dont install veriuser.h. 1999-08-31 23:00:08 +00:00
steve e69345b9fe Elaborate and emit to vvm procedural functions. 1999-08-31 22:38:29 +00:00
steve 1c11c864d5 man page for the verilog front end. 1999-08-31 22:34:25 +00:00
steve 58d05dfca2 Updates from Stefan. 1999-08-31 22:25:52 +00:00
steve 7d71abaa05 man page for the verilog front end. 1999-08-31 22:25:02 +00:00
steve 6b3b6f3384 Makefile install targets. 1999-08-28 02:10:57 +00:00
steve 0fe25f68f9 Call the right vpiFinish code. 1999-08-28 02:10:44 +00:00
steve 3017636c05 continuous assignment lists. 1999-08-27 15:08:37 +00:00
steve 23acca48ff elaborate some aspects of functions. 1999-08-25 22:22:41 +00:00
steve 648e4c68e4 handle bufz in XNF backend. 1999-08-25 22:22:08 +00:00
steve 9eae940ebd Parameter overrides support from Peter Monta
AND and XOR support wide expressions.
1999-08-23 16:48:39 +00:00
steve 0175a4fce0 xilinx support from Larry Doolittle 1999-08-20 15:08:57 +00:00
steve aba4a877db Add vpi_sim_control 1999-08-19 02:51:03 +00:00
steve 031d91f813 Fixup spelling and some error messages. <[email protected]> 1999-08-18 04:00:02 +00:00
steve f1fdce78be Update compile command line. 1999-08-18 03:45:36 +00:00
steve b119613a8a credit 1999-08-18 03:45:21 +00:00
steve 567badc7af declare vou_sim_control 1999-08-18 03:44:49 +00:00
steve b62f094874 Add the verilog.sh script. 1999-08-17 15:57:43 +00:00
steve 28c0691b5f uninstall uninstalls everything. 1999-08-15 02:20:06 +00:00
steve 2d0e11283d Convert vvm to implement system tasks with vpi. 1999-08-15 01:23:56 +00:00
steve f1825c54a7 Mention the sigfold function. 1999-08-14 22:48:21 +00:00
steve cf1abfe38c Uninitialized low and high indices for single gate syntax 1999-08-08 20:06:06 +00:00
101 changed files with 17316 additions and 3332 deletions
+1
View File
@@ -6,6 +6,7 @@ ivl
dep
configure
Makefile
verilog
config.status
config.log
config.cache
+61 -21
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.11 1999/08/07 20:05:51 steve Exp $"
#ident "$Id: Makefile.in,v 1.24.2.1 1999/12/03 17:43:49 steve Exp $"
#
#
SHELL = /bin/sh
@@ -33,6 +33,7 @@ VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
mandir = @mandir@
includedir = $(prefix)/include
CC = @CC@
@@ -40,32 +41,58 @@ CXX = @CXX@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
STRIP = @STRIP@
CPPFLAGS = @CPPFLAGS@ @DEFS@
CXXFLAGS = @CXXFLAGS@
CXXFLAGS = @CXXFLAGS@ -I$(srcdir)
LDFLAGS = @LDFLAGS@
all: ivl
cd vvm ; make all
cd ivlpp ; make all
all: ivl verilog
cd vpi ; $(MAKE) all
cd vvm ; $(MAKE) all
cd ivlpp ; $(MAKE) all
clean:
rm *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc
cd vvm ; make clean
cd ivlpp ; make clean
rm -f *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc verilog
cd vpi ; $(MAKE) clean
cd vvm ; $(MAKE) clean
cd ivlpp ; $(MAKE) clean
distclean: clean
rm -f vpi/Makefile
rm -f vvm/Makefile
rm -f ivlpp/Makefile
rm -f config.status config.cache config.log
rm -f Makefile
TT = t-null.o t-verilog.o t-vvm.o t-xnf.o
FF = nobufz.o propinit.o sigfold.o xnfio.o xnfsyn.o
O = main.o cprop.o design_dump.o elaborate.o emit.o eval.o functor.o \
lexor.o mangle.o netlist.o parse.o parse_misc.o pform.o pform_dump.o \
verinum.o verireal.o target.o targets.o Module.o PExpr.o PGate.o \
O = main.o cprop.o design_dump.o elaborate.o elab_expr.o emit.o eval.o \
eval_tree.o functor.o \
lexor.o lexor_keyword.o mangle.o netlist.o pad_to_width.o \
parse.o parse_misc.o pform.o pform_dump.o \
set_width.o \
verinum.o verireal.o target.o targets.o Module.o PDelays.o PExpr.o PGate.o \
PTask.o PFunction.o PWire.o Statement.o \
$(FF) $(TT)
Makefile: Makefile.in config.status
./config.status
# Make the actual verilog program from the script template. This
# simply invloves editing the substitution strings in the script into
# the configured copy.
tmp1 = bindir
tmp2 = libdir
tmp3 = includedir
tmp4 = CXX
verilog: $(srcdir)/verilog.sh
sed -e 's;@$(tmp1)@;@bindir@;' \
-e 's;@$(tmp2)@;@libdir@;' \
-e 's;@$(tmp3)@;@includedir@;' \
-e 's;@$(tmp4)@;@CXX@;' < $< > $@
ivl: $O
$(CXX) $(CXXFLAGS) -o ivl $O
@@ -79,25 +106,38 @@ lexor.o dep/lexor.d: lexor.cc parse.h
parse.o dep/parse.d: parse.cc
parse.h parse.cc: parse.y
bison --verbose -t -p VL -d parse.y -o parse.cc
parse.h parse.cc: $(srcdir)/parse.y
bison --verbose -t -p VL -d $(srcdir)/parse.y -o parse.cc
mv parse.cc.h parse.h
lexor.cc: lexor.lex
flex -PVL -s -olexor.cc lexor.lex
lexor.cc: $(srcdir)/lexor.lex
flex -PVL -s -olexor.cc $(srcdir)/lexor.lex
install: all installdirs $(bindir)/ivl
cd vvm ; make install
cd ivlpp ; make install
install: all installdirs $(bindir)/verilog $(libdir)/ivl/ivl $(mandir)/man1/verilog.1
cd vpi ; $(MAKE) install
cd vvm ; $(MAKE) install
cd ivlpp ; $(MAKE) install
$(bindir)/ivl: ivl
$(INSTALL_PROGRAM) ./ivl $(bindir)/ivl
$(bindir)/verilog: ./verilog
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
$(libdir)/ivl/ivl: ivl
$(INSTALL_PROGRAM) ./ivl $(libdir)/ivl/ivl
$(STRIP) $(libdir)/ivl/ivl
$(mandir)/man1/verilog.1: $(srcdir)/verilog.1
$(INSTALL_DATA) $(srcdir)/verilog.1 $(mandir)/man1/verilog.1
installdirs: mkinstalldirs
$(srcdir)/mkinstalldirs $(includedir) $(bindir)
$(srcdir)/mkinstalldirs $(bindir) $(mandir)/man1
uninstall:
rm -f $(bindir)/ivl
rm -f $(bindir)/verilog
rm -f $(mandir)/man1/verilog.1
cd vpi ; $(MAKE) uninstall
cd vvm ; $(MAKE) uninstall
cd ivlpp ; $(MAKE) uninstall
-include $(patsubst %.o, dep/%.d, $O)
+6 -1
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: Module.cc,v 1.6 1999/08/04 02:13:02 steve Exp $"
#ident "$Id: Module.cc,v 1.7 1999/09/17 02:06:25 steve Exp $"
#endif
# include "Module.h"
@@ -30,6 +30,8 @@ Module::Module(const string&name, const svector<Module::port_t*>*pp)
ports_ = *pp;
for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) {
port_t*cur = ports_[idx];
if (cur == 0)
continue;
for (unsigned jdx = 0 ; jdx < cur->wires.count() ; jdx += 1)
add_wire(cur->wires[jdx]);
}
@@ -99,6 +101,9 @@ PWire* Module::get_wire(const string&name)
/*
* $Log: Module.cc,v $
* Revision 1.7 1999/09/17 02:06:25 steve
* Handle unconnected module ports.
*
* Revision 1.6 1999/08/04 02:13:02 steve
* Elaborate module ports that are concatenations of
* module signals.
+18 -2
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: Module.h,v 1.8 1999/08/04 02:13:02 steve Exp $"
#ident "$Id: Module.h,v 1.10 1999/11/27 19:07:57 steve Exp $"
#endif
# include <list>
@@ -33,6 +33,7 @@ class PFunction;
class PWire;
class PProcess;
class Design;
class NetScope;
/*
* A module is a named container and scope. A module holds a bunch of
@@ -64,6 +65,14 @@ class Module {
into this map. */
map<string,PExpr*>parameters;
/* Parameters may be overridden at instantiation time;
the overrides do not contain explicit parameter names,
but rather refer to parameters in the order they
appear in the instantiated module. Therefore a
list of names in module-order is needed to pass from
a parameter-index to its name. */
list<string> param_names;
const string&get_name() const { return name_; }
void add_gate(PGate*gate);
@@ -85,7 +94,7 @@ class Module {
const list<PProcess*>& get_behaviors() const { return behaviors_; }
void dump(ostream&out) const;
bool elaborate(Design*, const string&path) const;
bool elaborate(Design*, NetScope*scope, svector<PExpr*>*overrides_) const;
private:
const string name_;
@@ -105,6 +114,13 @@ class Module {
/*
* $Log: Module.h,v $
* Revision 1.10 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.9 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.8 1999/08/04 02:13:02 steve
* Elaborate module ports that are concatenations of
* module signals.
+103
View File
@@ -0,0 +1,103 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PDelays.cc,v 1.1 1999/09/04 19:11:46 steve Exp $"
#endif
# include "PDelays.h"
# include "PExpr.h"
# include "verinum.h"
PDelays::PDelays()
{
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
delay_[idx] = 0;
}
PDelays::~PDelays()
{
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
delete delay_[idx];
}
void PDelays::set_delay(PExpr*del)
{
assert(del);
assert(delay_[0] == 0);
delay_[0] = del;
}
void PDelays::set_delays(const svector<PExpr*>*del)
{
assert(del);
assert(del->count() <= 3);
for (unsigned idx = 0 ; idx < del->count() ; idx += 1)
delay_[idx] = (*del)[idx];
}
void PDelays::eval_delays(Design*des, const string&path,
unsigned long&rise_time,
unsigned long&fall_time,
unsigned long&decay_time) const
{
verinum*dv;
if (delay_[0]) {
dv = delay_[0]->eval_const(des, path);
assert(dv);
rise_time = dv->as_ulong();
delete dv;
if (delay_[1]) {
dv = delay_[1]->eval_const(des, path);
assert(dv);
fall_time = dv->as_ulong();
delete dv;
if (delay_[2]) {
dv = delay_[2]->eval_const(des, path);
assert(dv);
decay_time = dv->as_ulong();
delete dv;
} else {
if (rise_time < fall_time)
decay_time = rise_time;
else
decay_time = fall_time;
}
} else {
assert(delay_[2] == 0);
fall_time = rise_time;
decay_time = rise_time;
}
} else {
rise_time = 0;
fall_time = 0;
decay_time = 0;
}
}
/*
* $Log: PDelays.cc,v $
* Revision 1.1 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
*/
+67
View File
@@ -0,0 +1,67 @@
#ifndef __PDelays_H
#define __PDelays_H
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PDelays.h,v 1.1 1999/09/04 19:11:46 steve Exp $"
#endif
# include "svector.h"
# include <string>
class Design;
class PExpr;
class ostream;
/*
* Various PForm objects can carry delays. These delays include rise,
* fall and decay times. This class arranges to carry the triplet.
*/
class PDelays {
public:
PDelays();
~PDelays();
void set_delay(PExpr*);
void set_delays(const svector<PExpr*>*del);
void eval_delays(Design*des, const string&path,
unsigned long&rise_time,
unsigned long&fall_time,
unsigned long&decay_time) const;
void dump_delays(ostream&out) const;
private:
PExpr* delay_[3];
private: // not implemented
PDelays(const PDelays&);
PDelays& operator= (const PDelays&);
};
ostream& operator << (ostream&o, const PDelays&);
/*
* $Log: PDelays.h,v $
* Revision 1.1 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
*/
#endif
+42 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PExpr.cc,v 1.7 1999/07/22 02:05:20 steve Exp $"
#ident "$Id: PExpr.cc,v 1.11 1999/10/31 04:11:27 steve Exp $"
#endif
# include "PExpr.h"
@@ -38,14 +38,40 @@ bool PExpr::is_constant(Module*) const
return false;
}
NetNet* PExpr::elaborate_net(Design*des, const string&path, unsigned,
unsigned long,
unsigned long,
unsigned long) const
{
cerr << "Don't know how to elaborate `" << *this
<< "' as gates." << endl;
return 0;
}
NetNet* PExpr::elaborate_lnet(Design*des, const string&path) const
{
cerr << get_line() << ": expression not valid in assign l-value: "
<< *this << endl;
return 0;
}
bool PEBinary::is_constant(Module*mod) const
{
return left_->is_constant(mod) && right_->is_constant(mod);
}
PECallFunction::PECallFunction(const string &n, const svector<PExpr *> &parms)
: name_(n), parms_(parms)
{
}
PECallFunction::~PECallFunction()
{
}
bool PEConcat::is_constant(Module *mod) const
{
bool constant = repeat_->is_constant(mod);
bool constant = repeat_? repeat_->is_constant(mod) : true;
for (unsigned i = 0; constant && i < parms_.count(); ++i) {
constant = constant && parms_[i]->is_constant(mod);
}
@@ -102,6 +128,20 @@ bool PETernary::is_constant(Module*) const
/*
* $Log: PExpr.cc,v $
* Revision 1.11 1999/10/31 04:11:27 steve
* Add to netlist links pin name and instance number,
* and arrange in vvm for pin connections by name
* and instance number.
*
* Revision 1.10 1999/09/25 02:57:29 steve
* Parse system function calls.
*
* Revision 1.9 1999/09/16 04:18:15 steve
* elaborate concatenation repeats.
*
* Revision 1.8 1999/09/15 04:17:52 steve
* separate assign lval elaboration for error checking.
*
* Revision 1.7 1999/07/22 02:05:20 steve
* is_constant method for PEConcat.
*
+104 -26
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PExpr.h,v 1.17 1999/08/01 21:18:55 steve Exp $"
#ident "$Id: PExpr.h,v 1.25 1999/11/21 00:13:08 steve Exp $"
#endif
# include <string>
@@ -47,12 +47,22 @@ class PExpr : public LineInfo {
virtual ~PExpr();
virtual void dump(ostream&) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned long rise =0,
unsigned long fall =0,
unsigned long decay =0) const;
// Procedural elaboration of the expression.
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
// This method elaborate the expression as gates, for use in a
// continuous assign or other wholly structural context.
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
// This method elaborates the expression as gates, but
// restricted for use as l-values of continuous assignments.
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
// This attempts to evaluate a constant expression, and return
// a verinum as a result. If the expression cannot be
// evaluated, return 0.
@@ -68,6 +78,7 @@ class PExpr : public LineInfo {
// identifiers and any other module specific interpretations
// of expresions.
virtual bool is_constant(Module*) const;
};
ostream& operator << (ostream&, const PExpr&);
@@ -80,10 +91,12 @@ class PEConcat : public PExpr {
~PEConcat();
virtual void dump(ostream&) const;
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned long rise =0,
unsigned long fall =0,
unsigned long decay =0) const;
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual bool is_constant(Module*) const;
@@ -116,11 +129,19 @@ class PEIdent : public PExpr {
: text_(s), msb_(0), lsb_(0), idx_(0) { }
virtual void dump(ostream&) const;
// Identifiers are allowed (with restrictions) is assign l-values.
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
// Structural r-values are OK.
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned long rise =0,
unsigned long fall =0,
unsigned long decay =0) const;
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual bool is_constant(Module*) const;
verinum* eval_const(const Design*des, const string&path) const;
@@ -138,6 +159,12 @@ class PEIdent : public PExpr {
// If this is a reference to a memory, this is the index
// expression.
PExpr*idx_;
NetNet* elaborate_net_ram_(Design*des, const string&path,
NetMemory*mem, unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
};
class PENumber : public PExpr {
@@ -151,9 +178,10 @@ class PENumber : public PExpr {
virtual void dump(ostream&) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned long rise =0,
unsigned long fall =0,
unsigned long decay =0) const;
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual verinum* eval_const(const Design*des, const string&path) const;
@@ -188,9 +216,10 @@ class PEUnary : public PExpr {
virtual void dump(ostream&out) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned long rise =0,
unsigned long fall =0,
unsigned long decay =0) const;
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
private:
@@ -208,9 +237,10 @@ class PEBinary : public PExpr {
virtual void dump(ostream&out) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned long rise =0,
unsigned long fall =0,
unsigned long decay =0) const;
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual verinum* eval_const(const Design*des, const string&path) const;
@@ -218,6 +248,22 @@ class PEBinary : public PExpr {
char op_;
PExpr*left_;
PExpr*right_;
NetNet* elaborate_net_add_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_cmp_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_shift_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
};
/*
@@ -234,6 +280,7 @@ class PETernary : public PExpr {
virtual void dump(ostream&out) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned width,
unsigned long rise =0,
unsigned long fall =0,
unsigned long decay =0) const;
@@ -246,22 +293,53 @@ class PETernary : public PExpr {
PExpr*fal_;
};
/*
* This class represents a parsed call to a function.
*/
class PECallFunction : public PExpr {
public:
explicit PECallFunction(const string &n, const svector<PExpr *> &parms)
: name_(n), parms_(parms) {}
~PECallFunction() {}
public:
explicit PECallFunction(const string &n, const svector<PExpr *> &parms);
~PECallFunction();
virtual void dump(ostream &) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
private:
private:
string name_;
svector<PExpr *> parms_;
NetESFunc* elaborate_sfunc_(Design*des, const string&path) const;
};
/*
* $Log: PExpr.h,v $
* Revision 1.25 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.24 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.23 1999/11/05 21:45:19 steve
* Fix NetConst being set to zero width, and clean
* up elaborate_set_cmp_ for NetEBinary.
*
* Revision 1.22 1999/10/31 20:08:24 steve
* Include subtraction in LPM_ADD_SUB device.
*
* Revision 1.21 1999/10/31 04:11:27 steve
* Add to netlist links pin name and instance number,
* and arrange in vvm for pin connections by name
* and instance number.
*
* Revision 1.20 1999/09/25 02:57:29 steve
* Parse system function calls.
*
* Revision 1.19 1999/09/15 04:17:52 steve
* separate assign lval elaboration for error checking.
*
* Revision 1.18 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.17 1999/08/01 21:18:55 steve
* elaborate rise/fall/decay for continuous assign.
*
+36 -1
View File
@@ -1,10 +1,45 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PFunction.cc,v 1.2 1999/08/25 22:22:41 steve Exp $"
#endif
#include "PTask.h"
PFunction::PFunction(svector<PWire*>*p, Statement*s)
: ports_(p), statement_(s)
: out_(0), ports_(p), statement_(s)
{
}
PFunction::~PFunction()
{
}
void PFunction::set_output(PWire*o)
{
assert(out_ == 0);
out_ = o;
}
/*
* $Log: PFunction.cc,v $
* Revision 1.2 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
*/
+10 -52
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PGate.cc,v 1.3 1999/08/01 21:18:55 steve Exp $"
#ident "$Id: PGate.cc,v 1.5 1999/09/14 01:50:35 steve Exp $"
#endif
# include "PGate.h"
@@ -30,14 +30,7 @@ PGate::PGate(const string&name,
const svector<PExpr*>*del)
: name_(name), pins_(pins)
{
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
delay_[idx] = 0;
if (del) {
assert(del->count() <= 3);
for (unsigned idx = 0 ; idx < del->count() ; idx += 1)
delay_[idx] = (*del)[idx];
}
if (del) delay_.set_delays(del);
}
PGate::PGate(const string&name,
@@ -45,23 +38,16 @@ PGate::PGate(const string&name,
PExpr*del)
: name_(name), pins_(pins)
{
delay_[0] = del;
delay_[1] = 0;
delay_[2] = 0;
if (del) delay_.set_delay(del);
}
PGate::PGate(const string&name, svector<PExpr*>*pins)
: name_(name), pins_(pins)
{
delay_[0] = 0;
delay_[1] = 0;
delay_[2] = 0;
}
PGate::~PGate()
{
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
delete delay_[idx];
}
/*
@@ -77,41 +63,7 @@ void PGate::eval_delays(Design*des, const string&path,
unsigned long&fall_time,
unsigned long&decay_time) const
{
verinum*dv;
if (delay_[0]) {
dv = delay_[0]->eval_const(des, path);
assert(dv);
rise_time = dv->as_ulong();
delete dv;
if (delay_[1]) {
dv = delay_[1]->eval_const(des, path);
assert(dv);
fall_time = dv->as_ulong();
delete dv;
if (delay_[2]) {
dv = delay_[2]->eval_const(des, path);
assert(dv);
decay_time = dv->as_ulong();
delete dv;
} else {
if (rise_time < fall_time)
decay_time = rise_time;
else
decay_time = fall_time;
}
} else {
assert(delay_[2] == 0);
fall_time = rise_time;
decay_time = rise_time;
}
} else {
rise_time = 0;
fall_time = 0;
decay_time = 0;
}
delay_.eval_delays(des, path, rise_time, fall_time, decay_time);
}
PGAssign::PGAssign(svector<PExpr*>*pins)
@@ -160,6 +112,12 @@ void PGBuiltin::set_range(PExpr*msb, PExpr*lsb)
/*
* $Log: PGate.cc,v $
* Revision 1.5 1999/09/14 01:50:35 steve
* Handle gates without delays.
*
* Revision 1.4 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.3 1999/08/01 21:18:55 steve
* elaborate rise/fall/decay for continuous assign.
*
+15 -6
View File
@@ -19,11 +19,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PGate.h,v 1.8 1999/08/01 21:18:55 steve Exp $"
#ident "$Id: PGate.h,v 1.10 1999/09/04 19:11:46 steve Exp $"
#endif
# include "svector.h"
# include "LineInfo.h"
# include "PDelays.h"
class PExpr;
class PUdp;
class Design;
@@ -72,7 +73,7 @@ class PGate : public LineInfo {
private:
const string name_;
PExpr* delay_[3];
PDelays delay_;
svector<PExpr*>*pins_;
private: // not implemented
@@ -150,8 +151,8 @@ class PGModule : public PGate {
// If the binding of ports is by position, this constructor
// builds everything all at once.
explicit PGModule(const string&type, const string&name,
svector<PExpr*>*pins)
: PGate(name, pins), type_(type), pins_(0), npins_(0) { }
svector<PExpr*>*overrides, svector<PExpr*>*pins)
: PGate(name, pins), type_(type), overrides_(overrides), pins_(0), npins_(0) { }
// If the binding of ports is by name, this constructor takes
// the bindings and stores them for later elaboration.
@@ -160,8 +161,8 @@ class PGModule : public PGate {
PExpr* parm;
};
explicit PGModule(const string&type, const string&name,
bind_t*pins, unsigned npins)
: PGate(name, 0), type_(type), pins_(pins), npins_(npins) { }
svector<PExpr*>*overrides, bind_t*pins, unsigned npins)
: PGate(name, 0), type_(type), overrides_(overrides), pins_(pins), npins_(npins) { }
virtual void dump(ostream&out) const;
@@ -169,6 +170,7 @@ class PGModule : public PGate {
private:
string type_;
svector<PExpr*>*overrides_;
bind_t*pins_;
unsigned npins_;
@@ -178,6 +180,13 @@ class PGModule : public PGate {
/*
* $Log: PGate.h,v $
* Revision 1.10 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.9 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.8 1999/08/01 21:18:55 steve
* elaborate rise/fall/decay for continuous assign.
*
+32 -6
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PTask.h,v 1.3 1999/07/31 19:14:47 steve Exp $"
#ident "$Id: PTask.h,v 1.6 1999/09/30 21:28:34 steve Exp $"
#endif
# include "LineInfo.h"
@@ -38,7 +38,9 @@ class PTask : public LineInfo {
explicit PTask(svector<PWire*>*p, Statement*s);
~PTask();
virtual void elaborate(Design*des, const string&path) const;
void elaborate_1(Design*des, const string&path) const;
void elaborate_2(Design*des, const string&path) const;
void dump(ostream&, unsigned) const;
private:
@@ -50,21 +52,45 @@ class PTask : public LineInfo {
PTask& operator=(const PTask&);
};
/*
* The function is similar to a task (in this context) but there is a
* single output port and a set of input ports. The output port is the
* function return value.
*/
class PFunction : public LineInfo {
public:
explicit PFunction(svector<PWire *> *p, Statement *s);
public:
explicit PFunction(svector<PWire *>*p, Statement *s);
~PFunction();
//virtual void elaborate(Design *des, const string &path) const {}
void set_output(PWire*);
/* Functions are elaborated in 2 passes. */
void elaborate_1(Design *des, const string &path) const;
void elaborate_2(Design *des, const string &path) const;
void dump(ostream&, unsigned) const;
private:
private:
PWire*out_;
svector<PWire *> *ports_;
Statement *statement_;
};
/*
* $Log: PTask.h,v $
* Revision 1.6 1999/09/30 21:28:34 steve
* Handle mutual reference of tasks by elaborating
* task definitions in two passes, like functions.
*
* Revision 1.5 1999/09/01 20:46:19 steve
* Handle recursive functions and arbitrary function
* references to other functions, properly pass
* function parameters and save function results.
*
* Revision 1.4 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.3 1999/07/31 19:14:47 steve
* Add functions up to elaboration (Ed Carter)
*
+8 -1
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PWire.cc,v 1.1 1999/06/17 05:34:42 steve Exp $"
#ident "$Id: PWire.cc,v 1.2 1999/09/10 05:02:09 steve Exp $"
#endif
# include "PWire.h"
@@ -41,6 +41,10 @@ bool PWire::set_wire_type(NetNet::Type t)
case NetNet::IMPLICIT:
type_ = t;
return true;
case NetNet::IMPLICIT_REG:
if (t == NetNet::REG) { type_ = t; return true; }
if (t == NetNet::INTEGER) {type_ = t; return true; }
return false;
case NetNet::REG:
if (t == NetNet::REG) return true;
if (t == NetNet::INTEGER) {type_ = t; return true; }
@@ -96,6 +100,9 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
/*
* $Log: PWire.cc,v $
* Revision 1.2 1999/09/10 05:02:09 steve
* Handle integers at task parameters.
*
* Revision 1.1 1999/06/17 05:34:42 steve
* Clean up interface of the PWire class,
* Properly match wire ranges.
+5 -2
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PWire.h,v 1.5 1999/06/17 05:34:42 steve Exp $"
#ident "$Id: PWire.h,v 1.6 1999/11/27 19:07:57 steve Exp $"
#endif
# include "netlist.h"
@@ -58,7 +58,7 @@ class PWire : public LineInfo {
// Write myself to the specified stream.
void dump(ostream&out) const;
void elaborate(Design*, const string&path) const;
void elaborate(Design*, NetScope*scope) const;
private:
string name_;
@@ -82,6 +82,9 @@ class PWire : public LineInfo {
/*
* $Log: PWire.h,v $
* Revision 1.6 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.5 1999/06/17 05:34:42 steve
* Clean up interface of the PWire class,
* Properly match wire ranges.
+139 -81
View File
@@ -1,53 +1,101 @@
THE ICARUS VERILOG COMPILATION SYSTEM
July 7, 1999
September 18, 1999
1.0 What is ICARUS Verilog(IVL)?
1.0 What is ICARUS Verilog?
Icarus Verilog is intended to compile ALL of the Verilog HDL as described
in the IEEE-1364 standard. Of course, it's not quite there yet. It does
currently handle a mix of structural and behavioral constructs.
currently handle a mix of structural and behavioral constructs. For a
view of the current state of Icarus Verilog, see its home page at
<http://www.icarus.com/eda/verilog>.
IVL is not aimed at being a simulator in the traditional sense, but a
compiler that generates code employed by back-end tools. These back-
end tools currently include a simulator written in C++ called VVM
and an XNF (Xilinx Netlist Format) generator. See "vvm.txt" and
"xnf.txt" for further details on these back-end processors.
"xnf.txt" for further details on these back-end processors. In the
future, backends are expected for EDIF/LPM, structural Verilog, etc.
2.0 How IVL Works
2.0 Building/Installing IVL From Source
If you are starting from source, the build process is designed to be
as simple as practical. Someone basically familiar with the target
system and C/C++ compilation should be able to build the source
distribution with little effort. Some actual programming skills are
not required, but helpful in case of problems.
2.1 Compile Time Prerequisites
You need the following software to compile Icarus Verilog from source
on a UNIX-like system:
- GNU Make
The Makefiles use some GNU extensions to, so a basic POSIX
make will not work. Linux systems typically come with a
satisfactory make.
- ISO C++ Compiler
The ivl program is written in C++ and makes use of templates
and some of the standard C++ library. egcs compilers with
the associated libstdc++ are known to work.
- bison
2.2 Compilation
Unpack the tar-ball and cd into the verilog-######### directory
(presumably that is how you got to this README) and compile the source
with the commands:
./configure
make
2.3 Installation
Now install the files in an appropriate place. (The makefiles by
default install in /usr/local unless you specify a different prefix
with the --prefix=<path> flag to the configure command.) Do this as
root.
make install
3.0 How IVL Works
This tool includes a parser which reads in Verilog (plus extensions)
and generates an internal netlist. The netlist is passed to various
processing steps that transform the design to more optimal/practical
forms, then passed to a code generator for final output. The
forms, then is passed to a code generator for final output. The
processing steps and the code generator are selected by command line
switches.
2.1 Preprocessing
3.1 Preprocessing
There is a separate program, ivlpp, that does the preprocessing. This
program implements the `include and `define directives producing
output that is equivalent but without the directives. See
ivlpp/ivlpp.txt for details.
output that is equivalent but without the directives. The output is a
single file with line number directives, so that the actual compiler
only sees a single input file. See ivlpp/ivlpp.txt for details.
2.2 Parse
3.2 Parse
The verilog compiler starts by parsing the verilog source file. The
output of the parse in a list of Module objects in PFORM. The pform
(see pform.h) is mostly a direct reflection of the compilation
unit. There may be dangling references, and it is not yet clear which
step. There may be dangling references, and it is not yet clear which
module is the root.
One can see a human readable version of the final PFORM by using the
``-P <path>'' flag to the compiler. This will cause ivl to dump the
PFORM into the file named <path>.
2.3 Elaboration
3.3 Elaboration
This phase takes the pform and generates a netlist. The driver selects
(by user request or lucky guess) the root module to elaborate,
resolves references and expands the instantiations to form the design
netlist. (See netlist.txt.)
netlist. (See netlist.txt.) Final semantic checks are performed during
elaboration, and some simple optimizations are performed.
The elaborate() function performs the elaboration.
@@ -56,7 +104,7 @@ optimized netlist by using the ``-N <path>'' flag to the compiler. If
elaboration succeeds, the final netlist (i.e. after optimizations but
before code generation) will be dumped into the file named <path>.
2.4 Optimization
3.4 Optimization
This is actually a collection of processing steps that perform
optimizations that do not depend on the target technology. Examples of
@@ -69,7 +117,7 @@ some useful transformations would be,
The actual functions performed are specified on the command line by
the -F flags (See below).
2.5 Code Generation
3.5 Code Generation
This step takes the design netlist and uses it to drive the code
generator. (See target.h.) This may require transforming the
@@ -82,25 +130,14 @@ to generate actual output.
The target code generator to used is given by the -t flag on the
command line.
3.0 Building/Installing IVL
4.0 Running Verilog
Unpack the tar-ball and cd into the verilog-######### directory.
The preferred way to invoke the compiler with the verilog(1)
command. This program invokes the preprocessor (ivlpp) and the
compiler (ivl) with the proper command line options to get the job
done in a friendly way. See the verilog(1) man page for usage details.
./configure
make
cd vvm
make
Now install the files in an appropriate place. (The makefiles by
default install in /usr/local unless you specify a different prefix
with the --prefix=<path> flag to the configure command.) Do this as
root.
make install
cd vvm
make install
4.0 Running IVL
4.1 Running IVL Directly
The ivl command is the compiler driver, that invokes the parser,
optimization functions and the code generator.
@@ -208,78 +245,92 @@ endmodule
--------------------------------------------------------------
Insure that "ivl" is on your search path, and the library
libvvm.a is available.
Insure that "verilog" is on your search path, and the vpi library
is available.
For csh -
setenv PATH /usr/local/bin:$PATH
setenv LD_LIBRARY_PATH /usr/local/lib:$LD_LIBRARY_PATH
setenv PATH /usr/local/bin:$PATH
setenv VPI_MODULE_PATH /usr/local/lib/ivl
ivl -t vvm -o hello.cc hello.vl
g++ hello.cc -o hello -lvvm
verilog hello.vl
(The above presumes that /usr/local/include and /usr/local/lib are
part of the compiler search path, which is usually the case for egcs.)
part of the compiler search path, which is usually the case for gcc.)
To run the program
./hello
./hello
5.0 Unsupported Constructs
IVL is in development - as such it still only supports a (growing) subset
of verilog. Below is a description of some of the currently unsupported
verilog features.
- The "?" operator. Example: count = val ? 1 : 0;
- Ranges within parameter definitions:
Example: parameter [15:0] seed = 16'ha3;
[Note: IEEE Std: 1364-1995 does not allow the syntax.]
- The "&&" operator:
Example: if (a && 0) do = 1;
- The "===" operator: Example: if( a === b) do = 1;
- The ">=" operator: Example: if ( a >= 0) do = 1;
- The ">" operator: Example: if ( a > 0) do = 1;
- The "<=" operator: Example: if ( a <= 0) do = 1;
- The "<<" shift operator: Example: a = 8'b0000_0010 << 1;
verilog features. This list is not exhaustive, and does not account
for errors in the compiler. See the Icarus Verilog web page for the
current state of support for Verilog.
- Min/Typ/Max expressions: Example: a = (1 : 6 : 14);
- Expansion of a string into a larger variable:
Example: reg [0:15] b; b = "b";
- Memories work, but only in procedural code.
- Function declarations/calls.
- Non-scalar memories, i.e. other than registers.
Example: reg [1:0] b [2:0];
- Delay list. Example: sample #(9,99) sample1(a,b);
- Bit ranges within IF. Example: if (a[2:3]) do = 1;
- Assignment timing delay: Example: a = #1 0; #1 a = #2 ~a;
- Bit Ranges within $write, $display.
reg [1:0] b [2:0], bar;
wire [1:0] foo;
always foo = b[i]; // sorry
always @(i) bar = b[i]; // OK
- `timescale directive
- Specify blocks
- force/release/assign/deassign procedural assignments not
supported.
- Named port parameters.
Example: module foo(.x(r[0])) ; reg r[7:0]; endmodule
- block disable not supported, i.e.:
begin : foo
[...]
disable foo; // sorry
[...]
end
- fork/join is not supported in vvm runtime
- Structural shift operators are in general not supported.
Procedural expressions are OK. Constant expressions are OK.
assign foo = a << b; // sorry
always @(a or b) foo = a << b; // OK
parameter foo = a << b; // OK
- Functions in structural contexts are not supported.
assign foo = user_function(a,b); // sorry
always @(a or b) foo = user_function(a,b); // OK
- multiplicative operators (*, /, %) are not supported.
assign foo = a * b; // sorry
always @(a or b) foo = a * b; // sorry
- event data type is not supported.
- real data type not supported.
- system functions are not supported. (User defined functions are
supported, and system tasks are supported.)
assign foo = $some_function(a,b); // sorry
always @(a or b) foo = $some_function(a,b); // sorry
- non-constant delay expressions, i.e.:
reg [7:0] del;
always #(reg) $display($time,,"del = %d", del); // sorry
- drive strengths are parsed, bug ignored.
Specify blocks are parsed but ignored in general.
Note that binding to a port by name does work from the outside.
i.e. ``foo foogate(.x(n[0]))'' is OK.
6.0 CREDITS
@@ -288,9 +339,15 @@ Williams. The proper notices are in the head of each file. However,
I have received aid in the form of fixes, Verilog guidance, and
especially testing from many people, including (in alphabetical order):
Eric Aardoom <[email protected]>
Ed Carter <[email protected]>
Larry Doolittle <[email protected]>
Guy Hutchison <[email protected]>
Ales Hvezda <[email protected]>
James Lee <[email protected]>
Peter Monta <[email protected]>
Daniel H. Nelsen <[email protected]>
Stefan Petersen <[email protected]>
Jason Schonberg <[email protected]>
Stuart Sutherland <[email protected]>
Stephen Tell <[email protected]>
@@ -298,4 +355,5 @@ especially testing from many people, including (in alphabetical order):
Steve Wilson <[email protected]>
and others. Testers in particular include a larger community of people
interested in a GPL Verilog for Linux.
interested in a GPL Verilog for Linux. Special thanks to Steve Wilson
for collecting and organizing the test suite code for all those testers.
+39 -7
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: Statement.cc,v 1.12 1999/07/12 00:59:36 steve Exp $"
#ident "$Id: Statement.cc,v 1.16 1999/09/29 18:36:02 steve Exp $"
#endif
# include "Statement.h"
@@ -27,20 +27,30 @@ Statement::~Statement()
{
}
PAssign_::PAssign_(PExpr*lval, PExpr*ex)
: event_(0), lval_(lval), rval_(ex)
{
}
PAssign_::PAssign_(PExpr*lval, PExpr*de, PExpr*ex)
: lval_(lval), delay_(de), rval_(ex)
: event_(0), lval_(lval), rval_(ex)
{
if (de) delay_.set_delay(de);
}
PAssign_::PAssign_(PExpr*lval, PEventStatement*ev, PExpr*ex)
: event_(ev), lval_(lval), rval_(ex)
{
}
PAssign_::~PAssign_()
{
delete lval_;
delete delay_;
delete rval_;
}
PAssign::PAssign(PExpr*lval, PExpr*ex)
: PAssign_(lval, 0, ex)
: PAssign_(lval, ex)
{
}
@@ -49,12 +59,22 @@ PAssign::PAssign(PExpr*lval, PExpr*d, PExpr*ex)
{
}
PAssign::PAssign(PExpr*lval, PEventStatement*d, PExpr*ex)
: PAssign_(lval, d, ex)
{
}
PAssign::~PAssign()
{
}
PAssignNB::PAssignNB(PExpr*lval, PExpr*ex)
: PAssign_(lval, 0, ex)
: PAssign_(lval, ex)
{
}
PAssignNB::PAssignNB(PExpr*lval, PExpr*d, PExpr*ex)
: PAssign_(lval, d, ex)
{
}
@@ -88,8 +108,8 @@ PCallTask::PCallTask(const string&n, const svector<PExpr*>&p)
{
}
PCase::PCase(PExpr*ex, svector<PCase::Item*>*l)
: expr_(ex), items_(l)
PCase::PCase(NetCase::TYPE t, PExpr*ex, svector<PCase::Item*>*l)
: type_(t), expr_(ex), items_(l)
{
}
@@ -143,6 +163,18 @@ PWhile::~PWhile()
/*
* $Log: Statement.cc,v $
* Revision 1.16 1999/09/29 18:36:02 steve
* Full case support
*
* Revision 1.15 1999/09/22 02:00:48 steve
* assignment with blocking event delay.
*
* Revision 1.14 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.13 1999/09/02 01:59:27 steve
* Parse non-blocking assignment delays.
*
* Revision 1.12 1999/07/12 00:59:36 steve
* procedural blocking assignment delays.
*
+33 -4
View File
@@ -19,15 +19,17 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: Statement.h,v 1.15 1999/07/12 00:59:36 steve Exp $"
#ident "$Id: Statement.h,v 1.20 1999/09/29 18:36:02 steve Exp $"
#endif
# include <string>
# include "svector.h"
# include "PDelays.h"
# include "PExpr.h"
# include "LineInfo.h"
class PExpr;
class Statement;
class PEventStatement;
/*
* The PProcess is the root of a behavioral process. Each process gets
@@ -77,11 +79,12 @@ class Statement : public LineInfo {
*/
class PAssign_ : public Statement {
public:
explicit PAssign_(PExpr*lval, PExpr*ex);
explicit PAssign_(PExpr*lval, PExpr*de, PExpr*ex);
explicit PAssign_(PExpr*lval, PEventStatement*de, PExpr*ex);
virtual ~PAssign_() =0;
const PExpr* lval() const { return lval_; }
const PExpr* delay() const { return delay_; }
const PExpr* rval() const { return rval_; }
protected:
@@ -89,9 +92,11 @@ class PAssign_ : public Statement {
unsigned&lsb, unsigned&msb,
NetExpr*&mux) const;
PDelays delay_;
PEventStatement*event_;
private:
PExpr* lval_;
PExpr* delay_;
PExpr* rval_;
};
@@ -100,6 +105,7 @@ class PAssign : public PAssign_ {
public:
explicit PAssign(PExpr*lval, PExpr*ex);
explicit PAssign(PExpr*lval, PExpr*de, PExpr*ex);
explicit PAssign(PExpr*lval, PEventStatement*de, PExpr*ex);
~PAssign();
virtual void dump(ostream&out, unsigned ind) const;
@@ -114,12 +120,15 @@ class PAssignNB : public PAssign_ {
public:
explicit PAssignNB(PExpr*lval, PExpr*ex);
explicit PAssignNB(PExpr*lval, PExpr*de, PExpr*ex);
~PAssignNB();
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
private:
NetProc*assign_to_memory_(class NetMemory*, PExpr*,
Design*des, const string&path) const;
};
/*
@@ -191,13 +200,14 @@ class PCase : public Statement {
Statement*stat;
};
PCase(PExpr*ex, svector<Item*>*);
PCase(NetCase::TYPE, PExpr*ex, svector<Item*>*);
~PCase();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
NetCase::TYPE type_;
PExpr*expr_;
svector<Item*>*items_;
@@ -256,6 +266,10 @@ class PEventStatement : public Statement {
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
// This method is used to elaborate, but attach a previously
// elaborated statement to the event.
NetProc* elaborate_st(Design*des, const string&path, NetProc*st) const;
private:
svector<PEEvent*>expr_;
Statement*statement_;
@@ -333,6 +347,21 @@ class PWhile : public Statement {
/*
* $Log: Statement.h,v $
* Revision 1.20 1999/09/29 18:36:02 steve
* Full case support
*
* Revision 1.19 1999/09/22 02:00:48 steve
* assignment with blocking event delay.
*
* Revision 1.18 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.17 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.16 1999/09/02 01:59:27 steve
* Parse non-blocking assignment delays.
*
* Revision 1.15 1999/07/12 00:59:36 steve
* procedural blocking assignment delays.
*
Vendored Executable
+912
View File
@@ -0,0 +1,912 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
#
# This file 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Written by Per Bothner <[email protected]>.
# The master version of this file is at the FSF in /home/gd/gnu/lib.
#
# This script attempts to guess a canonical system name similar to
# config.sub. If it succeeds, it prints the system name on stdout, and
# exits with 0. Otherwise, it exits with 1.
#
# The plan is that this can be called by configure scripts if you
# don't specify an explicit system type (host/target name).
#
# Only a few systems have been added to this list; please add others
# (but try to keep the structure clean).
#
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# ([email protected] 8/24/94.)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
PATH=$PATH:/.attbin ; export PATH
fi
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
# Note: order is significant - the case branches are not exclusive.
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
alpha:OSF1:*:*)
if test $UNAME_RELEASE = "V4.0"; then
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
fi
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
cat <<EOF >dummy.s
.globl main
.ent main
main:
.frame \$30,0,\$26,0
.prologue 0
.long 0x47e03d80 # implver $0
lda \$2,259
.long 0x47e20c21 # amask $2,$1
srl \$1,8,\$2
sll \$2,2,\$2
sll \$0,3,\$0
addl \$1,\$0,\$0
addl \$2,\$0,\$0
ret \$31,(\$26),1
.end main
EOF
${CC-cc} dummy.s -o dummy 2>/dev/null
if test "$?" = 0 ; then
./dummy
case "$?" in
7)
UNAME_MACHINE="alpha"
;;
15)
UNAME_MACHINE="alphaev5"
;;
14)
UNAME_MACHINE="alphaev56"
;;
10)
UNAME_MACHINE="alphapca56"
;;
16)
UNAME_MACHINE="alphaev6"
;;
esac
fi
rm -f dummy.s dummy
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]`
exit 0 ;;
21064:Windows_NT:50:3)
echo alpha-dec-winnt3.5
exit 0 ;;
Amiga*:UNIX_System_V:4.0:*)
echo m68k-cbm-sysv4
exit 0;;
amiga:NetBSD:*:*)
echo m68k-cbm-netbsd${UNAME_RELEASE}
exit 0 ;;
amiga:OpenBSD:*:*)
echo m68k-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
arc64:OpenBSD:*:*)
echo mips64el-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
arc:OpenBSD:*:*)
echo mipsel-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
hkmips:OpenBSD:*:*)
echo mips-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
pmax:OpenBSD:*:*)
echo mipsel-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
sgi:OpenBSD:*:*)
echo mips-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
wgrisc:OpenBSD:*:*)
echo mipsel-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
exit 0;;
arm32:NetBSD:*:*)
echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
exit 0 ;;
SR2?01:HI-UX/MPP:*:*)
echo hppa1.1-hitachi-hiuxmpp
exit 0;;
Pyramid*:OSx*:*:*|MIS*:OSx*:*:*)
# [email protected] (Earle F. Ake) contributed MIS and NILE.
if test "`(/bin/universe) 2>/dev/null`" = att ; then
echo pyramid-pyramid-sysv3
else
echo pyramid-pyramid-bsd
fi
exit 0 ;;
NILE:*:*:dcosx)
echo pyramid-pyramid-svr4
exit 0 ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit 0 ;;
i86pc:SunOS:5.*:*)
echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit 0 ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit 0 ;;
sun4*:SunOS:*:*)
case "`/usr/bin/arch -k`" in
Series*|S4*)
UNAME_RELEASE=`uname -v`
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
exit 0 ;;
sun3*:SunOS:*:*)
echo m68k-sun-sunos${UNAME_RELEASE}
exit 0 ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
case "`/bin/arch`" in
sun3)
echo m68k-sun-sunos${UNAME_RELEASE}
;;
sun4)
echo sparc-sun-sunos${UNAME_RELEASE}
;;
esac
exit 0 ;;
aushp:SunOS:*:*)
echo sparc-auspex-sunos${UNAME_RELEASE}
exit 0 ;;
atari*:NetBSD:*:*)
echo m68k-atari-netbsd${UNAME_RELEASE}
exit 0 ;;
atari*:OpenBSD:*:*)
echo m68k-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
sun3*:NetBSD:*:*)
echo m68k-sun-netbsd${UNAME_RELEASE}
exit 0 ;;
sun3*:OpenBSD:*:*)
echo m68k-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
mac68k:NetBSD:*:*)
echo m68k-apple-netbsd${UNAME_RELEASE}
exit 0 ;;
mac68k:OpenBSD:*:*)
echo m68k-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
mvme68k:OpenBSD:*:*)
echo m68k-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
mvme88k:OpenBSD:*:*)
echo m88k-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
powerpc:machten:*:*)
echo powerpc-apple-machten${UNAME_RELEASE}
exit 0 ;;
RISC*:Mach:*:*)
echo mips-dec-mach_bsd4.3
exit 0 ;;
RISC*:ULTRIX:*:*)
echo mips-dec-ultrix${UNAME_RELEASE}
exit 0 ;;
VAX*:ULTRIX*:*:*)
echo vax-dec-ultrix${UNAME_RELEASE}
exit 0 ;;
2020:CLIX:*:*)
echo clipper-intergraph-clix${UNAME_RELEASE}
exit 0 ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
sed 's/^ //' << EOF >dummy.c
int main (argc, argv) int argc; char **argv; {
#if defined (host_mips) && defined (MIPSEB)
#if defined (SYSTYPE_SYSV)
printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
#endif
#if defined (SYSTYPE_SVR4)
printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
#endif
#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
#endif
#endif
exit (-1);
}
EOF
${CC-cc} dummy.c -o dummy \
&& ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
&& rm dummy.c dummy && exit 0
rm -f dummy.c dummy
echo mips-mips-riscos${UNAME_RELEASE}
exit 0 ;;
Night_Hawk:Power_UNIX:*:*)
echo powerpc-harris-powerunix
exit 0 ;;
m88k:CX/UX:7*:*)
echo m88k-harris-cxux7
exit 0 ;;
m88k:*:4*:R4*)
echo m88k-motorola-sysv4
exit 0 ;;
m88k:*:3*:R3*)
echo m88k-motorola-sysv3
exit 0 ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
-o ${TARGET_BINARY_INTERFACE}x = x ] ; then
echo m88k-dg-dgux${UNAME_RELEASE}
else
echo m88k-dg-dguxbcs${UNAME_RELEASE}
fi
else echo i586-dg-dgux${UNAME_RELEASE}
fi
exit 0 ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
exit 0 ;;
M88*:*:R3*:*)
# Delta 88k system running SVR3
echo m88k-motorola-sysv3
exit 0 ;;
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
echo m88k-tektronix-sysv3
exit 0 ;;
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
echo m68k-tektronix-bsd
exit 0 ;;
*:IRIX*:*:*)
echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
exit 0 ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
i?86:AIX:*:*)
echo i386-ibm-aix
exit 0 ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
sed 's/^ //' << EOF >dummy.c
#include <sys/systemcfg.h>
main()
{
if (!__power_pc())
exit(1);
puts("powerpc-ibm-aix3.2.5");
exit(0);
}
EOF
${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
rm -f dummy.c dummy
echo rs6000-ibm-aix3.2.5
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
echo rs6000-ibm-aix3.2.4
else
echo rs6000-ibm-aix3.2
fi
exit 0 ;;
*:AIX:*:4)
if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
IBM_ARCH=rs6000
else
IBM_ARCH=powerpc
fi
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
else
IBM_REV=4.${UNAME_RELEASE}
fi
echo ${IBM_ARCH}-ibm-aix${IBM_REV}
exit 0 ;;
*:AIX:*:*)
echo rs6000-ibm-aix
exit 0 ;;
ibmrt:4.4BSD:*|romp-ibm:BSD:*)
echo romp-ibm-bsd4.4
exit 0 ;;
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
exit 0 ;; # report: romp-ibm BSD 4.3
*:BOSX:*:*)
echo rs6000-bull-bosx
exit 0 ;;
DPX/2?00:B.O.S.:*:*)
echo m68k-bull-sysv3
exit 0 ;;
9000/[34]??:4.3bsd:1.*:*)
echo m68k-hp-bsd
exit 0 ;;
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
echo m68k-hp-bsd4.4
exit 0 ;;
9000/[3478]??:HP-UX:*:*)
case "${UNAME_MACHINE}" in
9000/31? ) HP_ARCH=m68000 ;;
9000/[34]?? ) HP_ARCH=m68k ;;
9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;;
9000/8?? ) HP_ARCH=hppa1.0 ;;
esac
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
exit 0 ;;
3050*:HI-UX:*:*)
sed 's/^ //' << EOF >dummy.c
#include <unistd.h>
int
main ()
{
long cpu = sysconf (_SC_CPU_VERSION);
/* The order matters, because CPU_IS_HP_MC68K erroneously returns
true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
results, however. */
if (CPU_IS_PA_RISC (cpu))
{
switch (cpu)
{
case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
default: puts ("hppa-hitachi-hiuxwe2"); break;
}
}
else if (CPU_IS_HP_MC68K (cpu))
puts ("m68k-hitachi-hiuxwe2");
else puts ("unknown-hitachi-hiuxwe2");
exit (0);
}
EOF
${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
rm -f dummy.c dummy
echo unknown-hitachi-hiuxwe2
exit 0 ;;
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
echo hppa1.1-hp-bsd
exit 0 ;;
9000/8??:4.3bsd:*:*)
echo hppa1.0-hp-bsd
exit 0 ;;
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
echo hppa1.1-hp-osf
exit 0 ;;
hp8??:OSF1:*:*)
echo hppa1.0-hp-osf
exit 0 ;;
i?86:OSF1:*:*)
if [ -x /usr/sbin/sysversion ] ; then
echo ${UNAME_MACHINE}-unknown-osf1mk
else
echo ${UNAME_MACHINE}-unknown-osf1
fi
exit 0 ;;
parisc*:Lites*:*:*)
echo hppa1.1-hp-lites
exit 0 ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
exit 0 ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
exit 0 ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
echo c34-convex-bsd
exit 0 ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
echo c38-convex-bsd
exit 0 ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
exit 0 ;;
CRAY*X-MP:*:*:*)
echo xmp-cray-unicos
exit 0 ;;
CRAY*Y-MP:*:*:*)
echo ymp-cray-unicos${UNAME_RELEASE}
exit 0 ;;
CRAY*[A-Z]90:*:*:*)
echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
-e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
exit 0 ;;
CRAY*TS:*:*:*)
echo t90-cray-unicos${UNAME_RELEASE}
exit 0 ;;
CRAY-2:*:*:*)
echo cray2-cray-unicos
exit 0 ;;
F300:UNIX_System_V:*:*)
FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit 0 ;;
F301:UNIX_System_V:*:*)
echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
exit 0 ;;
hp3[0-9][05]:NetBSD:*:*)
echo m68k-hp-netbsd${UNAME_RELEASE}
exit 0 ;;
hp300:OpenBSD:*:*)
echo m68k-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
i?86:BSD/386:*:* | *:BSD/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
exit 0 ;;
*:FreeBSD:*:*)
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit 0 ;;
*:NetBSD:*:*)
echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
exit 0 ;;
*:OpenBSD:*:*)
echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
exit 0 ;;
i*:CYGWIN*:*)
echo i386-pc-cygwin32
exit 0 ;;
i*:MINGW*:*)
echo i386-pc-mingw32
exit 0 ;;
p*:CYGWIN*:*)
echo powerpcle-unknown-cygwin32
exit 0 ;;
prep*:SunOS:5.*:*)
echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit 0 ;;
*:GNU:*:*)
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
exit 0 ;;
*:Linux:*:*)
# The BFD linker knows what the default object file format is, so
# first see if it will tell us.
ld_help_string=`ld --help 2>&1`
ld_supported_emulations=`echo $ld_help_string \
| sed -ne '/supported emulations:/!d
s/[ ][ ]*/ /g
s/.*supported emulations: *//
s/ .*//
p'`
case "$ld_supported_emulations" in
i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;;
i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;;
sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
elf32ppc)
# Determine Lib Version
cat >dummy.c <<EOF
#include <features.h>
#if defined(__GLIBC__)
extern char __libc_version[];
extern char __libc_release[];
#endif
main(argc, argv)
int argc;
char *argv[];
{
#if defined(__GLIBC__)
printf("%s %s\n", __libc_version, __libc_release);
#else
printf("unkown\n");
#endif
return 0;
}
EOF
LIBC=""
${CC-cc} dummy.c -o dummy 2>/dev/null
if test "$?" = 0 ; then
./dummy | grep 1\.99 > /dev/null
if test "$?" = 0 ; then
LIBC="libc1"
fi
fi
rm -f dummy.c dummy
echo powerpc-unknown-linux-gnu${LIBC} ; exit 0 ;;
esac
if test "${UNAME_MACHINE}" = "alpha" ; then
sed 's/^ //' <<EOF >dummy.s
.globl main
.ent main
main:
.frame \$30,0,\$26,0
.prologue 0
.long 0x47e03d80 # implver $0
lda \$2,259
.long 0x47e20c21 # amask $2,$1
srl \$1,8,\$2
sll \$2,2,\$2
sll \$0,3,\$0
addl \$1,\$0,\$0
addl \$2,\$0,\$0
ret \$31,(\$26),1
.end main
EOF
LIBC=""
${CC-cc} dummy.s -o dummy 2>/dev/null
if test "$?" = 0 ; then
./dummy
case "$?" in
7)
UNAME_MACHINE="alpha"
;;
15)
UNAME_MACHINE="alphaev5"
;;
14)
UNAME_MACHINE="alphaev56"
;;
10)
UNAME_MACHINE="alphapca56"
;;
16)
UNAME_MACHINE="alphaev6"
;;
esac
objdump --private-headers dummy | \
grep ld.so.1 > /dev/null
if test "$?" = 0 ; then
LIBC="libc1"
fi
fi
rm -f dummy.s dummy
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
elif test "${UNAME_MACHINE}" = "mips" ; then
cat >dummy.c <<EOF
main(argc, argv)
int argc;
char *argv[];
{
#ifdef __MIPSEB__
printf ("%s-unknown-linux-gnu\n", argv[1]);
#endif
#ifdef __MIPSEL__
printf ("%sel-unknown-linux-gnu\n", argv[1]);
#endif
return 0;
}
EOF
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
rm -f dummy.c dummy
else
# Either a pre-BFD a.out linker (linux-gnuoldld)
# or one that does not give us useful --help.
# GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
# If ld does not provide *any* "supported emulations:"
# that means it is gnuoldld.
echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
case "${UNAME_MACHINE}" in
i?86)
VENDOR=pc;
;;
*)
VENDOR=unknown;
;;
esac
# Determine whether the default compiler is a.out or elf
cat >dummy.c <<EOF
#include <features.h>
main(argc, argv)
int argc;
char *argv[];
{
#ifdef __ELF__
# ifdef __GLIBC__
# if __GLIBC__ >= 2
printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
# else
printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
# endif
# else
printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
# endif
#else
printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
#endif
return 0;
}
EOF
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
rm -f dummy.c dummy
fi ;;
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
# are messed up and put the nodename in both sysname and nodename.
i?86:DYNIX/ptx:4*:*)
echo i386-sequent-sysv4
exit 0 ;;
i?86:UNIX_SV:4.2MP:2.*)
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
# I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
# Use sysv4.2uw... so that sysv4* matches it.
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
exit 0 ;;
i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
else
echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
fi
exit 0 ;;
i?86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
elif /bin/uname -X 2>/dev/null >/dev/null ; then
UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
&& UNAME_MACHINE=i586
echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
else
echo ${UNAME_MACHINE}-pc-sysv32
fi
exit 0 ;;
pc:*:*:*)
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i386.
echo i386-pc-msdosdjgpp
exit 0 ;;
Intel:Mach:3*:*)
echo i386-pc-mach3
exit 0 ;;
paragon:*:*:*)
echo i860-intel-osf1
exit 0 ;;
i860:*:4.*:*) # i860-SVR4
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
else # Add other i860-SVR4 vendors below as they are discovered.
echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
fi
exit 0 ;;
mini*:CTIX:SYS*5:*)
# "miniframe"
echo m68010-convergent-sysv
exit 0 ;;
M68*:*:R3V[567]*:*)
test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& echo i486-ncr-sysv4.3${OS_REL} && exit 0
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
&& echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& echo i486-ncr-sysv4 && exit 0 ;;
m68*:LynxOS:2.*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
exit 0 ;;
mc68030:UNIX_System_V:4.*:*)
echo m68k-atari-sysv4
exit 0 ;;
i?86:LynxOS:2.*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
exit 0 ;;
TSUNAMI:LynxOS:2.*:*)
echo sparc-unknown-lynxos${UNAME_RELEASE}
exit 0 ;;
rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit 0 ;;
SM[BE]S:UNIX_SV:*:*)
echo mips-dde-sysv${UNAME_RELEASE}
exit 0 ;;
RM*:SINIX-*:*:*)
echo mips-sni-sysv4
exit 0 ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null`
echo ${UNAME_MACHINE}-sni-sysv4
else
echo ns32k-sni-sysv
fi
exit 0 ;;
PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
# says <[email protected]>
echo i586-unisys-sysv4
exit 0 ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes <[email protected]>.
# How about differentiating between stratus architectures? -djm
echo hppa1.1-stratus-sysv4
exit 0 ;;
*:*:*:FTX*)
# From [email protected].
echo i860-stratus-sysv4
exit 0 ;;
mc68*:A/UX:*:*)
echo m68k-apple-aux${UNAME_RELEASE}
exit 0 ;;
news*:NEWS-OS:*:6*)
echo mips-sony-newsos6
exit 0 ;;
R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*)
if [ -d /usr/nec ]; then
echo mips-nec-sysv${UNAME_RELEASE}
else
echo mips-unknown-sysv${UNAME_RELEASE}
fi
exit 0 ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
cat >dummy.c <<EOF
#ifdef _SEQUENT_
# include <sys/types.h>
# include <sys/utsname.h>
#endif
main ()
{
#if defined (sony)
#if defined (MIPSEB)
/* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
I don't know.... */
printf ("mips-sony-bsd\n"); exit (0);
#else
#include <sys/param.h>
printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
"4"
#else
""
#endif
); exit (0);
#endif
#endif
#if defined (__arm) && defined (__acorn) && defined (__unix)
printf ("arm-acorn-riscix"); exit (0);
#endif
#if defined (hp300) && !defined (hpux)
printf ("m68k-hp-bsd\n"); exit (0);
#endif
#if defined (NeXT)
#if !defined (__ARCHITECTURE__)
#define __ARCHITECTURE__ "m68k"
#endif
int version;
version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
exit (0);
#endif
#if defined (MULTIMAX) || defined (n16)
#if defined (UMAXV)
printf ("ns32k-encore-sysv\n"); exit (0);
#else
#if defined (CMU)
printf ("ns32k-encore-mach\n"); exit (0);
#else
printf ("ns32k-encore-bsd\n"); exit (0);
#endif
#endif
#endif
#if defined (__386BSD__)
printf ("i386-pc-bsd\n"); exit (0);
#endif
#if defined (sequent)
#if defined (i386)
printf ("i386-sequent-dynix\n"); exit (0);
#endif
#if defined (ns32000)
printf ("ns32k-sequent-dynix\n"); exit (0);
#endif
#endif
#if defined (_SEQUENT_)
struct utsname un;
uname(&un);
if (strncmp(un.version, "V2", 2) == 0) {
printf ("i386-sequent-ptx2\n"); exit (0);
}
if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
printf ("i386-sequent-ptx1\n"); exit (0);
}
printf ("i386-sequent-ptx\n"); exit (0);
#endif
#if defined (vax)
#if !defined (ultrix)
printf ("vax-dec-bsd\n"); exit (0);
#else
printf ("vax-dec-ultrix\n"); exit (0);
#endif
#endif
#if defined (alliant) && defined (i860)
printf ("i860-alliant-bsd\n"); exit (0);
#endif
exit (1);
}
EOF
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
rm -f dummy.c dummy
# Apollos put the system type in the environment.
test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
# Convex versions that predate uname can use getsysinfo(1)
if [ -x /usr/convex/getsysinfo ]
then
case `getsysinfo -f cpu_type` in
c1*)
echo c1-convex-bsd
exit 0 ;;
c2*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
exit 0 ;;
c34*)
echo c34-convex-bsd
exit 0 ;;
c38*)
echo c38-convex-bsd
exit 0 ;;
c4*)
echo c4-convex-bsd
exit 0 ;;
esac
fi
#echo '(Unable to guess system type)' 1>&2
exit 1
Vendored Executable
+1178
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -4,6 +4,8 @@ AC_INIT(netlist.h)
dnl Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AC_CHECK_TOOL(STRIP, strip, true)
AC_CHECK_HEADERS(getopt.h)
AC_PROG_INSTALL
AC_OUTPUT(Makefile ivlpp/Makefile vvm/Makefile)
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile)
+310 -37
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: design_dump.cc,v 1.34 1999/08/01 16:34:50 steve Exp $"
#ident "$Id: design_dump.cc,v 1.61 1999/11/28 23:42:02 steve Exp $"
#endif
/*
@@ -49,6 +49,8 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
pin_count() << "]";
if (local_flag_)
o << " (local)";
if (scope_)
o << " scope=" << scope_->name();
o << " #(" << rise_time() << "," << fall_time() << "," <<
decay_time() << ") init=";
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
@@ -84,7 +86,9 @@ void NetNode::dump_node(ostream&o, unsigned ind) const
void NetObj::dump_node_pins(ostream&o, unsigned ind) const
{
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
o << setw(ind) << "" << idx;
o << setw(ind) << "" << idx << " " << pin(idx).get_name()
<< "<" << pin(idx).get_inst() << ">";
switch (pin(idx).get_dir()) {
case Link::PASSIVE:
o << " p";
@@ -121,26 +125,65 @@ void NetObj::dump_obj_attr(ostream&o, unsigned ind) const
}
}
void NetAddSub::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Adder (NetAddSub): " << 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): " <<
name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetCompare::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_COMPARE (NetCompare): " <<
name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetMux::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Multiplexer (NetMux): " << name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetAssign::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Procedural assign: " << *rval_ << endl;
o << setw(ind) << "" << "Procedural assign (NetAssign): " << name();
if (bmux())
o << "[" << *bmux() << "]";
o << " = " << *rval() << endl;
dump_node_pins(o, ind+4);
}
void NetAssignNB::dump_node(ostream&o, unsigned ind) const
{
if (bmux_)
o << setw(ind) << "" << "Procedural NB assign: " << name()
<< "[" << *bmux_ << "] <= " << *rval_ << endl;
if (bmux())
o << setw(ind) << "" << "Procedural NB assign (NetAssignNB): "
<< name() << "[" << *bmux() << "] <= " << *rval() << endl;
else
o << setw(ind) << "" << "Procedural NB assign: " << name()
<< " <= " << *rval_ << endl;
o << setw(ind) << "" << "Procedural NB assign (NetAssignNB): "
<< name() << " <= " << *rval() << endl;
dump_node_pins(o, ind+4);
}
void NetBUFZ::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "BUFZ: " << name() << endl;
o << setw(ind) << "" << "NetBUFZ: " << name() << endl;
dump_node_pins(o, ind+4);
}
void NetCaseCmp::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "case compare === : " << name() << endl;
dump_node_pins(o, ind+4);
}
@@ -150,6 +193,13 @@ void NetConst::dump_node(ostream&o, unsigned ind) const
dump_node_pins(o, ind+4);
}
void NetFF::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_FF: " << name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetLogic::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "logic: ";
@@ -193,6 +243,14 @@ void NetLogic::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetRamDq::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_RAM_DQ (" << mem_->name() << "): "
<< name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetTaskDef::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "task " << name_ << ";" << endl;
@@ -273,6 +331,12 @@ void NetUDP::dump_comb_(ostream&o, unsigned ind) const
o << " #(" << rise_time() << "," << fall_time() << "," << decay_time() <<
") " << name() << endl;
for (CM_::const_iterator ent = cm_.begin()
; ent != cm_.end() ; ent++) {
o << setw(ind+6) << "" << (*ent).first << " --> " <<
(*ent).second << endl;
}
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
@@ -327,28 +391,35 @@ void NetAssign::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "";
const NetNet*sig;
unsigned msb, lsb;
find_lval_range(sig, msb, lsb);
o << sig->name() << "[" << msb;
if (pin_count() > 1)
o << ":" << lsb;
o << "] = ";
rval_->dump(o);
o << ";" << endl;
if (bmux()) {
o << name() << "[" << *bmux() << "] = ";
if (rise_time())
o << "#" << rise_time() << " ";
o << *rval() << ";" << endl;
} else {
o << name() << " = ";
if (rise_time())
o << "#" << rise_time() << " ";
o << *rval() << ";" << endl;
}
}
void NetAssignNB::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "";
if (bmux_) {
o << name() << "[" << *bmux_ << "] <= " << *rval_ << ";" <<
endl;
if (bmux()) {
o << name() << "[" << *bmux() << "] <= ";
if (rise_time())
o << "#" << rise_time() << " ";
o << *rval() << ";" << endl;
} else {
o << name() << " <= " << *rval_ << ";" << endl;
o << name() << " <= ";
if (rise_time())
o << "#" << rise_time() << " ";
o << *rval() << ";" << endl;
}
}
@@ -357,10 +428,22 @@ void NetAssignMem::dump(ostream&o, unsigned ind) const
o << setw(ind) << "";
o << "/* " << get_line() << " */" << endl;
o << setw(ind) << "";
o << mem_->name() << "[";
index_->dump(o);
o << memory()->name() << "[";
index()->dump(o);
o << "] = ";
rval_->dump(o);
rval()->dump(o);
o << ";" << endl;
}
void NetAssignMemNB::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "";
o << "/* " << get_line() << " */" << endl;
o << setw(ind) << "";
o << memory()->name() << "[";
index()->dump(o);
o << "] <= ";
rval()->dump(o);
o << ";" << endl;
}
@@ -382,7 +465,17 @@ void NetBlock::dump(ostream&o, unsigned ind) const
void NetCase::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "case (" << *expr_ << ")" << endl;
switch (type_) {
case EQ:
o << setw(ind) << "" << "case (" << *expr_ << ")" << endl;
break;
case EQX:
o << setw(ind) << "" << "casex (" << *expr_ << ")" << endl;
break;
case EQZ:
o << setw(ind) << "" << "casez (" << *expr_ << ")" << endl;
break;
}
for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) {
o << setw(ind+2) << "";
@@ -423,6 +516,15 @@ void NetForever::dump(ostream&o, unsigned ind) const
statement_->dump(o, ind+2);
}
void NetFuncDef::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "function " << name_ << endl;
if (statement_)
statement_->dump(o, ind+2);
else
o << setw(ind+2) << "" << "// NO STATEMENT" << endl;
}
void NetPDelay::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "#" << delay_;
@@ -479,6 +581,23 @@ void NetRepeat::dump(ostream&o, unsigned ind) const
statement_->dump(o, ind+2);
}
void NetScope::dump(ostream&o) const
{
o << name_;
switch (type_) {
case BEGIN_END:
o << " sequential block";
break;
case FORK_JOIN:
o << " parallel block";
break;
case MODULE:
o << " module";
break;
}
o << endl;
}
void NetSTask::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << name_;
@@ -558,9 +677,15 @@ void NetEBinary::dump(ostream&o) const
case 'o':
o << "||";
break;
case 'O':
o << "~|";
break;
case 'r':
o << ">>";
break;
case 'X':
o << "~^";
break;
}
o << "(";
right_->dump(o);
@@ -569,9 +694,20 @@ void NetEBinary::dump(ostream&o) const
void NetEConcat::dump(ostream&o) const
{
o << "{" << *parms_[0];
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1)
o << ", " << *parms_[idx];
if (repeat_ != 1)
o << repeat_;
if (parms_[0])
o << "{" << *parms_[0];
else
o << "{";
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
if (parms_[idx])
o << ", " << *parms_[idx];
else
o << ", ";
}
o << "}";
}
@@ -588,6 +724,11 @@ void NetEIdent::dump(ostream&o) const
o << name_;
}
void NetEScope::dump(ostream&o) const
{
o << "<scope=" << scope_->name() << ">";
}
void NetESignal::dump(ostream&o) const
{
o << name();
@@ -608,28 +749,54 @@ void NetEMemory::dump(ostream&o) const
o << "]";
}
void NetESignal::dump_node(ostream&o, unsigned ind) const
void NetEParam::dump(ostream&o) const
{
o << setw(ind) << "" << "Expression Node: " << name() << endl;
dump_node_pins(o, ind+4);
o << "<" << path_ << "." << name_ << ">";
}
void NetETernary::dump(ostream&o) const
{
o << "(" << *cond_ << ")? (" << *true_val_ << ") : (" <<
false_val_ << ")";
o << "(" << *cond_ << ") ? (" << *true_val_ << ") : (" <<
*false_val_ << ")";
}
void NetEUFunc::dump(ostream&o) const
{
o << name() << "(";
assert(parms_.count() > 0);
parms_[0]->dump(o);
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
o << ", ";
parms_[idx]->dump(o);
}
o << ")";
}
void NetEUnary::dump(ostream&o) const
{
o << op_ << "(";
switch (op_) {
case 'N':
o << "~|";
break;
default:
o << op_;
break;
}
o << "(";
expr_->dump(o);
o << ")";
}
void Design::dump(ostream&o) const
{
o << "SCOPES:" << endl;
{
map<string,NetScope*>::const_iterator pp;
for (pp = scopes_.begin()
; pp != scopes_.end() ; pp ++)
(*pp).second -> dump(o);
}
o << "ELABORATED PARAMETERS:" << endl;
{
map<string,NetExpr*>::const_iterator pp;
@@ -660,6 +827,15 @@ void Design::dump(ostream&o) const
}
}
o << "ELABORATED FUNCTION DEFINITIONS:" << endl;
{
map<string,NetFuncDef*>::const_iterator pp;
for (pp = funcs_.begin()
; pp != funcs_.end() ; pp ++) {
(*pp).second->dump(o, 0);
}
}
o << "ELABORATED TASK DEFINITIONS:" << endl;
{
map<string,NetTaskDef*>::const_iterator pp;
@@ -690,6 +866,103 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.61 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.60 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.59 1999/11/24 04:01:58 steve
* Detect and list scope names.
*
* Revision 1.58 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.57 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.56 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.55 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
*
* Add the LPM_MUX device, and integrate it with the
* ternary synthesis from Larry. Replace the lpm_mux
* generator in t-xnf.cc to use XNF EQU devices to
* put muxs into function units.
*
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
*
* Revision 1.54 1999/11/04 01:12:41 steve
* Elaborate combinational UDP devices.
*
* Revision 1.53 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.52 1999/10/31 20:08:24 steve
* Include subtraction in LPM_ADD_SUB device.
*
* Revision 1.51 1999/10/31 04:11:27 steve
* Add to netlist links pin name and instance number,
* and arrange in vvm for pin connections by name
* and instance number.
*
* Revision 1.50 1999/10/10 01:59:54 steve
* Structural case equals device.
*
* Revision 1.49 1999/10/08 02:00:35 steve
* Fix dump of sase statements.
*
* Revision 1.48 1999/10/07 05:25:33 steve
* Add non-const bit select in l-value of assignment.
*
* Revision 1.47 1999/10/06 05:06:16 steve
* Move the rvalue into NetAssign_ common code.
*
* Revision 1.46 1999/10/05 06:19:46 steve
* Add support for reduction NOR.
*
* Revision 1.45 1999/09/30 02:43:01 steve
* Elaborate ~^ and ~| operators.
*
* Revision 1.44 1999/09/29 18:36:03 steve
* Full case support
*
* Revision 1.43 1999/09/21 00:13:40 steve
* Support parameters that reference other paramters.
*
* Revision 1.42 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
* Revision 1.41 1999/09/19 01:06:36 steve
* dump the repeat count, if applicable.
*
* Revision 1.40 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.39 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.38 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.37 1999/09/01 20:46:19 steve
* Handle recursive functions and arbitrary function
* references to other functions, properly pass
* function parameters and save function results.
*
* Revision 1.36 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.35 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.34 1999/08/01 16:34:50 steve
* Parse and elaborate rise/fall/decay times
* for gates, and handle the rules for partial
+10 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@picturel.com)
* Copyright (c) 1999 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,22 +17,22 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_monitor.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
#ident "$Id: dup_expr.cc,v 1.1 1999/11/27 19:07:57 steve Exp $"
#endif
# include "vvm.h"
# include "netlist.h"
# include <cassert>
vvm_monitor_t::vvm_monitor_t(const string&n)
: name_(n)
NetEScope* NetEScope::dup_expr() const
{
assert(0);
return 0;
}
/*
* $Log: vvm_monitor.cc,v $
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
* $Log: dup_expr.cc,v $
* Revision 1.1 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
*/
+373
View File
@@ -0,0 +1,373 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: elab_expr.cc,v 1.12 1999/11/30 04:54:01 steve Exp $"
#endif
# include "pform.h"
# include "netlist.h"
/*
* Elaborate binary expressions. This involves elaborating the left
* and right sides, and creating one of a variety of different NetExpr
* types.
*/
NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
{
bool flag;
NetExpr*lp = left_->elaborate_expr(des, path);
NetExpr*rp = right_->elaborate_expr(des, path);
if ((lp == 0) || (rp == 0)) {
delete lp;
delete rp;
return 0;
}
/* If either expression can be evaluated ahead of time, then
do so. This can prove helpful later. */
{ NetExpr*tmp;
tmp = lp->eval_tree();
if (tmp) {
delete lp;
lp = tmp;
}
tmp = rp->eval_tree();
if (tmp) {
delete rp;
rp = tmp;
}
}
NetEBinary*tmp;
switch (op_) {
default:
tmp = new NetEBinary(op_, lp, rp);
tmp->set_line(*this);
break;
case 'a':
case 'o':
tmp = new NetEBLogic(op_, lp, rp);
tmp->set_line(*this);
break;
case 'l':
case 'r':
tmp = new NetEBShift(op_, lp, rp);
tmp->set_line(*this);
break;
case '^':
case '&':
case '|':
case 'O':
case 'X':
tmp = new NetEBBits(op_, lp, rp);
tmp->set_line(*this);
break;
case '+':
case '-':
tmp = new NetEBAdd(op_, lp, rp);
tmp->set_line(*this);
break;
case 'e': /* == */
case 'E': /* === */
case 'n': /* != */
case 'N': /* !== */
case 'L': /* <= */
case 'G': /* >= */
case '<':
case '>':
tmp = new NetEBComp(op_, lp, rp);
tmp->set_line(*this);
flag = tmp->set_width(1);
if (flag == false) {
cerr << get_line() << ": internal error: "
"expression bit width of comparison != 1." << endl;
des->errors += 1;
}
break;
}
return tmp;
}
NetESFunc* PECallFunction::elaborate_sfunc_(Design*des, const string&path) const
{
cerr << get_line() << ": sorry: system functions not supported."
<< endl;
des->errors += 1;
return 0;
}
NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
{
if (name_[0] == '$')
return elaborate_sfunc_(des, path);
string myname = path+"."+name_;
NetFuncDef*def = des->find_function(path, name_);
if (def == 0) {
cerr << get_line() << ": error: No function " << name_ <<
" in this context (" << path << ")." << endl;
des->errors += 1;
return 0;
}
assert(def);
svector<NetExpr*> parms (parms_.count());
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
NetExpr*tmp = parms_[idx]->elaborate_expr(des, myname);
parms[idx] = tmp;
}
/* Look for the return value signal for the called function in
the context of the function definition, not my context. */
NetNet*res = des->find_signal(def->name(), name_);
if (res == 0) {
cerr << get_line() << ": internal error: Unable to locate "
"function return value for " << name_ << " in " <<
def->name() << "." << endl;
des->errors += 1;
return 0;
}
assert(res);
NetESignal*eres = new NetESignal(res);
assert(eres);
NetEUFunc*func = new NetEUFunc(def, eres, parms);
return func;
}
NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
{
// System identifiers show up in the netlist as identifiers.
if (text_[0] == '$')
return new NetEIdent(text_, 64);
string name = path+"."+text_;
// If the identifier name is a parameter name, then return
// a reference to the parameter expression.
if (const NetExpr*ex = des->find_parameter(path, text_)) {
NetExpr*tmp;
if (dynamic_cast<const NetExpr*>(ex))
tmp = ex->dup_expr();
else
tmp = new NetEParam(des, path, text_);
tmp->set_line(*this);
return tmp;
}
// If the identifier names a signal (a register or wire)
// then create a NetESignal node to handle it.
if (NetNet*net = des->find_signal(path, text_)) {
// If this is a part select of a signal, then make a new
// temporary signal that is connected to just the
// selected bits.
if (lsb_) {
assert(msb_);
verinum*lsn = lsb_->eval_const(des, path);
verinum*msn = msb_->eval_const(des, path);
if ((lsn == 0) || (msn == 0)) {
cerr << get_line() << ": error: "
"Part select expresions must be "
"constant expressions." << endl;
des->errors += 1;
return 0;
}
assert(lsn);
assert(msn);
unsigned long lsv = lsn->as_ulong();
unsigned long msv = msn->as_ulong();
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
assert(wid <= net->pin_count());
assert(net->sb_to_idx(msv) >= net->sb_to_idx(lsv));
string tname = des->local_symbol(path);
NetTmp*tsig = new NetTmp(tname, wid);
// Connect the pins from the lsb up to the msb.
unsigned off = net->sb_to_idx(lsv);
for (unsigned idx = 0 ; idx < wid ; idx += 1)
connect(tsig->pin(idx), net->pin(idx+off));
NetESignal*tmp = new NetESignal(tsig);
tmp->set_line(*this);
des->add_signal(tsig);
return tmp;
}
// If the bit select is constant, then treat it similar
// to the part select, so that I save the effort of
// making a mux part in the netlist.
verinum*msn;
if (msb_ && (msn = msb_->eval_const(des, path))) {
assert(idx_ == 0);
unsigned long msv = msn->as_ulong();
string tname = des->local_symbol(path);
NetTmp*tsig = new NetTmp(tname);
connect(tsig->pin(0), net->pin(msv));
NetESignal*tmp = new NetESignal(tsig);
tmp->set_line(*this);
des->add_signal(tsig);
return tmp;
}
NetESignal*node = new NetESignal(net);
assert(idx_ == 0);
// Non-constant bit select? punt and make a subsignal
// device to mux the bit in the net.
if (msb_) {
NetExpr*ex = msb_->elaborate_expr(des, path);
NetESubSignal*ss = new NetESubSignal(node, ex);
ss->set_line(*this);
return ss;
}
// All else fails, return the signal itself as the
// expression.
assert(msb_ == 0);
return node;
}
// If the identifier names a memory, then this is a
// memory reference and I must generate a NetEMemory
// object to handle it.
if (NetMemory*mem = des->find_memory(path, text_)) {
if (msb_ == 0) {
cerr << get_line() << ": error: Memory ``" << name <<
"'' referenced without an index expression." << endl;
des->errors += 1;
return 0;
}
assert(msb_ != 0);
assert(lsb_ == 0);
assert(idx_ == 0);
NetExpr*i = msb_->elaborate_expr(des, path);
if (msb_ && i == 0) {
cerr << get_line() << ": error: Unable to exaborate "
"index expression `" << *msb_ << "'" << endl;
des->errors += 1;
return 0;
}
NetEMemory*node = new NetEMemory(mem, i);
node->set_line(*this);
return node;
}
// Finally, if this is a scope name, then return that.
if (NetScope*nsc = des->find_scope(text_)) {
NetEScope*tmp = new NetEScope(nsc);
tmp->set_line(*this);
return tmp;
}
// I cannot interpret this identifier. Error message.
cerr << get_line() << ": error: Unable to bind wire/reg/memory "
"`" << path << "." << text_ << "'" << endl;
des->errors += 1;
return 0;
}
/*
* Elaborate the Ternary operator. I know that the expressions were
* parsed so I can presume that they exist, and call elaboration
* methods. If any elaboration fails, then give up and return 0.
*/
NetExpr*PETernary::elaborate_expr(Design*des, const string&path) const
{
assert(expr_);
assert(tru_);
assert(fal_);
NetExpr*con = expr_->elaborate_expr(des, path);
if (con == 0)
return 0;
NetExpr*tru = tru_->elaborate_expr(des, path);
if (tru == 0) {
delete con;
return 0;
}
NetExpr*fal = fal_->elaborate_expr(des, path);
if (fal == 0) {
delete con;
delete tru;
return 0;
}
NetETernary*res = new NetETernary(con, tru, fal);
return res;
}
/*
* $Log: elab_expr.cc,v $
* Revision 1.12 1999/11/30 04:54:01 steve
* Match scope names as last resort.
*
* Revision 1.11 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.10 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.9 1999/11/21 17:35:37 steve
* Memory name lookup handles scopes.
*
* Revision 1.8 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
* Revision 1.7 1999/10/18 00:02:21 steve
* Catch unindexed memory reference.
*
* Revision 1.6 1999/09/30 02:43:02 steve
* Elaborate ~^ and ~| operators.
*
* Revision 1.5 1999/09/30 00:48:49 steve
* Cope with errors during ternary operator elaboration.
*
* Revision 1.4 1999/09/29 22:57:10 steve
* Move code to elab_expr.cc
*
* Revision 1.3 1999/09/25 02:57:30 steve
* Parse system function calls.
*
* Revision 1.2 1999/09/21 00:13:40 steve
* Support parameters that reference other paramters.
*
* Revision 1.1 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
*/
+945
View File
@@ -0,0 +1,945 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: elab_net.cc,v 1.11 1999/12/02 04:08:10 steve Exp $"
#endif
# include "PExpr.h"
# include "netlist.h"
/*
* Elaborating binary operations generally involves elaborating the
* left and right expressions, then making an output wire and
* connecting the lot together with the right kind of gate.
*/
NetNet* PEBinary::elaborate_net(Design*des, const string&path,
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
switch (op_) {
case '+':
case '-':
return elaborate_net_add_(des, path, width, rise, fall, decay);
case 'E':
case 'e':
case 'n':
case '<':
case '>':
case 'L': // <=
case 'G': // >=
return elaborate_net_cmp_(des, path, width, rise, fall, decay);
case 'l': // <<
case 'r': // >>
return elaborate_net_shift_(des, path, width, rise, fall, decay);
}
NetNet*lsig = left_->elaborate_net(des, path, width, 0, 0, 0),
*rsig = right_->elaborate_net(des, path, width, 0, 0, 0);
if (lsig == 0) {
cerr << get_line() << ": error: Cannot elaborate ";
left_->dump(cerr);
cerr << endl;
return 0;
}
if (rsig == 0) {
cerr << get_line() << ": error: Cannot elaborate ";
right_->dump(cerr);
cerr << endl;
return 0;
}
NetNet*osig;
NetNode*gate;
NetNode*gate_t;
switch (op_) {
case '^': // XOR
assert(lsig->pin_count() == rsig->pin_count());
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
lsig->pin_count());
osig->local_flag(true);
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate = new NetLogic(des->local_symbol(path), 3,
NetLogic::XOR);
connect(gate->pin(1), lsig->pin(idx));
connect(gate->pin(2), rsig->pin(idx));
connect(gate->pin(0), osig->pin(idx));
gate->rise_time(rise);
gate->fall_time(fall);
gate->decay_time(decay);
des->add_node(gate);
}
des->add_signal(osig);
break;
case '&': // AND
assert(lsig->pin_count() == rsig->pin_count());
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
lsig->pin_count());
osig->local_flag(true);
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate = new NetLogic(des->local_symbol(path), 3,
NetLogic::AND);
connect(gate->pin(1), lsig->pin(idx));
connect(gate->pin(2), rsig->pin(idx));
connect(gate->pin(0), osig->pin(idx));
gate->rise_time(rise);
gate->fall_time(fall);
gate->decay_time(decay);
des->add_node(gate);
}
des->add_signal(osig);
break;
case '|': // Bitwise OR
assert(lsig->pin_count() == rsig->pin_count());
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
lsig->pin_count());
osig->local_flag(true);
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate = new NetLogic(des->local_symbol(path), 3,
NetLogic::OR);
connect(gate->pin(1), lsig->pin(idx));
connect(gate->pin(2), rsig->pin(idx));
connect(gate->pin(0), osig->pin(idx));
gate->rise_time(rise);
gate->fall_time(fall);
gate->decay_time(decay);
des->add_node(gate);
}
des->add_signal(osig);
break;
case 'a': // && (logical AND)
gate = new NetLogic(des->local_symbol(path), 3, NetLogic::AND);
// The first OR gate returns 1 if the left value is true...
if (lsig->pin_count() > 1) {
gate_t = new NetLogic(des->local_symbol(path),
1+lsig->pin_count(), NetLogic::OR);
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
connect(gate_t->pin(idx+1), lsig->pin(idx));
connect(gate->pin(1), gate_t->pin(0));
des->add_node(gate_t);
} else {
connect(gate->pin(1), lsig->pin(0));
}
// The second OR gate returns 1 if the right value is true...
if (rsig->pin_count() > 1) {
gate_t = new NetLogic(des->local_symbol(path),
1+rsig->pin_count(), NetLogic::OR);
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
connect(gate_t->pin(idx+1), rsig->pin(idx));
connect(gate->pin(2), gate_t->pin(0));
des->add_node(gate_t);
} else {
connect(gate->pin(2), rsig->pin(0));
}
// The output is the AND of the two logic values.
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
osig->local_flag(true);
connect(gate->pin(0), osig->pin(0));
des->add_signal(osig);
gate->rise_time(rise);
gate->fall_time(fall);
gate->decay_time(decay);
des->add_node(gate);
break;
case 'E': // === (Case equals)
case 'e': // ==
case 'n': // !=
case '<':
case '>':
case 'G': // >=
case 'L': // <=
assert(0);
break;
case '+':
assert(0);
break;
case 'l':
case 'r':
assert(0);
break;
default:
cerr << get_line() << ": internal error: unsupported"
" combinational operator (" << op_ << ")." << endl;
des->errors += 1;
osig = 0;
}
if (NetTmp*tmp = dynamic_cast<NetTmp*>(lsig))
delete tmp;
if (NetTmp*tmp = dynamic_cast<NetTmp*>(rsig))
delete tmp;
return osig;
}
/*
* Elaborate the structural +/- as an AddSub object. Connect DataA and
* DataB to the parameters, and connect the output signal to the
* Result. In this context, the device is a combinational adder with
* fixed direction, so leave Add_Sub unconnected and set the
* LPM_Direction property.
*/
NetNet* PEBinary::elaborate_net_add_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
NetNet*lsig = left_->elaborate_net(des, path, lwidth, 0, 0, 0),
*rsig = right_->elaborate_net(des, path, lwidth, 0, 0, 0);
if (lsig == 0) {
cerr << get_line() << ": error: Cannot elaborate ";
left_->dump(cerr);
cerr << endl;
return 0;
}
if (rsig == 0) {
cerr << get_line() << ": error: Cannot elaborate ";
right_->dump(cerr);
cerr << endl;
return 0;
}
NetNet*osig;
NetNode*gate;
NetNode*gate_t;
string name = des->local_symbol(path);
unsigned width = lsig->pin_count();
if (rsig->pin_count() > lsig->pin_count())
width = rsig->pin_count();
// Make the adder as wide as the widest operand
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE, width);
NetAddSub*adder = new NetAddSub(name, width);
// Connect the adder to the various parts.
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
connect(lsig->pin(idx), adder->pin_DataA(idx));
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
connect(rsig->pin(idx), adder->pin_DataB(idx));
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1)
connect(osig->pin(idx), adder->pin_Result(idx));
gate = adder;
des->add_signal(osig);
gate->rise_time(rise);
gate->fall_time(fall);
gate->decay_time(decay);
des->add_node(gate);
switch (op_) {
case '+':
gate->attribute("LPM_Direction", "ADD");
break;
case '-':
gate->attribute("LPM_Direction", "SUB");
break;
}
if (NetTmp*tmp = dynamic_cast<NetTmp*>(lsig))
delete tmp;
if (NetTmp*tmp = dynamic_cast<NetTmp*>(rsig))
delete tmp;
return osig;
}
/*
* Elaborate the various binary comparison operators.
*/
NetNet* PEBinary::elaborate_net_cmp_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
NetNet*lsig = left_->elaborate_net(des, path, 0, 0, 0, 0),
*rsig = right_->elaborate_net(des, path, 0, 0, 0, 0);
if (lsig == 0) {
cerr << get_line() << ": error: Cannot elaborate ";
left_->dump(cerr);
cerr << endl;
return 0;
}
if (rsig == 0) {
cerr << get_line() << ": error: Cannot elaborate ";
right_->dump(cerr);
cerr << endl;
return 0;
}
if (lsig->pin_count() != rsig->pin_count()) {
cerr << get_line() << ": internal error: Cannot match "
"structural net widths " << lsig->pin_count() <<
" and " << rsig->pin_count() << "." << endl;
delete lsig;
delete rsig;
des->errors += 1;
return 0;
}
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
osig->local_flag(true);
NetNode*gate;
NetNode*gate_t;
switch (op_) {
case '<':
case '>':
case 'L':
case 'G': {
NetCompare*cmp = new NetCompare(des->local_symbol(path),
lsig->pin_count());
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
connect(cmp->pin_DataA(idx), lsig->pin(idx));
connect(cmp->pin_DataB(idx), rsig->pin(idx));
}
switch (op_) {
case '<':
connect(cmp->pin_ALB(), osig->pin(0));
break;
case '>':
connect(cmp->pin_AGB(), osig->pin(0));
break;
case 'L':
connect(cmp->pin_ALEB(), osig->pin(0));
break;
case 'G':
connect(cmp->pin_AGEB(), osig->pin(0));
break;
}
gate = cmp;
break;
}
case 'E': // Case equals (===)
// The comparison generates gates to bitwise compare
// each pair, and AND all the comparison results.
gate = new NetLogic(des->local_symbol(path),
1+lsig->pin_count(),
NetLogic::AND);
connect(gate->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate_t = new NetCaseCmp(des->local_symbol(path));
connect(gate_t->pin(1), lsig->pin(idx));
connect(gate_t->pin(2), rsig->pin(idx));
connect(gate_t->pin(0), gate->pin(idx+1));
des->add_node(gate_t);
// Attach a label to this intermediate wire
NetNet*tmp = new NetNet(0, des->local_symbol(path),
NetNet::WIRE);
tmp->local_flag(true);
connect(gate_t->pin(0), tmp->pin(0));
des->add_signal(tmp);
}
break;
case 'e': // ==
gate = new NetLogic(des->local_symbol(path),
1+lsig->pin_count(),
NetLogic::AND);
connect(gate->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate_t = new NetLogic(des->local_symbol(path), 3,
NetLogic::XNOR);
connect(gate_t->pin(1), lsig->pin(idx));
connect(gate_t->pin(2), rsig->pin(idx));
connect(gate_t->pin(0), gate->pin(idx+1));
des->add_node(gate_t);
}
break;
case 'n': // !=
gate = new NetLogic(des->local_symbol(path),
1+lsig->pin_count(),
NetLogic::OR);
connect(gate->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate_t = new NetLogic(des->local_symbol(path), 3,
NetLogic::XOR);
connect(gate_t->pin(1), lsig->pin(idx));
connect(gate_t->pin(2), rsig->pin(idx));
connect(gate_t->pin(0), gate->pin(idx+1));
des->add_node(gate_t);
}
break;
default:
assert(0);
}
des->add_signal(osig);
gate->rise_time(rise);
gate->fall_time(fall);
gate->decay_time(decay);
des->add_node(gate);
return osig;
}
NetNet* PEBinary::elaborate_net_shift_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
NetNet*lsig = left_->elaborate_net(des, path, lwidth, 0, 0, 0);
if (lsig == 0) return 0;
/* Handle the special case of a constant shift amount. There
is no reason in this case to create a gate at all, just
connect the lsig to the osig with the bit positions
shifted. */
if (verinum*rval = right_->eval_const(des, path)) {
assert(rval->is_defined());
unsigned dist = rval->as_ulong();
if (dist > lsig->pin_count())
dist = lsig->pin_count();
/* Very special case, constant 0 shift. */
if (dist == 0) return lsig;
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
lsig->pin_count());
osig->local_flag(true);
NetConst*zero = new NetConst(des->local_symbol(path), verinum::V0);
des->add_node(zero);
if (op_ == 'l') {
unsigned idx;
for (idx = 0 ; idx < dist ; idx += 1)
connect(osig->pin(idx), zero->pin(0));
for (idx = dist ; idx < lsig->pin_count() ; idx += 1)
connect(osig->pin(idx), lsig->pin(idx-dist));
} else {
assert(op_ == 'r');
unsigned idx;
unsigned keep = lsig->pin_count()-dist;
for (idx = 0 ; idx < keep ; idx += 1)
connect(osig->pin(idx), lsig->pin(idx+dist));
for (idx = keep ; idx < lsig->pin_count() ; idx += 1)
connect(osig->pin(idx), zero->pin(0));
}
des->add_signal(osig);
return osig;
}
unsigned dwid = 0;
while ((1 << dwid) < lsig->pin_count())
dwid += 1;
NetNet*rsig = right_->elaborate_net(des, path, dwid, 0, 0, 0);
if (rsig == 0) return 0;
NetCLShift*gate = new NetCLShift(des->local_symbol(path),
lsig->pin_count(),
rsig->pin_count());
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
lsig->pin_count());
osig->local_flag(true);
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
connect(osig->pin(idx), gate->pin_Result(idx));
connect(lsig->pin(idx), gate->pin_Data(idx));
}
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
connect(rsig->pin(idx), gate->pin_Distance(idx));
if (op_ == 'r') {
NetConst*dir = new NetConst(des->local_symbol(path), verinum::V1);
connect(dir->pin(0), gate->pin_Direction());
des->add_node(dir);
}
des->add_signal(osig);
des->add_node(gate);
return osig;
}
/*
* The concatenation operator, as a net, is a wide signal that is
* connected to all the pins of the elaborated expression nets.
*/
NetNet* PEConcat::elaborate_net(Design*des, const string&path,
unsigned,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
svector<NetNet*>nets (parms_.count());
unsigned pins = 0;
unsigned errors = 0;
if (repeat_) {
verinum*rep = repeat_->eval_const(des, path);
if (rep == 0) {
cerr << get_line() << ": internal error: Unable to "
<< "evaluate constant repeat expression." << endl;
des->errors += 1;
return 0;
}
unsigned long repeat = rep->as_ulong();
assert(parms_.count() == 1);
NetNet*obj = parms_[0]->elaborate_net(des, path, 0, rise,
fall, decay);
NetTmp*tmp = new NetTmp(des->local_symbol(path),
repeat * obj->pin_count());
for (unsigned idx = 0 ; idx < repeat ; idx += 1) {
unsigned base = obj->pin_count() * idx;
for (unsigned pin = 0 ; pin < obj->pin_count() ; pin += 1)
connect(tmp->pin(base+pin), obj->pin(pin));
}
des->add_signal(tmp);
return tmp;
}
/* Elaborate the operands of the concatenation. */
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
nets[idx] = parms_[idx]->elaborate_net(des, path, 0,
rise,fall,decay);
if (nets[idx] == 0)
errors += 1;
else
pins += nets[idx]->pin_count();
}
/* If any of the sub expressions failed to elaborate, then
delete all those that did and abort myself. */
if (errors) {
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
if (nets[idx]) delete nets[idx];
}
des->errors += 1;
return 0;
}
/* Make the temporary signal that connects to all the
operands, and connect it up. Scan the operands of the
concat operator from least significant to most significant,
which is opposite from how they are given in the list. */
NetNet*osig = new NetNet(0, des->local_symbol(path),
NetNet::IMPLICIT, pins);
pins = 0;
for (unsigned idx = nets.count() ; idx > 0 ; idx -= 1) {
NetNet*cur = nets[idx-1];
for (unsigned pin = 0 ; pin < cur->pin_count() ; pin += 1) {
connect(osig->pin(pins), cur->pin(pin));
pins += 1;
}
}
osig->local_flag(true);
des->add_signal(osig);
return osig;
}
NetNet* PEIdent::elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
NetScope*scope = des->find_scope(path);
NetNet*sig = des->find_signal(path, text_);
if (sig == 0) {
/* If the identifier is a memory instead of a signal,
then handle it elsewhere. Create a RAM. */
if (NetMemory*mem = des->find_memory(path, text_))
return elaborate_net_ram_(des, path, mem, lwidth,
rise, fall, decay);
if (const NetExpr*pe = des->find_parameter(path, text_)) {
const NetEConst*pc = dynamic_cast<const NetEConst*>(pe);
assert(pc);
verinum pvalue = pc->value();
sig = new NetNet(0, path+"."+text_, NetNet::IMPLICIT,
pc->expr_width());
for (unsigned idx = 0; idx < sig->pin_count(); idx += 1) {
NetConst*cp = new NetConst(des->local_symbol(path),
pvalue[idx]);
connect(sig->pin(idx), cp->pin(0));
des->add_node(cp);
}
} else {
sig = new NetNet(scope, path+"."+text_, NetNet::IMPLICIT, 1);
des->add_signal(sig);
cerr << get_line() << ": warning: Implicitly defining "
"wire " << path << "." << text_ << "." << endl;
}
}
assert(sig);
if (msb_ && lsb_) {
verinum*mval = msb_->eval_const(des, path);
if (mval == 0) {
cerr << msb_->get_line() << ": error: unable to "
"evaluate constant expression: " << *msb_ <<
endl;
des->errors += 1;
return 0;
}
verinum*lval = lsb_->eval_const(des, path);
if (lval == 0) {
cerr << lsb_->get_line() << ": error: unable to "
"evaluate constant expression: " << *lsb_ <<
endl;
delete mval;
des->errors += 1;
return 0;
}
assert(mval);
assert(lval);
unsigned midx = sig->sb_to_idx(mval->as_long());
unsigned lidx = sig->sb_to_idx(lval->as_long());
if (midx >= lidx) {
NetTmp*tmp = new NetTmp(des->local_symbol(path),
midx-lidx+1);
des->add_signal(tmp);
if (tmp->pin_count() > sig->pin_count()) {
cerr << get_line() << ": bit select out of "
<< "range for " << sig->name() << endl;
return sig;
}
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
connect(tmp->pin(idx-lidx), sig->pin(idx));
sig = tmp;
} else {
NetTmp*tmp = new NetTmp(des->local_symbol(path),
lidx-midx+1);
des->add_signal(tmp);
assert(tmp->pin_count() <= sig->pin_count());
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
connect(tmp->pin(idx-midx), sig->pin(idx));
sig = tmp;
}
} else if (msb_) {
verinum*mval = msb_->eval_const(des, path);
if (mval == 0) {
cerr << get_line() << ": index of " << text_ <<
" needs to be constant in this context." <<
endl;
des->errors += 1;
return 0;
}
assert(mval);
unsigned idx = sig->sb_to_idx(mval->as_long());
if (idx >= sig->pin_count()) {
cerr << get_line() << "; index " << sig->name() <<
"[" << mval->as_long() << "] out of range." << endl;
des->errors += 1;
idx = 0;
}
NetTmp*tmp = new NetTmp(des->local_symbol(path), 1);
des->add_signal(tmp);
connect(tmp->pin(0), sig->pin(idx));
sig = tmp;
}
return sig;
}
/*
* When I run into an identifier in an expression that referrs to a
* memory, create a RAM port object.
*/
NetNet* PEIdent::elaborate_net_ram_(Design*des, const string&path,
NetMemory*mem, unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
if (msb_ == 0) {
cerr << get_line() << ": error: memory reference without"
" the required index expression." << endl;
des->errors += 1;
return 0;
}
NetNet*adr = msb_->elaborate_net(des, path, 0, 0, 0, 0);
if (adr == 0)
return 0;
NetRamDq*ram = new NetRamDq(des->local_symbol(mem->name()),
mem, adr->pin_count());
des->add_node(ram);
for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1)
connect(ram->pin_Address(idx), adr->pin(idx));
NetNet*osig = new NetTmp(des->local_symbol(mem->name()), ram->width());
des->add_signal(osig);
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1)
connect(ram->pin_Q(idx), osig->pin(idx));
return osig;
}
/*
* Identifiers in continuous assignment l-values are limited to wires
* and that ilk. Detect registers and memories here and report errors.
*/
NetNet* PEIdent::elaborate_lnet(Design*des, const string&path) const
{
NetNet*sig = des->find_signal(path, text_);
if (sig == 0) {
/* Don't allow memories here. Is it a memory? */
if (des->find_memory(path, text_)) {
cerr << get_line() << ": error: memories (" << text_
<< ") cannot be l-values in continuous "
<< "assignments." << endl;
return 0;
}
/* Fine, create an implicit wire as an l-value. */
sig = new NetNet(0, path+"."+text_, NetNet::IMPLICIT, 1);
des->add_signal(sig);
cerr << get_line() << ": warning: Implicitly defining "
"wire " << path << "." << text_ << "." << endl;
}
assert(sig);
/* Don't allow registers as assign l-values. */
if (sig->type() == NetNet::REG) {
cerr << get_line() << ": error: registers (" << sig->name()
<< ") cannot be l-values in continuous"
<< " assignments." << endl;
return 0;
}
if (msb_ && lsb_) {
/* Detect a part select. Evaluate the bits and elaborate
the l-value by creating a sub-net that links to just
the right pins. */
verinum*mval = msb_->eval_const(des, path);
assert(mval);
verinum*lval = lsb_->eval_const(des, path);
assert(lval);
unsigned midx = sig->sb_to_idx(mval->as_long());
unsigned lidx = sig->sb_to_idx(lval->as_long());
if (midx >= lidx) {
NetTmp*tmp = new NetTmp(des->local_symbol(path),
midx-lidx+1);
des->add_signal(tmp);
if (tmp->pin_count() > sig->pin_count()) {
cerr << get_line() << ": bit select out of "
<< "range for " << sig->name() << endl;
return sig;
}
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
connect(tmp->pin(idx-lidx), sig->pin(idx));
sig = tmp;
} else {
NetTmp*tmp = new NetTmp(des->local_symbol(path),
lidx-midx+1);
des->add_signal(tmp);
assert(tmp->pin_count() <= sig->pin_count());
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
connect(tmp->pin(idx-midx), sig->pin(idx));
sig = tmp;
}
} else if (msb_) {
verinum*mval = msb_->eval_const(des, path);
if (mval == 0) {
cerr << get_line() << ": index of " << text_ <<
" needs to be constant in this context." <<
endl;
des->errors += 1;
return 0;
}
assert(mval);
unsigned idx = sig->sb_to_idx(mval->as_long());
if (idx >= sig->pin_count()) {
cerr << get_line() << "; index " << sig->name() <<
"[" << mval->as_long() << "] out of range." << endl;
des->errors += 1;
idx = 0;
}
NetTmp*tmp = new NetTmp(des->local_symbol(path), 1);
des->add_signal(tmp);
connect(tmp->pin(0), sig->pin(idx));
sig = tmp;
}
return sig;
}
/*
* Elaborate a number as a NetConst object.
*/
NetNet* PENumber::elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
unsigned width = value_->len();
if ((lwidth > 0) && (lwidth < width))
width = lwidth;
NetNet*net = new NetNet(0, des->local_symbol(path),
NetNet::IMPLICIT, width);
net->local_flag(true);
for (unsigned idx = 0 ; idx < width ; idx += 1) {
NetConst*tmp = new NetConst(des->local_symbol(path),
value_->get(idx));
des->add_node(tmp);
connect(net->pin(idx), tmp->pin(0));
}
des->add_signal(net);
return net;
}
/*
* Elaborate the ternary operator in a netlist by creating a LPM_MUX
* with width matching the result, size == 2 and 1 select input.
*/
NetNet* PETernary::elaborate_net(Design*des, const string&path,
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
NetNet* expr_sig = expr_->elaborate_net(des, path, 0, 0, 0, 0);
NetNet* tru_sig = tru_->elaborate_net(des, path, width, 0, 0, 0);
NetNet* fal_sig = fal_->elaborate_net(des, path, width, 0, 0, 0);
if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) {
des->errors += 1;
return 0;
}
assert(tru_sig->pin_count() == fal_sig->pin_count());
assert(width == tru_sig->pin_count());
assert(expr_sig->pin_count() == 1);
NetNet*sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
tru_sig->pin_count());
sig->local_flag(true);
NetMux*mux = new NetMux(des->local_symbol(path), width, 2, 1);
connect(mux->pin_Sel(0), expr_sig->pin(0));
for (unsigned idx = 0 ; idx < width ; idx += 1) {
connect(mux->pin_Result(idx), sig->pin(idx));
connect(mux->pin_Data(idx,0), fal_sig->pin(idx));
connect(mux->pin_Data(idx,1), tru_sig->pin(idx));
}
des->add_signal(sig);
des->add_node(mux);
return sig;
}
/*
* $Log: elab_net.cc,v $
* Revision 1.11 1999/12/02 04:08:10 steve
* Elaborate net repeat concatenations.
*
* Revision 1.10 1999/11/30 04:33:41 steve
* Put implicitly defined signals in the scope.
*
* Revision 1.9 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.8 1999/11/21 17:35:37 steve
* Memory name lookup handles scopes.
*
* Revision 1.7 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.6 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.5 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.4 1999/11/05 23:36:31 steve
* Forgot to return the mux for use after elaboration.
*
* Revision 1.3 1999/11/05 21:45:19 steve
* Fix NetConst being set to zero width, and clean
* up elaborate_set_cmp_ for NetEBinary.
*
* Revision 1.2 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
*
* Add the LPM_MUX device, and integrate it with the
* ternary synthesis from Larry. Replace the lpm_mux
* generator in t-xnf.cc to use XNF EQU devices to
* put muxs into function units.
*
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
*
* Revision 1.1 1999/10/31 20:08:24 steve
* Include subtraction in LPM_ADD_SUB device.
*
*/
+737 -758
View File
File diff suppressed because it is too large Load Diff
+162 -30
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: emit.cc,v 1.18 1999/07/17 19:50:59 steve Exp $"
#ident "$Id: emit.cc,v 1.31 1999/11/28 23:42:02 steve Exp $"
#endif
/*
@@ -45,6 +45,11 @@ void NetUDP::emit_node(ostream&o, struct target_t*tgt) const
tgt->udp(o, this);
}
void NetAddSub::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_add_sub(o, this);
}
void NetAssign::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_assign(o, this);
@@ -55,11 +60,41 @@ void NetAssignNB::emit_node(ostream&o, struct target_t*tgt) const
tgt->net_assign_nb(o, this);
}
void NetCaseCmp::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_case_cmp(o, this);
}
void NetCLShift::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_clshift(o, this);
}
void NetCompare::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_compare(o, this);
}
void NetConst::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_const(o, this);
}
void NetFF::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_ff(o, this);
}
void NetMux::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_mux(o, this);
}
void NetRamDq::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_ram_dq(o, this);
}
void NetNEvent::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_event(o, this);
@@ -70,54 +105,68 @@ void NetBUFZ::emit_node(ostream&o, struct target_t*tgt) const
tgt->bufz(o, this);
}
void NetProcTop::emit(ostream&o, struct target_t*tgt) const
bool NetProcTop::emit(ostream&o, struct target_t*tgt) const
{
tgt->process(o, this);
return tgt->process(o, this);
}
void NetProc::emit_proc(ostream&o, struct target_t*tgt) const
bool NetProc::emit_proc(ostream&o, struct target_t*tgt) const
{
cerr << "EMIT: Proc type? " << typeid(*this).name() << endl;
return false;
}
void NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_assign(o, this);
return true;
}
void NetAssignNB::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssignNB::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_assign_nb(o, this);
return true;
}
void NetAssignMem::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssignMem::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_assign_mem(o, this);
return true;
}
void NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssignMemNB::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_block(o, this);
tgt->proc_assign_mem_nb(o, this);
return true;
}
void NetCase::emit_proc(ostream&o, struct target_t*tgt) const
bool NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_block(o, this);
}
bool NetCase::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_case(o, this);
return true;
}
void NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
bool NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_condit(o, this);
return true;
}
void NetForever::emit_proc(ostream&o, struct target_t*tgt) const
bool NetForever::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_forever(o, this);
return true;
}
void NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
bool NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_delay(o, this);
return true;
}
void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
@@ -125,9 +174,10 @@ void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
if (statement_) statement_->emit_proc(o, tgt);
}
void NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
bool NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_event(o, this);
return true;
}
void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
@@ -135,24 +185,28 @@ void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
if (statement_) statement_->emit_proc(o, tgt);
}
void NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
bool NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_repeat(o, this);
return true;
}
void NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
bool NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_stask(o, this);
return true;
}
void NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
bool NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_utask(o, this);
return true;
}
void NetWhile::emit_proc(ostream&o, struct target_t*tgt) const
bool NetWhile::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_while(o, this);
return true;
}
void NetBlock::emit_recurse(ostream&o, struct target_t*tgt) const
@@ -196,10 +250,18 @@ void NetWhile::emit_proc_recurse(ostream&o, struct target_t*tgt) const
proc_->emit_proc(o, tgt);
}
void Design::emit(ostream&o, struct target_t*tgt) const
bool Design::emit(ostream&o, struct target_t*tgt) const
{
bool rc = true;
tgt->start_design(o, this);
// enumerate the scopes
{ map<string,NetScope*>::const_iterator sc;
for (sc = scopes_.begin() ; sc != scopes_.end() ; sc++) {
tgt->scope(o, (*sc).second);
}
}
// emit signals
if (signals_) {
NetNet*cur = signals_->sig_next_;
@@ -229,6 +291,14 @@ void Design::emit(ostream&o, struct target_t*tgt) const
}
// emit function definitions
{
map<string,NetFuncDef*>::const_iterator ta;
for (ta = funcs_.begin() ; ta != funcs_.end() ; ta ++) {
tgt->func_def(o, (*ta).second);
}
}
// emit task definitions
{
map<string,NetTaskDef*>::const_iterator ta;
@@ -239,9 +309,10 @@ void Design::emit(ostream&o, struct target_t*tgt) const
// emit the processes
for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_)
idx->emit(o, tgt);
rc = rc && idx->emit(o, tgt);
tgt->end_design(o, this);
return rc;
}
void NetEBinary::expr_scan(struct expr_scan_t*tgt) const
@@ -269,16 +340,27 @@ void NetEMemory::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_memory(this);
}
void NetEParam::expr_scan(struct expr_scan_t*tgt) const
{
cerr << get_line() << ":internal error: unexpected NetEParam."
<< endl;
}
void NetEScope::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_scope(this);
}
void NetEUFunc::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_ufunc(this);
}
void NetESignal::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_signal(this);
}
void NetESignal::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_esignal(o, this);
}
void NetESubSignal::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_subsignal(this);
@@ -294,20 +376,70 @@ void NetEUnary::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_unary(this);
}
void emit(ostream&o, const Design*des, const char*type)
bool emit(ostream&o, const Design*des, const char*type)
{
for (unsigned idx = 0 ; target_table[idx] ; idx += 1) {
const struct target*tgt = target_table[idx];
if (tgt->name == type) {
des->emit(o, tgt->meth);
return;
}
if (tgt->name == type)
return des->emit(o, tgt->meth);
}
}
/*
* $Log: emit.cc,v $
* Revision 1.31 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.30 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.29 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.28 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.27 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.26 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
*
* Add the LPM_MUX device, and integrate it with the
* ternary synthesis from Larry. Replace the lpm_mux
* generator in t-xnf.cc to use XNF EQU devices to
* put muxs into function units.
*
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
*
* Revision 1.25 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.24 1999/10/10 01:59:54 steve
* Structural case equals device.
*
* Revision 1.23 1999/09/22 16:57:23 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.22 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
* Revision 1.21 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.20 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.19 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.18 1999/07/17 19:50:59 steve
* netlist support for ternary operator.
*
+90 -5
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: eval.cc,v 1.5 1999/08/06 04:05:28 steve Exp $"
#ident "$Id: eval.cc,v 1.12 1999/11/30 04:48:17 steve Exp $"
#endif
# include "PExpr.h"
@@ -41,12 +41,46 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
verinum*res;
switch (op_) {
case '+': {
assert(l->is_defined());
assert(r->is_defined());
long lv = l->as_long();
long rv = r->as_long();
res = new verinum(lv+rv, l->len());
break;
}
case '-': {
assert(l->is_defined());
assert(r->is_defined());
long lv = l->as_long();
long rv = r->as_long();
res = new verinum(lv-rv, l->len());
break;
}
case '*': {
assert(l->is_defined());
assert(r->is_defined());
long lv = l->as_long();
long rv = r->as_long();
res = new verinum(lv * rv, l->len());
break;
}
case '/': {
assert(l->is_defined());
assert(r->is_defined());
long lv = l->as_long();
long rv = r->as_long();
res = new verinum(lv / rv, l->len());
break;
}
case '%': {
assert(l->is_defined());
assert(r->is_defined());
long lv = l->as_long();
long rv = r->as_long();
res = new verinum(lv % rv, l->len());
break;
}
default:
delete l;
delete r;
@@ -56,11 +90,25 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
return res;
}
/*
* Evaluate an identifier as a constant expression. This is only
* possible if the identifier is that of a parameter.
*/
verinum* PEIdent::eval_const(const Design*des, const string&path) const
{
assert(msb_ == 0);
const NetExpr*expr = des->find_parameter(path, text_);
if (expr == 0) return 0;
if (expr == 0)
return 0;
assert(msb_ == 0);
if (dynamic_cast<const NetEParam*>(expr)) {
cerr << get_line() << ": sorry: I cannot evaluate ``" <<
text_ << "'' in this context." << endl;
return 0;
}
const NetEConst*eval = dynamic_cast<const NetEConst*>(expr);
assert(eval);
return new verinum(eval->value());
@@ -71,14 +119,51 @@ verinum* PENumber::eval_const(const Design*, const string&) const
return new verinum(value());
}
verinum* PETernary::eval_const(const Design*, const string&) const
verinum* PETernary::eval_const(const Design*des, const string&path) const
{
assert(0);
verinum*test = expr_->eval_const(des, path);
if (test == 0)
return 0;
verinum::V bit = test->get(0);
delete test;
switch (bit) {
case verinum::V0:
return fal_->eval_const(des, path);
case verinum::V1:
return tru_->eval_const(des, path);
default:
return 0;
// XXXX It is possible to handle this case if both fal_
// and tru_ are constant. Someday...
}
}
/*
* $Log: eval.cc,v $
* Revision 1.12 1999/11/30 04:48:17 steve
* Handle evaluation of ternary during elaboration.
*
* Revision 1.11 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.10 1999/11/21 20:03:24 steve
* Handle multiply in constant expressions.
*
* Revision 1.9 1999/10/08 17:48:09 steve
* Support + in constant expressions.
*
* Revision 1.8 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
* Revision 1.7 1999/09/18 01:52:48 steve
* Remove spurious message.
*
* Revision 1.6 1999/09/16 04:18:15 steve
* elaborate concatenation repeats.
*
* Revision 1.5 1999/08/06 04:05:28 steve
* Handle scope of parameters.
*
+286
View File
@@ -0,0 +1,286 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: eval_tree.cc,v 1.6 1999/10/22 23:57:53 steve Exp $"
#endif
# include "netlist.h"
NetExpr* NetExpr::eval_tree()
{
return 0;
}
/*
* Some of the derived classes can be evaluated by the compiler, this
* method provides the common aid of evaluating the parameter
* expressions.
*/
void NetEBinary::eval_sub_tree_()
{
NetExpr*tmp = left_->eval_tree();
if (tmp) {
delete left_;
left_ = tmp;
}
tmp = right_->eval_tree();
if (tmp){
delete right_;
right_ = tmp;
}
}
NetEConst* NetEBAdd::eval_tree()
{
eval_sub_tree_();
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
if (lc == 0) return 0;
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
if (rc == 0) return 0;
verinum lval = lc->value();
verinum rval = rc->value();
verinum val;
switch (op_) {
case '+':
val = lval + rval;
break;
case '-':
val = lval - rval;
break;
default:
return 0;
}
return new NetEConst(val);
}
NetEConst* NetEBComp::eval_eqeq_()
{
NetEConst*l = dynamic_cast<NetEConst*>(left_);
if (l == 0) return 0;
NetEConst*r = dynamic_cast<NetEConst*>(right_);
if (r == 0) return 0;
const verinum&lv = l->value();
const verinum&rv = r->value();
if (lv.len() < rv.len())
return 0;
verinum result(verinum::V1, 1);
for (unsigned idx = 0 ; idx < lv.len(); idx += 1) {
if (lv[idx] != rv[idx])
result = verinum::V0;
}
return new NetEConst(result);
}
NetEConst* NetEBComp::eval_leeq_()
{
NetEConst*r = dynamic_cast<NetEConst*>(right_);
if (r == 0) return 0;
verinum rv = r->value();
/* Detect the case where the right side is greater that or
equal to the largest value the left side can possibly
have. */
assert(left_->expr_width() > 0);
verinum lv (verinum::V1, left_->expr_width());
if (lv <= rv) {
verinum result(verinum::V1, 1);
return new NetEConst(result);
}
return 0;
}
NetEConst* NetEBComp::eval_tree()
{
eval_sub_tree_();
switch (op_) {
case 'e':
return eval_eqeq_();
case 'L':
return eval_leeq_();
default:
return 0;
}
}
NetEConst* NetEBLogic::eval_tree()
{
eval_sub_tree_();
return 0;
}
/*
* Evaluate the shift operator if possible. For this to work, both
* operands must be constant.
*/
NetEConst* NetEBShift::eval_tree()
{
eval_sub_tree_();
NetEConst*re = dynamic_cast<NetEConst*>(right_);
if (re == 0)
return 0;
NetEConst*le = dynamic_cast<NetEConst*>(left_);
if (le == 0)
return 0;
NetEConst*res;
verinum rv = re->value();
verinum lv = le->value();
if (rv.is_defined()) {
unsigned wid = expr_width();
unsigned shift = rv.as_ulong();
verinum nv (verinum::V0, wid);
if (op() == 'r')
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1)
nv.set(idx, lv[idx+shift]);
else
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1)
nv.set(idx+shift, lv[idx]);
res = new NetEConst(nv);
} else {
verinum nv (verinum::Vx, expr_width());
res = new NetEConst(nv);
}
return res;
}
NetExpr* NetEConcat::eval_tree()
{
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
// Parameter not here? This is an error, but presumably
// already caught and we are here just to catch more.
if (parms_[idx] == 0)
continue;
// If this parameter is already a constant, all is well
// so go on.
if (dynamic_cast<NetEConst*>(parms_[idx]))
continue;
// Finally, try to evaluate the parameter expression
// that is here. If I succeed, reset the parameter to
// the evaluated value.
assert(parms_[idx]);
NetExpr*expr = parms_[idx]->eval_tree();
if (expr) {
delete parms_[idx];
parms_[idx] = expr;
}
}
unsigned gap = expr_width() / repeat_;
verinum val (verinum::Vx, repeat_ * gap);
// build up the result from least significant to most.
unsigned cur = 0;
for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) {
NetEConst*expr = dynamic_cast<NetEConst*>(parms_[idx-1]);
if (expr == 0)
return 0;
verinum tmp = expr->value();
for (unsigned bit = 0 ; bit < tmp.len() ; bit += 1, cur += 1)
for (unsigned rep = 0 ; rep < repeat_ ; rep += 1)
val.set(rep*gap+cur, tmp[bit]);
}
NetEConst*res = new NetEConst(val);
res->set_width(val.len());
return res;
}
NetExpr* NetEParam::eval_tree()
{
if (des_ == 0)
return 0;
const NetExpr*expr = des_->find_parameter(path_, name_);
assert(expr);
NetExpr*nexpr = expr->dup_expr();
assert(nexpr);
// If the parameter that I refer to is already evaluated, then
// return the constant value.
if (dynamic_cast<NetEConst*>(nexpr))
return nexpr;
// Try to evaluate the expression. If I cannot, then the
// expression is not a constant expression and I fail here.
NetExpr*res = nexpr->eval_tree();
if (res == 0) {
delete nexpr;
return 0;
}
// The result can be saved as the value of the parameter for
// future reference, and return a copy to the caller.
des_->set_parameter(path_+"."+name_, res);
return res->dup_expr();
}
/*
* $Log: eval_tree.cc,v $
* Revision 1.6 1999/10/22 23:57:53 steve
* do the <= in bits, not numbers.
*
* Revision 1.5 1999/10/10 23:29:37 steve
* Support evaluating + operator at compile time.
*
* Revision 1.4 1999/09/23 03:56:57 steve
* Support shift operators.
*
* Revision 1.3 1999/09/23 00:21:54 steve
* Move set_width methods into a single file,
* Add the NetEBLogic class for logic expressions,
* Fix error setting with of && in if statements.
*
* Revision 1.2 1999/09/21 00:13:40 steve
* Support parameters that reference other paramters.
*
* Revision 1.1 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
*/
+242
View File
@@ -0,0 +1,242 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: expr_synth.cc,v 1.6 1999/11/28 23:42:02 steve Exp $"
#endif
# include "netlist.h"
NetNet* NetExpr::synthesize(Design*des)
{
cerr << get_line() << ": internal error: cannot synthesize expression: "
<< *this << endl;
des->errors += 1;
return 0;
}
/*
* Make an LPM_ADD_SUB device from addition operators.
*/
NetNet* NetEBAdd::synthesize(Design*des)
{
assert((op()=='+') || (op()=='-'));
string path = des->local_symbol("SYNTH");
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
assert(lsig->pin_count() == rsig->pin_count());
unsigned width=lsig->pin_count();
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
string oname = des->local_symbol(path);
NetAddSub *adder = new NetAddSub(oname, width);
for (unsigned idx = 0 ; idx < width; idx += 1) {
connect(lsig->pin(idx), adder->pin_DataA(idx));
connect(rsig->pin(idx), adder->pin_DataB(idx));
connect(osig->pin(idx), adder->pin_Result(idx));
}
des->add_node(adder);
des->add_signal(osig);
switch (op()) {
case '+':
adder->attribute("LPM_Direction", "ADD");
break;
case '-':
adder->attribute("LPM_Direction", "SUB");
break;
}
return osig;
}
/*
* The bitwise logic operators are turned into discrete gates pretty
* easily. Synthesize the left and right sub-expressions to get
* signals, then just connect a single gate to each bit of the vector
* of the expression.
*/
NetNet* NetEBBits::synthesize(Design*des)
{
string path = des->local_symbol("SYNTH");
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
assert(lsig->pin_count() == rsig->pin_count());
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, lsig->pin_count());
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
string oname = des->local_symbol(path);
NetLogic*gate;
switch (op()) {
case '&':
gate = new NetLogic(oname, 3, NetLogic::AND);
break;
case '|':
gate = new NetLogic(oname, 3, NetLogic::OR);
break;
case '^':
gate = new NetLogic(oname, 3, NetLogic::XOR);
break;
case 'O':
gate = new NetLogic(oname, 3, NetLogic::NOR);
break;
case 'X':
gate = new NetLogic(oname, 3, NetLogic::XNOR);
break;
default:
assert(0);
}
connect(osig->pin(idx), gate->pin(0));
connect(lsig->pin(idx), gate->pin(1));
connect(rsig->pin(idx), gate->pin(2));
des->add_node(gate);
}
des->add_signal(osig);
return osig;
}
NetNet* NetEConst::synthesize(Design*des)
{
string path = des->local_symbol("SYNTH");
unsigned width=expr_width();
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
for (unsigned idx = 0 ; idx < width; idx += 1) {
string oname = des->local_symbol(path);
NetConst *c = new NetConst(oname, value().get(idx));
connect(osig->pin(idx), c->pin(0));
des->add_node(c);
}
des->add_signal(osig);
return osig;
}
/*
* The bitwise unary logic operator (there is only one) is turned
* into discrete gates just as easily as the binary ones above.
*/
NetNet* NetEUBits::synthesize(Design*des)
{
string path = des->local_symbol("SYNTH");
NetNet*isig = expr_->synthesize(des);
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, isig->pin_count());
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
string oname = des->local_symbol(path);
NetLogic*gate;
switch (op()) {
case '~':
gate = new NetLogic(oname, 2, NetLogic::NOT);
break;
default:
assert(0);
}
connect(osig->pin(idx), gate->pin(0));
connect(isig->pin(idx), gate->pin(1));
des->add_node(gate);
}
des->add_signal(osig);
return osig;
}
NetNet* NetETernary::synthesize(Design *des)
{
string path = des->local_symbol("SYNTH");
NetNet*csig = cond_->synthesize(des);
NetNet*tsig = true_val_->synthesize(des);
NetNet*fsig = false_val_->synthesize(des);
assert(csig->pin_count() == 1);
assert(tsig->pin_count() == fsig->pin_count());
unsigned width=tsig->pin_count();
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
string oname = des->local_symbol(path);
NetMux *mux = new NetMux(oname, width, 2, 1);
for (unsigned idx = 0 ; idx < width; idx += 1) {
connect(tsig->pin(idx), mux->pin_Data(idx, 1));
connect(fsig->pin(idx), mux->pin_Data(idx, 0));
connect(osig->pin(idx), mux->pin_Result(idx));
}
des->add_node(mux);
connect(csig->pin(0), mux->pin_Sel(0));
des->add_signal(osig);
return osig;
}
NetNet* NetESignal::synthesize(Design*des)
{
return net_;
}
/*
* $Log: expr_synth.cc,v $
* Revision 1.6 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.5 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.4 1999/11/19 03:00:59 steve
* Whoops, created a signal with a duplicate name.
*
* Revision 1.3 1999/11/05 04:40:40 steve
* Patch to synthesize LPM_ADD_SUB from expressions,
* Thanks to Larry Doolittle. Also handle constants
* in expressions.
*
* Synthesize adders in XNF, based on a patch from
* Larry. Accept synthesis of constants from Larry
* as is.
*
* Revision 1.2 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
*
* Add the LPM_MUX device, and integrate it with the
* ternary synthesis from Larry. Replace the lpm_mux
* generator in t-xnf.cc to use XNF EQU devices to
* put muxs into function units.
*
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
*
* Revision 1.1 1999/11/02 04:55:34 steve
* Add the synthesize method to NetExpr to handle
* synthesis of expressions, and use that method
* to improve r-value handling of LPM_FF synthesis.
*
* Modify the XNF target to handle LPM_FF objects.
*
*/
+79 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: functor.cc,v 1.2 1999/07/18 05:52:46 steve Exp $"
#ident "$Id: functor.cc,v 1.5 1999/12/01 06:06:16 steve Exp $"
#endif
# include "functor.h"
@@ -35,14 +35,19 @@ void functor_t::process(class Design*, class NetProcTop*)
{
}
void functor_t::lpm_ff(class Design*, class NetFF*)
{
}
void Design::functor(functor_t*fun)
{
// apply to signals
if (signals_) {
NetNet*cur = signals_->sig_next_;
do {
NetNet*tmp = cur->sig_next_;
fun->signal(this, cur);
cur = cur->sig_next_;
cur = tmp;
} while (cur != signals_->sig_next_);
}
@@ -53,10 +58,82 @@ void Design::functor(functor_t*fun)
procs_idx_ = idx->next_;
fun->process(this, idx);
}
// apply to nodes
if (nodes_) {
NetNode*cur = nodes_->node_next_;
do {
NetNode*tmp = cur->node_next_;
cur->functor_node(this, fun);
cur = tmp;
} while (cur != nodes_->node_next_);
}
}
void NetNode::functor_node(Design*, functor_t*)
{
}
void NetFF::functor_node(Design*des, functor_t*fun)
{
fun->lpm_ff(des, this);
}
proc_match_t::~proc_match_t()
{
}
int NetProc::match_proc(proc_match_t*that)
{
return 0;
}
int proc_match_t::assign(NetAssign*)
{
return 0;
}
int NetAssign::match_proc(proc_match_t*that)
{
return that->assign(this);
}
int proc_match_t::condit(NetCondit*)
{
return 0;
}
int NetCondit::match_proc(proc_match_t*that)
{
return that->condit(this);
}
int proc_match_t::pevent(NetPEvent*)
{
return 0;
}
int NetPEvent::match_proc(proc_match_t*that)
{
return that->pevent(this);
}
/*
* $Log: functor.cc,v $
* Revision 1.5 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
* Revision 1.4 1999/11/18 03:52:19 steve
* Turn NetTmp objects into normal local NetNet objects,
* and add the nodangle functor to clean up the local
* symbols generated by elaboration and other steps.
*
* Revision 1.3 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.2 1999/07/18 05:52:46 steve
* xnfsyn generates DFF objects for XNF output, and
* properly rewrites the Design netlist in the process.
+20 -1
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: functor.h,v 1.1 1999/07/17 22:01:13 steve Exp $"
#ident "$Id: functor.h,v 1.3 1999/12/01 06:06:16 steve Exp $"
#endif
/*
@@ -42,10 +42,29 @@ struct functor_t {
/* This method is called for each process in the design. */
virtual void process(class Design*des, class NetProcTop*);
/* This method is called for each FF in the design. */
virtual void lpm_ff(class Design*des, class NetFF*);
};
struct proc_match_t {
virtual ~proc_match_t();
virtual int assign(class NetAssign*);
virtual int condit(class NetCondit*);
virtual int pevent(class NetPEvent*);
};
/*
* $Log: functor.h,v $
* Revision 1.3 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
* Revision 1.2 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.1 1999/07/17 22:01:13 steve
* Add the functor interface for functor transforms.
*
+6 -5
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.5 1999/07/30 00:42:33 steve Exp $"
#ident "$Id: Makefile.in,v 1.6.2.1 1999/12/03 17:43:49 steve Exp $"
#
#
SHELL = /bin/sh
@@ -33,6 +33,7 @@ VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
libexecdir = $(libdir)/ivl
includedir = $(prefix)/include
CC = @CC@
@@ -60,13 +61,13 @@ lexor.c: lexor.lex
parse.h parse.c: parse.y
bison --verbose -t -d parse.y -o parse.c
install: all installdirs $(bindir)/ivlpp
install: all installdirs $(libexecdir)/ivlpp
$(bindir)/ivlpp: ivlpp
$(INSTALL_PROGRAM) ./ivlpp $(bindir)/ivlpp
$(libexecdir)/ivlpp: ivlpp
$(INSTALL_PROGRAM) ./ivlpp $(libexecdir)/ivlpp
installdirs: ../mkinstalldirs
$(srcdir)/../mkinstalldirs $(includedir) $(bindir)
$(srcdir)/../mkinstalldirs $(bindir)
uninstall:
rm -f $(bindir)/ivlpp
+5 -2
View File
@@ -19,12 +19,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: globals.h,v 1.1 1999/07/03 20:03:47 steve Exp $"
#ident "$Id: globals.h,v 1.2 1999/09/05 22:33:18 steve Exp $"
#endif
# include <stdio.h>
extern void reset_lexor(FILE*out, const char*ipath);
extern void reset_lexor(FILE*out, char*paths[]);
extern void define_macro(const char*name, const char*value);
/* These variables contain the include directories to be searched when
@@ -40,6 +40,9 @@ extern int yyparse();
/*
* $Log: globals.h,v $
* Revision 1.2 1999/09/05 22:33:18 steve
* Take multiple source files on the command line.
*
* Revision 1.1 1999/07/03 20:03:47 steve
* Add include path and line directives.
*
+67 -12
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: lexor.lex,v 1.11 1999/07/25 00:03:13 steve Exp $"
#ident "$Id: lexor.lex,v 1.14 1999/10/08 17:27:56 steve Exp $"
#endif
# include <stdio.h>
@@ -60,6 +60,7 @@ struct include_stack_t {
struct include_stack_t*next;
};
static struct include_stack_t*file_queue = 0;
static struct include_stack_t*istack = 0;
static struct include_stack_t*standby = 0;
@@ -114,7 +115,7 @@ W [ \t\b\f]+
that follows it. when the directive ends, the do_include function
performs the include operation. */
^`include { BEGIN(PPINCLUDE); }
^{W}?`include { BEGIN(PPINCLUDE); }
<PPINCLUDE>\"[^\"]*\" { include_filename(); }
@@ -128,7 +129,7 @@ W [ \t\b\f]+
directive and the name, go into PPDEFINE mode and prepare to
collect the defined value. */
^`define{W}[a-zA-Z][a-zA-Z0-9_]*{W}? { BEGIN(PPDEFINE); def_start(); }
`define{W}[a-zA-Z][a-zA-Z0-9_]*{W}? { BEGIN(PPDEFINE); def_start(); }
<PPDEFINE>.*\n {
do_define();
@@ -137,7 +138,7 @@ W [ \t\b\f]+
BEGIN(0);
}
^`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
/* Detect conditional compilation directives, and parse them. If I
@@ -466,15 +467,22 @@ static void do_include()
yy_switch_to_buffer(yy_new_buffer(istack->file, YY_BUF_SIZE));
if (line_direct_flag && istack->path)
fprintf(yyout, "#line \"%s\" %u\n", istack->path, istack->lineno);
fprintf(yyout, "\n#line \"%s\" %u\n",
istack->path, istack->lineno);
}
/*
* The lexical analyzer calls this function when the current file
* ends. Here I pop the include stack and resume the previous file. If
* there is no previous file, then the main input is ended.
*/
static int yywrap()
{
int line_mask_flag = 0;
struct include_stack_t*isp = istack;
istack = isp->next;
/* Delete the current input buffers, and free the cell. */
yy_delete_buffer(YY_CURRENT_BUFFER);
if (isp->file) {
fclose(isp->file);
@@ -492,13 +500,42 @@ static int yywrap()
}
free(isp);
if (istack == 0)
return 1;
/* If I am out if include stack, the main input is
done. Look for another file to process in the input
queue. If none are there, give up. Otherwise, open the file
and continue parsing. */
if (istack == 0) {
if (file_queue == 0)
return 1;
istack = file_queue;
file_queue = file_queue->next;
istack->next = 0;
istack->lineno = 0;
istack->file = fopen(istack->path, "r");
if (istack->file == 0) {
perror(istack->path);
exit(1);
}
if (line_direct_flag)
fprintf(yyout, "\n#line \"%s\" 0\n", istack->path);
yyrestart(isp->file);
return 0;
}
/* Otherwise, resume the input buffer that is the new stack
top. If I need to print a line directive, do so. */
yy_switch_to_buffer(istack->yybs);
if (line_direct_flag && istack->path && !line_mask_flag)
fprintf(yyout, "#line \"%s\" %u\n", istack->path, istack->lineno);
fprintf(yyout, "\n#line \"%s\" %u\n",
istack->path, istack->lineno);
return 0;
}
@@ -507,14 +544,16 @@ static int yywrap()
* opened, and the lexor is initialized. The include stack is cleared
* and ready to go.
*/
void reset_lexor(FILE*out, const char*path)
void reset_lexor(FILE*out, char*paths[])
{
unsigned idx;
struct include_stack_t*tail = 0;
struct include_stack_t*isp = malloc(sizeof(struct include_stack_t));
isp->path = strdup(path);
isp->file = fopen(path, "r");
isp->path = strdup(paths[0]);
isp->file = fopen(paths[0], "r");
isp->str = 0;
if (isp->file == 0) {
perror(path);
perror(paths[0]);
exit(1);
}
@@ -525,4 +564,20 @@ void reset_lexor(FILE*out, const char*path)
assert(istack == 0);
istack = isp;
isp->next = 0;
/* Now build up a queue of all the remaining file names, so
that yywrap can pull them when needed. */
file_queue = 0;
for (idx = 1 ; paths[idx] ; idx += 1) {
isp = malloc(sizeof(struct include_stack_t));
isp->path = strdup(paths[idx]);
isp->str = 0;
isp->next = 0;
if (tail)
tail->next = isp;
else
file_queue = isp;
tail = isp;
}
}
+17 -3
View File
@@ -17,7 +17,7 @@ const char COPYRIGHT[] =
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: main.c,v 1.2 1999/07/03 20:03:47 steve Exp $"
#ident "$Id: main.c,v 1.4 1999/11/29 17:02:21 steve Exp $"
#endif
const char NOTICE[] =
@@ -42,6 +42,9 @@ const char VERSION[] = "$Name: $ $State: Exp $";
# include <malloc.h>
# include <unistd.h>
# include <string.h>
#if defined(HAVE_GETOPT_H)
# include <getopt.h>
#endif
# include "globals.h"
char**include_dir = 0;
@@ -109,7 +112,7 @@ int main(int argc, char*argv[])
flag_errors += 1;
if (flag_errors) {
fprintf(stderr, "\nUsage: %s [-v][-L][-I<dir>][-D<def>] <file>\n"
fprintf(stderr, "\nUsage: %s [-v][-L][-I<dir>][-D<def>] <file>...\n"
" -D<def> - Predefine a value.\n"
" -I<dir> - Add an include file search directory\n"
" -L - Emit line number directives\n"
@@ -129,12 +132,23 @@ int main(int argc, char*argv[])
out = stdout;
}
reset_lexor(out, argv[optind]);
if (argv[optind] == 0) {
fprintf(stderr, "%s: No input files given.\n", argv[0]);
return 1;
}
reset_lexor(out, argv+optind);
return yyparse();
}
/*
* $Log: main.c,v $
* Revision 1.4 1999/11/29 17:02:21 steve
* include getopt if present.
*
* Revision 1.3 1999/09/05 22:33:18 steve
* Take multiple source files on the command line.
*
* Revision 1.2 1999/07/03 20:03:47 steve
* Add include path and line directives.
*
+78 -130
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: lexor.lex,v 1.33 1999/07/17 18:25:38 steve Exp $"
#ident "$Id: lexor.lex,v 1.38 1999/11/23 02:49:04 steve Exp $"
#endif
//# define YYSTYPE lexval
@@ -40,8 +40,9 @@ extern YYLTYPE yylloc;
static void reset_lexor();
static void line_directive();
static void line_directive2();
static int check_identifier(const char*name);
extern int check_identifier(const char*str, int len);
static verinum*make_sized_binary(const char*txt);
static verinum*make_sized_dec(const char*txt);
static verinum*make_unsized_dec(const char*txt);
@@ -66,6 +67,7 @@ W [ \t\b\f\r]+
%%
^"#line"[ ]+\"[^\"]*\"[ ]+[0-9]+.* { line_directive(); }
^"`line"[ ]+[0-9]+[ ]+\"[^\"]*\".* { line_directive2(); }
[ \t\b\f\r] { ; }
\n { yylloc.first_line += 1; }
@@ -128,7 +130,7 @@ W [ \t\b\f\r]+
<UDPTABLE>[pPnN01\?\*\-] { return yytext[0]; }
[a-zA-Z_][a-zA-Z0-9$_]* {
int rc = check_identifier(yytext);
int rc = check_identifier(yytext, yyleng);
if (rc == IDENTIFIER)
yylval.text = strdup(yytext);
else
@@ -150,11 +152,14 @@ W [ \t\b\f\r]+
yylval.text = strdup(yytext);
return SYSTEM_IDENTIFIER; }
\.[a-zA-Z_][a-zA-Z0-9$_]* {
yylval.text = strdup(yytext+1);
\.{W}?[a-zA-Z_][a-zA-Z0-9$_]* {
char*cp = yytext+1;
while (! (isalpha(*cp) || (*cp == '_')))
cp += 1;
yylval.text = strdup(cp);
return PORTNAME; }
[0-9][0-9_]*[ \t]*\'d[ \t]*[0-9][0-9_]* {
[0-9][0-9_]*[ \t]*\'[dD][ \t]*[0-9][0-9_]* {
yylval.number = make_sized_dec(yytext);
return NUMBER; }
[0-9][0-9_]*[ \t]*\'[bB][ \t]*[0-1xzXZ_\?]+ {
@@ -305,118 +310,6 @@ void lex_end_table()
BEGIN(INITIAL);
}
static const struct { const char*name; int code; } key_table[] = {
{ "always", K_always },
{ "and", K_and },
{ "assign", K_assign },
{ "begin", K_begin },
{ "buf", K_buf },
{ "bufif0", K_bufif0 },
{ "bufif1", K_bufif1 },
{ "case", K_case },
{ "casex", K_casex },
{ "casez", K_casez },
{ "cmos", K_cmos },
{ "deassign", K_deassign },
{ "default", K_default },
{ "defparam", K_defparam },
{ "disable", K_disable },
{ "edge", K_edge },
{ "else", K_else },
{ "end", K_end },
{ "endcase", K_endcase },
{ "endfunction", K_endfunction },
{ "endmodule", K_endmodule },
{ "endprimitive", K_endprimitive },
{ "endspecify", K_endspecify },
{ "endtable", K_endtable },
{ "endtask", K_endtask },
{ "event", K_event },
{ "for", K_for },
{ "force", K_force },
{ "forever", K_forever },
{ "fork", K_fork },
{ "function", K_function },
{ "highz0", K_highz0 },
{ "highz1", K_highz1 },
{ "if", K_if },
{ "initial", K_initial },
{ "inout", K_inout },
{ "input", K_input },
{ "integer", K_integer },
{ "join", K_join },
{ "large", K_large },
{ "macromodule", K_macromodule },
{ "medium", K_medium },
{ "module", K_module },
{ "nand", K_nand },
{ "negedge", K_negedge },
{ "nmos", K_nmos },
{ "nor", K_nor },
{ "not", K_not },
{ "notif0", K_notif0 },
{ "notif1", K_notif1 },
{ "or", K_or },
{ "output", K_output },
{ "parameter", K_parameter },
{ "pmos", K_pmos },
{ "posedge", K_posedge },
{ "primitive", K_primitive },
{ "pull0", K_pull0 },
{ "pull1", K_pull1 },
{ "pulldown", K_pulldown },
{ "pullup", K_pullup },
{ "rcmos", K_rcmos },
{ "reg", K_reg },
{ "release", K_release },
{ "repeat", K_repeat },
{ "rnmos", K_rnmos },
{ "rpmos", K_rpmos },
{ "rtran", K_rtran },
{ "rtranif0", K_rtranif0 },
{ "rtranif1", K_rtranif1 },
{ "scalered", K_scalered },
{ "small", K_small },
{ "specify", K_specify },
{ "specparam", K_specparam },
{ "strong0", K_strong0 },
{ "strong1", K_strong1 },
{ "supply0", K_supply0 },
{ "supply1", K_supply1 },
{ "table", K_table },
{ "task", K_task },
{ "time", K_time },
{ "tran", K_tran },
{ "tranif0", K_tranif0 },
{ "tranif1", K_tranif1 },
{ "tri", K_tri },
{ "tri0", K_tri0 },
{ "tri1", K_tri1 },
{ "triand", K_triand },
{ "trior", K_trior },
{ "trireg", K_trireg },
{ "vectored", K_vectored },
{ "wait", K_wait },
{ "wand", K_wand },
{ "weak0", K_weak0 },
{ "weak1", K_weak1 },
{ "while", K_while },
{ "wire", K_wire },
{ "wor", K_wor },
{ "xnor", K_xnor },
{ "xor", K_xor },
{ 0, IDENTIFIER }
};
static int check_identifier(const char*name)
{
for (unsigned idx = 0 ; key_table[idx].name ; idx += 1)
if (strcmp(key_table[idx].name, name) == 0)
return key_table[idx].code;
return IDENTIFIER;
}
static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
{
assert(tolower(*ptr) == 'b');
@@ -540,47 +433,77 @@ static verinum*make_sized_octal(const char*txt)
ptr += 1;
assert(tolower(*ptr) == 'o');
/* We know from the size number how bit to make the verinom
array, so make it now. */
verinum::V*bits = new verinum::V[size];
/* skip white space between size and the base token. */
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
unsigned idx = 0;
/* Find the end of the digits. ptr already points to the start. */
char*eptr = ptr + strlen(ptr);
while ((eptr > ptr) && (idx < (size-3))) {
switch (*eptr) {
/* From the last digit and forward, build up the number, least
significant bit first. This loop will not get the last few
bits if the size is not a multiple of 3. */
unsigned idx = 0;
while ((eptr > ptr) && ((idx/3) < (size/3))) switch (*--eptr) {
case 'x': case 'X':
bits[idx++] = verinum::Vx;
bits[idx++] = verinum::Vx;
bits[idx++] = verinum::Vx;
break;
case 'z': case 'Z': case '?':
bits[idx++] = verinum::Vz;
bits[idx++] = verinum::Vz;
bits[idx++] = verinum::Vz;
break;
default: {
unsigned val = *eptr - '0';
bits[idx++] = (val&1)? verinum::V1 : verinum::V0;
bits[idx++] = (val&2)? verinum::V1 : verinum::V0;
bits[idx++] = (val&4)? verinum::V1 : verinum::V0;
}
}
eptr -= 1;
}
// zero extend octal numbers
while (idx < size) switch (ptr[1]) {
if ((eptr > ptr) && (idx < size)) switch (*--eptr) {
case 'x': case 'X':
bits[idx++] = verinum::Vx;
for ( ; idx < size ; idx += 1)
bits[idx] = verinum::Vx;
break;
case 'z': case 'Z': case '?':
bits[idx++] = verinum::Vz;
for ( ; idx < size ; idx += 1)
bits[idx] = verinum::Vz;
break;
default:
bits[idx++] = verinum::V0;
default: {
unsigned val = *eptr - '0';
for ( ; idx < size ; idx += 1) {
bits[idx] = (val&1)? verinum::V1 : verinum::V0;
val >>= 1;
}
break;
}
} else {
// zero extend octal numbers
while (idx < size) switch (ptr[1]) {
case 'x': case 'X':
bits[idx++] = verinum::Vx;
break;
case 'z': case 'Z': case '?':
bits[idx++] = verinum::Vz;
break;
default:
bits[idx++] = verinum::V0;
}
}
return new verinum(bits, size, true);
@@ -857,6 +780,31 @@ static void line_directive()
yylloc.first_line = strtoul(qt2,0,0);
}
static void line_directive2()
{
assert(strncmp(yytext,"`line",5) == 0);
char*cp = yytext + strlen("`line");
cp += strspn(cp, " ");
yylloc.first_line = strtoul(cp,&cp,10);
cp += strspn(cp, " ");
if (*cp == 0) return;
char*qt1 = strchr(yytext, '"');
assert(qt1);
qt1 += 1;
char*qt2 = strchr(qt1, '"');
assert(qt2);
char*buf = new char[qt2-qt1+1];
strncpy(buf, qt1, qt2-qt1);
buf[qt2-qt1] = 0;
delete[]yylloc.text;
yylloc.text = buf;
}
static void reset_lexor()
{
yyrestart(vl_input);
+230
View File
@@ -0,0 +1,230 @@
/* C code produced by gperf version 2.7 */
/* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf > lexor_keyword.cc */
#include "parse_misc.h"
#include "parse.h"
#include <string.h>
#define TOTAL_KEYWORDS 99
#define MIN_WORD_LENGTH 2
#define MAX_WORD_LENGTH 12
#define MIN_HASH_VALUE 7
#define MAX_HASH_VALUE 239
/* maximum key range = 233, duplicates = 0 */
#ifdef __GNUC__
__inline
#endif
static unsigned int
keyword_hash (const char *str, int len)
{
static const unsigned char asso_values[] =
{
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 126, 66,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 31, 11, 81,
1, 1, 81, 26, 11, 51, 11, 21, 81, 81,
1, 46, 16, 240, 1, 1, 6, 11, 36, 46,
21, 16, 6, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240
};
int hval = len;
hval += asso_values[(unsigned char)str[len - 1]];
hval += asso_values[(unsigned char)str[0]];
hval += asso_values[(unsigned char)str[1]];
if (len > 2)
hval += asso_values[(unsigned char)str[2]];
return hval ;
}
int
check_identifier (const char *str, int len)
{
static const struct { const char *name; int tokenType; } wordlist[] =
{
{""}, {""}, {""}, {""}, {""}, {""}, {""},
{"end", K_end},
{""}, {""}, {""},
{"endcase", K_endcase},
{"endtable", K_endtable},
{"endmodule", K_endmodule},
{"rtran", K_rtran},
{"endfunction", K_endfunction},
{"endprimitive", K_endprimitive},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""},
{"endspecify", K_endspecify},
{"repeat", K_repeat},
{"endtask", K_endtask},
{""},
{"edge", K_edge},
{""}, {""},
{"negedge", K_negedge},
{"and", K_and},
{"nand", K_nand},
{""},
{"assign", K_assign},
{"specify", K_specify},
{"deassign", K_deassign},
{"tran", K_tran},
{"begin", K_begin},
{""}, {""}, {""}, {""},
{"event", K_event},
{"or", K_or},
{""},
{"nor", K_nor},
{""},
{"table", K_table},
{""}, {""},
{"reg", K_reg},
{"parameter", K_parameter},
{""}, {""},
{"disable", K_disable},
{"not", K_not},
{"task", K_task},
{"trior", K_trior},
{"triand", K_triand},
{"integer", K_integer},
{""}, {""}, {""}, {""},
{"posedge", K_posedge},
{"xor", K_xor},
{"xnor", K_xnor},
{""},
{"output", K_output},
{""}, {""},
{"primitive", K_primitive},
{"input", K_input},
{""},
{"strong1", K_strong1},
{"rtranif1", K_rtranif1},
{"wand", K_wand},
{""}, {""}, {""}, {""},
{"else", K_else},
{"rnmos", K_rnmos},
{"trireg", K_trireg},
{"release", K_release},
{""}, {""}, {""}, {""},
{"default", K_default},
{"wor", K_wor},
{""}, {""}, {""},
{"supply1", K_supply1},
{"function", K_function},
{"wire", K_wire},
{"rpmos", K_rpmos},
{""}, {""}, {""},
{"specparam", K_specparam},
{"inout", K_inout},
{""},
{"tranif1", K_tranif1},
{"tri", K_tri},
{"join", K_join},
{"while", K_while},
{""}, {""},
{"pulldown", K_pulldown},
{"case", K_case},
{"large", K_large},
{""}, {""},
{"scalered", K_scalered},
{""},
{"casez", K_casez},
{"notif1", K_notif1},
{""},
{"vectored", K_vectored},
{"tri1", K_tri1},
{""},
{"pullup", K_pullup},
{""},
{"for", K_for},
{"nmos", K_nmos},
{"force", K_force},
{"module", K_module},
{"forever", K_forever},
{""},
{"wait", K_wait},
{"casex", K_casex},
{""},
{"strong0", K_strong0},
{"rtranif0", K_rtranif0},
{"time", K_time},
{""}, {""}, {""}, {""},
{"pmos", K_pmos},
{"weak1", K_weak1},
{""}, {""}, {""},
{"fork", K_fork},
{""}, {""}, {""}, {""}, {""}, {""},
{"highz1", K_highz1},
{"supply0", K_supply0},
{""}, {""}, {""},
{"always", K_always},
{""}, {""}, {""},
{"rcmos", K_rcmos},
{"medium", K_medium},
{"tranif0", K_tranif0},
{"defparam", K_defparam},
{""}, {""},
{"bufif1", K_bufif1},
{""}, {""}, {""},
{"pull1", K_pull1},
{""}, {""}, {""}, {""}, {""},
{"notif0", K_notif0},
{""},
{"buf", K_buf},
{"tri0", K_tri0},
{""}, {""},
{"initial", K_initial},
{""}, {""}, {""}, {""}, {""}, {""}, {""},
{"small", K_small},
{""}, {""}, {""}, {""}, {""},
{"macromodule", K_macromodule},
{""}, {""}, {""},
{"weak0", K_weak0},
{""}, {""}, {""},
{"cmos", K_cmos},
{""},
{"if", K_if},
{""}, {""}, {""}, {""},
{"highz0", K_highz0},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""},
{"bufif0", K_bufif0},
{""}, {""}, {""},
{"pull0", K_pull0}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
int key = keyword_hash (str, len);
if (key <= MAX_HASH_VALUE && key >= 0)
{
const char *s = wordlist[key].name;
if (*str == *s && !strcmp (str + 1, s + 1))
return wordlist[key].tokenType;
}
}
return IDENTIFIER;
}
+112
View File
@@ -0,0 +1,112 @@
%{
/* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf */
#include "parse_misc.h"
#include "parse.h"
#include <string.h>
%}
struct Keywords {
char *name;
int tokenType;
} Keywords;
%%
always, K_always
and, K_and
assign, K_assign
begin, K_begin
buf, K_buf
bufif0, K_bufif0
bufif1, K_bufif1
case, K_case
casex, K_casex
casez, K_casez
cmos, K_cmos
deassign, K_deassign
default, K_default
defparam, K_defparam
disable, K_disable
edge, K_edge
else, K_else
end, K_end
endcase, K_endcase
endfunction, K_endfunction
endmodule, K_endmodule
endprimitive, K_endprimitive
endspecify, K_endspecify
endtable, K_endtable
endtask, K_endtask
event, K_event
for, K_for
force, K_force
forever, K_forever
fork, K_fork
function, K_function
highz0, K_highz0
highz1, K_highz1
if, K_if
initial, K_initial
inout, K_inout
input, K_input
integer, K_integer
join, K_join
large, K_large
macromodule, K_macromodule
medium, K_medium
module, K_module
nand, K_nand
negedge, K_negedge
nmos, K_nmos
nor, K_nor
not, K_not
notif0, K_notif0
notif1, K_notif1
or, K_or
output, K_output
parameter, K_parameter
pmos, K_pmos
posedge, K_posedge
primitive, K_primitive
pull0, K_pull0
pull1, K_pull1
pulldown, K_pulldown
pullup, K_pullup
rcmos, K_rcmos
reg, K_reg
release, K_release
repeat, K_repeat
rnmos, K_rnmos
rpmos, K_rpmos
rtran, K_rtran
rtranif0, K_rtranif0
rtranif1, K_rtranif1
scalered, K_scalered
small, K_small
specify, K_specify
specparam, K_specparam
strong0, K_strong0
strong1, K_strong1
supply0, K_supply0
supply1, K_supply1
table, K_table
task, K_task
time, K_time
tran, K_tran
tranif0, K_tranif0
tranif1, K_tranif1
tri, K_tri
tri0, K_tri0
tri1, K_tri1
triand, K_triand
trior, K_trior
trireg, K_trireg
vectored, K_vectored
wait, K_wait
wand, K_wand
weak0, K_weak0
weak1, K_weak1
while, K_while
wire, K_wire
wor, K_wor
xnor, K_xnor
xor, K_xor
+26
View File
@@ -0,0 +1,26 @@
WHAT IS LPM
LPM (Library of Paramaterized Modules) is EIS-IS standard 103-A. It is
a standard library of abstract devices that are designed to be close
enough to the target hardware to be easily translated, yet abstract
enough to support a variety of target technologies without excessive
constraints. Icarus Verilog uses LPM internally to represent idealized
hardware, especially when doing target neutral synthesis.
In general, the user does not even see the LPM that Icarus Verilog
generates, because the LPM devices are translated into technology
specific devices by the final code generator or target specific
optimizers.
INTERNAL USES OF LPM
Internally, Icarus Verilog uses LPM devices to represent the design in
abstract, especially when synthesizing such functions as addition,
flip-flops, etc. The ``synth'' functor generates LPM modules when
interpreting procedural constructs. The functor generates the LPM
objects needed to replace a behavioral description, and uses
attributes to tag the devices with LPM properties.
Code generators need to understand the supported LPM devices so that
they can translate the devices into technology specific devices.
+33 -5
View File
@@ -19,7 +19,7 @@ const char COPYRIGHT[] =
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: main.cc,v 1.22 1999/08/03 04:14:49 steve Exp $"
#ident "$Id: main.cc,v 1.26 1999/11/29 17:02:21 steve Exp $"
#endif
const char NOTICE[] =
@@ -44,6 +44,9 @@ const char NOTICE[] =
# include <queue>
# include <map>
# include <unistd.h>
#if defined(HAVE_GETOPT_H)
# include <getopt.h>
#endif
# include "pform.h"
# include "netlist.h"
# include "target.h"
@@ -75,12 +78,13 @@ static void parm_to_flagmap(const string&flag)
extern Design* elaborate(const map<string,Module*>&modules,
const map<string,PUdp*>&primitives,
const string&root);
extern void emit(ostream&o, const Design*, const char*);
extern void cprop(Design*des);
extern void propinit(Design*des);
extern void sigfold(Design*des);
extern void synth(Design*des);
extern void nobufz(Design*des);
extern void nodangle(Design*des);
extern void xnfio(Design*des);
extern void xnfsyn(Design*des);
@@ -91,8 +95,10 @@ static struct net_func_map {
} func_table[] = {
{ "cprop", &cprop },
{ "nobufz", &nobufz },
{ "propinit", &propinit },
{ "nodangle",&nodangle },
{ "propinit",&propinit },
{ "sigfold", &sigfold },
{ "synth", &synth },
{ "xnfio", &xnfio },
{ "xnfsyn", &xnfsyn },
{ 0, 0 }
@@ -252,6 +258,7 @@ int main(int argc, char*argv[])
}
bool emit_rc;
if (out_path) {
ofstream out;
out.open(out_path);
@@ -261,10 +268,15 @@ int main(int argc, char*argv[])
return 1;
}
emit(out, des, target);
emit_rc = emit(out, des, target);
} else {
emit(cout, des, target);
emit_rc = emit(cout, des, target);
}
if (!emit_rc) {
cerr << "internal error: Code generation had errors." << endl;
return 1;
}
return 0;
@@ -272,6 +284,22 @@ int main(int argc, char*argv[])
/*
* $Log: main.cc,v $
* Revision 1.26 1999/11/29 17:02:21 steve
* include getopt if present.
*
* Revision 1.25 1999/11/18 03:52:19 steve
* Turn NetTmp objects into normal local NetNet objects,
* and add the nodangle functor to clean up the local
* symbols generated by elaboration and other steps.
*
* Revision 1.24 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.23 1999/09/22 16:57:23 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.22 1999/08/03 04:14:49 steve
* Parse into pform arbitrarily complex module
* port declarations.
+1566 -398
View File
File diff suppressed because it is too large Load Diff
+911 -138
View File
File diff suppressed because it is too large Load Diff
+79 -11
View File
@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ident "$Id: netlist.txt,v 1.3 1999/07/24 02:11:20 steve Exp $"
#ident "$Id: netlist.txt,v 1.7 1999/11/28 23:42:02 steve Exp $"
Note that the netlist.h header contains detailed descriptions of how
@@ -53,14 +53,39 @@ in the vector.
Node and net pins can be connected together via the connect
function. Connections are transitive (A==B and B==c means A==C) so
connections accumulate on a link as items are connected to it. The
descructors for nets and nodes automatically arrange for pins to be
destructors for nets and nodes automatically arrange for pins to be
disconnected when the item is deleted, so that the netlist can be
changed during processing.
STRUCTURAL LINKS
The NetNode and NetNet classes contain arrays of Link objects, one
object per pin. Each pin is a single bit. The Link objects link
circularly to all the NetNode and NetNet objects' links that are
connected together in the design. This way, code that examines a node
of the design can discover what is connected to each pin.
See the NetObj::Link class definition for a description of the link
methods.
Currently, a link has 3 possible direction properties:
PASSIVE -- These pins are sampled by the object that holds the
pin based on some external event. These are used,
for example, by NetESignal objects that read a
point for a procedural expression.
INPUT -- These pins potentially react to the setting of its
input.
OUTPUT -- These pins potentially drive the node. (They may be
three-state.)
BEHAVIORAL ITEMS: NetProcTop, NetProc and derived classes
Behavioral items are not in general linked to the netlist. Instead,
they represent elabrated behavioral statements. The type of the object
they represent elaborated behavioral statements. The type of the object
implies what the behavior of the statement does. For example, a
NetCondit object represents an ``if'' statement, and carries a
condition expression and up to two alternative sub-statements.
@@ -89,6 +114,35 @@ and a NetProc. The NetAssign_ node has pins that represent the l-value
of the statement, and carries behavioral expressions that represent
the r-value of the assignment.
MEMORIES
The netlist form includes the NetMemory type to hold the content of a
memory. Instances of this type represent the declaration of a memory,
and occur once for each memory. References to the memory are managed
by the NetEMemory and NetAssignMem_ classes.
An instance of the NetEMemory class is created whenever a procedural
expression references a memory element. The operand is the index to
use to address (and read) the memory.
An instance of the NetAssignMem_ class is created when there is a
procedural assignment to the memory. The NetAssignMem_ object
represents the l-value reference (a write) to the memory. As with the
NetEMemory class, this is a procedural reference only.
When a memory reference appears in structural context (i.e. continuous
assignments) elaboration creates a NetRamDq. This is a LPM_RAM_DQ
device. Elaboration leaves the write control and data input pins
unconnected for now, because memories cannot appear is l-values of
continuous assignments. However, the synthesis functor may connect
signals to the write control lines to get a fully operational RAM.
By the time elaboration completes, there may be many NetAssignMem_,
NetEMemory and NetRamDq objects referencing the same NetMemory
object. Each represents a port into the memory. It is up to the
synthesis steps (and the target code) to figure out what to do with
these ports.
EXPRESSIONS
Expressions are represented as a tree of NetExpr nodes. The NetExpr
@@ -105,7 +159,7 @@ structurally as events are like devices that trigger behavioral
statements.
However, typical expressions the behavioral description are
represented as a tree of NetExpr nodes. The derived clas of the node
represented as a tree of NetExpr nodes. The derived class of the node
encodes what kind of operator the node represents.
EXPRESSION BIT WIDTH
@@ -150,17 +204,14 @@ INTERACTION OF EXPRESSIONS AND STRUCTURE: NetESignal
The NetAssign_ class described above is the means for processes to
manipulate the net, but values are read from the net by NetESignal
objects. These objects are class NetExpr because they can appear in
expressions (and have width) but are also class NetNode because they
connect to and receive signals from the structural aspects of the
design.
expressions (and have width). They are not NetNode object, but hold
pointers to a NetNet object, which is used to retrieve values with the
expression is evaluated.
The pins of a NetESignal object are passive. The values at the pin are
only sampled when the process evaluates the expression that includes
the NetESignal object.
HIERARCHY IN NETLISTS
The obvious hierarchical structure of verilog is the module. The
The obvious hierarchical structure of Verilog is the module. The
Verilog program may contain any number of instantiations of modules in
order to form an hierarchical design. However, the elaboration of the
design into a netlist erases module boundaries. Modules are expanded
@@ -189,6 +240,23 @@ some task calls. C++ programmers recognize this as inlining a task.)
$Log: netlist.txt,v $
Revision 1.7 1999/11/28 23:42:02 steve
NetESignal object no longer need to be NetNode
objects. Let them keep a pointer to NetNet objects.
Revision 1.6 1999/11/21 00:13:09 steve
Support memories in continuous assignments.
Revision 1.5 1999/11/02 04:55:34 steve
Add the synthesize method to NetExpr to handle
synthesis of expressions, and use that method
to improve r-value handling of LPM_FF synthesis.
Modify the XNF target to handle LPM_FF objects.
Revision 1.4 1999/09/29 00:03:27 steve
Spelling fixes from Larry.
Revision 1.3 1999/07/24 02:11:20 steve
Elaborate task input ports.
+42
View File
@@ -0,0 +1,42 @@
#ifndef __netmisc_H
#define __netmisc_H
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: netmisc.h,v 1.1 1999/09/29 00:42:51 steve Exp $"
#endif
# include "netlist.h"
/*
* This funciton transforms an expression by padding the high bits
* with V0 until the expression has the desired width. This may mean
* not transforming the expression at all, if it is already wide
* enough.
*/
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid);
/*
* $Log: netmisc.h,v $
* Revision 1.1 1999/09/29 00:42:51 steve
* Allow expanding of additive operators.
*
*/
#endif
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 1999Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: nodangle.cc,v 1.2 1999/11/28 23:42:02 steve Exp $"
#endif
/*
* This functor scans the design looking for dangling objects and
* excess local signals. These deletions are not necessarily required
* for proper functioning of anything, but they can clean up the
* appearance of design files that are generated.
*/
# include "functor.h"
# include "netlist.h"
class nodangle_f : public functor_t {
public:
void signal(Design*des, NetNet*sig);
};
void nodangle_f::signal(Design*des, NetNet*sig)
{
if (! sig->local_flag())
return;
if (sig->get_eref() > 0)
return;
/* Check to see if there is some significant signal connected
to every pin of this signal. */
unsigned significant_flags = 0;
for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) {
NetObj::Link&lnk = sig->pin(idx);
for (NetObj::Link*cur = lnk.next_link()
; cur != &lnk ; cur = cur->next_link()) {
NetNet*cursig = dynamic_cast<NetNet*>(cur->get_obj());
if (cursig == 0)
continue;
if (cursig->local_flag())
continue;
significant_flags += 1;
break;
}
}
/* If every pin is connected to another significant signal,
then I can delete this one. */
if (significant_flags == sig->pin_count())
delete sig;
}
void nodangle(Design*des)
{
nodangle_f fun;
des->functor(&fun);
}
/*
* $Log: nodangle.cc,v $
* Revision 1.2 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.1 1999/11/18 03:52:20 steve
* Turn NetTmp objects into normal local NetNet objects,
* and add the nodangle functor to clean up the local
* symbols generated by elaboration and other steps.
*
*/
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pad_to_width.cc,v 1.1 1999/09/29 00:42:51 steve Exp $"
#endif
# include "netlist.h"
# include "netmisc.h"
/*
* This funciton transforms an expression by padding the high bits
* with V0 until the expression has the desired width. This may mean
* not transforming the expression at all, if it is already wide
* enough.
*/
NetExpr*pad_to_width(NetExpr*expr, unsigned wid)
{
if (wid > expr->expr_width()) {
verinum pad(verinum::V0, wid - expr->expr_width());
NetEConst*co = new NetEConst(pad);
NetEConcat*cc = new NetEConcat(2);
cc->set(0, co);
cc->set(1, expr);
cc->set_width(wid);
expr = cc;
}
return expr;
}
/*
* $Log: pad_to_width.cc,v $
* Revision 1.1 1999/09/29 00:42:51 steve
* Allow expanding of additive operators.
*
*/
+240 -118
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: parse.y,v 1.58 1999/08/03 04:48:51 steve Exp $"
#ident "$Id: parse.y,v 1.76 1999/11/15 04:43:52 steve Exp $"
#endif
# include "parse_misc.h"
@@ -109,7 +109,7 @@ extern void lex_end_table();
%type <text> net_decl_assign
%type <strings> net_decl_assigns
%type <mport> port port_reference port_reference_list
%type <mport> port port_opt port_reference port_reference_list
%type <mports> list_of_ports list_of_ports_opt
%type <wires> task_item task_item_list task_item_list_opt
@@ -129,6 +129,7 @@ extern void lex_end_table();
%type <expr> delay_value
%type <exprs> delay delay_opt delay_value_list
%type <exprs> expression_list
%type <exprs> assign assign_list
%type <exprs> range range_opt
%type <nettype> net_type
@@ -137,17 +138,19 @@ extern void lex_end_table();
%type <task> task_body
%type <function> func_body
%type <exprs> range_or_type_opt
%type <event_expr> event_expression_list
%type <event_expr> event_expression
%type <event_statement> event_control
%type <statement> statement statement_opt
%type <statement_list> statement_list
%left '?' ':'
%right '?' ':'
%left K_LOR
%left K_LAND
%left '|'
%left '^'
%left '&'
%left '^' K_NXOR K_NOR
%left '&' K_NAND
%left K_EQ K_NE K_CEQ K_CNE
%left K_GE K_LE '<' '>'
%left K_LS K_RS
@@ -155,16 +158,37 @@ extern void lex_end_table();
%left '*' '/' '%'
%left UNARY_PREC
/* to resolve dangling else ambiguity: */
%nonassoc less_than_K_else
%nonassoc K_else
%%
/* A degenerate source file can be completely empty. */
main : source_file | ;
source_file
: description
| source_file description
;
/* The block_item_decl is used in function definitions, task
definitions, module definitions and named blocks. Wherever a new
scope is entered, the source may declare new registers and
integers. This rule matches those declarations. The containing
rule has presumably set up the scope. */
block_item_decl
: K_reg range_opt register_variable_list ';'
: K_reg range register_variable_list ';'
{ pform_set_net_range($3, $2);
delete $2;
delete $3;
}
| K_reg register_variable_list ';'
{ delete $2; }
| K_integer list_of_variables ';'
{ pform_set_reg_integer($2);
delete $2;
}
;
block_item_decls
@@ -196,7 +220,7 @@ case_item
$$ = tmp;
}
| error ':' statement_opt
{ yyerror(@1, "Incomprehensible case expression.");
{ yyerror(@1, "error: Incomprehensible case expression.");
yyerrok;
}
;
@@ -230,11 +254,12 @@ defparam_assign
: identifier '=' expression
{ PExpr*tmp = $3;
if (!pform_expression_is_constant(tmp)) {
yyerror(@3, "parameter value must be constant.");
yyerror(@3, "error: parameter value "
"must be constant.");
delete tmp;
tmp = 0;
}
yyerror(@1, "Sorry, defparam assignments not supported.");
yyerror(@1, "sorry: defparam assignments not supported.");
delete $1;
delete $3;
}
@@ -243,8 +268,8 @@ defparam_assign
defparam_assign_list
: defparam_assign
| range defparam_assign
{ yyerror(@1, "Ranges in parameter definition "
"are not supported.");
{ yywarn(@1, "Ranges in parameter definition "
"are not supported.");
delete $1;
}
| defparam_assign_list ',' defparam_assign
@@ -270,7 +295,7 @@ delay_value
: NUMBER
{ verinum*tmp = $1;
if (tmp == 0) {
yyerror(@1, "XXXX internal error: delay.");
yyerror(@1, "internal error: delay.");
$$ = 0;
} else {
$$ = new PENumber(tmp);
@@ -311,12 +336,29 @@ description
}
;
drive_strength
: '(' dr_strength0 ',' dr_strength1 ')'
| '(' dr_strength1 ',' dr_strength0 ')'
| '(' dr_strength0 ',' K_highz1 ')'
| '(' dr_strength1 ',' K_highz0 ')'
| '(' K_highz1 ',' dr_strength0 ')'
| '(' K_highz0 ',' dr_strength1 ')'
;
drive_strength_opt
: drive_strength
|
;
dr_strength0 : K_supply0 | K_strong0 | K_pull0 | K_weak0 ;
dr_strength1 : K_supply1 | K_strong1 | K_pull1 | K_weak1 ;
event_control
: '@' IDENTIFIER
{ yyerror(@1, "Sorry, event control not supported.");
{ yyerror(@1, "sorry: event control not supported.");
$$ = 0;
}
| '@' '(' event_expression ')'
| '@' '(' event_expression_list ')'
{ PEventStatement*tmp = new PEventStatement(*$3);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
@@ -324,11 +366,22 @@ event_control
$$ = tmp;
}
| '@' '(' error ')'
{ yyerror(@1, "Malformed event control expression.");
{ yyerror(@1, "error: Malformed event control expression.");
$$ = 0;
}
;
event_expression_list
: event_expression
{ $$ = $1; }
| event_expression_list K_or event_expression
{ svector<PEEvent*>*tmp = new svector<PEEvent*>(*$1, *$3);
delete $1;
delete $3;
$$ = tmp;
}
;
event_expression
: K_posedge expression
{ PEEvent*tmp = new PEEvent(NetNEvent::POSEDGE, $2);
@@ -354,12 +407,6 @@ event_expression
(*tl)[0] = tmp;
$$ = tl;
}
| event_expression K_or event_expression
{ svector<PEEvent*>*tmp = new svector<PEEvent*>(*$1, *$3);
delete $1;
delete $3;
$$ = tmp;
}
;
expression
@@ -469,6 +516,18 @@ expression
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_NOR expression
{ PEBinary*tmp = new PEBinary('O', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_NXOR expression
{ PEBinary*tmp = new PEBinary('X', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression '<' expression
{ PEBinary*tmp = new PEBinary('<', $1, $3);
tmp->set_file(@2.text);
@@ -579,7 +638,7 @@ expr_primary
$$ = tmp;
}
| REALTIME
{ yyerror(@1, "Sorry, real constants not supported.");
{ yyerror(@1, "sorry: real constants not supported.");
delete $1;
$$ = 0;
}
@@ -628,13 +687,15 @@ expr_primary
$$ = tmp;
}
| SYSTEM_IDENTIFIER '(' expression_list ')'
{ yyerror(@2, "Sorry, function calls not supported.");
$$ = 0;
{ PECallFunction*tmp = new PECallFunction($1, *$3);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| '(' expression ')'
{ $$ = $2; }
| '(' expression ':' expression ':' expression ')'
{ yyerror(@2, "Sorry, (min:typ:max) not supported.");
{ yyerror(@2, "sorry: (min:typ:max) not supported.");
$$ = $4;
delete $2;
delete $6;
@@ -649,7 +710,8 @@ expr_primary
| '{' expression '{' expression_list '}' '}'
{ PExpr*rep = $2;
if (!pform_expression_is_constant($2)) {
yyerror(@2, "Repeat expression must be constant.");
yyerror(@2, "error: Repeat expression "
"must be constant.");
delete rep;
delete $2;
rep = 0;
@@ -667,31 +729,45 @@ func_body
: function_item_list statement
{ $$ = new PFunction($1, $2); }
| function_item_list
{ yyerror(@1, "function body has no statement."); }
{ yyerror(@1, "error: function body has no statement.");
$$ = new PFunction($1, 0);
}
;
/* A function_item is either a block item (i.e. a reg or integer
declaration) or an input declaration. There are no output or
inout ports. */
function_item
: K_input range_opt list_of_variables ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT, $2, $3);
= pform_make_task_ports(NetNet::PINPUT, $2, $3,
@1.text, @1.first_line);
delete $2;
delete $3;
$$ = tmp;
}
| K_reg range_opt list_of_variables ';'
{ $$ = 0; }
| K_integer list_of_variables ';'
| block_item_decl
{ $$ = 0; }
;
/* A function_item_list only lists the input/output/inout
declarations. The integer and reg declarations are handled in
place, so are not listed. The list builder needs to account for
the possibility that the various parts may be NULL. */
function_item_list
: function_item
{ $$ = $1; }
| function_item_list function_item
{ svector<PWire*>*tmp = new svector<PWire*>(*$1, *$2);
delete $1;
delete $2;
$$ = tmp;
{ if ($1 && $2) {
svector<PWire*>*tmp = new svector<PWire*>(*$1, *$2);
delete $1;
delete $2;
$$ = tmp;
} else if ($1) {
$$ = $1;
} else {
$$ = $2;
}
}
;
@@ -798,19 +874,18 @@ identifier
: IDENTIFIER
{ $$ = $1; }
| HIDENTIFIER
{ yyerror(@1, "Sorry, qualified identifiers not supported.");
$$ = $1;
{ $$ = $1;
}
;
list_of_ports
: port
: port_opt
{ svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(1);
(*tmp)[0] = $1;
$$ = tmp;
}
| list_of_ports ',' port
| list_of_ports ',' port_opt
{ svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(*$1, $3);
delete $1;
@@ -820,7 +895,6 @@ list_of_ports
list_of_ports_opt
: '(' list_of_ports ')' { $$ = $2; }
| '(' ')' { $$ = 0; }
| { $$ = 0; }
;
@@ -854,7 +928,7 @@ lavalue
{ PEIdent*tmp = new PEIdent($1);
PExpr*sel = $3;
if (! pform_expression_is_constant(sel)) {
yyerror(@2, "Bit select in lvalue must "
yyerror(@2, "eror: Bit select in lvalue must "
"contain a constant expression.");
delete sel;
} else {
@@ -922,6 +996,26 @@ lpvalue
}
;
assign
: lavalue '=' expression
{ svector<PExpr*>*tmp = new svector<PExpr*>(2);
(*tmp)[0] = $1;
(*tmp)[1] = $3;
$$ = tmp;
}
;
assign_list
: assign_list ',' assign
{ svector<PExpr*>*tmp = new svector<PExpr*>(*$1, *$3);
delete $1;
delete $3;
$$ = tmp;
}
| assign
{ $$ = $1; }
;
module
: K_module IDENTIFIER list_of_ports_opt ';'
{ pform_startmodule($2, $3);
@@ -958,7 +1052,7 @@ module_item
delete $3;
}
| K_trireg charge_strength_opt range_opt delay_opt list_of_variables ';'
{ yyerror(@1, "Sorry, trireg nets not supported.");
{ yyerror(@1, "sorry: trireg nets not supported.");
delete $3;
}
| port_type range_opt list_of_variables ';'
@@ -969,20 +1063,10 @@ module_item
}
delete $3;
}
| K_reg range register_variable_list ';'
{ pform_set_net_range($3, $2);
delete $2;
delete $3;
}
| K_reg register_variable_list ';'
{ delete $2; }
| K_integer register_variable_list ';'
{ pform_set_reg_integer($2);
delete $2;
}
| block_item_decl
| K_defparam defparam_assign_list ';'
| K_event list_of_variables ';'
{ yyerror(@1, "Sorry, named events not supported.");
{ yyerror(@1, "sorry: named events not supported.");
delete $2;
}
| K_parameter parameter_assign_list ';'
@@ -990,18 +1074,11 @@ module_item
{ pform_makegates($1, $2, $3);
}
| IDENTIFIER delay_opt gate_instance_list ';'
{ pform_make_modgates($1, $3);
{ pform_make_modgates($1, $2, $3);
delete $1;
if ($2) {
yyerror(@2, "Sorry, parameter override not supported.");
delete $2;
}
}
| K_assign delay_opt lavalue '=' expression ';'
{ PGAssign*tmp = pform_make_pgassign($3, $5, $2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
}
| K_assign drive_strength_opt delay_opt assign_list ';'
{ pform_make_pgassign_list($4, $3, @1.text, @1.first_line); }
| K_assign error '=' expression ';'
| K_always statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $2);
@@ -1032,7 +1109,7 @@ module_item
{ PFunction *tmp = $6;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
pform_set_function($3, $6);
pform_set_function($3, $2, $6);
delete $3;
}
| K_specify specify_item_list K_endspecify
@@ -1045,7 +1122,7 @@ module_item
delete $7;
}
| KK_attribute '(' error ')' ';'
{ yyerror(@1, "Misformed $attribute parameter list."); }
{ yyerror(@1, "error: Misformed $attribute parameter list."); }
;
module_item_list
@@ -1105,7 +1182,8 @@ parameter_assign
: IDENTIFIER '=' expression
{ PExpr*tmp = $3;
if (!pform_expression_is_constant(tmp)) {
yyerror(@3, "parameter value must be constant.");
yyerror(@3, "error: parameter value "
"must be constant.");
delete tmp;
tmp = 0;
}
@@ -1117,7 +1195,7 @@ parameter_assign
parameter_assign_list
: parameter_assign
| range parameter_assign
{ yyerror(@1, "Ranges in parameter definition "
{ yywarn(@1, "Ranges in parameter definition "
"are not supported.");
delete $1;
}
@@ -1159,6 +1237,11 @@ port
}
;
port_opt
: port { $$ = $1; }
| { $$ = 0; }
;
port_reference
: IDENTIFIER
{ Module::port_t*ptmp = new Module::port_t(1);
@@ -1177,11 +1260,11 @@ port_reference
wtmp->set_file(@1.text);
wtmp->set_lineno(@1.first_line);
if (!pform_expression_is_constant($3)) {
yyerror(@3, "msb expression of port bit select "
yyerror(@3, "error: msb expression of port bit select "
"must be constant.");
}
if (!pform_expression_is_constant($5)) {
yyerror(@5, "lsb expression of port bit select "
yyerror(@5, "error: lsb expression of port bit select "
"must be constant.");
}
wtmp->set_range($3, $5);
@@ -1192,7 +1275,7 @@ port_reference
$$ = ptmp;
}
| IDENTIFIER '[' error ']'
{ yyerror(@1, "invalid port bit select");
{ yyerror(@1, "error: invalid port bit select");
Module::port_t*ptmp = new Module::port_t(1);
PWire*wtmp = new PWire($1, NetNet::IMPLICIT,
NetNet::PIMPLICIT);
@@ -1229,7 +1312,7 @@ port_name
$$ = tmp;
}
| PORTNAME '(' error ')'
{ yyerror(@3, "invalid port connection expression.");
{ yyerror(@3, "error: invalid port connection expression.");
portname_t*tmp = new portname_t;
tmp->name = $1;
tmp->parm = 0;
@@ -1269,12 +1352,12 @@ range
: '[' expression ':' expression ']'
{ svector<PExpr*>*tmp = new svector<PExpr*> (2);
if (!pform_expression_is_constant($2))
yyerror(@2, "msb of range must be constant.");
yyerror(@2, "error: msb of range must be constant.");
(*tmp)[0] = $2;
if (!pform_expression_is_constant($4))
yyerror(@4, "msb of range must be constant.");
yyerror(@4, "error: msb of range must be constant.");
(*tmp)[1] = $4;
@@ -1288,12 +1371,12 @@ range_opt
;
range_or_type_opt
: range { }
| K_integer
| K_real
| K_realtime
| K_time
|
: range { $$ = $1; }
| K_integer { $$ = 0; }
| K_real { $$ = 0; }
| K_realtime { $$ = 0; }
| K_time { $$ = 0; }
| { $$ = 0; }
;
/* The register_variable rule is matched only when I am parsing
variables in a "reg" definition. I therefore know that I am
@@ -1307,16 +1390,16 @@ register_variable
}
| IDENTIFIER '=' expression
{ pform_makewire(@1, $1, NetNet::REG);
yyerror(@2, "net declaration assignment to reg/integer not allowed.");
yyerror(@2, "error: net declaration assignment to reg/integer not allowed.");
delete $3;
$$ = $1;
}
| IDENTIFIER '[' expression ':' expression ']'
{ pform_makewire(@1, $1, NetNet::REG);
if (! pform_expression_is_constant($3))
yyerror(@3, "msb of register range must be constant.");
yyerror(@3, "error: msb of register range must be constant.");
if (! pform_expression_is_constant($5))
yyerror(@3, "lsb of register range must be constant.");
yyerror(@3, "error: lsb of register range must be constant.");
pform_set_reg_idx($1, $3, $5);
$$ = $1;
}
@@ -1340,8 +1423,7 @@ register_variable_list
specify_item
: K_specparam specparam_list ';'
| specify_simple_path '=' '(' expression_list ')' ';'
{ /* yyerror(@1, "Sorry, specify path declarations not supported."); */
delete $4;
{ delete $4;
}
;
@@ -1357,8 +1439,7 @@ specify_simple_path
specparam
: IDENTIFIER '=' expression
{ /* yyerror(@1, "Sorry, specparam assignments not supported."); */
delete $1;
{ delete $1;
delete $3;
}
;
@@ -1372,7 +1453,7 @@ spec_polarity: '+' | '-' | ;
statement
: K_assign lavalue '=' expression ';'
{ yyerror(@1, "Sorry, procedural continuous assign not supported.");
{ yyerror(@1, "sorry: procedural continuous assign not supported.");
$$ = 0;
}
| K_begin statement_list K_end
@@ -1409,16 +1490,16 @@ statement
| K_begin error K_end
{ yyerrok; }
| K_deassign lavalue';'
{ yyerror(@1, "Sorry, deassign not supported.");
{ yyerror(@1, "sorry:, deassign not supported.");
$$ = 0;
}
| K_disable IDENTIFIER ';'
{ yyerror(@1, "Sorry, disable statements not supported.");
{ yyerror(@1, "sorry: disable statements not supported.");
delete $2;
$$ = 0;
}
| K_force lavalue '=' expression ';'
{ yyerror(@1, "Sorry, procedural force assign not supported.");
{ yyerror(@1, "sorry: procedural force assign not supported.");
$$ = 0;
}
| K_forever statement
@@ -1434,14 +1515,16 @@ statement
delete $2;
$$ = tmp;
}
| K_release lavalue ';'
{ yyerror(@1, "Sorry, release not supported.");
$$ = 0;
}
| K_repeat '(' expression ')' statement
{ PRepeat*tmp = new PRepeat($3, $5);
| K_fork ':' IDENTIFIER
{ pform_push_scope($3); }
block_item_decls_opt
statement_list K_join
{ pform_pop_scope();
PBlock*tmp = new PBlock($3, PBlock::BL_PAR, *$6);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $3;
delete $6;
$$ = tmp;
}
| K_fork K_join
@@ -1450,24 +1533,38 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_fork ':' IDENTIFIER K_join
{ PBlock*tmp = new PBlock(PBlock::BL_PAR);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_release lavalue ';'
{ yyerror(@1, "sorry: release not supported.");
$$ = 0;
}
| K_repeat '(' expression ')' statement
{ PRepeat*tmp = new PRepeat($3, $5);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_case '(' expression ')' case_items K_endcase
{ PCase*tmp = new PCase($3, $5);
{ PCase*tmp = new PCase(NetCase::EQ, $3, $5);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_casex '(' expression ')' case_items K_endcase
{ PCase*tmp = new PCase($3, $5);
{ PCase*tmp = new PCase(NetCase::EQX, $3, $5);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
yywarn(@1, "casex not properly supported, using case.");
$$ = tmp;
}
| K_casez '(' expression ')' case_items K_endcase
{ PCase*tmp = new PCase($3, $5);
{ PCase*tmp = new PCase(NetCase::EQZ, $3, $5);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
yywarn(@1, "casez not properly supported, using case.");
$$ = tmp;
}
| K_case '(' expression ')' error K_endcase
@@ -1476,7 +1573,7 @@ statement
{ yyerrok; }
| K_casez '(' expression ')' error K_endcase
{ yyerrok; }
| K_if '(' expression ')' statement_opt
| K_if '(' expression ')' statement_opt %prec less_than_K_else
{ PCondit*tmp = new PCondit($3, $5, 0);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
@@ -1488,12 +1585,12 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_if '(' error ')' statement_opt
{ yyerror(@1, "Malformed conditional expression.");
| K_if '(' error ')' statement_opt %prec less_than_K_else
{ yyerror(@1, "error: Malformed conditional expression.");
$$ = $5;
}
| K_if '(' error ')' statement_opt K_else statement_opt
{ yyerror(@1, "Malformed conditional expression.");
{ yyerror(@1, "error: Malformed conditional expression.");
$$ = $5;
}
| K_for '(' lpvalue '=' expression ';' expression ';'
@@ -1506,16 +1603,16 @@ statement
| K_for '(' lpvalue '=' expression ';' expression ';'
error ')' statement
{ $$ = 0;
yyerror(@9, "Error in for loop step assigment.");
yyerror(@9, "error: Error in for loop step assigment.");
}
| K_for '(' lpvalue '=' expression ';' error ';'
lpvalue '=' expression ')' statement
{ $$ = 0;
yyerror(@7, "Error in for loop condition expression.");
yyerror(@7, "error: Error in for loop condition expression.");
}
| K_for '(' error ')' statement
{ $$ = 0;
yyerror(@3, "Incomprehensible for loop.");
yyerror(@3, "error: Incomprehensible for loop.");
}
| K_while '(' expression ')' statement
{ PWhile*tmp = new PWhile($3, $5);
@@ -1523,12 +1620,12 @@ statement
}
| K_while '(' error ')' statement
{ $$ = 0;
yyerror(@3, "Error in while loop condition.");
yyerror(@3, "error: Error in while loop condition.");
}
| delay statement_opt
{ PExpr*del = (*$1)[0];
if ($1->count() != 1)
yyerror(@1, "Sorry, delay lists not supported here.");
yyerror(@1, "sorry: delay lists not supported here.");
PDelayStatement*tmp = new PDelayStatement(del, $2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
@@ -1537,7 +1634,7 @@ statement
| event_control statement_opt
{ PEventStatement*tmp = $1;
if (tmp == 0) {
yyerror(@1, "Invalid event control.");
yyerror(@1, "error: Invalid event control.");
$$ = 0;
} else {
tmp->set_statement($2);
@@ -1559,12 +1656,34 @@ statement
| lpvalue '=' delay expression ';'
{ PExpr*del = (*$3)[0];
if ($3->count() != 1)
yyerror(@1, "Sorry, delay lists not supported here.");
yyerror(@1, "sorry: Delay lists not supported here.");
PAssign*tmp = new PAssign($1,del,$4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| lpvalue K_LE delay expression ';'
{ PExpr*del = (*$3)[0];
if ($3->count() != 1)
yyerror(@1, "sorry: Delay lists not supported here.");
PAssignNB*tmp = new PAssignNB($1,del,$4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| lpvalue '=' event_control expression ';'
{ PAssign*tmp = new PAssign($1,$3,$4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| lpvalue K_LE event_control expression ';'
{ yyerror(@1, "sorry: Event controls not supported here.");
PAssignNB*tmp = new PAssignNB($1,$4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_wait '(' expression ')' statement_opt
{ PEventStatement*tmp;
PEEvent*etmp = new PEEvent(NetNEvent::POSITIVE, $3);
@@ -1621,7 +1740,7 @@ statement
$$ = tmp;
}
| error ';'
{ yyerror(@1, "malformed statement");
{ yyerror(@1, "error: malformed statement");
yyerrok;
$$ = new PNoop;
}
@@ -1654,24 +1773,27 @@ task_body
task_item
: block_item_decl
{ $$ = 0; }
{ $$ = new svector<PWire*>(0); }
| K_input range_opt list_of_variables ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT, $2, $3);
= pform_make_task_ports(NetNet::PINPUT, $2,
$3, @1.text, @1.first_line);
delete $2;
delete $3;
$$ = tmp;
}
| K_output range_opt list_of_variables ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::POUTPUT, $2, $3);
= pform_make_task_ports(NetNet::POUTPUT, $2, $3,
@1.text, @1.first_line);
delete $2;
delete $3;
$$ = tmp;
}
| K_inout range_opt list_of_variables ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT, $2, $3);
= pform_make_task_ports(NetNet::PINOUT, $2, $3,
@1.text, @1.first_line);
delete $2;
delete $3;
$$ = tmp;
+5 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: parse_misc.cc,v 1.2 1998/11/07 17:05:05 steve Exp $"
#ident "$Id: parse_misc.cc,v 1.3 1999/09/29 21:15:31 steve Exp $"
#endif
# include "parse_misc.h"
@@ -48,7 +48,7 @@ void yywarn(const YYLTYPE&loc, const char*msg)
if (loc.text)
cerr << loc.text << ":";
cerr << loc.first_line << ": warning -- " << msg << endl;
cerr << loc.first_line << ": warning: " << msg << endl;
}
int VLwrap()
@@ -58,6 +58,9 @@ int VLwrap()
/*
* $Log: parse_misc.cc,v $
* Revision 1.3 1999/09/29 21:15:31 steve
* Standardize formatting of warning messages.
*
* Revision 1.2 1998/11/07 17:05:05 steve
* Handle procedural conditional, and some
* of the conditional expressions.
+110 -17
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform.cc,v 1.37 1999/08/03 04:14:49 steve Exp $"
#ident "$Id: pform.cc,v 1.47 1999/11/23 01:04:57 steve Exp $"
#endif
# include "compiler.h"
@@ -42,7 +42,9 @@ static Module*pform_cur_module = 0;
/*
* The scope stack and the following functions handle the processing
* of scope. As I enter a scope, the push function is called, and as I
* leave a scope the opo function is called.
* leave a scope the pop function is called.
*
* The top module is not included in the scope list.
*/
struct scope_name_t {
string name;
@@ -97,6 +99,15 @@ static unsigned long evaluate_delay(PExpr*delay)
void pform_startmodule(const string&name, svector<Module::port_t*>*ports)
{
assert( pform_cur_module == 0 );
/* The parser parses ``module foo()'' as having one
unconnected port, but it is really a module with no
ports. Fix it up here. */
if (ports && (ports->count() == 1) && ((*ports)[0] == 0)) {
delete ports;
ports = 0;
}
pform_cur_module = new Module(name, ports);
delete ports;
}
@@ -296,6 +307,7 @@ void pform_makegates(PGBuiltin::Type type,
*/
static void pform_make_modgate(const string&type,
const string&name,
svector<PExpr*>*overrides,
svector<PExpr*>*wires,
const string&fn, unsigned ln)
{
@@ -306,7 +318,7 @@ static void pform_make_modgate(const string&type,
return;
}
PGate*cur = new PGModule(type, name, wires);
PGate*cur = new PGModule(type, name, overrides, wires);
cur->set_file(fn);
cur->set_lineno(ln);
pform_cur_module->add_gate(cur);
@@ -314,6 +326,7 @@ static void pform_make_modgate(const string&type,
static void pform_make_modgate(const string&type,
const string&name,
svector<PExpr*>*overrides,
svector<portname_t*>*bind,
const string&fn, unsigned ln)
{
@@ -332,27 +345,29 @@ static void pform_make_modgate(const string&type,
pins[idx].parm = curp->parm;
}
PGate*cur = new PGModule(type, name, pins, npins);
PGate*cur = new PGModule(type, name, overrides, pins, npins);
cur->set_file(fn);
cur->set_lineno(ln);
pform_cur_module->add_gate(cur);
}
void pform_make_modgates(const string&type, svector<lgate>*gates)
void pform_make_modgates(const string&type,
svector<PExpr*>*overrides,
svector<lgate>*gates)
{
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
lgate cur = (*gates)[idx];
if (cur.parms_by_name) {
pform_make_modgate(type, cur.name, cur.parms_by_name,
pform_make_modgate(type, cur.name, overrides, cur.parms_by_name,
cur.file, cur.lineno);
} else if (cur.parms) {
pform_make_modgate(type, cur.name, cur.parms, cur.file,
pform_make_modgate(type, cur.name, overrides, cur.parms, cur.file,
cur.lineno);
} else {
svector<PExpr*>*wires = new svector<PExpr*>(0);
pform_make_modgate(type, cur.name, wires, cur.file,
pform_make_modgate(type, cur.name, overrides, wires, cur.file,
cur.lineno);
}
}
@@ -378,6 +393,20 @@ PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
return cur;
}
void pform_make_pgassign_list(svector<PExpr*>*alist,
svector<PExpr*>*del,
const string& text,
unsigned lineno)
{
PGAssign*tmp;
for (unsigned idx = 0 ; idx < alist->count()/2 ; idx += 1) {
tmp = pform_make_pgassign((*alist)[2*idx],
(*alist)[2*idx+1], del);
tmp->set_file(text);
tmp->set_lineno(lineno);
}
}
void pform_makewire(const vlltype&li, const string&nm,
NetNet::Type type)
{
@@ -465,8 +494,11 @@ void pform_set_port_type(const string&name, NetNet::PortType pt)
*/
svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
const svector<PExpr*>*range,
const list<string>*names)
const list<string>*names,
const string& file,
unsigned lineno)
{
assert(names);
svector<PWire*>*res = new svector<PWire*>(0);
for (list<string>::const_iterator cur = names->begin()
; cur != names->end() ; cur ++ ) {
@@ -480,6 +512,8 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
curw->set_port_type(pt);
} else {
curw = new PWire(name, NetNet::IMPLICIT_REG, pt);
curw->set_file(file);
curw->set_lineno(lineno);
pform_cur_module->add_wire(curw);
}
@@ -500,8 +534,21 @@ void pform_set_task(const string&name, PTask*task)
pform_cur_module->add_task(name, task);
}
void pform_set_function(const string&name, PFunction *func)
/*
* This function is called to fill out the definition of the function
* with the trappings that are discovered after the basic function
* name is parsed.
*/
void pform_set_function(const string&name, svector<PExpr*>*ra, PFunction *func)
{
PWire*out = new PWire(name+"."+name, NetNet::REG, NetNet::POUTPUT);
if (ra) {
assert(ra->count() == 2);
out->set_range((*ra)[0], (*ra)[1]);
delete ra;
}
pform_cur_module->add_wire(out);
func->set_output(out);
pform_cur_module->add_function(name, func);
}
@@ -536,21 +583,26 @@ void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r)
{
PWire*cur = pform_cur_module->get_wire(name);
if (cur == 0) {
VLerror("name is not a valid net.");
VLerror(" error: name is not a valid net.");
return;
}
cur->set_memory_idx(l, r);
}
/*
* This function attaches a range to a given name. The function is
* only called by the parser within the scope of the net declaration,
* and the name that I receive only has the tail component.
*/
static void pform_set_net_range(const string&name, const svector<PExpr*>*range)
{
assert(range);
assert(range->count() == 2);
PWire*cur = pform_cur_module->get_wire(name);
PWire*cur = pform_cur_module->get_wire(scoped_name(name));
if (cur == 0) {
VLerror("name is not a valid net.");
VLerror(" error: name is not a valid net.");
return;
}
@@ -573,6 +625,7 @@ void pform_set_net_range(list<string>*names, const svector<PExpr*>*range)
void pform_set_parameter(const string&name, PExpr*expr)
{
pform_cur_module->parameters[name] = expr;
pform_cur_module->param_names.push_back(name);
}
void pform_set_port_type(list<string>*names, NetNet::PortType pt)
@@ -584,12 +637,18 @@ void pform_set_port_type(list<string>*names, NetNet::PortType pt)
}
}
static void pform_set_reg_integer(const string&name)
static void pform_set_reg_integer(const string&nm)
{
string name = scoped_name(nm);
PWire*cur = pform_cur_module->get_wire(name);
if (cur == 0) {
cur = new PWire(name, NetNet::INTEGER, NetNet::NOT_A_PORT);
pform_cur_module->add_wire(cur);
} else {
bool rc = cur->set_wire_type(NetNet::INTEGER);
assert(rc);
}
assert(cur);
bool rc = cur->set_wire_type(NetNet::INTEGER);
assert(rc);
cur->set_range(new PENumber(new verinum(INTEGER_WIDTH-1, INTEGER_WIDTH)),
new PENumber(new verinum(0UL, INTEGER_WIDTH)));
@@ -634,7 +693,10 @@ int pform_parse(const char*path, map<string,Module*>&modules,
map<string,PUdp*>&prim)
{
vl_file = path;
vl_input = fopen(path, "r");
if (strcmp(path, "-") == 0)
vl_input = stdin;
else
vl_input = fopen(path, "r");
if (vl_input == 0) {
cerr << "Unable to open " <<vl_file << "." << endl;
return 11;
@@ -655,6 +717,37 @@ int pform_parse(const char*path, map<string,Module*>&modules,
/*
* $Log: pform.cc,v $
* Revision 1.47 1999/11/23 01:04:57 steve
* A file name of - means standard input.
*
* Revision 1.46 1999/09/30 01:22:37 steve
* Handle declaration of integers (including scope) in functions.
*
* Revision 1.45 1999/09/21 00:58:33 steve
* Get scope right when setting the net range.
*
* Revision 1.44 1999/09/17 02:06:26 steve
* Handle unconnected module ports.
*
* Revision 1.43 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.42 1999/09/10 05:02:09 steve
* Handle integers at task parameters.
*
* Revision 1.41 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.40 1999/08/27 15:08:37 steve
* continuous assignment lists.
*
* Revision 1.39 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.38 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.37 1999/08/03 04:14:49 steve
* Parse into pform arbitrarily complex module
* port declarations.
+25 -5
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform.h,v 1.27 1999/08/03 04:14:49 steve Exp $"
#ident "$Id: pform.h,v 1.31 1999/09/10 05:02:09 steve Exp $"
#endif
# include "netlist.h"
@@ -121,7 +121,7 @@ extern void pform_set_net_range(list<string>*names, const svector<PExpr*>*);
extern void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r);
extern void pform_set_reg_integer(list<string>*names);
extern void pform_set_task(const string&, PTask*);
extern void pform_set_function(const string&, PFunction*);
extern void pform_set_function(const string&, svector<PExpr*>*, PFunction*);
extern void pform_set_attrib(const string&name, const string&key,
const string&value);
extern void pform_set_type_attrib(const string&name, const string&key,
@@ -141,18 +141,25 @@ extern void pform_makegates(PGBuiltin::Type type,
svector<PExpr*>*delay,
svector<lgate>*gates);
extern void pform_make_modgates(const string&type, svector<lgate>*gates);
extern void pform_make_modgates(const string&type,
svector<PExpr*>*overrides,
svector<lgate>*gates);
/* Make a continuous assignment node, with optional bit- or part- select. */
extern PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
svector<PExpr*>*delays);
extern void pform_make_pgassign_list(svector<PExpr*>*alist,
svector<PExpr*>*del,
const string& text,
unsigned lineno);
/* Given a port type and a list of names, make a list of wires that
can be used as task port information. */
extern svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
const svector<PExpr*>*range,
const list<string>*names);
const list<string>*names,
const string& file,
unsigned lineno);
/*
@@ -167,6 +174,19 @@ extern void pform_dump(ostream&out, Module*mod);
/*
* $Log: pform.h,v $
* Revision 1.31 1999/09/10 05:02:09 steve
* Handle integers at task parameters.
*
* Revision 1.30 1999/08/27 15:08:37 steve
* continuous assignment lists.
*
* Revision 1.29 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.28 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.27 1999/08/03 04:14:49 steve
* Parse into pform arbitrarily complex module
* port declarations.
+112 -22
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform_dump.cc,v 1.34 1999/08/03 04:49:13 steve Exp $"
#ident "$Id: pform_dump.cc,v 1.45 1999/10/10 01:59:55 steve Exp $"
#endif
/*
@@ -37,6 +37,12 @@ ostream& operator << (ostream&out, const PExpr&obj)
return out;
}
ostream& operator << (ostream&o, const PDelays&d)
{
d.dump_delays(o);
return o;
}
void PExpr::dump(ostream&out) const
{
out << typeid(*this).name();
@@ -65,7 +71,7 @@ void PECallFunction::dump(ostream &out) const
{
out << name_ << "(";
parms_[0]->dump(out);
for (unsigned idx = 0; idx < parms_.count(); ++idx) {
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
out << ", ";
parms_[idx]->dump(out);
}
@@ -126,6 +132,9 @@ void PEBinary::dump(ostream&out) const
{
out << "(" << *left_ << ")";
switch (op_) {
case 'a':
out << "&&";
break;
case 'e':
out << "==";
break;
@@ -209,7 +218,7 @@ void PGate::dump_pins(ostream&out) const
}
}
void PGate::dump_delays(ostream&out) const
void PDelays::dump_delays(ostream&out) const
{
if (delay_[0] && delay_[1] && delay_[2])
out << "#(" << *delay_[0] << "," << *delay_[1] << "," <<
@@ -221,10 +230,15 @@ void PGate::dump_delays(ostream&out) const
}
void PGate::dump_delays(ostream&out) const
{
delay_.dump_delays(out);
}
void PGate::dump(ostream&out) const
{
out << " " << typeid(*this).name() << " ";
dump_delays(out);
delay_.dump_delays(out);
out << " " << get_name() << "(";
dump_pins(out);
out << ");" << endl;
@@ -268,12 +282,25 @@ void PGBuiltin::dump(ostream&out) const
void PGModule::dump(ostream&out) const
{
out << " " << type_ << " " << get_name() << "(";
out << " " << type_ << " ";
if (overrides_) {
out << "#(";
out << *((*overrides_)[0]);
for (unsigned idx = 1 ; idx < overrides_->count() ; idx += 1) {
out << "," << *((*overrides_)[idx]);
}
out << ") ";
}
out << get_name() << "(";
if (pins_) {
out << "." << pins_[0].name << "(" << *pins_[0].parm << ")";
out << "." << pins_[0].name << "(";
if (pins_[0].parm) out << *pins_[0].parm;
out << ")";
for (unsigned idx = 1 ; idx < npins_ ; idx += 1) {
out << ", ." << pins_[idx].name << "(" <<
*pins_[idx].parm << ")";
out << ", ." << pins_[idx].name << "(";
if (pins_[idx].parm)
out << *pins_[idx].parm;
out << ")";
}
} else {
dump_pins(out);
@@ -294,18 +321,14 @@ void Statement::dump(ostream&out, unsigned ind) const
void PAssign::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "";
out << *lval() << " = ";
if (delay()) out << "#" << *delay() << " ";
out << *rval() << ";";
out << *lval() << " = " << delay_ << " " << *rval() << ";";
out << " /* " << get_line() << " */" << endl;
}
void PAssignNB::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "";
out << *lval() << " <= ";
if (delay()) out << "#" << *delay() << " ";
out << *rval() << ";";
out << *lval() << " <= " << delay_ << " " << *rval() << ";";
out << " /* " << get_line() << " */" << endl;
}
@@ -317,7 +340,10 @@ void PBlock::dump(ostream&out, unsigned ind) const
out << endl;
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) {
list_[idx]->dump(out, ind+2);
if (list_[idx])
list_[idx]->dump(out, ind+2);
else
out << setw(ind+2) << "" << "/* NOOP */ ;" << endl;
}
out << setw(ind) << "" << "end" << endl;
@@ -345,8 +371,19 @@ void PCallTask::dump(ostream&out, unsigned ind) const
void PCase::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "case (" << *expr_ << ") /* " <<
get_line() << " */" << endl;
out << setw(ind) << "";
switch (type_) {
case NetCase::EQ:
out << "case";
break;
case NetCase::EQX:
out << "casex";
break;
case NetCase::EQZ:
out << "casez";
break;
}
out << " (" << *expr_ << ") /* " << get_line() << " */" << endl;
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
PCase::Item*cur = (*items_)[idx];
@@ -377,7 +414,10 @@ void PCase::dump(ostream&out, unsigned ind) const
void PCondit::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "if (" << *expr_ << ")" << endl;
if_->dump(out, ind+3);
if (if_)
if_->dump(out, ind+3);
else
out << setw(ind) << ";" << endl;
if (else_) {
out << setw(ind) << "" << "else" << endl;
else_->dump(out, ind+3);
@@ -430,13 +470,17 @@ void PForStatement::dump(ostream&out, unsigned ind) const
void PFunction::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "output " << out_->name() << ";" << endl;
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
out << setw(ind) << "";
out << "input ";
out << (*ports_)[idx]->name() << ";" << endl;
}
statement_->dump(out, ind);
if (statement_)
statement_->dump(out, ind);
else
out << setw(ind) << "" << "/* NOOP */" << endl;
}
void PRepeat::dump(ostream&out, unsigned ind) const
@@ -464,7 +508,10 @@ void PTask::dump(ostream&out, unsigned ind) const
out << (*ports_)[idx]->name() << ";" << endl;
}
statement_->dump(out, ind);
if (statement_)
statement_->dump(out, ind);
else
out << setw(ind) << "" << "/* NOOP */" << endl;
}
@@ -496,6 +543,12 @@ void Module::dump(ostream&out) const
for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) {
port_t*cur = ports_[idx];
if (cur == 0) {
out << " unconnected" << endl;
continue;
}
switch (cur->wires[0]->get_port_type()) {
case NetNet::PINPUT:
out << " input ." << cur->name << "(";
@@ -522,8 +575,11 @@ void Module::dump(ostream&out) const
typedef map<string,PExpr*>::const_iterator parm_iter_t;
for (parm_iter_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
out << " parameter " << (*cur).first << " = " <<
*(*cur).second << ";" << endl;
out << " parameter " << (*cur).first << " = ";
if ((*cur).second)
out << *(*cur).second << ";" << endl;
else
out << "/* ERROR */;" << endl;
}
// Iterate through and display all the wires.
@@ -619,6 +675,40 @@ void PUdp::dump(ostream&out) const
/*
* $Log: pform_dump.cc,v $
* Revision 1.45 1999/10/10 01:59:55 steve
* Structural case equals device.
*
* Revision 1.44 1999/09/30 02:43:02 steve
* Elaborate ~^ and ~| operators.
*
* Revision 1.43 1999/09/30 00:48:50 steve
* Cope with errors during ternary operator elaboration.
*
* Revision 1.42 1999/09/29 21:15:58 steve
* Handle some mor missing names.
*
* Revision 1.41 1999/09/29 20:23:53 steve
* Handle empty named ports in the dump.
*
* Revision 1.40 1999/09/29 18:36:04 steve
* Full case support
*
* Revision 1.39 1999/09/17 02:06:26 steve
* Handle unconnected module ports.
*
* Revision 1.38 1999/09/08 02:24:39 steve
* Empty conditionals (pmonta@imedia.com)
*
* Revision 1.37 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.36 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.35 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.34 1999/08/03 04:49:13 steve
* Proper port type names.
*
+280
View File
@@ -0,0 +1,280 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: set_width.cc,v 1.6 1999/10/05 06:19:46 steve Exp $"
#endif
/*
* This file contains set_width methods for the various NetExpr
* classes. The set_width method is used by elaboration to ask the
* expression to resize itself. If the expression can't, then the
* set_width method will return false and the caller will arrange for
* whatever is needed to deal with the size mismatch.
*/
# include "netlist.h"
# include "netmisc.h"
# include <typeinfo>
bool NetExpr::set_width(unsigned w)
{
cerr << typeid(*this).name() << ": set_width(unsigned) "
"not implemented." << endl;
expr_width(w);
return false;
}
bool NetEBinary::set_width(unsigned w)
{
bool flag = true;
switch (op_) {
case 'l': // left shift (<<)
case 'r': // right shift (>>)
flag = left_->set_width(w);
expr_width(w);
break;
/* The default rule is that the operands of the binary
operator might as well use the same width as the
output from the binary operation. */
default:
expr_width(left_->expr_width() > right_->expr_width()
? left_->expr_width() : right_->expr_width());
cerr << "NetEBinary::set_width(): Using default for " <<
op_ << "." << endl;
flag = false;
case '%':
case '/':
flag = left_->set_width(w) && flag;
flag = right_->set_width(w) && flag;
expr_width(w);
break;
}
return flag;
}
/*
* The bitwise logical operators have operands the same size as the
* result. Anything else is a mess.
*/
bool NetEBAdd::set_width(unsigned w)
{
unsigned wid = w;
if (left_->expr_width() > wid)
wid = left_->expr_width();
if (right_->expr_width() > wid)
wid = right_->expr_width();
left_->set_width(wid);
right_->set_width(wid);
if (left_->expr_width() < wid) {
NetExpr*tmp = pad_to_width(left_, wid);
assert(tmp);
left_ = tmp;
}
if (right_->expr_width() < wid) {
NetExpr*tmp = pad_to_width(right_, wid);
assert(tmp);
right_ = tmp;
}
expr_width(wid);
return wid == w;
}
/*
* The bitwise logical operators have operands the same size as the
* result. Anything else is a mess.
*/
bool NetEBBits::set_width(unsigned w)
{
bool flag = true;
flag = left_->set_width(w) && flag;
flag = right_->set_width(w) && flag;
if (flag)
expr_width(w);
return flag;
}
/*
* Comparison operators allow the subexpressions to have
* their own natural width, but the comparison operator result has a
* fixed width of 1.
*/
bool NetEBComp::set_width(unsigned w)
{
bool flag = true;
return (w == 1);
}
bool NetEBLogic::set_width(unsigned w)
{
bool flag;
flag = left_->set_width(right_->expr_width());
if (!flag)
flag = right_->set_width(left_->expr_width());
return (w == 1);
}
/*
* The shift operator allows the shift amount to have its own
* natural width. The width of the operator result is the width of the
* left operand, the value that is to be shifted.
*/
bool NetEBShift::set_width(unsigned w)
{
bool flag;
flag = left_->set_width(w);
return flag;
}
/*
* Add up the widths from all the expressions that are concatenated
* together. This is the width of the expression, tough luck if you
* want it otherwise.
*
* If during the course of elaboration one of the sub-expressions is
* broken, then don't count it in the width. This doesn't really
* matter because the null expression is indication of an error and
* the compiler will not go beyond elaboration.
*/
bool NetEConcat::set_width(unsigned w)
{
unsigned sum = 0;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
if (parms_[idx] != 0)
sum += parms_[idx]->expr_width();
sum *= repeat_;
expr_width(sum);
if (sum != w) return false;
return true;
}
bool NetEConst::set_width(unsigned w)
{
if (w > value_.len())
return false;
assert(w <= value_.len());
value_ = verinum(value_, w);
expr_width(w);
return true;
}
bool NetEMemory::set_width(unsigned w)
{
if (w != mem_->width())
return false;
expr_width(w);
return true;
}
bool NetEParam::set_width(unsigned)
{
return false;
}
/*
* The signal should automatically pad with zeros to get to th desired
* width. Do not allow signal bits to be truncated, however.
*/
bool NetESignal::set_width(unsigned w)
{
if (w != pin_count())
return false;
return true;
}
bool NetESubSignal::set_width(unsigned w)
{
if (w != 1) return false;
return true;
}
bool NetETernary::set_width(unsigned w)
{
bool flag = true;
flag = flag && true_val_->set_width(w);
flag = flag && false_val_->set_width(w);
expr_width(true_val_->expr_width());
return flag;
}
/*
* XXXX FIX ME: For now, just take whatever the caller says as my
* width. What I really need to do is note the width of the output
* parameter of the function definition and take that into account.
*/
bool NetEUFunc::set_width(unsigned wid)
{
expr_width(wid);
return true;
}
bool NetEUnary::set_width(unsigned w)
{
bool flag = true;
switch (op_) {
case '~':
case '-':
flag = expr_->set_width(w);
break;
default:
flag = expr_width() == w;
break;
}
expr_width(w);
return flag;
}
/*
* $Log: set_width.cc,v $
* Revision 1.6 1999/10/05 06:19:46 steve
* Add support for reduction NOR.
*
* Revision 1.5 1999/10/05 04:02:10 steve
* Relaxed width handling for <= assignment.
*
* Revision 1.4 1999/09/29 00:42:51 steve
* Allow expanding of additive operators.
*
* Revision 1.3 1999/09/23 03:56:57 steve
* Support shift operators.
*
* Revision 1.2 1999/09/23 02:27:50 steve
* comparison parameter width is self determined.
*
* Revision 1.1 1999/09/23 00:21:55 steve
* Move set_width methods into a single file,
* Add the NetEBLogic class for logic expressions,
* Fix error setting with of && in if statements.
*
*/
+23 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sigfold.cc,v 1.2 1998/12/02 04:37:13 steve Exp $"
#ident "$Id: sigfold.cc,v 1.3 1999/11/06 04:51:11 steve Exp $"
#endif
# include "netlist.h"
@@ -83,6 +83,24 @@ static void clear_extra_signals(NetNet*net, unsigned npin)
continue;
}
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig)) {
cerr << "internal warning: sigfold found NetTmp--"
"deleting it." << endl;
// save the next link, ...
NetObj*nxt;
unsigned pnxt;
cur->pin(pin).next_link(nxt, pnxt);
// disconnect the target signal, ...
sig->pin(pin).unlink();
// And onward.
cur = nxt;
pin = pnxt;
continue;
}
// Skip the node if it has incompatible attributes.
if (! net->has_compat_attributes(*sig)) {
@@ -152,10 +170,13 @@ void sigfold(Design*des)
/*
* $Log: sigfold.cc,v $
* Revision 1.3 1999/11/06 04:51:11 steve
* Catch NetTmp objects.
*
* Revision 1.2 1998/12/02 04:37:13 steve
* Add the nobufz function to eliminate bufz objects,
* Object links are marked with direction,
* constant propagation is more careful will wide links,
* constant propagation is more careful with wide links,
* Signal folding is aware of attributes, and
* the XNF target can dump UDP objects based on LCA
* attributes.
+210
View File
@@ -0,0 +1,210 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: synth.cc,v 1.3 1999/12/01 06:06:16 steve Exp $"
#endif
/*
* The synth function searches the behavioral description for
* patterns that are known to represent LPM library components. This
* is especially interesting for the sequential components such as
* flip flops and latches. As threads are transformed into components,
* the design is rewritten.
*/
# include "functor.h"
# include "netlist.h"
/*
* This transform recognizes the following patterns:
*
* always @(posedge CLK) Q = D
* always @(negedge CLK) Q = D
*
* always @(posedge CLK) if (CE) Q = D;
* always @(negedge CLK) if (CE) Q = D;
*
* The r-value of the assignments must be identifiers (i.e. wires or
* registers) and the CE must be single-bit identifiers. The generated
* device will be wide enough to accomodate Q and D.
*/
class match_dff : public proc_match_t {
public:
match_dff(Design*d, NetProcTop*t)
: des_(d), top_(t), pclk_(0), nclk_(0), con_(0), ce_(0),
asn_(0), d_(0)
{ }
~match_dff() { }
void make_it();
private:
virtual int assign(NetAssign*);
virtual int condit(NetCondit*);
virtual int pevent(NetPEvent*);
Design*des_;
NetProcTop*top_;
NetPEvent*pclk_;
NetNEvent*nclk_;
NetCondit *con_;
NetNet*ce_;
NetAssign *asn_;
NetNet*d_;
};
int match_dff::assign(NetAssign*as)
{
if (!pclk_)
return 0;
if (asn_)
return 0;
asn_ = as;
d_ = asn_->rval()->synthesize(des_);
if (d_ == 0)
return 0;
return 1;
}
int match_dff::condit(NetCondit*co)
{
if (!pclk_)
return 0;
if (con_ || asn_)
return 0;
con_ = co;
if (con_->else_clause())
return 0;
ce_ = con_->expr()->synthesize(des_);
if (ce_ == 0)
return 0;
return con_->if_clause()->match_proc(this);
}
int match_dff::pevent(NetPEvent*pe)
{
if (pclk_ || con_ || asn_)
return 0;
pclk_ = pe;
// ... there must be a single event source, ...
svector<class NetNEvent*>*neb = pclk_->back_list();
if (neb == 0)
return 0;
if (neb->count() != 1) {
delete neb;
return 0;
}
nclk_ = (*neb)[0];
delete neb;
return pclk_->statement()->match_proc(this);
}
void match_dff::make_it()
{
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) {
connect(ff->pin_Data(idx), d_->pin(idx));
connect(ff->pin_Q(idx), asn_->pin(idx));
}
connect(ff->pin_Clock(), nclk_->pin(0));
if (ce_) connect(ff->pin_Enable(), ce_->pin(0));
ff->attribute("LPM_FFType", "DFF");
if (nclk_->type() == NetNEvent::NEGEDGE)
ff->attribute("Clock:LPM_Polarity", "INVERT");
des_->add_node(ff);
}
class synth_f : public functor_t {
public:
void process(class Design*, class NetProcTop*);
private:
void proc_always_(class Design*);
NetProcTop*top_;
};
/*
* Look at a process, and divide the problem into always and initial
* threads.
*/
void synth_f::process(class Design*des, class NetProcTop*top)
{
switch (top->type()) {
case NetProcTop::KALWAYS:
top_ = top;
proc_always_(des);
break;
}
}
/*
* An "always ..." statement has been found.
*/
void synth_f::proc_always_(class Design*des)
{
match_dff dff_pat(des, top_);
if (top_->statement()->match_proc(&dff_pat)) {
dff_pat.make_it();
des->delete_process(top_);
return;
}
}
void synth(Design*des)
{
synth_f synth_obj;
des->functor(&synth_obj);
}
/*
* $Log: synth.cc,v $
* Revision 1.3 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
* Revision 1.2 1999/11/02 04:55:34 steve
* Add the synthesize method to NetExpr to handle
* synthesis of expressions, and use that method
* to improve r-value handling of LPM_FF synthesis.
*
* Modify the XNF target to handle LPM_FF objects.
*
* Revision 1.1 1999/11/01 02:07:41 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
*/
+19 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: t-null.cc,v 1.4 1999/07/03 02:12:52 steve Exp $"
#ident "$Id: t-null.cc,v 1.8 1999/10/05 03:26:37 steve Exp $"
#endif
# include "netlist.h"
@@ -33,19 +33,36 @@ static class target_null_t : public target_t {
void bufz(ostream&os, const NetBUFZ*) { }
void memory(ostream&, const NetMemory*) { }
void task_def(ostream&, const NetTaskDef*) { }
void net_assign(ostream&os, const NetAssign*) { }
void net_assign_nb(ostream&os, const NetAssignNB*) { }
void net_esignal(ostream&, const NetESignal*) { }
void net_event(ostream&, const NetNEvent*) { }
void proc_block(ostream&, const NetBlock*) { }
bool proc_block(ostream&, const NetBlock*) { return true; }
void proc_condit(ostream&, const NetCondit*) { }
void proc_delay(ostream&, const NetPDelay*) { }
void proc_event(ostream&, const NetPEvent*) { }
void proc_forever(ostream&, const NetForever*) { }
void proc_repeat(ostream&, const NetRepeat*) { }
void proc_stask(ostream&, const NetSTask*) { }
void proc_utask(ostream&os, const NetUTask*) { }
} target_null_obj;
extern const struct target tgt_null = { "null", &target_null_obj };
/*
* $Log: t-null.cc,v $
* Revision 1.8 1999/10/05 03:26:37 steve
* null target ignore assignment nodes.
*
* Revision 1.7 1999/09/30 21:27:29 steve
* Ignore user task definitions.
*
* Revision 1.6 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.5 1999/09/17 02:06:26 steve
* Handle unconnected module ports.
*
* Revision 1.4 1999/07/03 02:12:52 steve
* Elaborate user defined tasks.
*
+7 -3
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: t-verilog.cc,v 1.7 1999/08/01 16:34:50 steve Exp $"
#ident "$Id: t-verilog.cc,v 1.8 1999/09/22 16:57:24 steve Exp $"
#endif
/*
@@ -43,7 +43,7 @@ class target_verilog : public target_t {
virtual void logic(ostream&os, const NetLogic*);
virtual void bufz(ostream&os, const NetBUFZ*);
virtual void start_process(ostream&os, const NetProcTop*);
virtual void proc_block(ostream&os, const NetBlock*);
virtual bool proc_block(ostream&os, const NetBlock*);
virtual void proc_delay(ostream&os, const NetPDelay*);
virtual void proc_event(ostream&os, const NetPEvent*);
virtual void proc_stask(ostream&os, const NetSTask*);
@@ -173,13 +173,14 @@ void target_verilog::emit_expr_(ostream&os, const NetExpr*expr)
}
}
void target_verilog::proc_block(ostream&os, const NetBlock*net)
bool target_verilog::proc_block(ostream&os, const NetBlock*net)
{
os << setw(indent_) << "" << "begin" << endl;
indent_ += 4;
net->emit_recurse(os, this);
indent_ -= 4;
os << setw(indent_) << "" << "end" << endl;
return true;
}
void target_verilog::proc_delay(ostream&os, const NetPDelay*net)
@@ -271,6 +272,9 @@ const struct target tgt_verilog = {
/*
* $Log: t-verilog.cc,v $
* Revision 1.8 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.7 1999/08/01 16:34:50 steve
* Parse and elaborate rise/fall/decay times
* for gates, and handle the rules for partial
+1066 -441
View File
File diff suppressed because it is too large Load Diff
+399 -25
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: t-xnf.cc,v 1.7 1999/07/17 03:39:11 steve Exp $"
#ident "$Id: t-xnf.cc,v 1.18 1999/11/19 03:02:25 steve Exp $"
#endif
/* XNF BACKEND
@@ -33,6 +33,12 @@
* PART record. Valid types are defined by Xilinx or the
* receiving tools.
*
* ncf=<path>
* Specify the path to a NCF file. This is an OUTPUT file into
* which the code generator will write netlist constraints that
* relate to pin assignments, CLB placement, etc. If this flag is
* not given, no NCF file will be written.
*
* WIRE ATTRIBUTES
*
* PAD = <io><n>
@@ -63,6 +69,8 @@
# include "netlist.h"
# include "target.h"
# include <fstream>
# include <strstream>
class target_xnf : public target_t {
@@ -70,19 +78,33 @@ class target_xnf : public target_t {
void start_design(ostream&os, const Design*);
void end_design(ostream&os, const Design*);
void signal(ostream&os, const NetNet*);
void lpm_add_sub(ostream&os, const NetAddSub*);
void lpm_ff(ostream&os, const NetFF*);
void lpm_mux(ostream&os, const NetMux*);
void net_const(ostream&os, const NetConst*);
void logic(ostream&os, const NetLogic*);
void bufz(ostream&os, const NetBUFZ*);
void udp(ostream&os, const NetUDP*);
private:
static string mangle(const string&);
static string choose_sig_name(const NetObj::Link*lnk);
static void draw_pin(ostream&os, const string&name,
const NetObj::Link&lnk);
static void draw_sym_with_lcaname(ostream&os, string lca,
const NetNode*net);
static void draw_xor(ostream&os, const NetAddSub*, unsigned idx);
enum adder_type {FORCE0, LOWER, UPPER, DOUBLE };
static void draw_carry(ostream&os, const NetAddSub*, unsigned idx,
enum adder_type);
ofstream ncf_;
};
/*
* This function takes a signal name and mangles it into an equivilent
* This function takes a signal name and mangles it into an equivalent
* name that is suitable to the XNF format.
*/
string target_xnf::mangle(const string&name)
@@ -101,6 +123,58 @@ string target_xnf::mangle(const string&name)
return result;
}
/*
* This method takes a signal and pin number as a nexus. Scan the
* nexus to decide which name to use if there are lots of attached
* signals.
*/
string target_xnf::choose_sig_name(const NetObj::Link*lnk)
{
const NetNet*sig = dynamic_cast<const NetNet*>(lnk->get_obj());
unsigned pin = lnk->get_pin();
for (const NetObj::Link*cur = lnk->next_link()
; cur != lnk ; cur = cur->next_link()) {
const NetNet*cursig = dynamic_cast<const NetNet*>(cur->get_obj());
if (cursig == 0)
continue;
if (sig == 0) {
sig = cursig;
pin = cur->get_pin();
continue;
}
if ((cursig->pin_count() == 1) && (sig->pin_count() > 1))
continue;
if ((cursig->pin_count() > 1) && (sig->pin_count() == 1)) {
sig = cursig;
pin = cur->get_pin();
continue;
}
if (cursig->local_flag() && !sig->local_flag())
continue;
if (cursig->name() < sig->name())
continue;
sig = cursig;
pin = cur->get_pin();
}
assert(sig);
ostrstream tmp;
tmp << mangle(sig->name());
if (sig->pin_count() > 1)
tmp << "<" << pin << ">";
tmp << ends;
return tmp.str();
}
void target_xnf::draw_pin(ostream&os, const string&name,
const NetObj::Link&lnk)
{
@@ -121,26 +195,11 @@ void target_xnf::draw_pin(ostream&os, const string&name,
type = 'O';
break;
}
unsigned cpin;
const NetObj*cur;
for (lnk.next_link(cur, cpin)
; cur->pin(cpin) != lnk
; cur->pin(cpin).next_link(cur, cpin)) {
const NetNet*sig = dynamic_cast<const NetNet*>(cur);
if (sig) {
os << " PIN, " << use_name << ", " << type << ", "
<< mangle(sig->name());
if (sig->pin_count() > 1)
os << "<" << cpin << ">";
if (inv)
os << ",,INV";
os << endl;
}
}
os << " PIN, " << use_name << ", " << type << ", " <<
choose_sig_name(&lnk);
if (inv) os << ",,INV";
os << endl;
}
static string scrape_pin_name(string&list)
@@ -166,22 +225,35 @@ void target_xnf::draw_sym_with_lcaname(ostream&os, string lca,
os << "SYM, " << mangle(net->name()) << ", " << lcaname
<< ", LIBVER=2.0.0" << endl;
for (idx = 0 ; idx < net->pin_count() ; idx += 1)
draw_pin(os, scrape_pin_name(lca), net->pin(idx));
for (idx = 0 ; idx < net->pin_count() ; idx += 1) {
string usename = scrape_pin_name(lca);
if (usename == "") continue;
draw_pin(os, usename, net->pin(idx));
}
os << "END" << endl;
}
void target_xnf::start_design(ostream&os, const Design*des)
{
string ncfpath = des->get_flag("ncf");
if (ncfpath != "")
ncf_.open(ncfpath.c_str());
os << "LCANET,6" << endl;
os << "PROG,verilog,0.0,\"Icarus Verilog\"" << endl;
os << "PART," << des->get_flag("part") << endl;
os << "PROG,verilog,0.2PRE,\"Icarus Verilog\"" << endl;
ncf_ << "# Generated by Icarus Verilog 0.2PRE" << endl;
if (des->get_flag("part") != "") {
os << "PART," << des->get_flag("part") << endl;
ncf_ << "CONFIG PART=" << des->get_flag("part") << ";" << endl;
}
}
void target_xnf::end_design(ostream&os, const Design*)
{
os << "EOF" << endl;
ncf_.close();
}
void scrape_pad_info(string str, char&dir, unsigned&num)
@@ -251,6 +323,239 @@ void target_xnf::signal(ostream&os, const NetNet*net)
scrape_pad_info(pad, dir, num);
os << "EXT, " << mangle(net->name()) << ", " << dir
<< ", " << num << endl;
ncf_ << "# Assignment to pin " << num << " (DIR=" << dir <<
") by $attribute(" << net->name() << ", \"PAD\", \"" <<
pad << "\")" << endl;
ncf_ << "NET " << mangle(net->name()) << " LOC=P" << num << ";"
<< endl;
}
void target_xnf::draw_xor(ostream &os, const NetAddSub*gate, unsigned idx)
{
string name = mangle(gate->name());
string name_add = name;
string name_cout = name + "/COUT";
// We only need to pick up the
// carry if we are not the 0 bit. (We know it is 0).
os << "SYM, " << name_add << "<" << (idx+0) << ">, XOR, "
"LIBVER=2.0.0" << endl;
draw_pin(os, "O", gate->pin_Result(idx));
draw_pin(os, "I0", gate->pin_DataA(idx));
draw_pin(os, "I1", gate->pin_DataB(idx));
if (idx > 0) {
os << " PIN, I2, I, " << name_cout << "<" <<
idx << ">" << endl;
}
os << "END" << endl;
}
void target_xnf::draw_carry(ostream &os, const NetAddSub*gate, unsigned idx,
enum adder_type type)
{
string name = mangle(gate->name());
string name_cy4 = name + "/CY";
string name_cym = name + "/CM";
string name_cout = name + "/COUT";
os << "SYM, " << name_cy4 << "<" << idx << ">, CY4, "
"LIBVER=2.0.0" << endl;
// Less significant bit addends, if any
if ( type == LOWER || type == DOUBLE ) {
draw_pin(os, "A0", gate->pin_DataA(idx));
draw_pin(os, "B0", gate->pin_DataB(idx));
}
// More significant bit addends, if any
if ( type == UPPER || type == DOUBLE ) {
unsigned int i = (type==UPPER)?idx:(idx+1);
draw_pin(os, "A1", gate->pin_DataA(i));
draw_pin(os, "B1", gate->pin_DataB(i));
}
// Carry input
if ( type != FORCE0 && type != UPPER ) {
os << " PIN, CIN, I, " << name_cout << "<" <<
idx << ">" << endl;
}
// Connect the Cout0 to a signal so that I can connect
// it to the adder.
if ( type == LOWER || type == DOUBLE ) {
os << " PIN, COUT0, O, " << name_cout << "<" << (idx+1) <<
">" << endl;
}
// Connect the Cout, this will connect to the next Cin
if ( type == FORCE0 || type == UPPER || type == DOUBLE ) {
unsigned int to = (type==FORCE0)?(0):(idx+2);
if (type==UPPER) to=idx+1;
os << " PIN, COUT, O, " << name_cout << "<" << to <<
">" << endl;
}
// Carry In for mode UPPER comes from a strange place
if ( type == UPPER ) {
os << " PIN, A0, I, " << name_cout << "<dummy>" << endl;
}
// These are the mode inputs from the CY_xx pseudo-device
for (unsigned cn = 0 ; cn < 8 ; cn += 1) {
os << " PIN, C" << cn << ", I, " << name << "/C"
<< cn << "<" << (idx) << ">" << endl;
}
os << "END" << endl;
// Complete the dummy force used above
if ( type == UPPER ) {
os << "PWR, 0, " << name_cout << "<dummy>" << endl;
}
// On to the CY_xx pseudo-device itself
os << "SYM, " << name_cym << "<" << (idx) << ">, ";
switch (type) {
case FORCE0:
os << "CY4_37, CYMODE=FORCE-0" << endl;
break;
case LOWER:
os << "CY4_01, CYMODE=ADD-F-CI" << endl;
break;
case UPPER:
os << "CY4_03, CYMODE=ADD-G-F1" << endl;
break;
case DOUBLE:
os << "CY4_02, CYMODE=ADD-FG-CI" << endl;
break;
}
for (unsigned cn = 0 ; cn < 8 ; cn += 1) {
os << " PIN, C" << cn << ", O, " << name << "/C"
<< cn << "<" << (idx) << ">" << endl;
}
os << "END" << endl;
}
/*
* This function makes an adder out of carry logic symbols. It makes
* as many 2 bit adders as are possible, then the top bit is made into
* a 1-bit adder (with carry in) in the F unit. The low carry is
* initialized with the FORCE-0 configuration of a carry unit below
* the 0 bit. This takes up the carry logic of the CLB below, but not
* the G function.
*
* References:
* XNF 6.1 Specification
* Application note XAPP013
* Xilinx Libraries Guide, Chapter 12
*/
void target_xnf::lpm_add_sub(ostream&os, const NetAddSub*gate)
{
unsigned width = gate->width();
// Don't handle carry output yet
// assert (count_outputs(gate->pin_Cout())==0);
unsigned carry_width = width-1;
/* Make the force-0 cary mode object to initialize the bottom
bits of the carry chain. Label this with the width instead
of the bit position so that symbols don't clash. */
if (carry_width%2) {
draw_carry(os, gate, width, FORCE0);
} else {
draw_carry(os, gate, 0, UPPER);
}
/* Now make the 2 bit adders that chain from the cin
initializer and up. Save the tail bit (if there is one) for
later. */
for (unsigned idx = 1-(carry_width%2) ; idx < carry_width-1 ; idx += 2) {
draw_carry(os, gate, idx, DOUBLE);
}
/* Always have a tail bit */
draw_carry(os, gate, carry_width-1, LOWER);
for (unsigned idx = 0 ; idx < width ; ++idx) {
draw_xor(os, gate, idx);
}
}
void target_xnf::lpm_ff(ostream&os, const NetFF*net)
{
string type = net->attribute("LPM_FFType");
if (type == "") type = "DFF";
// XXXX For now, only support DFF
assert(type == "DFF");
string lcaname = net->attribute("XNF-LCA");
if (lcaname != "") {
draw_sym_with_lcaname(os, lcaname, net);
return;
}
assert(net->attribute("XNF-LCA") == "");
for (unsigned idx = 0 ; idx < net->width() ; idx += 1) {
os << "SYM, " << mangle(net->name()) << "<" << idx
<< ">, DFF, LIBVER=2.0.0" << endl;
draw_pin(os, "Q", net->pin_Q(idx));
draw_pin(os, "D", net->pin_Data(idx));
if (net->attribute("Clock:LPM_Polarity") == "INVERT")
draw_pin(os, "~C", net->pin_Clock());
else
draw_pin(os, "C", net->pin_Clock());
if (count_outputs(net->pin_Enable()) > 0)
draw_pin(os, "CE", net->pin_Enable());
os << "END" << endl;
}
}
/*
* Generate an LPM_MUX.
*
* XXXX NOTE: For now, this only supports combinational LPM_MUX
* devices that have a single select input. These are typically
* generated from ?: expressions.
*/
void target_xnf::lpm_mux(ostream&os, const NetMux*net)
{
assert(net->sel_width() == 1);
assert(net->size() == 2);
for (unsigned idx = 0 ; idx < net->width() ; idx += 1) {
os << "SYM, " << mangle(net->name()) << "<" << idx << ">,"
<< " EQN, EQN=(I0 * I2) + (~I0 * I1)" << endl;
draw_pin(os, "I0", net->pin_Sel(0));
draw_pin(os, "I1", net->pin_Data(idx,0));
draw_pin(os, "I2", net->pin_Data(idx,1));
draw_pin(os, "O", net->pin_Result(idx));
os << "END" << endl;
}
}
void target_xnf::net_const(ostream&os, const NetConst*c)
{
verinum::V v=c->value();
assert(v==verinum::V0 || v==verinum::V1);
const NetObj::Link& lnk = c->pin(0);
// Code parallels draw_pin above, some smart c++ guru should
// find a way to make a method out of this.
unsigned cpin;
const NetObj*cur;
os << " PWR, " << v << ", " << choose_sig_name(&lnk) << endl;
}
/*
@@ -313,6 +618,21 @@ void target_xnf::logic(ostream&os, const NetLogic*net)
os << "END" << endl;
}
void target_xnf::bufz(ostream&os, const NetBUFZ*net)
{
static int warned_once=0;
if (!warned_once) {
cerr << "Warning: BUFZ object found for xnf output."
" Try -Fnobufz." << endl;
warned_once=1;
}
os << "SYM, " << mangle(net->name()) << ", BUF, LIBVER=2.0.0" << endl;
assert(net->pin_count() == 2);
draw_pin(os, "O", net->pin(0));
draw_pin(os, "I", net->pin(1));
os << "END" << endl;
}
void target_xnf::udp(ostream&os, const NetUDP*net)
{
string lca = net->attribute("XNF-LCA");
@@ -333,6 +653,60 @@ extern const struct target tgt_xnf = { "xnf", &target_xnf_obj };
/*
* $Log: t-xnf.cc,v $
* Revision 1.18 1999/11/19 03:02:25 steve
* Detect flip-flops connected to opads and turn
* them into OUTFF devices. Inprove support for
* the XNF-LCA attribute in the process.
*
* Revision 1.17 1999/11/17 18:52:09 steve
* Add algorithm for choosing nexus name from attached signals.
*
* Revision 1.16 1999/11/17 01:31:28 steve
* Clean up warnings that add_sub got from Alliance
*
* Revision 1.15 1999/11/06 04:51:42 steve
* Support writing some XNF things into an NCF file.
*
* Revision 1.14 1999/11/05 18:43:12 steve
* fix syntax of EQN record.
*
* Revision 1.13 1999/11/05 07:10:45 steve
* Include the obvious XOR gates in the adders.
*
* Revision 1.12 1999/11/05 04:40:40 steve
* Patch to synthesize LPM_ADD_SUB from expressions,
* Thanks to Larry Doolittle. Also handle constants
* in expressions.
*
* Synthesize adders in XNF, based on a patch from
* Larry. Accept synthesis of constants from Larry
* as is.
*
* Revision 1.11 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
*
* Add the LPM_MUX device, and integrate it with the
* ternary synthesis from Larry. Replace the lpm_mux
* generator in t-xnf.cc to use XNF EQU devices to
* put muxs into function units.
*
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
*
* Revision 1.10 1999/11/02 04:55:34 steve
* Add the synthesize method to NetExpr to handle
* synthesis of expressions, and use that method
* to improve r-value handling of LPM_FF synthesis.
*
* Modify the XNF target to handle LPM_FF objects.
*
* Revision 1.9 1999/08/25 22:22:08 steve
* handle bufz in XNF backend.
*
* Revision 1.8 1999/08/18 04:00:02 steve
* Fixup spelling and some error messages. <LRDoolittle@lbl.gov>
*
* Revision 1.7 1999/07/17 03:39:11 steve
* simplified process scan for targets.
*
+130 -12
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: target.cc,v 1.15 1999/07/17 19:51:00 steve Exp $"
#ident "$Id: target.cc,v 1.28 1999/11/28 23:42:03 steve Exp $"
#endif
# include "target.h"
@@ -31,6 +31,10 @@ void target_t::start_design(ostream&os, const Design*)
{
}
void target_t::scope(ostream&, const NetScope*)
{
}
void target_t::signal(ostream&os, const NetNet*)
{
}
@@ -41,6 +45,12 @@ void target_t::memory(ostream&os, const NetMemory*)
"Unhandled memory." << endl;
}
void target_t::func_def(ostream&os, const NetFuncDef*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled function definition." << endl;
}
void target_t::task_def(ostream&os, const NetTaskDef*)
{
cerr << "target (" << typeid(*this).name() << "): "
@@ -63,6 +73,42 @@ void target_t::udp(ostream&os, const NetUDP*)
"Unhandled UDP." << endl;
}
void target_t::lpm_add_sub(ostream&, const NetAddSub*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetAddSub." << endl;
}
void target_t::lpm_clshift(ostream&, const NetCLShift*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetCLShift." << endl;
}
void target_t::lpm_compare(ostream&, const NetCompare*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetCompare." << endl;
}
void target_t::lpm_ff(ostream&, const NetFF*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetFF." << endl;
}
void target_t::lpm_mux(ostream&, const NetMux*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetMux." << endl;
}
void target_t::lpm_ram_dq(ostream&, const NetRamDq*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetRamDq." << endl;
}
void target_t::net_assign(ostream&os, const NetAssign*)
{
}
@@ -73,27 +119,28 @@ void target_t::net_assign_nb(ostream&os, const NetAssignNB*)
"Unhandled non-blocking assignment node." << endl;
}
void target_t::net_case_cmp(ostream&os, const NetCaseCmp*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled case compare node." << endl;
}
void target_t::net_const(ostream&os, const NetConst*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled CONSTANT node." << endl;
}
void target_t::net_esignal(ostream&os, const NetESignal*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled Expression Signal node." << endl;
}
void target_t::net_event(ostream&os, const NetNEvent*)
void target_t::net_event(ostream&os, const NetNEvent*net)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled EVENT net node." << endl;
net->dump_node(cerr, 4);
}
void target_t::process(ostream&os, const NetProcTop*top)
bool target_t::process(ostream&os, const NetProcTop*top)
{
top->statement()->emit_proc(os, this);
return top->statement()->emit_proc(os, this);
}
void target_t::proc_assign(ostream&os, const NetAssign*)
@@ -114,10 +161,17 @@ void target_t::proc_assign_nb(ostream&os, const NetAssignNB*)
"Unhandled non-blocking assignment." << endl;
}
void target_t::proc_block(ostream&os, const NetBlock*)
void target_t::proc_assign_mem_nb(ostream&os, const NetAssignMemNB*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled non-blocking memory assignment." << endl;
}
bool target_t::proc_block(ostream&os, const NetBlock*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled proc_block." << endl;
return false;
}
void target_t::proc_case(ostream&os, const NetCase*cur)
@@ -140,10 +194,11 @@ void target_t::proc_delay(ostream&os, const NetPDelay*)
"Unhandled proc_delay." << endl;
}
void target_t::proc_event(ostream&os, const NetPEvent*)
void target_t::proc_event(ostream&os, const NetPEvent*net)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled proc_event." << endl;
net->dump(cerr, 4);
}
void target_t::proc_forever(ostream&os, const NetForever*)
@@ -209,6 +264,12 @@ void expr_scan_t::expr_memory(const NetEMemory*)
"unhandled expr_memory." << endl;
}
void expr_scan_t::expr_scope(const NetEScope*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
"unhandled expr_scope." << endl;
}
void expr_scan_t::expr_signal(const NetESignal*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
@@ -227,6 +288,12 @@ void expr_scan_t::expr_ternary(const NetETernary*)
"unhandled expr_ternary." << endl;
}
void expr_scan_t::expr_ufunc(const NetEUFunc*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
"unhandled function call." << endl;
}
void expr_scan_t::expr_unary(const NetEUnary*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
@@ -241,6 +308,57 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
/*
* $Log: target.cc,v $
* Revision 1.28 1999/11/28 23:42:03 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.27 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.26 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.25 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.24 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.23 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
*
* Add the LPM_MUX device, and integrate it with the
* ternary synthesis from Larry. Replace the lpm_mux
* generator in t-xnf.cc to use XNF EQU devices to
* put muxs into function units.
*
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
*
* Revision 1.22 1999/11/01 02:07:41 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.21 1999/10/10 01:59:55 steve
* Structural case equals device.
*
* Revision 1.20 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.19 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.18 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.17 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.16 1999/08/18 04:00:02 steve
* Fixup spelling and some error messages. <LRDoolittle@lbl.gov>
*
* Revision 1.15 1999/07/17 19:51:00 steve
* netlist support for ternary operator.
*
+69 -5
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: target.h,v 1.15 1999/07/17 19:51:00 steve Exp $"
#ident "$Id: target.h,v 1.27 1999/11/28 23:42:03 steve Exp $"
#endif
# include "netlist.h"
@@ -55,6 +55,10 @@ struct target_t {
/* Start the design. */
virtual void start_design(ostream&os, const Design*);
/* This is called once for each scope in the design, before
anything else is called. */
virtual void scope(ostream&os, const NetScope*);
/* Output a signal (called for each signal) */
virtual void signal(ostream&os, const NetNet*);
@@ -63,6 +67,15 @@ struct target_t {
/* Output a defined task. */
virtual void task_def(ostream&, const NetTaskDef*);
virtual void func_def(ostream&, const NetFuncDef*);
/* LPM style components are handled here. */
virtual void lpm_add_sub(ostream&os, const NetAddSub*);
virtual void lpm_clshift(ostream&os, const NetCLShift*);
virtual void lpm_compare(ostream&os, const NetCompare*);
virtual void lpm_ff(ostream&os, const NetFF*);
virtual void lpm_mux(ostream&os, const NetMux*);
virtual void lpm_ram_dq(ostream&os, const NetRamDq*);
/* Output a gate (called for each gate) */
virtual void logic(ostream&os, const NetLogic*);
@@ -70,19 +83,20 @@ struct target_t {
virtual void udp(ostream&os, const NetUDP*);
virtual void net_assign(ostream&os, const NetAssign*);
virtual void net_assign_nb(ostream&os, const NetAssignNB*);
virtual void net_case_cmp(ostream&os, const NetCaseCmp*);
virtual void net_const(ostream&os, const NetConst*);
virtual void net_esignal(ostream&os, const NetESignal*);
virtual void net_event(ostream&os, const NetNEvent*);
/* Output a process (called for each process). It is up to the
target to recurse if desired. */
virtual void process(ostream&os, const NetProcTop*);
virtual bool process(ostream&os, const NetProcTop*);
/* Various kinds of process nodes are dispatched through these. */
virtual void proc_assign(ostream&os, const NetAssign*);
virtual void proc_assign_mem(ostream&os, const NetAssignMem*);
virtual void proc_assign_nb(ostream&os, const NetAssignNB*);
virtual void proc_block(ostream&os, const NetBlock*);
virtual void proc_assign_mem_nb(ostream&os, const NetAssignMemNB*);
virtual bool proc_block(ostream&os, const NetBlock*);
virtual void proc_case(ostream&os, const NetCase*);
virtual void proc_condit(ostream&os, const NetCondit*);
virtual void proc_forever(ostream&os, const NetForever*);
@@ -106,9 +120,11 @@ struct expr_scan_t {
virtual void expr_concat(const NetEConcat*);
virtual void expr_ident(const NetEIdent*);
virtual void expr_memory(const NetEMemory*);
virtual void expr_scope(const NetEScope*);
virtual void expr_signal(const NetESignal*);
virtual void expr_subsignal(const NetESubSignal*);
virtual void expr_ternary(const NetETernary*);
virtual void expr_ufunc(const NetEUFunc*);
virtual void expr_unary(const NetEUnary*);
virtual void expr_binary(const NetEBinary*);
};
@@ -117,7 +133,7 @@ struct expr_scan_t {
/* The emit functions take a design and emit it to the output stream
using the specified target. If the target is given by name, it is
located in the target_table and used. */
extern void emit(ostream&o, const Design*des, const char*type);
extern bool emit(ostream&o, const Design*des, const char*type);
/* This function takes a fully qualified verilog name (which may have,
for example, dots in it) and produces a mangled version that can be
@@ -130,6 +146,54 @@ extern const struct target *target_table[];
/*
* $Log: target.h,v $
* Revision 1.27 1999/11/28 23:42:03 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.26 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.25 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.24 1999/11/14 23:43:46 steve
* Support combinatorial comparators.
*
* Revision 1.23 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.22 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
*
* Add the LPM_MUX device, and integrate it with the
* ternary synthesis from Larry. Replace the lpm_mux
* generator in t-xnf.cc to use XNF EQU devices to
* put muxs into function units.
*
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
*
* Revision 1.21 1999/11/01 02:07:41 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.20 1999/10/10 01:59:55 steve
* Structural case equals device.
*
* Revision 1.19 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.18 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.17 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.16 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.15 1999/07/17 19:51:00 steve
* netlist support for ternary operator.
*
+86
View File
@@ -0,0 +1,86 @@
.TH verilog 1 "Septemeber 13th, 1999" Version 19990913
.SH NAME
verilog - Icarus Verilog Driver
.SH SYNOPSIS
.B verilog
[-Dmacro[=defn]] [-Iincludepath] [-X] [-o outputfilename] [-s topmodule] sourcefile[s]
.SH DESCRIPTION
.PP
\fIverilog\fP is the compiler driver script for compiling Verilog code
to either a VVM-format (Verilog Virtual Machine) for simulation or to
XNF (Xilinx Netlist Format) to be used in Xilinx FPGA's.
\fIverilog\fP is just massaging the input switches and then calls
the preprocessor (ivlpp), the compiler (ivl) and (optional) the C++
compiler.
Please read the official documentation (very minimal at this point)
on how to use \fIivl et al\fP, since this man page just describes the
"easy startscript" \fIverilog\fP.
.SH OPTIONS
.l
\fIverilog\fP accepts the following options:
.TP 8
.B -D\fImacro\fP
Defines macro \fImacro\fP with the string `1' as its definition.
.TP 8
.B -D\fImacro=defn\fP
Defines macro \fImacro\fP as \fIdefn\fP.
.TP 8
.B -I\fIincludepath\fP
Append path \fIincludepath\fP to list of paths searched for include files.
.TP 8
.B -X
Generate XNF files as output. Default is VVM-format.
.TP 8
.B -x
Executes the generated file directly after compilation.
.TP 8
.B -o \fIfilename\fP
Place output in the file \fIfilename\fP. If not given, \fIverilog\fP tries to
make a guess; if the input filename is "hello.v", the output
filename will be "hello" (for VVM target) or "hello.xnf" (for XNF target).
If several files are given on the command line, the \fIlast\fP filename will
be used.
.TP 8
.B -s \fItopmodule name\fP
To explicitly set the module \fIivl\fP will use as a top-level module.
.SH EXAMPLES
These examples assume that you have a Verilog source file called hello.v in
the current directory
To compile hello.v to an executable file called hello:
verilog hello.v
To compile hello.v to an executable file called runnable:
verilog -o runnable hello.v
To compile hello.v to a file in XNF-format called hello.xnf
verilog -X hello.v
.SH "ENVIRONMENT"
.ta \w'VPI_MODULE_PATH 'u
VPI_MODULE_PATH path to PLI modules
.SH "AUTHORS"
.nf
.ta \w'verilog 'u
verilog Stefan Petersen ([email protected])
ivlpp Steve Williams ([email protected])
ivl Steve Williams ([email protected])
.SH SEE ALSO
.BR ivlpp (N/A)
.BR ivl (N/A)
.SH COPYRIGHT
.nf
Copyright \(co 1999 Stefan Petersen
This document can be freely redistributed according to the terms of the
GNU General Public License version 2.0
+131
View File
@@ -0,0 +1,131 @@
#!/bin/sh
# verilog - A wrapper shell script for ivl
# Copyright (C) 1999 Stefan Petersen ([email protected])
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
# Added support for the -t flag, for odd-ball target types. <[email protected]>
# Added support for functors, especially for the XNF target. <[email protected]>
# Setup variables
execPath=@libdir@/ivl
execIVLPP=${execPath}/ivlpp
execIVL=${execPath}/ivl
execCpp=@CXX@
tmpDir=/tmp
tmpPPFile=${tmpDir}/ivl$$.pp
tmpCCFile=${tmpDir}/ivl$$.cc
includedir=@includedir@
libdir=@libdir@
VPIModulePath=@libdir@/ivl
target="vvm"
targetSuffix=""
functors=""
flags=""
# If VPI module path aren't set up, warn at least
if test -z "${VPI_MODULE_PATH}" ; then
echo "Warning: Missing environment variable VPI_MODULE_PATH.";
echo "To be able to execute, set VPI_MODULE_PATH to ${VPIModulePath}";
export VPI_MODULE_PATH=${VPIModulePath}
fi
# Try to extract given parameters
parameter=`getopt D:I:Xxf:o:s:t: "$@"`
eval set -- "${parameter}"
while true ; do
case "$1" in
-D) extDefines="${extDefines} -D$2" ; shift 2 ;;
-I) extIncPath="${extIncPath} -I $2" ; shift 2 ;;
-X) target="xnf" ; shift ;;
-f) flags="$flags -f$2" ; shift 2 ;;
-o) outputFile=$2 ; shift 2 ;;
-s) topModule="-s $2 " ; shift 2 ;;
-t) target="$2" ; shift 2 ;;
-x) execute="true"; shift ;;
--) shift ; break ;;
*) echo "Internal error! Arg is $1 " ; exit 1 ;;
esac
done
# The rest is filenames
verilogFile=$@;
if test -z "${verilogFile}" ; then
echo "Missing infile";
echo "verilog [-Dmacro[=defn]] [-Iincludepath] [-X] [-x] [-o outputfilename] [-s topmodule] sourcefile[s]" ;
exit 1;
fi
# Choose a target file suffix based on the target type.
case "$target" in
vvm) targetSuffix="" ;;
xnf) targetSuffix=".xnf"
functors="-Fxnfsyn -Fsigfold -Fxnfio" ;;
*) targetSuffix=".$target" ;;
esac
# If no output file is given should we guess one or...?
# Assumes a few silly things if several files are given
if test -z "${outputFile}" ; then
outputFile=`echo ${verilogFile} | sed -e 's;.* ;;' | sed -e 's;\..*$;;'`
outputFile="${outputFile}${targetSuffix}" ;
fi
# Preprocess
${execIVLPP} ${extDefines} ${extIncPath} -L -o ${tmpPPFile} ${verilogFile}
if test $? -ne 0 ; then
echo "Preprocessing failed. Terminating compilation."
rm -f ${tmpPPFile}
exit 1
fi
# Compile preprocessed verilog file
${execIVL} -t ${target} -o ${tmpCCFile} ${topModule} ${functors} ${flags} ${tmpPPFile}
if test $? -ne 0 ; then
echo "Verilog compilation failed. Terminating compilation."
rm -f ${tmpCCFile}
exit 1
fi
rm -f ${tmpPPFile}
case "${target}" in
"xnf") mv ${tmpCCFile} ${outputFile} ;;
"vvm") ${execCpp} -rdynamic -I${includedir} -L${libdir} ${tmpCCFile} -o ${outputFile} -lvvm -ldl ;
if test $? -ne 0 ; then
echo "C++ compilation failed. Terminating compilation."
rm -f ${tmpCCFile}
exit 1
fi
rm -f ${tmpCCFile} ;;
*) mv ${tmpCCFile} ${outputFile} ;;
esac
if test ${execute} ; then
./${outputFile}
fi
+171 -5
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: verinum.cc,v 1.9 1999/07/20 05:12:22 steve Exp $"
#ident "$Id: verinum.cc,v 1.12 1999/11/06 16:00:17 steve Exp $"
#endif
# include "verinum.h"
@@ -213,6 +213,18 @@ string verinum::as_string() const
return result;
}
bool verinum::is_before(const verinum&that) const
{
if (that.nbits_ > nbits_) return true;
if (that.nbits_ < nbits_) return false;
for (unsigned idx = nbits_ ; idx > 0 ; idx -= 1) {
if (bits_[idx-1] < that.bits_[idx-1]) return true;
if (bits_[idx-1] > that.bits_[idx-1]) return false;
}
return false;
}
bool verinum::is_defined() const
{
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) {
@@ -296,20 +308,174 @@ ostream& operator<< (ostream&o, const verinum&v)
return o;
}
bool operator == (const verinum&left, const verinum&right)
verinum::V operator == (const verinum&left, const verinum&right)
{
if (left.len() != right.len())
return false;
return verinum::V0;
for (unsigned idx = 0 ; idx < left.len() ; idx += 1)
if (left[idx] != right[idx])
return false;
return verinum::V0;
return true;
return verinum::V1;
}
verinum::V operator <= (const verinum&left, const verinum&right)
{
unsigned idx;
for (idx = left.len() ; idx > right.len() ; idx -= 1) {
if (left[idx-1] != verinum::V0) return verinum::V0;
}
for (idx = right.len() ; idx > left.len() ; idx -= 1) {
if (right[idx-1] != verinum::V0) return verinum::V0;
}
while (idx > 0) {
if (left[idx-1] == verinum::Vx) return verinum::Vx;
if (left[idx-1] == verinum::Vz) return verinum::Vx;
if (right[idx-1] == verinum::Vx) return verinum::Vx;
if (right[idx-1] == verinum::Vz) return verinum::Vx;
if (left[idx-1] > right[idx-1]) return verinum::V0;
idx -= 1;
}
return verinum::V1;
}
static verinum::V add_with_carry(verinum::V l, verinum::V r, verinum::V&c)
{
unsigned sum = 0;
switch (c) {
case verinum::Vx:
case verinum::Vz:
c = verinum::Vx;
return verinum::Vx;
case verinum::V0:
break;
case verinum::V1:
sum += 1;
}
switch (l) {
case verinum::Vx:
case verinum::Vz:
c = verinum::Vx;
return verinum::Vx;
case verinum::V0:
break;
case verinum::V1:
sum += 1;
break;
}
switch (r) {
case verinum::Vx:
case verinum::Vz:
c = verinum::Vx;
return verinum::Vx;
case verinum::V0:
break;
case verinum::V1:
sum += 1;
break;
}
if (sum & 2)
c = verinum::V1;
else
c = verinum::V0;
if (sum & 1)
return verinum::V1;
else
return verinum::V0;
}
verinum not(const verinum&left)
{
verinum val = left;
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
switch (val[idx]) {
case verinum::V0:
val.set(idx, verinum::V1);
break;
case verinum::V1:
val.set(idx, verinum::V0);
break;
default:
val.set(idx, verinum::Vx);
break;
}
return val;
}
/*
* Addition works a bit at a time, from the least significant up to
* the most significant.
*/
verinum operator + (const verinum&left, const verinum&right)
{
unsigned min = left.len();
if (right.len() < min) min = right.len();
unsigned max = left.len();
if (right.len() > max) max = right.len();
verinum val (verinum::V0, max);
verinum::V carry = verinum::V0;
for (unsigned idx = 0 ; idx < min ; idx += 1)
val.set(idx, add_with_carry(left[idx], right[idx], carry));
if (left.len() > right.len()) {
for (unsigned idx = min ; idx < max ; idx += 1)
val.set(idx,add_with_carry(left[idx], verinum::V0, carry));
} else {
for (unsigned idx = min ; idx < max ; idx += 1)
val.set(idx, add_with_carry(verinum::V0, right[idx], carry));
}
return val;
}
verinum operator - (const verinum&left, const verinum&r)
{
verinum right = not(r);
unsigned min = left.len();
if (right.len() < min) min = right.len();
unsigned max = left.len();
if (right.len() > max) max = right.len();
verinum val (verinum::V0, max);
verinum::V carry = verinum::V1;
for (unsigned idx = 0 ; idx < min ; idx += 1)
val.set(idx, add_with_carry(left[idx], right[idx], carry));
if (left.len() > right.len()) {
for (unsigned idx = min ; idx < max ; idx += 1)
val.set(idx,add_with_carry(left[idx], verinum::V0, carry));
} else {
for (unsigned idx = min ; idx < max ; idx += 1)
val.set(idx, add_with_carry(verinum::V0, right[idx], carry));
}
return val;
}
/*
* $Log: verinum.cc,v $
* Revision 1.12 1999/11/06 16:00:17 steve
* Put number constants into a static table.
*
* Revision 1.11 1999/10/22 23:57:53 steve
* do the <= in bits, not numbers.
*
* Revision 1.10 1999/10/10 23:29:37 steve
* Support evaluating + operator at compile time.
*
* Revision 1.9 1999/07/20 05:12:22 steve
* Implement the set method.
*
+17 -2
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: verinum.h,v 1.5 1999/05/13 04:02:09 steve Exp $"
#ident "$Id: verinum.h,v 1.8 1999/11/06 16:00:17 steve Exp $"
#endif
# include <string>
@@ -63,6 +63,9 @@ class verinum {
// an ascii description instead of a number value.
bool is_string() const { return string_flag_; }
// Comparison for use in sorting algorithms.
bool is_before(const verinum&that) const;
// Individual bits can be accessed with the get and set
// methods.
V get(unsigned idx) const;
@@ -90,10 +93,22 @@ class ostream;
extern ostream& operator<< (ostream&, const verinum&);
extern ostream& operator<< (ostream&, verinum::V);
extern bool operator == (const verinum&left, const verinum&right);
extern verinum::V operator == (const verinum&left, const verinum&right);
extern verinum::V operator <= (const verinum&left, const verinum&right);
extern verinum operator + (const verinum&left, const verinum&right);
extern verinum operator - (const verinum&left, const verinum&right);
/*
* $Log: verinum.h,v $
* Revision 1.8 1999/11/06 16:00:17 steve
* Put number constants into a static table.
*
* Revision 1.7 1999/10/22 23:57:53 steve
* do the <= in bits, not numbers.
*
* Revision 1.6 1999/10/10 23:29:37 steve
* Support evaluating + operator at compile time.
*
* Revision 1.5 1999/05/13 04:02:09 steve
* More precise handling of verinum bit lengths.
*
+56
View File
@@ -0,0 +1,56 @@
HOW IT WORKS
The VPI interface for Icarus Verilog works by creating from a
collection of PLI applications a single vpi module. The vpi module
includes compiled code for the applications linked together (with any
other libraries that the applications need) into a module with a
single exported symbol, the vlog_startup_routines array.
The product that wishes to invoke the module (normally at run time)
loads the module, locates the vlog_startup_routines table, and calls
all the startup routines contained in that table. It is possible for a
product to link with many modules. In that case, all the modules are
linked in and startup routines are called in order.
The product that uses vpi modules uses the environment variable
VPI_MODULE_PATH as a ':' separated list of directories. This is the
module search path. When a module is specified by name (using whatever
means the product supports) the module search path is scanned until
the module is located.
The special module name "system.vpi" is part of the core Icarus
Verilog distribution and includes implementations of the standard
system tasks/functions.
COMPILING A VPI MODULE (LINUX)
To compile a module, first compile down to object files all the PLI
applications that you wish to include in the module. Then, create a
small "C" source file that defines only the startup table like so:
extern void hello_register();
void (*vlog_startup_routines[])() = {
hello_register,
0
};
Compile this table source down to its object file, as well. Finally,
link the application with the command:
cc -o foo.vpi -shared <all the .o files>
No VPI libraries need to be included because the product that loads
the module will supply all the standard vpi functions. If you use any
non-vpi library functions, you may need to include libraries to
support them.
The resulting foo.vpi file is the vpi module. Place it in a location
where the product to use it can locate it.
CAVEAT EMPTOR
Only the calltf function is supported. The compiletf and sizetf
functions are invoked at compile time, and the ivl compiler does not
yet support VPI.
+3
View File
@@ -0,0 +1,3 @@
Makefile
system.vpi
dep
+81
View File
@@ -0,0 +1,81 @@
#
# 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. In order to redistribute the software in
# binary form, you will need a Picture Elements Binary Software
# License.
#
# 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
#
#ident "$Id: Makefile.in,v 1.7 1999/11/07 20:33:30 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.0
prefix = @prefix@
exec_prefix = @exec_prefix@
srcdir = @srcdir@
VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
includedir = $(prefix)/include
CC = @CC@
CXX = @CXX@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CPPFLAGS = @CPPFLAGS@ @DEFS@ -fpic
CXXFLAGS = @CXXFLAGS@
LDFLAGS = @LDFLAGS@
all: system.vpi
%.o dep/%.d: %.c
@[ -d dep ] || mkdir dep
$(CC) -Wall $(CPPFLAGS) -I$(srcdir) -MD -c $< -o $*.o
mv $*.d dep
O = sys_table.o sys_display.o sys_finish.o sys_vcd.o
system.vpi: $O
$(CC) -shared -o $@ $O
clean:
rm -f *.o dep/*.d
install: all installdirs $(libdir)/ivl/system.vpi \
$(includedir)/vpi_user.h
$(libdir)/ivl/system.vpi: ./system.vpi
$(INSTALL_PROGRAM) ./system.vpi $(libdir)/ivl/system.vpi
$(includedir)/vpi_user.h: $(srcdir)/vpi_user.h
$(INSTALL_DATA) $(srcdir)/vpi_user.h $(includedir)/vpi_user.h
installdirs: ../mkinstalldirs
$(srcdir)/../mkinstalldirs $(includedir) $(bindir) $(libdir)/ivl
uninstall:
rm -f $(libdir)/ivl/system.vpi
rm -f $(includedir)/vpi_user.h
-include $(patsubst %.o, dep/%.d, $O)
+447
View File
@@ -0,0 +1,447 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sys_display.c,v 1.9 1999/11/07 02:25:07 steve Exp $"
#endif
# include "vpi_user.h"
# include <assert.h>
# include <string.h>
# include <ctype.h>
# include <stdlib.h>
struct strobe_cb_info {
char*name;
vpiHandle*items;
unsigned nitems;
};
static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
{
vpiHandle item;
unsigned nitems = 1;
vpiHandle*items = malloc(sizeof(vpiHandle));
items[0] = vpi_scan(argv);
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
items = realloc(items, (nitems+1)*sizeof(vpiHandle));
items[nitems] = item;
nitems += 1;
}
info->nitems = nitems;
info->items = items;
}
/*
* If $display discovers a string as a parameter, this function is
* called to process it as a format string. I need the argv handle as
* well so that I can look for arguments as I move forward through the
* string.
*/
static int format_str(char*fmt, int argc, vpiHandle*argv)
{
s_vpi_value value;
char buf[256];
char*cp = fmt;
int idx;
assert(fmt);
idx = 0;
while (*cp) {
size_t cnt = strcspn(cp, "%\\");
if (cnt > 0) {
if (cnt >= sizeof buf)
cnt = sizeof buf - 1;
strncpy(buf, cp, cnt);
buf[cnt] = 0;
vpi_printf("%s", buf);
cp += cnt;
} else if (*cp == '%') {
int fsize = -1;
cp += 1;
if (isdigit(*cp))
fsize = strtoul(cp, &cp, 10);
switch (*cp) {
case 0:
break;
case 'b':
case 'B':
value.format = vpiBinStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
cp += 1;
break;
case 'd':
case 'D':
value.format = vpiDecStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
cp += 1;
break;
case 'h':
case 'H':
case 'x':
case 'X':
value.format = vpiHexStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
cp += 1;
break;
case 'm':
vpi_printf("%s", vpi_get_str(vpiFullName, argv[idx]));
idx += 1;
cp += 1;
break;
case 'o':
case 'O':
value.format = vpiOctStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
cp += 1;
break;
case 't':
case 'T':
value.format = vpiDecStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
cp += 1;
break;
case '%':
vpi_printf("%%");
cp += 1;
break;
default:
vpi_printf("%c", *cp);
cp += 1;
break;
}
} else {
cp += 1;
switch (*cp) {
case 0:
break;
case 'n':
vpi_printf("\n");
cp += 1;
break;
default:
vpi_printf("%c", *cp);
cp += 1;
}
}
}
return idx;
}
static void do_display(struct strobe_cb_info*info)
{
s_vpi_value value;
int idx;
for (idx = 0 ; idx < info->nitems ; idx += 1) {
vpiHandle item = info->items[idx];
switch (vpi_get(vpiType, item)) {
case 0:
vpi_printf(" ");
break;
case vpiConstant:
if (vpi_get(vpiConstType, item) == vpiStringConst) {
value.format = vpiStringVal;
vpi_get_value(item, &value);
idx += format_str(value.value.str,
info->nitems-idx-1,
info->items+idx+1);
} else {
value.format = vpiBinStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
}
break;
case vpiNet:
case vpiReg:
value.format = vpiBinStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
break;
case vpiTimeVar:
value.format = vpiTimeVal;
vpi_get_value(item, &value);
vpi_printf("%u", value.value.time->low);
break;
default:
vpi_printf("?");
break;
}
}
}
static int sys_display_calltf(char *name)
{
struct strobe_cb_info info;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
array_from_iterator(&info, argv);
do_display(&info);
free(info.items);
if (strcmp(name,"$display") == 0)
vpi_printf("\n");
return 0;
}
/*
* The strobe implementation takes the parameter handles that are
* passed to the calltf and puts them in to an array for safe
* keeping. That array (and other bookkeeping) is passed, via the
* struct_cb_info object, to the REadOnlySych function strobe_cb,
* where it is use to perform the actual formatting and printing.
*/
static int strobe_cb(p_cb_data cb)
{
struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data;
do_display(info);
vpi_printf("\n");
free(info->name);
free(info->items);
free(info);
return 0;
}
static int sys_strobe_calltf(char*name)
{
struct t_cb_data cb;
struct t_vpi_time time;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
struct strobe_cb_info*info = calloc(1, sizeof(struct strobe_cb_info));
array_from_iterator(info, argv);
info->name = strdup(name);
time.type = vpiSimTime;
time.low = 0;
time.high = 0;
cb.reason = cbReadOnlySynch;
cb.cb_rtn = strobe_cb;
cb.time = &time;
cb.obj = 0;
cb.user_data = (char*)info;
vpi_register_cb(&cb);
return 0;
}
/*
* The $monitor system task works by managing these static variables,
* and the cbValueChange callbacks associated with registers and
* nets. Note that it is proper to keep the state in static variables
* because there can only be one monitor at a time pending (even
* though that monitor may be watching many variables).
*/
static struct strobe_cb_info monitor_info = { 0, 0, 0 };
static int monitor_scheduled = 0;
static vpiHandle *monitor_callbacks = 0;
static int monitor_cb_2(p_cb_data cb)
{
do_display(&monitor_info);
vpi_printf("\n");
monitor_scheduled = 0;
return 0;
}
static int monitor_cb_1(p_cb_data cause)
{
struct t_cb_data cb;
struct t_vpi_time time;
/* Reschedule this event so that it happens for the next
trigger on this variable. */
cb = *cause;
vpi_register_cb(&cb);
if (monitor_scheduled) return 0;
/* This this action caused the first trigger, then schedule
the monitor to happen at the end of the time slice and mark
it as scheduled. */
monitor_scheduled += 1;
time.type = vpiSimTime;
time.low = 0;
time.high = 0;
cb.reason = cbReadOnlySynch;
cb.cb_rtn = monitor_cb_2;
cb.time = &time;
cb.obj = 0;
vpi_register_cb(&cb);
return 0;
}
static int sys_monitor_calltf(char*name)
{
unsigned idx;
struct t_cb_data cb;
struct t_vpi_time time;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
if (monitor_callbacks) {
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1)
if (monitor_callbacks[idx])
vpi_remove_cb(monitor_callbacks[idx]);
free(monitor_callbacks);
monitor_callbacks = 0;
free(monitor_info.items);
free(monitor_info.name);
monitor_info.items = 0;
monitor_info.nitems = 0;
monitor_info.name = 0;
}
array_from_iterator(&monitor_info, argv);
monitor_info.name = strdup(name);
monitor_callbacks = calloc(monitor_info.nitems, sizeof(vpiHandle));
time.type = vpiSuppressTime;
cb.reason = cbValueChange;
cb.cb_rtn = monitor_cb_1;
cb.time = &time;
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) {
switch (vpi_get(vpiType, monitor_info.items[idx])) {
case vpiNet:
case vpiReg:
cb.obj = monitor_info.items[idx];
monitor_callbacks[idx] = vpi_register_cb(&cb);
break;
}
}
return 0;
}
void sys_display_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask;
tf_data.tfname = "$display";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$display";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$write";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$write";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$strobe";
tf_data.calltf = sys_strobe_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$strobe";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$monitor";
tf_data.calltf = sys_monitor_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$monitor";
vpi_register_systf(&tf_data);
}
/*
* $Log: sys_display.c,v $
* Revision 1.9 1999/11/07 02:25:07 steve
* Add the $monitor implementation.
*
* Revision 1.8 1999/11/06 23:32:14 steve
* Unify display and strobe format routines.
*
* Revision 1.7 1999/11/06 22:16:50 steve
* Get the $strobe task working.
*
* Revision 1.6 1999/10/29 03:37:22 steve
* Support vpiValueChance callbacks.
*
* Revision 1.5 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.4 1999/10/10 14:50:50 steve
* Add Octal dump format.
*
* Revision 1.3 1999/10/08 17:47:49 steve
* Add the %t formatting escape.
*
* Revision 1.2 1999/09/29 01:41:18 steve
* Support the $write system task, and have the
* vpi_scan function free iterators as needed.
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sys_finish.c,v 1.3 1999/08/28 02:10:44 steve Exp $"
#endif
# include "vpi_user.h"
static int sys_finish_calltf(char *xx)
{
vpi_sim_control(vpiFinish, 0);
return 0;
}
void sys_finish_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask;
tf_data.tfname = "$finish";
tf_data.calltf = sys_finish_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
vpi_register_systf(&tf_data);
}
/*
* $Log: sys_finish.c,v $
* Revision 1.3 1999/08/28 02:10:44 steve
* Call the right vpiFinish code.
*
* Revision 1.2 1999/08/19 02:51:03 steve
* Add vpi_sim_control
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sys_table.c,v 1.2 1999/11/07 20:33:30 steve Exp $"
#endif
extern void sys_finish_register();
extern void sys_display_register();
extern void sys_vcd_register();
void (*vlog_startup_routines[])() = {
sys_finish_register,
sys_display_register,
sys_vcd_register,
0
};
/*
* $Log: sys_table.c,v $
* Revision 1.2 1999/11/07 20:33:30 steve
* Add VCD output and related system tasks.
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
+237
View File
@@ -0,0 +1,237 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sys_vcd.c,v 1.2 1999/11/28 00:56:08 steve Exp $"
#endif
/*
* This file contains the implementations of the VCD related
* funcitons.
*/
# include <vpi_user.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
static FILE*dump_file = 0;
struct vcd_info {
vpiHandle item;
vpiHandle cb;
struct t_vpi_time time;
char*ident;
struct vcd_info*next;
};
static struct vcd_info*vcd_list = 0;
unsigned long vcd_cur_time = 0;
static int variable_cb(p_cb_data cause)
{
unsigned long now = cause->time->low;
s_vpi_value value;
struct t_cb_data cb;
struct vcd_info*info = (struct vcd_info*)cause->user_data;
/* Reschedule this event so that it happens for the next
trigger on this variable. */
cb = *cause;
vpi_register_cb(&cb);
if (now != vcd_cur_time) {
fprintf(dump_file, "#%lu\n", now);
vcd_cur_time = now;
}
if (vpi_get(vpiSize, info->item) == 1) {
value.format = vpiBinStrVal;
vpi_get_value(info->item, &value);
fprintf(dump_file, "%s%s\n", value.value.str, info->ident);
} else {
value.format = vpiBinStrVal;
vpi_get_value(info->item, &value);
fprintf(dump_file, "b%s %s\n", value.value.str, info->ident);
}
return 0;
}
static int sys_dumpall_calltf(char*name)
{
return 0;
}
static int sys_dumpfile_calltf(char*name)
{
char*path;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item = vpi_scan(argv);
if (item) {
s_vpi_value value;
if (vpi_get(vpiType, item) != vpiConstant) {
vpi_printf("ERROR: %s parameter must be a constant\n", name);
return 0;
}
if (vpi_get(vpiConstType, item) != vpiStringConst) {
vpi_printf("ERROR: %s parameter must be a constant\n", name);
return 0;
}
value.format = vpiStringVal;
vpi_get_value(item, &value);
path = strdup(value.value.str);
vpi_free_object(argv);
} else {
path = strdup("dumpfile.vcd");
}
assert(dump_file == 0);
dump_file = fopen(path, "w");
if (dump_file == 0) {
vpi_printf("ERROR: Unable to open %s for output.\n", path);
return 0;
}
free(path);
return 0;
}
static void scan_scope(unsigned depth, vpiHandle argv)
{
struct t_cb_data cb;
struct vcd_info*info;
char ident[64];
unsigned nident = 0;
vpiHandle item;
vpiHandle sublist;
cb.reason = cbValueChange;
cb.cb_rtn = variable_cb;
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
const char*type;
switch (vpi_get(vpiType, item)) {
case vpiNet:
case vpiReg:
type = "wire";
if (vpi_get(vpiType, item) == vpiReg)
type = "reg";
sprintf(ident, "<%u", nident++);
info = malloc(sizeof(*info));
info->time.type = vpiSimTime;
cb.time = &info->time;
cb.user_data = (char*)info;
cb.obj = item;
info->item = item;
info->ident = strdup(ident);
info->cb = vpi_register_cb(&cb);
info->next = vcd_list;
vcd_list = info;
fprintf(dump_file, "$var %s %u %s %s $end\n",
type, vpi_get(vpiSize, item), ident,
vpi_get_str(vpiFullName, item));
break;
case vpiModule:
sublist = vpi_iterate(vpiInternalScope, item);
if (sublist && (depth > 0))
scan_scope(depth-1, sublist);
break;
default:
vpi_printf("ERROR: $dumpvars: Unsupported parameter type\n");
}
}
}
static int sys_dumpvars_calltf(char*name)
{
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item = vpi_scan(argv);
if (item == 0) {
vpi_printf("SORRY: %s requires arguments\n", name);
return 0;
}
assert(dump_file);
scan_scope(99, argv);
fprintf(dump_file, "$enddefinitions $end\n");
fprintf(dump_file, "#0\n");
return 0;
}
void sys_vcd_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpall";
tf_data.calltf = sys_dumpall_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpall";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpfile";
tf_data.calltf = sys_dumpfile_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpfile";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpvars";
tf_data.calltf = sys_dumpvars_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpvars";
vpi_register_systf(&tf_data);
}
/*
* $Log: sys_vcd.c,v $
* Revision 1.2 1999/11/28 00:56:08 steve
* Build up the lists in the scope of a module,
* and get $dumpvars to scan the scope for items.
*
* Revision 1.1 1999/11/07 20:33:30 steve
* Add VCD output and related system tasks.
*
*/
+246
View File
@@ -0,0 +1,246 @@
#ifndef __vpi_user_H
#define __vpi_user_H
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_user.h,v 1.9 1999/11/28 00:56:08 steve Exp $"
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct __vpiHandle *vpiHandle;
/*
* This structure is created by the VPI application to provide hooks
* into the application that the compiler/simulator can access.
*/
typedef struct t_vpi_systf_data {
int type;
int subtype;
char *tfname;
int (*calltf)(char*);
int (*compiletf)(char*);
int (*sizetf)();
char *user_data;
} s_vpi_systf_data, *p_vpi_systf_data;
/* The type in the above structure can have one of the following
values: */
#define vpiSysTask 1
#define vpiSysFunc 2
typedef struct t_vpi_time {
int type;
unsigned int high;
unsigned int low;
double real;
} s_vpi_time, *p_vpi_time;
#define vpiScaledRealTime 1
#define vpiSimTime 2
#define vpiSuppressTime 3
/*
* This structure holds values that are passed back and forth between
* the simulator and the application.
*/
typedef struct t_vpi_value {
int format;
union {
char*str;
int scalar;
int integer;
double real;
struct t_vpi_time *time;
struct t_vpi_vecval *vector;
struct t_vpi_strengthval *strength;
char*misc;
} value;
} s_vpi_value, *p_vpi_value;
/* These are valid codes for the format of the t_vpi_value structure. */
#define vpiBinStrVal 1
#define vpiOctStrVal 2
#define vpiDecStrVal 3
#define vpiHexStrVal 4
#define vpiScalerVal 5
#define vpiIntVal 6
#define vpiReadVal 7
#define vpiStringVal 8
#define vpiVectorVal 9
#define vpiStrengthVal 10
#define vpiTimeVal 11
#define vpiObjTypeVal 12
#define vpiSuppressVal 13
/* OBJECT CODES */
#define vpiConstant 7
#define vpiIterator 27
#define vpiMemory 29
#define vpiMemoryWord 30
#define vpiModule 32
#define vpiNamedBegin 33
#define vpiNamedFork 35
#define vpiNet 36
#define vpiReg 48
#define vpiSysTaskCall 57
#define vpiTimeVar 63
#define vpiSysTfCall 85
#define vpiArgument 89
#define vpiInternalScope 92
#define vpiCallback 1000
/* PROPERTIES */
#define vpiType 1
#define vpiName 2
#define vpiFullName 3
#define vpiSize 4
#define vpiConstType 43
# define vpiDecConst 1
# define vpiRealConst 2
# define vpiBinaryConst 3
# define vpiOctConst 4
# define vpiHexConst 5
# define vpiStringConst 6
/* VPI FUNCTIONS */
extern void vpi_register_systf(const struct t_vpi_systf_data*ss);
extern void vpi_printf(const char*fmt, ...);
/*
* support for VPI callback functions.
*/
typedef struct t_cb_data {
int reason;
int (*cb_rtn)(struct t_cb_data*cb);
vpiHandle obj;
p_vpi_time time;
p_vpi_value value;
int index;
char*user_data;
} s_cb_data, *p_cb_data;
#define cbValueChange 1
#define cbStmt 2
#define cbForce 3
#define cbRelease 4
#define cbAtStartOfSimTime 5
#define cbReadWriteSynch 6
#define cbReadOnlySynch 7
#define cbNextSimTime 8
#define cbAfterDelay 9
#define cbEndOfCompile 10
#define cbStartOfSimulation 11
#define cbEndOfSimulation 12
#define cbError 13
#define cbTchkViolation 14
#define cbStartOfSave 15
#define cbEndOfSave 16
#define cbStartOfRestart 17
#define cbEndOfRestart 18
#define cbStartOfReset 19
#define cbEndOfReset 20
#define cbEnterInteractive 21
#define cbExitInteractive 22
#define cbInteractiveScopeChange 23
#define cbUnresolvedSystf 24
extern vpiHandle vpi_register_cb(p_cb_data data);
extern int vpi_remove_cb(vpiHandle ref);
/*
* This function allows a vpi application to control the simulation
* engine. The operation parameter specifies the function to
* perform. The remaining parameters (if any) are interpreted by the
* operation. The vpi_sim_control definition was added to P1364-2000
* 14 July 1999. See PLI Task Force ID: PTF-161
*
* vpiFinish - perform the $finish operation, as soon as the user
* function returns. This operation takes a single
* parameter, a diagnostic exit code.
*
* vpiStop -
* vpiReset -
* vpiSetInteractiveScope -
*/
extern void vpi_sim_control(int operation, ...);
#define vpiStop 1
#define vpiFinish 2
#define vpiReset 3
#define vpiSetInteractiveScope 4
extern vpiHandle vpi_handle(int type, vpiHandle ref);
extern vpiHandle vpi_iterate(int type, vpiHandle ref);
extern vpiHandle vpi_scan(vpiHandle iter);
extern int vpi_get(int property, vpiHandle ref);
extern char* vpi_get_str(int property, vpiHandle ref);
extern void vpi_get_value(vpiHandle expr, p_vpi_value value);
extern int vpi_free_object(vpiHandle ref);
/* This is the table of startup routines included in each module. */
extern void (*vlog_startup_routines[])();
#ifdef __cplusplus
}
#endif
/*
* $Log: vpi_user.h,v $
* Revision 1.9 1999/11/28 00:56:08 steve
* Build up the lists in the scope of a module,
* and get $dumpvars to scan the scope for items.
*
* Revision 1.8 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.7 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
* Revision 1.6 1999/11/07 20:33:30 steve
* Add VCD output and related system tasks.
*
* Revision 1.5 1999/11/07 02:25:08 steve
* Add the $monitor implementation.
*
* Revision 1.4 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.3 1999/08/19 02:51:03 steve
* Add vpi_sim_control
*
* Revision 1.2 1999/08/18 03:44:49 steve
* declare vou_sim_control
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
#endif
+18 -1
View File
@@ -16,6 +16,17 @@ So a sample command line to compile a Verilog file to C++ would be:
ivl -F nobufz -F sigfold -F propinit -t vvm -o foo.cc foo.vl
Once the program is compiled down to C++ code, it needs to be further
compiled and linked into an executable image. The command for doing
this is highly dependent on the system where you use Icarus
Verilog. For Linux, the compile command is typically:
c++ -rdynamic -o foo foo.cc -lvvm -ldl
On any system, the compiled program requires that the VPI_MODULE_PATH
be set to a ':' separated list of directories to search for vpi files,
the system.vpi file in particular. This is a run time requirement.
ATTRIBUTES
(none)
@@ -99,8 +110,14 @@ bits are at:
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
$Id: vvm.txt,v 1.1 1999/04/29 16:29:04 steve Exp $
$Id: vvm.txt,v 1.3 1999/08/18 03:45:36 steve Exp $
$Log: vvm.txt,v $
Revision 1.3 1999/08/18 03:45:36 steve
Update compile command line.
Revision 1.2 1999/08/15 01:23:56 steve
Convert vvm to implement system tasks with vpi.
Revision 1.1 1999/04/29 16:29:04 steve
Add vvm target documentation
+27 -10
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.3 1999/05/09 01:24:59 steve Exp $"
#ident "$Id: Makefile.in,v 1.14 1999/11/27 19:07:58 steve Exp $"
#
#
SHELL = /bin/sh
@@ -35,14 +35,15 @@ bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
includedir = $(prefix)/include
CC = @CC@
CXX = @CXX@
CC = @CC@ -I$(srcdir) -I$(srcdir)/../vpi
CXX = @CXX@ -I$(srcdir) -I$(srcdir)/../vpi
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CPPFLAGS = @CPPFLAGS@ @DEFS@
CXXFLAGS = @CXXFLAGS@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
all: libvvm.a
@@ -52,23 +53,35 @@ all: libvvm.a
$(CXX) -Wall -fno-exceptions $(CXXFLAGS) -MD -c $< -o $*.o
mv $*.d dep
TF = display.o
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_monitor.o vvm_pevent.o \
vvm_simulation.o vvm_thread.o $(TF)
%.o dep/%.d: %.c
@[ -d dep ] || mkdir dep
$(CC) -Wall $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_gates.o vvm_pevent.o \
vvm_simulation.o vvm_thread.o vpip.o
P = vpi_callback.o \
vpi_const.o vpi_iter.o vpi_memory.o vpi_null.o \
vpi_priv.o vpi_scope.o vpi_signal.o vpi_simulation.o vpi_systask.o vpi_time.o
libvvm.a: $O
rm -f $@
ar cvqf $@ $O
ar cvq $@ $O
vpip.o: $P
$(LD) -r -o vpip.o $P
clean:
rm -f *.o dep/*.d
install: all installdirs $(libdir)/libvvm.a \
$(includedir)/vvm.h \
$(includedir)/vvm_calltf.h \
$(includedir)/vpi_priv.h \
$(includedir)/vvm_func.h \
$(includedir)/vvm_gates.h \
$(includedir)/vvm_thread.h
$(includedir)/vvm_thread.h \
$(includedir)/vvm_calltf.h
$(libdir)/libvvm.a: ./libvvm.a
$(INSTALL_PROGRAM) ./libvvm.a $(libdir)/libvvm.a
@@ -88,8 +101,11 @@ $(includedir)/vvm_gates.h: $(srcdir)/vvm_gates.h
$(includedir)/vvm_thread.h: $(srcdir)/vvm_thread.h
$(INSTALL_DATA) $(srcdir)/vvm_thread.h $(includedir)/vvm_thread.h
$(includedir)/vpi_priv.h: $(srcdir)/vpi_priv.h
$(INSTALL_DATA) $(srcdir)/vpi_priv.h $(includedir)/vpi_priv.h
installdirs: mkinstalldirs
$(srcdir)/mkinstalldirs $(includedir) $(bindir)
$(srcdir)/mkinstalldirs $(includedir) $(libdir)
uninstall:
rm -f $(libdir)/libvvm.a
@@ -98,6 +114,7 @@ uninstall:
rm -f $(includedir)/vvm_func.h
rm -f $(includedir)/vvm_gates.h
rm -f $(includedir)/vvm_thread.h
rm -f $(includedir)/vpi_priv.h
-include $(patsubst %.o, dep/%.d, $O)
-264
View File
@@ -1,264 +0,0 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: display.cc,v 1.5 1999/05/31 15:46:36 steve Exp $"
#endif
# include "vvm.h"
# include "vvm_calltf.h"
# include <iostream>
static void format_hex(vvm_simulation*sim, ostream&os,
class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::TIME:
os << sim->get_sim_time();
break;
case vvm_calltf_parm::NONE:
os << "z";
break;
case vvm_calltf_parm::ULONG:
os << ((parm->as_ulong()&1) ? "0" : "1");
break;
case vvm_calltf_parm::STRING:
os << parm->as_string();
break;
case vvm_calltf_parm::BITS:
unsigned c = 0;
for (unsigned idx = parm->as_bits()->get_width()
; idx > 0 ; idx -= 1)
c = (c << 1) | parm->as_bits()->get_bit(idx-1);
cout.form("%x",c);
break;
}
}
static void format_bit(vvm_simulation*sim, ostream&os,
class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::TIME:
os << (sim->get_sim_time()&1);
break;
case vvm_calltf_parm::NONE:
os << "z";
break;
case vvm_calltf_parm::ULONG:
os << ((parm->as_ulong()&1) ? "0" : "1");
break;
case vvm_calltf_parm::STRING:
os << parm->as_string();
break;
case vvm_calltf_parm::BITS:
for (unsigned idx = parm->as_bits()->get_width()
; idx > 0 ; idx -= 1)
os << parm->as_bits()->get_bit(idx-1);
break;
}
}
static void format_dec(vvm_simulation*sim, ostream&os,
class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::TIME:
os << sim->get_sim_time();
break;
case vvm_calltf_parm::NONE:
os << "0";
break;
case vvm_calltf_parm::ULONG:
os << parm->as_ulong();
break;
case vvm_calltf_parm::STRING:
os << parm->as_string();
break;
case vvm_calltf_parm::BITS: {
unsigned long val = 0;
unsigned long mask = 1;
const vvm_bits_t*bstr = parm->as_bits();
for (unsigned idx = 0 ; idx < bstr->get_width() ; idx += 1) {
if (bstr->get_bit(idx) == V1) val |= mask;
mask <<= 1;
}
os << val;
break;
}
}
}
static void format_name(ostream&os, class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::TIME:
os << "$time";
break;
case vvm_calltf_parm::NONE:
break;
case vvm_calltf_parm::ULONG:
os << parm->as_ulong();
break;
case vvm_calltf_parm::STRING:
os << "\"" << parm->as_string() << "\"";
break;
case vvm_calltf_parm::BITS:
os << parm->sig_name();
break;
}
}
static unsigned format(vvm_simulation*sim, const string&str,
unsigned nparms,
class vvm_calltf_parm*parms)
{
char prev = 0;
unsigned next_parm = 0;
unsigned idx = 0;
while (idx < str.length()) {
if (prev == '%') {
switch (str[idx]) {
case 'b':
case 'B':
format_bit(sim, cout, parms+next_parm);
next_parm += 1;
break;
case 'x':
case 'X':
case 'h':
case 'H':
format_hex(sim, cout, parms+next_parm);
next_parm += 1;
break;
case 'd':
case 'D':
format_dec(sim, cout, parms+next_parm);
next_parm += 1;
break;
case 'm':
case 'M':
format_name(cout, parms+next_parm);
next_parm += 1;
break;
case '%':
cout << str[idx];
break;
}
prev = 0;
} else {
if (str[idx] != '%')
cout << str[idx];
else
prev = '%';
}
idx += 1;
}
return next_parm;
}
void Sdisplay(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms)
{
for (unsigned idx = 0 ; idx < nparms ; idx += 1)
switch (parms[idx].type()) {
case vvm_calltf_parm::NONE:
cout << " ";
break;
case vvm_calltf_parm::TIME:
cout << sim->get_sim_time();
break;
case vvm_calltf_parm::ULONG:
cout << parms[idx].as_ulong();
break;
case vvm_calltf_parm::STRING:
idx += format(sim, parms[idx].as_string(),
nparms-idx-1, parms+idx+1);
break;
case vvm_calltf_parm::BITS:
cout << *parms[idx].as_bits();
break;
}
cout << endl;
}
class monitor_event : public vvm_event {
public:
monitor_event(vvm_simulation*sim,
unsigned nparms, class vvm_calltf_parm*parms)
{ sim_ = sim;
nparms_ = nparms;
parms_ = new vvm_calltf_parm[nparms];
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1)
parms_[idx] = parms[idx];
}
~monitor_event() { delete[]parms_; }
private:
vvm_simulation*sim_;
unsigned nparms_;
vvm_calltf_parm*parms_;
void event_function();
};
void monitor_event::event_function()
{
Sdisplay(sim_, "$display", nparms_, parms_);
}
static monitor_event*mon = 0;
void Smonitor(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms)
{
if (mon) delete mon;
mon = new monitor_event(sim, nparms, parms);
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
if (parms[idx].type() != vvm_calltf_parm::BITS)
continue;
parms[idx].as_mon()->enable(mon);
}
}
/*
* $Log: display.cc,v $
* Revision 1.5 1999/05/31 15:46:36 steve
* Handle time in more places.
*
* Revision 1.4 1999/05/12 04:02:17 steve
* Add %x support contributed by Steve Wilson.
*
* Revision 1.3 1999/01/01 01:44:40 steve
* Proberly print vectors in binary.
*
* Revision 1.2 1998/11/10 00:48:31 steve
* Add support it vvm target for level-sensitive
* triggers (i.e. the Verilog wait).
* Fix display of $time is format strings.
*
* Revision 1.1 1998/11/09 23:44:10 steve
* Add vvm library.
*
*/
+188
View File
@@ -0,0 +1,188 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_callback.c,v 1.4 1999/11/07 20:33:30 steve Exp $"
#endif
# include "vpi_priv.h"
# include <stdlib.h>
# include <assert.h>
static struct __vpirt vpip_callback_rt = {
vpiCallback,
0,
0,
0,
0,
0
};
/*
* This function is called by the scheduler to execute an event of
* some sort. The parameter is a vpiHandle of the callback that is to
* be executed.
*/
static void vpip_call_callback(void*cp)
{
unsigned long now;
struct __vpiCallback*rfp = (struct __vpiCallback*)cp;
assert(rfp->base.vpi_type->type_code == vpiCallback);
switch (rfp->cb_data.time->type) {
case vpiSuppressTime:
case vpiScaledRealTime: // XXXX not supported
break;
case vpiSimTime:
now = ((struct __vpiTimeVar*)vpip_sim_time())->time;
rfp->cb_data.time->low = now;
rfp->cb_data.time->high = 0;
break;
}
rfp->cb_data.cb_rtn(&rfp->cb_data);
free(rfp);
}
/*
* This function is called by the product when it changes the value of
* a signal. It arranges for all the value chance callbacks to be
* called.
*/
void vpip_run_value_changes(struct __vpiSignal*sig)
{
struct __vpiCallback*cur;
if (sig->monitor == 0) return;
while (sig->monitor->next != sig->monitor) {
cur = sig->monitor->next;
sig->monitor->next = cur->next;
cur->next = 0;
cur->ev = vpip_sim_insert_event(0, cur, vpip_call_callback, 0);
}
cur = sig->monitor;
sig->monitor = 0;
cur->next = 0;
cur->ev = vpip_sim_insert_event(0, cur, vpip_call_callback, 0);
}
/*
* Handle read-only synch events. This causes the callback to be
* scheduled for a moment at the end of the time period. This method
* handles scheduling with itme delays.
*/
static void go_readonly_synch(struct __vpiCallback*rfp)
{
unsigned long tim;
assert(rfp->cb_data.time);
assert(rfp->cb_data.time->type == vpiSimTime);
assert(rfp->cb_data.time->high == 0);
tim = rfp->cb_data.time->low;
rfp->ev = vpip_sim_insert_event(tim, rfp, vpip_call_callback, 1);
}
/*
* To schedule a value change, attach the callback to the signal to me
* monitored. I'll be inserted as an event later.
*/
static void go_value_change(struct __vpiCallback*rfp)
{
struct __vpiSignal*sig = (struct __vpiSignal*)rfp->cb_data.obj;
assert((sig->base.vpi_type->type_code == vpiReg)
|| (sig->base.vpi_type->type_code == vpiNet));
/* If there are no monitor events, start the list. */
if (sig->monitor == 0) {
rfp->next = rfp;
sig->monitor = rfp;
return;
}
/* Put me at the end of the list. Remember that the monitor
points to the *last* item in the list. */
rfp->next = sig->monitor->next;
sig->monitor->next = rfp;
sig->monitor = rfp;
}
/*
* Register callbacks. This supports a variety of callback reasons,
* mostly by dispatching them to a type specific handler.
*/
vpiHandle vpi_register_cb(p_cb_data data)
{
struct __vpiCallback*rfp = calloc(1, sizeof(struct __vpiCallback));
rfp->base.vpi_type = &vpip_callback_rt;
rfp->cb_data = *data;
switch (data->reason) {
case cbReadOnlySynch:
go_readonly_synch(rfp);
break;
case cbValueChange:
go_value_change(rfp);
break;
default:
assert(0);
}
return &(rfp->base);
}
int vpi_remove_cb(vpiHandle ref)
{
struct __vpiCallback*rfp = (struct __vpiCallback*)ref;
assert(ref->vpi_type->type_code == vpiCallback);
if (rfp->ev) {
/* callbacks attached to events are easy. */
vpip_sim_cancel_event(rfp->ev);
} else {
assert(0);
}
free(rfp);
return 0;
}
/*
* $Log: vpi_callback.c,v $
* Revision 1.4 1999/11/07 20:33:30 steve
* Add VCD output and related system tasks.
*
* Revision 1.3 1999/10/29 03:37:22 steve
* Support vpiValueChance callbacks.
*
* Revision 1.2 1999/10/28 04:47:57 steve
* Support delay in constSync callback.
*
* Revision 1.1 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
*/
+336
View File
@@ -0,0 +1,336 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_const.c,v 1.4 1999/11/06 22:16:50 steve Exp $"
#endif
# include "vpi_priv.h"
# include <assert.h>
# include <string.h>
# include <stdio.h>
/*
* This function is used in a couple places to interpret a bit string
* as a value.
*/
void vpip_bits_get_value(enum vpip_bit_t*bits, unsigned nbits, s_vpi_value*vp)
{
static char buff[1024];
char*cp;
unsigned val;
unsigned idx;
cp = buff;
switch (vp->format) {
case vpiObjTypeVal:
case vpiBinStrVal:
for (idx = 0 ; idx < nbits ; idx += 1)
switch (bits[nbits-idx-1]) {
case V0:
*cp++ = '0';
break;
case V1:
*cp++ = '1';
break;
case Vx:
*cp++ = 'x';
break;
case Vz:
*cp++ = 'z';
break;
}
vp->format = vpiBinStrVal;
break;
case vpiDecStrVal:
val = 0;
for (idx = 0 ; idx < nbits ; idx += 1) {
val *= 2;
switch (bits[nbits-idx-1]) {
case V0:
case Vx:
case Vz:
break;
case V1:
val += 1;
break;
}
}
sprintf(cp, "%u", val);
cp += strlen(cp);
break;
case vpiOctStrVal:
if (nbits%3) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = 0 ; i < nbits%3 ; i += 1) {
v *= 2;
switch (bits[nbits-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == nbits%3)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == nbits%3)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "01234567"[v];
}
for (idx = nbits%3 ; idx < nbits ; idx += 3) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = idx ; i < idx+3 ; i += 1) {
v *= 2;
switch (bits[nbits-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == 3)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == 3)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "01234567"[v];
}
break;
case vpiHexStrVal:
if (nbits%4) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = 0 ; i < nbits%4 ; i += 1) {
v *= 2;
switch (bits[nbits-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == nbits%4)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == nbits%4)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "0123456789abcdef"[v];
}
for (idx = nbits%4 ; idx < nbits ; idx += 4) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = idx ; i < idx+4 ; i += 1) {
v *= 2;
switch (bits[nbits-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == 4)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == 4)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "0123456789abcdef"[v];
}
break;
default:
*cp++ = '(';
*cp++ = '?';
*cp++ = ')';
break;
}
*cp++ = 0;
vp->value.str = buff;
}
static int string_get(int code, vpiHandle ref)
{
struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref;
assert(ref->vpi_type->type_code == vpiConstant);
switch (code) {
case vpiConstType:
return vpiStringConst;
default:
assert(0);
return 0;
}
}
static void string_value(vpiHandle ref, p_vpi_value vp)
{
struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref;
assert(ref->vpi_type->type_code == vpiConstant);
switch (vp->format) {
case vpiObjTypeVal:
case vpiStringVal:
vp->value.str = rfp->value;
vp->format = vpiStringVal;
break;
default:
vp->format = vpiSuppressVal;
break;
}
}
static int number_get(int code, vpiHandle ref)
{
struct __vpiNumberConst*rfp = (struct __vpiNumberConst*)ref;
assert(ref->vpi_type->type_code == vpiConstant);
switch (code) {
case vpiConstType:
return vpiBinaryConst;
default:
assert(0);
return 0;
}
}
static void number_value(vpiHandle ref, p_vpi_value vp)
{
struct __vpiNumberConst*rfp = (struct __vpiNumberConst*)ref;
assert(ref->vpi_type->type_code == vpiConstant);
vpip_bits_get_value(rfp->bits, rfp->nbits, vp);
}
static const struct __vpirt vpip_string_rt = {
vpiConstant,
string_get,
0,
string_value,
0,
0
};
static const struct __vpirt vpip_number_rt = {
vpiConstant,
number_get,
0,
number_value,
0,
0
};
vpiHandle vpip_make_string_const(struct __vpiStringConst*ref, const char*val)
{
ref->base.vpi_type = &vpip_string_rt;
ref->value = val;
return &(ref->base);
}
vpiHandle vpip_make_number_const(struct __vpiNumberConst*ref,
const enum vpip_bit_t*bits,
unsigned nbits)
{
ref->base.vpi_type = &vpip_number_rt;
ref->bits = bits;
ref->nbits = nbits;
return &(ref->base);
}
/*
* $Log: vpi_const.c,v $
* Revision 1.4 1999/11/06 22:16:50 steve
* Get the $strobe task working.
*
* Revision 1.3 1999/11/06 16:52:16 steve
* complete value retrieval for number constants.
*
* Revision 1.2 1999/11/06 16:00:18 steve
* Put number constants into a static table.
*
* Revision 1.1 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
*/
+77
View File
@@ -0,0 +1,77 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_iter.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
#endif
/*
* Find here the methods functions in support of iterator objects.
*/
# include "vpi_priv.h"
# include <stdlib.h>
# include <assert.h>
static const struct __vpirt vpip_iterator_rt = {
vpiIterator,
0,
0,
0,
0,
0
};
vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args)
{
struct __vpiIterator*res = calloc(1, sizeof(struct __vpiIterator));
res->base.vpi_type = &vpip_iterator_rt;
res->args = args;
res->nargs = nargs;
res->next = 0;
return &(res->base);
}
/*
* The vpi_scan function only applies to iterators. It returns the
* next vpiHandle in the iterated list.
*/
vpiHandle vpi_scan(vpiHandle ref)
{
struct __vpiIterator*hp = (struct __vpiIterator*)ref;
assert(ref->vpi_type->type_code == vpiIterator);
if (hp->next == hp->nargs) {
vpi_free_object(ref);
return 0;
}
return hp->args[hp->next++];
}
/*
* $Log: vpi_iter.c,v $
* Revision 1.1 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
*/
+91
View File
@@ -0,0 +1,91 @@
/*
* Copyright (c) 1999 Picture Elements, Inc.
* Stephen Williams (steve@picturel.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version. In order to redistribute the software in
* binary form, you will need a Picture Elements Binary Software
* License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
* ---
* You should also have recieved a copy of the Picture Elements
* Binary Software License offer along with the source. This offer
* allows you to obtain the right to redistribute the software in
* binary (compiled) form. If you have not received it, contact
* Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704.
*/
#if !defined(WINNT)
#ident "$Id: vpi_memory.c,v 1.1 1999/11/10 02:52:24 steve Exp $"
#endif
# include "vpi_priv.h"
# include <stdlib.h>
# include <assert.h>
static int memory_get(int code, vpiHandle ref)
{
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
assert(ref->vpi_type->type_code==vpiMemory);
switch (code) {
case vpiSize:
return rfp->size;
default:
return 0;
}
}
static char* memory_get_str(int code, vpiHandle ref)
{
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
assert(ref->vpi_type->type_code==vpiMemory);
switch (code) {
case vpiFullName:
return (char*)rfp->name;
}
return 0;
}
static const struct __vpirt vpip_memory_rt = {
vpiMemory,
memory_get,
memory_get_str,
0,
0,
0
};
vpiHandle vpip_make_memory(struct __vpiMemory*ref, const char*name,
unsigned wid, unsigned siz)
{
ref->base.vpi_type = &vpip_memory_rt;
ref->name = name;
ref->bits = calloc(wid*siz, sizeof(enum vpip_bit_t));
ref->width = wid;
ref->size = siz;
return &(ref->base);
}
/*
* $Log: vpi_memory.c,v $
* Revision 1.1 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
*/
+47
View File
@@ -0,0 +1,47 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_null.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
#endif
# include "vpi_priv.h"
static const struct __vpirt vpip_null_rt = {
0,
0,
0,
0,
0,
0
};
struct __vpiNull vpip_null = {
{ &vpip_null_rt }
};
/*
* $Log: vpi_null.c,v $
* Revision 1.1 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
*/
+160
View File
@@ -0,0 +1,160 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_priv.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
#endif
# include "vpi_priv.h"
# include <assert.h>
# include <stdarg.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
/*
* Keep a list of vpi_systf_data structures. This list is searched
* forward whenever a function is invoked by name, and items are
* pushed in front of the list whenever they are registered. This
* allows entries to override older entries.
*/
struct systf_entry {
struct systf_entry* next;
s_vpi_systf_data systf_data;
};
static struct systf_entry*systf_list = 0;
/* This is the handle of the task currently being called. */
static struct __vpiSysTaskCall*vpip_cur_task;
void vpip_calltask(const char*fname, unsigned nparms, vpiHandle*parms)
{
struct systf_entry*idx;
struct __vpiSysTaskCall cur_task;
cur_task.base.vpi_type = &vpip_systask_rt;
cur_task.args = parms;
cur_task.nargs = nparms;
vpip_cur_task = &cur_task;
/* Look for a systf function to invoke. */
for (idx = systf_list ; idx ; idx = idx->next)
if (strcmp(fname, idx->systf_data.tfname) == 0) {
cur_task.info = &idx->systf_data;
idx->systf_data.calltf(idx->systf_data.user_data);
return;
}
/* Finally, if nothing is found then something is not
right. Print out the function name all the parameters
passed, so that someone can deal with it. */
vpi_printf("Call %s\n", fname);
}
int vpi_free_object(vpiHandle ref)
{
free(ref);
return 0;
}
int vpi_get(int property, vpiHandle ref)
{
if (property == vpiType)
return ref->vpi_type->type_code;
if (ref->vpi_type->vpi_get_ == 0)
return -1;
return (ref->vpi_type->vpi_get_)(property, ref);
}
char* vpi_get_str(int property, vpiHandle ref)
{
if (ref->vpi_type->vpi_get_str_ == 0)
return 0;
return (ref->vpi_type->vpi_get_str_)(property, ref);
}
void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
{
if (expr->vpi_type->vpi_get_value_) {
(expr->vpi_type->vpi_get_value_)(expr, vp);
return;
}
vp->format = vpiSuppressVal;
}
vpiHandle vpi_handle(int type, vpiHandle ref)
{
if (type == vpiSysTfCall) {
assert(ref == 0);
return &vpip_cur_task->base;
}
assert(ref->vpi_type->handle_);
return (ref->vpi_type->handle_)(type, ref);
}
/*
* This function asks the object to return an iterator for
* the specified reference. It is up to the iterate_ method to
* allocate a properly formed iterator.
*/
vpiHandle vpi_iterate(int type, vpiHandle ref)
{
assert(ref->vpi_type->iterate_);
return (ref->vpi_type->iterate_)(type, ref);
}
void vpi_printf(const char*fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
/*
* This function adds the information that the user supplies to a list
* that I keep.
*/
void vpi_register_systf(const struct t_vpi_systf_data*systf)
{
struct systf_entry*cur = calloc(1, sizeof(struct systf_entry));
cur->systf_data = *systf;
cur->systf_data.tfname = strdup(systf->tfname);
cur->next = systf_list;
systf_list = cur;
}
/*
* $Log: vpi_priv.c,v $
* Revision 1.1 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
*/
+306
View File
@@ -0,0 +1,306 @@
#ifndef __vpi_priv_H
#define __vpi_priv_H
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_priv.h,v 1.8 1999/11/28 00:56:08 steve Exp $"
#endif
/*
* This header file describes the "back side" of the VPI
* interface. The product that offers the VPI interface uses types and
* methods declared here to manage the VPI structures and provide the
* needed behaviors.
*/
# include <vpi_user.h>
#ifdef __cplusplus
extern "C" {
#endif
struct __vpirt;
enum vpip_bit_t { V0 = 0, V1, Vx, Vz };
extern void vpip_bits_get_value(enum vpip_bit_t*bits, unsigned nbits,
s_vpi_value*vp);
/*
* This structure is the very base of a vpiHandle. Every handle
* structure starts with this structure, so that the library can
* internally pass the derived types as pointers to one of these.
*/
struct __vpiHandle {
const struct __vpirt *vpi_type;
};
/*
* Objects with this structure are used to represent a type of
* vpiHandle. A specific object becomes of this type by holding a
* pointer to an instance of this structure.
*/
struct __vpirt {
int type_code;
/* These methods extract information from the handle. */
int (*vpi_get_)(int, vpiHandle);
char* (*vpi_get_str_)(int, vpiHandle);
void (*vpi_get_value_)(vpiHandle, p_vpi_value);
/* These methods follow references. */
vpiHandle (*handle_)(int, vpiHandle);
vpiHandle (*iterate_)(int, vpiHandle);
};
/*
* This is a private handle type that doesn't seem to be well defined
* by the VPI standard.
*/
struct __vpiCallback {
struct __vpiHandle base;
struct t_cb_data cb_data;
struct vpip_event*ev;
struct __vpiCallback*next;
};
/*
* The vpiHandle for an iterator has this structure. The definition of
* the methods lives in vpi_iter.c
*/
struct __vpiIterator {
struct __vpiHandle base;
vpiHandle *args;
unsigned nargs;
unsigned next;
};
/*
* Memory is an array of bits that is accessible in N-bit chunks, with
* N being the width of a word.
*/
struct __vpiMemory {
struct __vpiHandle base;
/* The signal has a name (this points to static memory.) */
const char*name;
enum vpip_bit_t*bits;
unsigned width;
unsigned size;
};
/*
* This type is occasionally useful. Really! And while we're at it,
* create a single instance of the null object. (This is all we need.)
*/
struct __vpiNull {
struct __vpiHandle base;
};
extern struct __vpiNull vpip_null;
/*
* This type represents the handle to a Verilog scope. These include
* module instantiations and name begin-end blocks. The attach
* function is used to attach handles to the scope by the runtime
* initializaiton.
*/
struct __vpiScope {
struct __vpiHandle base;
/* The scope has a name. (this points to static memory.) */
const char*name;
/* Keep an array of internal scope items. */
struct __vpiHandle**intern;
unsigned nintern;
};
extern void vpip_attach_to_scope(struct __vpiScope*scope, vpiHandle obj);
/*
* This structure represents nets and registers. You can tell which by
* the type_code in the base. The bits member points to the actual
* array of bits that the environment provides. The bits must persist
* as long as this object persists.
*/
struct __vpiSignal {
struct __vpiHandle base;
/* The signal has a name (this points to static memory.) */
const char*name;
/* The signal has a value and dimension. */
enum vpip_bit_t*bits;
unsigned nbits;
/* monitors are added here. */
struct __vpiCallback*monitor;
};
extern const struct __vpirt vpip_systask_rt;
struct __vpiSysTaskCall {
struct __vpiHandle base;
s_vpi_systf_data*info;
vpiHandle*args;
unsigned nargs;
const char*file;
unsigned lineno;
int subtype;
};
/*
* Represent a TimeVar variable. The actual time is stored in the
* "time" member for fast manipulation by various bits of the
* simulation engine. The time_obj member is used as persistent
* storage of the time value when get_value is used (on the opaque
* handle) to the get time.
*/
struct __vpiTimeVar {
struct __vpiHandle base;
const char*name;
unsigned long time;
struct t_vpi_time time_obj;
};
struct __vpiStringConst {
struct __vpiHandle base;
const char*value;
};
struct __vpiNumberConst {
struct __vpiHandle base;
enum vpip_bit_t*bits;
unsigned nbits;
};
/*
* These are methods to initialize specific handle types. Except for
* vpip_make_iterator, all the vpi_make_* functions expect the caller
* to allocate the memory for the handle. The result is the vpiHandle
* of the constructed object.
*/
extern vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args);
extern vpiHandle vpip_make_net(struct __vpiSignal*ref, const char*name);
extern vpiHandle vpip_make_scope(struct __vpiScope*ref,
int type_code,
const char*name);
extern vpiHandle vpip_make_string_const(struct __vpiStringConst*ref,
const char*val);
extern vpiHandle vpip_make_number_const(struct __vpiNumberConst*ref,
const enum vpip_bit_t*bits,
unsigned nbits);
extern vpiHandle vpip_make_memory(struct __vpiMemory*ref, const char*name,
unsigned width, unsigned size);
extern vpiHandle vpip_make_reg(struct __vpiSignal*ref, const char*name);
extern vpiHandle vpip_make_time_var(struct __vpiTimeVar*ref,
const char*val);
/* Use this function to call a registered task. */
extern void vpip_calltask(const char*name, unsigned nparms, vpiHandle*parms);
extern void vpip_run_value_changes(struct __vpiSignal*sig);
/*
* The simulation object holds the current state of the
* simulation. There is a single global variable that is the
* simulation.
*/
struct vpip_simulation_cycle;
struct vpip_event;
struct vpip_simulation {
/* Current simulation time. */
struct __vpiTimeVar sim_time;
/* List of cbReadOnlySynch callbacks. */
struct __vpiCallback*read_sync_list;
/* List of simulation cycles, starting with the next time. */
struct vpip_simulation_cycle*sim;
int going_flag;
};
extern struct vpip_simulation vpip_simulation_obj;
extern void vpip_init_simulation();
extern void vpip_simulation_run();
/*
* Schedule an event to be run sometime in the future. The d parmater
* is the delay in simulation units before the event is processed. If
* the non-block flag is set, the event is scheduled to happen at the
* end of the time step.
*
* The return value from the insert method is a cookie that can be
* used to manipulate the event before it is executed.
*/
extern struct vpip_event* vpip_sim_insert_event(unsigned long d,
void*user_data,
void (*sim_fun)(void*),
int nonblock_flag);
extern void vpip_sim_cancel_event(struct vpip_event*cookie);
/*
* This function returns a handle to the vpiTimeVar that is th main
* simulation time clock.
*/
extern vpiHandle vpip_sim_time();
/*
* Return true if the going_flag is false.
*/
extern int vpip_finished();
#ifdef __cplusplus
}
#endif
/*
* $Log: vpi_priv.h,v $
* Revision 1.8 1999/11/28 00:56:08 steve
* Build up the lists in the scope of a module,
* and get $dumpvars to scan the scope for items.
*
* Revision 1.7 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.6 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
* Revision 1.5 1999/11/06 16:52:16 steve
* complete value retrieval for number constants.
*
* Revision 1.4 1999/11/06 16:00:18 steve
* Put number constants into a static table.
*
* Revision 1.3 1999/10/29 03:37:22 steve
* Support vpiValueChance callbacks.
*
* Revision 1.2 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
#endif
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_scope.c,v 1.2 1999/11/28 00:56:08 steve Exp $"
#endif
# include "vpi_priv.h"
# include <stdlib.h>
# include <assert.h>
static vpiHandle module_iter(int code, vpiHandle obj)
{
struct __vpiScope*ref = (struct __vpiScope*)obj;
assert(obj->vpi_type->type_code == vpiModule);
switch (code) {
case vpiInternalScope:
return vpip_make_iterator(ref->nintern, ref->intern);
}
return 0;
}
static const struct __vpirt vpip_module_rt = {
vpiModule,
0,
0,
0,
0,
module_iter
};
vpiHandle vpip_make_scope(struct __vpiScope*ref, int type, const char*name)
{
ref->intern = 0;
ref->nintern = 0;
switch (type) {
case vpiModule:
ref->base.vpi_type = &vpip_module_rt;
break;
default:
assert(0);
}
return &ref->base;
}
void vpip_attach_to_scope(struct __vpiScope*ref, vpiHandle obj)
{
unsigned idx = ref->nintern++;
if (ref->intern == 0)
ref->intern = malloc(sizeof(vpiHandle));
else
ref->intern = realloc(ref->intern, sizeof(vpiHandle)*ref->nintern);
ref->intern[idx] = obj;
}
/*
* $Log: vpi_scope.c,v $
* Revision 1.2 1999/11/28 00:56:08 steve
* Build up the lists in the scope of a module,
* and get $dumpvars to scan the scope for items.
*
* Revision 1.1 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
*/
+123
View File
@@ -0,0 +1,123 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_signal.c,v 1.5 1999/11/07 20:33:30 steve Exp $"
#endif
# include "vpi_priv.h"
# include <assert.h>
static int signal_get(int code, vpiHandle ref)
{
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
assert((ref->vpi_type->type_code==vpiNet)
|| (ref->vpi_type->type_code==vpiReg));
switch (code) {
case vpiSize:
return rfp->nbits;
default:
return 0;
}
}
static char* signal_get_str(int code, vpiHandle ref)
{
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
assert((ref->vpi_type->type_code==vpiNet)
|| (ref->vpi_type->type_code==vpiReg));
switch (code) {
case vpiFullName:
return (char*)rfp->name;
}
return 0;
}
static void signal_get_value(vpiHandle ref, s_vpi_value*vp)
{
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
assert((ref->vpi_type->type_code==vpiNet)
|| (ref->vpi_type->type_code==vpiReg));
vpip_bits_get_value(rfp->bits, rfp->nbits, vp);
}
static const struct __vpirt vpip_net_rt = {
vpiNet,
signal_get,
signal_get_str,
signal_get_value,
0,
0
};
vpiHandle vpip_make_net(struct __vpiSignal*ref, const char*name)
{
ref->base.vpi_type = &vpip_net_rt;
ref->name = name;
ref->monitor = 0;
return &(ref->base);
}
static const struct __vpirt vpip_reg_rt = {
vpiReg,
signal_get,
signal_get_str,
signal_get_value,
0,
0
};
vpiHandle vpip_make_reg(struct __vpiSignal*ref, const char*name)
{
ref->base.vpi_type = &vpip_reg_rt;
ref->name = name;
ref->monitor = 0;
return &(ref->base);
}
/*
* $Log: vpi_signal.c,v $
* Revision 1.5 1999/11/07 20:33:30 steve
* Add VCD output and related system tasks.
*
* Revision 1.4 1999/11/07 02:25:08 steve
* Add the $monitor implementation.
*
* Revision 1.3 1999/11/06 16:52:16 steve
* complete value retrieval for number constants.
*
* Revision 1.2 1999/10/29 03:37:22 steve
* Support vpiValueChance callbacks.
*
* Revision 1.1 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
*/
+205
View File
@@ -0,0 +1,205 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_simulation.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
#endif
# include "vpi_priv.h"
# include <stdlib.h>
# include <assert.h>
struct vpip_event {
void*user_data;
void (*sim_fun)(void*);
struct vpip_event*next;
};
struct vpip_simulation vpip_simulation_obj;
void vpi_sim_control(int func, ...)
{
switch (func) {
case vpiFinish:
vpip_simulation_obj.going_flag = 0;
break;
}
}
/*
* The simulation event queue is a list of simulation cycles that in
* turn contain lists of simulation events. The simulation cycle
* represents the happening at some simulation time.
*/
struct vpip_simulation_cycle {
unsigned long delay;
struct vpip_simulation_cycle*next;
struct vpip_simulation_cycle*prev;
struct vpip_event*event_list;
struct vpip_event*event_last;
struct vpip_event*nonblock_list;
struct vpip_event*nonblock_last;
};
void vpip_init_simulation()
{
struct vpip_simulation_cycle*cur;
vpip_make_time_var(&vpip_simulation_obj.sim_time, "$time");
vpip_simulation_obj.read_sync_list = 0;
/* Allocate a header cell for the simulation event list. */
cur = calloc(1, sizeof(struct vpip_simulation_cycle));
cur->delay = 0;
cur->next = cur->prev = cur;
vpip_simulation_obj.sim = cur;
}
vpiHandle vpip_sim_time()
{
return &vpip_simulation_obj.sim_time.base;
}
struct vpip_event* vpip_sim_insert_event(unsigned long delay,
void*user_data,
void (*sim_fun)(void*),
int nonblock_flag)
{
struct vpip_event*event;
struct vpip_simulation_cycle*cur;
event = calloc(1, sizeof(struct vpip_event));
event->user_data = user_data;
event->sim_fun = sim_fun;
cur = vpip_simulation_obj.sim->next;
while ((cur != vpip_simulation_obj.sim) && (cur->delay < delay)) {
delay -= cur->delay;
cur = cur->next;
}
/* If there is no cycle cell for the specified time, create one. */
if ((cur == vpip_simulation_obj.sim) || (cur->delay > delay)) {
struct vpip_simulation_cycle*cell
= calloc(1,sizeof(struct vpip_simulation_cycle));
cell->delay = delay;
if (cur != vpip_simulation_obj.sim)
cur->delay -= delay;
cell->next = cur;
cell->prev = cur->prev;
cell->next->prev = cell;
cell->prev->next = cell;
cur = cell;
}
/* Put the event into the end of the cycle list. */
event->next = 0;
if (nonblock_flag) {
if (cur->nonblock_list == 0) {
cur->nonblock_list = cur->nonblock_last = event;
} else {
cur->nonblock_last->next = event;
cur->nonblock_last = event;
}
} else {
if (cur->event_list == 0) {
cur->event_list = cur->event_last = event;
} else {
cur->event_last->next = event;
cur->event_last = event;
}
}
return event;
}
void vpip_sim_cancel_event(struct vpip_event*ev)
{
assert(0);
}
int vpip_finished()
{
return ! vpip_simulation_obj.going_flag;
}
void vpip_simulation_run()
{
vpip_simulation_obj.sim_time.time = 0;
vpip_simulation_obj.going_flag = !0;
while (vpip_simulation_obj.going_flag) {
struct vpip_simulation_cycle*sim = vpip_simulation_obj.sim;
/* Step the time forward to the next time cycle. */
vpip_simulation_obj.sim_time.time += sim->delay;
sim->delay = 0;
while (vpip_simulation_obj.going_flag) {
struct vpip_event*active = sim->event_list;
sim->event_list = 0;
sim->event_last = 0;
if (active == 0) {
active = sim->nonblock_list;
sim->nonblock_list = 0;
sim->nonblock_last = 0;
}
if (active == 0)
break;
while (active && vpip_simulation_obj.going_flag) {
struct vpip_event*cur = active;
active = cur->next;
(cur->sim_fun)(cur->user_data);
free(cur);
}
}
if (! vpip_simulation_obj.going_flag)
break;
{ struct vpip_simulation_cycle*next = sim->next;
if (next == sim) {
vpip_simulation_obj.going_flag = 0;
break;
}
sim->next->prev = sim->prev;
sim->prev->next = sim->next;
free(sim);
vpip_simulation_obj.sim = next;
}
}
}
/*
* $Log: vpi_simulation.c,v $
* Revision 1.1 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
*/
+56
View File
@@ -0,0 +1,56 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_systask.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
#endif
# include "vpi_priv.h"
# include <stdlib.h>
# include <assert.h>
static vpiHandle systask_iter(int type, vpiHandle ref)
{
struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref;
assert(ref->vpi_type->type_code == vpiSysTaskCall);
if (rfp->nargs == 0)
return 0;
return vpip_make_iterator(rfp->nargs, rfp->args);
}
const struct __vpirt vpip_systask_rt = {
vpiSysTaskCall,
0,
0,
0,
0,
systask_iter
};
/*
* $Log: vpi_systask.c,v $
* Revision 1.1 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
*/
+84
View File
@@ -0,0 +1,84 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_time.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
#endif
# include "vpi_priv.h"
# include <assert.h>
# include <stdio.h>
/*
* IEEE-1364 VPI pretty much mandates the existance of this sort of
* thing. (Either this or a huge memory leak.) Sorry.
*/
static char buf_obj[128];
static void timevar_get_value(vpiHandle ref, s_vpi_value*vp)
{
struct __vpiTimeVar*rfp = (struct __vpiTimeVar*)ref;
assert(ref->vpi_type->type_code == vpiTimeVar);
switch (vp->format) {
case vpiObjTypeVal:
case vpiTimeVal:
rfp->time_obj.low = rfp->time;
vp->value.time = &rfp->time_obj;
vp->format = vpiTimeVal;
break;
case vpiDecStrVal:
sprintf(buf_obj, "%lu", rfp->time);
vp->value.str = buf_obj;
break;
default:
vp->format = vpiSuppressVal;
vp->value.str = 0;
break;
}
}
static const struct __vpirt vpip_time_var_rt = {
vpiTimeVar,
0,
0,
timevar_get_value,
0,
0
};
vpiHandle vpip_make_time_var(struct __vpiTimeVar*ref, const char*val)
{
ref->base.vpi_type = &vpip_time_var_rt;
ref->name = val;
return &(ref->base);
}
/*
* $Log: vpi_time.c,v $
* Revision 1.1 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
*/
+161 -95
View File
@@ -1,7 +1,7 @@
#ifndef __vvm_H
#define __vvm_H
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-1999 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
@@ -19,12 +19,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm.h,v 1.9 1999/06/21 01:02:34 steve Exp $"
#ident "$Id: vvm.h,v 1.24 1999/12/02 03:36:01 steve Exp $"
#endif
# include <vector>
# include <string>
# include <cassert>
# include "vpi_priv.h"
/*
* The Verilog Virtual Machine are definitions for the virtual machine
@@ -37,15 +36,10 @@ class vvm_event;
class vvm_simulation;
class vvm_simulation_cycle;
class vvm_thread;
/* The vvm_bit_t is the basic unit of value for a scalar signal in
Verilog. It represents all the possible values. The vvm_bitstring_t
is a vector of vvm_bit_t and is used when variable-length bit
arrays are needed. */
enum vvm_bit_t { V0 = 0, V1, Vx, Vz };
class ostream;
inline vvm_bit_t operator & (vvm_bit_t l, vvm_bit_t r)
inline vpip_bit_t operator & (vpip_bit_t l, vpip_bit_t r)
{
if (l == V0) return V0;
if (r == V0) return V0;
@@ -53,7 +47,7 @@ inline vvm_bit_t operator & (vvm_bit_t l, vvm_bit_t r)
return Vx;
}
inline vvm_bit_t operator | (vvm_bit_t l, vvm_bit_t r)
inline vpip_bit_t operator | (vpip_bit_t l, vpip_bit_t r)
{
if (l == V1) return V1;
if (r == V1) return V1;
@@ -61,7 +55,7 @@ inline vvm_bit_t operator | (vvm_bit_t l, vvm_bit_t r)
return Vx;
}
inline vvm_bit_t operator ^ (vvm_bit_t l, vvm_bit_t r)
inline vpip_bit_t operator ^ (vpip_bit_t l, vpip_bit_t r)
{
if (l == Vx) return Vx;
if (l == Vz) return Vx;
@@ -71,7 +65,7 @@ inline vvm_bit_t operator ^ (vvm_bit_t l, vvm_bit_t r)
return (r == V0)? V1 : V0;
}
inline vvm_bit_t less_with_cascade(vvm_bit_t l, vvm_bit_t r, vvm_bit_t c)
inline vpip_bit_t less_with_cascade(vpip_bit_t l, vpip_bit_t r, vpip_bit_t c)
{
if (l == Vx) return Vx;
if (r == Vx) return Vx;
@@ -80,9 +74,18 @@ inline vvm_bit_t less_with_cascade(vvm_bit_t l, vvm_bit_t r, vvm_bit_t c)
return c;
}
extern vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry);
inline vpip_bit_t greater_with_cascade(vpip_bit_t l, vpip_bit_t r, vpip_bit_t c)
{
if (l == Vx) return Vx;
if (r == Vx) return Vx;
if (l > r) return V1;
if (l < r) return V0;
return c;
}
inline vvm_bit_t not(vvm_bit_t l)
extern vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry);
inline vpip_bit_t not(vpip_bit_t l)
{
switch (l) {
case V0:
@@ -94,18 +97,23 @@ inline vvm_bit_t not(vvm_bit_t l)
}
}
extern bool posedge(vpip_bit_t from, vpip_bit_t to);
class vvm_bits_t {
public:
virtual ~vvm_bits_t() =0;
virtual unsigned get_width() const =0;
virtual vvm_bit_t get_bit(unsigned idx) const =0;
virtual vpip_bit_t get_bit(unsigned idx) const =0;
unsigned as_unsigned() const;
};
extern ostream& operator << (ostream&os, vvm_bit_t);
extern ostream& operator << (ostream&os, vpip_bit_t);
extern ostream& operator << (ostream&os, const vvm_bits_t&str);
/*
* The vvm_bitset_t is a fixed width array-like set of vvm_bit_t
* The vvm_bitset_t is a fixed width array-like set of vpip_bit_t
* items. A number is often times made up of bit sets instead of
* single bits. The fixed array is used when possible because of the
* more thorough type checking and (hopefully) better optimization.
@@ -115,33 +123,31 @@ template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
public:
vvm_bitset_t()
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
bits_[idx] = Vz;
bits[idx] = Vz;
}
vvm_bit_t operator[] (unsigned idx) const { return bits_[idx]; }
vvm_bit_t&operator[] (unsigned idx) { return bits_[idx]; }
vvm_bitset_t(const vvm_bits_t&that)
{ unsigned wid = WIDTH;
if (that.get_width() < WIDTH)
wid = that.get_width();
for (unsigned idx = 0 ; idx < wid ; idx += 1)
bits[idx] = that.get_bit(idx);
for (unsigned idx = wid ; idx < WIDTH ; idx += 1)
bits[idx] = V0;
}
vvm_bitset_t(const vvm_bitset_t<WIDTH>&that)
{ bits = that.bits; }
vpip_bit_t operator[] (unsigned idx) const { return bits[idx]; }
vpip_bit_t&operator[] (unsigned idx) { return bits[idx]; }
unsigned get_width() const { return WIDTH; }
vvm_bit_t get_bit(unsigned idx) const { return bits_[idx]; }
vpip_bit_t get_bit(unsigned idx) const { return bits[idx]; }
bool eequal(const vvm_bitset_t<WIDTH>&that) const
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
if (bits_[idx] != that.bits_[idx])
return false;
return true;
}
unsigned as_unsigned() const
{ unsigned result = 0;
for (unsigned idx = WIDTH ; idx > 0 ; idx -= 1) {
result <<= 1;
if (bits_[idx-1]) result |= 1;
}
return result;
}
private:
vvm_bit_t bits_[WIDTH];
public:
vpip_bit_t bits[WIDTH];
};
/*
@@ -154,12 +160,14 @@ class vvm_event {
friend class vvm_simulation;
public:
vvm_event() { }
vvm_event();
virtual ~vvm_event() =0;
virtual void event_function() =0;
static void callback_(void*);
private:
vvm_event*next_;
struct vpip_event*event_;
private: // not implemented
vvm_event(const vvm_event&);
@@ -205,18 +213,7 @@ class vvm_simulation {
// only one event can be a monitor.
void monitor_event(vvm_event*);
unsigned long get_sim_time() const { return time_; }
void s_finish();
private:
bool going_;
vvm_simulation_cycle*sim_;
// Triggered monitor event.
vvm_event*mon_;
unsigned long time_;
bool finished() const;
private: // not implemented
vvm_simulation(const vvm_simulation&);
@@ -224,62 +221,131 @@ class vvm_simulation {
};
/*
* The vvm_monitor_t is usually associated with a vvm_bitset_t that
* represents a signal. The VVM code generator generates calls to the
* trigger method whenever an assignment or output value is set on
* the associated signal. The trigger, if enabled, then causes the
* monitor event to be scheduled in the simulation.
*
* This object also carries the canonical signal name, for the use of
* %m display patterns.
* The vvm_signal_t template is the real object that handles the
* receiving of assignments and doing whatever is done. It also
* connects VPI to the C++/vvm design.
*/
class vvm_monitor_t {
public:
vvm_monitor_t(const string&);
void trigger(vvm_simulation*sim)
{ if (event_) sim->monitor_event(event_); }
const string& name() const { return name_; }
void enable(vvm_event*e) { event_ = e; }
private:
string name_;
vvm_event*event_;
private: // not implemented
vvm_monitor_t(const vvm_monitor_t&);
vvm_monitor_t& operator= (const vvm_monitor_t&);
};
template <unsigned WIDTH> class vvm_signal_t : public vvm_monitor_t {
template <unsigned WIDTH> class vvm_signal_t : public __vpiSignal {
public:
vvm_signal_t(const string&n, vvm_bitset_t<WIDTH>*b)
: vvm_monitor_t(n), bits_(b)
{ }
vvm_signal_t(vvm_bitset_t<WIDTH>*b)
{ bits = b->bits;
nbits = WIDTH;
}
~vvm_signal_t() { }
void init(unsigned idx, vvm_bit_t val)
{ (*bits_)[idx] = val; }
void init_P(unsigned idx, vpip_bit_t val)
{ bits[idx] = val; }
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ (*bits_)[idx] = val;
trigger(sim);
void set_P(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ bits[idx] = val;
vpip_run_value_changes(this);
}
void set(vvm_simulation*sim, const vvm_bitset_t<WIDTH>&val)
void set_P(vvm_simulation*sim, const vvm_bitset_t<WIDTH>&val)
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
set(sim, idx, val[idx]);
}
};
struct vvm_ram_callback {
vvm_ram_callback();
virtual ~vvm_ram_callback();
virtual void handle_write(vvm_simulation*sim, unsigned idx) =0;
vvm_ram_callback*next_;
};
template <unsigned WIDTH, unsigned SIZE>
class vvm_memory_t : public __vpiMemory {
public:
vvm_memory_t()
{ cb_list_ = 0;
}
void set_word(vvm_simulation*sim, unsigned addr,
const vvm_bitset_t<WIDTH>&val)
{ unsigned base = WIDTH * addr;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
bits[base+idx] = val[idx];
call_list_(sim, addr);
}
vvm_bitset_t<WIDTH> get_word(unsigned addr) const
{ vvm_bitset_t<WIDTH> val;
unsigned base = WIDTH * addr;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
val[idx] = bits[base+idx];
return val;
}
void set_callback(vvm_ram_callback*ram)
{ ram->next_ = cb_list_;
cb_list_ = ram;
}
private:
vvm_bitset_t<WIDTH>*bits_;
vvm_ram_callback*cb_list_;
void call_list_(vvm_simulation*sim, unsigned idx)
{ for (vvm_ram_callback*cur = cb_list_; cur; cur = cur->next_)
cur->handle_write(sim, idx);
}
};
/*
* $Log: vvm.h,v $
* Revision 1.24 1999/12/02 03:36:01 steve
* shiftl and shiftr take unsized second parameter.
*
* Revision 1.23 1999/11/22 00:30:52 steve
* Detemplate some and, or and nor methods.
*
* Revision 1.22 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.21 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
* Revision 1.20 1999/11/01 02:07:41 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.19 1999/10/31 04:11:28 steve
* Add to netlist links pin name and instance number,
* and arrange in vvm for pin connections by name
* and instance number.
*
* Revision 1.18 1999/10/29 03:37:22 steve
* Support vpiValueChance callbacks.
*
* Revision 1.17 1999/10/28 21:36:00 steve
* Get rid of monitor_t and fold __vpiSignal into signal.
*
* Revision 1.16 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.15 1999/10/13 03:15:51 steve
* Remove useless operator=.
*
* Revision 1.14 1999/10/06 01:28:18 steve
* The $finish task should work immediately.
*
* Revision 1.13 1999/10/05 04:02:10 steve
* Relaxed width handling for <= assignment.
*
* Revision 1.12 1999/09/29 18:36:04 steve
* Full case support
*
* Revision 1.11 1999/09/28 01:13:15 steve
* Support in vvm > and >= behavioral operators.
*
* Revision 1.10 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
* Revision 1.9 1999/06/21 01:02:34 steve
* Add init to vvm_signal_t.
*
+65 -3
View File
@@ -17,12 +17,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_bit.cc,v 1.2 1998/11/10 00:48:31 steve Exp $"
#ident "$Id: vvm_bit.cc,v 1.7 1999/12/02 03:36:01 steve Exp $"
#endif
# include "vvm.h"
# include <iostream>
ostream& operator << (ostream&os, vvm_bit_t bit)
ostream& operator << (ostream&os, vpip_bit_t bit)
{
switch (bit) {
case V0:
@@ -41,6 +42,20 @@ ostream& operator << (ostream&os, vvm_bit_t bit)
return os;
}
bool posedge(vpip_bit_t from, vpip_bit_t to)
{
switch (from) {
case V1:
return false;
case V0:
return from != to;
case Vx:
case Vz:
return to == V1;
}
return false;
}
ostream& operator << (ostream&os, const vvm_bits_t&str)
{
os << str.get_width() << "b'";
@@ -54,7 +69,34 @@ vvm_bits_t::~vvm_bits_t()
{
}
vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry)
unsigned vvm_bits_t::as_unsigned() const
{
unsigned result = 0;
unsigned width = get_width();
for (unsigned idx = width ; idx > 0 ; idx -= 1) {
result <<= 1;
switch (get_bit(idx-1)) {
case V0:
case Vx:
case Vz:
break;
case V1:
result |= 1;
break;
}
}
return result;
}
vvm_ram_callback::vvm_ram_callback()
{
}
vvm_ram_callback::~vvm_ram_callback()
{
}
vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry)
{
unsigned li, ri, ci;
switch (l) {
@@ -100,6 +142,26 @@ vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry)
/*
* $Log: vvm_bit.cc,v $
* Revision 1.7 1999/12/02 03:36:01 steve
* shiftl and shiftr take unsized second parameter.
*
* Revision 1.6 1999/11/22 00:30:52 steve
* Detemplate some and, or and nor methods.
*
* Revision 1.5 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.4 1999/11/01 02:07:41 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.3 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.2 1998/11/10 00:48:31 steve
* Add support it vvm target for level-sensitive
* triggers (i.e. the Verilog wait).
+113 -136
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-1999 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,153 +17,130 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_calltf.cc,v 1.2 1999/05/31 15:46:36 steve Exp $"
#ident "$Id: vvm_calltf.cc,v 1.9 1999/11/28 18:05:37 steve Exp $"
#endif
# include "vvm_calltf.h"
# include <vpi_user.h>
# include "vpi_priv.h"
# include <new>
# include <iostream>
# include <assert.h>
# include <stdlib.h>
# include <stdarg.h>
# include <malloc.h>
# include <stdio.h>
# include <dlfcn.h>
vvm_calltf_parm::vvm_calltf_parm()
: type_(NONE)
# define MAX_PATHLEN 1024
static char*module_path = 0;
void vvm_set_module_path(const char*path)
{
}
vvm_calltf_parm::vvm_calltf_parm(TYPE t)
: type_(t)
{
assert((t == NONE) || (t == TIME));
}
void vvm_calltf_parm::release_()
{
switch (type_) {
case NONE:
case TIME:
case ULONG:
break;
case STRING:
((string*)string_)->string::~string();
break;
case BITS:
break;
}
type_ = NONE;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (unsigned long val)
{
release_();
type_ = ULONG;
ulong_ = val;
return *this;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (const string&val)
{
release_();
type_ = STRING;
new (string_) string (val);
return *this;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm::SIG&val)
{
release_();
type_ = BITS;
bits_ = val;
return *this;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm&that)
{
if (this == &that)
return *this;
release_();
switch (that.type_) {
case NONE:
case TIME:
type_ = that.type_;
break;
case ULONG:
type_ = ULONG;
ulong_ = that.ulong_;
break;
case STRING:
type_ = STRING;
new (string_) string (that.as_string());
break;
case BITS:
type_ = BITS;
bits_ = that.bits_;
break;
}
return *this;
}
vvm_calltf_parm::~vvm_calltf_parm()
{
release_();
}
extern void Sdisplay(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms);
extern void Smonitor(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms);
static void Sfinish(vvm_simulation*sim, const string&,
unsigned, class vvm_calltf_parm*)
{
sim->s_finish();
}
static struct {
const string name;
void (*func)(vvm_simulation*, const string&,
unsigned, class vvm_calltf_parm*);
} sys_table[] = {
{ "$display", &Sdisplay },
{ "$finish", &Sfinish },
{ "$monitor", &Smonitor },
{ "", 0 }
};
void vvm_calltask(vvm_simulation*sim, const string&fname,
unsigned nparms, class vvm_calltf_parm*parms)
{
for (unsigned idx = 0 ; sys_table[idx].func ; idx += 1)
if (fname == sys_table[idx].name) {
sys_table[idx].func(sim, fname, nparms, parms);
return;
}
cout << "Call " << fname << "(";
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
if (idx > 0) cout << ", ";
switch (parms[idx].type()) {
case vvm_calltf_parm::NONE:
break;
case vvm_calltf_parm::ULONG:
cout << parms[idx].as_ulong();
break;
case vvm_calltf_parm::STRING:
cout << "\"" << parms[idx].as_string() << "\"";
break;
case vvm_calltf_parm::BITS:
cout << *parms[idx].as_bits();
break;
case vvm_calltf_parm::TIME:
break;
}
}
cout << ")" << endl;
if (module_path) free(module_path);
module_path = strdup(path);
}
/*
* The load_vpi_module function attempts to locate and load the named
* vpi module and call the included startup routines. This is invoked
* by the generated C++ code to load all the modules that the
* simulation requires.
*
* If there is a '/' character in the name, or there is no
* VPI_MODULE_PATH, the the name is usd as is. No path is searched for
* the module.
*
* If there is a VPI_MODULE_PATH and there is no '/' in the name, the
* VPI_MODULE_PATH is taken as a ':' separated list of directory
* names. Each directory is searched for a module with the right name
* that will link in. The current working directory is not implicitly
* tried. If you wish '.' be in th search path, include it.
*/
typedef void (*vlog_startup_routines_t)(void);
void vvm_load_vpi_module(const char*name)
{
void*mod = 0;
const char*path = getenv("VPI_MODULE_PATH");
if (path == 0) path = module_path;
if ((path == 0) || (strchr(name, '/'))) {
mod = dlopen(name, RTLD_NOW);
if (mod == 0) {
cerr << name << ": " << dlerror() << endl;
return;
}
} else {
const char*cur = path;
const char*ep;
for (cur = path ; cur ; cur = ep? ep+1 : 0) {
char dest[MAX_PATHLEN+1];
ep = strchr(cur, ':');
size_t n = ep? ep-cur : strlen(cur);
if ((n + strlen(name) + 2) > sizeof dest)
continue;
strncpy(dest, cur, n);
dest[n] = '/';
dest[n+1] = 0;
strcat(dest, name);
mod = dlopen(dest, RTLD_NOW);
if (mod) break;
}
}
if (mod == 0) {
cerr << dlerror() << endl;
return;
}
void*table = dlsym(mod, "vlog_startup_routines");
vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table;
if (routines == 0) {
cerr << name << ": Unable to locate the vlog_startup_routines"
" table." << endl;
dlclose(mod);
return;
}
for (unsigned idx = 0 ; routines[idx] ; idx += 1)
(routines[idx])();
}
/*
* $Log: vvm_calltf.cc,v $
* Revision 1.9 1999/11/28 18:05:37 steve
* Set VPI_MODULE_PATH in the target code, if desired.
*
* Revision 1.8 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.7 1999/10/10 14:57:38 steve
* Handle display of odd octal/hex widths (Eric Ardoom)
*
* Revision 1.6 1999/09/29 01:41:18 steve
* Support the $write system task, and have the
* vpi_scan function free iterators as needed.
*
* Revision 1.5 1999/09/13 03:08:10 steve
* fix vpiHexStrVal dumping of digits to strings.
*
* Revision 1.4 1999/08/19 02:51:11 steve
* Add vpi_sim_control
*
* Revision 1.3 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
* Revision 1.2 1999/05/31 15:46:36 steve
* Handle time in more places.
*
+17 -52
View File
@@ -19,69 +19,34 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_calltf.h,v 1.1 1998/11/09 23:44:11 steve Exp $"
#ident "$Id: vvm_calltf.h,v 1.4 1999/11/28 18:05:37 steve Exp $"
#endif
# include "vvm.h"
# include <string>
/*
* The vvm environment supports external calls to C++ by
* vvm_calltask. The code generator generates calls to vvm_calltask
* that corresponds to the system call in the Verilog source. The
* vvm_calltask in turn locates the function (by name) and calls the
* C++ code that implements the task.
*
* The parameters of the task are implemented as an array of
* vvm_calltf_parm objects. Each object represents a paramter from the
* source.
* This function loads a vpi module by name.
*/
class vvm_calltf_parm {
extern void vvm_set_module_path(const char*path);
extern void vvm_load_vpi_module(const char*path);
public:
enum TYPE { NONE, ULONG, STRING, BITS, TIME };
vvm_calltf_parm();
explicit vvm_calltf_parm(TYPE);
vvm_calltf_parm(const vvm_calltf_parm&);
~vvm_calltf_parm();
TYPE type() const { return type_; }
struct SIG {
vvm_bits_t*bits;
vvm_monitor_t*mon;
};
unsigned long as_ulong() const { return ulong_; }
string as_string() const { return *(string*)string_; }
vvm_bits_t* as_bits() const { return bits_.bits; }
vvm_monitor_t* as_mon() const { return bits_.mon; }
const string& sig_name() const { return bits_.mon->name(); }
vvm_calltf_parm& operator= (unsigned long);
vvm_calltf_parm& operator= (const string&);
vvm_calltf_parm& operator= (const SIG&);
vvm_calltf_parm& operator= (const vvm_calltf_parm&);
private:
TYPE type_;
union {
unsigned long ulong_;
char string_[sizeof(string)];
SIG bits_;
};
void release_();
};
extern void vvm_calltask(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms);
/*
* $Log: vvm_calltf.h,v $
* Revision 1.4 1999/11/28 18:05:37 steve
* Set VPI_MODULE_PATH in the target code, if desired.
*
* Revision 1.3 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.2 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
+19 -1
View File
@@ -17,18 +17,36 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_event.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
#ident "$Id: vvm_event.cc,v 1.2 1999/10/28 00:47:25 steve Exp $"
#endif
# include "vvm.h"
# include <assert.h>
vvm_event::vvm_event()
{
event_ = 0;
}
vvm_event::~vvm_event()
{
}
void vvm_event::callback_(void*cbd)
{
vvm_event*obj = reinterpret_cast<vvm_event*>(cbd);
obj->event_function();
delete obj;
}
/*
* $Log: vvm_event.cc,v $
* Revision 1.2 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
+313 -5
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_func.h,v 1.7 1999/06/24 04:20:47 steve Exp $"
#ident "$Id: vvm_func.h,v 1.16 1999/12/02 03:36:01 steve Exp $"
#endif
# include "vvm.h"
@@ -78,6 +78,13 @@ vvm_bitset_t<1> vvm_unop_or(const vvm_bitset_t<WIDTH>&r)
return res;
}
template <unsigned WIDTH>
vvm_bitset_t<1> vvm_unop_nor(const vvm_bitset_t<WIDTH>&r)
{
vvm_bitset_t<1>res = vvm_unop_or(r);
return vvm_unop_not(res);
}
template <unsigned WIDTH>
vvm_bitset_t<1> vvm_unop_lnot(const vvm_bitset_t<WIDTH>&r)
{
@@ -85,6 +92,44 @@ vvm_bitset_t<1> vvm_unop_lnot(const vvm_bitset_t<WIDTH>&r)
return vvm_unop_not(res);
}
/*
* The unary XOR is the reduction XOR. It returns a single bit.
*/
template <unsigned WIDTH>
vvm_bitset_t<1> vvm_unop_xor(const vvm_bitset_t<WIDTH>&r)
{
vvm_bitset_t<1> res;
res[0] = V0;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
if (r[idx] == V1)
res[0] = not(res[0]);
}
return res;
}
template <unsigned WIDTH>
vvm_bitset_t<1> vvm_unop_xnor(const vvm_bitset_t<WIDTH>&r)
{
return not(vvm_unop_xor(r));
}
//
// simple-minded unary minus operator (two's complement)
//
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_unop_uminus(const vvm_bitset_t<WIDTH>&l)
{
vvm_bitset_t<WIDTH> res;
res = vvm_unop_not(l);
vpip_bit_t carry = V1;
for (int i = 0; i < WIDTH; i++)
res[i] = add_with_carry(res[i], V0, carry);
return res;
}
/*
* Implement the binary AND operator. This is a bitwise and with all
* the parameters and the result having the same width.
@@ -125,7 +170,7 @@ vvm_bitset_t<WIDTH> vvm_binop_plus(const vvm_bitset_t<WIDTH>&l,
const vvm_bitset_t<WIDTH>&r)
{
vvm_bitset_t<WIDTH> result;
vvm_bit_t carry = V0;
vpip_bit_t carry = V0;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
result[idx] = add_with_carry(l[idx], r[idx], carry);
@@ -143,7 +188,7 @@ vvm_bitset_t<WIDTH> vvm_binop_minus(const vvm_bitset_t<WIDTH>&l,
{
vvm_bitset_t<WIDTH> res;
res = vvm_unop_not(r);
vvm_bit_t carry = V1;
vpip_bit_t carry = V1;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
res[idx] = add_with_carry(l[idx], res[idx], carry);
@@ -165,6 +210,40 @@ vvm_bitset_t<WIDTH> vvm_binop_xor(const vvm_bitset_t<WIDTH>&l,
return result;
}
/*
* the binary 'l' operator is a logic left-shift by the number of positions
* indicated by argument r. r is an unsigned integer, which is represented
* internally as a 32-bit bitvector.
*/
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_binop_shiftl(const vvm_bitset_t<WIDTH>&l,
const vvm_bits_t&r)
{
vvm_bitset_t<WIDTH> result;
vvm_u32 s = r.as_unsigned();
for (unsigned idx = 0; idx < WIDTH; idx++)
result[idx] = (idx < s) ? V0 : l[idx-s];
return result;
}
/*
* The binary 'r' operator is a logic right-shift by the number of positions
* indicated by argument r. r is an unsigned integer, which is represented
* internally by a 32-bit bitvector.
*/
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_binop_shiftr(const vvm_bitset_t<WIDTH>&l,
const vvm_bits_t&r)
{
vvm_bitset_t<WIDTH> result;
vvm_u32 s = r.as_unsigned();
for (unsigned idx = 0; idx < WIDTH; idx++)
result[idx] = (idx < (WIDTH-s)) ? l[idx+s] : V0;
return result;
}
/*
* Tests for equality are a bit tricky, as they allow for the left and
* right subexpressions to have different size. The shorter bitset is
@@ -239,6 +318,10 @@ vvm_bitset_t<1> vvm_binop_eq(const vvm_bitset_t<LW>&l,
}
}
/*
* This function return true if all the bits are the same. Even x and
* z bites are compared for equality.
*/
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_eeq(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
@@ -277,6 +360,112 @@ vvm_bitset_t<1> vvm_binop_eeq(const vvm_bitset_t<LW>&l,
return result;
}
/*
* This function return true if all the bits are the same. The x and z
* bits are don't care, s don't make the result false.
*/
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_xeq(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V1;
if (LW <= RW) {
for (unsigned idx = 0 ; idx < LW ; idx += 1) {
if ((l[idx] == Vz) || (r[idx] == Vz))
continue;
if ((l[idx] == Vx) || (r[idx] == Vx))
continue;
if (l[idx] != r[idx]) {
result[0] = V0;
return result;
}
}
for (unsigned idx = LW ; idx < RW ; idx += 1) {
if ((r[idx] == Vx) || (r[idx] == Vz))
continue;
if (r[idx] != V0) {
result[0] = V0;
return result;
}
}
} else {
for (unsigned idx = 0 ; idx < RW ; idx += 1) {
if ((l[idx] == Vz) || (r[idx] == Vz))
continue;
if ((l[idx] == Vx) || (r[idx] == Vx))
continue;
if (l[idx] != r[idx]) {
result[0] = V0;
return result;
}
}
for (unsigned idx = RW ; idx < LW ; idx += 1) {
if ((l[idx] == Vx) || (l[idx] == Vz))
continue;
if (l[idx] != V0) {
result[0] = V0;
return result;
}
}
}
return result;
}
/*
* This function return true if all the bits are the same. The z
* bits are don't care, so don't make the result false.
*/
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_zeq(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V1;
if (LW <= RW) {
for (unsigned idx = 0 ; idx < LW ; idx += 1) {
if ((l[idx] == Vz) || (r[idx] == Vz))
continue;
if (l[idx] != r[idx]) {
result[0] = V0;
return result;
}
}
for (unsigned idx = LW ; idx < RW ; idx += 1) {
if (r[idx] == Vz)
continue;
if (r[idx] != V0) {
result[0] = V0;
return result;
}
}
} else {
for (unsigned idx = 0 ; idx < RW ; idx += 1) {
if ((l[idx] == Vz) || (r[idx] == Vz))
continue;
if (l[idx] != r[idx]) {
result[0] = V0;
return result;
}
}
for (unsigned idx = RW ; idx < LW ; idx += 1) {
if (l[idx] == Vz)
continue;
if (l[idx] != V0) {
result[0] = V0;
return result;
}
}
}
return result;
}
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_ne(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
@@ -299,12 +488,87 @@ template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_lt(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
assert(LW == RW);
vvm_bitset_t<1> result;
result[0] = V0;
for (unsigned idx = 0 ; idx < LW ; idx += 1)
const unsigned common = (LW < RW)? LW : RW;
for (unsigned idx = 0 ; idx < common ; idx += 1)
result[0] = less_with_cascade(l[idx], r[idx], result[0]);
if (LW > RW) {
for (unsigned idx = RW ; idx < LW ; idx += 1)
result[0] = less_with_cascade(l[idx], V0, result[0]);
} else {
for (unsigned idx = LW ; idx < RW ; idx += 1)
result[0] = less_with_cascade(V0, r[idx], result[0]);
}
return result;
}
/*
* The <= operator takes operands of natural width and returns a
* single bit. The result is V1 if l <= r, otherwise V0;
*/
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_le(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V1;
const unsigned common = (LW < RW)? LW : RW;
for (unsigned idx = 0 ; idx < common ; idx += 1)
result[0] = less_with_cascade(l[idx], r[idx], result[0]);
if (LW > RW) {
for (unsigned idx = RW ; idx < LW ; idx += 1)
result[0] = less_with_cascade(l[idx], V0, result[0]);
} else {
for (unsigned idx = LW ; idx < RW ; idx += 1)
result[0] = less_with_cascade(V0, r[idx], result[0]);
}
return result;
}
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_gt(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V0;
const unsigned common = (LW < RW)? LW : RW;
for (unsigned idx = 0 ; idx < common ; idx += 1)
result[0] = greater_with_cascade(l[idx], r[idx], result[0]);
if (LW > RW) {
for (unsigned idx = RW ; idx < LW ; idx += 1)
result[0] = greater_with_cascade(l[idx], V0, result[0]);
} else {
for (unsigned idx = LW ; idx < RW ; idx += 1)
result[0] = greater_with_cascade(V0, r[idx], result[0]);
}
return result;
}
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_ge(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V1;
const unsigned common = (LW < RW)? LW : RW;
for (unsigned idx = 0 ; idx < common ; idx += 1)
result[0] = greater_with_cascade(l[idx], r[idx], result[0]);
if (LW > RW) {
for (unsigned idx = RW ; idx < LW ; idx += 1)
result[0] = greater_with_cascade(l[idx], V0, result[0]);
} else {
for (unsigned idx = LW ; idx < RW ; idx += 1)
result[0] = greater_with_cascade(V0, r[idx], result[0]);
}
return result;
}
@@ -328,8 +592,52 @@ vvm_bitset_t<1> vvm_binop_lor(const vvm_bitset_t<LW>&l,
return res1;
}
template <unsigned W>
vvm_bitset_t<W> vvm_ternary(vpip_bit_t c, const vvm_bitset_t<W>&t,
const vvm_bitset_t<W>&f)
{
switch (c) {
case V0:
return f;
case V1:
return t;
default:
return f;
}
}
/*
* $Log: vvm_func.h,v $
* Revision 1.16 1999/12/02 03:36:01 steve
* shiftl and shiftr take unsized second parameter.
*
* Revision 1.15 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.14 1999/10/05 06:19:47 steve
* Add support for reduction NOR.
*
* Revision 1.13 1999/10/01 15:26:29 steve
* Add some vvm operators from Eric Aardoom.
*
* Revision 1.12 1999/09/29 22:57:26 steve
* LT supports different width objects.
*
* Revision 1.11 1999/09/29 18:36:04 steve
* Full case support
*
* Revision 1.10 1999/09/28 01:13:16 steve
* Support in vvm > and >= behavioral operators.
*
* Revision 1.9 1999/09/23 04:39:52 steve
* The <= operator takes different width operands.
*
* Revision 1.8 1999/09/11 04:43:17 steve
* Support ternary and <= operators in vvm.
*
* Revision 1.7 1999/06/24 04:20:47 steve
* Add !== and === operators.
*
+159
View File
@@ -0,0 +1,159 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
* ---
* You should also have recieved a copy of the Picture Elements
* Binary Software License offer along with the source. This offer
* allows you to obtain the right to redistribute the software in
* binary (compiled) form. If you have not received it, contact
* Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704.
*/
#if !defined(WINNT)
#ident "$Id: vvm_gates.cc,v 1.3 1999/12/02 04:54:11 steve Exp $"
#endif
# include "vvm_gates.h"
vvm_out_event::vvm_out_event(vvm_simulation*s, vpip_bit_t v, action_t o)
: output_(o), sim_(s), val_(v)
{
}
vvm_out_event::~vvm_out_event()
{
}
void vvm_out_event::event_function()
{
output_(sim_, val_);
}
vvm_1bit_out::vvm_1bit_out(vvm_out_event::action_t o, unsigned d)
: output_(o), delay_(d)
{
}
vvm_1bit_out::~vvm_1bit_out()
{
}
void vvm_1bit_out::output(vvm_simulation*sim, vpip_bit_t val)
{
vvm_event*ev = new vvm_out_event(sim, val, output_);
if (delay_ > 0)
sim->insert_event(delay_, ev);
else
sim->active_event(ev);
}
vpip_bit_t compute_and(const vpip_bit_t*inp, unsigned count)
{
vpip_bit_t outval = inp[0];
for (unsigned i = 1 ; i < count ; i += 1)
outval = outval & inp[i];
return outval;
}
vpip_bit_t compute_or(const vpip_bit_t*inp, unsigned count)
{
vpip_bit_t outval = inp[0];
for (unsigned i = 1 ; i < count ; i += 1)
outval = outval | inp[i];
return outval;
}
vpip_bit_t compute_nor(const vpip_bit_t*inp, unsigned count)
{
vpip_bit_t outval = inp[0];
for (unsigned i = 1 ; i < count ; i += 1)
outval = outval | inp[i];
return not(outval);
}
vpip_bit_t compute_xor(const vpip_bit_t*inp, unsigned count)
{
vpip_bit_t outval = inp[0];
for (unsigned i = 1; i < count; i++)
outval = outval ^ inp[i];
return outval;
}
vpip_bit_t compute_nand(const vpip_bit_t*inp, unsigned count)
{
return not(compute_and(inp,count));
}
vpip_bit_t compute_xnor(const vpip_bit_t*inp, unsigned count)
{
return not(compute_xor(inp,count));
}
void compute_mux(vpip_bit_t*out, unsigned wid,
const vpip_bit_t*sel, unsigned swid,
const vpip_bit_t*dat, unsigned size)
{
unsigned tmp = 0;
for (unsigned idx = 0 ; idx < swid ; idx += 1)
switch (sel[idx]) {
case V0:
break;
case V1:
tmp |= (1<<idx);
break;
default:
tmp = size;
break;
}
if (tmp >= size) {
if (swid > 1) {
for (unsigned idx = 0; idx < wid ; idx += 1)
out[idx] = Vx;
} else {
const unsigned b0 = 0;
const unsigned b1 = wid;
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (dat[idx+b0] == dat[idx+b1])
out[idx] = dat[idx+b0];
else
out[idx] = Vx;
}
}
} else {
unsigned b = tmp * wid;
for (unsigned idx = 0; idx < wid ; idx += 1)
out[idx] = dat[idx+b];
}
}
/*
* $Log: vvm_gates.cc,v $
* Revision 1.3 1999/12/02 04:54:11 steve
* Handle mux sel of X, if inputs are equal.
*
* Revision 1.2 1999/11/24 04:38:49 steve
* LT and GT fixes from Eric Aardoom.
*
* Revision 1.1 1999/11/22 00:30:52 steve
* Detemplate some and, or and nor methods.
*
*/
+619 -179
View File
@@ -19,12 +19,23 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_gates.h,v 1.12 1999/07/17 03:07:27 steve Exp $"
#ident "$Id: vvm_gates.h,v 1.30 1999/12/02 16:58:58 steve Exp $"
#endif
# include "vvm.h"
# include <assert.h>
extern vpip_bit_t compute_nand(const vpip_bit_t*inp, unsigned count);
extern vpip_bit_t compute_and(const vpip_bit_t*inp, unsigned count);
extern vpip_bit_t compute_nor(const vpip_bit_t*inp, unsigned count);
extern vpip_bit_t compute_or(const vpip_bit_t*inp, unsigned count);
extern vpip_bit_t compute_xor(const vpip_bit_t*inp, unsigned count);
extern vpip_bit_t compute_xnor(const vpip_bit_t*inp, unsigned count);
extern void compute_mux(vpip_bit_t*out, unsigned wid,
const vpip_bit_t*sel, unsigned swid,
const vpip_bit_t*dat, unsigned size);
/*
* A vvm gate is constructed with an input width and an output
* function. The input width represents all the input signals that go
@@ -36,83 +47,533 @@
class vvm_out_event : public vvm_event {
public:
typedef void (*action_t)(vvm_simulation*, vvm_bit_t);
vvm_out_event(vvm_simulation*s, vvm_bit_t v, action_t o)
: output_(o), sim_(s), val_(v) { }
typedef void (*action_t)(vvm_simulation*, vpip_bit_t);
void event_function()
{ output_(sim_, val_); }
vvm_out_event(vvm_simulation*s, vpip_bit_t v, action_t o);
~vvm_out_event();
void event_function();
private:
const action_t output_;
vvm_simulation*const sim_;
const vvm_bit_t val_;
const vpip_bit_t val_;
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_and {
class vvm_1bit_out {
public:
vvm_1bit_out(vvm_out_event::action_t, unsigned delay);
~vvm_1bit_out();
void output(vvm_simulation*sim, vpip_bit_t);
private:
vvm_out_event::action_t output_;
unsigned delay_;
};
/*
* This template implements the LPM_ADD_SUB device type. The width of
* the device is a template parameter. The device handles addition and
* subtraction, selectable by the Add_Sub input. When configured as a
* subtractor, the device works by adding the 2s complement of
* DataB.
*/
template <unsigned WIDTH> class vvm_add_sub {
public:
vvm_add_sub() : ndir_(V0) { }
void config_rout(unsigned idx, vvm_out_event::action_t a)
{ o_[idx] = a;
}
void init_DataA(unsigned idx, vpip_bit_t val)
{ a_[idx] = val;
}
void init_DataB(unsigned idx, vpip_bit_t val)
{ b_[idx] = val;
}
void init_Add_Sub(unsigned, vpip_bit_t val)
{ ndir_ = not(val);
}
void set_DataA(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ a_[idx] = val;
compute_(sim);
}
void set_DataB(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ b_[idx] = val;
compute_(sim);
}
private:
vpip_bit_t a_[WIDTH];
vpip_bit_t b_[WIDTH];
vpip_bit_t r_[WIDTH];
// this is the inverse of the Add_Sub port. It is 0 for add,
// and 1 for subtract.
vpip_bit_t ndir_;
vvm_out_event::action_t o_[WIDTH];
void compute_(vvm_simulation*sim)
{ vpip_bit_t carry = ndir_;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
vpip_bit_t val;
val = add_with_carry(a_[idx], b_[idx] ^ ndir_, carry);
if (val == r_[idx]) continue;
r_[idx] = val;
if (o_[idx] == 0) continue;
vvm_event*ev = new vvm_out_event(sim, val, o_[idx]);
sim->insert_event(0, ev);
}
}
};
template <unsigned WIDTH, unsigned long DELAY>
class vvm_and : private vvm_1bit_out {
public:
explicit vvm_and(vvm_out_event::action_t o)
: output_(o) { }
: vvm_1bit_out(o, DELAY) { }
void init(unsigned idx, vvm_bit_t val)
{ input_[idx-1] = val; }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void start(vvm_simulation*sim)
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
{ output(sim, compute_and(input_,WIDTH)); }
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ if (input_[idx-1] == val)
return;
input_[idx-1] = val;
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val) return;
input_[idx] = val;
output(sim, compute_and(input_,WIDTH));
}
private:
vvm_bit_t compute_() const
{ vvm_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval & input_[i];
return outval;
}
vvm_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
vpip_bit_t input_[WIDTH];
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_or {
template <unsigned WIDTH, unsigned WDIST> class vvm_clshift {
public:
explicit vvm_clshift()
{ dir_ = V0;
dist_val_ = WIDTH;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
data_[idx] = Vx;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
out_[idx] = 0;
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
dist_[idx] = Vx;
}
~vvm_clshift() { }
void init_Data(unsigned idx, vpip_bit_t val)
{ data_[idx] = val;
}
void init_Distance(unsigned idx, vpip_bit_t val)
{ dist_[idx] = val;
calculate_dist_();
}
void init_Direction(vpip_bit_t val)
{ dir_ = val; }
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (data_[idx] == val) return;
data_[idx] = val;
if ((dist_val_ + idx) >= WIDTH) return;
if ((dist_val_ + idx) < 0) return;
vvm_out_event::action_t out = out_[dist_val_+idx];
if (out == 0) return;
vvm_event*ev = new vvm_out_event(sim, val, out);
sim->active_event(ev);
}
void set_Distance(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (dist_[idx] == val) return;
dist_[idx] = val;
calculate_dist_();
compute_(sim);
}
void set_Direction(vvm_simulation*sim, unsigned, vpip_bit_t val)
{ if (dir_ == val) return;
dir_ = val;
calculate_dist_();
compute_(sim);
}
void config_rout(unsigned idx, vvm_out_event::action_t o)
{ out_[idx] = o;
}
private:
vpip_bit_t dir_;
vpip_bit_t data_[WIDTH];
vpip_bit_t dist_[WDIST];
vvm_out_event::action_t out_[WIDTH];
int dist_val_;
void calculate_dist_()
{ int tmp = 0;
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
switch (dist_[idx]) {
case V0:
break;
case V1:
tmp |= 1<<idx;
break;
default:
tmp = WIDTH;
}
if (tmp > WIDTH)
tmp = WIDTH;
else if (dir_ == V1)
tmp = -tmp;
dist_val_ = tmp;
}
void compute_(vvm_simulation*sim)
{ vvm_event*ev;
if (dist_val_ == WIDTH) {
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
if (out_[idx] == 0) continue;
ev = new vvm_out_event(sim, Vx, out_[idx]);
sim->active_event(ev);
}
return;
}
for (int idx = 0 ; idx < WIDTH ; idx += 1) {
if (out_[idx] == 0) continue;
vpip_bit_t val;
if ((idx-dist_val_) >= WIDTH) val = V0;
else if ((idx-dist_val_) < 0) val = V0;
else val = data_[idx-dist_val_];
ev = new vvm_out_event(sim, val, out_[idx]);
sim->active_event(ev);
}
}
};
template <unsigned WIDTH> class vvm_compare {
public:
explicit vvm_compare()
{ out_lt_ = 0;
out_le_ = 0;
gt_ = Vx;
lt_ = Vx;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
a_[idx] = Vx;
b_[idx] = Vx;
}
}
~vvm_compare() { }
void init_DataA(unsigned idx, vpip_bit_t val)
{ a_[idx] = val; }
void init_DataB(unsigned idx, vpip_bit_t val)
{ b_[idx] = val; }
void set_DataA(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (a_[idx] == val) return;
a_[idx] = val;
compute_(sim);
}
void set_DataB(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (b_[idx] == val) return;
b_[idx] = val;
compute_(sim);
}
void config_ALB_out(vvm_out_event::action_t o)
{ out_lt_ = o; }
void config_ALEB_out(vvm_out_event::action_t o)
{ out_le_ = o; }
void config_AGB_out(vvm_out_event::action_t o)
{ out_gt_ = o; }
void config_AGEB_out(vvm_out_event::action_t o)
{ out_ge_ = o; }
private:
vpip_bit_t a_[WIDTH];
vpip_bit_t b_[WIDTH];
vpip_bit_t gt_;
vpip_bit_t lt_;
vvm_out_event::action_t out_lt_;
vvm_out_event::action_t out_le_;
vvm_out_event::action_t out_gt_;
vvm_out_event::action_t out_ge_;
void compute_(vvm_simulation*sim)
{ vpip_bit_t gt = V0;
vpip_bit_t lt = V0;
vvm_event*ev;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
gt = greater_with_cascade(a_[idx], b_[idx], gt);
lt = less_with_cascade(a_[idx], b_[idx], lt);
}
if ((gt_ == gt) && (lt_ == lt)) return;
gt_ = gt;
lt_ = lt;
if (out_lt_) {
ev = new vvm_out_event(sim, lt_, out_lt_);
sim->active_event(ev);
}
if (out_le_) {
ev = new vvm_out_event(sim, not(gt_), out_le_);
sim->active_event(ev);
}
if (out_gt_) {
ev = new vvm_out_event(sim, gt_, out_gt_);
sim->active_event(ev);
}
if (out_ge_) {
ev = new vvm_out_event(sim, not(lt_), out_ge_);
sim->active_event(ev);
}
}
};
/*
* This class simulates the LPM flip-flop device.
* XXXX Inverted clock not yet supported.
*/
template <unsigned WIDTH> class vvm_ff {
public:
explicit vvm_ff()
{ clk_ = Vx;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
q_[idx] = Vx;
}
~vvm_ff() { }
void init_Data(unsigned idx, vpip_bit_t val) { d_[idx] = val; }
void init_Clock(unsigned, vpip_bit_t val) { clk_ = val; }
void set_Clock(vvm_simulation*sim, unsigned, vpip_bit_t val)
{ if (val == clk_) return;
bool flag = posedge(clk_, val);
clk_ = val;
if (flag) latch_(sim);
}
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ d_[idx] = val;
}
void config_rout(unsigned idx, vvm_out_event::action_t o)
{ out_[idx] = o;
}
private:
vpip_bit_t d_[WIDTH];
vpip_bit_t q_[WIDTH];
vpip_bit_t clk_;
vvm_out_event::action_t out_[WIDTH];
void latch_(vvm_simulation*sim)
{ q_ = d_;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
if (out_[idx]) {
vvm_event*ev = new vvm_out_event(sim, q_[idx],
out_[idx]);
sim->active_event(ev);
}
}
};
/*
* This class supports mux devices. The width is the width of the data
* (or bus) path, SIZE is the number of alternative inputs and SELWID
* is the size (in bits) of the selector input.
*/
template <unsigned WIDTH, unsigned SIZE, unsigned SELWID> class vvm_mux {
public:
explicit vvm_mux()
{ unsigned idx;
for (idx = 0 ; idx < WIDTH ; idx += 1) out_[idx] = 0;
for (idx = 0 ; idx < WIDTH ; idx += 1) output_[idx] = Vx;
for (idx = 0 ; idx < SELWID; idx += 1) sel_[idx] = Vx;
for (idx = 0 ; idx < WIDTH*SIZE; idx += 1) input_[idx] = Vx;
}
void init_Sel(unsigned idx, vpip_bit_t val)
{ sel_[idx] = val; }
void init_Data(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void set_Sel(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (sel_[idx] == val) return;
sel_[idx] = val;
evaluate_(sim);
}
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val) return;
input_[idx] = val;
evaluate_(sim);
}
void config_rout(unsigned idx, vvm_out_event::action_t o)
{ out_[idx] = o; }
private:
vpip_bit_t sel_[SELWID];
vpip_bit_t input_[WIDTH * SIZE];
vpip_bit_t output_[WIDTH];
vvm_out_event::action_t out_[WIDTH];
void evaluate_(vvm_simulation*sim)
{ vpip_bit_t tmp[WIDTH];
compute_mux(tmp, WIDTH, sel_, SELWID, input_, SIZE);
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
if (tmp[idx] != output_[idx]) {
output_[idx] = tmp[idx];
vvm_event*ev = new vvm_out_event(sim,
output_[idx],
out_[idx]);
sim->active_event(ev);
}
}
};
template <unsigned WIDTH, unsigned long DELAY>
class vvm_or : private vvm_1bit_out {
public:
explicit vvm_or(vvm_out_event::action_t o)
: output_(o) { }
: vvm_1bit_out(o,DELAY) { }
void init(unsigned idx, vvm_bit_t val)
{ input_[idx-1] = val; }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void start(vvm_simulation*sim)
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
{ output(sim, compute_or(input_,WIDTH)); }
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
input_[idx] = val;
output(sim, compute_or(input_,WIDTH));
}
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ if (input_[idx-1] == val)
return;
input_[idx-1] = val;
private:
vpip_bit_t input_[WIDTH];
};
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
template <unsigned WIDTH, unsigned long DELAY>
class vvm_nor : private vvm_1bit_out {
public:
explicit vvm_nor(vvm_out_event::action_t o)
: vvm_1bit_out(o, DELAY) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void start(vvm_simulation*sim)
{ output(sim, compute_nor(input_,WIDTH)); }
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
input_[idx] = val;
output(sim, compute_nor(input_,WIDTH));
}
private:
vpip_bit_t input_[WIDTH];
};
template <unsigned WIDTH, unsigned AWIDTH, unsigned SIZE>
class vvm_ram_dq : protected vvm_ram_callback {
public:
vvm_ram_dq(vvm_memory_t<WIDTH,SIZE>*mem)
: mem_(mem)
{ mem->set_callback(this);
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
out_[idx] = 0;
for (unsigned idx = 0 ; idx < AWIDTH ; idx += 1)
addr_[idx] = Vx;
}
void init_Address(unsigned idx, vpip_bit_t val)
{ addr_[idx] = val; }
void set_Address(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (addr_[idx] == val) return;
addr_[idx] = val;
compute_();
send_out_(sim);
}
void handle_write(vvm_simulation*sim, unsigned idx)
{ if (idx == addr_val_) send_out_(sim); }
void config_rout(unsigned idx, vvm_out_event::action_t o)
{ out_[idx] = o; }
private:
vvm_memory_t<WIDTH,SIZE>*mem_;
vpip_bit_t addr_[AWIDTH];
vvm_out_event::action_t out_[WIDTH];
unsigned long addr_val_;
void compute_()
{ unsigned bit;
unsigned mask;
addr_val_ = 0;
for (bit = 0, mask = 1 ; bit < AWIDTH ; bit += 1, mask <<= 1)
if (addr_[bit] == V1) addr_val_ |= mask;
}
void send_out_(vvm_simulation*sim)
{ vvm_bitset_t<WIDTH>ov = mem_->get_word(addr_val_);
for (unsigned bit = 0 ; bit < WIDTH ; bit += 1)
if (out_[bit]) {
vvm_event*ev = new vvm_out_event(sim,
ov[bit],
out_[bit]);
sim->active_event(ev);
}
}
};
template <unsigned long DELAY> class vvm_buf {
public:
explicit vvm_buf(vvm_out_event::action_t o)
: output_(o)
{ }
void init_I(unsigned, vpip_bit_t) { }
void start(vvm_simulation*) { }
void set_I(vvm_simulation*sim, unsigned, vpip_bit_t val)
{ vpip_bit_t outval = val;
if (val == Vz) val = Vx;
vvm_event*ev = new vvm_out_event(sim, outval, output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
@@ -120,14 +581,6 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_or {
}
private:
vvm_bit_t compute_() const
{ vvm_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval | input_[i];
return outval;
}
vvm_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
};
@@ -140,7 +593,7 @@ template <unsigned long DELAY> class vvm_bufif1 {
input_[1] = Vx;
}
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx-1] == val)
return;
input_[idx-1] = val;
@@ -156,126 +609,115 @@ template <unsigned long DELAY> class vvm_bufif1 {
}
private:
vvm_bit_t input_[2];
vpip_bit_t input_[2];
vvm_out_event::action_t output_;
vvm_bit_t compute_() const
vpip_bit_t compute_() const
{ if (input_[1] != V1) return Vz;
if (input_[0] == Vz) return Vx;
return input_[0];
}
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_nand {
template <unsigned WIDTH, unsigned long DELAY>
class vvm_nand : private vvm_1bit_out {
public:
explicit vvm_nand(vvm_out_event::action_t o)
: output_(o)
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
input_[idx] = V0;
}
: vvm_1bit_out(o, DELAY) { }
void init(unsigned idx, vvm_bit_t val) { input_[idx-1] = val; }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
// Set an input of the NAND gate causes a new output value to
// be calculated and an event generated to make the output
// happen. The input pins are numbered from 1 - WIDTH.
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ if (input_[idx-1] == val)
return;
input_[idx-1] = val;
vvm_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval & input_[i];
void start(vvm_simulation*sim)
{ output(sim, compute_nand(input_,WIDTH)); }
vvm_event*ev = new vvm_out_event(sim, not(outval), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val) return;
input_[idx] = val;
output(sim, compute_nand(input_,WIDTH));
}
private:
vvm_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
vpip_bit_t input_[WIDTH];
};
/*
* Simple inverter buffer.
*/
template <unsigned long DELAY> class vvm_not {
template <unsigned long DELAY> class vvm_not : private vvm_1bit_out {
public:
explicit vvm_not(vvm_out_event::action_t o)
: output_(o)
{ }
: vvm_1bit_out(o, DELAY) { }
void init(unsigned, vvm_bit_t) { }
void init_I(unsigned, vpip_bit_t) { }
void start(vvm_simulation*) { }
void set(vvm_simulation*sim, unsigned, vvm_bit_t val)
{ vvm_bit_t outval = not(val);
vvm_event*ev = new vvm_out_event(sim, outval, output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
void set_I(vvm_simulation*sim, unsigned, vpip_bit_t val)
{ output(sim, not(val)); }
private:
vvm_out_event::action_t output_;
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_xnor {
template <unsigned WIDTH, unsigned long DELAY>
class vvm_xnor : private vvm_1bit_out {
public:
explicit vvm_xnor(vvm_out_event::action_t o)
: output_(o) { }
: vvm_1bit_out(o,DELAY) { }
void init_I(unsigned idx, vpip_bit_t val) { input_[idx] = val; }
void init(unsigned idx, vvm_bit_t val) { input_[idx-1] = val; }
void start(vvm_simulation*sim)
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
{ output(sim,compute_xnor(input_,WIDTH)); }
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ if (input_[idx-1] == val)
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
input_[idx-1] = val;
vvm_bit_t outval = compute_();
vvm_event*ev = new vvm_out_event(sim, outval, output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
input_[idx] = val;
output(sim,compute_xnor(input_,WIDTH));
}
private:
vvm_bit_t compute_() const
{ vvm_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval ^ input_[i];
outval = not(outval);
return outval;
}
vvm_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
vpip_bit_t input_[WIDTH];
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
template <unsigned WIDTH, unsigned long DELAY>
class vvm_xor : private vvm_1bit_out {
public:
explicit vvm_xor(vvm_out_event::action_t o)
: vvm_1bit_out(o,DELAY) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void start(vvm_simulation*sim)
{ output(sim,compute_xor(input_,WIDTH)); }
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
input_[idx] = val;
output(sim,compute_xor(input_,WIDTH)); }
private:
vpip_bit_t input_[WIDTH];
};
/*
* This gate has only 3 pins, the output at pin 0 and two inputs. The
* output is 1 or 0 if the two inputs are exactly equal or not.
*/
template <unsigned long DELAY> class vvm_eeq {
public:
explicit vvm_eeq(vvm_out_event::action_t o)
: output_(o) { }
void init(unsigned idx, vvm_bit_t val)
{ input_[idx-1] = val; }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void start(vvm_simulation*sim)
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
@@ -285,23 +727,23 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
sim->active_event(ev);
}
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ if (input_[idx-1] == val)
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
input_[idx-1] = val;
input_[idx] = val;
start(sim);
}
private:
vvm_bit_t compute_() const
{ vvm_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval ^ input_[i];
vpip_bit_t compute_() const
{ vpip_bit_t outval = V0;
if (input_[0] == input_[1])
outval = V1;
return outval;
}
vvm_bit_t input_[WIDTH];
vpip_bit_t input_[2];
vvm_out_event::action_t output_;
};
@@ -315,7 +757,7 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
template <unsigned WIDTH> class vvm_udp_ssequ {
public:
explicit vvm_udp_ssequ(vvm_out_event::action_t o, vvm_bit_t i,
explicit vvm_udp_ssequ(vvm_out_event::action_t o, vpip_bit_t i,
const vvm_u32*tab)
: output_(o), table_(tab)
{ state_[0] = i;
@@ -323,10 +765,10 @@ template <unsigned WIDTH> class vvm_udp_ssequ {
state_[idx] = Vx;
}
void init(unsigned pin, vvm_bit_t val)
void init(unsigned pin, vpip_bit_t val)
{ state_[pin] = val; }
void set(vvm_simulation*sim, unsigned pin, vvm_bit_t val)
void set(vvm_simulation*sim, unsigned pin, vpip_bit_t val)
{ assert(pin > 0);
assert(pin < WIDTH+1);
if (val == Vz) val = Vx;
@@ -353,8 +795,8 @@ template <unsigned WIDTH> class vvm_udp_ssequ {
code &= 3;
break;
}
// Convert the code to a vvm_bit_t and run with it.
vvm_bit_t outval = (code == 0)? V0 : (code == 1)? V1 : Vx;
// Convert the code to a vpip_bit_t and run with it.
vpip_bit_t outval = (code == 0)? V0 : (code == 1)? V1 : Vx;
state_[0] = outval;
state_[pin] = val;
vvm_event*ev = new vvm_out_event(sim, outval, output_);
@@ -364,7 +806,7 @@ template <unsigned WIDTH> class vvm_udp_ssequ {
private:
vvm_out_event::action_t output_;
const vvm_u32*const table_;
vvm_bit_t state_[WIDTH+1];
vpip_bit_t state_[WIDTH+1];
};
class vvm_bufz {
@@ -373,9 +815,9 @@ class vvm_bufz {
: output_(o)
{ }
void init(unsigned idx, vvm_bit_t val) { }
void init(unsigned idx, vpip_bit_t val) { }
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ output_(sim, val); }
private:
@@ -420,7 +862,7 @@ template <unsigned WIDTH> class vvm_pevent {
vvm_bitset_t<WIDTH> get() const { return value_; }
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
void set_P(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (value_[idx] == val) return;
switch (edge_) {
case ANYEDGE:
@@ -438,7 +880,7 @@ template <unsigned WIDTH> class vvm_pevent {
value_[idx] = val;
}
void init(int idx, vvm_bit_t val)
void init_P(int idx, vpip_bit_t val)
{ assert(idx < WIDTH);
value_[idx] = val;
}
@@ -455,48 +897,46 @@ template <unsigned WIDTH> class vvm_pevent {
/*
* $Log: vvm_gates.h,v $
* Revision 1.12 1999/07/17 03:07:27 steve
* pevent objects have initial values.
* Revision 1.30 1999/12/02 16:58:58 steve
* Update case comparison (Eric Aardoom).
*
* Revision 1.11 1999/06/09 00:58:29 steve
* Support for binary | (Stephen Tell)
* Revision 1.29 1999/12/02 04:54:11 steve
* Handle mux sel of X, if inputs are equal.
*
* Revision 1.10 1999/05/03 01:51:29 steve
* Restore support for wait event control.
* Revision 1.28 1999/11/25 01:34:04 steve
* Reduce more gate templates to use vvm_1bit_out (Eric Aardoom)
*
* Revision 1.9 1999/05/01 20:43:55 steve
* Handle wide events, such as @(a) where a has
* many bits in it.
* Revision 1.27 1999/11/24 04:38:49 steve
* LT and GT fixes from Eric Aardoom.
*
* Add to vvm the binary ^ and unary & operators.
* Revision 1.26 1999/11/22 00:30:52 steve
* Detemplate some and, or and nor methods.
*
* Dump events a bit more completely.
* Revision 1.25 1999/11/21 01:16:51 steve
* Fix coding errors handling names of logic devices,
* and add support for buf device in vvm.
*
* Revision 1.8 1999/05/01 02:57:53 steve
* Handle much more complex event expressions.
* Revision 1.24 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.7 1999/02/15 05:52:50 steve
* Mangle that handles device instance numbers.
* Revision 1.23 1999/11/15 00:42:31 steve
* Fixup to include right shift support.
*
* Revision 1.6 1999/01/31 18:15:55 steve
* Missing start methods.
* Revision 1.22 1999/11/14 23:43:46 steve
* Support combinatorial comparators.
*
* Revision 1.5 1999/01/01 01:44:56 steve
* Support the start() method.
* Revision 1.21 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.4 1998/12/20 02:05:41 steve
* Function to calculate wire initial value.
* Revision 1.20 1999/11/14 18:22:12 steve
* Fix NAND gate support to use named pins.
*
* Revision 1.3 1998/12/17 23:54:58 steve
* VVM support for small sequential UDP objects.
*
* Revision 1.2 1998/11/10 00:48:31 steve
* Add support it vvm target for level-sensitive
* triggers (i.e. the Verilog wait).
* Fix display of $time is format strings.
*
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
* Revision 1.19 1999/11/13 03:46:52 steve
* Support the LPM_MUX in vvm.
*
* Revision 1.18 1999/11/01 02:07:41 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*/
#endif
+23 -135
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-1999 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,101 +17,37 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_simulation.cc,v 1.4 1999/06/19 03:31:33 steve Exp $"
#ident "$Id: vvm_simulation.cc,v 1.7 1999/10/28 00:47:25 steve Exp $"
#endif
# include "vvm.h"
# include "vvm_thread.h"
# include "vpi_priv.h"
# include <assert.h>
/*
* The state of the simulation is stored as a list of simulation
* times. Each simulation time contains the delay to get to it, and
* also a list of events that are to execute here.
*
* The "events" member points to a list of inactive events to be made
* active as a group. Update events go into this list.
*
* The "nonblock" member points to a list of events to be executed
* only after ordinary events run out. This is intended to support the
* semantics of nonblocking assignment.
*/
struct vvm_simulation_cycle {
unsigned long delay;
struct vvm_simulation_cycle*next;
struct vvm_simulation_cycle*prev;
struct vvm_event*event_list;
struct vvm_event*event_last;
struct vvm_event*nonblock_list;
struct vvm_event*nonblock_last;
vvm_simulation_cycle()
: event_list(0), event_last(0), nonblock_list(0),
nonblock_last(0)
{ }
};
vvm_simulation::vvm_simulation()
{
sim_ = new vvm_simulation_cycle;
sim_->delay = 0;
sim_->next = sim_->prev = sim_;
mon_ = 0;
}
vvm_simulation::~vvm_simulation()
{
}
void vvm_simulation::insert_event(unsigned long delay, vvm_event*event)
void vvm_simulation::monitor_event(vvm_event*)
{
vvm_simulation_cycle*cur = sim_->next;
while ((cur != sim_) && (cur->delay < delay)) {
delay -= cur->delay;
cur = cur->next;
}
if ((cur == sim_) || (cur->delay > delay)) {
vvm_simulation_cycle*cell = new vvm_simulation_cycle;
cell->delay = delay;
if (cur != sim_)
cur->delay -= delay;
cell->next = cur;
cell->prev = cur->prev;
cell->next->prev = cell;
cell->prev->next = cell;
cur = cell;
}
event->next_ = 0;
if (cur->event_list == 0) {
cur->event_list = cur->event_last = event;
} else {
cur->event_last->next_ = event;
cur->event_last = event;
}
assert(0);
}
void vvm_simulation::monitor_event(vvm_event*event)
void vvm_simulation::insert_event(unsigned long delay, vvm_event*event)
{
mon_ = event;
event->event_ = vpip_sim_insert_event(delay, event,
vvm_event::callback_, 0);
}
void vvm_simulation::active_event(vvm_event*event)
{
event->next_ = 0;
if (sim_->event_list == 0) {
sim_->event_list = sim_->event_last = event;
} else {
sim_->event_last->next_ = event;
sim_->event_last = event;
}
event->event_ = vpip_sim_insert_event(0, event,
vvm_event::callback_, 0);
}
/*
@@ -121,62 +57,7 @@ void vvm_simulation::active_event(vvm_event*event)
*/
void vvm_simulation::run()
{
assert(sim_);
time_ = 0;
going_ = true;
while (going_) {
/* Step the time forward to the cycle I am about to
execute. */
time_ += sim_->delay;
sim_->delay = 0;
for (;;) {
/* Look for some events to make active. If the
main event list is empty, then activate the
nonblock list. */
vvm_event*active = sim_->event_list;
sim_->event_list = 0;
sim_->event_last = 0;
if (active == 0) {
active = sim_->nonblock_list;
sim_->nonblock_list = 0;
sim_->nonblock_last = 0;
}
/* Oops, no events left. Break out of this time cycle. */
if (active == 0)
break;
while (active) {
vvm_event*cur = active;
active = cur->next_;
cur->event_function();
delete cur;
}
}
/* XXXX Execute monitor events here. */
if (mon_) {
mon_->event_function();
mon_ = 0;
}
/* The time cycle is done, delete it from the list and
step to the next time. */
struct vvm_simulation_cycle*next = sim_->next;
if (next == sim_) {
going_ = false;
break;
}
sim_->next->prev = sim_->prev;
sim_->prev->next = sim_->next;
delete sim_;
sim_ = next;
}
vpip_simulation_run();
}
class delay_event : public vvm_event {
@@ -188,14 +69,9 @@ class delay_event : public vvm_event {
vvm_thread*thr_;
};
void vvm_simulation::s_finish()
{
going_ = false;
}
void vvm_simulation::thread_delay(unsigned long delay, vvm_thread*thr)
{
assert(delay > 0);
delay_event*ev = new delay_event(thr);
insert_event(delay, ev);
}
@@ -209,6 +85,18 @@ void vvm_simulation::thread_active(vvm_thread*thr)
/*
* $Log: vvm_simulation.cc,v $
* Revision 1.7 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.6 1999/10/06 01:28:18 steve
* The $finish task should work immediately.
*
* Revision 1.5 1999/09/29 02:53:33 steve
* Useless assertion.
*
* Revision 1.4 1999/06/19 03:31:33 steve
* End run if events run out.
*
+92
View File
@@ -0,0 +1,92 @@
For those of you who wish to use Icarus Verilog, in combination with
the Xilinx back end (Foundation or Alliance), it can be done. I have
run some admittedly simple (no arithmetic, 600 equivalent gates) designs
through this setup, targeting a Spartan XCS10.
Verilog:
As of Icarus Verilog 19990814, you still can't have logic buried
in procedural (flip-flop) assignment. I use a hacked workaround
copy of ivl that allows 1-bit wide logic. The other approach
is to use temporary wires, assign them to the logic, and assign
the reg to that wire. For example, instead of
always @ (posedge Clk) Z = ~Q1 & ~Q2 & ~Q3 & ~Q4;
you can write
wire newZ;
assign newZ = ~Q1 & ~Q2 & ~Q3 & ~Q4;
always @ (posedge Clk) Z = newZ;
Procedural assignments have to be given one at a time, to be
"found" by xnfsyn. Say
always @ (posedge Clk) Y = newY;
always @ (posedge Clk) Z = newZ;
rather than
always @ (posedge Clk) begin
Y = newY;
Z = newZ;
end
I had reason to use a global clock net. I used this snippet of
Verilog code to make it happen:
primitive BUFG ( O, I );
output O;
input I;
table
0:0;
1:1;
endtable
endprimitive
$attribute(BUFG,"XNF-LCA","BUFG:O,I")
Oh, yes, you probably also want to choose I/O pins! Try this:
wire d1;
$attribute(d1, "PAD", "i45"); // input
wire vsync;
$attribute(vsync, "PAD", "o67"); // output
Running ivl:
The -F switches are important. The following order seems to robustly
generate valid XNF files:
-Fxnfio -Fnobufz -Fsigfold -Fxnfsyn
Generating .pcf files:
The ngdbuild step seems to lose pin placement information that ivl
puts in the XNF file. Use xnf2pcf to extract this information to
a .pcf file, which the Xilinx place-and-route software _will_ pay
attention to.
Running the Xilinx back end:
You can presumably use the GUI, but that doesn't fit in Makefiles :-).
Here is the command sequence in pseudo-shell-script:
ngdbuild -p $part $1.xnf $1.ngd
map -p $part -o map.ncd $1.ngd
xnf2pcf <$1.xnf >$1.pcf # see above
par -w -ol 2 -d 0 map.ncd $1.ncd $1.pcf
bitgen_flags = -g ConfigRate:SLOW -g TdoPin:PULLNONE -g DonePin:PULLUP \
-g CRC:enable -g StartUpClk:CCLK -g SyncToDone:no \
-g DoneActive:C1 -g OutputsActive:C3 -g GSRInactive:C4 \
-g ReadClk:CCLK -g ReadCapture:enable -g ReadAbort:disable
bitgen $1.ncd -l -w $bitgen_flags
The Xilinx software has diarrhea of the temp files (14, not including
.xnf, .pcf, .ngd, .ncd, and .bit), so this sequence is best done in a
dedicated directory. Note in particular that map.ncd is a generic name.
Downloading:
I use the XESS (http://www.xess.com/) XSP-10 development board, which
uses the PC parallel (printer) port for downloading and interaction
with the host. They made an old version of their download program
public domain, posted it at
http://www.xess.com/FPGA/xstools.zip ,
and now there is a Linux port at
ftp://ftp.microux.com/pub/pilotscope/xstools.tar.gz .
The above hints are based on my experience with Foundation 1.5 on NT
(gack) and Alliance 2.1i on Solaris. Your mileage may vary. Good luck!
- Larry Doolittle <[email protected]> August 19, 1999
+123 -10
View File
@@ -10,7 +10,87 @@ may be useful even independent of Xilinx parts.
Icarus Verilog supports XNF as specified by the Xilinx Netlist Format
Specification, Version 6.1.
IVL SUPPORT FOR XNF
GENERATE XNF OUTPUT -- THE SHORT STORY
The easiest way to compile for XNF output is with the "verilog"
command (man verilog) and the -X switch:
% verilog -fpart=4010e -fncf=prog.ncf -X prog.v
This generates from the prog.v Verilog source file the prog.xnf output
and the prog.ncf netlist constraints file. The verilog program
arranges to call the preprocessor and the ivl compiler with all the
correct switches for generating XNF.
XNF PADS IN VERILOG SOURCE
You can assign wires to pads using the Icarus Verilog $attribute
extension. Attach to a scaler signal (wire or register) the PAD
attribute with the value that specifies the direction and pin
number. For example:
wire foo, bar, bid;
$attribute(foo, "PAD", "i1"); // Input pad on pin 1
$attribute(bar, "PAD", "o2"); // Output pad on pin 2
$attribute(bid, "PAD", "b3"); // Bi-directional pad on pin 3
The XNFIO function uses these attributes to locate signals that are
connected to pads, and generates XNF I/O block devices to connect to
the pad to do the FPGA pin buffering that is needed. So the Verilog
programmer need not in general specify the IBUF/OBUF buffers.
If the programmer does connect buffers to pads, the compiler will
notice them and convert them to I/OBUFs automatically. For example:
buf b1 (sig, foo);
connects to pad foo, so will be converted into an XNF IBUF
device. Also:
bufif1 bt (bar, value, en);
connects to pad bar so will automatically be converted into an OBUFT
device. Icarus Verilog understands OBUF, IBUF and OBUFT (with optionally
inverted enable) devices and will convert Verilog devices from the
source, or generate missing devices.
In addition, the Verilog programmer may explicitly declare a device as
an I/OBUF by attaching an attribute to the device, like so:
buf b1 (sig, foo);
$attribute(b1, "XNF-LCA", "OBUF:O,I");
This latter feature is not entirely recomended as it expects that the
programmer really knows how the pins of the XNF device are to be
connected. It also bypasses the efforts of the compiler, so is not
checked for correctness.
XNF SPECIAL DEVICES
There are certain special devices in XNF that Verilog does not
naturally represent, although there are similar more generic Verilog
devices. The most obvious and useful example is the clock driver,
otherwise known as the global buffer BUFG. As with pads, Icarus
Verilog uses the $attribute extension to allow you to specify special
devices.
The $attribute statement can be applied to devices much the same way
one applies them to wires. For example, to turn a buffer into a clock
buffer:
wire iclk, clk;
buf BUFG (clk, iclk);
$attribute(iclk, "PAD", "i1");
$attribute(BUFG, "XNF-LCA", "BUFG:O,I");
The above statements cause the buffer BUFG to be emitted in the XNF
output as a BUFG device with the first signal called "O" and the
second called "I". The rest of this example connects the input of the
BUFG to a signal from the input pin #1 and connects the output to the
internal wire "clk". Incidentally, this example will cause an IBUF to
be generated to connect the iclk signal to input pin #1.
SUMMARY OF IVL SUPPORT FOR XNF
Icarus Verilog has a code generator and synthesis functions that
support generation of XNF netlists. The XNF modules also allow the
@@ -22,15 +102,28 @@ line. The code generator needs to know the type of part to generate
code for, so the ``-fpart=<type>'' flag is also needed. For example,
to generate code for the 4010E the command line might start out as:
ivl -txnf -fpart=4010e -Fxnfsyn -Fxnfio [...]
ivl -txnf -fpart=4010e -Fsynth -Fnodangle -Fxnfio [...]
Icarus Verilog includes the functions ``xnfsyn'' and ``xnfio'' to
Icarus Verilog includes the functions ``synth'' and ``xnfio'' to
perform transformations and optimizations on the design before code is
generated. The xnfsyn function matches certain behavioral constructs
to XNF components, and the xnfio function generates pads and fills the
IOBs.
generated. The ``synth'' function matches certain behavioral constructs
to structural components, and the xnfio function generates pads and
fills the IOBs.
XNFSYN FUNCTION
SUPPORTED FLAGS
-fpart=<part>
Specify the type of part to target. This string is written
literally into the PART, record of the XNF, and may also be
used to control synthesis and placement.
-fncf=<path>
Cause the code generator to write into <path> the netlist
constraints needed for controlling placement and timing. This
switch is required if pin assignments are assigned in the
Verilog source.
THE SYNTH FUNCTION
This function does synthesis transformations on the entered design,
making it possible to generate XNF netlist components from certain
@@ -38,13 +131,13 @@ behavioral constructs. This is needed in Verilog for example to model
some of the synchronous components of the XNF library.
It is a bit much to expect a Verilog compiler in general to generate
components from arbitrary behavioral descriptions, so the xnfsyn
components from arbitrary behavioral descriptions, so the synth
function works by matching statements that have some documented
structure, and substituting them for the equivalent XNF component. A
fully synthesize-able design, then, is one where the behavioral
statements can all be matched and substituted by the xnfsyn function.
statements can all be matched and substituted by the synth function.
XNFIO FUNCTION
THE XNFIO FUNCTION
The "xnfio" function transforms the netlist where the IOBs are
concerned. The signals with PAD attributes are checked, and
@@ -83,6 +176,26 @@ IBUF, NOT gates cannot be absorbed as in the OPAD case.
$Log: xnf.txt,v $
Revision 1.9 1999/11/18 03:52:20 steve
Turn NetTmp objects into normal local NetNet objects,
and add the nodangle functor to clean up the local
symbols generated by elaboration and other steps.
Revision 1.8 1999/11/06 04:51:42 steve
Support writing some XNF things into an NCF file.
Revision 1.7 1999/11/03 05:18:18 steve
XNF synthesis now uses the synth functor.
Revision 1.6 1999/11/02 01:43:55 steve
Fix iobuf and iobufif handling.
Revision 1.5 1999/10/09 17:52:27 steve
support XNF OBUFT devices.
Revision 1.4 1999/08/14 22:48:21 steve
Mention the sigfold function.
Revision 1.3 1999/07/22 02:05:20 steve
is_constant method for PEConcat.
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
# xnf2pcf
# Converts perfectly good EXT records from an XNF file to
# a .pcf file for the "par" step of the Xilinx toolchain.
# Why on earth is this needed? Oh, well, the joys of working
# with black-box-ware.
# Usage: xnf2pcf <design.xnf >design.pcf
# Refer to the resulting .pcf file in the invocation of "par", syntax:
# par [options] infile[.ncd] outfile pcf_file[.pcf]
# Tested (successfully!) with XNF from Icarus Verilog, see
# http://www.geda.seul.org/tools/verilog/index.html
# and Xilinx back end tools from Foundation 1.5
# Author: Larry Doolittle <[email protected]>
# Date: August 19, 1999
echo "SCHEMATIC START ;"
echo "SCHEMATIC END ;"
echo
awk '/^EXT/{gsub(",",""); printf("COMP \"%s\" LOCATE = SITE \"P%s\" ;\n", $2, $4)}'
+125 -15
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: xnfio.cc,v 1.2 1999/07/17 22:01:14 steve Exp $"
#ident "$Id: xnfio.cc,v 1.9 1999/11/27 19:07:58 steve Exp $"
#endif
# include "functor.h"
@@ -49,13 +49,19 @@ static bool is_a_pad(const NetNet*net)
* really lame to not do the obvious optimization.
*/
static void make_obuf(Design*des, NetNet*net)
static NetLogic* make_obuf(Design*des, NetNet*net)
{
assert(net->pin_count() == 1);
/* FIXME: If there is nothing internally driving this PAD, I
can connect the PAD to a pullup and disconnect it from the
rest of the circuit. This would save routing resources. */
if (count_outputs(net->pin(0)) <= 0) {
cerr << net->get_line() << ":warning: No outputs to OPAD: "
<< net->name() << endl;
return 0;
}
assert(count_outputs(net->pin(0)) > 0);
/* Look for an existing OBUF connected to this signal. If it
@@ -68,11 +74,12 @@ static void make_obuf(Design*des, NetNet*net)
// Try to use an existing BUF as an OBUF. This moves the
// BUF into the IOB.
if ((tmp->type() == NetLogic::BUF) &&
(count_inputs(tmp->pin(0)) == 0) &&
(count_outputs(tmp->pin(0)) == 1)) {
if ((tmp->type() == NetLogic::BUF)
&& (count_inputs(tmp->pin(0)) == 0)
&& (count_outputs(tmp->pin(0)) == 1)
&& (idx->get_pin() == 0) ) {
tmp->attribute("XNF-LCA", "OBUF:O,I");
return;
return tmp;
}
// Try to use an existing INV as an OBUF. Certain
@@ -80,11 +87,32 @@ static void make_obuf(Design*des, NetNet*net)
// which looks just like an inverter. This uses the
// available resources of an IOB to optimize away an
// otherwise expensive inverter.
if ((tmp->type() == NetLogic::NOT) &&
(count_inputs(tmp->pin(0)) == 0) &&
(count_outputs(tmp->pin(0)) == 1)) {
if ((tmp->type() == NetLogic::NOT)
&& (count_inputs(tmp->pin(0)) == 0)
&& (count_outputs(tmp->pin(0)) == 1)
&& (idx->get_pin() == 0) ) {
tmp->attribute("XNF-LCA", "OBUF:O,~I");
return;
return tmp;
}
// Try to use an existing bufif1 as an OBUFT. Of course
// this will only work if the output of the bufif1 is
// connected only to the pad. Handle bufif0 the same
// way, but the T input is inverted.
if ((tmp->type() == NetLogic::BUFIF1)
&& (count_inputs(tmp->pin(0)) == 0)
&& (count_outputs(tmp->pin(0)) == 1)
&& (idx->get_pin() == 0) ) {
tmp->attribute("XNF-LCA", "OBUFT:O,I,~T");
return tmp;
}
if ((tmp->type() == NetLogic::BUFIF0)
&& (count_inputs(tmp->pin(0)) == 0)
&& (count_outputs(tmp->pin(0)) == 1)
&& (idx->get_pin() == 0) ) {
tmp->attribute("XNF-LCA", "OBUFT:O,I,T");
return tmp;
}
}
@@ -107,10 +135,64 @@ static void make_obuf(Design*des, NetNet*net)
// of the netlist, to create a ring without a signal. Detect
// this case and create a new signal.
if (count_signals(buf->pin(1)) == 0) {
NetNet*tmp = new NetNet(des->local_symbol("$"), NetNet::WIRE);
NetNet*tmp = new NetNet(0, des->local_symbol("$"), NetNet::WIRE);
tmp->local_flag(true);
connect(buf->pin(1), tmp->pin(0));
des->add_signal(tmp);
}
return buf;
}
static void absorb_OFF(Design*des, NetLogic*buf)
{
/* If the nexus connects is not a simple point-to-point link,
then I can't drag it into the IOB. Give up. */
if (count_outputs(buf->pin(1)) != 1)
return;
if (count_inputs(buf->pin(1)) != 1)
return;
/* For now, only support OUTFF. */
if (buf->type() != NetLogic::BUF)
return;
NetObj::Link*drv = find_next_output(&buf->pin(1));
assert(drv);
/* Make sure the device is a FF with width 1. */
NetFF*ff = dynamic_cast<NetFF*>(drv->get_obj());
if (ff == 0)
return;
if (ff->width() != 1)
return;
if (ff->attribute("LPM_FFType") != "DFF")
return;
/* Connect the flip-flop output to the buffer output and
delete the buffer. The XNF OUTFF can buffer the pin. */
connect(ff->pin_Q(0), buf->pin(0));
delete buf;
/* Finally, build up an XNF-LCA value that defines this
devices as an OUTFF and gives each pin an XNF name. */
char**names = new char*[ff->pin_count()];
for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1)
names[idx] = "";
if (ff->attribute("Clock:LPM_Polarity") == "INVERT")
names[ff->pin_Clock().get_pin()] = "~C";
else
names[ff->pin_Clock().get_pin()] = "C";
names[ff->pin_Data(0).get_pin()] = "D";
names[ff->pin_Q(0).get_pin()] = "Q";
string lname = string("OUTFF:") + names[0];
for (unsigned idx = 1 ; idx < ff->pin_count() ; idx += 1)
lname = lname + "," + names[idx];
delete[]names;
ff->attribute("XNF-LCA", lname);
}
static void make_ibuf(Design*des, NetNet*net)
@@ -156,7 +238,7 @@ static void make_ibuf(Design*des, NetNet*net)
// of the netlist, to create a ring without a signal. Detect
// this case and create a new signal.
if (count_signals(buf->pin(0)) == 0) {
NetNet*tmp = new NetNet(des->local_symbol("$"), NetNet::WIRE);
NetNet*tmp = new NetNet(0, des->local_symbol("$"), NetNet::WIRE);
connect(buf->pin(0), tmp->pin(0));
des->add_signal(tmp);
}
@@ -164,6 +246,7 @@ static void make_ibuf(Design*des, NetNet*net)
void xnfio_f::signal(Design*des, NetNet*net)
{
NetNode*buf;
if (! is_a_pad(net))
return;
@@ -176,9 +259,13 @@ void xnfio_f::signal(Design*des, NetNet*net)
make_ibuf(des, net);
break;
case 'o':
case 'O':
make_obuf(des, net);
break;
case 'O': {
NetLogic*buf = make_obuf(des, net);
if (buf == 0) break;
absorb_OFF(des, buf);
break;
}
// FIXME: Only IPAD and OPAD supported. Need to
// add support for IOPAD.
default:
@@ -195,6 +282,29 @@ void xnfio(Design*des)
/*
* $Log: xnfio.cc,v $
* Revision 1.9 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.8 1999/11/19 05:02:15 steve
* Handle inverted clock into OUTFF.
*
* Revision 1.7 1999/11/19 03:02:25 steve
* Detect flip-flops connected to opads and turn
* them into OUTFF devices. Inprove support for
* the XNF-LCA attribute in the process.
*
* Revision 1.6 1999/11/18 02:58:37 steve
* Handle (with a warning) unconnected opads.
*
* Revision 1.5 1999/11/02 04:55:01 steve
* repair the sense of T from bufif01
*
* Revision 1.4 1999/11/02 01:43:55 steve
* Fix iobuf and iobufif handling.
*
* Revision 1.3 1999/10/09 17:52:27 steve
* support XNF OBUFT devices.
*
* Revision 1.2 1999/07/17 22:01:14 steve
* Add the functor interface for functor transforms.
*

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