Compare commits

...
566 Commits
Author SHA1 Message Date
steve 02fc59fbdf Parse parameters within nested scopes. 2001-01-13 22:20:08 +00:00
steve 4e7a5d55d0 Handle error idents in constants not in any scope (PR#97) 2001-01-12 04:31:27 +00:00
steve 5fb7f9ca91 Generated function prototype. (PR#107) 2001-01-12 04:20:18 +00:00
steve 246f2d5884 Match memories within task scopes. (PR#101) 2001-01-10 05:32:44 +00:00
steve 5276752276 Build task outputs as lval instead of nets. (PR#98) 2001-01-10 03:13:23 +00:00
steve 6bf599e839 Cope with width mismatches to module ports (PR#89) 2001-01-09 05:58:47 +00:00
steve fff32b1b54 Clean up the jedec header that is written. 2001-01-09 04:41:32 +00:00
steve a64a4d7a9b Fixes to support compilation using vpath. 2001-01-09 03:11:27 +00:00
steve 9eb6f9dbb9 Generate the jedec to configure the macrocells. 2001-01-09 03:10:48 +00:00
steve 430e46d718 Assert on length of bit vector. 2001-01-07 18:22:15 +00:00
steve cd9a30707b Detect port direction attached to non-ports. 2001-01-07 07:00:31 +00:00
steve ad0853d666 Support signed decimal display of variables. 2001-01-06 22:22:17 +00:00
steve cc18d065aa declaration initialization for time variables. 2001-01-06 06:31:58 +00:00
steve 14c67a5389 James has moved. 2001-01-06 04:32:56 +00:00
steve 68e672e61a Support arrays of integers. 2001-01-06 02:29:35 +00:00
steve 2703456ad4 Document the -c flag. 2001-01-05 05:16:03 +00:00
steve 8ee00ec562 Fix net division to cope with small output sizes. 2001-01-05 03:19:47 +00:00
steve 8bfae1e641 Evaluate constant === and !== expressions. 2001-01-04 16:49:50 +00:00
steve 8befc6f7c4 Add support for << is signal indices. 2001-01-04 04:47:51 +00:00
steve d5ec89813d Evaluate constant logical && and ||. 2001-01-04 04:28:42 +00:00
steve ac7ae1ba6f Resolve repeat ambiguity in favor of loop. 2001-01-02 17:28:08 +00:00
steve 120a211e68 Support a bunch of unary operators in parameter expressions. 2001-01-02 04:21:13 +00:00
steve b6a18098c7 Evaluate constant &, | and unary ~. 2001-01-02 03:23:40 +00:00
steve 112936d661 Fix shift and ternary operators in parameter expressions (PR#86) 2001-01-01 21:49:33 +00:00
steve 4d09c43ecf Add $stop that does a finish. 2001-01-01 19:33:44 +00:00
steve 2a6f8634f6 repeat loops ambiguity. 2001-01-01 19:12:35 +00:00
steve 5803e8c42c Handle function scopes in dumpvars scn (PR#95) 2001-01-01 08:10:35 +00:00
steve eda3c63f72 reg_assign into function ports. (PR#95) 2001-01-01 01:41:09 +00:00
steve 365b149ec1 Propagate initial value of constants into wires. 2000-12-30 03:11:15 +00:00
steve e68c26bb87 Generate smaller code for reg assigns. 2000-12-17 05:33:11 +00:00
steve 4e7f8766fa Generate loops to initialize vectors or constants. 2000-12-16 23:55:24 +00:00
steve fe209a6996 Handle non-constant l-values. 2000-12-16 20:00:17 +00:00
steve f4671a3082 Evaluate <= and ?: in parameter expressions (PR#81) 2000-12-16 19:03:30 +00:00
steve c9881c115a Spelling error. 2000-12-16 17:16:08 +00:00
steve 0a3bda87d6 Observe delays in non-blocking assignments (PR#83) 2000-12-16 16:57:43 +00:00
steve 8ae4e25720 Detect recursive instantiations (PR#2) 2000-12-16 01:45:47 +00:00
steve 44131d4b16 Allow non-blocking assign to pad memory word with zeros. 2000-12-15 21:54:43 +00:00
steve d5eb3a2bad concatenation as parameter to system tasks. PR#64) 2000-12-15 21:40:26 +00:00
steve 086348035e Fix memory access in vvm. (PR#70) 2000-12-15 20:05:16 +00:00
steve 05b5b91a84 A dlerror implementatin that HP/UX might like. 2000-12-15 18:06:47 +00:00
steve bcbd5b2c5c Remove limits from the similar events search. 2000-12-15 17:45:07 +00:00
steve 8c680d158a Autoconfigure the dlopen functions. 2000-12-15 05:45:25 +00:00
steve 8fe6324aec functions with system tasks (PR#46) 2000-12-15 03:06:04 +00:00
steve 15a426cc73 remove dead macro. 2000-12-15 02:00:31 +00:00
steve 770dfe5eaa Trim dr from the string line. 2000-12-15 02:00:11 +00:00
steve 5144725b8f Accept x in outputs of primitive. (PR#84) 2000-12-15 01:24:17 +00:00
steve 189f55b894 rounding of time and x in primitives. 2000-12-15 00:21:46 +00:00
steve e836bc951d Detect -mdll support in Cygwin. 2000-12-14 23:38:04 +00:00
steve f0718b1345 Start support for fitting the logic. 2000-12-14 23:37:47 +00:00
steve 9cb91ce9aa Eat carriage returns. 2000-12-14 23:36:59 +00:00
steve 4abf4b0a9a include vpi_user.h. 2000-12-14 23:36:34 +00:00
steve 7d622fc6ab Support more logic gate types. 2000-12-14 23:23:07 +00:00
steve 3e73ec3e0f sorry for concatenated memories in l-values. (PR#76) 2000-12-12 06:14:51 +00:00
steve 36a1b37789 Fix truncated octal constants (PR#76) 2000-12-12 06:13:44 +00:00
steve e34ef2a2b9 NetEUFuncs are allowed as system task parameters. 2000-12-12 03:30:44 +00:00
steve fd0f618529 out-line vvm_bitset_t methods. 2000-12-12 03:30:25 +00:00
steve a010dd1cc0 Mangle [] characters. (PR#67) 2000-12-11 01:06:24 +00:00
steve 5dbea64759 Add support for signed reg variables,
simulate in t-vvm signed comparisons.
2000-12-11 00:31:43 +00:00
steve 084a464cf1 Support decimal constants in behavioral delays. 2000-12-10 22:01:35 +00:00
steve c0f951c146 vpiStringVal handles leding nulls as blanks. (PR#62) 2000-12-10 19:15:19 +00:00
steve 9ddd0491f7 Support delays on continuous assignment from idents. (PR#40) 2000-12-10 06:41:59 +00:00
steve 245472ca63 unary expressions as parameters (PR#42, PR#68) 2000-12-09 06:17:20 +00:00
steve 371f43e227 documentation... 2000-12-09 05:40:42 +00:00
steve 9fe0d9b120 Add the -tpal target to use the pal.tgt module. 2000-12-09 05:40:09 +00:00
steve 16c50ad810 Stuff registers into macrocells. 2000-12-09 03:42:52 +00:00
steve a4da2c7ed5 The ipal library is called ipal. 2000-12-09 01:19:58 +00:00
steve 40da501cec Add the pal loadable target. 2000-12-09 01:17:38 +00:00
steve f6507cba43 Check lvalue of procedural continuous assign (PR#29) 2000-12-06 06:31:09 +00:00
steve e027247a0e fix portfaults pass values. 2000-12-06 05:15:21 +00:00
steve 789e862ca4 parse real and realtime declarations. 2000-12-05 22:32:05 +00:00
steve a6b83ac5da real and trireg not supported. 2000-12-05 22:31:38 +00:00
steve 3b9a60414e Make signal attributes available to ivl_target API. 2000-12-05 06:29:33 +00:00
steve 4f638882c9 Add Attrib class for holding NetObj attributes. 2000-12-04 17:37:03 +00:00
steve 4faec154f0 Finally remove the verilog.sh script. 2000-12-02 05:57:46 +00:00
steve ff53b60c66 Remove excess *.d dependencies for parse.d 2000-12-02 05:30:08 +00:00
steve a2a40869b0 Spelling error in comment. 2000-12-02 05:08:04 +00:00
steve b714f57797 Catch up to null.tgt and libvpip.a files. 2000-12-02 05:07:14 +00:00
steve d0ec7e2c02 Make the null target into a loadable target. 2000-12-02 04:50:32 +00:00
steve d16d29c591 Support for %s in $display (PR#62) 2000-12-02 02:40:56 +00:00
steve e310532434 Handle null statements inside a wait. (PR#60) 2000-12-01 23:52:49 +00:00
steve 4eed86d519 Detect part select errors on l-values. 2000-12-01 02:55:37 +00:00
steve ef49fc127f Change LineInfo to store const C strings. 2000-11-30 17:31:42 +00:00
steve e6151db172 Add command file (-c) support from Nadim Shaikli. 2000-11-30 02:50:54 +00:00
steve 28af357c8a Clean a bit more completely. 2000-11-29 23:59:29 +00:00
steve a5c69b50e5 Do not delete synthesized signals used in expressions. 2000-11-29 23:16:18 +00:00
steve 02f876ac69 More informative BUFZ warning. 2000-11-29 23:15:54 +00:00
steve ea921efced synthesis for unary reduction ! and N operators. 2000-11-29 05:24:00 +00:00
steve 4bf3e37af3 Add XNF support for NE comparators. 2000-11-29 02:54:49 +00:00
steve 291ab97422 Add support for || synthesis (PR#53) 2000-11-29 02:09:52 +00:00
steve 12db3340cc Typo writing I pins to AND gates in compare. 2000-11-29 01:34:17 +00:00
steve e33fb3ce51 Propagate constants through xnor gates. (PR#51) 2000-11-23 01:55:52 +00:00
steve 92424eea10 synthesize the rvalue of <= statements. 2000-11-22 21:18:42 +00:00
steve 4ca0bffc7f Connect the CE if it is linked at all. 2000-11-22 21:18:20 +00:00
steve c86da66b77 Allow sole module to be a root. 2000-11-22 20:48:32 +00:00
steve f7d62b96aa whoops, wrong copyright notice. 2000-11-21 03:55:20 +00:00
steve 482323843e Whoops, return the calculated constant value rom driven_value. 2000-11-20 01:41:12 +00:00
steve f4443a7dfa Add support for supply nets (PR#17) 2000-11-20 00:58:40 +00:00
steve 1f07ba52b6 Integer parameter comments. 2000-11-19 22:03:04 +00:00
steve ec0d12b738 Killing some signals might make others killable. 2000-11-19 20:48:53 +00:00
steve 457d193238 Fix cases where signal iteration might die early. 2000-11-19 20:48:30 +00:00
steve e05b9a4769 Replace AND constand propagation. 2000-11-19 05:26:58 +00:00
steve 2750977e4a Thorough constant propagation for or and nor gates. 2000-11-18 05:13:27 +00:00
steve ff5846100c Delete unreferenced signals no matter what. 2000-11-18 05:12:45 +00:00
steve da926fa08b Watch out in functor, it may delete the last signal. 2000-11-18 04:53:04 +00:00
steve fc6978e4de Handle constant propagation through XOR gates,
including reducing the gate to a constant,
 a buffer or an inverter if possible.
2000-11-18 04:10:37 +00:00
steve 11e6440162 Fix warning about temporaries. 2000-11-15 20:31:05 +00:00
steve f74368dec2 Missing LPM related symbols in ivl.def. 2000-11-15 20:30:21 +00:00
steve 4b264a4c58 More robust way to cope with parse.cc compilation. 2000-11-15 19:26:35 +00:00
steve 0ca9b2736b flip-flop pins for ivl_target API. 2000-11-12 17:47:29 +00:00
steve 28bc621f11 change set for support of nmos, pmos, rnmos, rpmos, notif0, and notif1
change set to correct behavior of bufif0 and bufif1
 (Tim Leight)

 Also includes fix for PR#27
2000-11-11 01:52:09 +00:00
steve 197ed46b26 configure bindir and libdir 2000-11-11 00:48:35 +00:00
steve b05aadfd94 Configure bindir and libdir 2000-11-11 00:38:40 +00:00
steve a8da692540 Add support for the t-dll backend grabing flip-flops. 2000-11-11 00:03:36 +00:00
steve 1d6f48914f Initialize scope when creating it. 2000-11-09 22:19:34 +00:00
steve 1046c86c84 Remember to include the -S condition. 2000-11-09 21:58:00 +00:00
steve 47ce0f3c46 show concatenation operators. 2000-11-09 05:14:07 +00:00
steve 2dd1d070ec Display l-values with width. 2000-11-07 06:14:06 +00:00
steve f4ed0e35af Handle connectsion to internally unconnected modules (PR#38) 2000-11-05 06:05:59 +00:00
steve 61ad0b23c8 Apply sequential UDP rework from Stephan Boettcher (PR#39) 2000-11-04 06:36:24 +00:00
steve 5415dd70c5 Integrate parameter count changes (PR#34) 2000-11-04 05:49:22 +00:00
steve ff514aab72 pad different width inputs to muxes. (PR#14) 2000-11-04 05:06:04 +00:00
steve d7788b88b7 Modifications in support of gcc 2.96 2000-11-04 01:54:01 +00:00
steve a1cfabafb8 Use the %m string properly. 2000-11-04 01:53:24 +00:00
steve 35769ef541 Scope information is needed by all types of display tasks. 2000-11-04 01:52:57 +00:00
steve 80d3342178 VCD scans tasks (PR#35) 2000-11-01 06:05:44 +00:00
steve 4d27b947bc Add the general $time system function. 2000-11-01 03:19:36 +00:00
steve 3591e06c4e Support time variables. 2000-10-31 17:49:02 +00:00
steve 88c8547486 Remove C++ string from variable lists. 2000-10-31 17:00:04 +00:00
steve d92ac5772c Spelling error. 2000-10-31 16:59:45 +00:00
steve f2997d7767 Detect reverse bit order in part select. (PR#33) 2000-10-30 21:35:40 +00:00
steve 7df9943679 get width right for reversed part select net. (PR#33) 2000-10-30 20:55:53 +00:00
steve f3dfff7d76 task threads ned their scope initialized. (PR#32) 2000-10-29 17:10:02 +00:00
steve 23a5bd072d Remove the compiled in Verilog target. 2000-10-28 22:35:58 +00:00
steve d6efae4bdd API for concatenation expressions. 2000-10-28 22:32:34 +00:00
steve 10fbb2a1bb Glitches in cygwin build process. 2000-10-28 19:12:43 +00:00
steve 5b65f15df4 stub for the concat operator. 2000-10-28 17:55:03 +00:00
steve 72229abda6 check explicitly uses local libraries. 2000-10-28 17:51:45 +00:00
steve 427de3ab0b Handle - and _ in target names. 2000-10-28 17:51:01 +00:00
steve 6962841546 Split vpip for everybody. 2000-10-28 17:27:59 +00:00
steve bb414303a0 make check target (PR#3) 2000-10-28 04:16:11 +00:00
steve 431228e881 make check target (PR#3) 2000-10-28 03:58:11 +00:00
steve 07d7008853 Use the conf file to generate the vvm ivl string. 2000-10-28 03:45:47 +00:00
steve 7545db5e26 Use the conf file to generate the vvm ivl string. 2000-10-28 03:45:47 +00:00
steve ad4931e813 Add scope to threads in vvm, pass that scope
to vpi sysTaskFunc objects, and add vpi calls
 to access that information.

 $display displays scope in %m (PR#1)
2000-10-28 00:51:41 +00:00
steve f915efaf15 Fix handling of errors in behavioral lvalues. (PR#28) 2000-10-26 17:09:46 +00:00
steve df660bab0c draw proper signal references for the gates. 2000-10-26 16:42:25 +00:00
steve 26350fdcf5 emit declarations of signals and gates. 2000-10-26 00:32:28 +00:00
steve 0e7ca326ce Put signals into a signal_table 2000-10-26 00:29:10 +00:00
steve 88b479a82b mangle the backslash to a dollar. 2000-10-25 23:21:37 +00:00
steve e08314eaf5 Scan the processes, and get the target signals 2000-10-25 05:41:55 +00:00
steve b8fe10d27d Get target signal from nexus_ptr. 2000-10-25 05:41:24 +00:00
steve 1cc7b6d4d7 Nexus value is initially unknown so that it propogates for sure. 2000-10-23 00:32:48 +00:00
steve bb9eb2cd1d Fix decimal constant overflow warning (PR#26) 2000-10-22 22:27:59 +00:00
steve add2ae16fa Reduce the target entry points to the target_design. 2000-10-21 16:49:45 +00:00
steve ecf71efc84 Document the -C flag of iverilog. 2000-10-18 21:53:05 +00:00
steve e10679633d Add ivl_lval_t and support for assignment l-values. 2000-10-18 20:04:39 +00:00
steve f5fae7f271 Stubs so that cygwin port will link ivl. 2000-10-16 22:44:54 +00:00
steve 90ae46476c Makefile patches to support target loading under cygwin. 2000-10-15 21:02:08 +00:00
steve 2dedd6c067 Scopes and processes are accessible randomly from
the design, and signals and logic are accessible
 from scopes. Remove the target calls that are no
 longer needed.

 Add the ivl_nexus_ptr_t and the means to get at
 them from nexus objects.

 Give names to methods that manipulate the ivl_design_t
 type more consistent names.
2000-10-15 04:46:23 +00:00
steve 7ee46bc621 More sophisticated number length warning. 2000-10-14 16:48:59 +00:00
steve 368e5b72be bit width warnings from Jim Norris (PR#24) 2000-10-14 04:07:54 +00:00
steve f526d235d1 Check for missing concat subexpressions (PR#11) 2000-10-14 02:23:02 +00:00
steve 06f5482631 Skip the o radix in octal numbers. 2000-10-14 01:31:30 +00:00
steve 52b649cd5e Include constants in nexus targets. 2000-10-13 03:39:27 +00:00
steve 588966320f commentary. 2000-10-13 03:38:48 +00:00
steve 5ce28c193a iverilog with an iverilog.conf configuration file. 2000-10-08 22:36:55 +00:00
steve c9bcda147e Missing stream in call to fprintf. 2000-10-08 05:00:04 +00:00
steve 4819d54d51 Fix repeat concatenation with multiple expressions (PR#10) 2000-10-08 04:59:36 +00:00
steve 8fe887ffe1 Back pointers in the nexus objects into the devices
that point to it.

 Collect threads into a list in the design.
2000-10-08 04:01:54 +00:00
steve 76e2c509d7 Put logic devices into scopes. 2000-10-07 19:45:42 +00:00
steve 6f69773c57 ivl_target updates, including more complete
handling of ivl_nexus_t objects. Much reduced
 dependencies on pointers to netlist objects.
2000-10-06 23:46:50 +00:00
steve 8ba1facb66 Replace data references with function calls. (Venkat) 2000-10-06 23:11:39 +00:00
steve 20d07a7366 Eliminate zero inputs to xor. 2000-10-06 21:26:34 +00:00
steve 02bee9358c sfuncs are char* and are compared with strcmp 2000-10-06 02:21:35 +00:00
steve 41f3ba65a1 xor and constant devices. 2000-10-05 05:03:01 +00:00
steve ce19190eae Overview documentation for loadable targets. 2000-10-04 22:13:51 +00:00
steve d7fcd66826 Overview documentation for loadable targets. 2000-10-04 21:50:55 +00:00
steve 9680de25cd Fix the clean target and excess dependencies. 2000-10-04 17:08:31 +00:00
steve aac5fc246a Use char8 instead of string to store name. 2000-10-04 16:30:39 +00:00
steve 887654b7c5 Use .def file instead of _dllexport. 2000-10-04 02:37:44 +00:00
steve 07aa86f0fa print reg signals. 2000-10-04 02:24:20 +00:00
steve 2f668421a3 Strip the installed .vpi file. 2000-10-04 02:01:40 +00:00
steve bb777f317b Cleanup build of VPI modules under Cygwin. (Venkat) 2000-10-03 16:15:35 +00:00
steve b34a451cbc Cygwin port changes from Venkat 2000-09-30 03:20:47 +00:00
steve c12e0f5416 ivl_expr_t support for binary operators,
Create a proper ivl_scope_t object.
2000-09-30 02:18:15 +00:00
steve 40028f263f Do not put noop statements into blocks. 2000-09-29 22:58:57 +00:00
steve 21e0e8a8a1 Cnstant evaluation of NE. 2000-09-29 04:42:56 +00:00
steve 700bcfda70 handel, by truncation, verinums that are to long for long integers. 2000-09-28 03:55:55 +00:00
steve fff759de20 multiply in parameter expressions. 2000-09-27 18:28:37 +00:00
steve 79b1c51e68 Detect indefinite widths where definite widths are required. 2000-09-26 05:05:58 +00:00
steve 8b581cef46 Remove the obsolete NetEIdent class. 2000-09-26 01:35:42 +00:00
steve d6b43519a8 Add EX_NUMBER and ST_TRIGGER to dll-api. 2000-09-26 00:30:07 +00:00
steve cbe20e8bcf fix null pointer when elaborating undefined task. 2000-09-24 17:41:13 +00:00
steve e8bb53e2ea API access to signal type and port type. 2000-09-24 15:46:00 +00:00
steve 2be1c115ff Move some NetNet method out of the header file. 2000-09-24 15:44:44 +00:00
steve 36cc374ec9 Add support for signal expressions. 2000-09-24 02:21:53 +00:00
steve 043bd2876b Update documentation to use iverilog. 2000-09-23 17:46:11 +00:00
steve 57ced29227 Handle unknowns in decimal strings. 2000-09-23 16:34:47 +00:00
steve 80c69d565b Add enough tgt-verilog code to support hello world. 2000-09-23 05:15:07 +00:00
steve 3a2eff2265 Parse specify delay values. 2000-09-23 03:04:10 +00:00
steve 48ff3590bc Access to the name of a system task call. 2000-09-22 03:58:30 +00:00
steve 9067c91656 Correctly measure comples l-values of assignments. 2000-09-20 02:53:14 +00:00
steve 13c1378666 Remember to make the includedir. 2000-09-20 01:02:13 +00:00
steve 39cf6bd164 Introduce the means to get statement types. 2000-09-19 04:15:27 +00:00
steve ea53f2b54f Typo stepping ot next probe in delete. 2000-09-19 03:00:36 +00:00
steve effc84c46d Get the structure for ivl_statement_t worked out. 2000-09-18 01:24:32 +00:00
steve 89d7176734 Add support for modulus (Eric Aardoom) 2000-09-17 21:26:15 +00:00
steve f8478a4408 More thorough credits section. 2000-09-17 19:06:58 +00:00
steve 8978bbd5e6 full featured l-values for non-blocking assiginment. 2000-09-16 21:28:14 +00:00
steve 063d56ffc1 undefined macros are null (with warnings.) 2000-09-13 22:33:13 +00:00
steve 67472379b4 Error message for invalid variable list. 2000-09-13 16:32:26 +00:00
steve 7e9a7ed0cb Version information for vlog_vpi_info. 2000-09-12 01:17:40 +00:00
steve db1b53c1e7 Oops, the -m flag takes a parameter and needs the : 2000-09-12 01:17:19 +00:00
steve 68c6c48a18 Some error checking. 2000-09-10 15:43:59 +00:00
steve 3c94635f99 Agressively merge NetAssign_ within concatenations. 2000-09-10 03:59:59 +00:00
steve 8a69c54886 elaborate complex l-values 2000-09-10 02:18:16 +00:00
steve b6ce313e91 move lval elaboration to PExpr virtual methods. 2000-09-09 15:21:26 +00:00
steve 3ae76a8638 initialize vlog info. 2000-09-08 17:08:10 +00:00
steve d86b37d90f Support unary + and - in constants. 2000-09-07 22:38:13 +00:00
steve e27934a577 ack, detect when lval fails. 2000-09-07 22:37:48 +00:00
steve ddcba9d91f The + operator now preserves signedness. 2000-09-07 22:37:10 +00:00
steve 44438c9678 more robust abut ternary bit widths. 2000-09-07 21:28:51 +00:00
steve 4cf75adf94 Fix bit padding of assign signal-to-signal 2000-09-07 01:29:44 +00:00
steve 49570b8cd9 encapsulate access to the l-value expected width. 2000-09-07 00:06:53 +00:00
steve 24e46723b0 Change elaborate_lval to return NetAssign_ objects. 2000-09-03 17:58:35 +00:00
steve e95d0c3b87 Properly ignore NetAssign_ objects. 2000-09-03 17:58:14 +00:00
steve ece3f5e0a2 Slightly more helpful warning. 2000-09-03 17:57:53 +00:00
steve 115d24a292 Pull NetAssign_ creation out of constructors. 2000-09-02 23:40:12 +00:00
steve ac81f6a201 Rearrange NetAssign to make NetAssign_ separate. 2000-09-02 20:54:20 +00:00
steve ff32325d07 t-dll iterates signals, and passes them to the
target module.

 Some of NetObj should return char*, not string.
2000-08-27 15:51:50 +00:00
steve eb781a7441 Handle out of range part select expressions. 2000-08-26 01:31:29 +00:00
steve 8876cda37f Get at gate information for ivl_target interface. 2000-08-26 00:54:03 +00:00
steve df113f962b Clean up warnings and portability issues. 2000-08-20 17:49:04 +00:00
steve d0fc6d515d Add ivl_target support for logic gates, and
make the interface more accessible.
2000-08-20 04:13:56 +00:00
steve 3cb666dd2f Add target calls for scope, events and logic. 2000-08-19 18:12:42 +00:00
steve a59bbdeb4f Proper error messages when port direction is missing. 2000-08-18 04:38:57 +00:00
steve 9abd84952b add th t-dll functions for net_const, net_bufz and processes. 2000-08-14 04:39:56 +00:00
steve 3ae4d2cf91 use -fPIC for sparc. 2000-08-12 20:54:33 +00:00
steve 534521f88b Limit signal scope search at module boundaries. 2000-08-12 17:59:48 +00:00
steve 566aad9e15 Start stub for loadable targets. 2000-08-12 16:34:37 +00:00
steve 248baa26e1 Move all file manipulation out of target class. 2000-08-09 03:43:45 +00:00
steve 91a462e38c Add the -N switch to the iverilog command. 2000-08-09 01:34:00 +00:00
steve d58533fd7b target methods need not take a file stream. 2000-08-08 01:50:42 +00:00
steve dab45178a7 Add vpi_vlog_info support from Adrian 2000-08-08 01:47:40 +00:00
steve e01137ced3 cleanup. 2000-08-02 14:48:15 +00:00
steve b5a36fef70 use bufif0 if z is in true case of mux. 2000-08-02 14:48:01 +00:00
steve 2e3e9ecf37 tri01 support in vvm. 2000-08-02 00:57:02 +00:00
steve 60c2046be6 Extend x or z that is top bit of a constant. 2000-08-01 22:44:26 +00:00
steve 1325a3e2b6 Use the iverilog command in documentation. 2000-08-01 21:32:40 +00:00
steve d677f226f3 Support <= in synthesis of DFF and ram devices. 2000-08-01 02:48:41 +00:00
steve eb93e3d2f5 Treat CR as white space in timespec lines. 2000-08-01 02:14:34 +00:00
steve 7cccbda275 Handle different forms of line end. 2000-08-01 01:38:25 +00:00
steve 931ec257f0 Report error when dumpfile is missing. 2000-07-31 03:34:31 +00:00
steve b6562d3ed9 timescale and min:typ:max expressions *do* work onw. 2000-07-30 22:09:09 +00:00
steve 0243fca8dc Rearrange task and function elaboration so that the
NetTaskDef and NetFuncDef functions are created during
 signal enaboration, and carry these objects in the
 NetScope class instead of the extra, useless map in
 the Design class.
2000-07-30 18:25:43 +00:00
steve 30a81731dd Introduce min:typ:max support. 2000-07-29 17:58:20 +00:00
steve 3aa250b16b Report code generation errors through proc_delay. 2000-07-29 16:21:08 +00:00
steve 39c71ef68a fix problem coalescing events w/ probes. 2000-07-29 03:55:38 +00:00
steve 4494a7a4f3 Support elaboration of disable statements. 2000-07-27 05:13:44 +00:00
steve 739365abe5 Parse disable statements to pform. 2000-07-26 05:08:07 +00:00
steve 880b712140 Get VCD timescale from design precision. 2000-07-26 04:07:59 +00:00
steve 08e6bf2e27 Make simulation precision available to VPI. 2000-07-26 03:53:11 +00:00
steve 5f7c298a21 Fix RAM matching. 2000-07-26 03:52:59 +00:00
steve 34399cf297 memory is not a data type in verilog. 2000-07-25 22:49:32 +00:00
steve cb7b1b6c94 Unlink z constants from nets. 2000-07-25 02:55:13 +00:00
steve 53489e6abe Document ieee1364 issues. 2000-07-23 18:06:31 +00:00
steve 4f75d04a42 Document time scale in netlists. 2000-07-23 18:06:15 +00:00
steve 81dab9c572 Excessive assert. 2000-07-23 02:41:32 +00:00
steve 286cef19fb Parse and elaborate timescale to scopes. 2000-07-22 22:09:03 +00:00
steve 741b17245d Handle some edge cases during node scans. 2000-07-16 04:56:07 +00:00
steve 2a08824ae9 Detect muxing Vz as a bufufN. 2000-07-15 05:13:43 +00:00
steve 42e4ff47c8 Move inital value handling from NetNet to Nexus
objects. This allows better propogation of inital
 values.

 Clean up constant propagation  a bit to account
 for regs that are not really values.
2000-07-14 06:12:56 +00:00
steve 8dd2fc7095 More detailed handling of exit status from commands. 2000-07-11 23:30:03 +00:00
steve c07cc005bd proper init method for bufz devices. 2000-07-11 23:08:33 +00:00
steve 79ca317c1d Better handle failures to build lexor_keyword.cc 2000-07-11 23:07:28 +00:00
steve b8946d4cb3 Add the dist_uniform function. 2000-07-08 22:41:07 +00:00
steve 8902645fa7 Allow set vpiIntVal on bitset type objects. 2000-07-08 22:40:07 +00:00
steve 9c12fcffe4 pass zero-delay values immediately. 2000-07-08 22:39:32 +00:00
steve 9b59001cf9 Eleminate reduction gate for 1-bit compares. 2000-07-08 04:59:20 +00:00
steve 18eb34921f Add support for non-constant delays in delay statements,
Support evaluating ! in constant expressions, and
 move some code from netlist.cc to net_proc.cc.
2000-07-07 04:53:53 +00:00
steve cdb3eb7e6b Connect all the l and r bits of a NE expression. 2000-07-06 18:13:24 +00:00
steve e152b91226 unop_not can take out width same as in width. 2000-07-06 18:12:28 +00:00
steve 056a3f7220 Allow unary operators in constant expressions. 2000-06-30 15:50:20 +00:00
steve 888360dd3b Handle errors from parser slightly differently. 2000-06-30 15:49:44 +00:00
steve 337eee7dcb Reduce result is OK in ~ operator. 2000-06-30 15:47:06 +00:00
steve de76c77820 Catch errors from compile that leave the low 8 bits empty. 2000-06-30 04:42:23 +00:00
steve 642e1bccd9 Use nexus type to get nexus name. 2000-06-28 18:38:54 +00:00
steve 1562784a48 Initialize memories as they are create. 2000-06-28 18:38:00 +00:00
steve 042724612e Handle delay_value_lists in simple paths. (Wen-jung Tseng) 2000-06-27 16:00:40 +00:00
steve 62d83e962a properly match unconnected_drive directive. (Wen-jung Tseng) 2000-06-27 04:36:29 +00:00
steve 583868e74e Redesign Links to include the Nexus class that
carries properties of the connected set of links.
2000-06-25 19:59:41 +00:00
steve e52ada617e Get rid of useless next_link method. 2000-06-24 22:55:19 +00:00
steve f3384c7da5 expression scan uses tgt_ to get output files. 2000-06-24 16:40:46 +00:00
steve d94acc1c5c Update to final release. 2000-06-21 19:09:54 +00:00
steve 4febf5801b Handle width expansion of shift operators. 2000-06-18 03:29:52 +00:00
steve e52243a82d Up to rc2 in the file name. 2000-06-18 02:02:26 +00:00
steve db8cc7d98d Detect some hosts that do not support -rdynamic. 2000-06-16 19:00:06 +00:00
steve bec4a205ec Do not install bin/verilog. 2000-06-16 18:59:49 +00:00
steve a2d3a5aab0 Do not include bin/verilog in the product. 2000-06-16 18:59:07 +00:00
steve 9bc3a8f241 Solaris pkg files. 2000-06-16 18:58:45 +00:00
steve 8f64656984 Binary expressions as operands to system tasks. 2000-06-15 04:23:17 +00:00
steve 6f3153d703 Ignore more things in null target. 2000-06-14 20:29:39 +00:00
steve 80878e2e53 Support concatenation in parameter expressions. 2000-06-13 05:22:16 +00:00
steve 66ae567b25 Index in memory assign should be a NetExpr. 2000-06-13 03:24:48 +00:00
steve 413d852012 NetEParam supports dup_expr. 2000-06-12 03:57:10 +00:00
steve 8b03550a1e Fix subract of short value form long one. 2000-06-12 03:56:51 +00:00
steve 6329549938 Prepare for release candidate. 2000-06-10 17:51:40 +00:00
steve 6f9cc57e70 Current reality of what is supported. 2000-06-07 03:53:16 +00:00
steve 3d85c66b02 Do not install obsolete verilog script. 2000-06-07 03:52:55 +00:00
steve fcbbbfe3d6 Expand constants in its special case assignment. (Stephan Boettcher) 2000-06-06 02:32:45 +00:00
steve ea8bc7f419 Interpret the depth paramter of dumpvars. 2000-06-03 02:22:15 +00:00
steve 161fa9c4e7 Do not attach temporaries to scopes. 2000-06-03 02:13:43 +00:00
steve c2b134e7d6 Output signal of + is a temporary. 2000-06-03 02:13:15 +00:00
steve 9c1dc92d74 Parameters can be strings. 2000-06-01 02:31:39 +00:00
steve a674df662f The NetESignal shortcut cannot expand an rvalue. 2000-05-31 03:52:07 +00:00
steve c1c0168893 Globally merge redundant event objects. 2000-05-31 02:26:49 +00:00
steve 9c65596b1a typo: fix vpiReadVal to vpiRealVal 2000-05-31 02:15:43 +00:00
steve 503ed3276f typ vpiRealType. 2000-05-31 01:32:16 +00:00
steve 14d87e3e11 Typo saving third delay value in list. 2000-05-31 01:31:52 +00:00
steve fd09bc3e3e Merge similar probes within a module. 2000-05-27 19:33:23 +00:00
steve e0dcdf6b72 Handle wide conditions in ternary operator. 2000-05-26 05:26:11 +00:00
steve 0c62321402 Emin init code only once per nexus. 2000-05-25 06:02:12 +00:00
steve 1bde1b862d Optimize assignment from signals. 2000-05-25 01:45:35 +00:00
steve 8fc2dc2cd1 Better parsing of expressions lists will empty expressoins. 2000-05-23 16:03:13 +00:00
steve 092b1bded5 Add vpi numbers to the bits table. 2000-05-20 02:48:51 +00:00
steve b93415e8f1 Combine constants into a bit table. 2000-05-20 02:26:23 +00:00
steve 28df01b880 Add the integer modulus function. 2000-05-19 04:22:55 +00:00
steve 2f419f0e08 Catch part select of memories as an error. 2000-05-19 01:55:09 +00:00
steve d9eed14972 Accept different widths for add operands. 2000-05-19 01:43:16 +00:00
steve cc3d4c8231 Ternary operator handles bit sizes. 2000-05-18 20:35:08 +00:00
steve 38b4de87ad Overcautious assert in shift is removed. 2000-05-18 20:23:40 +00:00
steve 0f13af2ea1 Support writing scalars and vectors to signals. 2000-05-18 03:27:32 +00:00
steve a96fa80ccc Add the module option to iverilog. 2000-05-17 03:53:29 +00:00
steve 085c31d671 syn-rules.cc.output is generated. 2000-05-16 04:05:59 +00:00
steve 3676d66408 Module ports are really special PEIdent
expressions, because a name can be used
 many places in the port list.
2000-05-16 04:05:15 +00:00
steve addedf7231 Fix -f flag handling. 2000-05-14 19:41:52 +00:00
steve 562e4c28d2 Update to use iverilog. 2000-05-14 19:41:22 +00:00
steve 1e0e1a2b64 Add a demonstration of DFF initialization. 2000-05-14 19:41:08 +00:00
steve ea96c3ef66 Support initialization of FF Q value. 2000-05-14 17:55:04 +00:00
steve cca036c4a8 Make rules consistent with token stream. 2000-05-13 22:46:22 +00:00
steve 3c9902d93e Use yacc based synthesizer. 2000-05-13 20:55:47 +00:00
steve e5511fd0a7 Up to date support, and mention iverilog. 2000-05-13 20:55:15 +00:00
steve afdb76c929 Use iverilog command. 2000-05-13 20:54:48 +00:00
steve b44abcd481 Get rid of gverilog source. 2000-05-12 05:23:15 +00:00
steve c3282bfa6c NetCAssign needs to incr_eref its lval to lock it down. 2000-05-12 01:22:41 +00:00
steve 367db72c99 Add support for procedural continuous assignment. 2000-05-11 23:37:26 +00:00
steve 4f0b0cb8ce No need for nobufz. 2000-05-11 01:44:52 +00:00
steve d68339a96a Calculate the X output value from drive0 and drive1 2000-05-11 01:37:33 +00:00
steve 6021c7b192 Give strengths to logic and bufz devices. 2000-05-09 21:16:35 +00:00
steve d4bab8709b Remove test print. 2000-05-09 00:02:29 +00:00
steve 2f59918c74 Parameterize LD lib in C++ command line. 2000-05-09 00:02:13 +00:00
steve de1a7a0933 Deliver gate output strengths to the netlist. 2000-05-08 05:30:19 +00:00
steve e9742c662b no need for nobufz functor. 2000-05-08 05:29:43 +00:00
steve e81ce68e8c Use bufz to make assignments directional. 2000-05-08 05:28:29 +00:00
steve c98e4b25b3 Restore vvm_bufz to working condition. 2000-05-08 05:27:32 +00:00
steve c4d8ded269 non-blocking assignment to a bit select. 2000-05-07 21:17:21 +00:00
steve 35a2690d75 Properly elaborate repeat concatenations. 2000-05-07 20:48:14 +00:00
steve ca6631fdda Fix connection of Direction of LMP_CLSHIFT
to constant values. Remember to add a signal
 to the nexus and connect the receiver in vvm.
2000-05-07 19:40:26 +00:00
steve b28f258463 Import MCD support from Stephen Tell, and add
system function parameter support to the IVL core.
2000-05-07 18:20:07 +00:00
steve b90cda1f3f Carry strength values from Verilog source to the
pform and netlist for gates.

 Change vvm constants to use the driver_t to drive
 a constant value. This works better if there are
 multiple drivers on a signal.
2000-05-07 04:37:55 +00:00
steve ca2fd41bb6 Carry assignment strength to pform. 2000-05-06 15:41:56 +00:00
steve 43643ba98f Add the -I and -D switches to iverilog. 2000-05-05 01:07:42 +00:00
steve f847b9cfeb Tell ivlpp to generate line number directives. 2000-05-04 20:08:20 +00:00
steve fbe475ef7d Add infrastructure for system functions, move
$time to that structure and add $random.
2000-05-04 03:37:58 +00:00
steve f95b082339 More features of ivl available through iverilog. 2000-05-03 22:14:31 +00:00
steve 0a70a8a954 Allow ternary result to be padded to result width. 2000-05-03 21:21:36 +00:00
steve ed5e587cf1 Support named for in VPI. 2000-05-03 05:03:26 +00:00
steve 1db70a0c46 Move signal elaboration to a seperate pass. 2000-05-02 16:27:38 +00:00
steve 69612ceb73 Move memories to the NetScope object. 2000-05-02 03:13:30 +00:00
steve 8d8f1e2401 Move signal tables to the NetScope class. 2000-05-02 00:58:11 +00:00
steve b175e4aef7 Better inc and lib paths for iverilog. 2000-05-01 23:55:22 +00:00
steve 8a4937bada missing header file. 2000-04-29 04:53:44 +00:00
steve b5b15a5990 The -f flag is now in place. 2000-04-29 01:20:14 +00:00
steve 3aef1be0e7 Proper bounds checking of the left operator of right shift. 2000-04-29 01:19:47 +00:00
steve 77361fb8a0 Overly aggressive eliding of task calls. 2000-04-28 23:12:12 +00:00
steve 3a9be680a4 Skip empty tasks. 2000-04-28 22:17:47 +00:00
steve acfb5c177d Over agressive signal elimination in constant probadation. 2000-04-28 21:00:28 +00:00
steve 2b40c7ce11 integer division in expressions properly get width. 2000-04-28 18:43:23 +00:00
steve 08e9a114a2 Catch memory word parameters to tasks. 2000-04-28 16:50:53 +00:00
steve 1f7090135b Mussed up command string mashing. 2000-04-26 21:11:41 +00:00
steve 1412eb2697 iverilog man page. 2000-04-26 20:53:21 +00:00
steve dab5999621 Handle assigning small values to big registers. 2000-04-26 18:35:11 +00:00
steve 906c7b4783 Do not set width too small to hold significant bits. 2000-04-26 03:33:32 +00:00
steve e78af393de AND handles argument padding if necessary. 2000-04-26 03:32:40 +00:00
steve 72c8897d13 Handling mixing of defines within ifdef/endif. 2000-04-26 01:35:26 +00:00
steve 9ca1791b43 automatically generate macro interface code. 2000-04-23 23:03:13 +00:00
steve 6e8fe39cc7 Better comments about bufif devices. 2000-04-23 21:17:31 +00:00
steve 6446add9cd Emit code for the bufif devices. 2000-04-23 21:15:07 +00:00
steve ebacf88b14 The -s flag. 2000-04-23 21:14:32 +00:00
steve a8114ae122 Add support for the procedural release statement. 2000-04-23 03:45:24 +00:00
steve 44838f8973 Add support for force assignment. 2000-04-22 04:20:19 +00:00
steve ad8811282b module path in vvm target. 2000-04-21 22:54:47 +00:00
steve 181b776f0c Support the -tnull target type. 2000-04-21 22:51:38 +00:00
steve c0d51dd2eb Add the iverilog driver program. 2000-04-21 06:41:02 +00:00
steve 99a891b8a1 Bit padding in assignment to memory. 2000-04-21 04:38:15 +00:00
steve 23725cf42c Catch bad operand to some unary operators. 2000-04-21 03:22:18 +00:00
steve 9a36dcd33d Many Unary operators have known widths. 2000-04-21 02:46:42 +00:00
steve d539b0b5fe Generic multiplier (Chris Lattner) 2000-04-21 02:30:40 +00:00
steve 37e65614a0 exit if hex value is missing. 2000-04-21 02:00:35 +00:00
steve 88d3ad51b0 Generate code for identity compare. Use gates. 2000-04-20 02:34:47 +00:00
steve 2094a2f466 Catch some simple identity compareoptimizations. 2000-04-20 00:28:03 +00:00
steve 74c43032b3 Clean up unneeded NetEvent objects. 2000-04-18 04:50:19 +00:00
steve 4f07c43976 Minor cleanup of NetTaskDef. 2000-04-18 01:02:53 +00:00
steve 726f7b8b11 Synthesis of comparator in expressions.
Connect the NetEvent and related classes
 together better.
2000-04-16 23:32:18 +00:00
steve 5624a66bbb Catch expressions that are part of conditionals. 2000-04-16 22:57:34 +00:00
steve 7484feceb5 fork-join support in vvm. 2000-04-15 19:51:30 +00:00
steve d033509359 Support chained events. 2000-04-15 02:25:32 +00:00
steve 62c6422724 Document the calling convention. 2000-04-15 01:44:59 +00:00
steve df0808d5bb No more class derivation from vvm_thread. 2000-04-14 23:31:53 +00:00
steve 4493e968da Finally remove the NetNEvent and NetPEvent classes,
Get synthesis working with the NetEvWait class,
 and get started supporting multiple events in a
 wait in vvm.
2000-04-12 20:02:52 +00:00
steve 59bbc27268 Backwards sense of assert test. 2000-04-12 16:08:46 +00:00
steve b1fd927acb Named events really should be expressed with PEIdent
objects in the pform,

 Handle named events within the mix of net events
 and edges. As a unified lot they get caught together.
 wait statements are broken into more complex statements
 that include a conditional.

 Do not generate NetPEvent or NetNEvent objects in
 elaboration. NetEvent, NetEvWait and NetEvProbe
 take over those functions in the netlist.
2000-04-12 04:23:57 +00:00
steve b0d0cdbd7d Multiple thread can block on an event. 2000-04-12 01:53:07 +00:00
steve 8dbd64121f All events now use the NetEvent class. 2000-04-10 05:26:05 +00:00
steve 72b3508911 Catch event declarations during scope elaborate. 2000-04-09 17:44:30 +00:00
steve 8d16ee9dd5 uninitialized event_ list. 2000-04-09 17:04:56 +00:00
steve cad5df1e9f Donot create tables that have no entries. 2000-04-09 16:55:42 +00:00
steve e9b06f1022 Catch event names in parentheses. 2000-04-09 16:43:50 +00:00
steve 7307deb3a9 Catch duplicate $dumpvars of symbols (ajb) 2000-04-09 04:18:16 +00:00
steve f6959ba09e Fix memory object compile problems. 2000-04-08 05:49:59 +00:00
steve 2693a8cd7d Revamped VCD id generation and duplicates removal. (ajb) 2000-04-08 05:28:39 +00:00
steve 30e8289239 Simulate named event trigger and waits. 2000-04-04 03:20:15 +00:00
steve b62a7ace5c Remove the useless sref template. 2000-04-02 04:26:06 +00:00
steve 67bdd433a9 Detect the signed keyword. 2000-04-02 04:25:39 +00:00
steve 6150be2324 detect unsupported block on named events. 2000-04-01 22:14:19 +00:00
steve 694ff934af Add support for integer division. 2000-04-01 21:40:22 +00:00
steve 2dd010dc04 Named events as far as the pform. 2000-04-01 19:31:57 +00:00
steve 26dcecebdb allow cancelling of cbValueChange events. 2000-03-31 07:08:39 +00:00
steve d97ab9be23 New and improved combinational primitives. 2000-03-29 04:37:10 +00:00
steve 995f7e89d1 Handle define of macro without value. 2000-03-29 04:36:42 +00:00
steve 995f61ace4 Forgot to return elaborate result (Dan Nelsen) 2000-03-29 04:06:28 +00:00
steve b9d19d3358 Speling error. 2000-03-27 04:38:15 +00:00
steve ffc3a42405 Remove the vvm_bits_t abstract class. 2000-03-26 16:55:41 +00:00
steve 8a10511105 vvm_bitset_t is no longer a template. 2000-03-26 16:28:31 +00:00
steve 9f84deeb56 signal bits are referenced at run time by the vpiSignal struct. 2000-03-25 05:02:24 +00:00
steve dcaea50b8f Remove all remain vvm_bitset_t return values,
and disallow vvm_bitset_t copying.
2000-03-25 02:43:56 +00:00
steve c790ccca5a Update vvm_ram_dq to nexus style. 2000-03-24 03:47:01 +00:00
steve edc40f1792 vvm_unop and vvm_binop pass result by reference
instead of returning a value.
2000-03-24 02:43:36 +00:00
steve eb9ed665f3 Do not create 0 length parameters to system tasks. 2000-03-23 03:24:39 +00:00
steve d4370a0878 Integrate drive resolution function. 2000-03-22 05:16:38 +00:00
steve a9e11d6546 Replace the vpip_bit_t with a typedef and
define values for all the different bit
 values, including strengths.
2000-03-22 04:26:40 +00:00
steve 649ce73047 Minor performance boost for gperf keyword table. 2000-03-21 05:08:32 +00:00
steve 3265f3f63a Remove dangerous tmp signal delete. 2000-03-20 17:54:10 +00:00
steve c3da6febbd More complete error message about no signal. 2000-03-20 17:40:54 +00:00
steve c5b64b4ad4 Do not link adder pins that ar unconnected. 2000-03-20 17:40:33 +00:00
steve 44d30ad127 select correct bit when reg has non-zero lsb. 2000-03-20 16:57:22 +00:00
steve 94270ff988 Fix lval part select of non-blocking assign. 2000-03-20 15:28:58 +00:00
steve 2deb379c06 Update the FF device to nexus style. 2000-03-18 23:22:37 +00:00
steve 09e0d668a6 Handle EOF in defines. 2000-03-18 06:12:26 +00:00
steve 80bd855329 Update bufz to nexus style. 2000-03-18 02:26:02 +00:00
steve 567de6ba39 Generate references into a table of nexus objects instead of
generating lots of isolated nexus objects. Easier on linkers
 and compilers,

 Add missing nexus support for l-value bit selects,

 Detemplatize the vvm_mux type.

 Fix up the vvm_nexus destructor to disconnect from drivers.
2000-03-18 01:26:59 +00:00
steve 48de739506 Switch to control warnings. 2000-03-17 21:50:25 +00:00
steve 3adaf23aab Detemplatize the vvm_signal_t class. 2000-03-17 20:21:14 +00:00
steve e71413123e nor2 and and2 optimized gates. 2000-03-17 19:23:59 +00:00
steve 51e96a2d8b Adder and comparator in nexus style. 2000-03-17 17:25:53 +00:00
steve 38fd245767 Remove some useless template parameters. 2000-03-17 03:36:07 +00:00
steve 20712d3fcc Update vvm_mult to nexus style. 2000-03-17 03:05:13 +00:00
steve 8cbf4f815e vvm_clshift implementation without templates. 2000-03-17 02:22:03 +00:00
steve 5ea3610d4a Update LPM_MUX to nexus style. 2000-03-16 23:13:49 +00:00
steve 9deb7f6ba5 Update LMP_CLSHIFT to use nexus interface. 2000-03-16 21:47:27 +00:00
steve 7ab6ff77ad Properly initialize driver and nexus values. 2000-03-16 21:45:07 +00:00
steve 2563e2b717 Revise the VVM backend to use nexus objects so that
drivers and resolution functions can be used, and
 the t-vvm module doesn't need to write a zillion
 output functions.
2000-03-16 19:03:03 +00:00
steve 2e05f7f7ec Remove unneeded templates. 2000-03-13 00:02:34 +00:00
steve 01c5147079 Connect output of NB assign to indexed pin. 2000-03-12 21:41:47 +00:00
steve 71a506a28a Binary and unary operators in parameter expressions. 2000-03-12 18:22:11 +00:00
steve 6eef54595f Support localparam. 2000-03-12 17:09:40 +00:00
steve 79f772200a Allow parameter identifiers in parameter expressions. 2000-03-12 04:35:22 +00:00
steve 78ab1a7bba Locate scopes in statements. 2000-03-11 03:25:51 +00:00
steve 61822d48aa Handle defparam to partial hierarchical names. 2000-03-10 06:20:48 +00:00
steve e7efc2709a Redesign the implementation of scopes and parameters.
I now generate the scopes and notice the parameters
 in a separate pass over the pform. Once the scopes
 are generated, I can process overrides and evalutate
 paremeters before elaboration begins.
2000-03-08 04:36:53 +00:00
steve 0fbca815b4 Fix up start of the readmemx lexor. 2000-03-05 20:01:19 +00:00
steve 1698a19cf6 Parse all the various edge types. 2000-03-05 18:26:51 +00:00
steve 7b5b5c2f39 Handle mixed case in UDP edges. 2000-03-05 06:14:10 +00:00
steve 2a68121685 Use the new cell, instead of the deleted old one. 2000-03-05 06:13:29 +00:00
steve 380d5620e6 Simpler implementation of multiplication. 2000-03-04 01:13:54 +00:00
steve aae17041ef Remove excess variable. 2000-02-29 05:20:21 +00:00
steve 1d7cf5bb8c Handle scope of complex guards when writing case in functions. 2000-02-29 05:02:30 +00:00
steve 8696a4363a Fix warning and typo. 2000-02-29 01:41:32 +00:00
steve 59c240bc9b I no longer need to declare string and number tables early. 2000-02-24 01:57:10 +00:00
steve d751b05cec change not to v_not. 2000-02-24 01:56:28 +00:00
steve 843af31958 Some compilers do not accept the not symbol. 2000-02-23 04:43:43 +00:00
steve 5aea537ab9 Add Kato to the list. 2000-02-23 04:42:49 +00:00
steve b734ecf02f Macintosh compilers do not support ident. 2000-02-23 02:56:53 +00:00
steve 5b52c384d6 Catch module instantiation arrays. 2000-02-18 05:15:02 +00:00
steve 2cba0a50f3 Fix overlap of identifiers when multiple modules used. 2000-02-17 06:04:30 +00:00
steve b354cf68b8 Fix up width matching in structural bitwise operators. 2000-02-16 03:58:27 +00:00
steve a9264d71c6 Unary reduction operators do not set their operand width 2000-02-14 06:04:52 +00:00
steve e0873f6c14 Support case in functions. 2000-02-14 01:20:50 +00:00
steve b8ddbcf62b support if-else in function definitions. 2000-02-14 00:12:09 +00:00
steve bd09bed662 Mark the line numbers of NetCondit nodes. 2000-02-14 00:11:11 +00:00
steve 1ee4015aa8 Handle selecting memory words at run time. 2000-02-13 19:59:33 +00:00
steve a8d787bd66 Accept memory words as parameter to $display. 2000-02-13 19:18:27 +00:00
steve e77bcf6910 Include some block matching from Larry. 2000-02-13 04:35:43 +00:00
steve 2bc8f79e0f Update xilinx-hints.txt from Larry. 2000-02-13 04:06:49 +00:00
steve e58be1b128 Jason moved. 2000-02-13 04:05:47 +00:00
steve ee180f6cf0 Include the scope in named gates. 2000-02-06 23:13:14 +00:00
steve ce0b97a8f0 Fix up compiling with configured -ldl switch. 2000-02-05 06:40:35 +00:00
steve cf8d17a6ab Handle systems that need underscores in symbols. 2000-01-24 00:18:20 +00:00
steve e6bd088984 Compile time problems with vpi_user.h 2000-01-23 23:54:36 +00:00
steve 9b3c3b6e7a add the -m flag. 2000-01-21 05:41:51 +00:00
steve dc5bd8ea59 $dumpall checkpointing in VCD dump. 2000-01-20 06:04:55 +00:00
steve 121b6c2ecb missing break is switch. 2000-01-18 04:53:57 +00:00
steve 57d28e4f86 Support structural XNOR. 2000-01-18 04:53:40 +00:00
steve d84b72609d Add the XNOR operator. 2000-01-13 06:05:46 +00:00
steve ef98be1192 Support for multiple VPI modules. 2000-01-13 05:11:24 +00:00
steve 3b9dedbc86 Catch some parameter problems. 2000-01-13 04:48:50 +00:00
steve aa8908c52f Multiplication all the way to simulation. 2000-01-13 03:35:35 +00:00
steve 3d1ffced57 Elaborate net widths of constants to as small
as is possible, obeying context constraints.

 Comparison operators can handle operands with
 different widths.
2000-01-11 04:20:57 +00:00
steve f37f69f160 minor type syntax fix for stubborn C++ compilers. 2000-01-10 22:16:24 +00:00
steve fac3bde2c8 Elaborate parameters afer binding of overrides. 2000-01-10 01:35:23 +00:00
steve 9125a4c451 Careful with wires connected to multiple ports. 2000-01-09 20:37:57 +00:00
steve bed47a4ab4 Make the library install directory. 2000-01-09 17:43:28 +00:00
steve 2de887c2ff Support named parameter override lists. 2000-01-09 05:50:48 +00:00
steve fdf2c1b0d0 Non-blocking memory writes. 2000-01-08 03:09:14 +00:00
steve 7f78b9bf56 Handle longer paths and the null target (spe) 2000-01-08 02:28:43 +00:00
steve d6f53b2582 Initial support for signed constants. 2000-01-07 03:45:49 +00:00
steve 848110bc33 Only sign-extend unsized numbers. 2000-01-06 05:57:06 +00:00
steve eb4cdc5026 Cleanup and some asserts. 2000-01-06 05:56:22 +00:00
steve 3d673c1f02 Add memory address range check. 2000-01-06 05:56:02 +00:00
steve a48b4c4f8d Functor support from Stefan 2000-01-04 02:51:54 +00:00
steve ba7fdb580d Add a signal to nexus of padding constant. 2000-01-02 22:07:09 +00:00
steve 9e5ff89ef3 Add structural reduction NAND,
Fix size coercion of structural shifts.
2000-01-02 21:45:31 +00:00
steve 0d5e4b40d0 Structural reduction XNOR. 2000-01-02 19:39:03 +00:00
steve 142b9e667d Do not overrun the pin index when the LSB != 0. 2000-01-02 18:25:37 +00:00
steve f3b76d958d It is possible for node to initialize several pins of a signal. 2000-01-02 17:57:56 +00:00
steve 87d6df5204 Handle nodes running out during node scan. 2000-01-02 17:57:20 +00:00
steve c7193fa6fe Do not delete constants that input to exressions. 2000-01-02 17:56:42 +00:00
steve 645c24289e Handle general constant expressions in delays. 2000-01-02 01:59:52 +00:00
steve e52a5be16e Forgot to handle no overrides at all. 2000-01-02 01:59:28 +00:00
steve 7e37b61a05 Fix module parameter override syntax. 2000-01-01 23:47:58 +00:00
steve cbd353fbb8 Fix forming of ivlpp command line. 2000-01-01 21:33:50 +00:00
steve 4c274223cf Move ivl and ivlpp to the lib directory. 2000-01-01 20:57:50 +00:00
steve 65e4e9f428 Properly expand/shrink constants in expressions. 2000-01-01 19:56:51 +00:00
steve e6820ed169 Handle synthesis of concatenation. 2000-01-01 06:18:00 +00:00
steve c3cb0f2371 Propogate line number information when expanding expressions. 2000-01-01 06:17:25 +00:00
steve 31f1ceea9f delay1 expressions can take parentheses. 1999-12-31 17:39:00 +00:00
steve 94afe54741 Standardize some of the error messages. 1999-12-31 17:38:37 +00:00
steve 080f161c37 Fix output file name calculations. 1999-12-31 05:27:42 +00:00
steve 5ce35e3e60 Fix event trigger and repeat control parse errors. 1999-12-31 03:24:30 +00:00
steve 6d0edcf58a Support reg initial assignment syntax. 1999-12-30 19:06:14 +00:00
steve 7033836e01 Remove the now useless sigfold functor. 1999-12-30 17:37:13 +00:00
steve b7409d98ff Version and ebug options. 1999-12-30 04:59:39 +00:00
steve b6d1bb1fa7 Propogate constant 0 in low bits of adders. 1999-12-30 04:19:12 +00:00
steve 4558a7d8d0 Proper init_ method prototype. 1999-12-19 20:57:07 +00:00
steve 22c2625ace Add the gverilog driver program. 1999-12-18 04:15:01 +00:00
steve 4de8ba489d Rewrite the cprop functor to use the functor_t interface. 1999-12-17 06:18:15 +00:00
steve 65ae92859c NetConst can now hold wide constants. 1999-12-17 03:38:46 +00:00
steve d355270c2d Capture the carry out of carry-chain addition. 1999-12-16 18:54:32 +00:00
steve ced7cc6d60 Structural logical or. 1999-12-16 03:46:39 +00:00
steve d54cc14ca2 Simulate carry output on adders. 1999-12-16 02:42:14 +00:00
steve 98a57f4fac Handle blanks after b is binary numbers 1999-12-16 01:20:17 +00:00
steve 40ca71b10b Support named begin scope at run time. 1999-12-15 18:21:20 +00:00
steve e7e58cdd71 Add readmemb. 1999-12-15 04:35:34 +00:00
steve 1dcf9de34c Implement vpi_put_value for memory words. 1999-12-15 04:15:17 +00:00
steve fcb1d8dc72 Excess warning. 1999-12-15 04:02:38 +00:00
steve 5fa7e1c31b Add the VPI implementation of $readmemh. 1999-12-15 04:01:14 +00:00
steve 6e3c258edb Detect duplicate scopes. 1999-12-14 23:42:16 +00:00
steve 6be5421c8a Remove the useless vvm_simulation class. 1999-12-12 19:47:54 +00:00
steve 76655ce2bb Allow memories without indices in expressions. 1999-12-12 06:03:14 +00:00
steve 3e1738dcec Fix support for attaching attributes to primitive gates. 1999-12-11 05:45:41 +00:00
steve ec8dec74a6 Example how to mke OUTFF devices in IOBs. 1999-12-11 04:10:39 +00:00
steve 838d25890b Various spelling fixes. 1999-12-09 06:00:55 +00:00
steve 4a6d3a5104 Fix const/non-const errors. 1999-12-09 06:00:00 +00:00
steve b688cdbc40 Add some examples as documentation. 1999-12-05 21:08:56 +00:00
steve 09de918198 Generate XNF RAMS from synthesized memories. 1999-12-05 19:30:42 +00:00
steve 3e2bb85f58 Synthesize LPM_RAM_DQ for writes into memories. 1999-12-05 02:24:08 +00:00
216 changed files with 37934 additions and 10618 deletions
+4 -1
View File
@@ -1,12 +1,15 @@
lexor_keyword.cc
parse.h
parse.cc
parse.cc.output
syn-rules.cc
syn-rules.cc.output
lexor.cc
ivl
ivl.exp
dep
configure
Makefile
verilog
config.status
config.log
config.cache
+125
View File
@@ -0,0 +1,125 @@
/*
* Copyright (c) 2000 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: Attrib.cc,v 1.1 2000/12/04 17:37:03 steve Exp $"
#endif
# include "Attrib.h"
# include <assert.h>
Attrib::Attrib()
{
nlist_ = 0;
list_ = 0;
}
Attrib::~Attrib()
{
delete[] list_;
}
void Attrib::set_attributes(const map<string,string>&attr)
{
assert(list_ == 0);
nlist_ = attr.size();
list_ = new cell_[nlist_];
map<string,string>::const_iterator idx;
unsigned jdx;
for (idx = attr.begin(), jdx = 0 ; idx != attr.end() ; idx ++, jdx++) {
struct cell_*tmp = list_ + jdx;
tmp->key = (*idx).first;
tmp->val = (*idx).second;
}
}
string Attrib::attribute(const string&key) const
{
for (unsigned idx = 0 ; idx < nlist_ ; idx += 1) {
if (key == list_[idx].key)
return list_[idx].val;
}
return "";
}
void Attrib::attribute(const string&key, const string&value)
{
unsigned idx;
for (idx = 0 ; idx < nlist_ ; idx += 1) {
if (key == list_[idx].key) {
list_[idx].val = value;
return;
}
}
struct cell_*tmp = new struct cell_[nlist_+1];
for (idx = 0 ; idx < nlist_ ; idx += 1)
tmp[idx] = list_[idx];
tmp[nlist_].key = key;
tmp[nlist_].val = value;
nlist_ += 1;
delete[]list_;
list_ = tmp;
}
bool Attrib::has_compat_attributes(const Attrib&that) const
{
unsigned idx;
for (idx = 0 ; idx < that.nlist_ ; idx += 1) {
string tmp = attribute(that.list_[idx].key);
if (tmp != that.list_[idx].val)
return false;
}
return true;
}
unsigned Attrib::size() const
{
return nlist_;
}
string Attrib::key(unsigned idx) const
{
assert(idx < nlist_);
return list_[idx].key;
}
string Attrib::value(unsigned idx) const
{
assert(idx < nlist_);
return list_[idx].val;
}
/*
* $Log: Attrib.cc,v $
* Revision 1.1 2000/12/04 17:37:03 steve
* Add Attrib class for holding NetObj attributes.
*
*/
+69
View File
@@ -0,0 +1,69 @@
#ifndef __Attrib_H
#define __Attrib_H
/*
* Copyright (c) 2000 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: Attrib.h,v 1.1 2000/12/04 17:37:03 steve Exp $"
#endif
# include <string>
# include <map>
/*
* This class keeps a map of key/value pairs. The map can be set from
* an STL map, or by setting individual mappings.
*/
class Attrib {
public:
Attrib();
~Attrib();
void set_attributes(const map<string,string>&attr);
string attribute(const string&key) const;
void attribute(const string&key, const string&value);
bool has_compat_attributes(const Attrib&that) const;
/* Provide a means of iterating over the entries in the map. */
unsigned size() const;
string key(unsigned idx) const;
string value(unsigned idx) const;
private:
struct cell_ {
string key;
string val;
};
unsigned nlist_;
struct cell_*list_;
private: // not implemented
Attrib(const Attrib&);
Attrib& operator= (const Attrib&);
};
/*
* $Log: Attrib.h,v $
* Revision 1.1 2000/12/04 17:37:03 steve
* Add Attrib class for holding NetObj attributes.
*
*/
#endif
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: LineInfo.cc,v 1.1 2000/11/30 17:31:42 steve Exp $"
#endif
# include "LineInfo.h"
# include <cstdio>
LineInfo::~LineInfo()
{
}
string LineInfo::get_line() const
{
char buf[8];
sprintf(buf, "%u", lineno_);
return string(file_? file_ : "") + ":" + buf;
}
void LineInfo::set_line(const LineInfo&that)
{
file_ = that.file_;
lineno_ = that.lineno_;
}
/*
* $Log: LineInfo.cc,v $
* Revision 1.1 2000/11/30 17:31:42 steve
* Change LineInfo to store const C strings.
*
*/
+23 -35
View File
@@ -18,59 +18,47 @@
* 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: LineInfo.h,v 1.3 1999/02/15 02:06:15 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: LineInfo.h,v 1.5 2000/11/30 17:31:42 steve Exp $"
#endif
# include <cstdio>
# include <string>
/*
* This class holds line information for an internal object.
*
* Note that the file names are C-style strings that are allocated by
* the lexor (which parses the line directives) and are never
* deallocated. We can therefore safely store the pointer and never
* delete the string, even if LineInfo objects are destroyed.
*/
class LineInfo {
public:
LineInfo() : lineno_(0) { }
LineInfo() : file_(0), lineno_(0) { }
~LineInfo();
string get_line() const
{ char buf[8];
sprintf(buf, "%u", lineno_);
return file_ + ":" + buf;
}
string get_line() const;
void set_line(const LineInfo&that)
{ file_ = that.file_;
lineno_ = that.lineno_;
}
void set_line(const LineInfo&that);
void set_file(const string&f) { file_ = f; }
void set_file(const char*f) { file_ = f; }
void set_lineno(unsigned n) { lineno_ = n; }
private:
string file_;
const char* file_;
unsigned lineno_;
};
/*
* $Log: LineInfo.h,v $
* Revision 1.5 2000/11/30 17:31:42 steve
* Change LineInfo to store const C strings.
*
* Revision 1.4 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/02/15 02:06:15 steve
* Elaborate gate ranges.
*
* Revision 1.2 1999/02/01 00:26:48 steve
* Carry some line info to the netlist,
* Dump line numbers for processes.
* Elaborate prints errors about port vector
* width mismatch
* Emit better handles null statements.
*
* Revision 1.1 1999/01/25 05:45:56 steve
* Add the LineInfo class to carry the source file
* location of things. PGate, Statement and PProcess.
*
* elaborate handles module parameter mismatches,
* missing or incorrect lvalues for procedural
* assignment, and errors are propogated to the
* top of the elaboration call tree.
*
* Attach line numbers to processes, gates and
* assignment statements.
*
*/
#endif
+93 -48
View File
@@ -3,9 +3,7 @@
# 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.
# 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
@@ -18,12 +16,12 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.30 1999/11/29 17:02:21 steve Exp $"
#ident "$Id: Makefile.in,v 1.89 2001/01/09 03:11:27 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.0
VERSION = 0.3
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -31,113 +29,160 @@ srcdir = @srcdir@
VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
mandir = @mandir@
bindir = @bindir@
libdir = @libdir@
includedir = $(prefix)/include
dllib=@DLLIB@
rdynamic=@rdynamic@
CC = @CC@
CXX = @CXX@
INSTALL = @INSTALL@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
STRIP = @STRIP@
CPPFLAGS = @CPPFLAGS@ @DEFS@
CXXFLAGS = @CXXFLAGS@ -I$(srcdir)
CXXFLAGS = @CXXFLAGS@ -I. -I$(srcdir)
LDFLAGS = @LDFLAGS@
all: ivl verilog
cd vpi ; $(MAKE) all
# The TARGETS variable lists the target modules that can be build and
# installed. Some of them depend on external things, so are only
# compiled if the prerequisites are installed.
TARGETS = tgt-null
ifeq ('@HAVE_IPAL@','yes')
TARGETS += tgt-pal
endif
all: ivl@EXEEXT@
cd vvm ; $(MAKE) all
cd vpi ; $(MAKE) all
cd ivlpp ; $(MAKE) all
cd driver ; $(MAKE) all
cd tgt-verilog ; $(MAKE) all
cd tgt-stub ; $(MAKE) all
for tgt in $(TARGETS); do (cd $$tgt ; $(MAKE) all); done
# This rule rules the compiler in the trivial hello.vl program to make
# sure the basics were compiled properly.
check: all
driver/iverilog -Ccheck.conf -ocheck -tvvm-check -B./ivlpp examples/hello.vl
$(CXX) -o check $(rdynamic) -fno-exceptions -Ivvm -Ivpi -Lvvm check.cc -lvvm -lvpip $(dllib)
./check | grep 'Hello, World'
clean:
rm -f *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc verilog
cd vpi ; $(MAKE) clean
rm -f *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc lexor_keyword.cc ivl@EXEEXT@ libivl.a
cd vvm ; $(MAKE) clean
cd vpi ; $(MAKE) clean
cd driver ; $(MAKE) clean
cd ivlpp ; $(MAKE) clean
cd tgt-verilog ; $(MAKE) clean
cd tgt-stub ; $(MAKE) clean
for tgt in $(TARGETS); do (cd $$tgt ; $(MAKE) clean); done
distclean: clean
rm -f vpi/Makefile
rm -f vvm/Makefile
rm -f vpi/Makefile
rm -f ivlpp/Makefile
rm -f driver/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 nodangle.o propinit.o sigfold.o synth.o xnfio.o xnfsyn.o
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o t-vvm.o t-xnf.o
FF = nodangle.o synth.o syn-rules.o xnfio.o
O = main.o cprop.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
elab_net.o emit.o eval.o eval_tree.o expr_synth.o functor.o \
lexor.o lexor_keyword.o mangle.o netlist.o pad_to_width.o \
elab_lval.o elab_net.o elab_anet.o elab_pexpr.o elab_scope.o \
elab_sig.o emit.o eval.o \
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
mangle.o netlist.o net_assign.o \
net_design.o net_event.o net_force.o net_link.o net_modulo.o net_proc.o \
net_scope.o net_udp.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 \
verinum.o verireal.o target.o targets.o util.o \
Attrib.o LineInfo.o Module.o PDelays.o PEvent.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
ifeq (@CYGWIN@,yes)
ivl@EXEEXT@: $O ivl.def
dlltool --dllname ivl@EXEEXT@ --def ivl.def \
--output-lib libivl.a --output-exp ivl.exp
# $(CXX) -o ivl@EXEEXT@ -Wl,--base-file,ivl.base ivl.exp $O $(dllib)
# dlltool --dllname ivl@EXEEXT@ --base-file ivl.base \
# --output-exp ivl.exp --def ivl.def
$(CXX) -o ivl@EXEEXT@ ivl.exp $O $(dllib)
else
ivl@EXEEXT@: $O
$(CXX) $(CXXFLAGS) $(rdynamic) $(LDFLAGS) -o ivl@EXEEXT@ $O $(dllib)
endif
%.o dep/%.d: %.cc
%.o: %.cc
@[ -d dep ] || mkdir dep
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o
mv $*.d dep/$*.d
lexor.o dep/lexor.d: lexor.cc parse.h
lexor.o: lexor.cc parse.h
parse.o dep/parse.d: parse.cc
parse.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
syn-rules.cc: $(srcdir)/syn-rules.y
bison --verbose -p syn_ -o syn-rules.cc $(srcdir)/syn-rules.y
lexor.cc: $(srcdir)/lexor.lex
flex -PVL -s -olexor.cc $(srcdir)/lexor.lex
install: all installdirs $(bindir)/verilog $(bindir)/ivl $(mandir)/man1/verilog.1
cd vpi ; $(MAKE) install
lexor_keyword.o: lexor_keyword.cc
lexor_keyword.cc: lexor_keyword.gperf
gperf -o -i 7 -C -k 1-3,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/iverilog.conf $(includedir)/ivl_target.h
cd vvm ; $(MAKE) install
cd vpi ; $(MAKE) install
cd ivlpp ; $(MAKE) install
cd driver ; $(MAKE) install
for tgt in $(TARGETS); do (cd $$tgt ; $(MAKE) install); done
$(bindir)/verilog: ./verilog
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
$(libdir)/ivl/ivl@EXEEXT@: ./ivl@EXEEXT@
$(INSTALL_PROGRAM) ./ivl@EXEEXT@ $(libdir)/ivl/ivl@EXEEXT@
$(STRIP) $(libdir)/ivl/ivl@EXEEXT@
$(bindir)/ivl: ivl
$(INSTALL_PROGRAM) ./ivl $(bindir)/ivl
$(STRIP) $(bindir)/ivl
$(libdir)/ivl/iverilog.conf: $(srcdir)/iverilog.conf
$(INSTALL_DATA) $(srcdir)/iverilog.conf $(libdir)/ivl/iverilog.conf
$(mandir)/man1/verilog.1: $(srcdir)/verilog.1
$(INSTALL_DATA) $(srcdir)/verilog.1 $(mandir)/man1/verilog.1
$(includedir)/ivl_target.h: $(srcdir)/ivl_target.h
$(INSTALL_DATA) $(srcdir)/ivl_target.h $(includedir)/ivl_target.h
installdirs: mkinstalldirs
$(srcdir)/mkinstalldirs $(bindir) $(mandir)/man1
$(srcdir)/mkinstalldirs $(bindir) $(includedir) $(libdir)/ivl
uninstall:
rm -f $(bindir)/ivl
rm -f $(libdir)/ivl/ivl@EXEEXT@
rm -f $(bindir)/verilog
rm -f $(mandir)/man1/verilog.1
rm -f $(bindir)/gverilog@EXEEXT@
rm -f $(includedir)/ivl_target.h
cd driver ; $(MAKE) uninstall
cd vpi ; $(MAKE) uninstall
cd vvm ; $(MAKE) uninstall
cd ivlpp ; $(MAKE) uninstall
for tgt in $(TARGETS); do (cd $$tgt ; $(MAKE) uninstall); done
-include $(patsubst %.o, dep/%.d, $O)
+77 -20
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams ([email protected])
* Copyright (c) 1998-2000 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
@@ -16,26 +16,21 @@
* 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: Module.cc,v 1.7 1999/09/17 02:06:25 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: Module.cc,v 1.14 2000/11/15 20:31:05 steve Exp $"
#endif
# include "Module.h"
# include "PGate.h"
# include "PWire.h"
# include <assert.h>
Module::Module(const string&name, const svector<Module::port_t*>*pp)
: name_(name)
{
if (pp) {
if (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]);
}
}
}
void Module::add_gate(PGate*gate)
@@ -53,9 +48,14 @@ void Module::add_function(const string &name, PFunction *func)
funcs_[name] = func;
}
void Module::add_wire(PWire*wire)
PWire* Module::add_wire(PWire*wire)
{
wires_.push_back(wire);
PWire*&ep = wires_[wire->name()];
if (ep) return ep;
assert(ep == 0);
ep = wire;
return wire;
}
void Module::add_behavior(PProcess*b)
@@ -68,10 +68,20 @@ unsigned Module::port_count() const
return ports_.count();
}
const svector<PWire*>& Module::get_port(unsigned idx) const
/*
* Return the array of PEIdent object that are at this port of the
* module. If the port is internally unconnected, return an empty
* array.
*/
const svector<PEIdent*>& Module::get_port(unsigned idx) const
{
assert(idx < ports_.count());
return ports_[idx]->wires;
static svector<PEIdent*> zero;
if (ports_[idx])
return ports_[idx]->expr;
else
return zero;
}
unsigned Module::find_port(const string&name) const
@@ -85,22 +95,69 @@ unsigned Module::find_port(const string&name) const
}
PWire* Module::get_wire(const string&name)
PWire* Module::get_wire(const string&name) const
{
for (list<PWire*>::iterator cur = wires_.begin()
; cur != wires_.end()
map<string,PWire*>::const_iterator obj = wires_.find(name);
if (obj == wires_.end())
return 0;
else
return (*obj).second;
}
PGate* Module::get_gate(const string&name)
{
for (list<PGate*>::iterator cur = gates_.begin()
; cur != gates_.end()
; cur ++ ) {
if ((*cur)->name() == name)
if ((*cur)->get_name() == name)
return *cur;
}
return 0;
}
const map<string,PWire*>& Module::get_wires() const
{
return wires_;
}
const list<PGate*>& Module::get_gates() const
{
return gates_;
}
const list<PProcess*>& Module::get_behaviors() const
{
return behaviors_;
}
/*
* $Log: Module.cc,v $
* Revision 1.14 2000/11/15 20:31:05 steve
* Fix warning about temporaries.
*
* Revision 1.13 2000/11/05 06:05:59 steve
* Handle connectsion to internally unconnected modules (PR#38)
*
* Revision 1.12 2000/05/16 04:05:15 steve
* Module ports are really special PEIdent
* expressions, because a name can be used
* many places in the port list.
*
* Revision 1.11 2000/03/12 17:09:40 steve
* Support localparam.
*
* Revision 1.10 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.9 2000/01/09 20:37:57 steve
* Careful with wires connected to multiple ports.
*
* Revision 1.8 1999/12/11 05:45:41 steve
* Fix support for attaching attributes to primitive gates.
*
* Revision 1.7 1999/09/17 02:06:25 steve
* Handle unconnected module ports.
*
+81 -14
View File
@@ -1,7 +1,7 @@
#ifndef __Module_H
#define __Module_H
/*
* Copyright (c) 1998 Stephen Williams ([email protected])
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,15 +18,18 @@
* 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: Module.h,v 1.10 1999/11/27 19:07:57 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: Module.h,v 1.21 2000/11/05 06:05:59 steve Exp $"
#endif
# include <list>
# include <map>
# include "svector.h"
# include "named.h"
# include <string>
class PEvent;
class PExpr;
class PEIdent;
class PGate;
class PTask;
class PFunction;
@@ -51,9 +54,7 @@ class Module {
public:
struct port_t {
string name;
svector<PWire*>wires;
port_t(int c=0) : wires(c) { }
svector<PEIdent*> expr;
};
public:
@@ -64,6 +65,13 @@ class Module {
module is elaborated. During parsing, I put the parameters
into this map. */
map<string,PExpr*>parameters;
map<string,PExpr*>localparams;
/* The module also has defparam assignments which don't create
new parameters within the module, but may be used to set
values within this module (when instantiated) or in other
instantiated modules. */
map<string,PExpr*>defparms;
/* Parameters may be overridden at instantiation time;
the overrides do not contain explicit parameter names,
@@ -73,34 +81,54 @@ class Module {
a parameter-index to its name. */
list<string> param_names;
/* Keep a table of named events declared in the module. */
map<string,PEvent*>events;
/* These are the timescale for this module. The default is
set by the `timescale directive. */
int time_unit, time_precision;
const string&get_name() const { return name_; }
void add_gate(PGate*gate);
void add_wire(PWire*wire);
// The add_wire method adds a wire by name, but only if the
// wire name doesn't already exist. Either way, the result is
// the existing wire or the pointer passed in.
PWire* add_wire(PWire*wire);
void add_behavior(PProcess*behave);
void add_task(const string&name, PTask*def);
void add_function(const string&name, PFunction*def);
unsigned port_count() const;
const svector<PWire*>& get_port(unsigned idx) const;
const svector<PEIdent*>& get_port(unsigned idx) const;
unsigned find_port(const string&) const;
// Find a wire by name. This is used for connecting gates to
// existing wires, etc.
PWire* get_wire(const string&name);
PWire* get_wire(const string&name) const;
PGate* get_gate(const string&name);
const list<PWire*>& get_wires() const { return wires_; }
const list<PGate*>& get_gates() const { return gates_; }
const list<PProcess*>& get_behaviors() const { return behaviors_; }
const map<string,PWire*>& get_wires() const;
const list<PGate*>& get_gates() const;
const list<PProcess*>& get_behaviors() const;
void dump(ostream&out) const;
bool elaborate(Design*, NetScope*scope, svector<PExpr*>*overrides_) const;
bool elaborate(Design*, NetScope*scope) const;
bool elaborate_scope(Design*, NetScope*scope) const;
bool elaborate_sig(Design*, NetScope*scope) const;
private:
const string name_;
/* This is an array of port descriptors, which is in turn a
named array of PEident pointers. */
svector<port_t*> ports_;
list<PWire*> wires_;
map<string,PWire*> wires_;
list<PGate*> gates_;
list<PProcess*> behaviors_;
map<string,PTask*> tasks_;
@@ -114,6 +142,45 @@ class Module {
/*
* $Log: Module.h,v $
* Revision 1.21 2000/11/05 06:05:59 steve
* Handle connectsion to internally unconnected modules (PR#38)
*
* Revision 1.20 2000/07/22 22:09:03 steve
* Parse and elaborate timescale to scopes.
*
* Revision 1.19 2000/05/16 04:05:15 steve
* Module ports are really special PEIdent
* expressions, because a name can be used
* many places in the port list.
*
* Revision 1.18 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
* Revision 1.17 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.16 2000/03/12 17:09:40 steve
* Support localparam.
*
* Revision 1.15 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.14 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.13 2000/01/09 20:37:57 steve
* Careful with wires connected to multiple ports.
*
* Revision 1.12 2000/01/09 05:50:48 steve
* Support named parameter override lists.
*
* Revision 1.11 1999/12/11 05:45:41 steve
* Fix support for attaching attributes to primitive gates.
*
* Revision 1.10 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
+5 -2
View File
@@ -16,8 +16,8 @@
* 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 $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PDelays.cc,v 1.2 2000/02/23 02:56:53 steve Exp $"
#endif
# include "PDelays.h"
@@ -96,6 +96,9 @@ void PDelays::eval_delays(Design*des, const string&path,
/*
* $Log: PDelays.cc,v $
* Revision 1.2 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
+5 -2
View File
@@ -18,8 +18,8 @@
* 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 $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PDelays.h,v 1.2 2000/02/23 02:56:53 steve Exp $"
#endif
# include "svector.h"
@@ -60,6 +60,9 @@ ostream& operator << (ostream&o, const PDelays&);
/*
* $Log: PDelays.h,v $
* Revision 1.2 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
+45
View File
@@ -0,0 +1,45 @@
/*
* Copyright (c) 200Stephen 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) && !defined(macintosh)
#ident "$Id: PEvent.cc,v 1.1 2000/04/01 19:31:57 steve Exp $"
#endif
# include "PEvent.h"
PEvent::PEvent(const string&n)
: name_(n)
{
}
PEvent::~PEvent()
{
}
string PEvent::name() const
{
return name_;
}
/*
* $Log: PEvent.cc,v $
* Revision 1.1 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
*/
+65
View File
@@ -0,0 +1,65 @@
#ifndef __PEvent_H
#define __PEvent_H
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: PEvent.h,v 1.3 2000/04/09 17:44:30 steve Exp $"
#endif
# include "LineInfo.h"
# include <string>
class ostream;
class Design;
class NetScope;
/*
* The PEvent class represents event objects. These are things that
* are declared in Verilog as ``event foo;''
*/
class PEvent : public LineInfo {
public:
explicit PEvent(const string&name);
~PEvent();
string name() const;
void elaborate_scope(Design*des, NetScope*scope) const;
private:
string name_;
private: // not implemented
PEvent(const PEvent&);
PEvent& operator= (const PEvent&);
};
/*
* $Log: PEvent.h,v $
* Revision 1.3 2000/04/09 17:44:30 steve
* Catch event declarations during scope elaborate.
*
* Revision 1.2 2000/04/04 03:20:15 steve
* Simulate named event trigger and waits.
*
* Revision 1.1 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
*/
#endif
+179 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams <[email protected]>
* Copyright (c) 1998-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
@@ -16,14 +16,18 @@
* 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: PExpr.cc,v 1.11 1999/10/31 04:11:27 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PExpr.cc,v 1.22 2001/01/12 04:31:27 steve Exp $"
#endif
# include "PExpr.h"
# include "Module.h"
# include <typeinfo>
PExpr::PExpr()
{
}
PExpr::~PExpr()
{
}
@@ -41,16 +45,18 @@ bool PExpr::is_constant(Module*) const
NetNet* PExpr::elaborate_net(Design*des, const string&path, unsigned,
unsigned long,
unsigned long,
unsigned long) const
unsigned long,
Link::strength_t,
Link::strength_t) const
{
cerr << "Don't know how to elaborate `" << *this
<< "' as gates." << endl;
cerr << get_line() << ": error: Unable 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: "
cerr << get_line() << ": error: expression not valid in assign l-value: "
<< *this << endl;
return 0;
}
@@ -60,15 +66,25 @@ 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)
PECallFunction::PECallFunction(const char*n, const svector<PExpr *> &parms)
: name_(n), parms_(parms)
{
}
PECallFunction::PECallFunction(const char*n)
: name_(n)
{
}
PECallFunction::~PECallFunction()
{
}
PEConcat::PEConcat(const svector<PExpr*>&p, PExpr*r)
: parms_(p), repeat_(r)
{
}
bool PEConcat::is_constant(Module *mod) const
{
bool constant = repeat_? repeat_->is_constant(mod) : true;
@@ -83,14 +99,86 @@ PEConcat::~PEConcat()
delete repeat_;
}
PEEvent::PEEvent(PEEvent::edge_t t, PExpr*e)
: type_(t), expr_(e)
{
}
PEEvent::~PEEvent()
{
}
PEEvent::edge_t PEEvent::type() const
{
return type_;
}
PExpr* PEEvent::expr() const
{
return expr_;
}
PEFNumber::PEFNumber(verireal*v)
: value_(v)
{
}
PEFNumber::~PEFNumber()
{
delete value_;
}
const verireal& PEFNumber::value() const
{
return *value_;
}
PEIdent::PEIdent(const string&s)
: text_(s), msb_(0), lsb_(0), idx_(0)
{
}
PEIdent::~PEIdent()
{
}
string PEIdent::name() const
{
return text_;
}
/*
* An identifier can be in a constant expresion if (and only if) it is
* a parameter.
*/
bool PEIdent::is_constant(Module*mod) const
{
map<string,PExpr*>::const_iterator cur = mod->parameters.find(text_);
return cur != mod->parameters.end();
map<string,PExpr*>::const_iterator cur;
if (mod == 0) return false;
cur = mod->parameters.find(text_);
if (cur != mod->parameters.end()) return true;
cur = mod->localparams.find(text_);
if (cur != mod->localparams.end()) return true;
return false;
}
PENumber::PENumber(verinum*vp)
: value_(vp)
{
assert(vp);
}
PENumber::~PENumber()
{
delete value_;
}
const verinum& PENumber::value() const
{
return *value_;
}
bool PENumber::is_the_same(const PExpr*that) const
@@ -107,6 +195,20 @@ bool PENumber::is_constant(Module*) const
return true;
}
PEString::PEString(const string&s)
: text_(s)
{
}
PEString::~PEString()
{
}
string PEString::value() const
{
return text_;
}
bool PEString::is_constant(Module*) const
{
return true;
@@ -121,13 +223,78 @@ PETernary::~PETernary()
{
}
bool PETernary::is_constant(Module*) const
bool PETernary::is_constant(Module*m) const
{
return false;
return expr_->is_constant(m)
&& tru_->is_constant(m)
&& fal_->is_constant(m);
}
PEUnary::PEUnary(char op, PExpr*ex)
: op_(op), expr_(ex)
{
}
PEUnary::~PEUnary()
{
}
bool PEUnary::is_constant(Module*m) const
{
return expr_->is_constant(m);
}
/*
* $Log: PExpr.cc,v $
* Revision 1.22 2001/01/12 04:31:27 steve
* Handle error idents in constants not in any scope (PR#97)
*
* Revision 1.21 2000/12/16 19:03:30 steve
* Evaluate <= and ?: in parameter expressions (PR#81)
*
* Revision 1.20 2000/12/10 22:01:35 steve
* Support decimal constants in behavioral delays.
*
* Revision 1.19 2000/06/30 15:50:20 steve
* Allow unary operators in constant expressions.
*
* Revision 1.18 2000/05/07 04:37:55 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.17 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.16 2000/04/12 04:23:57 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.15 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.14 2000/03/12 18:22:11 steve
* Binary and unary operators in parameter expressions.
*
* Revision 1.13 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.12 1999/12/31 17:38:37 steve
* Standardize some of the error messages.
*
* 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
+253 -46
View File
@@ -1,7 +1,7 @@
#ifndef __PExpr_H
#define __PExpr_H
/*
* Copyright (c) 1998-1999 Stephen Williams <[email protected]>
* Copyright (c) 1998-2000 Stephen Williams <[email protected]>
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,8 +18,8 @@
* 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: PExpr.h,v 1.25 1999/11/21 00:13:08 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PExpr.h,v 1.47 2000/12/16 19:03:30 steve Exp $"
#endif
# include <string>
@@ -32,6 +32,7 @@ class Design;
class Module;
class NetNet;
class NetExpr;
class NetScope;
/*
* The PExpr class hierarchy supports the description of
@@ -43,13 +44,21 @@ class NetExpr;
*/
class PExpr : public LineInfo {
public:
PExpr();
virtual ~PExpr();
virtual void dump(ostream&) const;
// Procedural elaboration of the expression.
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope) const;
// Elaborate expressions that are the r-value of parameter
// assignments. This elaboration follows the restrictions of
// constant expressions and supports later overriding and
// evaluation of parameters.
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
// This method elaborate the expression as gates, for use in a
// continuous assign or other wholly structural context.
@@ -57,12 +66,23 @@ class PExpr : public LineInfo {
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
unsigned long decay,
Link::strength_t drive0 =Link::STRONG,
Link::strength_t drive1 =Link::STRONG)
const;
// This method elaborates the expression as NetNet objects. It
// only allows regs suitable for procedural continuous assignments.
virtual NetNet* elaborate_anet(Design*des, NetScope*scope) 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;
// Expressions that can be in the l-value of procedural
// assignments can be elaborated with this method.
virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const;
// This attempts to evaluate a constant expression, and return
// a verinum as a result. If the expression cannot be
// evaluated, return 0.
@@ -79,6 +99,9 @@ class PExpr : public LineInfo {
// of expresions.
virtual bool is_constant(Module*) const;
private: // not implemented
PExpr(const PExpr&);
PExpr& operator= (const PExpr&);
};
ostream& operator << (ostream&, const PExpr&);
@@ -86,18 +109,26 @@ ostream& operator << (ostream&, const PExpr&);
class PEConcat : public PExpr {
public:
PEConcat(const svector<PExpr*>&p, PExpr*r =0)
: parms_(p), repeat_(r) { }
PEConcat(const svector<PExpr*>&p, PExpr*r =0);
~PEConcat();
virtual void dump(ostream&) const;
// Concatenated Regs can be on the left of procedural
// continuous assignments.
virtual NetNet* elaborate_anet(Design*des, NetScope*scope) const;
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*) const;
virtual NetEConcat*elaborate_pexpr(Design*des, NetScope*) const;
virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const;
virtual bool is_constant(Module*) const;
private:
@@ -105,48 +136,92 @@ class PEConcat : public PExpr {
PExpr*repeat_;
};
/*
* Event expressions are expressions that can be combined with the
* event "or" operator. These include "posedge foo" and similar, and
* also include named events. "edge" events are associated with an
* expression, whereas named events simply have a name, which
* represents an event variable.
*/
class PEEvent : public PExpr {
public:
PEEvent(NetNEvent::Type t, PExpr*e)
: type_(t), expr_(e)
{ }
enum edge_t {ANYEDGE, POSEDGE, NEGEDGE, POSITIVE};
NetNEvent::Type type() const { return type_; }
PExpr* expr() const { return expr_; }
// Use this constructor to create events based on edges or levels.
PEEvent(edge_t t, PExpr*e);
~PEEvent();
edge_t type() const;
PExpr* expr() const;
virtual void dump(ostream&) const;
private:
edge_t type_;
PExpr *expr_;
};
/*
* This holds a floating point constant in the source.
*/
class PEFNumber : public PExpr {
public:
explicit PEFNumber(verireal*vp);
~PEFNumber();
const verireal& value() const;
/* The eval_const method as applied to a floating point number
gets the *integer* value of the number. This accounts for
any rounding that is needed to get the value. */
virtual verinum* eval_const(const Design*des, const string&path) const;
virtual void dump(ostream&) const;
private:
NetNEvent::Type type_;
PExpr*expr_;
verireal*value_;
};
class PEIdent : public PExpr {
public:
explicit PEIdent(const string&s)
: text_(s), msb_(0), lsb_(0), idx_(0) { }
explicit PEIdent(const string&s);
~PEIdent();
virtual void dump(ostream&) const;
// Regs can be on the left of procedural continuous assignments
virtual NetNet* elaborate_anet(Design*des, NetScope*scope) const;
// Identifiers are allowed (with restrictions) is assign l-values.
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
// Identifiers are also allowed as procedural assignment l-values.
virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const;
// Structural r-values are OK.
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
// Elaborate the PEIdent as a port to a module. This method
// only applies to Ident expressions.
NetNet* elaborate_port(Design*des, NetScope*sc) const;
virtual bool is_constant(Module*) const;
verinum* eval_const(const Design*des, const string&path) const;
// XXXX
string name() const { return text_; }
string name() const;
private:
string text_;
@@ -170,19 +245,21 @@ class PEIdent : public PExpr {
class PENumber : public PExpr {
public:
explicit PENumber(verinum*vp)
: value_(vp) { assert(vp); }
~PENumber() { delete value_; }
explicit PENumber(verinum*vp);
~PENumber();
const verinum& value() const { return *value_; }
const verinum& value() const;
virtual void dump(ostream&) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetEConst*elaborate_expr(Design*des, NetScope*) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual verinum* eval_const(const Design*des, const string&path) const;
virtual bool is_the_same(const PExpr*that) const;
@@ -195,12 +272,13 @@ class PENumber : public PExpr {
class PEString : public PExpr {
public:
explicit PEString(const string&s)
: text_(s) { }
explicit PEString(const string&s);
~PEString();
string value() const { return text_; }
string value() const;
virtual void dump(ostream&) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual NetEConst*elaborate_expr(Design*des, NetScope*) const;
virtual NetEConst*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual bool is_constant(Module*) const;
@@ -211,16 +289,22 @@ class PEString : public PExpr {
class PEUnary : public PExpr {
public:
explicit PEUnary(char op, PExpr*ex)
: op_(op), expr_(ex) { }
explicit PEUnary(char op, PExpr*ex);
~PEUnary();
virtual void dump(ostream&out) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetEUnary*elaborate_expr(Design*des, NetScope*) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual verinum* eval_const(const Design*des, const string&path) const;
virtual bool is_constant(Module*) const;
private:
char op_;
@@ -240,8 +324,11 @@ class PEBinary : public PExpr {
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetEBinary*elaborate_expr(Design*des, NetScope*) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual verinum* eval_const(const Design*des, const string&path) const;
private:
@@ -249,16 +336,43 @@ class PEBinary : public PExpr {
PExpr*left_;
PExpr*right_;
NetEBinary*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp) const;
NetNet* elaborate_net_add_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_bit_(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_div_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_mod_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_log_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_mul_(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,
@@ -281,10 +395,13 @@ 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;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
unsigned long rise,
unsigned long fall,
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetETernary*elaborate_expr(Design*des, NetScope*) const;
virtual NetETernary*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual verinum* eval_const(const Design*des, const string&path) const;
private:
@@ -294,25 +411,115 @@ class PETernary : public PExpr {
};
/*
* This class represents a parsed call to a function.
* This class represents a parsed call to a function, including calls
* to system functions.
*/
class PECallFunction : public PExpr {
public:
explicit PECallFunction(const string &n, const svector<PExpr *> &parms);
explicit PECallFunction(const char*n, const svector<PExpr *> &parms);
explicit PECallFunction(const char*n);
~PECallFunction();
virtual void dump(ostream &) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope) const;
private:
string name_;
svector<PExpr *> parms_;
NetESFunc* elaborate_sfunc_(Design*des, const string&path) const;
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope) const;
};
/*
* $Log: PExpr.h,v $
* Revision 1.47 2000/12/16 19:03:30 steve
* Evaluate <= and ?: in parameter expressions (PR#81)
*
* Revision 1.46 2000/12/10 22:01:35 steve
* Support decimal constants in behavioral delays.
*
* Revision 1.45 2000/12/06 06:31:09 steve
* Check lvalue of procedural continuous assign (PR#29)
*
* Revision 1.44 2000/09/17 21:26:15 steve
* Add support for modulus (Eric Aardoom)
*
* Revision 1.43 2000/09/09 15:21:26 steve
* move lval elaboration to PExpr virtual methods.
*
* Revision 1.42 2000/09/07 22:38:13 steve
* Support unary + and - in constants.
*
* Revision 1.41 2000/06/30 15:50:20 steve
* Allow unary operators in constant expressions.
*
* Revision 1.40 2000/06/13 05:22:16 steve
* Support concatenation in parameter expressions.
*
* Revision 1.39 2000/06/01 02:31:39 steve
* Parameters can be strings.
*
* Revision 1.38 2000/05/16 04:05:15 steve
* Module ports are really special PEIdent
* expressions, because a name can be used
* many places in the port list.
*
* Revision 1.37 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.36 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.35 2000/04/12 04:23:57 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.34 2000/04/01 21:40:22 steve
* Add support for integer division.
*
* Revision 1.33 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.32 2000/03/12 18:22:11 steve
* Binary and unary operators in parameter expressions.
*
* Revision 1.31 2000/03/12 04:35:22 steve
* Allow parameter identifiers in parameter expressions.
*
* Revision 1.30 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.29 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.28 2000/02/16 03:58:27 steve
* Fix up width matching in structural bitwise operators.
*
* Revision 1.27 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.26 1999/12/16 03:46:39 steve
* Structural logical or.
*
* Revision 1.25 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
+23 -4
View File
@@ -16,14 +16,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PFunction.cc,v 1.2 1999/08/25 22:22:41 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PFunction.cc,v 1.4 2001/01/13 22:20:08 steve Exp $"
#endif
#include "PTask.h"
PFunction::PFunction(svector<PWire*>*p, Statement*s)
: out_(0), ports_(p), statement_(s)
PFunction::PFunction()
: out_(0), ports_(0), statement_(0)
{
}
@@ -31,6 +31,19 @@ PFunction::~PFunction()
{
}
void PFunction::set_ports(svector<PWire *>*p)
{
assert(ports_ == 0);
ports_ = p;
}
void PFunction::set_statement(Statement*s)
{
assert(s != 0);
assert(statement_ == 0);
statement_ = s;
}
void PFunction::set_output(PWire*o)
{
assert(out_ == 0);
@@ -39,6 +52,12 @@ void PFunction::set_output(PWire*o)
/*
* $Log: PFunction.cc,v $
* Revision 1.4 2001/01/13 22:20:08 steve
* Parse parameters within nested scopes.
*
* Revision 1.3 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
+85 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
* Copyright (c) 1999-2000 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
@@ -16,8 +16,8 @@
* 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: PGate.cc,v 1.5 1999/09/14 01:50:35 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PGate.cc,v 1.9 2000/05/06 15:41:56 steve Exp $"
#endif
# include "PGate.h"
@@ -31,6 +31,8 @@ PGate::PGate(const string&name,
: name_(name), pins_(pins)
{
if (del) delay_.set_delays(del);
str0_ = STRONG;
str1_ = STRONG;
}
PGate::PGate(const string&name,
@@ -39,17 +41,45 @@ PGate::PGate(const string&name,
: name_(name), pins_(pins)
{
if (del) delay_.set_delay(del);
str0_ = STRONG;
str1_ = STRONG;
}
PGate::PGate(const string&name, svector<PExpr*>*pins)
: name_(name), pins_(pins)
{
str0_ = STRONG;
str1_ = STRONG;
}
PGate::~PGate()
{
}
PGate::strength_t PGate::strength0() const
{
return str0_;
}
void PGate::strength0(PGate::strength_t s)
{
str0_ = s;
}
PGate::strength_t PGate::strength1() const
{
return str1_;
}
void PGate::strength1(PGate::strength_t s)
{
str1_ = s;
}
void PGate::elaborate_scope(Design*, NetScope*) const
{
}
/*
* This method is used during elaboration to calculate the
* rise/fall/decay times for the gate. These values were set in pform
@@ -110,8 +140,60 @@ void PGBuiltin::set_range(PExpr*msb, PExpr*lsb)
lsb_ = lsb;
}
PGModule::PGModule(const string&type, const string&name, svector<PExpr*>*pins)
: PGate(name, pins), type_(type), overrides_(0), pins_(0),
npins_(0), parms_(0), nparms_(0), msb_(0), lsb_(0)
{
}
PGModule::PGModule(const string&type, const string&name,
named<PExpr*>*pins, unsigned npins)
: PGate(name, 0), type_(type), overrides_(0), pins_(pins),
npins_(npins), parms_(0), nparms_(0), msb_(0), lsb_(0)
{
}
void PGModule::set_parameters(svector<PExpr*>*o)
{
assert(overrides_ == 0);
overrides_ = o;
}
void PGModule::set_parameters(named<PExpr*>*pa, unsigned npa)
{
assert(parms_ == 0);
assert(overrides_ == 0);
parms_ = pa;
nparms_ = npa;
}
void PGModule::set_range(PExpr*msb, PExpr*lsb)
{
assert(msb_ == 0);
assert(lsb_ == 0);
msb_ = msb;
lsb_ = lsb;
}
/*
* $Log: PGate.cc,v $
* Revision 1.9 2000/05/06 15:41:56 steve
* Carry assignment strength to pform.
*
* Revision 1.8 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.7 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.6 2000/02/18 05:15:02 steve
* Catch module instantiation arrays.
*
* Revision 1.5 1999/09/14 01:50:35 steve
* Handle gates without delays.
*
+80 -13
View File
@@ -1,7 +1,7 @@
#ifndef __PGate_H
#define __PGate_H
/*
* Copyright (c) 1998-1999 Stephen Williams ([email protected])
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,16 +18,20 @@
* 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: PGate.h,v 1.10 1999/09/04 19:11:46 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PGate.h,v 1.18 2000/05/06 15:41:56 steve Exp $"
#endif
# include "svector.h"
# include "named.h"
# include "LineInfo.h"
# include "PDelays.h"
# include <map>
# include <string>
class PExpr;
class PUdp;
class Design;
class NetScope;
class Module;
/*
@@ -38,10 +42,17 @@ class Module;
* This pins of a gate are connected to expressions. The elaboration
* step will need to convert expressions to a network of gates in
* order to elaborate expression inputs, but that can easily be done.
*
* The PGate base class also carries the strength0 and strength1
* strengths for those gates where the driver[s] can be described by a
* single strength pair. There is a strength of the 0 drive, and a
* strength of the 1 drive.
*/
class PGate : public LineInfo {
public:
enum strength_t { HIGHZ, WEAK, PULL, STRONG, SUPPLY };
explicit PGate(const string&name, svector<PExpr*>*pins,
const svector<PExpr*>*del);
@@ -62,8 +73,18 @@ class PGate : public LineInfo {
unsigned pin_count() const { return pins_? pins_->count() : 0; }
const PExpr*pin(unsigned idx) const { return (*pins_)[idx]; }
strength_t strength0() const;
strength_t strength1() const;
void strength0(strength_t);
void strength1(strength_t);
map<string,string> attributes;
virtual void dump(ostream&out) const;
virtual void elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*sc) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
protected:
const svector<PExpr*>* get_pins() const { return pins_; }
@@ -76,6 +97,8 @@ class PGate : public LineInfo {
PDelays delay_;
svector<PExpr*>*pins_;
strength_t str0_, str1_;
private: // not implemented
PGate(const PGate&);
PGate& operator= (const PGate&);
@@ -151,35 +174,79 @@ 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*>*overrides, svector<PExpr*>*pins)
: PGate(name, pins), type_(type), overrides_(overrides), pins_(0), npins_(0) { }
svector<PExpr*>*pins);
// If the binding of ports is by name, this constructor takes
// the bindings and stores them for later elaboration.
struct bind_t {
string name;
PExpr* parm;
};
explicit PGModule(const string&type, const string&name,
svector<PExpr*>*overrides, bind_t*pins, unsigned npins)
: PGate(name, 0), type_(type), overrides_(overrides), pins_(pins), npins_(npins) { }
named<PExpr*>*pins, unsigned npins);
// Parameter overrides can come as an ordered list, or a set
// of named expressions.
void set_parameters(svector<PExpr*>*o);
void set_parameters(named<PExpr*>*pa, unsigned npa);
// Modules can be instantiated in ranges. The parser uses this
// method to pass the range to the pform.
void set_range(PExpr*msb, PExpr*lsb);
virtual void dump(ostream&out) const;
virtual void elaborate(Design*, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*sc) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
private:
string type_;
svector<PExpr*>*overrides_;
bind_t*pins_;
named<PExpr*>*pins_;
unsigned npins_;
// These members support parameter override by name
named<PExpr*>*parms_;
unsigned nparms_;
// Arrays of modules are give if these are set.
PExpr*msb_;
PExpr*lsb_;
void elaborate_mod_(Design*, Module*mod, const string&path) const;
void elaborate_udp_(Design*, PUdp *udp, const string&path) const;
void elaborate_sudp_(Design*, PUdp *udp, const string&path) const;
void elaborate_cudp_(Design*, PUdp *udp, const string&path) const;
void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const;
bool elaborate_sig_mod_(Design*des, NetScope*scope, Module*mod) const;
};
/*
* $Log: PGate.h,v $
* Revision 1.18 2000/05/06 15:41:56 steve
* Carry assignment strength to pform.
*
* Revision 1.17 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
* Revision 1.16 2000/03/29 04:37:10 steve
* New and improved combinational primitives.
*
* Revision 1.15 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.14 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.13 2000/02/18 05:15:02 steve
* Catch module instantiation arrays.
*
* Revision 1.12 2000/01/09 05:50:48 steve
* Support named parameter override lists.
*
* Revision 1.11 1999/12/11 05:45:41 steve
* Fix support for attaching attributes to primitive gates.
*
* Revision 1.10 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
+24 -4
View File
@@ -16,14 +16,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PTask.cc,v 1.2 1999/07/24 02:11:19 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PTask.cc,v 1.4 2001/01/13 22:20:08 steve Exp $"
#endif
# include "PTask.h"
PTask::PTask(svector<PWire*>*p, Statement*s)
: ports_(p), statement_(s)
PTask::PTask()
: ports_(0), statement_(0)
{
}
@@ -31,8 +31,28 @@ PTask::~PTask()
{
}
void PTask::set_ports(svector<PWire*>*p)
{
assert(ports_ == 0);
ports_ = p;
}
void PTask::set_statement(Statement*s)
{
assert(statement_ == 0);
assert(s != 0);
statement_ = s;
}
/*
* $Log: PTask.cc,v $
* Revision 1.4 2001/01/13 22:20:08 steve
* Parse parameters within nested scopes.
*
* Revision 1.3 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 1999/07/24 02:11:19 steve
* Elaborate task input ports.
*
+49 -10
View File
@@ -1,7 +1,7 @@
#ifndef __PTask_H
#define __PTask_H
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
* Copyright (c) 1999-2000 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,14 +18,15 @@
* 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: PTask.h,v 1.6 1999/09/30 21:28:34 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PTask.h,v 1.10 2001/01/13 22:20:08 steve Exp $"
#endif
# include "LineInfo.h"
# include "svector.h"
# include <string>
class Design;
class NetScope;
class PWire;
class Statement;
@@ -35,11 +36,23 @@ class Statement;
class PTask : public LineInfo {
public:
explicit PTask(svector<PWire*>*p, Statement*s);
explicit PTask();
~PTask();
void elaborate_1(Design*des, const string&path) const;
void elaborate_2(Design*des, const string&path) const;
void set_ports(svector<PWire *>*p);
void set_statement(Statement *s);
// Tasks introduce scope, to need to be handled during the
// scope elaboration pass. The scope passed is my scope,
// created by the containing scope. I fill it in with stuff if
// I need to.
void elaborate_scope(Design*des, NetScope*scope) const;
// Bind the ports to the regs that are the ports.
void elaborate_sig(Design*des, NetScope*scope) const;
// Elaborate the statement to finish off the task definition.
void elaborate(Design*des, const string&path) const;
void dump(ostream&, unsigned) const;
@@ -60,14 +73,20 @@ class PTask : public LineInfo {
class PFunction : public LineInfo {
public:
explicit PFunction(svector<PWire *>*p, Statement *s);
explicit PFunction();
~PFunction();
void set_ports(svector<PWire *>*p);
void set_statement(Statement *s);
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 elaborate_scope(Design*des, NetScope*scope) const;
/* elaborate the ports and return value. */
void elaborate_sig(Design *des, NetScope*) const;
/* Elaborate the behavioral statement. */
void elaborate(Design *des, NetScope*) const;
void dump(ostream&, unsigned) const;
@@ -79,6 +98,26 @@ class PFunction : public LineInfo {
/*
* $Log: PTask.h,v $
* Revision 1.10 2001/01/13 22:20:08 steve
* Parse parameters within nested scopes.
*
* Revision 1.9 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.8 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.7 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.6 1999/09/30 21:28:34 steve
* Handle mutual reference of tasks by elaborating
* task definitions in two passes, like functions.
+6 -3
View File
@@ -1,7 +1,7 @@
#ifndef __PUdp_H
#define __PUdp_H
/*
* Copyright (c) 1998 Stephen Williams ([email protected])
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,8 +18,8 @@
* 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: PUdp.h,v 1.3 1999/06/15 03:44:53 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PUdp.h,v 1.4 2000/02/23 02:56:53 steve Exp $"
#endif
# include <map>
@@ -82,6 +82,9 @@ class PUdp {
/*
* $Log: PUdp.h,v $
* Revision 1.4 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/06/15 03:44:53 steve
* Get rid of the STL vector template.
*
+24 -6
View File
@@ -16,15 +16,15 @@
* 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: PWire.cc,v 1.2 1999/09/10 05:02:09 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PWire.cc,v 1.5 2001/01/06 02:29:35 steve Exp $"
#endif
# include "PWire.h"
# include <assert.h>
PWire::PWire(const string&n, NetNet::Type t, NetNet::PortType pt)
: name_(n), type_(t), port_type_(pt), lidx_(0), ridx_(0)
: name_(n), type_(t), port_type_(pt), signed_(false), lidx_(0), ridx_(0)
{
}
@@ -43,11 +43,9 @@ bool PWire::set_wire_type(NetNet::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; }
return false;
default:
if (type_ != t)
@@ -83,6 +81,16 @@ bool PWire::set_port_type(NetNet::PortType pt)
}
}
void PWire::set_signed(bool flag)
{
signed_ = flag;
}
bool PWire::get_signed() const
{
return signed_;
}
void PWire::set_range(PExpr*m, PExpr*l)
{
msb_ = svector<PExpr*>(msb_,m);
@@ -93,13 +101,23 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
{
assert(lidx_ == 0);
assert(ridx_ == 0);
assert((type_ == NetNet::REG) || (type_ == NetNet::INTEGER));
assert(type_ == NetNet::REG);
lidx_ = ldx;
ridx_ = rdx;
}
/*
* $Log: PWire.cc,v $
* Revision 1.5 2001/01/06 02:29:35 steve
* Support arrays of integers.
*
* Revision 1.4 2000/12/11 00:31:43 steve
* Add support for signed reg variables,
* simulate in t-vvm signed comparisons.
*
* Revision 1.3 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 1999/09/10 05:02:09 steve
* Handle integers at task parameters.
*
+18 -4
View File
@@ -1,7 +1,7 @@
#ifndef __PWire_H
#define __PWire_H
/*
* Copyright (c) 1998 Stephen Williams ([email protected])
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,8 +18,8 @@
* 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: PWire.h,v 1.6 1999/11/27 19:07:57 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PWire.h,v 1.9 2000/12/11 00:31:43 steve Exp $"
#endif
# include "netlist.h"
@@ -49,6 +49,9 @@ class PWire : public LineInfo {
NetNet::PortType get_port_type() const;
bool set_port_type(NetNet::PortType);
void set_signed(bool flag);
bool get_signed() const;
void set_range(PExpr*msb, PExpr*lsb);
void set_memory_idx(PExpr*ldx, PExpr*rdx);
@@ -58,12 +61,13 @@ class PWire : public LineInfo {
// Write myself to the specified stream.
void dump(ostream&out) const;
void elaborate(Design*, NetScope*scope) const;
void elaborate_sig(Design*, NetScope*scope) const;
private:
string name_;
NetNet::Type type_;
NetNet::PortType port_type_;
bool signed_;
// These members hold expressions for the bit width of the
// wire. If they do not exist, the wire is 1 bit wide.
@@ -82,6 +86,16 @@ class PWire : public LineInfo {
/*
* $Log: PWire.h,v $
* Revision 1.9 2000/12/11 00:31:43 steve
* Add support for signed reg variables,
* simulate in t-vvm signed comparisons.
*
* Revision 1.8 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
* Revision 1.7 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.6 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
+182 -123
View File
@@ -1,23 +1,24 @@
THE ICARUS VERILOG COMPILATION SYSTEM
September 18, 1999
September 17, 2000
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. For a
view of the current state of Icarus Verilog, see its home page at
<http://www.icarus.com/eda/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. 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. In the
future, backends are expected for EDIF/LPM, structural Verilog, etc.
Icarus Verilog 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. In the future, backends are expected for EDIF/LPM,
structural Verilog, VHDL, etc.
2.0 Building/Installing IVL From Source
2.0 Building/Installing Icarus Verilog 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
@@ -33,15 +34,26 @@ 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.
satisfactory make. BSD based systems (i.e. NetBSD, FreeBSD)
typically have GNU make as the gmake program.
- 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.
The ivl and ivlpp programs are written in C++ and make use
of templates and some of the standard C++ library. egcs and
recent gcc compilers with the associated libstdc++ are known
to work. MSVC++ 5 and 6 are known to definitely *not* work.
- bison
- gperf 2.7
The lexical analyzer doesn't recognize keywords directly,
but instead matches symbols and looks them up in a hash
table in order to get the proper lexical code. The gperf
program generates the lookup table.
A version problem with this program is the most common cause
of difficulty. See the Icarus Verilog FAQ.
2.2 Compilation
Unpack the tar-ball and cd into the verilog-######### directory
@@ -60,7 +72,7 @@ root.
make install
3.0 How IVL Works
3.0 How Icarus Verilog Works
This tool includes a parser which reads in Verilog (plus extensions)
and generates an internal netlist. The netlist is passed to various
@@ -86,8 +98,8 @@ 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>.
``-P <path>'' flag to the compiler. This will cause iverilog to dump
the PFORM into the file named <path>.
3.3 Elaboration
@@ -95,7 +107,8 @@ 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.) Final semantic checks are performed during
elaboration, and some simple optimizations are performed.
elaboration, and some simple optimizations are performed. The netlist
includes all the behavioral descriptions, as well as gates and wires.
The elaborate() function performs the elaboration.
@@ -104,6 +117,31 @@ 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>.
Elaboration is actually performed it two steps: scopes and parameters
first, followed by the structural and behavioral elaboration.
3.3.1 Scope Elaboration
This pass scans through the pform looking for scopes and parameters. A
tree of NetScope objects is built up and placed in the Design object,
with the root module represented by the root NetScope object. The
elab_scope.cc and elab_pexpr.cc files contain most of the code for
handling this phase.
The tail of the elaborate_scope behavior (after the pform is
traversed) includes a scan of the NetScope tree to locate defparam
assignments that were collected during scope elaboration. This is when
the defparam overrides are applied to the parameters.
3.3.2 Netlist Elaboration
After the scopes and parameters are generated and the NetScope tree
fully formed, the elaboration runs through the pform again, this time
generating the structural and behavioral netlist. Parameters are
elaborated and evaluated by now so all the constants of code
generation are now known locally, so the netlist can be generated by
simply passing through the pform.
3.4 Optimization
This is actually a collection of processing steps that perform
@@ -114,7 +152,7 @@ some useful transformations would be,
- combinational reduction
- Constant propagation
The actual functions performed are specified on the command line by
The actual functions performed are specified on the ivl command line by
the -F flags (See below).
3.5 Code Generation
@@ -127,20 +165,50 @@ The emit() method of the Design class performs this step. It runs
through the design elements, calling target functions as need arises
to generate actual output.
The target code generator to used is given by the -t flag on the
The user selects the target code generator with the -t flag on the
command line.
4.0 Running Verilog
3.6 ATTRIBUTES
The preferred way to invoke the compiler with the verilog(1)
The parser accepts as an extension to Verilog the $attribute module
item. The syntax of the $attribute item is:
$attribute (<identifier>, <key>, <value>);
The $attribute keyword looks like a system task invocation. The
difference here is that the parameters are more restricted then those
of a system task. The <identifier> must be an identifier. This will be
the item to get an attribute. The <key> and <value> are strings, not
expressions, that give the key and the value of the attribute to be
attached to the identified object.
Attributes are [<key> <value>] pairs and are used to communicate with
the various processing steps. See the documentation for the processing
step for a list of the pertinent attributes.
Attributes can also be applied to gate types. When this is done, the
attribute is given to every instantiation of the primitive. The syntax
for the attribute statement is the same, except that the <identifier>
names a primitive earlier in the compilation unit and the statement is
placed in global scope, instead of within a module. The semicolon is
not part of a type attribute.
Note that attributes are also occasionally used for communication
between processing steps. Processing steps that are aware of others
may place attributes on netlist objects to communicate information to
later steps.
4.0 Running iverilog
The preferred way to invoke the compiler is with the iverilog(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.
done in a friendly way. See the iverilog(1) man page for usage details.
4.1 Running IVL Directly
4.1 Running IVL Directly (not recommended)
The ivl command is the compiler driver, that invokes the parser,
optimization functions and the code generator.
optimization functions and the code generator, but not the preprocessor.
Usage: ivl <options>... file
ivl -h
@@ -166,6 +234,17 @@ Usage: ivl <options>... file
target specific information to the target back-end, or
options/parameters to optimization functions, if any are defined.
-m <module>
Cause a named VPI module to be included in the module
list. This parameter appends the named module to the end of
the VPI_MODULE_LIST. This is an ordered list of modules to be
loaded into the simulation at runtime.
This list can also be set with -fVPI_MODULE_LIST=<list> which
sets the list completely. Then, -m after this will append
module names to the list sp specified. The default list
includes "system".
-N <file>
Dump the elaborated netlist to the named file. The netlist is
the folly elaborated netlist, after all the function modules
@@ -189,6 +268,11 @@ Usage: ivl <options>... file
file. If there are multiple modules, use this option to select
the module to be used as the top-level module.
-T [min|typ|max]
Normally, ivl will select typ values from min:type:max
expressions and print a warning. This flag tells the compiler
exactly which value to choose, and suppresses the warning.
-t <name>
Select the output format for the compiled result. Use the
"ivl -h" command to get a list of configured targets.
@@ -196,39 +280,7 @@ Usage: ivl <options>... file
-v
Print version and copyright information for ivl.
ATTRIBUTES
The parser accepts as an extension to Verilog the $attribute module
item. The syntax of the $attribute item is:
$attribute (<identifier>, <key>, <value>);
The $attribute keyword looks like a system task invocation. The
difference here is that the parameters are more restricted then those
of a system task. The <identifier> must be an identifier. This will be
the item to get an attribute. The <key> and <value> are strings, not
expressions, that give the key and the value of the attribute to be
attached to the identified object.
Attributes are [<key> <value>] pairs and are used to communicate with
the various processing steps. See the documentation for the processing
step for a list of the pertinent attributes.
Attributes can also be applied to gate types. When this is done, the
attribute is given to every instantiation of the primitive. The syntax
for the attribute statement is the same, except that the <identifier>
names a primitive earlier in the compilation unit and the statement is
placed in global scope, instead of within a module. The semicolon is
not part of a type attribute.
Currently, type attributes are only supported for UDP types.
Note that attributes are also occasionally used for communication
between processing steps. Processing steps that are aware of others
may place attributes on netlist objects to communicate information to
later steps.
4.1 EXAMPLES
4.2 EXAMPLES
Example: Compiling "hello.vl"
@@ -245,45 +297,30 @@ endmodule
--------------------------------------------------------------
Insure that "verilog" is on your search path, and the vpi library
Insure that "iverilog" is on your search path, and the vpi library
is available.
For csh -
To compile the program:
setenv PATH /usr/local/bin:$PATH
setenv VPI_MODULE_PATH /usr/local/lib/ivl
verilog hello.vl
iverilog 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 gcc.)
To run the program
To run the program:
./hello
./a.out
You can use the "-o" switch to name the output command to be generated
by the compiler. See the iverilog(1) man page.
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. 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);
- Memories work, but only in procedural code.
reg [1:0] b [2:0], bar;
wire [1:0] foo;
always foo = b[i]; // sorry
always @(i) bar = b[i]; // OK
- `timescale directive
- force/release/assign/deassign procedural assignments not
supported.
Icarus Verilog 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. 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.
- block disable not supported, i.e.:
@@ -293,62 +330,41 @@ current state of support for Verilog.
[...]
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.
- real data types not supported. This includes real and realtime.
assign foo = a * b; // sorry
always @(a or b) foo = a * b; // sorry
- System functions are supported, but the compiler presumes that
they return 32 bits. This is the typical case.
- event data type is not supported.
- Specify blocks are parsed but ignored in general.
- 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.
- trireg is not supported. tri0 and tri1 are supported.
6.0 CREDITS
Except where otherwise noted, ivl and ivlpp are Copyright Stephen
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):
Except where otherwise noted, Icarus Verilog, ivl and ivlpp are
Copyright Stephen 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]>
Stephan I. Boettcher <[email protected]>
Ed Carter <[email protected]>
Larry Doolittle <[email protected]>
Guy Hutchison <[email protected]>
Ales Hvezda <[email protected]>
James Lee <jml@seva.com>
Yasuhisa Kato <ykato@mac.com>
James Lee <[email protected]>
Peter Monta <[email protected]>
Daniel H. Nelsen <[email protected]>
Stefan Petersen <[email protected]>
Jason Schonberg <schon@mips.com>
Jason Schonberg <schonm@yahoo.com>
Stuart Sutherland <[email protected]>
Stephen Tell <[email protected]>
Stefan Theide <[email protected]>
@@ -357,3 +373,46 @@ especially testing from many people, including (in alphabetical order):
and others. Testers in particular include a larger community of people
interested in a GPL Verilog for Linux. Special thanks to Steve Wilson
for collecting and organizing the test suite code for all those testers.
6.1 PORT MAINTAINERS
This is a list of people who have created ports and precompiled
packages for various operating systems. These folks have graciously
taken on the task of building Icarus Verilog on their systems and
bundled it into neat packages.(*) If you want to be added to the list (or
removed from the list) send e-mail to me.
FreeBSD/{Intel,alpha}
*maintainer needed*
Linux/{alpha,Intel} (RPMS)
Stephen Williams <[email protected]>
Linux/* (.debs)
Hamish Moffatt <[email protected]>
Macintosh -- MacO/S
Yasuhisa Kato <[email protected]>
NetBSD/*
Dan <[email protected]>
Solaris/SPARC packages (.pkg)
Dan McMahill <[email protected]>
Cygwin32/*
Venkat Iyer <[email protected]>
(*) These are not the only systems where Icarus Verilog has been run,
just the systems where precompiled binaries are publicly available.
6.2 TEST SUITE MANAGER
Steve Wilson <[email protected]> or <[email protected]> has taken on
the large task of managing the test suite. He has maintained the
regression test scripts, the driver list, received submissions from
myself and others, and has written a great many tests on his own. Any
compiler writer, for any language, will tell you that the test suite
is at least as important as the compiler code itself.
+128 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams ([email protected])
* Copyright (c) 1998-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
@@ -16,8 +16,8 @@
* 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: Statement.cc,v 1.16 1999/09/29 18:36:02 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: Statement.cc,v 1.22 2000/07/26 05:08:07 steve Exp $"
#endif
# include "Statement.h"
@@ -122,6 +122,22 @@ PCase::~PCase()
delete[]items_;
}
PCAssign::PCAssign(PExpr*l, PExpr*r)
: lval_(l), expr_(r)
{
}
PCAssign::~PCAssign()
{
delete lval_;
delete expr_;
}
PCondit::PCondit(PExpr*ex, Statement*i, Statement*e)
: expr_(ex), if_(i), else_(e)
{
}
PCondit::~PCondit()
{
delete expr_;
@@ -129,6 +145,68 @@ PCondit::~PCondit()
delete else_;
}
PDeassign::PDeassign(PExpr*l)
: lval_(l)
{
}
PDeassign::~PDeassign()
{
delete lval_;
}
PDelayStatement::PDelayStatement(PExpr*d, Statement*st)
: delay_(d), statement_(st)
{
}
PDelayStatement::~PDelayStatement()
{
}
PDisable::PDisable(const string&sc)
: scope_(sc)
{
}
PDisable::~PDisable()
{
}
PEventStatement::PEventStatement(const svector<PEEvent*>&ee)
: expr_(ee), statement_(0)
{
}
PEventStatement::PEventStatement(PEEvent*ee)
: expr_(1), statement_(0)
{
expr_[0] = ee;
}
PEventStatement::~PEventStatement()
{
// delete the events and the statement?
}
void PEventStatement::set_statement(Statement*st)
{
statement_ = st;
}
PForce::PForce(PExpr*l, PExpr*r)
: lval_(l), expr_(r)
{
}
PForce::~PForce()
{
delete lval_;
delete expr_;
}
PForever::PForever(Statement*s)
: statement_(s)
{
@@ -144,6 +222,16 @@ PProcess::~PProcess()
delete statement_;
}
PRelease::PRelease(PExpr*l)
: lval_(l)
{
}
PRelease::~PRelease()
{
delete lval_;
}
PRepeat::PRepeat(PExpr*e, Statement*s)
: expr_(e), statement_(s)
{
@@ -155,6 +243,15 @@ PRepeat::~PRepeat()
delete statement_;
}
PTrigger::PTrigger(const string&e)
: event_(e)
{
}
PTrigger::~PTrigger()
{
}
PWhile::~PWhile()
{
delete cond_;
@@ -163,6 +260,34 @@ PWhile::~PWhile()
/*
* $Log: Statement.cc,v $
* Revision 1.22 2000/07/26 05:08:07 steve
* Parse disable statements to pform.
*
* Revision 1.21 2000/05/11 23:37:26 steve
* Add support for procedural continuous assignment.
*
* Revision 1.20 2000/04/22 04:20:19 steve
* Add support for force assignment.
*
* Revision 1.19 2000/04/12 04:23:57 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.18 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.17 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.16 1999/09/29 18:36:02 steve
* Full case support
*
+158 -15
View File
@@ -1,7 +1,7 @@
#ifndef __Statement_H
#define __Statement_H
/*
* Copyright (c) 1998 Stephen Williams ([email protected])
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,8 +18,8 @@
* 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: Statement.h,v 1.20 1999/09/29 18:36:02 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: Statement.h,v 1.29 2000/09/09 15:21:26 steve Exp $"
#endif
# include <string>
@@ -30,6 +30,11 @@
class PExpr;
class Statement;
class PEventStatement;
class Design;
class NetAssign_;
class NetCAssign;
class NetDeassign;
class NetScope;
/*
* The PProcess is the root of a behavioral process. Each process gets
@@ -70,6 +75,7 @@ class Statement : public LineInfo {
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
};
/*
@@ -88,9 +94,7 @@ class PAssign_ : public Statement {
const PExpr* rval() const { return rval_; }
protected:
NetNet*elaborate_lval(Design*, const string&path,
unsigned&lsb, unsigned&msb,
NetExpr*&mux) const;
NetAssign_* elaborate_lval(Design*, NetScope*scope) const;
PDelays delay_;
PEventStatement*event_;
@@ -155,6 +159,7 @@ class PBlock : public Statement {
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
private:
string name_;
@@ -204,6 +209,7 @@ class PCase : public Statement {
~PCase();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -217,14 +223,28 @@ class PCase : public Statement {
PCase& operator= (const PCase&);
};
class PCAssign : public Statement {
public:
explicit PCAssign(PExpr*l, PExpr*r);
~PCAssign();
virtual NetCAssign* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
PExpr*lval_;
PExpr*expr_;
};
class PCondit : public Statement {
public:
PCondit(PExpr*ex, Statement*i, Statement*e)
: expr_(ex), if_(i), else_(e) { }
PCondit(PExpr*ex, Statement*i, Statement*e);
~PCondit();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -237,34 +257,72 @@ class PCondit : public Statement {
PCondit& operator= (const PCondit&);
};
class PDeassign : public Statement {
public:
explicit PDeassign(PExpr*l);
~PDeassign();
virtual NetDeassign* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
PExpr*lval_;
};
class PDelayStatement : public Statement {
public:
PDelayStatement(PExpr*d, Statement*st)
: delay_(d), statement_(st) { }
PDelayStatement(PExpr*d, Statement*st);
~PDelayStatement();
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
private:
PExpr*delay_;
Statement*statement_;
};
/*
* This represends the parsing of a disable <scope> statement.
*/
class PDisable : public Statement {
public:
explicit PDisable(const string&sc);
~PDisable();
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
private:
string scope_;
};
/*
* The event statement represents the event delay in behavioral
* code. It comes from such things as:
*
* @name <statement>;
* @(expr) <statement>;
*/
class PEventStatement : public Statement {
public:
PEventStatement(const svector<PEEvent*>&ee)
: expr_(ee), statement_(0) { }
explicit PEventStatement(const svector<PEEvent*>&ee);
explicit PEventStatement(PEEvent*ee);
PEventStatement(PEEvent*ee)
: expr_(1), statement_(0) { expr_[0] = ee; }
~PEventStatement();
void set_statement(Statement*st) { statement_ = st; }
void set_statement(Statement*st);
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
// This method is used to elaborate, but attach a previously
// elaborated statement to the event.
@@ -275,12 +333,27 @@ class PEventStatement : public Statement {
Statement*statement_;
};
class PForce : public Statement {
public:
explicit PForce(PExpr*l, PExpr*r);
~PForce();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
PExpr*lval_;
PExpr*expr_;
};
class PForever : public Statement {
public:
explicit PForever(Statement*s);
~PForever();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -297,6 +370,7 @@ class PForStatement : public Statement {
{ }
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -323,6 +397,7 @@ class PRepeat : public Statement {
~PRepeat();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -330,6 +405,36 @@ class PRepeat : public Statement {
Statement*statement_;
};
class PRelease : public Statement {
public:
explicit PRelease(PExpr*l);
~PRelease();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
PExpr*lval_;
};
/*
* The PTrigger statement sends a trigger to a named event. Take the
* name here.
*/
class PTrigger : public Statement {
public:
explicit PTrigger(const string&ev);
~PTrigger();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
string event_;
};
class PWhile : public Statement {
public:
@@ -338,6 +443,7 @@ class PWhile : public Statement {
~PWhile();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -347,6 +453,43 @@ class PWhile : public Statement {
/*
* $Log: Statement.h,v $
* Revision 1.29 2000/09/09 15:21:26 steve
* move lval elaboration to PExpr virtual methods.
*
* Revision 1.28 2000/09/03 17:58:35 steve
* Change elaborate_lval to return NetAssign_ objects.
*
* Revision 1.27 2000/07/26 05:08:07 steve
* Parse disable statements to pform.
*
* Revision 1.26 2000/05/11 23:37:26 steve
* Add support for procedural continuous assignment.
*
* Revision 1.25 2000/04/22 04:20:19 steve
* Add support for force assignment.
*
* Revision 1.24 2000/04/12 04:23:57 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.23 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.22 2000/03/11 03:25:51 steve
* Locate scopes in statements.
*
* Revision 1.21 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.20 1999/09/29 18:36:02 steve
* Full case support
*
+6
View File
@@ -0,0 +1,6 @@
# The make check target uses this to check the compilation of the
# compiler.
[-tvvm-check]
<ivl>./ivl %W %[s-s%s] %[N-N%N] %[T-T%T] -tvvm -Fcprop -Fnodangle -fVPI_MODULE_PATH=vpi %f %m -o%o.cc -- -
+49 -3
View File
@@ -1,7 +1,7 @@
#ifndef __compiler_H
#define __compiler_H
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
* Copyright (c) 1999-2000 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,8 +18,8 @@
* 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: compiler.h,v 1.1 1999/06/06 20:42:48 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: compiler.h,v 1.5 2000/10/31 17:49:02 steve Exp $"
#endif
/*
@@ -33,8 +33,54 @@
# define INTEGER_WIDTH 32
#endif
/* The TIME_WIDTH is the width of time variables. */
#ifndef TIME_WIDTH
# define TIME_WIDTH 64
#endif
/*
* When doing dynamic linking, we need a uniform way to identify the
* symbol. Some compilers put leading _, some trailing _. The
* configure script figures out which is the local convention and
* defines NEED_LU and NEED_TU as required.
*/
#ifdef NEED_LU
#define LU "_"
#else
#define LU ""
#endif
#ifdef NEED_TU
#define TU "_"
#else
#define TU ""
#endif
/*
* These are flags to enable various sorts of warnings. By default all
* the warnings are of, the -W<list> parameter arranges for each to be
* enabled.
*/
/* Implicit definitions of wires. */
extern bool warn_implicit;
/*
* $Log: compiler.h,v $
* Revision 1.5 2000/10/31 17:49:02 steve
* Support time variables.
*
* Revision 1.4 2000/08/20 04:13:56 steve
* Add ivl_target support for logic gates, and
* make the interface more accessible.
*
* Revision 1.3 2000/03/17 21:50:25 steve
* Switch to control warnings.
*
* Revision 1.2 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1999/06/06 20:42:48 steve
* Make compiler width a compile time constant.
*
+135 -1
View File
@@ -6,6 +6,140 @@ AC_PROG_CC
AC_PROG_CXX
AC_CHECK_TOOL(STRIP, strip, true)
AC_CHECK_HEADERS(getopt.h)
AC_CHECK_HEADER(ipal.h, HAVE_IPAL=yes, HAVE_IPAL=)
AC_SUBST(HAVE_IPAL)
AC_PROG_INSTALL
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile)
# --
# Look for a dl library to use. First look for the standard dlopen
# functions, and failing that look for the HP specific shl_load function.
AC_CHECK_HEADERS(dlfcn.h dl.h, break)
DLLIB=''
AC_CHECK_LIB(dl,dlopen,[DLLIB=-ldl])
if test -z "$DLLIB" ; then
AC_CHECK_LIB(dld,shl_load,[DLLIB=-ldld])
fi
AC_SUBST(DLLIB)
AC_CANONICAL_HOST
# $host
#######################
## test for underscores. The vpi module loader in vvm needs to know this
## in order to know the name of the start symbol for the .vpi module.
#######################
AC_CYGWIN
AC_EXEEXT
AC_SUBST(CYGWIN)
AC_SUBST(EXEEXT)
AC_MSG_CHECKING("for leading and/or trailing underscores")
cat << EOF > underscore.c
void underscore(void){}
EOF
$CC -shared -c underscore.c > /dev/null 2>&1
CC_LEADING_UNDERSCORE=no
CC_TRAILING_UNDERSCORE=no
output=`nm underscore.o|grep _underscore 2>&1`
if test ! -z "$output" -a -z "$CYGWIN" ; then
CC_LEADING_UNDERSCORE=yes
AC_DEFINE(NEED_LU)
fi
output=`nm underscore.o|grep underscore_ 2>&1`
if test ! -z "$output"; then
CC_TRAILING_UNDERSCORE=yes
AC_DEFINE(NEED_TU)
fi
if test "$CC_LEADING_UNDERSCORE" = yes; then
AC_DEFINE(WLU)
fi
if test "$CC_TRAILING_UNDERSCORE" = yes; then
AC_DEFINE(WTU)
fi
rm underscore.c underscore.o
AC_MSG_RESULT("$CC_LEADING_UNDERSCORE $CC_TRAILING_UNDERSCORE")
#######################
## end of test for underscores
#######################
# The -fPIC flag is used to tell the compiler to make position
# independent code. It is needed when making shared objects.
AC_MSG_CHECKING("for flag to make position independent code")
PICFLAG=-fPIC
case "${host}" in
*-*-cygwin*)
PICFLAG=
;;
*-*-hpux*)
PICFLAG=+z
;;
esac
AC_SUBST(PICFLAG)
AC_MSG_RESULT($PICFLAG)
# The -rdynamic flag is used by iverilog when compiling the target,
# to know how to export symbols of the main program to loadable modules
# that are brought in by -ldl
AC_MSG_CHECKING("for -rdynamic compiler flag")
rdynamic=-rdynamic
case "${host}" in
*-*-netbsd*)
rdynamic="-Wl,--export-dynamic"
;;
*-*-solaris*)
rdynamic=""
;;
*-*-cygwin*)
rdynamic=""
;;
*-*-hpux*)
rdynamic="-E"
;;
esac
AC_SUBST(rdynamic)
AC_MSG_RESULT($rdynamic)
AC_MSG_CHECKING("for shared library link flag")
shared=-shared
case "${host}" in
*-*-cygwin*)
shared="-mdll -Wl,--enable-auto-image-base"
;;
*-*-hpux*)
shared="-b"
;;
esac
AC_SUBST(shared)
AC_MSG_RESULT($shared)
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile driver/Makefile tgt-null/Makefile tgt-stub/Makefile tgt-verilog/Makefile tgt-pal/Makefile)
+813 -118
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams ([email protected])
* Copyright (c) 1998-2000 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
@@ -16,13 +16,17 @@
* 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: cprop.cc,v 1.2 1998/12/02 04:37:13 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: cprop.cc,v 1.23 2000/12/30 03:11:15 steve Exp $"
#endif
# include "netlist.h"
# include "netmisc.h"
# include "functor.h"
# include <assert.h>
/*
* The cprop function below invokes constant propogation where
* possible. The elaboration generates NetConst objects. I can remove
@@ -30,163 +34,854 @@
* may even be able to replace nets with a new constant.
*/
static bool is_a_const_node(const NetNode*obj)
struct cprop_functor : public functor_t {
unsigned count;
virtual void lpm_add_sub(Design*des, NetAddSub*obj);
virtual void lpm_ff(Design*des, NetFF*obj);
virtual void lpm_logic(Design*des, NetLogic*obj);
virtual void lpm_mux(Design*des, NetMux*obj);
};
void cprop_functor::lpm_add_sub(Design*des, NetAddSub*obj)
{
return dynamic_cast<const NetConst*>(obj);
// For now, only additions are handled.
if (obj->attribute("LPM_Direction") != "ADD")
return;
// If the low bit on the A side is 0, then eliminate it from
// the adder, and pass the B side directly to the
// result. Don't reduce the adder smaller then a 1-bit
// adder. These will be eliminated later.
while ((obj->width() > 1)
&& link_drivers_constant(obj->pin_DataA(0))
&& (driven_value(obj->pin_DataA(0)) == verinum::V0)) {
NetAddSub*tmp = 0;
tmp = new NetAddSub(obj->name(), obj->width()-1);
//connect(tmp->pin_Aclr(), obj->pin_Aclr());
//connect(tmp->pin_Add_Sub(), obj->pin_Add_Sub());
//connect(tmp->pin_Clock(), obj->pin_Clock());
//connect(tmp->pin_Cin(), obj->pin_Cin());
connect(tmp->pin_Cout(), obj->pin_Cout());
//connect(tmp->pin_Overflow(), obj->pin_Overflow());
for (unsigned idx = 0 ; idx < tmp->width() ; idx += 1) {
connect(tmp->pin_DataA(idx), obj->pin_DataA(idx+1));
connect(tmp->pin_DataB(idx), obj->pin_DataB(idx+1));
connect(tmp->pin_Result(idx), obj->pin_Result(idx+1));
}
connect(obj->pin_Result(0), obj->pin_DataB(0));
delete obj;
des->add_node(tmp);
obj = tmp;
count += 1;
}
// Now do the same thing on the B side.
while ((obj->width() > 1)
&& link_drivers_constant(obj->pin_DataB(0))
&& (driven_value(obj->pin_DataB(0)) == verinum::V0)) {
NetAddSub*tmp = 0;
tmp = new NetAddSub(obj->name(), obj->width()-1);
//connect(tmp->pin_Aclr(), obj->pin_Aclr());
//connect(tmp->pin_Add_Sub(), obj->pin_Add_Sub());
//connect(tmp->pin_Clock(), obj->pin_Clock());
//connect(tmp->pin_Cin(), obj->pin_Cin());
connect(tmp->pin_Cout(), obj->pin_Cout());
//connect(tmp->pin_Overflow(), obj->pin_Overflow());
for (unsigned idx = 0 ; idx < tmp->width() ; idx += 1) {
connect(tmp->pin_DataA(idx), obj->pin_DataA(idx+1));
connect(tmp->pin_DataB(idx), obj->pin_DataB(idx+1));
connect(tmp->pin_Result(idx), obj->pin_Result(idx+1));
}
connect(obj->pin_Result(0), obj->pin_DataA(0));
delete obj;
des->add_node(tmp);
obj = tmp;
count += 1;
}
// If the adder is only 1 bit wide, then replace it with the
// simple logic gate.
if (obj->width() == 1) {
NetLogic*tmp;
if (obj->pin_Cout().is_linked()) {
tmp = new NetLogic(obj->scope(),
des->local_symbol(obj->name()), 3,
NetLogic::AND);
connect(tmp->pin(0), obj->pin_Cout());
connect(tmp->pin(1), obj->pin_DataA(0));
connect(tmp->pin(2), obj->pin_DataB(0));
des->add_node(tmp);
}
tmp = new NetLogic(obj->scope(), obj->name(), 3, NetLogic::XOR);
connect(tmp->pin(0), obj->pin_Result(0));
connect(tmp->pin(1), obj->pin_DataA(0));
connect(tmp->pin(2), obj->pin_DataB(0));
delete obj;
des->add_node(tmp);
count += 1;
return;
}
}
static bool const_into_xnor(Design*des, NetConst*obj,
NetLogic*log, unsigned pin)
void cprop_functor::lpm_ff(Design*des, NetFF*obj)
{
assert(pin > 0);
/* if this is the last input pin of the XNOR device, then
the device is simply buffering the constant value. */
if (log->pin_count() == 2) {
cerr << "cprop: delete gate " << log->name() <<
" and propogate " << obj->value() << "." << endl;
assert(pin == 1);
connect(log->pin(0), log->pin(1));
delete log;
return true;
}
/* If this is a constant 0, then replace the gate with one
1-pin smaller. Skip this pin. */
if (obj->value() == verinum::V0) {
cerr << "cprop: disconnect pin " << pin << " from gate "
<< log->name() << "." << endl;
NetLogic*tmp = new NetLogic(log->name(),
log->pin_count()-1,
NetLogic::XNOR);
connect(log->pin(0), tmp->pin(0));
unsigned idx, jdx;
for (idx = 1, jdx = 1 ; idx < log->pin_count() ; idx += 1) {
if (idx == pin) continue;
connect(log->pin(idx), tmp->pin(jdx));
jdx += 1;
// Look for and count unlinked FF outputs. Note that if the
// Data and Q pins are connected together, they can be removed
// from the circuit.
unsigned unlinked_count = 0;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
if (connected(obj->pin_Data(idx), obj->pin_Q(idx))) {
obj->pin_Data(idx).unlink();
obj->pin_Q(idx).unlink();
}
delete log;
des->add_node(tmp);
return true;
if (! obj->pin_Q(idx).is_linked())
unlinked_count += 1;
}
/* If this is a constant 1, then replace the gate with an XOR
that is 1-pin smaller. Removing the constant 1 causes the
sense of the output to change. */
if (obj->value() == verinum::V1) {
cerr << "cprop: disconnect pin " << pin << " from gate "
<< log->name() << "." << endl;
NetLogic*tmp = new NetLogic(log->name(),
log->pin_count()-1,
NetLogic::XOR);
connect(log->pin(0), tmp->pin(0));
unsigned idx, jdx;
for (idx = 1, jdx = 1 ; idx < log->pin_count() ; idx += 1) {
if (idx == pin) continue;
connect(log->pin(idx), tmp->pin(jdx));
jdx += 1;
}
delete log;
des->add_node(tmp);
return true;
// If the entire FF is unlinked, remove the whole thing.
if (unlinked_count == obj->width()) {
delete obj;
count += 1;
return;
}
/* If this is a constant X or Z, then the gate is certain to
generate an X. Replace the gate with a constant X. This may
cause other signals all over to become dangling. */
if ((obj->value() == verinum::Vx) || (obj->value() == verinum::Vz)) {
cerr << "cprop: replace gate " << log->name() << " with "
"a constant X." << endl;
// If some of the FFs are unconnected, make a new FF array
// that does not include the useless FF devices.
if (unlinked_count > 0) {
NetFF*tmp = new NetFF(obj->scope(), obj->name(),
obj->width()-unlinked_count);
connect(tmp->pin_Clock(), obj->pin_Clock());
connect(tmp->pin_Enable(), obj->pin_Enable());
connect(tmp->pin_Aload(), obj->pin_Aload());
connect(tmp->pin_Aset(), obj->pin_Aset());
connect(tmp->pin_Aclr(), obj->pin_Aclr());
connect(tmp->pin_Sload(), obj->pin_Sload());
connect(tmp->pin_Sset(), obj->pin_Sset());
connect(tmp->pin_Sclr(), obj->pin_Sclr());
NetConst*tmp = new NetConst(log->name(), verinum::Vx);
connect(log->pin(0), tmp->pin(0));
delete log;
unsigned tidx = 0;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1)
if (obj->pin_Q(idx).is_linked()) {
connect(tmp->pin_Data(tidx), obj->pin_Data(idx));
connect(tmp->pin_Q(tidx), obj->pin_Q(idx));
tidx += 1;
}
assert(tidx == obj->width() - unlinked_count);
delete obj;
des->add_node(tmp);
return true;
count += 1;
return;
}
return false;
}
static void look_for_core_logic(Design*des, NetConst*obj)
void cprop_functor::lpm_logic(Design*des, NetLogic*obj)
{
NetObj*cur = obj;
unsigned pin = 0;
for (obj->pin(0).next_link(cur, pin)
; cur != obj
; cur->pin(pin).next_link(cur, pin)) {
switch (obj->type()) {
NetLogic*log = dynamic_cast<NetLogic*>(cur);
if (log == 0)
continue;
case NetLogic::NAND:
case NetLogic::AND: {
unsigned top = obj->pin_count();
unsigned idx = 1;
unsigned xs = 0;
bool flag = false;
switch (log->type()) {
case NetLogic::XNOR:
flag = const_into_xnor(des, obj, log, pin);
break;
default:
break;
/* Eliminate all the 1 inputs. They have no effect
on the output of an AND gate. */
while (idx < top) {
if (! link_drivers_constant(obj->pin(idx))) {
idx += 1;
continue;
}
if (driven_value(obj->pin(idx)) == verinum::V1) {
obj->pin(idx).unlink();
top -= 1;
if (idx < top) {
connect(obj->pin(idx), obj->pin(top));
obj->pin(top).unlink();
}
continue;
}
if (driven_value(obj->pin(idx)) != verinum::V0) {
idx += 1;
xs += 1;
continue;
}
/* Oops! We just stumbled on a driven-0 input
to the AND gate. That means we can replace
the whole bloody thing with a constant
driver and exit now. */
NetConst*tmp;
switch (obj->type()) {
case NetLogic::AND:
tmp = new NetConst(obj->name(), verinum::V0);
break;
case NetLogic::NAND:
tmp = new NetConst(obj->name(), verinum::V1);
break;
default:
assert(0);
}
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
delete obj;
count += 1;
return;
}
/* If all the inputs were eliminated, then replace
the gate with a constant 1 and I am done. */
if (top == 1) {
NetConst*tmp;
switch (obj->type()) {
case NetLogic::AND:
tmp = new NetConst(obj->name(), verinum::V1);
break;
case NetLogic::NAND:
tmp = new NetConst(obj->name(), verinum::V0);
break;
default:
assert(0);
}
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
delete obj;
count += 1;
return;
}
/* If all the inputs are unknowns, then replace the
gate with a Vx. */
if (xs == (top-1)) {
NetConst*tmp;
tmp = new NetConst(obj->name(), verinum::Vx);
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
delete obj;
count += 1;
return;
}
/* If we are down to only one input, then replace
the AND with a BUF and exit now. */
if (top == 2) {
NetLogic*tmp;
switch (obj->type()) {
case NetLogic::AND:
tmp = new NetLogic(obj->scope(),
obj->name(), 2,
NetLogic::BUF);
break;
case NetLogic::NAND:
tmp = new NetLogic(obj->scope(),
obj->name(), 2,
NetLogic::NOT);
break;
default:
assert(0);
}
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
connect(obj->pin(1), tmp->pin(1));
delete obj;
count += 1;
return;
}
/* Finally, this cleans up the gate by creating a
new [N]OR gate that has the right number of
inputs, connected in the right place. */
if (top < obj->pin_count()) {
NetLogic*tmp = new NetLogic(obj->scope(),
obj->name(), top,
obj->type());
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
for (unsigned idx = 0 ; idx < top ; idx += 1)
connect(tmp->pin(idx), obj->pin(idx));
delete obj;
count += 1;
return;
}
break;
}
case NetLogic::NOR:
case NetLogic::OR: {
unsigned top = obj->pin_count();
unsigned idx = 1;
/* Eliminate all the 0 inputs. They have no effect
on the output of an OR gate. */
while (idx < top) {
if (! link_drivers_constant(obj->pin(idx))) {
idx += 1;
continue;
}
if (driven_value(obj->pin(idx)) == verinum::V0) {
obj->pin(idx).unlink();
top -= 1;
if (idx < top) {
connect(obj->pin(idx), obj->pin(top));
obj->pin(top).unlink();
}
continue;
}
if (driven_value(obj->pin(idx)) != verinum::V1) {
idx += 1;
continue;
}
/* Oops! We just stumbled on a driven-1 input
to the OR gate. That means we can replace
the whole bloody thing with a constant
driver and exit now. */
NetConst*tmp;
switch (obj->type()) {
case NetLogic::OR:
tmp = new NetConst(obj->name(), verinum::V1);
break;
case NetLogic::NOR:
tmp = new NetConst(obj->name(), verinum::V0);
break;
default:
assert(0);
}
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
delete obj;
count += 1;
return;
}
/* If all the inputs were eliminated, then replace
the gate with a constant 0 and I am done. */
if (top == 1) {
NetConst*tmp;
switch (obj->type()) {
case NetLogic::OR:
tmp = new NetConst(obj->name(), verinum::V0);
break;
case NetLogic::NOR:
tmp = new NetConst(obj->name(), verinum::V1);
break;
default:
assert(0);
}
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
delete obj;
count += 1;
return;
}
/* If we are down to only one input, then replace
the OR with a BUF and exit now. */
if (top == 2) {
NetLogic*tmp;
switch (obj->type()) {
case NetLogic::OR:
tmp = new NetLogic(obj->scope(),
obj->name(), 2,
NetLogic::BUF);
break;
case NetLogic::NOR:
tmp = new NetLogic(obj->scope(),
obj->name(), 2,
NetLogic::NOT);
break;
default:
assert(0);
}
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
connect(obj->pin(1), tmp->pin(1));
delete obj;
count += 1;
return;
}
/* Finally, this cleans up the gate by creating a
new [N]OR gate that has the right number of
inputs, connected in the right place. */
if (top < obj->pin_count()) {
NetLogic*tmp = new NetLogic(obj->scope(),
obj->name(), top,
obj->type());
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
for (unsigned idx = 0 ; idx < top ; idx += 1)
connect(tmp->pin(idx), obj->pin(idx));
delete obj;
count += 1;
return;
}
break;
}
case NetLogic::XNOR:
case NetLogic::XOR: {
unsigned top = obj->pin_count();
unsigned idx = 1;
/* Eliminate all the 0 inputs. They have no effect
on the output of an XOR gate. */
while (idx < top) {
if (! link_drivers_constant(obj->pin(idx))) {
idx += 1;
continue;
}
if (driven_value(obj->pin(idx)) == verinum::V0) {
obj->pin(idx).unlink();
top -= 1;
if (idx < top) {
connect(obj->pin(idx), obj->pin(top));
obj->pin(top).unlink();
}
} else {
idx += 1;
}
}
/* Look for pairs of constant 1 inputs. If I find a
pair, then eliminate both. Each iteration through
the loop, the `one' variable holds the index to
the previous V1, or 0 if there is none.
The `ones' variable counts the number of V1
inputs. After this loop completes, `ones' will be
0 or 1. */
unsigned one = 0, ones = 0;
idx = 1;
while (idx < top) {
if (! link_drivers_constant(obj->pin(idx))) {
idx += 1;
continue;
}
if (driven_value(obj->pin(idx)) == verinum::V1) {
if (one == 0) {
one = idx;
ones += 1;
idx += 1;
continue;
}
obj->pin(idx).unlink();
top -= 1;
if (idx < top) {
connect(obj->pin(idx), obj->pin(top));
obj->pin(top).unlink();
}
obj->pin(one).unlink();
top -= 1;
if (one < top) {
connect(obj->pin(one), obj->pin(top));
obj->pin(top).unlink();
}
assert(ones == 1);
ones = 0;
continue;
}
idx += 1;
}
/* If all the inputs were eliminated, then replace
the gate with a constant 0 and I am done. */
if (top == 1) {
verinum::V out = obj->type()==NetLogic::XNOR
? verinum::V1
: verinum::V0;
NetConst*tmp = new NetConst(obj->name(), out);
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
delete obj;
count += 1;
return;
}
/* If there is a stray V1 input and only one other
input, then replace the gate with an inverter and
we are done. */
if ((top == 3) && (ones == 1)) {
unsigned save;
if (! link_drivers_constant(obj->pin(1)))
save = 1;
else if (driven_value(obj->pin(1)) != verinum::V1)
save = 1;
else
save = 2;
NetLogic*tmp;
if (obj->type() == NetLogic::XOR)
tmp = new NetLogic(obj->scope(),
obj->name(), 2,
NetLogic::NOT);
else
tmp = new NetLogic(obj->scope(),
obj->name(), 2,
NetLogic::BUF);
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
connect(obj->pin(save), tmp->pin(1));
delete obj;
count += 1;
return;
}
/* If we are down to only one input, then replace
the XOR with a BUF and exit now. */
if (top == 2) {
NetLogic*tmp;
if (obj->type() == NetLogic::XOR)
tmp = new NetLogic(obj->scope(),
obj->name(), 2,
NetLogic::BUF);
else
tmp = new NetLogic(obj->scope(),
obj->name(), 2,
NetLogic::NOT);
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
connect(obj->pin(1), tmp->pin(1));
delete obj;
count += 1;
return;
}
/* Finally, this cleans up the gate by creating a
new XOR gate that has the right number of
inputs, connected in the right place. */
if (top < obj->pin_count()) {
NetLogic*tmp = new NetLogic(obj->scope(),
obj->name(), top,
obj->type());
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
for (unsigned idx = 0 ; idx < top ; idx += 1)
connect(tmp->pin(idx), obj->pin(idx));
delete obj;
count += 1;
return;
}
break;
}
/* If the optimization test tells me that a link was
deleted, restart the scan. */
if (flag) obj->pin(0).next_link(cur, pin);
default:
break;
}
}
/*
* This function looks to see if the constant is connected to nothing
* but signals. If that is the case, delete the dangling constant and
* the now useless signals.
* This detects the case where the mux selects between a value an
* Vz. In this case, replace the device with a bufif with the sel
* input used to enable the output.
*/
static void dangling_const(Design*des, NetConst*obj)
void cprop_functor::lpm_mux(Design*des, NetMux*obj)
{
// If there are any links that take input, abort this
// operation.
if (count_inputs(obj->pin(0)) > 0)
if (obj->size() != 2)
return;
if (obj->sel_width() != 1)
return;
// If there are no other drivers, delete all the signals that
// are also dangling.
if (count_outputs(obj->pin(0)) == 1) {
/* If the first input is all constant Vz, then replace the
NetMux with an array of BUFIF1 devices, with the enable
connected to the select input. */
bool flag = true;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
if (! link_drivers_constant(obj->pin_Data(idx, 0))) {
flag = false;
break;
}
NetObj*cur;
unsigned pin;
obj->pin(0).next_link(cur, pin);
while (cur != obj) {
cerr << "cprop: delete dangling signal " << cur->name() <<
"." << endl;
delete cur;
obj->pin(0).next_link(cur, pin);
if (driven_value(obj->pin_Data(idx, 0)) != verinum::Vz) {
flag = false;
break;
}
}
if (flag) {
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
NetLogic*tmp = new NetLogic(obj->scope(),
des->local_symbol(obj->name()),
3, NetLogic::BUFIF1);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
}
count += 1;
delete obj;
return;
}
/* If instead the second input is all constant Vz, replace the
NetMux with an array of BUFIF0 devices. */
flag = true;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
if (! link_drivers_constant(obj->pin_Data(idx, 1))) {
flag = false;
break;
}
if (driven_value(obj->pin_Data(idx, 1)) != verinum::Vz) {
flag = false;
break;
}
}
if (flag) {
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
NetLogic*tmp = new NetLogic(obj->scope(),
des->local_symbol(obj->name()),
3, NetLogic::BUFIF0);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,0), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
}
count += 1;
delete obj;
return;
}
}
/*
* This functor looks to see if the constant is connected to nothing
* but signals. If that is the case, delete the dangling constant and
* the now useless signals. This functor is applied after the regular
* functor to clean up dangling constants that might be left behind.
*/
struct cprop_dc_functor : public functor_t {
virtual void lpm_const(Design*des, NetConst*obj);
};
void cprop_dc_functor::lpm_const(Design*des, NetConst*obj)
{
// 'bz constant values drive high impedance to whatever is
// connected to it. In otherwords, it is a noop.
{ unsigned tmp = 0;
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
if (obj->value(idx) == verinum::Vz) {
obj->pin(idx).unlink();
tmp += 1;
}
if (tmp == obj->pin_count()) {
delete obj;
return;
}
}
// For each bit, if this is the only driver, then set the
// initial value of all the signals to this value.
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
if (count_outputs(obj->pin(idx)) > 1)
continue;
Nexus*nex = obj->pin(idx).nexus();
for (Link*clnk = nex->first_nlink()
; clnk ; clnk = clnk->next_nlink()) {
NetObj*cur;
unsigned pin;
clnk->cur_link(cur, pin);
NetNet*tmp = dynamic_cast<NetNet*>(cur);
if (tmp == 0)
continue;
tmp->pin(pin).set_init(obj->value(idx));
}
}
// If there are any links that take input, the constant is
// used structurally somewhere.
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
if (count_inputs(obj->pin(idx)) > 0)
return;
// Look for signals that have NetESignal nodes attached to
// them. If I find any, this this constant is used by a
// behavioral expression somewhere.
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
Nexus*nex = obj->pin(idx).nexus();
for (Link*clnk = nex->first_nlink()
; clnk ; clnk = clnk->next_nlink()) {
NetObj*cur;
unsigned pin;
clnk->cur_link(cur, pin);
NetNet*tmp = dynamic_cast<NetNet*>(cur);
if (tmp && tmp->get_eref() > 0)
return;
}
}
// Done. Delete me.
delete obj;
}
void cprop(Design*des)
{
des->clear_node_marks();
while (NetNode*obj = des->find_node(&is_a_const_node)) {
NetConst*cur = dynamic_cast<NetConst*>(obj);
look_for_core_logic(des, cur);
cur->set_mark();
dangling_const(des, cur);
}
// Continually propogate constants until a scan finds nothing
// to do.
cprop_functor prop;
do {
prop.count = 0;
des->functor(&prop);
} while (prop.count > 0);
cprop_dc_functor dc;
des->functor(&dc);
}
/*
* $Log: cprop.cc,v $
* Revision 1.23 2000/12/30 03:11:15 steve
* Propagate initial value of constants into wires.
*
* Revision 1.22 2000/11/23 01:55:52 steve
* Propagate constants through xnor gates. (PR#51)
*
* Revision 1.21 2000/11/19 05:26:58 steve
* Replace AND constand propagation.
*
* Revision 1.20 2000/11/18 05:13:27 steve
* Thorough constant propagation for or and nor gates.
*
* Revision 1.19 2000/11/18 04:10:37 steve
* Handle constant propagation through XOR gates,
* including reducing the gate to a constant,
* a buffer or an inverter if possible.
*
* Revision 1.18 2000/11/11 00:03:36 steve
* Add support for the t-dll backend grabing flip-flops.
*
* Revision 1.17 2000/10/07 19:45:42 steve
* Put logic devices into scopes.
*
* Revision 1.16 2000/10/06 21:26:34 steve
* Eliminate zero inputs to xor.
*
* Revision 1.15 2000/08/02 14:48:01 steve
* use bufif0 if z is in true case of mux.
*
* Revision 1.14 2000/07/25 02:55:13 steve
* Unlink z constants from nets.
*
* Revision 1.13 2000/07/15 05:13:43 steve
* Detect muxing Vz as a bufufN.
*
* Revision 1.12 2000/06/25 19:59:41 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
* Revision 1.11 2000/06/24 22:55:19 steve
* Get rid of useless next_link method.
*
* Revision 1.10 2000/05/14 17:55:04 steve
* Support initialization of FF Q value.
*
* Revision 1.9 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.8 2000/04/28 21:00:28 steve
* Over agressive signal elimination in constant probadation.
*
* Revision 1.7 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.6 2000/01/02 17:56:42 steve
* Do not delete constants that input to exressions.
*
* Revision 1.5 1999/12/30 04:19:12 steve
* Propogate constant 0 in low bits of adders.
*
* Revision 1.4 1999/12/17 06:18:15 steve
* Rewrite the cprop functor to use the functor_t interface.
*
* Revision 1.3 1999/12/17 03:38:46 steve
* NetConst can now hold wide constants.
*
* Revision 1.2 1998/12/02 04:37:13 steve
* Add the nobufz function to eliminate bufz objects,
* Object links are marked with direction,
+53
View File
@@ -0,0 +1,53 @@
This file describes the build procedure under cygwin32 (Windows 95/98/NT/2K)
----------------------------------------------------------------------------
To build using cygwin:
Prerequisites:
o Latest net release (1.1.4) of cygwin (sources.redhat.com/cygwin)
o autoconf version 2.13 (or later) from cygutils (cygutils.netpedia.net)
o cvs (1.10.8 or later) also from cygutils
Procedure:
o Get the source code - see the main icarus verilog page for how to
do this
o cd to the verilog directory
o autoconf
o ./configure
o make
o make install
That's all that's needed. But there're two common problems during
the make phase. All steps are in the verilog directory.
1.
If gcc dies saying virtual memory exhausted while compiling parse.c
then recompile with -O1 or without -O flag and do these steps to
continue
o make CXXFLAGS='' parse.o
o make
2.
If gcc dies in the vpi directory while compiling vpi_systask.c with the
error, conflicting types for `_cygwin_dll_entry', then fix the line in
/usr/include/cygwin/cygwin_dll.h. Change the line:
int WINAPI _cygwin_dll_entry (HANDLE h, DWORD reason, void *ptr); \
to
int WINAPI _cygwin_dll_entry (HINSTANCE h, DWORD reason, void *ptr); \
Note the change from HANDLE to HINSTANCE. Then do
o make
To build your own extensions - just include vpi_user.h and link with
a command like this:
$(CC) -shared -o <dllname> <objects> -Wl,--enable-auto-image-base -L../vvm -lvvm -lvpip
- Venkat Iyer <[email protected]>
+445 -429
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
Makefile
parse.c
parse.h
parse.output
lexor.c
iverilog
+90
View File
@@ -0,0 +1,90 @@
#
# 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.3 2001/01/09 03:11:27 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
mandir = @mandir@
dllib=@DLLIB@
rdynamic=@rdynamic@
CC = @CC@
CXX = @CXX@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CPPFLAGS = @CPPFLAGS@ @DEFS@
CFLAGS = @CFLAGS@ -I.
LDFLAGS = @LDFLAGS@
all: iverilog@EXEEXT@
clean:
rm -f *.o lexor.c parse.c parse.h parse.output
O = main.o build_string.o lexor.o parse.o
iverilog@EXEEXT@: $O
$(CC) $(LDFLAGS) $O -o iverilog@EXEEXT@
lexor.c: lexor.lex
flex -s -olexor.c $(srcdir)/lexor.lex
parse.h parse.c: parse.y
bison --verbose -t -d $(srcdir)/parse.y -o parse.c
main.o: main.c globals.h
$(CC) $(CPPFLAGS) -c -DCXX='"@CXX@"' -DIVL_ROOT='"@libdir@/ivl"' -DIVL_INC='"@includedir@"' -DIVL_LIB='"@libdir@"' -DRDYNAMIC=\"$(rdynamic)\" -DDLLIB='"@DLLIB@"' $(srcdir)/main.c
build_string.o: build_string.c globals.h
lexor.o: lexor.c parse.h globals.h
parse.o: parse.c globals.h
install: all installdirs $(bindir)/iverilog@EXEEXT@ $(mandir)/man1/iverilog.1
$(bindir)/iverilog@EXEEXT@: ./iverilog@EXEEXT@
$(INSTALL_PROGRAM) ./iverilog@EXEEXT@ $(bindir)/iverilog@EXEEXT@
$(mandir)/man1/iverilog.1: $(srcdir)/iverilog.man
$(INSTALL_DATA) $(srcdir)/iverilog.man $(mandir)/man1/iverilog.1
installdirs: ../mkinstalldirs
$(srcdir)/../mkinstalldirs $(bindir) $(mandir)/man1
uninstall:
rm -f $(bindir)/iverilog@EXEEXT@
rm -f $(mandir)/man1/iverilog.1
+151
View File
@@ -0,0 +1,151 @@
/*
* Copyright (c) 2000 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.
*
* 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) && !defined(macintosh)
#ident "$Id: build_string.c,v 1.2 2000/10/28 03:45:47 steve Exp $"
#endif
# include "globals.h"
# include <string.h>
# include <assert.h>
int build_string(char*output, size_t olen, const char*pattern)
{
char tmp_buf[1024];
char*output_save = output;
while (*pattern) {
if (*pattern == '%') {
pattern += 1;
switch (*pattern) {
case 0:
break;
case '%':
*output++ = '%';
break;
case '[': {
const char*tail;
pattern += 1;
assert(*pattern);
tail = strchr(pattern+1, ']');
assert(tail);
strncpy(tmp_buf, pattern+1, tail-pattern-1);
tmp_buf[tail-pattern-1] = 0;
if (((*pattern == 's') && start)
|| ((*pattern == 'N') && npath)
|| ((*pattern == 'T') && mtm)) {
int rc = build_string(output, olen,
tmp_buf);
output += rc;
olen -= rc;
}
pattern = tail;
break;
}
case 'B':
strcpy(output, base);
output += strlen(base);
olen -= strlen(base);
break;
case 'f':
if (f_list) {
strcpy(output, f_list);
output += strlen(f_list);
olen -= strlen(f_list);
}
break;
case 'm':
if (mod_list) {
strcpy(output, mod_list);
output += strlen(mod_list);
olen -= strlen(mod_list);
}
break;
case 'N':
if (npath) {
strcpy(output, npath);
output += strlen(npath);
olen -= strlen(npath);
}
break;
case 'o':
strcpy(output, opath);
output += strlen(opath);
olen -= strlen(opath);
break;
case 's':
if (start) {
strcpy(output, start);
output += strlen(start);
olen -= strlen(start);
}
break;
case 'T':
if (mtm) {
strcpy(output, mtm);
output += strlen(mtm);
olen -= strlen(mtm);
}
break;
case 't':
strcpy(output, targ);
output += strlen(targ);
olen -= strlen(targ);
break;
case 'W':
strcpy(output, warning_flags);
output += strlen(warning_flags);
olen -= strlen(warning_flags);
break;
}
pattern += 1;
} else {
*output++ = *pattern++;
olen -= 1;
}
}
*output = 0;
return output-output_save;
}
/*
* $Log: build_string.c,v $
* Revision 1.2 2000/10/28 03:45:47 steve
* Use the conf file to generate the vvm ivl string.
*
* Revision 1.1 2000/10/08 22:36:56 steve
* iverilog with an iverilog.conf configuration file.
*
*/
+72
View File
@@ -0,0 +1,72 @@
#ifndef __globals_H
#define __globals_H
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: globals.h,v 1.3 2000/11/09 21:58:00 steve Exp $"
#endif
# include <stddef.h>
/* This is the base (i.e. -B<value>) of the Icarus Verilog files. */
extern const char*base;
/* This is a list of all the -f<key>=<value> options from the
command line, concatenated together. */
extern char*f_list;
extern char*mod_list;
/* This is the optional -Tmin|typ|max setting. */
extern const char*mtm;
/* Ths is the optional -N<path> value, if one was supplied. */
extern const char*npath;
/* This is the name of the output file that the user selected. */
extern const char*opath;
/* This pointer is set if there was a -s<value> parameter. */
extern const char*start;
/* This flag is true if the -S flag was used on the command line. */
extern int synth_flag;
/* This is the name of the selected target. */
extern const char*targ;
extern char warning_flags[];
extern const char*lookup_pattern(const char*key);
extern int build_string(char*out, size_t olen, const char*pattern);
/*
* $Log: globals.h,v $
* Revision 1.3 2000/11/09 21:58:00 steve
* Remember to include the -S condition.
*
* Revision 1.2 2000/10/28 03:45:47 steve
* Use the conf file to generate the vvm ivl string.
*
* Revision 1.1 2000/10/08 22:36:56 steve
* iverilog with an iverilog.conf configuration file.
*
*/
#endif
+185
View File
@@ -0,0 +1,185 @@
.TH iverilog 1 "$Date: 2001/01/05 05:16:03 $" Version "$Date: 2001/01/05 05:16:03 $"
.SH NAME
iverilog - Icarus Verilog compiler
.SH SYNOPSIS
.B iverilog
[-ESv] [-Cpath] [-ccmdfile] [-Dmacro[=defn]] [-fflag=value] [-Iincludepath] [-mmodule] [-Nfile] [-ooutputfilename] [-stopmodule] [-ttype] [-Tmin/typ/max] [-Wclass] sourcefile
.SH DESCRIPTION
.PP
\fIiverilog\fP is a compiler that translates Verilog source code into
executable programs for simulation, or other netlist formats for
further processing. The currenty supported targets are \fIvvm\fP (for
executable simulation) and \fIxnf\fP for synthesis. Other target
types are added as code generators are implemented.
.SH OPTIONS
.l
\fIiverilog\fP accepts the following options:
.TP 8
.B -B\fIbase\fP
The \fIiverilog\fP program uses external programs to preprocess and
compile the verilog source. Normally, the path used to locate these
tools is built into the \fIiverilog\fP program. However, the \fB-B\fP
switch allows the user to select a different set of programs. The path
given is used to locate \fIivlpp\fP, \fIivl\fP and the VPI modules.
.TP 8
.B -c\fIfile\fP
This flag specifies an input file that contains a list of Verilog
source files. This is similar to the \fIcommand file\fP of other
Verilog simulators, in that it is a file that contains the file names
instead of taking them on the command line. The command file may
contain C-style comments (/*-*/) or shell-style comments (# to the end
of the line.)
.TP 8
.B -C\fIpath\fP
This flag selects the driver configuration file to use. Normally, the
iverilog program will read its configuration file from
/usr/lib/ivl/iverilog.conf (or the install path configured at compile
time) but the user can specify the path to a different configuration
file. This is useful when testing new configuration files. See the
installed configuration file for a summary of the file format.
.TP 8
.B -D\fImacro\fP
Defines macro \fImacro\fP with the string `1' as its definition. This
form is normally only used to trigger ifdef conditionals in the
Verilog source.
.TP 8
.B -D\fImacro=defn\fP
Defines macro \fImacro\fP as \fIdefn\fP.
.TP 8
.B -E
Preprocess the Verilog source, but do not compile it. The output file
is the Verilog input, but with file inclusions and macro references
expanded and removed. This is useful, for example, to preprocess
verilog source for use by other compilers.
.TP 8
.B -f\fIflag=value\fP
Assign a value to a target specific flag. The \fB-f\fP switch may be
used as often as necessary to specify all the desired flags. The flags
that are used depend on the target that is selected, and are described
in target specific documentation. Flags that are not used are ignored.
.TP 8
.B -I\fIincludedir\fP
Append directory \fIincludepdir\fP to list of directoriess searched
for Verilog include files. The \fB-I\fP switch may be used many times
to specify several directories to search, the directories are searched
in the order they appear on the command line.
.TP 8
.B -m\fImodule\fP
Add this module to the list of VPI modules to be loaded by the
simulation. Many modules can be specified, and all will be loaded, in
the order specified.
.TP 8
.B -N\fIpath\fP
This is used for debugging the compiler proper. Dump the final netlist
form of the design to the specified file. It otherwise does not affect
operation of the compiler. The dump happens after the design is
elaborated and optimized.
.TP 8
.B -o \fIfilename\fP
Place output in the file \fIfilename\fP. If no output file name is
specified, \fIiverilog\fP uses the default name \fBa.out\fP.
.TP 8
.B -S
Synthesize. Normally, if the target can accept behavioral
descriptions the compiler will leave processes in behavioral
form. The \fB-S\fP switch causes the compiler to perform synthesis
even if it is not necessary for the target. If the target type is a
netlist format, the \fB-S\fP switch is unnecessary and has no effect.
.TP 8
.B -s \fItopmodule\fP
Specify the top level module to elaborate. Icarus Verilog will by default
choose the only module that has no ports. However, this simplistic
heuristic is often not sufficient, and sometimes not what is wanted
anyhow.
.TP 8
.B -T\fImin|typ|max\fP
Use this switch to select min, typ or max times from min:typ:max
expressions. Normally, the compiler will simply use the typ value from
these expressions (with a warning) but this switch will tell the
compiler explicitly which value to use. This will suppress the
warning that the compiler is making a choice.
.TP 8
.B -t\fItarget\fP
Use this switch to specify the target output format. See the
\fBTARGETS\fP section below for a list of valid output formats.
.TP 8
.B -v
Turn on verbose messages. This will print the command lines that are
executed to perform the actual compilation, along with version
information from the various components.
.TP 8
.B -W\fIclass\fP
Turn on different classes of warnings. See the \fBWARNING TYPES\fP
section below for desctriptions of the different warning groups. If
multiple \fB-W\fP switches are used, the warning set is the union of
all the requested classes.
.SH TARGETS
The Icarus Verilog compiler supports a variety of targets, for
different purposes, and the \fB-t\fP switch is used to select the
desired target.
.TP 8
.B null
The null target causes no code to be generated. It is useful for
checking the syntax of the Verilog source.
.TP 8
.B vvm
This is the default. The target is an executable program that uses the
vvm simulation runtime. The compiler actually generates C++ code, then
compiles and links that code to make the output executable.
.TP 8
.B xnf
This is the Xilinx Netlist Format used by many tools for placing
devices in FPGAs or other programmable devices. The Icarus Verilog XNF
code generator can generate complete designs or XNF macros that can be
imported into larger designs by other tools.
.SH "WARNING TYPES"
These are the types of warnings that can be selected by the \fB-W\fP
switch.
.TP 8
.B all
This enables all supported warning categories.
.TP 8
.B implicit
This enables warnings for creation of implicit declarations. For
example, if a scaler wire X is used but not declared in the Verilog
source, this will print a warning at its first use.
.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 a.out:
verilog hello.v
To compile hello.v to an executable file called hello:
verilog -o hello hello.v
To compile hello.v to a file in XNF-format called hello.xnf
verilog -txnf -ohello.xnf hello.v
.SH "AUTHOR"
.nf
Steve Williams ([email protected])
.SH SEE ALSO
.BR "<http://www.icarus.com/eda/verilog/>"
.SH COPYRIGHT
.nf
Copyright \(co 2000 Stephen Williams
This document can be freely redistributed according to the terms of the
GNU General Public License version 2.0
+78
View File
@@ -0,0 +1,78 @@
%{
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: lexor.lex,v 1.4 2000/12/15 02:00:11 steve Exp $"
#endif
# include <string.h>
# include "parse.h"
%}
%x CTOKENS
%x PATTERN
%%
"#".* { /* eat comments */; }
"\n" { /* eat line-ends */; }
"\r" { /* eat line-ends */; }
"[" { BEGIN(CTOKENS); return '['; }
<CTOKENS>"]" { BEGIN(0); return ']'; }
<CTOKENS>[ \t\b]+ { /* skip white space */; }
<CTOKENS>"-S" { return CT_S; }
<CTOKENS>"-t"[a-zA-Z0-9\-_]+ {
yylval.text = strdup(yytext+2);
return CT_t; }
"<"[^>]*">" {
BEGIN(PATTERN);
yylval.text = strdup(yytext);
return PATTERN_NAME; }
<PATTERN>.* {
BEGIN(0);
/* Trim off a trailing \r. This is an issue in the DOS world. */
if (yytext[strlen(yytext)-1] == '\r')
yytext[strlen(yytext)-1] = 0;
yylval.text = strdup(yytext);
return PATTERN_TEXT; }
. { fprintf(stderr, "driver lexor: Unmatched character: %c\n", yytext[0]); }
%%
void reset_lexor(FILE*fd)
{
yyrestart(fd);
}
int yywrap()
{
return 1;
}
+537
View File
@@ -0,0 +1,537 @@
/*
* Copyright (c) 2000 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: main.c,v 1.5 2000/11/30 02:50:54 steve Exp $"
#endif
const char HELP[] =
"Usage: iverilog [-ESv] [-c <path>] [-Dmacro[=defn]]
[-f flag=value] [-I<dir>] [-m module]
[-o <output>] [-s top_module] [-t<type>]
[-W class] source_file(s)
See man page for details.";
#define MAXSIZE 4096
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
#if HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifndef IVL_ROOT
# define IVL_ROOT "."
#endif
#ifndef RDYNAMIC
# define RDYNAMIC "-rdynamic"
#endif
# include "globals.h"
const char*base = IVL_ROOT;
const char*mtm = 0;
const char*opath = "a.out";
const char*npath = 0;
const char*targ = "vvm";
const char*start = 0;
char warning_flags[16] = "";
char*inc_list = 0;
char*def_list = 0;
char*mod_list = 0;
char*command_filename = 0;
char*f_list = 0;
int synth_flag = 0;
int verbose_flag = 0;
int command_file = 0;
int inside_c_comment = 0;
FILE *fp;
char line[MAXSIZE];
char tmp[MAXSIZE];
/*
* This is the default target type. It looks up the bits that are
* needed to run the command from the configuration file (which is
* already parsed for us) so we can handle must of the generic cases.
*/
static int t_default(char*cmd, unsigned ncmd)
{
int rc;
const char*pattern;
pattern = lookup_pattern("<ivl>");
if (pattern == 0) {
fprintf(stderr, "No such target: %s\n", targ);
return -1;
}
tmp[0] = ' ';
tmp[1] = '|';
tmp[2] = ' ';
rc = build_string(tmp+3, sizeof tmp - 3, pattern);
cmd = realloc(cmd, ncmd+3+rc+1);
strcpy(cmd+ncmd, tmp);
if (verbose_flag)
printf("translate: %s\n", cmd);
rc = system(cmd);
if (rc != 0) {
if (WIFEXITED(rc))
return WEXITSTATUS(rc);
fprintf(stderr, "Command signaled: %s\n", cmd);
return -1;
}
return 0;
}
/*
* This function handles the vvm target. After preprocessing, run the
* ivl translator to get C++, then run g++ to make an executable
* program out of that.
*/
static int t_vvm(char*cmd, unsigned ncmd)
{
int rc;
const char*pattern = lookup_pattern("<ivl>");
if (pattern == 0) {
fprintf(stderr, "No such target: %s\n", targ);
return -1;
}
tmp[0] = ' ';
tmp[1] = '|';
tmp[2] = ' ';
rc = build_string(tmp+3, sizeof tmp - 3, pattern);
cmd = realloc(cmd, ncmd+3+rc+1);
strcpy(cmd+ncmd, tmp);
if (verbose_flag)
printf("translate: %s\n", cmd);
rc = system(cmd);
if (rc != 0) {
if (WIFEXITED(rc)) {
fprintf(stderr, "errors translating Verilog program.\n");
return WEXITSTATUS(rc);
} else {
fprintf(stderr, "Command signaled: %s\n", cmd);
return -1;
}
}
sprintf(tmp, "%s -O " RDYNAMIC " -fno-exceptions -o %s -I%s "
"-L%s %s.cc -lvvm -lvpip %s", CXX, opath, IVL_INC, IVL_LIB,
opath, DLLIB);
if (verbose_flag)
printf("compile: %s\n", tmp);
rc = system(tmp);
if (rc != 0) {
if (WIFEXITED(rc)) {
fprintf(stderr, "errors compiling translated program.\n");
return WEXITSTATUS(rc);
} else {
fprintf(stderr, "Command signaled: %s\n", tmp);
return -1;
}
}
sprintf(tmp, "%s.cc", opath);
unlink(tmp);
return 0;
}
static int t_xnf(char*cmd, unsigned ncmd)
{
int rc;
sprintf(tmp, " | %s/ivl %s -o %s -txnf -Fcprop -Fsynth -Fsyn-rules "
"-Fnodangle -Fxnfio", base, warning_flags, opath);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
if (f_list) {
rc = strlen(f_list);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, f_list);
ncmd += rc;
}
if (mtm) {
sprintf(tmp, " -T%s", mtm);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
}
if (npath) {
sprintf(tmp, " -N%s", npath);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
}
if (start) {
sprintf(tmp, " -s%s", start);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
}
sprintf(tmp, " -- -");
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
if (verbose_flag)
printf("translate: %s\n", cmd);
rc = system(cmd);
if (rc != 0) {
if (WIFEXITED(rc)) {
fprintf(stderr, "errors translating Verilog program.\n");
return WEXITSTATUS(rc);
}
fprintf(stderr, "Command signaled: %s\n", cmd);
return -1;
}
return 0;
}
static void process_warning_switch(const char*name)
{
if (warning_flags[0] == 0)
strcpy(warning_flags, "-W");
if (strcmp(name,"all") == 0) {
strcat(warning_flags, "i");
} else if (strcmp(name,"implicit") == 0) {
if (! strchr(warning_flags+2, 'i'))
strcat(warning_flags, "i");
}
}
int main(int argc, char **argv)
{
const char*config_path = 0;
char*cmd;
unsigned ncmd;
int e_flag = 0;
int opt, idx;
char*cp;
while ((opt = getopt(argc, argv, "B:C:c:D:Ef:hI:m:N::o:Ss:T:t:vW:")) != EOF) {
switch (opt) {
case 'B':
base = optarg;
break;
case 'C':
config_path = optarg;
break;
case 'c':
command_filename = malloc(strlen(optarg)+1);
strcat(command_filename, optarg);
break;
case 'D':
if (def_list == 0) {
def_list = malloc(strlen(" -D")+strlen(optarg)+1);
strcpy(def_list, " -D");
strcat(def_list, optarg);
} else {
def_list = realloc(def_list, strlen(def_list)
+ strlen(" -D")
+ strlen(optarg) + 1);
strcat(def_list, " -D");
strcat(def_list, optarg);
}
break;
case 'E':
e_flag = 1;
break;
case 'f':
if (f_list == 0) {
f_list = malloc(strlen(" -f")+strlen(optarg)+1);
strcpy(f_list, " -f");
strcat(f_list, optarg);
} else {
f_list = realloc(f_list, strlen(f_list) +
strlen(" -f") +
strlen(optarg) + 1);
strcat(f_list, " -f");
strcat(f_list, optarg);
}
break;
case 'h':
fprintf(stderr, "%s\n", HELP);
return 1;
case 'I':
if (inc_list == 0) {
inc_list = malloc(strlen(" -I")+strlen(optarg)+1);
strcpy(inc_list, " -I");
strcat(inc_list, optarg);
} else {
inc_list = realloc(inc_list, strlen(inc_list)
+ strlen(" -I")
+ strlen(optarg) + 1);
strcat(inc_list, " -I");
strcat(inc_list, optarg);
}
break;
case 'm':
if (mod_list == 0) {
mod_list = malloc(strlen(" -m")+strlen(optarg)+1);
strcpy(mod_list, " -m");
strcat(mod_list, optarg);
} else {
mod_list = realloc(mod_list, strlen(mod_list)
+ strlen(" -m")
+ strlen(optarg) + 1);
strcat(mod_list, " -m");
strcat(mod_list, optarg);
}
break;
case 'N':
npath = optarg;
break;
case 'o':
opath = optarg;
break;
case 'S':
synth_flag = 1;
break;
case 's':
start = optarg;
break;
case 'T':
if (strcmp(optarg,"min") == 0) {
mtm = "min";
} else if (strcmp(optarg,"typ") == 0) {
mtm = "typ";
} else if (strcmp(optarg,"max") == 0) {
mtm = "max";
} else {
fprintf(stderr, "%s: invalid -T%s argument\n",
argv[0], optarg);
return 1;
}
break;
case 't':
targ = optarg;
break;
case 'v':
verbose_flag = 1;
break;
case 'W':
process_warning_switch(optarg);
break;
case '?':
default:
return 1;
}
}
if ((optind == argc) && !command_filename) {
fprintf(stderr, "%s: No input files.\n", argv[0]);
fprintf(stderr, "%s\n", HELP);
return 1;
}
/* Load the iverilog.conf file to get our substitution
strings. */
{ char path[1024];
FILE*fd;
if (config_path) {
strcpy(path, config_path);
} else {
sprintf(path, "%s/iverilog.conf", base);
}
fd = fopen(path, "r");
reset_lexor(fd);
yyparse();
}
/* Start building the preprocess command line. */
sprintf(tmp, "%s/ivlpp %s%s", base,
verbose_flag?" -v":"",
e_flag?"":" -L");
ncmd = strlen(tmp);
cmd = malloc(ncmd + 1);
strcpy(cmd, tmp);
if (inc_list) {
cmd = realloc(cmd, ncmd + strlen(inc_list) + 1);
strcat(cmd, inc_list);
ncmd += strlen(inc_list);
}
if (def_list) {
cmd = realloc(cmd, ncmd + strlen(def_list) + 1);
strcat(cmd, def_list);
ncmd += strlen(def_list);
}
/* If user supplied a command file, retain its contents -- this
process supersedes command line source files. */
if (command_filename != 0) {
if (( fp = fopen(command_filename, "r")) == NULL ) {
fprintf(stderr, "%s: Can't open %s\n",
argv[0], command_filename);
return 1;
} else {
/* Process file and skip over commented-out lines.
Skips over c-like comment as well as '//' or
'#' lines. */
sprintf(tmp, "");
while (fgets(line, MAXSIZE, fp) != NULL) {
if ( strstr(line, "*/") != NULL ) {
inside_c_comment = 0;
continue;
}
if (inside_c_comment || (strstr(line, "/*") != NULL)) {
inside_c_comment = 1;
continue;
}
if ( (line[0] != '/' || line[1] != '/')
&& line[0] != '#' ) {
strcat (tmp, " ");
strncat (tmp, line, (strlen(line)-1));
}
}
fclose(fp);
}
cmd = realloc(cmd, ncmd+strlen(tmp)+1);
strcpy(cmd+ncmd, tmp);
ncmd += strlen(tmp);
} else {
/* Add all verilog source files to the preprocess
command line. */
for (idx = optind ; idx < argc ; idx += 1) {
sprintf(tmp, " %s", argv[idx]);
cmd = realloc(cmd, ncmd+strlen(tmp)+1);
strcpy(cmd+ncmd, tmp);
ncmd += strlen(tmp);
}
}
/* If the -E flag was given on the command line, then all we
do is run the preprocessor and put the output where the
user wants it. */
if (e_flag) {
int rc;
if (strcmp(opath,"-") != 0) {
sprintf(tmp, " > %s", opath);
cmd = realloc(cmd, ncmd+strlen(tmp)+1);
strcpy(cmd+ncmd, tmp);
ncmd += strlen(tmp);
}
if (verbose_flag)
printf("preprocess: %s\n", cmd);
rc = system(cmd);
if (rc != 0) {
if (WIFEXITED(rc)) {
fprintf(stderr, "errors preprocessing Verilog program.\n");
return WEXITSTATUS(rc);
}
fprintf(stderr, "Command signaled: %s\n", cmd);
return -1;
}
return 0;
}
if (strcmp(targ,"vvm") == 0)
return t_vvm(cmd, ncmd);
else if (strcmp(targ,"xnf") == 0)
return t_xnf(cmd, ncmd);
else {
return t_default(cmd, ncmd);
}
return 0;
}
/*
* $Log: main.c,v $
* Revision 1.5 2000/11/30 02:50:54 steve
* Add command file (-c) support from Nadim Shaikli.
*
* Revision 1.4 2000/10/28 17:28:16 steve
* Split vpip for everybody.
*
* Revision 1.3 2000/10/28 03:47:25 steve
* Use the conf file to generate the vvm ivl string.
*
* Revision 1.2 2000/10/28 03:45:47 steve
* Use the conf file to generate the vvm ivl string.
*
* Revision 1.1 2000/10/08 22:36:56 steve
* iverilog with an iverilog.conf configuration file.
*
*/
+162
View File
@@ -0,0 +1,162 @@
%{
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: parse.y,v 1.2 2000/11/09 21:58:00 steve Exp $"
#endif
# include <stdio.h>
# include <malloc.h>
# include "globals.h"
void yyerror(const char*);
enum drive_code_t {
CODE_S,
CODE_t,
};
struct drive_cond {
struct drive_cond*next;
enum drive_code_t code;
char* text;
};
static struct drive_cond *cur_cond = 0;
static void add_cond(enum drive_code_t code, char*text)
{
struct drive_cond*tmp;
tmp = calloc(1, sizeof(struct drive_cond));
tmp->code = code;
tmp->text = text;
tmp->next = cur_cond;
cur_cond = tmp;
}
struct drive_pattern {
struct drive_pattern*next;
char*name;
char*text;
struct drive_cond*cond;
};
static struct drive_pattern *patterns = 0;
static struct drive_pattern *plast = 0;
static void add_pattern(char*name, char*text)
{
struct drive_pattern*tmp;
tmp = calloc(1, sizeof(struct drive_pattern));
tmp->name = name;
tmp->text = text;
tmp->cond = cur_cond;
tmp->next = 0;
if (plast) {
plast->next = tmp;
plast = tmp;
} else {
patterns = tmp;
plast = tmp;
}
}
const char*lookup_pattern(const char*key)
{
struct drive_pattern*cur;
struct drive_cond*cc;
for (cur = patterns ; cur ; cur = cur->next) {
if (strcmp(key, cur->name) != 0)
continue;
for (cc = cur->cond ; cc ; cc = cc->next) {
switch (cc->code) {
case CODE_S:
if (synth_flag)
continue;
break;
case CODE_t:
if (strcmp(targ, cc->text) == 0)
continue;
break;
}
break;
}
if (cc) continue;
return cur->text;
}
return 0;
}
%}
%union {
char*text;
};
%token <text> PATTERN_NAME PATTERN_TEXT
%token <text> CT_t
%token CT_S
%%
start: section_list
section_list
: section
| section_list section
;
section : '[' ctoken_list ']' pattern_list { cur_cond = 0; } ;
ctoken_list
: ctoken
| ctoken_list ctoken
;
ctoken : CT_S { add_cond(CODE_S, 0); }
| CT_t { add_cond(CODE_t, $1); }
;
pattern_list
: pattern
| pattern_list pattern
;
pattern : PATTERN_NAME PATTERN_TEXT
{ add_pattern($1, $2); }
;
%%
void yyerror(const char*msg)
{
fprintf(stderr, "%s\n", msg);
}
+22 -2
View File
@@ -16,8 +16,8 @@
* 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: dup_expr.cc,v 1.1 1999/11/27 19:07:57 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: dup_expr.cc,v 1.4 2000/05/07 18:20:07 steve Exp $"
#endif
# include "netlist.h"
@@ -29,8 +29,28 @@ NetEScope* NetEScope::dup_expr() const
return 0;
}
NetESFunc* NetESFunc::dup_expr() const
{
NetESFunc*tmp = new NetESFunc(name_, expr_width(), nparms());
for (unsigned idx = 0 ; idx < nparms() ; idx += 1)
tmp->parm(idx, tmp->parm(idx)->dup_expr());
return tmp;
}
/*
* $Log: dup_expr.cc,v $
* Revision 1.4 2000/05/07 18:20:07 steve
* Import MCD support from Stephen Tell, and add
* system function parameter support to the IVL core.
*
* Revision 1.3 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.2 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
+157
View File
@@ -0,0 +1,157 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com.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) && !defined(macintosh)
#ident "$Id: elab_anet.cc,v 1.2 2001/01/06 02:29:36 steve Exp $"
#endif
/*
* The elaborate_anet methods elaborate expressions that are intended
* to be the left side of procedural continuous assignments.
*/
# include "PExpr.h"
# include "netlist.h"
# include <iostream>
NetNet* PExpr::elaborate_anet(Design*des, NetScope*scope) const
{
cerr << get_line() << ": error: Invalid expression on left side "
<< "of precedural continuous asignment." << endl;
return 0;
}
NetNet* PEConcat::elaborate_anet(Design*des, NetScope*scope) const
{
if (repeat_) {
cerr << get_line() << ": error: Repeat concatenations make "
"no sense in l-value expressions. I refuse." << endl;
des->errors += 1;
return 0;
}
svector<NetNet*>nets (parms_.count());
unsigned pins = 0;
unsigned errors = 0;
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
if (parms_[idx] == 0) {
cerr << get_line() << ": error: Empty expressions "
<< "not allowed in concatenations." << endl;
errors += 1;
continue;
}
nets[idx] = parms_[idx]->elaborate_anet(des, scope);
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.
Allow for a repeat count other then 1 by repeating the
connect loop as many times as necessary. */
NetNet*osig = new NetNet(scope, des->local_symbol(scope->name()),
NetNet::IMPLICIT_REG, 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);
return osig;
}
NetNet* PEIdent::elaborate_anet(Design*des, NetScope*scope) const
{
NetNet*sig = des->find_signal(scope, text_);
if (sig == 0) {
if (NetMemory*mem = des->find_memory(scope, text_)) {
cerr << get_line() << ": error: memories not allowed "
<< "on left side of procedural continuous "
<< "asignment." << endl;
des->errors += 1;
return 0;
}
cerr << get_line() << ": error: reg ``" << text_ << "'' "
<< "is undefined in this scope." << endl;
des->errors += 1;
return 0;
}
switch (sig->type()) {
case NetNet::REG:
case NetNet::IMPLICIT_REG:
break;
default:
cerr << get_line() << ": error: " << text_ << " is not "
<< "a reg in this context." << endl;
des->errors += 1;
return 0;
}
assert(sig);
if (msb_ || lsb_) {
cerr << get_line() << ": error: bit/part selects not allowed "
<< "on left side of procedural continuous asignment."
<< endl;
des->errors += 1;
return 0;
}
return sig;
}
/*
* $Log: elab_anet.cc,v $
* Revision 1.2 2001/01/06 02:29:36 steve
* Support arrays of integers.
*
* Revision 1.1 2000/12/06 06:31:09 steve
* Check lvalue of procedural continuous assign (PR#29)
*
*/
+334 -58
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,24 +16,33 @@
* 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 $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: elab_expr.cc,v 1.33 2001/01/13 22:20:08 steve Exp $"
#endif
# include "pform.h"
# include "netlist.h"
NetExpr* PExpr::elaborate_expr(Design*des, NetScope*) const
{
cerr << get_line() << ": internal error: I do not know how to elaborate"
<< " expression. " << endl;
cerr << get_line() << ": : Expression is: " << *this
<< endl;
des->errors += 1;
return 0;
}
/*
* 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
NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope) const
{
bool flag;
NetExpr*lp = left_->elaborate_expr(des, path);
NetExpr*rp = right_->elaborate_expr(des, path);
NetExpr*lp = left_->elaborate_expr(des, scope);
NetExpr*rp = right_->elaborate_expr(des, scope);
if ((lp == 0) || (rp == 0)) {
delete lp;
delete rp;
@@ -55,7 +64,21 @@ NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
}
}
NetEBinary*tmp = elaborate_expr_base_(des, lp, rp);
return tmp;
}
/*
* This is common elaboration of the operator. It presumes that the
* operands are elaborated as necessary, and all I need to do is make
* the correct NetEBinary object and connect the parameters.
*/
NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
NetExpr*lp, NetExpr*rp) const
{
bool flag;
NetEBinary*tmp;
switch (op_) {
default:
tmp = new NetEBinary(op_, lp, rp);
@@ -68,6 +91,17 @@ NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
tmp->set_line(*this);
break;
case '*':
tmp = new NetEBMult(op_, lp, rp);
tmp->set_line(*this);
break;
case '/':
case '%':
tmp = new NetEBDiv(op_, lp, rp);
tmp->set_line(*this);
break;
case 'l':
case 'r':
tmp = new NetEBShift(op_, lp, rp);
@@ -111,38 +145,69 @@ NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
return tmp;
}
NetESFunc* PECallFunction::elaborate_sfunc_(Design*des, const string&path) const
NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope) const
{
cerr << get_line() << ": sorry: system functions not supported."
<< endl;
des->errors += 1;
return 0;
unsigned wid = 32;
if (name_ == "$time")
wid = 64;
NetESFunc*fun = new NetESFunc(name_, wid, parms_.count());
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
PExpr*expr = parms_[idx];
NetExpr*tmp = expr->elaborate_expr(des, scope);
fun->parm(idx, tmp);
}
return fun;
}
NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope) const
{
if (name_[0] == '$')
return elaborate_sfunc_(des, path);
return elaborate_sfunc_(des, scope);
string myname = path+"."+name_;
NetFuncDef*def = des->find_function(path, name_);
NetFuncDef*def = des->find_function(scope, name_);
if (def == 0) {
cerr << get_line() << ": error: No function " << name_ <<
" in this context (" << path << ")." << endl;
" in this context (" << scope->name() << ")." << endl;
des->errors += 1;
return 0;
}
assert(def);
svector<NetExpr*> parms (parms_.count());
NetScope*dscope = des->find_scope(def->name());
assert(dscope);
/* How many parameters have I got? Normally the size of the
list is correct, but there is the special case of a list of
1 nil pointer. This is how the parser tells me of no
parameter. In other words, ``func()'' is 1 nil parameter. */
unsigned parms_count = parms_.count();
if ((parms_count == 1) && (parms_[0] == 0))
parms_count = 0;
svector<NetExpr*> parms (parms_count);
/* Elaborate the input expressions for the function. This is
done in the scope of the function call, and not the scope
of the function being called. The scope of the called
function is elaborated when the definition is elaborated. */
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
NetExpr*tmp = parms_[idx]->elaborate_expr(des, myname);
parms[idx] = tmp;
PExpr*tmp = parms_[idx];
assert(tmp);
parms[idx] = tmp->elaborate_expr(des, scope);
}
/* 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_);
/* Look for the return value signal for the called
function. This return value is a magic signal in the scope
of the function, that has the name of the function. The
function code assigns to this signal to return a value. */
NetNet*res = des->find_signal(dscope, name_);
if (res == 0) {
cerr << get_line() << ": internal error: Unable to locate "
"function return value for " << name_ << " in " <<
@@ -159,22 +224,66 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
}
NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope) const
{
// System identifiers show up in the netlist as identifiers.
if (text_[0] == '$')
return new NetEIdent(text_, 64);
unsigned repeat = 1;
string name = path+"."+text_;
/* If there is a repeat expression, then evaluate the constant
value and set the repeat count. */
if (repeat_) {
verinum*vrep = repeat_->eval_const(des, scope->name());
if (vrep == 0) {
cerr << get_line() << ": error: "
"concatenation repeat expression cannot be evaluated."
<< endl;
des->errors += 1;
return 0;
}
repeat = vrep->as_ulong();
delete vrep;
}
/* Make the empty concat expression. */
NetEConcat*tmp = new NetEConcat(parms_.count(), repeat);
tmp->set_line(*this);
/* Elaborate all the parameters and attach them to the concat node. */
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
assert(parms_[idx]);
NetExpr*ex = parms_[idx]->elaborate_expr(des, scope);
if (ex == 0) continue;
ex->set_line(*parms_[idx]);
if (! ex->has_width()) {
cerr << ex->get_line() << ": error: operand of "
<< "concatenation has indefinite width: "
<< *ex << endl;
des->errors += 1;
}
tmp->set(idx, ex);
}
return tmp;
}
NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope) const
{
assert(text_[0] != '$');
//string name = path+"."+text_;
assert(scope);
// 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_)) {
if (const NetExpr*ex = des->find_parameter(scope, text_)) {
NetExpr*tmp;
if (dynamic_cast<const NetExpr*>(ex))
tmp = ex->dup_expr();
else
tmp = new NetEParam(des, path, text_);
tmp = new NetEParam(des, scope, text_);
tmp->set_line(*this);
return tmp;
@@ -182,15 +291,16 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
// 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 (NetNet*net = des->find_signal(scope, text_)) {
// If this is a part select of a signal, then make a new
// temporary signal that is connected to just the
// selected bits.
// selected bits. The lsb_ and msb_ expressions are from
// the foo[msb:lsb] expression in the original.
if (lsb_) {
assert(msb_);
verinum*lsn = lsb_->eval_const(des, path);
verinum*msn = msb_->eval_const(des, path);
verinum*lsn = lsb_->eval_const(des, scope->name());
verinum*msn = msb_->eval_const(des, scope->name());
if ((lsn == 0) || (msn == 0)) {
cerr << get_line() << ": error: "
"Part select expresions must be "
@@ -201,14 +311,50 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
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);
/* The indices of part selects are signed
integers, so allow negative values. However,
the width that they represent is
unsigned. Remember that any order is possible,
i.e. [1:0], [-4,6], etc. */
long lsv = lsn->as_long();
long msv = msn->as_long();
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
if (wid > net->pin_count()) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of range."
<< endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
assert(wid <= net->pin_count());
if (net->sb_to_idx(msv) < net->sb_to_idx(lsv)) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of order."
<< endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
if (net->sb_to_idx(msv) >= net->pin_count()) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of range."
<< endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
string tname = des->local_symbol(scope->name());
NetTmp*tsig = new NetTmp(scope, tname, wid);
// Connect the pins from the lsb up to the msb.
unsigned off = net->sb_to_idx(lsv);
@@ -218,7 +364,6 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
NetESignal*tmp = new NetESignal(tsig);
tmp->set_line(*this);
des->add_signal(tsig);
return tmp;
}
@@ -226,17 +371,25 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
// 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))) {
if (msb_ && (msn = msb_->eval_const(des, scope->name()))) {
assert(idx_ == 0);
unsigned long msv = msn->as_ulong();
unsigned idx = net->sb_to_idx(msv);
string tname = des->local_symbol(path);
NetTmp*tsig = new NetTmp(tname);
connect(tsig->pin(0), net->pin(msv));
if (idx >= net->pin_count()) {
cerr << get_line() << ": internal error: "
<< "bit " << msv << " out of range of net "
<< net->name() << "[" << net->msb()
<< ":" << net->lsb() << "]." << endl;
return 0;
}
string tname = des->local_symbol(scope->name());
NetTmp*tsig = new NetTmp(scope, tname);
connect(tsig->pin(0), net->pin(idx));
NetESignal*tmp = new NetESignal(tsig);
tmp->set_line(*this);
des->add_signal(tsig);
return tmp;
}
@@ -246,7 +399,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
// 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);
NetExpr*ex = msb_->elaborate_expr(des, scope);
NetESubSignal*ss = new NetESubSignal(node, ex);
ss->set_line(*this);
return ss;
@@ -261,17 +414,23 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
// 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 (NetMemory*mem = des->find_memory(scope, text_)) {
if (msb_ == 0) {
cerr << get_line() << ": error: Memory ``" << name <<
"'' referenced without an index expression." << endl;
NetEMemory*node = new NetEMemory(mem);
node->set_line(*this);
return node;
}
assert(msb_ != 0);
if (lsb_) {
cerr << get_line() << ": error: part select of a memory: "
<< mem->name() << endl;
des->errors += 1;
return 0;
}
assert(msb_ != 0);
assert(lsb_ == 0);
assert(idx_ == 0);
NetExpr*i = msb_->elaborate_expr(des, path);
NetExpr*i = msb_->elaborate_expr(des, scope);
if (msb_ && i == 0) {
cerr << get_line() << ": error: Unable to exaborate "
"index expression `" << *msb_ << "'" << endl;
@@ -293,33 +452,48 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
// I cannot interpret this identifier. Error message.
cerr << get_line() << ": error: Unable to bind wire/reg/memory "
"`" << path << "." << text_ << "'" << endl;
"`" << text_ << "' in `" << scope->name() << "'" << endl;
des->errors += 1;
return 0;
}
NetEConst* PENumber::elaborate_expr(Design*des, NetScope*) const
{
assert(value_);
NetEConst*tmp = new NetEConst(*value_);
tmp->set_line(*this);
return tmp;
}
NetEConst* PEString::elaborate_expr(Design*des, NetScope*) const
{
NetEConst*tmp = new NetEConst(value());
tmp->set_line(*this);
return tmp;
}
/*
* 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
NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope) const
{
assert(expr_);
assert(tru_);
assert(fal_);
NetExpr*con = expr_->elaborate_expr(des, path);
NetExpr*con = expr_->elaborate_expr(des, scope);
if (con == 0)
return 0;
NetExpr*tru = tru_->elaborate_expr(des, path);
NetExpr*tru = tru_->elaborate_expr(des, scope);
if (tru == 0) {
delete con;
return 0;
}
NetExpr*fal = fal_->elaborate_expr(des, path);
NetExpr*fal = fal_->elaborate_expr(des, scope);
if (fal == 0) {
delete con;
delete tru;
@@ -330,8 +504,110 @@ NetExpr*PETernary::elaborate_expr(Design*des, const string&path) const
return res;
}
NetEUnary* PEUnary::elaborate_expr(Design*des, NetScope*scope) const
{
NetExpr*ip = expr_->elaborate_expr(des, scope);
if (ip == 0) return 0;
/* Should we evaluate expressions ahead of time,
* just like in PEBinary::elaborate_expr() ?
*/
NetEUnary*tmp;
switch (op_) {
default:
tmp = new NetEUnary(op_, ip);
tmp->set_line(*this);
break;
case '!': // Logical NOT
case '&': // Reduction AND
case '|': // Reduction OR
case '^': // Reduction XOR
case 'A': // Reduction NAND (~&)
case 'N': // Reduction NOR (~|)
case 'X': // Reduction NXOR (~^)
tmp = new NetEUReduce(op_, ip);
tmp->set_line(*this);
break;
case '~':
tmp = new NetEUBits(op_, ip);
tmp->set_line(*this);
break;
}
return tmp;
}
/*
* $Log: elab_expr.cc,v $
* Revision 1.33 2001/01/13 22:20:08 steve
* Parse parameters within nested scopes.
*
* Revision 1.32 2001/01/02 04:21:13 steve
* Support a bunch of unary operators in parameter expressions.
*
* Revision 1.31 2000/12/10 22:01:35 steve
* Support decimal constants in behavioral delays.
*
* Revision 1.30 2000/11/29 05:24:00 steve
* synthesis for unary reduction ! and N operators.
*
* Revision 1.29 2000/09/26 05:05:58 steve
* Detect indefinite widths where definite widths are required.
*
* Revision 1.28 2000/09/24 17:41:13 steve
* fix null pointer when elaborating undefined task.
*
* Revision 1.27 2000/08/26 01:31:29 steve
* Handle out of range part select expressions.
*
* Revision 1.26 2000/05/19 01:55:09 steve
* Catch part select of memories as an error.
*
* Revision 1.25 2000/05/07 18:20:07 steve
* Import MCD support from Stephen Tell, and add
* system function parameter support to the IVL core.
*
* Revision 1.24 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.23 2000/05/02 03:13:30 steve
* Move memories to the NetScope object.
*
* Revision 1.22 2000/05/02 00:58:11 steve
* Move signal tables to the NetScope class.
*
* Revision 1.21 2000/04/28 18:43:23 steve
* integer division in expressions properly get width.
*
* Revision 1.20 2000/03/29 04:06:28 steve
* Forgot to return elaborate result (Dan Nelsen)
*
* Revision 1.19 2000/03/20 16:57:22 steve
* select correct bit when reg has non-zero lsb.
*
* Revision 1.18 2000/03/12 18:22:11 steve
* Binary and unary operators in parameter expressions.
*
* Revision 1.17 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.16 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.15 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.14 2000/01/01 06:18:00 steve
* Handle synthesis of concatenation.
*
* Revision 1.13 1999/12/12 06:03:14 steve
* Allow memories without indices in expressions.
*
* Revision 1.12 1999/11/30 04:54:01 steve
* Match scope names as last resort.
*
+343
View File
@@ -0,0 +1,343 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: elab_lval.cc,v 1.11 2001/01/10 03:13:23 steve Exp $"
#endif
# include "PExpr.h"
# include "netlist.h"
/*
* These methods generate a NetAssign_ object for the l-value of the
* assignemnt. This is common code for the = and <= statements.
*
* What gets generated depends on the structure of the l-value. If the
* l-value is a simple name (i.e. foo <= <value>) the the NetAssign_
* is created the width of the foo reg and connected to all the
* bits.
*
* If there is a part select (i.e. foo[3:1] <= <value>) the NetAssign_
* is made only as wide as it needs to be (3 bits in this example) and
* connected to the correct bits of foo. A constant bit select is a
* special case of the part select.
*
* If the bit-select is non-constant (i.e. foo[<expr>] = <value>) the
* NetAssign_ is made wide enough to connect to all the bits of foo,
* then the mux expression is elaborated and attached to the
* NetAssign_ node as a b_mux value. The target must interpret the
* presense of a bmux value as taking a single bit and assigning it to
* the bit selected by the bmux expression.
*
* If the l-value expression is non-trivial, but can be fully
* evaluated at compile time (meaning any bit selects are constant)
* then elaboration will make a single NetAssign_ that connects to a
* synthetic reg that in turn connects to all the proper pins of the
* l-value.
*
* This last case can turn up in statements like: {a, b[1]} = c;
* rather then create a NetAssign_ for each item in the contatenation,
* elaboration makes a single NetAssign_ and connects it up properly.
*/
/*
* The default interpretation of an l-value to a procedural assignment
* is to try to make a net elaboration, and see if the result is
* suitable for assignment.
*/
NetAssign_* PExpr::elaborate_lval(Design*des, NetScope*scope) const
{
NetNet*ll = elaborate_net(des, scope->name(), 0, 0, 0, 0);
if (ll == 0) {
cerr << get_line() << ": Assignment l-value too complex."
<< endl;
return 0;
}
NetAssign_*lv = new NetAssign_(scope->local_symbol(), ll->pin_count());
for (unsigned idx = 0 ; idx < ll->pin_count() ; idx += 1)
connect(lv->pin(idx), ll->pin(idx));
des->add_node(lv);
return lv;
}
/*
* Concatenation expressions can appear as l-values. Handle them here.
*
* If adjacent l-values in the concatenation are not bit selects, then
* merge them into a single NetAssign_ object. This can happen is code
* like ``{ ...a, b, ...}''. As long as "a" and "b" do not have bit
* selects (or the bit selects are constant) we can merge the
* NetAssign_ objects.
*
* Be careful to get the bit order right. In the expression ``{a, b}''
* a is the MSB and b the LSB. Connect the LSB to the low pins of the
* NetAssign_ object.
*/
NetAssign_* PEConcat::elaborate_lval(Design*des, NetScope*scope) const
{
if (repeat_) {
cerr << get_line() << ": error: Repeat concatenations make "
"no sense in l-value expressions. I refuse." << endl;
des->errors += 1;
return 0;
}
NetAssign_*res = 0;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope);
/* If the l-value doesn't elaborate, the error was
already detected and printed. We just skip it and let
the compiler catch more errors. */
if (tmp == 0)
continue;
assert(tmp);
/* If adjacent l-values in the concatenation are not bit
selects, then merge them into a single NetAssign_
object.
If we cannot merge, then just link the new one to the
previous one. */
if (res && (res->bmux() == 0) && (tmp->bmux() == 0)) {
unsigned wid1 = tmp->pin_count();
unsigned wid2 = res->pin_count() + tmp->pin_count();
NetAssign_*tmp2 = new NetAssign_(res->name(), wid2);
assert(tmp->more == 0);
tmp2->more = res->more;
res->more = 0;
for (unsigned idx = 0 ; idx < wid1 ; idx += 1)
connect(tmp2->pin(idx), tmp->pin(idx));
for (unsigned idx = 0 ; idx < res->pin_count() ; idx += 1)
connect(tmp2->pin(idx+wid1), res->pin(idx));
delete res;
delete tmp;
res = tmp2;
des->add_node(res);
} else {
NetAssign_*last = tmp;
while (last->more)
last = last->more;
last->more = res;
res = tmp;
}
}
return res;
}
/*
* Handle the ident as an l-value. This includes bit and part selects
* of that ident.
*/
NetAssign_* PEIdent::elaborate_lval(Design*des, NetScope*scope) const
{
/* Get the signal referenced by the identifier, and make sure
it is a register. (Wires are not allows in this context. */
NetNet*reg = des->find_signal(scope, name());
if (reg == 0) {
NetMemory*mem = des->find_memory(scope, name());
if (mem != 0) {
cerr << get_line() << ": sorry: I cannot handle "
<< "memories in this l-value context." << endl;
} else {
cerr << get_line() << ": error: Could not find variable ``"
<< name() << "'' in ``" << scope->name() <<
"''" << endl;
}
des->errors += 1;
return 0;
}
assert(reg);
if (reg->type() != NetNet::REG) {
cerr << get_line() << ": error: " << name() <<
" is not a reg/integer/time in " << scope->name() <<
"." << endl;
des->errors += 1;
return 0;
}
long msb, lsb;
NetExpr*mux;
if (msb_ && lsb_) {
/* This handles part selects. In this case, there are
two bit select expressions, and both must be
constant. Evaluate them and pass the results back to
the caller. */
verinum*vl = lsb_->eval_const(des, scope->name());
if (vl == 0) {
cerr << lsb_->get_line() << ": error: "
"Part select expressions must be constant: "
<< *lsb_;
des->errors += 1;
return 0;
}
verinum*vm = msb_->eval_const(des, scope->name());
if (vl == 0) {
cerr << msb_->get_line() << ": error: "
"Part select expressions must be constant: "
<< *msb_;
des->errors += 1;
return 0;
}
msb = vm->as_long();
lsb = vl->as_long();
mux = 0;
} else if (msb_) {
/* If there is only a single select expression, it is a
bit select. Evaluate the constant value and treat it
as a part select with a bit width of 1. If the
expression it not constant, then return the
expression as a mux. */
assert(lsb_ == 0);
verinum*v = msb_->eval_const(des, scope->name());
if (v == 0) {
NetExpr*m = msb_->elaborate_expr(des, scope);
assert(m);
msb = 0;
lsb = 0;
mux = m;
} else {
msb = v->as_long();
lsb = v->as_long();
mux = 0;
}
} else {
/* No select expressions, so presume a part select the
width of the register. */
assert(msb_ == 0);
assert(lsb_ == 0);
msb = reg->msb();
lsb = reg->lsb();
mux = 0;
}
NetAssign_*lv;
if (mux) {
/* If there is a non-constant bit select, make a
NetAssign_ the width of the target reg and attach a
bmux to select the target bit. */
unsigned wid = reg->pin_count();
lv = new NetAssign_(des->local_symbol(scope->name()), wid);
for (unsigned idx = 0 ; idx < wid ; idx += 1)
connect(lv->pin(idx), reg->pin(idx));
lv->set_bmux(mux);
} else {
/* If the bit/part select is constant, then make the
NetAssign_ only as wide as it needs to be and connect
only to the selected bits of the reg. */
unsigned loff = reg->sb_to_idx(lsb);
unsigned moff = reg->sb_to_idx(msb);
unsigned wid = moff - loff + 1;
lv = new NetAssign_(des->local_symbol(scope->name()), wid);
if (moff < loff) {
cerr << get_line() << ": error: part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is reversed." << endl;
des->errors += 1;
return 0;
}
if (wid > reg->pin_count()) {
cerr << get_line() << ": error: part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
des->errors += 1;
return 0;
}
assert(moff < reg->pin_count());
for (unsigned idx = 0 ; idx < wid ; idx += 1)
connect(lv->pin(idx), reg->pin(idx+loff));
}
des->add_node(lv);
return lv;
}
/*
* $Log: elab_lval.cc,v $
* Revision 1.11 2001/01/10 03:13:23 steve
* Build task outputs as lval instead of nets. (PR#98)
*
* Revision 1.10 2001/01/06 06:31:58 steve
* declaration initialization for time variables.
*
* Revision 1.9 2001/01/06 02:29:36 steve
* Support arrays of integers.
*
* Revision 1.8 2000/12/12 06:14:51 steve
* sorry for concatenated memories in l-values. (PR#76)
*
* Revision 1.7 2000/12/01 02:55:37 steve
* Detect part select errors on l-values.
*
* Revision 1.6 2000/10/31 17:49:02 steve
* Support time variables.
*
* Revision 1.5 2000/10/26 17:09:46 steve
* Fix handling of errors in behavioral lvalues. (PR#28)
*
* Revision 1.4 2000/09/10 15:43:59 steve
* Some error checking.
*
* Revision 1.3 2000/09/10 03:59:59 steve
* Agressively merge NetAssign_ within concatenations.
*
* Revision 1.2 2000/09/10 02:18:16 steve
* elaborate complex l-values
*
* Revision 1.1 2000/09/09 15:21:26 steve
* move lval elaboration to PExpr virtual methods.
*
*/
+1310 -252
View File
File diff suppressed because it is too large Load Diff
+213
View File
@@ -0,0 +1,213 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: elab_pexpr.cc,v 1.7 2001/01/02 04:21:13 steve Exp $"
#endif
# include "PExpr.h"
NetExpr*PExpr::elaborate_pexpr(Design*des, NetScope*sc) const
{
cerr << get_line() << ": error: invalid parameter expression: "
<< *this << endl;
des->errors += 1;
return 0;
}
/*
* Binary operators have sub-expressions that must be elaborated as
* parameter expressions. If either of them fail, then give up. Once
* they are taken care of, make the base object just as in any other
* expression.
*/
NetExpr*PEBinary::elaborate_pexpr (Design*des, NetScope*scope) const
{
NetExpr*lp = left_->elaborate_pexpr(des, scope);
NetExpr*rp = right_->elaborate_pexpr(des, scope);
if ((lp == 0) || (rp == 0)) {
delete lp;
delete rp;
return 0;
}
NetEBinary*tmp = elaborate_expr_base_(des, lp, rp);
return tmp;
}
/*
* Event though parameters are not generally sized, parameter
* expressions can include concatenation expressions. This requires
* that the subexpressions all have well-defined size (in spite of
* being in a parameter expression) in order to get a defined
* value. The sub-expressions themsilves must also be value parameter
* expressions.
*/
NetEConcat* PEConcat::elaborate_pexpr(Design*des, NetScope*scope) const
{
unsigned repeat = 1;
/* If there is a repeat expression, then evaluate the constant
value and set the repeat count.
XXXX Potential bug XXX In principle, the repeat expression
can have a parameter name in it. Since where are in the
working of parameters now, we will not be able to
accurately evaluate such expressions. So eventually, I will
need to be able to defer the evaluation of the expression. */
if (repeat_) {
verinum*vrep = repeat_->eval_const(des, scope->name());
if (vrep == 0) {
cerr << get_line() << ": error: "
"concatenation repeat expression cannot be evaluated."
<< endl;
des->errors += 1;
return 0;
}
repeat = vrep->as_ulong();
delete vrep;
}
/* Make the empty concat expression. */
NetEConcat*tmp = new NetEConcat(parms_.count(), repeat);
tmp->set_line(*this);
/* Elaborate all the operands and attach them to the concat
node. Use the elaborate_pexpr method instead of the
elaborate_expr method. */
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
assert(parms_[idx]);
NetExpr*ex = parms_[idx]->elaborate_pexpr(des, scope);
if (ex == 0) continue;
ex->set_line(*parms_[idx]);
tmp->set(idx, ex);
}
return tmp;
}
/*
* Parameter expressions may reference other parameters, but only in
* the current scope. Preserve the parameter reference in the
* parameter expression I'm generating, instead of evaluating it now,
* because the referenced parameter may yet be overridden.
*/
NetExpr*PEIdent::elaborate_pexpr(Design*des, NetScope*scope) const
{
const NetExpr*ex = scope->get_parameter(text_);
if (ex == 0) {
cerr << get_line() << ": error: identifier ``" << text_ <<
"'' is not a parameter in " << scope->name() << "." << endl;
des->errors += 1;
return 0;
}
NetExpr*res = new NetEParam(des, scope, text_);
assert(res);
return res;
}
/*
* Simple numbers can be elaborated by the elaborate_expr method.
*/
NetExpr*PENumber::elaborate_pexpr(Design*des, NetScope*sc) const
{
return elaborate_expr(des, sc);
}
NetEConst* PEString::elaborate_pexpr(Design*des, NetScope*scope) const
{
return elaborate_expr(des, scope);
}
NetETernary* PETernary::elaborate_pexpr(Design*des, NetScope*scope) const
{
NetExpr*c = expr_->elaborate_pexpr(des, scope);
NetExpr*t = tru_->elaborate_pexpr(des, scope);
NetExpr*f = fal_->elaborate_pexpr(des, scope);
if (c == 0) return 0;
if (t == 0) return 0;
if (f == 0) return 0;
return new NetETernary(c, t, f);
}
NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
{
NetExpr*ip = expr_->elaborate_pexpr(des, scope);
if (ip == 0) return 0;
/* Should we evaluate expressions ahead of time,
* just like in PEBinary::elaborate_expr() ?
*/
NetEUnary*tmp;
switch (op_) {
default:
tmp = new NetEUnary(op_, ip);
tmp->set_line(*this);
break;
case '~':
tmp = new NetEUBits(op_, ip);
tmp->set_line(*this);
break;
case '!': // Logical NOT
case '&': // Reduction AND
case '|': // Reduction OR
case '^': // Reduction XOR
case 'A': // Reduction NAND (~&)
case 'N': // Reduction NOR (~|)
case 'X': // Reduction NXOR (~^)
tmp = new NetEUReduce(op_, ip);
tmp->set_line(*this);
break;
}
return tmp;
}
/*
* $Log: elab_pexpr.cc,v $
* Revision 1.7 2001/01/02 04:21:13 steve
* Support a bunch of unary operators in parameter expressions.
*
* Revision 1.6 2000/12/16 19:03:30 steve
* Evaluate <= and ?: in parameter expressions (PR#81)
*
* Revision 1.5 2000/06/13 05:22:16 steve
* Support concatenation in parameter expressions.
*
* Revision 1.4 2000/06/01 02:31:39 steve
* Parameters can be strings.
*
* Revision 1.3 2000/03/12 18:22:11 steve
* Binary and unary operators in parameter expressions.
*
* Revision 1.2 2000/03/12 04:35:22 steve
* Allow parameter identifiers in parameter expressions.
*
* Revision 1.1 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
*/
+477
View File
@@ -0,0 +1,477 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: elab_scope.cc,v 1.7 2000/12/16 01:45:48 steve Exp $"
#endif
/*
* Elaboration happens in two passes, generally. The first scans the
* pform to generate the NetScope tree and attach it to the Design
* object. The methods in this source file implement the elaboration
* of the scopes.
*/
# include "Module.h"
# include "PEvent.h"
# include "PExpr.h"
# include "PGate.h"
# include "PTask.h"
# include "PWire.h"
# include "Statement.h"
# include "netlist.h"
# include <typeinfo>
bool Module::elaborate_scope(Design*des, NetScope*scope) const
{
// Generate all the parameters that this instance of this
// module introduces to the design. This loop elaborates the
// parameters, but doesn't evaluate references to
// parameters. This scan practically locates all the
// parameters and puts them in the parameter table in the
// design.
// No expressions are evaluated, yet. For now, leave them in
// the pform and just place a NetEParam placeholder in the
// place of the elaborated expression.
typedef map<string,PExpr*>::const_iterator mparm_it_t;
// This loop scans the parameters in the module, and creates
// stub parameter entries in the scope for the parameter name.
for (mparm_it_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
scope->set_parameter((*cur).first, new NetEParam);
}
for (mparm_it_t cur = localparams.begin()
; cur != localparams.end() ; cur ++) {
scope->set_parameter((*cur).first, new NetEParam);
}
// Now scan the parameters again, this time elaborating them
// for use as parameter values. This is after the previous
// scan so that local parameter names can be used in the
// r-value expressions.
for (mparm_it_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
PExpr*ex = (*cur).second;
assert(ex);
NetExpr*val = ex->elaborate_pexpr(des, scope);
val = scope->set_parameter((*cur).first, val);
assert(val);
delete val;
}
for (mparm_it_t cur = localparams.begin()
; cur != localparams.end() ; cur ++) {
PExpr*ex = (*cur).second;
assert(ex);
NetExpr*val = ex->elaborate_pexpr(des, scope);
val = scope->set_parameter((*cur).first, val);
assert(val);
delete val;
}
// Run through the defparams for this module, elaborate the
// expressions in this context and save the result is a table
// for later final override.
// It is OK to elaborate the expressions of the defparam here
// because Verilog requires that the expressions only use
// local parameter names. It is *not* OK to do the override
// here becuase the parameter receiving the assignment may be
// in a scope not discovered by this pass.
for (mparm_it_t cur = defparms.begin()
; cur != defparms.end() ; cur ++ ) {
PExpr*ex = (*cur).second;
assert(ex);
NetExpr*val = ex->elaborate_pexpr(des, scope);
if (val == 0) continue;
scope->defparams[(*cur).first] = val;
}
// Tasks introduce new scopes, so scan the tasks in this
// module. Create a scope for the task and pass that to the
// elaborate_scope method of the PTask for detailed
// processing.
typedef map<string,PTask*>::const_iterator tasks_it_t;
for (tasks_it_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++ ) {
NetScope*task_scope = new NetScope(scope, (*cur).first,
NetScope::TASK);
(*cur).second->elaborate_scope(des, task_scope);
}
// Functions are very similar to tasks, at least from the
// perspective of scopes. So handle them exactly the same
// way.
typedef map<string,PFunction*>::const_iterator funcs_it_t;
for (funcs_it_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++ ) {
NetScope*func_scope = new NetScope(scope, (*cur).first,
NetScope::FUNC);
(*cur).second->elaborate_scope(des, func_scope);
}
// Gates include modules, which might introduce new scopes, so
// scan all of them to create those scopes.
typedef list<PGate*>::const_iterator gates_it_t;
for (gates_it_t cur = gates_.begin()
; cur != gates_.end() ; cur ++ ) {
(*cur) -> elaborate_scope(des, scope);
}
// initial and always blocks may contain begin-end and
// fork-join blocks that can introduce scopes. Therefore, I
// get to scan processes here.
typedef list<PProcess*>::const_iterator proc_it_t;
for (proc_it_t cur = behaviors_.begin()
; cur != behaviors_.end() ; cur ++ ) {
(*cur) -> statement() -> elaborate_scope(des, scope);
}
// Scan through all the named events in this scope. We do not
// need anything more then the current scope to do this
// elaboration, so do it now. This allows for normal
// elaboration to reference these events.
for (map<string,PEvent*>::const_iterator et = events.begin()
; et != events.end() ; et ++ ) {
(*et).second->elaborate_scope(des, scope);
}
return des->errors == 0;
}
void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
{
// Missing module instance names have already been rejected.
assert(get_name() != "");
string path = sc->name();
// Check for duplicate scopes. Simply look up the scope I'm
// about to create, and if I find it then somebody beat me to
// it.
if (NetScope*tmp = des->find_scope(path + "." + get_name())) {
cerr << get_line() << ": error: Instance/Scope name " <<
get_name() << " already used in this context." <<
endl;
des->errors += 1;
return;
}
// check for recursive instantiation by scanning the current
// scope and its parents. Look for a module instantiation of
// the same module, but farther up in the scope.
for (NetScope*scn = sc ; scn ; scn = scn->parent()) {
if (scn->type() != NetScope::MODULE)
continue;
if (mod->get_name() != scn->module_name())
continue;
cerr << get_line() << ": error: You cannot instantiate "
<< "module " << mod->get_name() << " within itself." << endl;
cerr << get_line() << ": : The offending instance is "
<< sc->name() << "." << get_name() << " within "
<< scn->name() << "." << endl;
des->errors += 1;
return;
}
// Create the new scope as a MODULE with my name.
NetScope*my_scope = new NetScope(sc, get_name(), NetScope::MODULE);
my_scope->set_module_name(mod->get_name().c_str());
// Set time units and precision.
my_scope->time_unit(mod->time_unit);
my_scope->time_precision(mod->time_precision);
des->set_precision(mod->time_precision);
// This call actually arranges for the description of the
// module type to process this instance and handle parameters
// and sub-scopes that might occur. Parameters are also
// created in that scope, as they exist. (I'll override them
// later.)
mod->elaborate_scope(des, my_scope);
// Look for module parameter replacements. This map receives
// those replacements.
typedef map<string,PExpr*>::const_iterator mparm_it_t;
map<string,PExpr*> replace;
// Positional parameter overrides are matched to parameter
// names by using the param_names list of parameter
// names. This is an ordered list of names so the first name
// is parameter 0, the second parameter 1, and so on.
if (overrides_) {
assert(parms_ == 0);
list<string>::const_iterator cur = mod->param_names.begin();
for (unsigned idx = 0
; idx < overrides_->count()
; idx += 1, cur++) {
replace[*cur] = (*overrides_)[idx];
}
}
// Named parameter overrides carry a name with each override
// so the mapping into the replace list is much easier.
if (parms_) {
assert(overrides_ == 0);
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1)
replace[parms_[idx].name] = parms_[idx].parm;
}
// And here we scan the replacements we collected. Elaborate
// the expression in my context, then replace the sub-scope
// parameter value with the new expression.
for (mparm_it_t cur = replace.begin()
; cur != replace.end() ; cur ++ ) {
PExpr*tmp = (*cur).second;
NetExpr*val = tmp->elaborate_pexpr(des, sc);
val = my_scope->set_parameter((*cur).first, val);
assert(val);
delete val;
}
}
/*
* The isn't really able to create new scopes, but it does create the
* event name in the current scope, so can be done during the
* elaborate_scope scan.
*/
void PEvent::elaborate_scope(Design*des, NetScope*scope) const
{
NetEvent*ev = new NetEvent(name_);
ev->set_line(*this);
scope->add_event(ev);
}
void PFunction::elaborate_scope(Design*des, NetScope*scope) const
{
}
void PTask::elaborate_scope(Design*des, NetScope*scope) const
{
assert(scope->type() == NetScope::TASK);
}
/*
* The base statement does not have sub-statements and does not
* introduce any scope, so this is a no-op.
*/
void Statement::elaborate_scope(Design*, NetScope*) const
{
}
/*
* When I get a behavioral block, check to see if it has a name. If it
* does, then create a new scope for the statements within it,
* otherwise use the current scope. Use the selected scope to scan the
* statements that I contain.
*/
void PBlock::elaborate_scope(Design*des, NetScope*scope) const
{
NetScope*my_scope = scope;
if (name_ != "") {
my_scope = new NetScope(scope, name_, bl_type_==BL_PAR
? NetScope::FORK_JOIN
: NetScope::BEGIN_END);
}
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1)
list_[idx] -> elaborate_scope(des, my_scope);
}
/*
* The case statement itseof does not introduce scope, but contains
* other statements that may be named blocks. So scan the case items
* with the elaborate_scope method.
*/
void PCase::elaborate_scope(Design*des, NetScope*scope) const
{
assert(items_);
for (unsigned idx = 0 ; idx < (*items_).count() ; idx += 1) {
assert( (*items_)[idx] );
if (Statement*sp = (*items_)[idx]->stat)
sp -> elaborate_scope(des, scope);
}
}
/*
* The conditional statement (if-else) does not introduce scope, but
* the statements of the clauses may, so elaborate_scope the contained
* statements.
*/
void PCondit::elaborate_scope(Design*des, NetScope*scope) const
{
if (if_)
if_ -> elaborate_scope(des, scope);
if (else_)
else_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PDelayStatement::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PEventStatement::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PForever::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PForStatement::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PRepeat::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PWhile::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* $Log: elab_scope.cc,v $
* Revision 1.7 2000/12/16 01:45:48 steve
* Detect recursive instantiations (PR#2)
*
* Revision 1.6 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.5 2000/07/22 22:09:03 steve
* Parse and elaborate timescale to scopes.
*
* Revision 1.4 2000/04/09 17:44:30 steve
* Catch event declarations during scope elaborate.
*
* Revision 1.3 2000/03/12 17:09:41 steve
* Support localparam.
*
* Revision 1.2 2000/03/11 03:25:52 steve
* Locate scopes in statements.
*
* Revision 1.1 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
*/
+448
View File
@@ -0,0 +1,448 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: elab_sig.cc,v 1.10 2001/01/13 22:20:08 steve Exp $"
#endif
# include "Module.h"
# include "PExpr.h"
# include "PGate.h"
# include "PTask.h"
# include "PWire.h"
# include "netlist.h"
# include "util.h"
/*
* This local function checks if a named signal is connected to a
* port. It looks in the array of ports passed, for NetEIdent objects
* within the port_t that have a matching name.
*/
static bool signal_is_in_port(const svector<Module::port_t*>&ports,
const string&name)
{
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
Module::port_t*pp = ports[idx];
// Skip internally unconnected ports.
if (pp == 0)
continue;
// This port has an internal connection. In this case,
// the port has 0 or more NetEIdent objects concatenated
// together that form the port.
for (unsigned cc = 0 ; cc < pp->expr.count() ; cc += 1) {
assert(pp->expr[cc]);
if (pp->expr[cc]->name() == name)
return true;
}
}
return false;
}
bool Module::elaborate_sig(Design*des, NetScope*scope) const
{
bool flag = true;
// Get all the explicitly declared wires of the module and
// start the signals list with them.
const map<string,PWire*>&wl = get_wires();
for (map<string,PWire*>::const_iterator wt = wl.begin()
; wt != wl.end()
; wt ++ ) {
PWire*cur = (*wt).second;
cur->elaborate_sig(des, scope);
// If this wire is a signal of the module (as opposed to
// a port of a function) and is a port, then check that
// the module knows about it.
NetNet*sig = scope->find_signal(cur->name());
if (sig && (sig->scope() == scope)
&& (cur->get_port_type() != NetNet::NOT_A_PORT)) {
string name = (*wt).first;
if (! signal_is_in_port(ports_, name)) {
cerr << cur->get_line() << ": error: Signal "
<< name << " has a declared direction "
<< "but is not a port." << endl;
des->errors += 1;
}
}
}
// Get all the gates of the module and elaborate them by
// connecting them to the signals. The gate may be simple or
// complex. What we are looking for is gates that are modules
// that can create scopes and signals.
const list<PGate*>&gl = get_gates();
for (list<PGate*>::const_iterator gt = gl.begin()
; gt != gl.end()
; gt ++ ) {
flag &= (*gt)->elaborate_sig(des, scope);
}
typedef map<string,PFunction*>::const_iterator mfunc_it_t;
for (mfunc_it_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++) {
NetScope*fscope = scope->child((*cur).first);
if (scope == 0) {
cerr << (*cur).second->get_line() << ": internal error: "
<< "Child scope for function " << (*cur).first
<< " missing in " << scope->name() << "." << endl;
des->errors += 1;
continue;
}
(*cur).second->elaborate_sig(des, fscope);
}
// After all the wires are elaborated, we are free to
// elaborate the ports of the tasks defined within this
// module. Run through them now.
typedef map<string,PTask*>::const_iterator mtask_it_t;
for (mtask_it_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++) {
NetScope*tscope = scope->child((*cur).first);
assert(tscope);
(*cur).second->elaborate_sig(des, tscope);
}
return flag;
}
bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope,
Module*rmod) const
{
// Missing module instance names have already been rejected.
assert(get_name() != "");
if (msb_) {
cerr << get_line() << ": sorry: Module instantiation arrays "
"are not yet supported." << endl;
des->errors += 1;
return false;
}
// I know a priori that the elaborate_scope created the scope
// already, so just look it up as a child of the current scope.
NetScope*my_scope = scope->child(get_name());
assert(my_scope);
return rmod->elaborate_sig(des, my_scope);
}
/*
* A function definition exists within an elaborated module.
*/
void PFunction::elaborate_sig(Design*des, NetScope*scope) const
{
string fname = scope->basename();
assert(scope->type() == NetScope::FUNC);
svector<NetNet*>ports (ports_? ports_->count()+1 : 1);
/* Get the reg for the return value. I know the name of the
reg variable, and I know that it is in this scope, so look
it up directly. */
ports[0] = scope->find_signal(scope->basename());
if (ports[0] == 0) {
cerr << get_line() << ": internal error: function scope "
<< scope->name() << " is missing return reg "
<< fname << "." << endl;
scope->dump(cerr);
des->errors += 1;
return;
}
if (ports_)
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
/* Parse the port name into the task name and the reg
name. We know by design that the port name is given
as two components: <func>.<port>. */
string pname = (*ports_)[idx]->name();
string ppath = parse_first_name(pname);
if (ppath != scope->basename()) {
cerr << get_line() << ": internal error: function "
<< "port " << (*ports_)[idx]->name()
<< " has wrong name for function "
<< scope->name() << "." << endl;
des->errors += 1;
}
NetNet*tmp = scope->find_signal(pname);
if (tmp == 0) {
cerr << get_line() << ": internal error: function "
<< scope->name() << " is missing port "
<< pname << "." << endl;
scope->dump(cerr);
des->errors += 1;
}
ports[idx+1] = tmp;
}
NetFuncDef*def = new NetFuncDef(scope, ports);
scope->set_func_def(def);
}
/*
* A task definition is a scope within an elaborated module. When we
* are elaborating signals, the scopes have already been created, as
* have the reg objects that are the parameters of this task. The
* elaborate_sig method of PTask is therefore left to connect the
* signals to the ports of the NetTaskDef definition. We know for
* certain that signals exist (They are in my scope!) so the port
* binding is sure to work.
*/
void PTask::elaborate_sig(Design*des, NetScope*scope) const
{
assert(scope->type() == NetScope::TASK);
svector<NetNet*>ports (ports_? ports_->count() : 0);
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
/* Parse the port name into the task name and the reg
name. We know by design that the port name is given
as two components: <task>.<port>. */
string pname = (*ports_)[idx]->name();
string ppath = parse_first_name(pname);
assert(pname != "");
/* check that the current scope really does have the
name of the first component of the task port name. Do
this by looking up the task scope in the parent of
the current scope. */
if (scope->parent()->child(ppath) != scope) {
cerr << "internal error: task scope " << ppath
<< " not the same as scope " << scope->name()
<< "?!" << endl;
return;
}
/* Find the signal for the port. We know by definition
that it is in the scope of the task, so look only in
the scope. */
NetNet*tmp = scope->find_signal(pname);
if (tmp == 0) {
cerr << get_line() << ": internal error: "
<< "Could not find port " << pname
<< " in scope " << scope->name() << endl;
scope->dump(cerr);
}
ports[idx] = tmp;
}
NetTaskDef*def = new NetTaskDef(scope->name(), ports);
scope->set_task_def(def);
}
bool PGate::elaborate_sig(Design*des, NetScope*scope) const
{
return true;
}
/*
* Elaborate a source wire. The "wire" is the declaration of wires,
* registers, ports and memories. The parser has already merged the
* multiple properties of a wire (i.e. "input wire") so come the
* elaboration this creates an object in the design that represent the
* defined item.
*/
void PWire::elaborate_sig(Design*des, NetScope*scope) const
{
/* The parser may produce hierarchical names for wires. I here
follow the scopes down to the base where I actually want to
elaborate the NetNet object. */
string basename = name_;
for (;;) {
string p = parse_first_name(basename);
if (basename == "") {
basename = p;
break;
}
scope = scope->child(p);
assert(scope);
}
const string path = scope->name();
NetNet::Type wtype = type_;
if (wtype == NetNet::IMPLICIT)
wtype = NetNet::WIRE;
if (wtype == NetNet::IMPLICIT_REG)
wtype = NetNet::REG;
unsigned wid = 1;
long lsb = 0, msb = 0;
if (msb_.count()) {
svector<long>mnum (msb_.count());
svector<long>lnum (msb_.count());
/* There may be multiple declarations of ranges, because
the symbol may have its range declared in i.e. input
and reg declarations. Calculate *all* the numbers
here. I will resolve the values later. */
for (unsigned idx = 0 ; idx < msb_.count() ; idx += 1) {
verinum*mval = msb_[idx]->eval_const(des,path);
if (mval == 0) {
cerr << msb_[idx]->get_line() << ": error: "
"Unable to evaluate constant expression ``" <<
*msb_[idx] << "''." << endl;
des->errors += 1;
return;
}
verinum*lval = lsb_[idx]->eval_const(des, path);
if (lval == 0) {
cerr << lsb_[idx]->get_line() << ": error: "
"Unable to evaluate constant expression ``" <<
*lsb_[idx] << "''." << endl;
des->errors += 1;
return;
}
mnum[idx] = mval->as_long();
lnum[idx] = lval->as_long();
delete mval;
delete lval;
}
/* Make sure all the values for msb and lsb match by
value. If not, report an error. */
for (unsigned idx = 1 ; idx < msb_.count() ; idx += 1) {
if ((mnum[idx] != mnum[0]) || (lnum[idx] != lnum[0])) {
cerr << get_line() << ": error: Inconsistent width, "
"[" << mnum[idx] << ":" << lnum[idx] << "]"
" vs. [" << mnum[0] << ":" << lnum[0] << "]"
" for signal ``" << basename << "''" << endl;
des->errors += 1;
return;
}
}
lsb = lnum[0];
msb = mnum[0];
if (mnum[0] > lnum[0])
wid = mnum[0] - lnum[0] + 1;
else
wid = lnum[0] - mnum[0] + 1;
}
if (lidx_ || ridx_) {
assert(lidx_ && ridx_);
// If the register has indices, then this is a
// memory. Create the memory object.
verinum*lval = lidx_->eval_const(des, path);
verinum*rval = ridx_->eval_const(des, path);
if ((lval == 0) || (rval == 0)) {
cerr << get_line() << ": internal error: There is "
<< "a problem evaluating indices for ``"
<< basename << "''." << endl;
des->errors += 1;
return;
}
assert(lval);
assert(rval);
long lnum = lval->as_long();
long rnum = rval->as_long();
delete lval;
delete rval;
NetMemory*sig = new NetMemory(scope, path+"."+basename,
wid, lnum, rnum);
} else {
NetNet*sig = new NetNet(scope, path + "." +basename, wtype, msb, lsb);
sig->set_line(*this);
sig->port_type(port_type_);
sig->set_signed(get_signed());
sig->set_attributes(attributes);
}
}
/*
* $Log: elab_sig.cc,v $
* Revision 1.10 2001/01/13 22:20:08 steve
* Parse parameters within nested scopes.
*
* Revision 1.9 2001/01/07 07:00:31 steve
* Detect port direction attached to non-ports.
*
* Revision 1.8 2001/01/04 04:47:51 steve
* Add support for << is signal indices.
*
* Revision 1.7 2000/12/11 00:31:43 steve
* Add support for signed reg variables,
* simulate in t-vvm signed comparisons.
*
* Revision 1.6 2000/12/04 17:37:04 steve
* Add Attrib class for holding NetObj attributes.
*
* Revision 1.5 2000/11/20 00:58:40 steve
* Add support for supply nets (PR#17)
*
* Revision 1.4 2000/09/07 22:37:48 steve
* ack, detect when lval fails.
*
* Revision 1.3 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.2 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.1 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
*/
+1206 -881
View File
File diff suppressed because it is too large Load Diff
+266 -244
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,8 +16,8 @@
* 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: emit.cc,v 1.31 1999/11/28 23:42:02 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: emit.cc,v 1.55 2000/11/04 01:54:01 steve Exp $"
#endif
/*
@@ -26,190 +26,240 @@
*/
# include "target.h"
# include "netlist.h"
# include <iostream>
# include <typeinfo>
# include <cassert>
void NetNode::emit_node(ostream&o, struct target_t*tgt) const
bool NetNode::emit_node(struct target_t*tgt) const
{
cerr << "EMIT: Gate type? " << typeid(*this).name() << endl;
return false;
}
void NetLogic::emit_node(ostream&o, struct target_t*tgt) const
bool NetLogic::emit_node(struct target_t*tgt) const
{
tgt->logic(o, this);
tgt->logic(this);
return true;
}
void NetUDP::emit_node(ostream&o, struct target_t*tgt) const
bool NetUDP_COMB::emit_node(struct target_t*tgt) const
{
tgt->udp(o, this);
tgt->udp_comb(this);
return true;
}
void NetAddSub::emit_node(ostream&o, struct target_t*tgt) const
bool NetUDP::emit_node(struct target_t*tgt) const
{
tgt->lpm_add_sub(o, this);
tgt->udp(this);
return true;
}
void NetAssign::emit_node(ostream&o, struct target_t*tgt) const
bool NetAddSub::emit_node(struct target_t*tgt) const
{
tgt->net_assign(o, this);
tgt->lpm_add_sub(this);
return true;
}
void NetAssignNB::emit_node(ostream&o, struct target_t*tgt) const
bool NetAssign_::emit_node(struct target_t*tgt) const
{
tgt->net_assign_nb(o, this);
tgt->net_assign(this);
return true;
}
void NetCaseCmp::emit_node(ostream&o, struct target_t*tgt) const
bool NetCaseCmp::emit_node(struct target_t*tgt) const
{
tgt->net_case_cmp(o, this);
tgt->net_case_cmp(this);
return true;
}
void NetCLShift::emit_node(ostream&o, struct target_t*tgt) const
bool NetCAssign::emit_node(struct target_t*tgt) const
{
tgt->lpm_clshift(o, this);
tgt->net_cassign(this);
return true;
}
void NetCompare::emit_node(ostream&o, struct target_t*tgt) const
bool NetCLShift::emit_node(struct target_t*tgt) const
{
tgt->lpm_compare(o, this);
tgt->lpm_clshift(this);
return true;
}
void NetConst::emit_node(ostream&o, struct target_t*tgt) const
bool NetCompare::emit_node(struct target_t*tgt) const
{
tgt->net_const(o, this);
tgt->lpm_compare(this);
return true;
}
void NetFF::emit_node(ostream&o, struct target_t*tgt) const
bool NetConst::emit_node(struct target_t*tgt) const
{
tgt->lpm_ff(o, this);
return tgt->net_const(this);
}
void NetMux::emit_node(ostream&o, struct target_t*tgt) const
bool NetDivide::emit_node(struct target_t*tgt) const
{
tgt->lpm_mux(o, this);
tgt->lpm_divide(this);
return true;
}
void NetRamDq::emit_node(ostream&o, struct target_t*tgt) const
bool NetFF::emit_node(struct target_t*tgt) const
{
tgt->lpm_ram_dq(o, this);
tgt->lpm_ff(this);
return true;
}
void NetNEvent::emit_node(ostream&o, struct target_t*tgt) const
bool NetForce::emit_node(struct target_t*tgt) const
{
tgt->net_event(o, this);
tgt->net_force(this);
return true;
}
void NetBUFZ::emit_node(ostream&o, struct target_t*tgt) const
bool NetModulo::emit_node(struct target_t*tgt) const
{
tgt->bufz(o, this);
tgt->lpm_modulo(this);
return true;
}
bool NetProcTop::emit(ostream&o, struct target_t*tgt) const
bool NetMult::emit_node(struct target_t*tgt) const
{
return tgt->process(o, this);
tgt->lpm_mult(this);
return true;
}
bool NetProc::emit_proc(ostream&o, struct target_t*tgt) const
bool NetMux::emit_node(struct target_t*tgt) const
{
tgt->lpm_mux(this);
return true;
}
bool NetRamDq::emit_node(struct target_t*tgt) const
{
tgt->lpm_ram_dq(this);
return true;
}
bool NetBUFZ::emit_node(struct target_t*tgt) const
{
return tgt->bufz(this);
}
bool NetProcTop::emit(struct target_t*tgt) const
{
return tgt->process(this);
}
bool NetProc::emit_proc(struct target_t*tgt) const
{
cerr << "EMIT: Proc type? " << typeid(*this).name() << endl;
return false;
}
bool NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssign::emit_proc(struct target_t*tgt) const
{
tgt->proc_assign(o, this);
tgt->proc_assign(this);
return true;
}
bool NetAssignNB::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssignNB::emit_proc(struct target_t*tgt) const
{
tgt->proc_assign_nb(o, this);
tgt->proc_assign_nb(this);
return true;
}
bool NetAssignMem::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssignMem::emit_proc(struct target_t*tgt) const
{
tgt->proc_assign_mem(o, this);
tgt->proc_assign_mem(this);
return true;
}
bool NetAssignMemNB::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssignMemNB::emit_proc(struct target_t*tgt) const
{
tgt->proc_assign_mem_nb(o, this);
tgt->proc_assign_mem_nb(this);
return true;
}
bool NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
bool NetBlock::emit_proc(struct target_t*tgt) const
{
return tgt->proc_block(o, this);
return tgt->proc_block(this);
}
bool NetCase::emit_proc(ostream&o, struct target_t*tgt) const
bool NetCase::emit_proc(struct target_t*tgt) const
{
tgt->proc_case(o, this);
tgt->proc_case(this);
return true;
}
bool NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
bool NetCAssign::emit_proc(struct target_t*tgt) const
{
tgt->proc_condit(o, this);
return tgt->proc_cassign(this);
}
bool NetCondit::emit_proc(struct target_t*tgt) const
{
tgt->proc_condit(this);
return true;
}
bool NetForever::emit_proc(ostream&o, struct target_t*tgt) const
bool NetDeassign::emit_proc(struct target_t*tgt) const
{
tgt->proc_forever(o, this);
return tgt->proc_deassign(this);
}
bool NetDisable::emit_proc(struct target_t*tgt) const
{
return tgt->proc_disable(this);
}
bool NetForce::emit_proc(struct target_t*tgt) const
{
return tgt->proc_force(this);
}
bool NetForever::emit_proc(struct target_t*tgt) const
{
tgt->proc_forever(this);
return true;
}
bool NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
bool NetPDelay::emit_proc(struct target_t*tgt) const
{
tgt->proc_delay(o, this);
return tgt->proc_delay(this);
}
bool NetPDelay::emit_proc_recurse(struct target_t*tgt) const
{
if (statement_) return statement_->emit_proc(tgt);
return true;
}
void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
bool NetRelease::emit_proc(struct target_t*tgt) const
{
if (statement_) statement_->emit_proc(o, tgt);
return tgt->proc_release(this);
}
bool NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
bool NetRepeat::emit_proc(struct target_t*tgt) const
{
tgt->proc_event(o, this);
tgt->proc_repeat(this);
return true;
}
void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
bool NetSTask::emit_proc(struct target_t*tgt) const
{
if (statement_) statement_->emit_proc(o, tgt);
}
bool NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_repeat(o, this);
tgt->proc_stask(this);
return true;
}
bool NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
bool NetUTask::emit_proc(struct target_t*tgt) const
{
tgt->proc_stask(o, this);
tgt->proc_utask(this);
return true;
}
bool NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
bool NetWhile::emit_proc(struct target_t*tgt) const
{
tgt->proc_utask(o, this);
tgt->proc_while(this);
return true;
}
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
void NetBlock::emit_recurse(struct target_t*tgt) const
{
if (last_ == 0)
return;
@@ -217,101 +267,138 @@ void NetBlock::emit_recurse(ostream&o, struct target_t*tgt) const
NetProc*cur = last_;
do {
cur = cur->next_;
cur->emit_proc(o, tgt);
cur->emit_proc(tgt);
} while (cur != last_);
}
void NetCondit::emit_recurse_if(ostream&o, struct target_t*tgt) const
void NetCondit::emit_recurse_if(struct target_t*tgt) const
{
if (if_)
if_->emit_proc(o, tgt);
if_->emit_proc(tgt);
}
void NetCondit::emit_recurse_else(ostream&o, struct target_t*tgt) const
void NetCondit::emit_recurse_else(struct target_t*tgt) const
{
if (else_)
else_->emit_proc(o, tgt);
else_->emit_proc(tgt);
}
void NetForever::emit_recurse(ostream&o, struct target_t*tgt) const
bool NetEvProbe::emit_node(struct target_t*tgt) const
{
tgt->net_probe(this);
return true;
}
bool NetEvTrig::emit_proc(struct target_t*tgt) const
{
return tgt->proc_trigger(this);
}
bool NetEvWait::emit_proc(struct target_t*tgt) const
{
return tgt->proc_wait(this);
}
bool NetEvWait::emit_recurse(struct target_t*tgt) const
{
if (!statement_) return true;
return statement_->emit_proc(tgt);
}
void NetForever::emit_recurse(struct target_t*tgt) const
{
if (statement_)
statement_->emit_proc(o, tgt);
statement_->emit_proc(tgt);
}
void NetRepeat::emit_recurse(ostream&o, struct target_t*tgt) const
void NetRepeat::emit_recurse(struct target_t*tgt) const
{
if (statement_)
statement_->emit_proc(o, tgt);
statement_->emit_proc(tgt);
}
void NetWhile::emit_proc_recurse(ostream&o, struct target_t*tgt) const
void NetScope::emit_scope(struct target_t*tgt) const
{
proc_->emit_proc(o, tgt);
}
tgt->scope(this);
bool Design::emit(ostream&o, struct target_t*tgt) const
{
bool rc = true;
tgt->start_design(o, this);
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_)
tgt->event(cur);
// enumerate the scopes
{ map<string,NetScope*>::const_iterator sc;
for (sc = scopes_.begin() ; sc != scopes_.end() ; sc++) {
tgt->scope(o, (*sc).second);
}
}
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_)
cur->emit_scope(tgt);
// emit signals
if (signals_) {
NetNet*cur = signals_->sig_next_;
do {
tgt->signal(o, cur);
tgt->signal(cur);
cur = cur->sig_next_;
} while (cur != signals_->sig_next_);
}
// emit memories
{
map<string,NetMemory*>::const_iterator mi;
for (mi = memories_.begin() ; mi != memories_.end() ; mi++) {
tgt->memory(o, (*mi).second);
}
if (memories_) {
NetMemory*cur = memories_->snext_;
do {
tgt->memory(cur);
cur = cur->snext_;
} while (cur != memories_->snext_);
}
}
void NetScope::emit_defs(struct target_t*tgt) const
{
switch (type_) {
case MODULE:
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_)
cur->emit_defs(tgt);
break;
case FUNC:
tgt->func_def(this->func_def());
break;
case TASK:
tgt->task_def(this->task_def());
break;
}
}
void NetWhile::emit_proc_recurse(struct target_t*tgt) const
{
proc_->emit_proc(tgt);
}
bool Design::emit(struct target_t*tgt) const
{
bool rc = true;
rc = rc && tgt->start_design(this);
if (rc == false)
return false;
// enumerate the scopes
root_scope_->emit_scope(tgt);
// emit nodes
if (nodes_) {
NetNode*cur = nodes_->node_next_;
do {
cur->emit_node(o, tgt);
rc = rc && cur->emit_node(tgt);
cur = cur->node_next_;
} while (cur != nodes_->node_next_);
}
// 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 and function definitions
root_scope_->emit_defs(tgt);
// emit task definitions
{
map<string,NetTaskDef*>::const_iterator ta;
for (ta = tasks_.begin() ; ta != tasks_.end() ; ta ++) {
tgt->task_def(o, (*ta).second);
}
}
// emit the processes
for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_)
rc = rc && idx->emit(o, tgt);
rc = rc && idx->emit(tgt);
tgt->end_design(o, this);
tgt->end_design(this);
return rc;
}
@@ -330,11 +417,6 @@ void NetEConst::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_const(this);
}
void NetEIdent::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_ident(this);
}
void NetEMemory::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_memory(this);
@@ -351,6 +433,11 @@ void NetEScope::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_scope(this);
}
void NetESFunc::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_sfunc(this);
}
void NetEUFunc::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_ufunc(this);
@@ -376,12 +463,12 @@ void NetEUnary::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_unary(this);
}
bool emit(ostream&o, const Design*des, const char*type)
bool emit(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)
return des->emit(o, tgt->meth);
if (strcmp(tgt->name, type) == 0)
return des->emit(tgt->meth);
}
}
@@ -389,135 +476,70 @@ bool emit(ostream&o, const Design*des, const char*type)
/*
* $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.55 2000/11/04 01:54:01 steve
* Modifications in support of gcc 2.96
*
* Revision 1.30 1999/11/27 19:07:57 steve
* Support the creation of scopes.
* Revision 1.54 2000/09/26 01:35:42 steve
* Remove the obsolete NetEIdent class.
*
* Revision 1.29 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
* Revision 1.53 2000/09/17 21:26:15 steve
* Add support for modulus (Eric Aardoom)
*
* Revision 1.28 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
* Revision 1.52 2000/09/02 20:54:20 steve
* Rearrange NetAssign to make NetAssign_ separate.
*
* Revision 1.27 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
* Revision 1.51 2000/08/14 04:39:56 steve
* add th t-dll functions for net_const, net_bufz and processes.
*
* Revision 1.26 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
* Revision 1.50 2000/08/09 03:43:45 steve
* Move all file manipulation out of target class.
*
* 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.
* Revision 1.49 2000/08/08 01:50:42 steve
* target methods need not take a file stream.
*
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
* Revision 1.48 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* 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.47 2000/07/29 16:21:08 steve
* Report code generation errors through proc_delay.
*
* Revision 1.24 1999/10/10 01:59:54 steve
* Structural case equals device.
* Revision 1.46 2000/07/27 05:13:44 steve
* Support elaboration of disable statements.
*
* Revision 1.23 1999/09/22 16:57:23 steve
* Catch parallel blocks in vvm emit.
* Revision 1.45 2000/05/11 23:37:27 steve
* Add support for procedural continuous assignment.
*
* Revision 1.22 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
* Revision 1.44 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.21 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
* Revision 1.43 2000/05/02 03:13:31 steve
* Move memories to the NetScope object.
*
* Revision 1.20 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
* Revision 1.42 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.19 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
* Revision 1.41 2000/04/23 03:45:24 steve
* Add support for the procedural release statement.
*
* Revision 1.18 1999/07/17 19:50:59 steve
* netlist support for ternary operator.
* Revision 1.40 2000/04/22 04:20:19 steve
* Add support for force assignment.
*
* Revision 1.17 1999/07/17 03:39:11 steve
* simplified process scan for targets.
* Revision 1.39 2000/04/12 04:23:58 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Revision 1.16 1999/07/07 04:20:57 steve
* Emit vvm for user defined tasks.
*
* Revision 1.15 1999/07/03 02:12:51 steve
* Elaborate user defined tasks.
*
* Revision 1.14 1999/06/19 21:06:16 steve
* Elaborate and supprort to vvm the forever
* and repeat statements.
*
* Revision 1.13 1999/06/09 03:00:06 steve
* Add support for procedural concatenation expression.
*
* Revision 1.12 1999/06/06 20:45:38 steve
* Add parse and elaboration of non-blocking assignments,
* Replace list<PCase::Item*> with an svector version,
* Add integer support.
*
* Revision 1.11 1999/05/12 04:03:19 steve
* emit NetAssignMem objects in vvm target.
*
* Revision 1.10 1999/05/07 01:21:18 steve
* Handle total lack of nodes and signals.
*
* Revision 1.9 1999/05/01 02:57:53 steve
* Handle much more complex event expressions.
*
* Revision 1.8 1999/04/25 00:44:10 steve
* Core handles subsignal expressions.
*
* Revision 1.7 1999/04/19 01:59:36 steve
* Add memories to the parse and elaboration phases.
*
* Revision 1.6 1999/02/08 02:49:56 steve
* Turn the NetESignal into a NetNode so
* that it can connect to the netlist.
* Implement the case statement.
* Convince t-vvm to output code for
* the case statement.
*
* Revision 1.5 1999/02/01 00:26:49 steve
* Carry some line info to the netlist,
* Dump line numbers for processes.
* Elaborate prints errors about port vector
* width mismatch
* Emit better handles null statements.
*
* Revision 1.4 1998/12/01 00:42:14 steve
* Elaborate UDP devices,
* Support UDP type attributes, and
* pass those attributes to nodes that
* are instantiated by elaboration,
* Put modules into a map instead of
* a simple list.
*
* Revision 1.3 1998/11/09 18:55:34 steve
* Add procedural while loops,
* Parse procedural for loops,
* Add procedural wait statements,
* Add constant nodes,
* Add XNOR logic gate,
* Make vvm output look a bit prettier.
*
* Revision 1.2 1998/11/07 17:05:05 steve
* Handle procedural conditional, and some
* of the conditional expressions.
*
* Elaborate signals and identifiers differently,
* allowing the netlist to hold signal information.
*
* Revision 1.1 1998/11/03 23:28:57 steve
* Introduce verilog to CVS.
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*/
+64 -4
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
@@ -16,8 +16,8 @@
* 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.cc,v 1.12 1999/11/30 04:48:17 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: eval.cc,v 1.17 2001/01/04 04:47:51 steve Exp $"
#endif
# include "PExpr.h"
@@ -81,12 +81,26 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
res = new verinum(lv % rv, l->len());
break;
}
case 'l': {
assert(r->is_defined());
unsigned long rv = r->as_ulong();
res = new verinum(verinum::V0, l->len());
if (rv < res->len()) {
unsigned cnt = res->len() - rv;
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
res->set(idx+rv, l->get(idx));
}
break;
}
default:
delete l;
delete r;
return 0;
}
delete l;
delete r;
return res;
}
@@ -96,7 +110,9 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
*/
verinum* PEIdent::eval_const(const Design*des, const string&path) const
{
const NetExpr*expr = des->find_parameter(path, text_);
const NetScope*scope = des->find_scope(path);
assert(scope);
const NetExpr*expr = des->find_parameter(scope, text_);
if (expr == 0)
return 0;
@@ -114,6 +130,12 @@ verinum* PEIdent::eval_const(const Design*des, const string&path) const
return new verinum(eval->value());
}
verinum* PEFNumber::eval_const(const Design*, const string&) const
{
long val = value_->as_long();
return new verinum(val);
}
verinum* PENumber::eval_const(const Design*, const string&) const
{
return new verinum(value());
@@ -139,9 +161,47 @@ verinum* PETernary::eval_const(const Design*des, const string&path) const
}
}
verinum* PEUnary::eval_const(const Design*des, const string&path) const
{
verinum*val = expr_->eval_const(des, path);
if (val == 0)
return 0;
switch (op_) {
case '+':
return val;
case '-':
*val = v_not(*val) + verinum(verinum::V1, 1);
return val;
}
delete val;
return 0;
}
/*
* $Log: eval.cc,v $
* Revision 1.17 2001/01/04 04:47:51 steve
* Add support for << is signal indices.
*
* Revision 1.16 2000/12/10 22:01:36 steve
* Support decimal constants in behavioral delays.
*
* Revision 1.15 2000/09/07 22:38:13 steve
* Support unary + and - in constants.
*
* Revision 1.14 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.13 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.12 1999/11/30 04:48:17 steve
* Handle evaluation of ternary during elaboration.
*
+618 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,8 +16,8 @@
* 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 $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: eval_tree.cc,v 1.20 2001/01/04 16:49:50 steve Exp $"
#endif
# include "netlist.h"
@@ -72,6 +72,72 @@ NetEConst* NetEBAdd::eval_tree()
return new NetEConst(val);
}
NetEConst* NetEBBits::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();
unsigned lwid = lc->expr_width();
if (lwid == 0) lwid = lval.len();
unsigned rwid = rc->expr_width();
if (rwid == 0) rwid = rval.len();
unsigned wid = expr_width();
if (wid == 0)
wid = (rwid > lwid)? rwid : lwid;
verinum res (verinum::V0, wid);
if (lwid > wid)
lwid = wid;
if (rwid > wid)
rwid = wid;
switch (op()) {
case '|': {
unsigned cnt = lwid;
if (cnt > wid) cnt = wid;
if (cnt > rwid) cnt = rwid;
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
res.set(idx, lval.get(idx) | rval.get(idx));
if (lwid < rwid)
for (unsigned idx = lwid ; idx < rwid ; idx += 1)
res.set(idx, lval.get(idx));
if (rwid < lwid)
for (unsigned idx = rwid ; idx < lwid ; idx += 1)
res.set(idx, rval.get(idx));
break;
}
case '&': {
unsigned cnt = lwid;
if (cnt > wid) cnt = wid;
if (cnt > rwid) cnt = rwid;
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
res.set(idx, lval.get(idx) & rval.get(idx));
break;
}
default:
return 0;
}
return new NetEConst(res);
}
NetEConst* NetEBComp::eval_eqeq_()
{
NetEConst*l = dynamic_cast<NetEConst*>(left_);
@@ -101,6 +167,10 @@ NetEConst* NetEBComp::eval_leeq_()
if (r == 0) return 0;
verinum rv = r->value();
if (! rv.is_defined()) {
verinum result(verinum::Vx, 1);
return new NetEConst(result);
}
/* Detect the case where the right side is greater that or
equal to the largest value the left side can possibly
@@ -112,32 +182,274 @@ NetEConst* NetEBComp::eval_leeq_()
return new NetEConst(result);
}
return 0;
/* Now go on to the normal test of the values. */
NetEConst*l = dynamic_cast<NetEConst*>(left_);
if (l == 0) return 0;
lv = l->value();
if (! lv.is_defined()) {
verinum result(verinum::Vx, 1);
return new NetEConst(result);
}
if (lv.has_sign() && rv.has_sign() && (lv.as_long() <= rv.as_long())) {
verinum result(verinum::V1, 1);
return new NetEConst(result);
}
if (lv.as_ulong() <= rv.as_ulong()) {
verinum result(verinum::V1, 1);
return new NetEConst(result);
}
verinum result(verinum::V0, 1);
return new NetEConst(result);
}
NetEConst* NetEBComp::eval_neeq_()
{
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();
verinum::V res = verinum::V0;
unsigned top = lv.len();
if (rv.len() < top)
top = rv.len();
for (unsigned idx = 0 ; idx < top ; idx += 1) {
switch (lv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
break;
default:
break;
}
switch (rv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
break;
default:
break;
}
if (res == verinum::Vx)
break;
if (rv.get(idx) != lv.get(idx))
res = verinum::V1;
}
if (res != verinum::Vx) {
for (unsigned idx = top ; idx < lv.len() ; idx += 1)
switch (lv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
break;
case verinum::V1:
if (res != verinum::Vx)
res = verinum::V1;
break;
default:
break;
}
for (unsigned idx = top ; idx < rv.len() ; idx += 1)
switch (rv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
break;
case verinum::V1:
if (res != verinum::Vx)
res = verinum::V1;
break;
default:
break;
}
}
return new NetEConst(verinum(res));
}
NetEConst* NetEBComp::eval_eqeqeq_()
{
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();
verinum::V res = verinum::V1;
unsigned cnt = lv.len();
if (cnt > rv.len())
cnt = rv.len();
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
if (lv.get(idx) != rv.get(idx))
res = verinum::V0;
for (unsigned idx = cnt ; idx < lv.len() ; idx += 1)
if (lv.get(idx) != verinum::V0)
res = verinum::V0;
for (unsigned idx = cnt ; idx < rv.len() ; idx += 1)
if (rv.get(idx) != verinum::V0)
res = verinum::V0;
return new NetEConst(verinum(res, 1));
}
NetEConst* NetEBComp::eval_neeqeq_()
{
NetEConst*tmp = eval_eqeqeq_();
if (tmp == 0)
return 0;
NetEConst*res;
if (tmp->value().get(0) == verinum::V0)
res = new NetEConst(verinum(verinum::V1,1));
else
res = new NetEConst(verinum(verinum::V0,1));
delete tmp;
return res;
}
NetEConst* NetEBComp::eval_tree()
{
eval_sub_tree_();
switch (op_) {
case 'e':
case 'E': // Case equality (===)
return eval_eqeqeq_();
case 'e': // Equality (==)
return eval_eqeq_();
case 'L':
case 'L': // <=
return eval_leeq_();
case 'N': // Cse inequality (!==)
return eval_neeqeq_();
case 'n': // not-equal (!=)
return eval_neeq_();
default:
return 0;
}
}
NetEConst* NetEBLogic::eval_tree()
NetEConst* NetEBDiv::eval_tree()
{
eval_sub_tree_();
return 0;
}
NetEConst* NetEBLogic::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::V lv = verinum::V0;
verinum::V rv = verinum::V0;
verinum v = lc->value();
for (unsigned idx = 0 ; idx < v.len() ; idx += 1)
if (v.get(idx) == verinum::V1)
lv = verinum::V1;
if (lv == verinum::V0)
for (unsigned idx = 0 ; idx < v.len() ; idx += 1)
if (v.get(idx) != verinum::V0)
lv = verinum::Vx;
v = rc->value();
for (unsigned idx = 0 ; idx < v.len() ; idx += 1)
if (v.get(idx) == verinum::V1)
rv = verinum::V1;
if (lv == verinum::V0)
for (unsigned idx = 0 ; idx < v.len() ; idx += 1)
if (v.get(idx) != verinum::V0)
rv = verinum::Vx;
verinum::V res;
switch (op_) {
case 'a': { // Logical AND (&&)
if ((lv == verinum::V0) || (rv == verinum::V0))
res = verinum::V0;
else if ((lv == verinum::V1) && (rv == verinum::V1))
res = verinum::V1;
else
res = verinum::Vx;
break;
}
case 'o': { // Logical OR (||)
if ((lv == verinum::V1) || (rv == verinum::V1))
res = verinum::V1;
else if ((lv == verinum::V0) && (rv == verinum::V0))
res = verinum::V0;
else
res = verinum::Vx;
break;
}
default:
return 0;
}
return new NetEConst(verinum(res, 1));
}
NetEConst* NetEBMult::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();
return new NetEConst(lval * rval);
}
/*
* Evaluate the shift operator if possible. For this to work, both
* operands must be constant.
@@ -157,32 +469,57 @@ NetEConst* NetEBShift::eval_tree()
verinum rv = re->value();
verinum lv = le->value();
/* Calculate the width of the result. If it is not fixed, then
get it from the left operand. */
unsigned wid = expr_width();
if (wid == 0)
wid = left_->expr_width();
if (rv.is_defined()) {
unsigned wid = expr_width();
unsigned shift = rv.as_ulong();
assert(wid);
verinum nv (verinum::V0, wid);
if (op() == 'r')
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1)
if (op() == 'r') {
unsigned cnt = wid;
if (cnt > nv.len())
cnt = nv.len();
if (shift >= lv.len())
cnt = 0;
else if (cnt > (lv.len()-shift))
cnt = (lv.len()-shift);
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
nv.set(idx, lv[idx+shift]);
else
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1)
} else {
unsigned cnt = wid;
if (cnt > lv.len())
cnt = lv.len();
if (shift >= nv.len())
cnt = 0;
else if (cnt > (nv.len()-shift))
cnt = nv.len() - shift;
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
nv.set(idx+shift, lv[idx]);
}
res = new NetEConst(nv);
} else {
verinum nv (verinum::Vx, expr_width());
assert(wid);
verinum nv (verinum::Vx, wid);
res = new NetEConst(nv);
}
return res;
}
NetExpr* NetEConcat::eval_tree()
NetEConst* NetEConcat::eval_tree()
{
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
@@ -235,7 +572,8 @@ NetExpr* NetEParam::eval_tree()
if (des_ == 0)
return 0;
const NetExpr*expr = des_->find_parameter(path_, name_);
assert(scope_);
const NetExpr*expr = scope_->get_parameter(name_);
assert(expr);
NetExpr*nexpr = expr->dup_expr();
@@ -256,12 +594,275 @@ NetExpr* NetEParam::eval_tree()
// 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);
scope_->set_parameter(name_, res);
return res->dup_expr();
}
/*
* A ternary expression evaluation is controlled by the condition
* expression. If the condition evaluates to true or false, then
* return the evaluated true or false expression. If the condition
* evaluates to x or z, then merge the constant bits of the true and
* false expressions.
*/
NetExpr* NetETernary::eval_tree()
{
NetExpr*tmp;
/* Evaluate the cond_ to a constant. If it already is a
constant, then there is nothing to do. */
NetEConst*c = dynamic_cast<NetEConst*>(cond_);
if (c == 0) {
tmp = cond_->eval_tree();
c = dynamic_cast<NetEConst*>(tmp);
if (c == 0)
return 0;
assert(cond_ != c);
delete cond_;
cond_ = c;
}
/* If the condition is 1 or 0, return the true or false
expression. Try to evaluate the expression down as far as
we can. */
if (c->value().get(0) == verinum::V1) {
tmp = dynamic_cast<NetEConst*>(true_val_);
if (tmp) return tmp->dup_expr();
tmp = true_val_->eval_tree();
if (tmp) {
delete true_val_;
true_val_ = tmp;
}
return true_val_->dup_expr();
}
if (c->value().get(0) == verinum::V0) {
tmp = dynamic_cast<NetEConst*>(false_val_);
if (tmp) return tmp->dup_expr();
tmp = false_val_->eval_tree();
if (tmp) {
delete false_val_;
false_val_ = tmp;
}
return false_val_->dup_expr();
}
/* Here we have a more complex case. We need to evaluate both
expressions down to constants then compare the values to
build up a constant result. */
NetEConst*t = dynamic_cast<NetEConst*>(true_val_);
if (t == 0) {
tmp = true_val_->eval_tree();
t = dynamic_cast<NetEConst*>(tmp);
if (t == 0)
return 0;
delete true_val_;
true_val_ = t;
}
NetEConst*f = dynamic_cast<NetEConst*>(false_val_);
if (f == 0) {
tmp = false_val_->eval_tree();
f = dynamic_cast<NetEConst*>(tmp);
if (f == 0)
return 0;
delete false_val_;
false_val_ = f;
}
unsigned size = t->expr_width();
assert(size == f->expr_width());
verinum val (verinum::V0, size);
for (unsigned idx = 0 ; idx < size ; idx += 1) {
verinum::V tv = t->value().get(idx);
verinum::V fv = f->value().get(idx);
if (tv == fv)
val.set(idx, tv);
else
val.set(idx, verinum::Vx);
}
NetEConst*rc = new NetEConst(val);
rc->set_line(*this);
return rc;
}
void NetEUnary::eval_expr_()
{
if (dynamic_cast<NetEConst*>(expr_))
return;
NetExpr*oper = expr_->eval_tree();
if (oper == 0)
return;
delete expr_;
expr_ = oper;
}
NetEConst* NetEUnary::eval_tree()
{
eval_expr_();
NetEConst*rval = dynamic_cast<NetEConst*>(expr_);
if (rval == 0)
return 0;
verinum val = rval->value();
switch (op_) {
case '~': {
/* Bitwise not is even simpler then logical
not. Just invert all the bits of the operand and
make the new value with the same dimensions. */
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
switch (val.get(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);
}
return new NetEConst(val);
}
default:
delete rval;
return 0;
}
}
NetEConst* NetEUBits::eval_tree()
{
return NetEUnary::eval_tree();
}
NetEConst* NetEUReduce::eval_tree()
{
eval_expr_();
NetEConst*rval = dynamic_cast<NetEConst*>(expr_);
if (rval == 0)
return 0;
verinum val = rval->value();
verinum::V res;
switch (op_) {
case '!': {
/* Evaluate the unary logical not by first scanning
the operand value for V1 and Vx bits. If we find
any V1 bits we know that the value is TRUE, so
the result of ! is V0. If there are no V1 bits
but there are some Vx/Vz bits, the result is
unknown. Otherwise, the result is V1. */
unsigned v1 = 0, vx = 0;
for (unsigned idx = 0 ; idx < val.len() ; idx += 1) {
switch (val.get(idx)) {
case verinum::V0:
break;
case verinum::V1:
v1 += 1;
break;
default:
vx += 1;
break;
}
}
res = v1? verinum::V0 : (vx? verinum::Vx : verinum::V1);
}
case '&': {
res = verinum::V1;
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
res = res & val.get(idx);
break;
}
case '|': {
res = verinum::V0;
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
res = res | val.get(idx);
break;
}
default:
return 0;
}
return new NetEConst(verinum(res, 1));
}
/*
* $Log: eval_tree.cc,v $
* Revision 1.20 2001/01/04 16:49:50 steve
* Evaluate constant === and !== expressions.
*
* Revision 1.19 2001/01/04 04:28:42 steve
* Evaluate constant logical && and ||.
*
* Revision 1.18 2001/01/02 04:21:14 steve
* Support a bunch of unary operators in parameter expressions.
*
* Revision 1.17 2001/01/02 03:23:40 steve
* Evaluate constant &, | and unary ~.
*
* Revision 1.16 2001/01/01 21:49:33 steve
* Fix shift and ternary operators in parameter expressions (PR#86)
*
* Revision 1.15 2000/12/16 20:00:17 steve
* Handle non-constant l-values.
*
* Revision 1.14 2000/12/16 19:03:30 steve
* Evaluate <= and ?: in parameter expressions (PR#81)
*
* Revision 1.13 2000/09/29 04:42:56 steve
* Cnstant evaluation of NE.
*
* Revision 1.12 2000/09/27 18:28:37 steve
* multiply in parameter expressions.
*
* Revision 1.11 2000/07/07 04:53:54 steve
* Add support for non-constant delays in delay statements,
* Support evaluating ! in constant expressions, and
* move some code from netlist.cc to net_proc.cc.
*
* Revision 1.10 2000/04/28 18:43:23 steve
* integer division in expressions properly get width.
*
* Revision 1.9 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.8 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.7 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.6 1999/10/22 23:57:53 steve
* do the <= in bits, not numbers.
*
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2000 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
*/
/*
* This source file demonstrates how to synthesize CLB flip-flops from
* Icarus Verilog, including giving the device an initial value.
*
* To compile this for XNF, try a command like this:
*
* iverilog -txnf -fpart=XC4010XLPQ160 -fncf=clbff.ncf -oclbff.xnf clbff.v
*
* That command causes an clbff.xnf and clbff.ncf file to be created.
* Next, make the clbff.ngd file with the command:
*
* xnf2ngd -l xilinxun -u clbff.xnf clbff.ngo
* ngdbuild clbff.ngo clbff.ngd
*
* Finally, map the file to fully render it in the target part. The
* par command is the step that actually optimizes the design and tries
* to meet timing constraints.
*
* map -o map.ncd clbff.ngd
* par -w map.ncd clbff.ncd
*
* At this point, you can use the FPGA Editor to edit the clbff.ncd
* file. Notice that the design uses two CLB flip-flops (possibly in
* the same CLB) with their outputs ANDed together. If you go into the
* block editor, you will see that the FF connected to main/Q<0> is
* configured so start up reset, and the FF connected to main/Q<1> is
* configured to start up set.
*/
module main;
wire clk, iclk;
wire i0, i1;
wire out;
wire [1:0] D = {i1, i0};
// This statement declares Q to be a 2 bit reg vector. The
// initial assignment will cause the synthesized device to take
// on an initial value specified here. Without the assignment,
// the initial value is unspecified. (Verilog simulates it as 2'bx.)
reg [1:0] Q = 2'b10;
// This simple logic gate get turned into a function unit.
// The par program will map this into a CLB F or G unit.
and (out, Q[0], Q[1]);
// This creates a global clock buffer. Notice how I attach an
// attribute to the named gate to force it to be mapped to the
// desired XNF device. This device will not be pulled into the
// IOB associated with iclk because of the attribute.
buf gbuf(clk, iclk);
$attribute(gbuf, "XNF-LCA", "GCLK:O,I");
// This is mapped to a DFF. Since Q and D are two bits wide, the
// code generator actually makes two DFF devices that share a
// clock input.
always @(posedge clk) Q <= D;
// These attribute commands assign pins to the listed wires.
// This can be done to wires and registers, as internally both
// are treated as named signals.
$attribute(out, "PAD", "o150");
$attribute(i0, "PAD", "i152");
$attribute(i1, "PAD", "i153");
$attribute(iclk,"PAD", "i154");
endmodule /* main */
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (c) 1998 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
*/
/*
* Here we have the canonical "Hello, World" program written in Verilog.
* We simply print to the program output a simple message. This example
* demonstrates the process of compiling and executing a program with
* Icarus Verilog.
*
* Compile this program with the command:
*
* iverilog -ohello hello.vl
*
* After churning for a little while, the program will create the output
* file "hello" which is compiled, linked and ready to run. Run this
* program like so:
*
* ./hello
*
* and the program will print the message to its output. Easy! For
* more on how to make the iverilog command work, see the iverilog
* manual page.
*/
module main();
initial
begin
$display("Hello, World");
$finish ;
end
endmodule
+76
View File
@@ -0,0 +1,76 @@
/*
* 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
* 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
*/
/*
* IVL should generate an AND gate, and should make an OBUF and two
* IBUF objects, along with the PAD objects.
*
* To compile this for XNF, try a command like this:
*
* iverilog -txnf -fpart=XC4010XLPQ160 -ooutff.xnf -fncf=outff.ncf outff.v
*
* That command causes an outff.xnf and outff.ncf file to be created.
* Next, make the outff.ngd file with the command:
*
* xnf2ngd -l xilinxun -u outff.xnf outff.ngo
* ngdbuild outff.ngo outff.ngd
*
* Finally, map the file to fully render it in the target part. The
* par command is the step that actually optimizes the design and tries
* to meet timing constraints.
*
* map -o map.ncd outff.ngd
* par -w map.ncd outff.ncd
*
* At this point, you can use the FPGA Editor to edit the outff.ncd
* file to see that the AND gate is in a CLB and the IOB for pin 150
* has its flip-flop in use, and that gbuf is a global buffer.
*/
module main;
wire clk, iclk;
wire i0, i1;
wire out;
reg o0;
// This simple logic gate get turned into a function unit.
// The par program will map this into a CLB F or G unit.
and (out, i0, i1);
// This creates a global clock buffer. Notice how I attach an
// attribute to the named gate to force it to be mapped to the
// desired XNF device. This device will not be pulled into the
// IOB associated with iclk because of the attribute.
buf gbuf(clk, iclk);
$attribute(gbuf, "XNF-LCA", "GCLK:O,I");
// This is mapped to a DFF. Since o0 is connected to a PAD, it
// is turned into a OUTFF so that it get placed into an IOB.
always @(posedge clk) o0 = out;
// These attribute commands assign pins to the listed wires.
// This can be done to wires and registers, as internally both
// are treated as named signals.
$attribute(o0, "PAD", "o150");
$attribute(i0, "PAD", "i152");
$attribute(i1, "PAD", "i153");
$attribute(iclk,"PAD", "i154");
endmodule /* main */
+121
View File
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2000 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
*/
/*
* This example shows how to use Icarus Verilog to generate PLD output.
* The design is intended to fit into a 22v10 in a PLCC package, with
* pin assignments locked down by design. The command to compile this
* into a jedec file is;
*
* iverilog -tpal -fpart=generic-22v10-plcc -opal_reg.jed pal_reg.v
*
* The output file name (passed through the -o<file> switch) can be
* any file you desire. If the compilation and fittin all succeed, the
* output file will be a JEDEC file that you can take to your favorite
* PROM programmer to program the part.
*
* This source demonstrates some important principles of synthesizing
* a design for a PLD, including how to specify synchronous logic, and
* how to assign signals to pins. The pin assignment in particular is
* part specific, and must be right for the fitting to succeed.
*/
/*
* The register module is an 8 bit register that copies the input to
* the output registers on the rising edge of the clk input. The
* always statement creates a simple d-type flip-flop that is loaded
* on the rising edge of the clock.
*
* The output drivers are controlled by a single active low output
* enable. I used bufif0 devices in this example, but the exact same
* thing can be achived with a continuous assignment like so:
*
* assign out = oe? 8'hzz : Q;
*
* Many people prefer the expression form. It is true that it does
* seem to express the intent a bit more clearly.
*/
module register (out, val, clk, oe);
output [7:0] out;
input [7:0] val;
input clk, oe;
reg [7:0] Q;
wire [7:0] out;
bufif0 drv[7:0](out, Q, oe);
always @(posedge clk) Q = val;
endmodule
/*
* The module pal is used to attach pin information to all the pins of
* the device. We use this to lock down the pin assignments of the
* synthesized result. The pin number assignments are for a 22v10 in
* a PLCC package.
*
* Note that this module has no logic in it. It is a convention I use
* that I put all the functionality in a seperate module (seen above)
* and isolate the Icarus Verilog specific $attribute madness into a
* top-level module. The advantage of this style is that the entire
* module can be `ifdef'ed out when doing simulation and you don't
* need to worry that functionality will be affected.
*/
module pal;
wire out7, out6, out5, out4, out3, out2, out1, out0;
wire inp7, inp6, inp5, inp4, inp3, inp2, inp1, inp0;
wire clk, oe;
// The PAD attributes attach the wires to pins of the
// device. Output pins are prefixed by a 'o', and input pins by an
// 'i'. If not all the available output pins are used, then the
// remaining are available for the synthesizer to drop internal
// registers or extra logic layers.
$attribute(out7, "PAD", "o27");
$attribute(out6, "PAD", "o26");
$attribute(out5, "PAD", "o25");
$attribute(out4, "PAD", "o24");
$attribute(out3, "PAD", "o23");
$attribute(out2, "PAD", "o21");
$attribute(out1, "PAD", "o20");
$attribute(out0, "PAD", "o19");
$attribute(inp7, "PAD", "i10");
$attribute(inp6, "PAD", "i9");
$attribute(inp5, "PAD", "i7");
$attribute(inp4, "PAD", "i6");
$attribute(inp3, "PAD", "i5");
$attribute(inp2, "PAD", "i4");
$attribute(inp1, "PAD", "i3");
$attribute(inp0, "PAD", "i2");
//$attribute(clk, "PAD", "CLK");
$attribute(oe, "PAD", "i13");
register dev({out7, out6, out5, out4, out3, out2, out1, out0},
{inp7, inp6, inp5, inp4, inp3, inp2, inp1, inp0},
clk, oe);
endmodule // pal
+114
View File
@@ -0,0 +1,114 @@
/*
* 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
*/
/*
* This example program simulates a 16x1 ram, and is used as an
* example for using VCD output and waveform viewers.
*
* Like any other Verilog simulation, compile this program with the
* command:
*
* iverilog show_vcd.vl
*
* This will generate the show_vcd command in the current directory.
* When you run the command, you will see the output from all the
* calls to $display, but also there will be a dump file ``show_vcd.vcd''.
* The name of this file is set by the statement:
*
* $dumpfile("show_vcd.vcd");
*
* in the main module. The output file uses the standard VCD file format
* so can be viewed using off-the-shelf waveform viewers. The remaining
* steps describe how to use GTKWave to view the file. If you are using
* a different viewer, see the documentation for that tool.
*
* To view the output generated by running show_vcd, start the GTKWave
* viewer with the command:
*
* wave show_vcd.vcd
*
* The GTKWave program will display its main window, and show in a small
* status box (upper left corner) that it succeeded in loading the dump
* file. However, there are no waveforms displayed yet. Select signals to
* add to the waveform display using the menu selection:
*
* "Search --> Signal Search Tree"
*
* This will bring up a dialog box that shows in directory tree format
* the signals of the program. Select the signals you wish to view, and
* click one of the buttons on the bottom of the dialog box to display
* the selected signals in the waveform window. Click "Exit" on the box
* to get rid of it.
*
* The magic that makes all this work is contained in the $dumpfile and
* $dumpvars system tasks. The $dumpfile task tells the simulation where
* to write the VCD output. This task must be called once before the
* $dumpvars task is called.
*
* The $dumpvars task tells the simulation what variables to write to
* the VCD output. The first parameter is how far to descend while
* scanning a scope, and the remaining paramters are signals or scope
* names to include in the dump. If a scope name is given, all the
* signals within the scope are dumped. If a wire or register name is
* given, that signal is included.
*/
module ram16x1 (q, d, a, we, wclk);
output q;
input d;
input [3:0] a;
input we;
input wclk;
reg mem[15:0];
assign q = mem[a];
always @(posedge wclk) if (we) mem[a] = d;
endmodule /* ram16x1 */
module main;
wire q;
reg d;
reg [3:0] a;
reg we, wclk;
ram16x1 r1 (q, d, a, we, wclk);
initial begin
$dumpfile("show_vcd.vcd");
$dumpvars(1, main.r1);
wclk = 0;
we = 1;
for (a = 0 ; a < 4'hf ; a = a + 1) begin
d = a[0];
#1 wclk = 1;
#1 wclk = 0;
$display("r1[%x] == %b", a, q);
end
for (a = 0 ; a < 4'hf ; a = a + 1)
#1 if (q !== a[0]) begin
$display("FAILED -- mem[%h] !== %b", a, a[0]);
$finish;
end
$display("PASSED");
end
endmodule /* main */
+140
View File
@@ -0,0 +1,140 @@
/*
* 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
*
* $Id: sqrt.vl,v 1.3 2000/11/04 01:53:24 steve Exp $"
*/
/*
* This example shows that Icarus Verilog can run non-trivial
* programs, too. This uses a variety of Verilog language features
* to implement the module of a square-root device. The program
* uses IEEE1364-1995 language features and should work correctly
* on any Verilog compiler.
*
* Run the file with Icarus Verilog under UNIX using the command:
*
* % iverilog -osqrt sqrt.v
* % ./sqrt
*/
/*
* This module approximates the square root of an unsigned 32bit
* number. The algorithm works by doing a bit-wise binary search.
* Starting from the most significant bit, the accumulated value
* tries to put a 1 in the bit position. If that makes the square
* to big for the input, the bit is left zero, otherwise it is set
* in the result. This continues for each bit, decreasing in
* significance, until all the bits are calculated or all the
* remaining bits are zero.
*
* Since the result is an integer, this function really calculates
* value of the expression:
*
* x = floor(sqrt(y))
*
* where sqrt(y) is the exact square root of y and floor(N) is the
* largest integer <= N.
*
* For 32bit numbers, this will never run more then 16 iterations,
* which amounts to 16 clocks.
*/
module sqrt32(clk, rdy, reset, x, .y(acc));
input clk;
output rdy;
input reset;
input [31:0] x;
output [15:0] acc;
// acc holds the accumulated result, and acc2 is the accumulated
// square of the accumulated result.
reg [15:0] acc;
reg [31:0] acc2;
// Keep track of which bit I'm working on.
reg [4:0] bitl;
wire [15:0] bit = 1 << bitl;
wire [31:0] bit2 = 1 << (bitl << 1);
// The output is ready when the bitl counter underflows.
wire rdy = bitl[4];
// guess holds the potential next values for acc, and guess2 holds
// the square of that guess. The guess2 calculation is a little bit
// subtle. The idea is that:
//
// guess2 = (acc + bit) * (acc + bit)
// = (acc * acc) + 2*acc*bit + bit*bit
// = acc2 + 2*acc*bit + bit2
// = acc2 + 2 * (acc<<bitl) + bit
//
// This works out using shifts because bit and bit2 are known to
// have only a single bit in them.
wire [15:0] guess = acc | bit;
wire [31:0] guess2 = acc2 + bit2 + ((acc << bitl) << 1);
task clear;
begin
acc = 0;
acc2 = 0;
bitl = 15;
end
endtask
initial clear;
always @(reset or posedge clk)
if (reset)
clear;
else begin
if (guess2 <= x) begin
acc <= guess;
acc2 <= guess2;
end
bitl <= bitl - 1;
end
endmodule
module main;
reg clk, reset;
reg [31:0] value;
wire [15:0] result;
wire rdy;
sqrt32 root(.clk(clk), .rdy(rdy), .reset(reset), .x(value), .y(result));
always #5 clk = ~clk;
always @(posedge rdy) begin
$display("sqrt(%d) --> %d", value, result);
$finish;
end
initial begin
clk = 0;
reset = 1;
$monitor($time,,"%m.acc = %b", root.acc);
#100 value = 63;
reset = 0;
end
endmodule /* main */
+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
*/
/*
* This example demonstrates Icarus Verilog's ability to synthesize
* efficient adders for Xilinx 4000 series FPGAs. The synthesis and
* code generation makes an adder and translates that into XOR gates
* and fast carry chain hardware.
*
* To compile this for XNF, try a command like this:
*
* iverilog -txnf -fpart=XC4010XLPQ160 -fncf=xnf_add.ncf -oxnf_add.xnf xnf_add.v
*
* That command causes an xnf_add.xnf and xnf_add.ncf file to be created.
* Next, Use Xilinx Alliance or Foundation tools to make the xnf_add.ngd
* file with the command:
*
* xnf2ngd -l xilinxun -u xnf_add.xnf xnf_add.ngo
* ngdbuild xnf_add.ngo xnf_add.ngd
*
* Finally, map the file to fully render it in the target part. The
* par command is the step that actually optimizes the design and tries
* to meet timing constraints.
*
* map -o map.ncd xnf_add.ngd
* par -w map.ncd xnf_add.ncd
*
* At this point, you can use the Xilinx FPGA Editor to edit the xnf_add.ncd
* file and see the carry chains made up to support the adder.
*/
module main;
wire [3:0] a, b;
wire [3:0] out;
wire carry;
wire a0, a1, a2, a3, b0, b1, b2, b3;
wire out0, out1, out2, out3;
// This creates the actual adder. Note that we also create a link
// to the carry output. The principle adder is 4 bits wide, so two
// IOBs are used to to the actual addition. PAR will place them in
// order along carry lines. An extra carry cell from below a[0] is
// used in FORCE-0 mode to load the bottom carry node.
//
// The carry signal from the top CY device is used to drive the
// main.carry wire shown here. It is managed in this case by using
// an ADD-FG-CI CY device for the top pair and using the CLB above
// the carry chain, with its CY in EXAMINE-CI mode, to put the carry
// out through its G function unit.
assign {carry, out} = a + b;
// These attribute commands assign pins to the listed wires.
// This can be done to wires and registers, as internally both
// are treated as named signals. It doesn't work (yet) on vectors,
// though, so break out the vectors with scaler assignments.
assign a[0] = a0;
assign a[1] = a1;
assign a[2] = a2;
assign a[3] = a3;
$attribute(a0, "PAD", "i150");
$attribute(a1, "PAD", "i152");
$attribute(a2, "PAD", "i153");
$attribute(a3, "PAD", "i154");
assign b[0] = b0;
assign b[1] = b1;
assign b[2] = b2;
assign b[3] = b3;
$attribute(b0, "PAD", "i155");
$attribute(b1, "PAD", "i156");
$attribute(b2, "PAD", "i157");
$attribute(b3, "PAD", "i158");
assign out0 = out[0];
assign out1 = out[1];
assign out2 = out[2];
assign out3 = out[3];
$attribute(out0, "PAD", "o71");
$attribute(out1, "PAD", "o72");
$attribute(out2, "PAD", "o73");
$attribute(out3, "PAD", "o74");
$attribute(carry, "PAD", "o75");
endmodule /* main */
+310 -27
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,8 +16,8 @@
* 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 $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: expr_synth.cc,v 1.18 2000/11/29 23:16:18 steve Exp $"
#endif
# include "netlist.h"
@@ -45,7 +45,7 @@ NetNet* NetEBAdd::synthesize(Design*des)
assert(lsig->pin_count() == rsig->pin_count());
unsigned width=lsig->pin_count();
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT, width);
string oname = des->local_symbol(path);
NetAddSub *adder = new NetAddSub(oname, width);
@@ -55,7 +55,6 @@ NetNet* NetEBAdd::synthesize(Design*des)
connect(osig->pin(idx), adder->pin_Result(idx));
}
des->add_node(adder);
des->add_signal(osig);
switch (op()) {
case '+':
@@ -77,12 +76,17 @@ NetNet* NetEBAdd::synthesize(Design*des)
*/
NetNet* NetEBBits::synthesize(Design*des)
{
string path = des->local_symbol("SYNTH");
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
NetScope*scope = lsig->scope();
assert(scope);
string path = des->local_symbol(scope->name());
assert(lsig->pin_count() == rsig->pin_count());
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, lsig->pin_count());
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT,
lsig->pin_count());
osig->local_flag(true);
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
string oname = des->local_symbol(path);
@@ -90,19 +94,19 @@ NetNet* NetEBBits::synthesize(Design*des)
switch (op()) {
case '&':
gate = new NetLogic(oname, 3, NetLogic::AND);
gate = new NetLogic(scope, oname, 3, NetLogic::AND);
break;
case '|':
gate = new NetLogic(oname, 3, NetLogic::OR);
gate = new NetLogic(scope, oname, 3, NetLogic::OR);
break;
case '^':
gate = new NetLogic(oname, 3, NetLogic::XOR);
gate = new NetLogic(scope, oname, 3, NetLogic::XOR);
break;
case 'O':
gate = new NetLogic(oname, 3, NetLogic::NOR);
gate = new NetLogic(scope, oname, 3, NetLogic::NOR);
break;
case 'X':
gate = new NetLogic(oname, 3, NetLogic::XNOR);
gate = new NetLogic(scope, oname, 3, NetLogic::XNOR);
break;
default:
assert(0);
@@ -115,23 +119,217 @@ NetNet* NetEBBits::synthesize(Design*des)
des->add_node(gate);
}
des->add_signal(osig);
return osig;
}
NetNet* NetEBComp::synthesize(Design*des)
{
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
NetScope*scope = lsig->scope();
assert(scope);
string path = des->local_symbol(scope->name());
unsigned width = lsig->pin_count();
if (rsig->pin_count() > lsig->pin_count())
width = rsig->pin_count();
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, 1);
osig->local_flag(true);
/* Handle the special case of a single bit equality
operation. Make an XNOR gate instead of a comparator. */
if ((width == 1) && ((op_ == 'e') || (op_ == 'E'))) {
NetLogic*gate = new NetLogic(scope, des->local_symbol(path),
3, NetLogic::XNOR);
connect(gate->pin(0), osig->pin(0));
connect(gate->pin(1), lsig->pin(0));
connect(gate->pin(2), rsig->pin(0));
des->add_node(gate);
return osig;
}
/* Handle the special case of a single bit inequality
operation. This is similar to single bit equality, but uses
an XOR instead of an XNOR gate. */
if ((width == 1) && ((op_ == 'n') || (op_ == 'N'))) {
NetLogic*gate = new NetLogic(scope, des->local_symbol(path),
3, NetLogic::XOR);
connect(gate->pin(0), osig->pin(0));
connect(gate->pin(1), lsig->pin(0));
connect(gate->pin(2), rsig->pin(0));
des->add_node(gate);
return osig;
}
NetCompare*dev = new NetCompare(des->local_symbol(path), width);
des->add_node(dev);
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
connect(dev->pin_DataA(idx), lsig->pin(idx));
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
connect(dev->pin_DataB(idx), rsig->pin(idx));
switch (op_) {
case '<':
connect(dev->pin_ALB(), osig->pin(0));
break;
case '>':
connect(dev->pin_AGB(), osig->pin(0));
break;
case 'e': // ==
case 'E': // === ?
connect(dev->pin_AEB(), osig->pin(0));
break;
case 'G': // >=
connect(dev->pin_AGEB(), osig->pin(0));
break;
case 'L': // <=
connect(dev->pin_ALEB(), osig->pin(0));
break;
case 'n': // !=
case 'N': // !==
connect(dev->pin_ANEB(), osig->pin(0));
break;
default:
cerr << get_line() << ": internal error: cannot synthesize "
"comparison: " << *this << endl;
des->errors += 1;
return 0;
}
return osig;
}
NetNet* NetEBDiv::synthesize(Design*des)
{
cerr << get_line() << ": internal error: cannot synthesize division: "
<< *this << endl;
des->errors += 1;
return 0;
}
NetNet* NetEBLogic::synthesize(Design*des)
{
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
if (lsig == 0)
return 0;
if (rsig == 0)
return 0;
NetScope*scope = lsig->scope();
assert(scope);
string path = des->local_symbol(scope->name());
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, 1);
osig->local_flag(true);
if (op() == 'o') {
/* Logic OR can handle the reduction *and* the logical
comparison with a single wide OR gate. So handle this
magically. */
string oname = des->local_symbol(path);
NetLogic*olog;
olog = new NetLogic(scope, oname,
lsig->pin_count()+rsig->pin_count()+1,
NetLogic::OR);
connect(osig->pin(0), olog->pin(0));
unsigned pin = 1;
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx = 1)
connect(olog->pin(pin+idx), lsig->pin(idx));
pin += lsig->pin_count();
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx = 1)
connect(olog->pin(pin+idx), rsig->pin(idx));
des->add_node(olog);
} else {
assert(op() == 'a');
/* Create the logic AND gate. This is a single bit
output, with inputs for each of the operands. */
NetLogic*olog;
string oname = des->local_symbol(path);
olog = new NetLogic(scope, oname, 3, NetLogic::AND);
connect(osig->pin(0), olog->pin(0));
des->add_node(olog);
/* XXXX Here, I need to reduce the parameters with
reduction or. */
/* By this point, the left and right parameters have been
reduced to single bit values. Now we just connect them to
the logic gate. */
assert(lsig->pin_count() == 1);
connect(lsig->pin(0), olog->pin(1));
assert(rsig->pin_count() == 1);
connect(lsig->pin(0), olog->pin(2));
}
return osig;
}
NetNet* NetEConcat::synthesize(Design*des)
{
NetScope*scope = des->find_root_scope();
assert(scope);
assert(repeat_ == 1);
string path = des->local_symbol("SYNTH");
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, expr_width());
osig->local_flag(true);
unsigned obit = 0;
for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) {
NetNet*tmp = parms_[idx-1]->synthesize(des);
for (unsigned bit = 0 ; bit < tmp->pin_count() ; bit += 1) {
connect(osig->pin(obit), tmp->pin(bit));
obit += 1;
}
if (tmp->local_flag() && tmp->get_eref() == 0)
delete tmp;
}
return osig;
}
NetNet* NetEConst::synthesize(Design*des)
{
NetScope*scope = des->find_root_scope();
assert(scope);
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);
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, width);
osig->local_flag(true);
NetConst*con = new NetConst(des->local_symbol(path), value());
for (unsigned idx = 0 ; idx < width; idx += 1)
connect(osig->pin(idx), con->pin(idx));
des->add_node(con);
return osig;
}
@@ -141,10 +339,15 @@ NetNet* NetEConst::synthesize(Design*des)
*/
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());
NetScope*scope = isig->scope();
assert(scope);
string path = des->local_symbol(scope->name());
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT,
isig->pin_count());
osig->local_flag(true);
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
string oname = des->local_symbol(path);
@@ -152,7 +355,7 @@ NetNet* NetEUBits::synthesize(Design*des)
switch (op()) {
case '~':
gate = new NetLogic(oname, 2, NetLogic::NOT);
gate = new NetLogic(scope, oname, 2, NetLogic::NOT);
break;
default:
assert(0);
@@ -163,7 +366,47 @@ NetNet* NetEUBits::synthesize(Design*des)
des->add_node(gate);
}
des->add_signal(osig);
return osig;
}
NetNet* NetEUReduce::synthesize(Design*des)
{
NetNet*isig = expr_->synthesize(des);
NetScope*scope = isig->scope();
assert(scope);
string path = des->local_symbol(scope->name());
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, 1);
osig->local_flag(true);
string oname = des->local_symbol(path);
NetLogic*gate;
switch (op()) {
case 'N':
case '!':
gate = new NetLogic(scope, oname, isig->pin_count()+1,
NetLogic::NOR);
break;
case '&':
gate = new NetLogic(scope, oname, isig->pin_count()+1,
NetLogic::AND);
break;
default:
cerr << get_line() << ": internal error: "
<< "Unable to synthesize " << *this << "." << endl;
return 0;
}
des->add_node(gate);
connect(gate->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < isig->pin_count() ; idx += 1)
connect(gate->pin(1+idx), isig->pin(idx));
return osig;
}
@@ -178,7 +421,8 @@ NetNet* NetETernary::synthesize(Design *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);
NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width);
osig->local_flag(true);
string oname = des->local_symbol(path);
NetMux *mux = new NetMux(oname, width, 2, 1);
@@ -189,7 +433,7 @@ NetNet* NetETernary::synthesize(Design *des)
}
des->add_node(mux);
connect(csig->pin(0), mux->pin_Sel(0));
des->add_signal(osig);
return osig;
}
@@ -200,6 +444,45 @@ NetNet* NetESignal::synthesize(Design*des)
/*
* $Log: expr_synth.cc,v $
* Revision 1.18 2000/11/29 23:16:18 steve
* Do not delete synthesized signals used in expressions.
*
* Revision 1.17 2000/11/29 05:24:00 steve
* synthesis for unary reduction ! and N operators.
*
* Revision 1.16 2000/11/29 02:09:52 steve
* Add support for || synthesis (PR#53)
*
* Revision 1.15 2000/10/07 19:45:43 steve
* Put logic devices into scopes.
*
* Revision 1.14 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.13 2000/04/28 18:43:23 steve
* integer division in expressions properly get width.
*
* Revision 1.12 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
* Revision 1.11 2000/04/16 23:32:18 steve
* Synthesis of comparator in expressions.
*
* Connect the NetEvent and related classes
* together better.
*
* Revision 1.10 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.9 2000/01/01 06:18:00 steve
* Handle synthesis of concatenation.
*
* Revision 1.8 1999/12/17 06:18:15 steve
* Rewrite the cprop functor to use the functor_t interface.
*
* Revision 1.7 1999/12/17 03:38:46 steve
* NetConst can now hold wide constants.
*
* 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.
+239 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,8 +16,8 @@
* 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: functor.cc,v 1.5 1999/12/01 06:06:16 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: functor.cc,v 1.24 2000/11/19 20:48:30 steve Exp $"
#endif
# include "functor.h"
@@ -27,6 +27,10 @@ functor_t::~functor_t()
{
}
void functor_t::event(class Design*, class NetEvent*)
{
}
void functor_t::signal(class Design*, class NetNet*)
{
}
@@ -35,21 +39,78 @@ void functor_t::process(class Design*, class NetProcTop*)
{
}
void functor_t::lpm_add_sub(class Design*, class NetAddSub*)
{
}
void functor_t::lpm_compare(class Design*, class NetCompare*)
{
}
void functor_t::lpm_const(class Design*, class NetConst*)
{
}
void functor_t::lpm_divide(class Design*, class NetDivide*)
{
}
void functor_t::lpm_modulo(class Design*, class NetModulo*)
{
}
void functor_t::lpm_ff(class Design*, class NetFF*)
{
}
void Design::functor(functor_t*fun)
void functor_t::lpm_logic(class Design*, class NetLogic*)
{
// apply to signals
}
void functor_t::lpm_mult(class Design*, class NetMult*)
{
}
void functor_t::lpm_mux(class Design*, class NetMux*)
{
}
void NetScope::run_functor(Design*des, functor_t*fun)
{
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_) {
cur->run_functor(des, fun);
}
for (NetEvent*cur = events_ ; cur ; /* */) {
NetEvent*tmp = cur;
cur = cur->snext_;
fun->event(des, tmp);
}
// apply to signals. Each iteration, allow for the possibility
// that the current signal deletes itself.
if (signals_) {
unsigned count = 0;
NetNet*cur = signals_->sig_next_;
do {
NetNet*tmp = cur->sig_next_;
fun->signal(this, cur);
cur = tmp;
count += 1;
cur = cur->sig_next_;
} while (cur != signals_->sig_next_);
cur = signals_->sig_next_;
for (unsigned idx = 0 ; idx < count ; idx += 1) {
NetNet*tmp = cur->sig_next_;
fun->signal(des, cur);
cur = tmp;
}
}
}
void Design::functor(functor_t*fun)
{
// Scan the scopes
root_scope_->run_functor(this, fun);
// apply to processes
procs_idx_ = procs_;
@@ -61,12 +122,30 @@ void Design::functor(functor_t*fun)
// apply to nodes
if (nodes_) {
/* Scan the circular list of nodes, starting with the
front of the list. (nodes_ points to the *end* of the
list.) The bar is the end point. At the end of the
do-while loop, I know that the bar has been
processed or (if bar == 0) no undeleted node has been
processed. */
NetNode*cur = nodes_->node_next_;
NetNode*bar = 0;
do {
NetNode*tmp = cur->node_next_;
cur->functor_node(this, fun);
/* Detect the case that cur has been deleted by
noticing if tmp->node_prev_ no longer points to
cur. If that's the case, clear the bar. */
if (tmp->node_prev_ != cur) {
if (cur == bar)
bar = 0;
} else if (bar == 0) {
bar = cur;
}
cur = tmp;
} while (cur != nodes_->node_next_);
} while (nodes_ && (cur != bar));
}
}
@@ -75,11 +154,51 @@ void NetNode::functor_node(Design*, functor_t*)
{
}
void NetAddSub::functor_node(Design*des, functor_t*fun)
{
fun->lpm_add_sub(des, this);
}
void NetCompare::functor_node(Design*des, functor_t*fun)
{
fun->lpm_compare(des, this);
}
void NetConst::functor_node(Design*des, functor_t*fun)
{
fun->lpm_const(des, this);
}
void NetDivide::functor_node(Design*des, functor_t*fun)
{
fun->lpm_divide(des, this);
}
void NetFF::functor_node(Design*des, functor_t*fun)
{
fun->lpm_ff(des, this);
}
void NetLogic::functor_node(Design*des, functor_t*fun)
{
fun->lpm_logic(des, this);
}
void NetModulo::functor_node(Design*des, functor_t*fun)
{
fun->lpm_modulo(des, this);
}
void NetMult::functor_node(Design*des, functor_t*fun)
{
fun->lpm_mult(des, this);
}
void NetMux::functor_node(Design*des, functor_t*fun)
{
fun->lpm_mux(des, this);
}
proc_match_t::~proc_match_t()
{
}
@@ -99,6 +218,48 @@ int NetAssign::match_proc(proc_match_t*that)
return that->assign(this);
}
int proc_match_t::assign_nb(NetAssignNB*)
{
return 0;
}
int NetAssignNB::match_proc(proc_match_t*that)
{
return that->assign_nb(this);
}
int proc_match_t::assign_mem(NetAssignMem*)
{
return 0;
}
int NetAssignMem::match_proc(proc_match_t*that)
{
return that->assign_mem(this);
}
int proc_match_t::assign_mem_nb(NetAssignMemNB*)
{
return 0;
}
int NetAssignMemNB::match_proc(proc_match_t*that)
{
return that->assign_mem_nb(this);
}
int proc_match_t::block(NetBlock*)
{
cerr << "default (failing) match for block" << endl;
return 0;
}
int NetBlock::match_proc(proc_match_t*that)
{
cerr << "NetBlock::match_proc" << endl;
return that->block(this);
}
int proc_match_t::condit(NetCondit*)
{
return 0;
@@ -109,18 +270,81 @@ int NetCondit::match_proc(proc_match_t*that)
return that->condit(this);
}
int proc_match_t::pevent(NetPEvent*)
int NetEvWait::match_proc(proc_match_t*that)
{
return that->event_wait(this);
}
int proc_match_t::event_wait(NetEvWait*)
{
return 0;
}
int NetPEvent::match_proc(proc_match_t*that)
{
return that->pevent(this);
}
/*
* $Log: functor.cc,v $
* Revision 1.24 2000/11/19 20:48:30 steve
* Fix cases where signal iteration might die early.
*
* Revision 1.23 2000/11/18 04:53:04 steve
* Watch out in functor, it may delete the last signal.
*
* Revision 1.22 2000/09/17 21:26:15 steve
* Add support for modulus (Eric Aardoom)
*
* Revision 1.21 2000/08/01 02:48:41 steve
* Support <= in synthesis of DFF and ram devices.
*
* Revision 1.20 2000/07/16 04:56:07 steve
* Handle some edge cases during node scans.
*
* Revision 1.19 2000/07/15 05:13:43 steve
* Detect muxing Vz as a bufufN.
*
* Revision 1.18 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.17 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
* Revision 1.16 2000/04/18 04:50:19 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.15 2000/04/16 23:32:18 steve
* Synthesis of comparator in expressions.
*
* Connect the NetEvent and related classes
* together better.
*
* Revision 1.14 2000/04/12 20:02:53 steve
* Finally remove the NetNEvent and NetPEvent classes,
* Get synthesis working with the NetEvWait class,
* and get started supporting multiple events in a
* wait in vvm.
*
* Revision 1.13 2000/04/01 21:40:22 steve
* Add support for integer division.
*
* Revision 1.12 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.11 2000/02/13 04:35:43 steve
* Include some block matching from Larry.
*
* Revision 1.10 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.9 2000/01/02 17:57:20 steve
* Handle nodes running out during node scan.
*
* Revision 1.8 1999/12/30 04:19:12 steve
* Propogate constant 0 in low bits of adders.
*
* Revision 1.7 1999/12/17 06:18:16 steve
* Rewrite the cprop functor to use the functor_t interface.
*
* Revision 1.6 1999/12/05 02:24:08 steve
* Synthesize LPM_RAM_DQ for writes into memories.
*
* Revision 1.5 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
+81 -14
View File
@@ -1,7 +1,7 @@
#ifndef __functor_H
#define __functor_H
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,14 +18,21 @@
* 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: functor.h,v 1.3 1999/12/01 06:06:16 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: functor.h,v 1.17 2000/09/17 21:26:15 steve Exp $"
#endif
/*
* The functor is an object that can be applied to a design to
* transform it. This is different from the target_t, which can only
* scan the design but not transform it in any way.
*
* When a functor it scanning a process, signal or node, the functor
* is free to manipulate the list by deleting items, including the
* node being scanned. The Design class scanner knows how to handle
* the situation. However, if objects are added to the netlist, there
* is no guarantee that object will be scanned unless the functor is
* rerun.
*/
class Design;
@@ -35,38 +42,98 @@ class NetProcTop;
struct functor_t {
virtual ~functor_t();
/* Signals are scanned first. This is called once for each
signal in the design. */
/* Events are scanned here. */
virtual void event(class Design*des, class NetEvent*);
/* This is called once for each signal in the design. */
virtual void signal(class Design*des, class NetNet*);
/* This method is called for each process in the design. */
virtual void process(class Design*des, class NetProcTop*);
/* This method is called for each structural adder. */
virtual void lpm_add_sub(class Design*des, class NetAddSub*);
/* This method is called for each structural comparator. */
virtual void lpm_compare(class Design*des, class NetCompare*);
/* This method is called for each structural constant. */
virtual void lpm_const(class Design*des, class NetConst*);
/* This method is called for each structural constant. */
virtual void lpm_divide(class Design*des, class NetDivide*);
/* This method is called for each structural constant. */
virtual void lpm_modulo(class Design*des, class NetModulo*);
/* This method is called for each FF in the design. */
virtual void lpm_ff(class Design*des, class NetFF*);
/* Handle LPM combinational logic devices. */
virtual void lpm_logic(class Design*des, class NetLogic*);
/* This method is called for each multiplier. */
virtual void lpm_mult(class Design*des, class NetMult*);
/* This method is called for each MUX. */
virtual void lpm_mux(class Design*des, class NetMux*);
};
struct proc_match_t {
virtual ~proc_match_t();
virtual int assign(class NetAssign*);
virtual int assign_mem(class NetAssignMem*);
virtual int assign_nb(class NetAssignNB*);
virtual int assign_mem_nb(class NetAssignMemNB*);
virtual int condit(class NetCondit*);
virtual int pevent(class NetPEvent*);
virtual int event_wait(class NetEvWait*);
virtual int block(class NetBlock*);
};
/*
* $Log: functor.h,v $
* Revision 1.3 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
* Revision 1.17 2000/09/17 21:26:15 steve
* Add support for modulus (Eric Aardoom)
*
* 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.16 2000/08/01 02:48:42 steve
* Support <= in synthesis of DFF and ram devices.
*
* Revision 1.1 1999/07/17 22:01:13 steve
* Add the functor interface for functor transforms.
* Revision 1.15 2000/07/16 04:56:07 steve
* Handle some edge cases during node scans.
*
* Revision 1.14 2000/07/15 05:13:44 steve
* Detect muxing Vz as a bufufN.
*
* Revision 1.13 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
* Revision 1.12 2000/04/18 04:50:19 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.11 2000/04/12 20:02:53 steve
* Finally remove the NetNEvent and NetPEvent classes,
* Get synthesis working with the NetEvWait class,
* and get started supporting multiple events in a
* wait in vvm.
*
* Revision 1.10 2000/04/01 21:40:22 steve
* Add support for integer division.
*
* Revision 1.9 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.8 2000/02/13 04:35:43 steve
* Include some block matching from Larry.
*
* Revision 1.7 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.6 1999/12/30 04:19:12 steve
* Propogate constant 0 in low bits of adders.
*
* Revision 1.5 1999/12/17 06:18:16 steve
* Rewrite the cprop functor to use the functor_t interface.
*/
#endif
+217
View File
@@ -0,0 +1,217 @@
Icarus Verilog vs. IEEE1364
Copyright 2000 Stephen Williams
The IEEE1364 standard is the bible that defines the correctness of the
Icarus Verilog implementation and behavior of the compiled
program. The IEEE1364.1 is also referenced for matters of
synthesis. So the ultimate definition of right and wrong comes from
those documents.
That does not mean that a Verilog implementation is fully
constrained. The standard document allows for implementation specific
behavior that, when properly accounted for, does not effect the
intended semantics of the specified language. It is therefore possible
and common to write programs that produce different results when run
by different Verilog implementations.
STANDARDIZATION ISSUES
These are some issues where the IEEE1364 left unclear, unspecified or
simply wrong. I'll try to be precise as I can, and reference the
standard as needed. I've made implementation decisions for Icarus
Verilog, and I will make clear what those decisions are and how they
affect the language.
* OBJECTS CAN BE DECLARED ANYWHERE IN THE MODULE
Consider this module:
module sample1;
initial foo = 1;
reg foo;
wire tmp = bar;
initial #1 $display("foo = %b, bar = %b", foo, tmp);
endmodule
Notice that the ``reg foo;'' declaration is placed after the first
initial statement. It turns out that this is a perfectly legal module
according to the -1995 and -2000 versions of the standard. The
statement ``reg foo;'' is a module_item_declaration which is in turn a
module_item. The BNF in the appendix of IEEE1364-1995 treats all
module_item statements equally, so no order is imposed.
Furthermore, there is no text (that I can find) elsewhere in the
standard that imposes any ordering restriction. The sorts of
restrictions I would look for are "module_item_declarations must
appear before all other module_items" or "variables must be declared
textually before they are referenced." Such statements simply do not
exist. (Personally, I think it is fine that they don't.)
The closest is the rules for implicit declarations of variables that
are otherwise undeclared. In the above example, ``bar'' is implicitly
declared and is therefore a wire. However, although ``initial foo = 1;''
is written before foo is declared, foo *is* declared within the
module, and declared legally by the BNF of the standard.
Here is another example:
module sample2;
initial x.foo = 1;
test x;
initial #1 $display("foo = %b", x.foo);
endmodule
module test;
reg foo;
endmodule;
From this example one can clearly see that foo is once again declared
after its use in behavioral code. One also sees a forward reference of
an entire module. Once again, the standard places no restriction on
the order of module declarations in a source file, so this program is,
according to the standard, perfectly well formed.
Icarus Verilog interprets both of these examples according to "The
Standard As I Understand It." However, commercial tools in general
break down with these programs. In particular, the first example
may generate different errors depending on the tool. The most common
error is to claim that ``foo'' is declared twice, once (implicitly) as
a wire and once as a reg.
So the question now becomes, "Is the standard broken, or are the tools
limited?" Coverage of the standard seems to vary widely from tool to
tool so it is not clear that the standard really is at fault. It is
clear, however, that somebody goofed somewhere.
My personal opinion is that there is no logical need to require that
all module_item_declarations preceed any other module items. I
personally would oppose such a restriction. It may make sense to
require that declarations of variables within a module be preceded by
their use, although even that is not necessary for the implementation
of efficient compilers.
However, the existence hierarchical naming syntax as demonstrated in
sample2 can have implications that affect any declaration order
rules. When reaching into a module with a hierarchical name, the
module being referenced is already completely declared (or not
declared at all, as in sample2) so module_item order is completely
irrelevent. But a "declare before use" rule would infect module
ordering, by requiring that modules that are used be first defined.
* TASK AND FUNCTION PARAMETERS CANNOT HAVE EXPLICIT TYPES
Consider a function negate that wants to take a signed integer value
and return its negative:
function integer negate;
input [15:0] val;
negate = -val;
endfunction
This is not quite right, because the input is implicitly a reg type,
which is unsigned. The result, then, will always be a negative value,
even if a negative val is passed in.
It is possible to fix up this specific example to work properly with
the bit pattern of a 16bit number, but that is not the point. What's
needed is clarification on whether an input can be declared in the
port declaration as well as in the contained block declaration.
As I understand the situation, this should be allowed:
function integer negate;
input [15:0] val;
reg signed [15:0] val;
negate = -val;
endfunction
In the -1995 standard, the variable is already implicitly a reg if
declared within a function or task. However, in the -2000 standard
there is now (as in this example) a reason why one might want to
actually declare the type explicitly.
I think that a port *cannot* be declared as an integer or time type
(though the result can) because the range of the port declaration must
match the range of the integer/time declaration, but the range of
integers is unspecified. This, by the way, also applies to module
ports.
* ROUNDING OF TIME
When the `timescale directive is present, the compiler is supposed to
round fractional times (after scaling) to the nearest integer. The
confusing bit here is that it is apparently conventional that if the
`timescale directive is *not* present, times are rounded towards zero
always.
* VALUE OF X IN PRIMITIVE OUTPUTS
The IEEE1364-1995 standard clearly states in Table 8-1 that the x
symbols is allowed in input columns, but is not allowed in
outputs. Furthermore, none of the examples have an x in the output of
a primitive. Table 8-1 in the IEEE1364-2000 also says the same thing.
However, the BNF clearly states that 0, 1, x and X are valid
output_symbol characters. The standard is self contradictory. So I
take it that x is allowed, as that is what Verilog-XL does.
* REPEAT LOOPS vs. REPEAT EVENT CONTROL
There seems to be ambiguity in how code like this should be parsed:
repeat (5) @(posedge clk) <statment>;
There are two valid interpretations of this code, from the
IEEE1364-1995 standard. One looks like this:
procedural_timing_control_statement ::=
delay_or_event_control statement_or_null
delay_or_event_control ::=
event_control
| repeat ( expression ) event_control
If this interpretation is used, then the statement <statement> should
be executed after the 5th posedge of clk. However, there is also this
interpretation:
loop_statement ::=
repeat ( expression ) statement
If *this* interpretation is used, then <statement> should be executed
5 times on the posedge of clk. The way the -1995 standard is written,
these are both equally valid interpretations of the example, yet they
produce very different results. The standard offers no guidance on how
to resolve this conflict, and the IEEE1364-2000 DRAFT does not improve
the situation.
Practice suggests that a repeat followed by an event control should be
interpreted as a loop head, and this is what Icarus Verilog does, as
well as all the other major Verilog tools, but the standard does not
say this.
$Id: ieee1364-notes.txt,v 1.5 2001/01/02 17:28:08 steve Exp $
$Log: ieee1364-notes.txt,v $
Revision 1.5 2001/01/02 17:28:08 steve
Resolve repeat ambiguity in favor of loop.
Revision 1.4 2001/01/01 19:12:35 steve
repeat loops ambiguity.
Revision 1.3 2000/12/15 00:21:46 steve
rounding of time and x in primitives.
Revision 1.2 2000/11/19 22:03:04 steve
Integer parameter comments.
Revision 1.1 2000/07/23 18:06:31 steve
Document ieee1364 issues.
+84
View File
@@ -0,0 +1,84 @@
# The iverilog.conf configuration file provides to the iverilog driver
# strings based on switches that are passed by the user on the command
# line.
#
# Comments start from the hash (#) character and run to the end of the
# line.
#
# Conditions are a list of requirements between [] characters. For the
# set of patterns following a string to b activated, all the
# conditions must be true. Valid conditions are:
#
# -S -- The -S flag is passed to iverilog
# -t<string> -- The -t<string> parameters is passed to iverilog
#
#
# Patterns have a name and text. The name has the form <key> where the
# key is some key value that is required by iverilog. The commonly
# used keys are:
#
# <ivl>
# The string here is the command line needed to take the
# preprocessor output (ivlpp) and compile it with the
# target. All target types use this key.
#
# The pattern text includes %<code> substitutions. iverilog
# substitutes values for the %<code> sequences within the text.
#
# %B Substitute the base libdir, -B flag of iverilog.
#
# %f Substitute the -f flags from the command line.
#
# %s Substitute the start module (-s flag) from the user.
#
# %N Substitute the value of the -N<path> flag.
#
# %o Substitute the value of the -o<path> flag, or the default
# output path if there is no -o flag.
#
# %T Substitute min, typ or max depending on the -T flag from the
# command line.
#
#
# %W Substitute the ivl warning flags.
#
# %[<c><text>]
# This substitution pattern is magical, and is the only
# multicharacter pattern. This tests the code <c>, and
# substitutes <text> into the output only if <c> is true.
# The <text> may include further substitution strings, and is
# terminated by a ``]'' character.
# This is the null (no op) target. Thre is a synthesis version and a
# non-synthesis version. Normally, this does not matter, but this can
# be useful and interesting if the -N flag is included.
[-tnull -S]
<ivl>%B/ivl %W %[s-s%s] %[N-N%N] %[T-T%T] -tdll -fDLL=%B/null.tgt -- -
[-tnull]
<ivl>%B/ivl %W %[s-s%s] %[N-N%N] %[T-T%T] -tdll -fDLL=%B/null.tgt -- -
# --
# The vvm target uses the <ivl> string to take the preprocessed code from
# standard input, compile it with the vvm code generator and write the
# result to %o.cc. The driver assumes this when invoking the C++ compiler
# on the result.
[-tvvm]
<ivl>%B/ivl %W %[s-s%s] %[N-N%N] %[T-T%T] -tvvm -Fcprop -Fnodangle -fVPI_MODULE_PATH=%B %f %m -o%o.cc -- -
# -- (not supported yet)
# This is the XNF code generator.
[-txnf]
<ivl>%B/ivl %[s-s%s] %[N-N%N] %[T-T%T] -tvvm -Fsynth -Fsyn-rules -Fcprop -Fnodangle -o%o -- -
# --
# This is the pal code generator. The target module requires the -fpart=<type>
# flag to specify the part type.
[-tpal]
<ivl>%B/ivl %[s-s%s] %[N-N%N] %[T-T%T] -tdll -fDLL=%B/pal.tgt -Fsynth -Fsyn-rules -Fcprop -Fnodangle -o%o -- -
+89
View File
@@ -0,0 +1,89 @@
EXPORTS
ivl_design_flag
ivl_design_process
ivl_design_root
ivl_const_bits
ivl_const_pin
ivl_const_pins
ivl_const_signed
ivl_expr_type
ivl_expr_bits
ivl_expr_name
ivl_expr_opcode
ivl_expr_oper1
ivl_expr_oper2
ivl_expr_oper3
ivl_expr_parm
ivl_expr_parms
ivl_expr_repeat
ivl_expr_signed
ivl_expr_string
ivl_expr_width
ivl_logic_name
ivl_logic_basename
ivl_logic_type
ivl_logic_pin
ivl_logic_pins
ivl_lpm_name
ivl_lpm_type
ivl_lpm_width
ivl_lpm_ff
ivl_lpm_ff_clk
ivl_lpm_ff_data
ivl_lpm_ff_q
ivl_lval_mux
ivl_lval_pin
ivl_lval_pins
ivl_nexus_name
ivl_nexus_ptrs
ivl_nexus_ptr
ivl_nexus_ptr_pin
ivl_nexus_ptr_lpm
ivl_nexus_ptr_log
ivl_nexus_ptr_sig
ivl_scope_children
ivl_scope_logs
ivl_scope_log
ivl_scope_lpms
ivl_scope_lpm
ivl_scope_name
ivl_scope_sigs
ivl_scope_sig
ivl_signal_attr
ivl_signal_pin
ivl_signal_pins
ivl_signal_port
ivl_signal_type
ivl_signal_name
ivl_signal_basename
ivl_process_type
ivl_process_stmt
ivl_statement_type
ivl_stmt_block_count
ivl_stmt_block_stmt
ivl_stmt_cond_expr
ivl_stmt_cond_false
ivl_stmt_cond_true
ivl_stmt_delay_val
ivl_stmt_lval
ivl_stmt_lvals
ivl_stmt_lwidth
ivl_stmt_name
ivl_stmt_parm
ivl_stmt_parm_count
ivl_stmt_rval
ivl_stmt_sub_stmt
+720
View File
@@ -0,0 +1,720 @@
#ifndef __ivl_target_H
#define __ivl_target_H
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: ivl_target.h,v 1.31 2001/01/06 06:31:58 steve Exp $"
#endif
#ifdef __cplusplus
#define _BEGIN_DECL extern "C" {
#define _END_DECL }
#else
#define _BEGIN_DECL
#define _END_DECL
#endif
_BEGIN_DECL
/*
* This header file describes the API for the loadable target
* module. The main program can load these modules and access the
* functions within the loaded module to implement the backend
* behavior.
*
* The interface is divided into two parts: the entry points within
* the core that are called by the module, and the entry points in
* the module that are called by the core. It is the latter that
* causes the module to be invoked in the first place, but most of the
* interesting information about the design is accessed through the
* various access functions that the modules calls into the core.
*/
/*
* In order to grab onto data in the design, the core passes cookies
* to the various functions of the module. These cookies can in turn
* be passed to access functions in the core to get more detailed
* information.
*
* The following typedefs list the various cookies that may be passed
* around.
*
* ivl_design_t
* This object represents the entire elaborated design. Various
* global properties and methods are available from this.
*
* ivl_expr_t
* This object represents a node of an expression. If the
* expression has sub-expressions, they can be accessed from
* various method described below. The ivl_expr_type method in
* particular gets the type of the node in the form of an
* ivl_expr_type_t enumeration value.
*
* Objects of this type represent expressions in
* processes. Structural expressions are instead treated as logic
* gates.
*
* ivl_lpm_t
* This object is the base class for all the various LPM type
* device nodes. This object carries a few base properties
* (including a type) including a handle to the specific type.
*
* All the ivl_lpm_*_t objects are derived from this type, and
* there are methods to get one from the other.
*
* ivl_lpm_ff_t
* This is a flip-flop.
*
* ivl_net_logic_t
* This object represents various built in logic devices. In fact,
* this includes just about every directional device that has a
* single output, including logic gates and nmos, pmos and cmon
* devices. There is also the occasional Icarus Verilog creation.
*
* ivl_nexus_t
* Structural links within an elaborated design are connected
* together at each bit. The connection point is a nexus, so pins
* of devices refer to an ivl_nexus_t. Furthermore, from a nexus
* there are backward references to all the device pins that point
* to it.
*
* ivl_process_t
* A Verilog process is represented by one of these. A process may
* be an "initial" or an "always" process. These come from initial
* or always statements from the verilog source.
*
* ivl_scope_t
* Elaborated scopes within a design are represented by this
* type. Objects of this type also act as containers for scoped
* objects such as signals.
*
* ivl_statement_t
* Statements within processes are represented by one of these. The
* ivl_process_t object holds one of these, but a statement may in
* turn contain other statements.
*
* -- A Note About Bit Sets --
* Some objects hold a value as an array of bits. In these cases there
* is some method that retrieves the width of the value and another
* that returns a "char*". The latter is a pointer to the least
* significant bit value. Bit values are represented by the characters
* '0', '1', 'x' and 'z'. Strengths are stored elsewhere.
*
* -- A Note About Names --
* The names of objects are complete, hierarchical names. That is,
* they include the instance name of the module that contains them.
*/
typedef struct ivl_design_s *ivl_design_t;
typedef struct ivl_expr_s *ivl_expr_t;
typedef struct ivl_lpm_s *ivl_lpm_t;
typedef struct ivl_lpm_ff_s *ivl_lpm_ff_t;
typedef struct ivl_lval_s *ivl_lval_t;
typedef struct ivl_net_const_s*ivl_net_const_t;
typedef struct ivl_net_event_s*ivl_net_event_t;
typedef struct ivl_net_logic_s*ivl_net_logic_t;
typedef struct ivl_net_probe_s*ivl_net_probe_t;
typedef struct ivl_nexus_s *ivl_nexus_t;
typedef struct ivl_nexus_ptr_s*ivl_nexus_ptr_t;
typedef struct ivl_process_s *ivl_process_t;
typedef struct ivl_scope_s *ivl_scope_t;
typedef struct ivl_signal_s *ivl_signal_t;
typedef struct ivl_statement_s*ivl_statement_t;
/*
* These are types that are defined as enumerations. These have
* explicit values so that the binary API is a bit more resilient to
* changes and additions to the enumerations.
*/
/* This is the type of an ivl_expr_t object. */
typedef enum ivl_expr_type_e {
IVL_EX_NONE = 0,
IVL_EX_BINARY,
IVL_EX_CONCAT,
IVL_EX_NUMBER,
IVL_EX_SFUNC,
IVL_EX_SIGNAL,
IVL_EX_STRING,
IVL_EX_SUBSIG,
} ivl_expr_type_t;
/* This is the type code for an ivl_net_logic_t object. */
typedef enum ivl_logic_e {
IVL_LO_NONE = 0,
IVL_LO_AND,
IVL_LO_BUF,
IVL_LO_BUFIF0,
IVL_LO_BUFIF1,
IVL_LO_BUFZ,
IVL_LO_NAND,
IVL_LO_NMOS,
IVL_LO_NOR,
IVL_LO_NOT,
IVL_LO_NOTIF0,
IVL_LO_NOTIF1,
IVL_LO_OR,
IVL_LO_RNMOS,
IVL_LO_RPMOS,
IVL_LO_PMOS,
IVL_LO_XNOR,
IVL_LO_XOR
} ivl_logic_t;
/* This is the type of an LPM object. */
typedef enum ivl_lpm_type_e {
IVL_LPM_FF
} ivl_lpm_type_t;
/* Processes are initial or always blocks with a statement. This is
the type of the ivl_process_t object. */
typedef enum ivl_process_type_e {
IVL_PR_INITIAL = 0,
IVL_PR_ALWAYS = 1
} ivl_process_type_t;
/* Signals (ivl_signal_t) that are ports into the scope that contains
them have a port type. Otherwise, they are port IVL_SIP_NONE. */
typedef enum ivl_signal_port_e {
IVL_SIP_NONE = 0,
IVL_SIP_INPUT = 1,
IVL_SIP_OUTPUT= 2,
IVL_SIP_INOUT = 3
} ivl_signal_port_t;
/* This is the type code for an ivl_signal_t object. Implicit types
are resolved by the core compiler, and integers are converted into
signed registers. */
typedef enum ivl_signal_type_e {
IVL_SIT_NONE = 0,
IVL_SIT_REG,
IVL_SIT_SUPPLY0,
IVL_SIT_SUPPLY1,
IVL_SIT_TRI,
IVL_SIT_TRI0,
IVL_SIT_TRI1,
IVL_SIT_TRIAND,
IVL_SIT_TRIOR,
IVL_SIT_WAND,
IVL_SIT_WIRE,
IVL_SIT_WOR
} ivl_signal_type_t;
/* This is the type code for ivl_statement_t objects. */
typedef enum ivl_statement_type_e {
IVL_ST_NONE = 0,
IVL_ST_NOOP = 1,
IVL_ST_ASSIGN,
IVL_ST_BLOCK,
IVL_ST_CONDIT,
IVL_ST_DELAY,
IVL_ST_DELAYX,
IVL_ST_STASK,
IVL_ST_TRIGGER,
IVL_ST_WAIT,
IVL_ST_WHILE
} ivl_statement_type_t;
/* This is the type of the function to apply to a process. */
typedef int (*ivl_process_f)(ivl_process_t net);
/* This is the type of a function to apply to a scope. */
typedef int (ivl_scope_f)(ivl_scope_t net);
/* DESIGN
* When handed a design (ivl_design_t) there are a few things that you
* can do with it. The Verilog program has one design that carries the
* entire program. Use the design methods to iterate over the elements
* of the design.
*
* ivl_design_flag
* This function returns the string value of a named flag. Flags
* come from the "-fkey=value" options to the iverilog command and
* are stored in a map for this function. Given the key, this
* function returns the value.
*
* The special key "-o" is the argument to the -o flag of the
* command line (or the default if the -o flag is not used) and is
* generally how the target learns the name of the output file.
*
* ivl_design_process
* This function scans the processes (threads) in the design. It
* calls the user suplied function on each of the processes until
* one of the functors returns non-0 or all the processes are
* scanned. This function will return 0, or the non-zero value that
* was returned from the last scanned process.
*
* ivl_design_root
* A design has a root named scope that is an instance of the top
* level module in the design. This is a hook for naming the
* design, or for starting the scope scan.
*/
extern const char* ivl_design_flag(ivl_design_t des, const char*key);
extern int ivl_design_process(ivl_design_t des, ivl_process_f fun);
extern ivl_scope_t ivl_design_root(ivl_design_t des);
/*
* These methods apply to ivl_net_const_t objects.
*/
extern const char* ivl_const_bits(ivl_net_const_t net);
extern ivl_nexus_t ivl_const_pin(ivl_net_const_t net, unsigned idx);
extern unsigned ivl_const_pins(ivl_net_const_t net);
extern int ivl_const_signed(ivl_net_const_t net);
/* EXPRESSIONS
*
* These methods operate on expression objects from the
* design. Expressions mainly exist in behavioral code. The
* ivl_expr_type() function returns the type of the expression node,
* and the remaining functions access value bits of the expression.
*
* ivl_expr_signed
* This method returns true (!= 0) if the expression node
* represents a signed expression. It is possible for sub-
* expressions to be unsigned even if a node is signed, but the
* IVL core figures all this out for you. At any rate, this method
* can be applied to any expression node.
*
* ivl_expr_type
* Get the type of the expression node. Every expression node has a
* type, which can affect how some of the other expression methods
* operate on the node
*
* ivl_expr_width
* This method returns the bit width of the expression at this
* node. It can be applied to any expression node.
*/
extern ivl_expr_type_t ivl_expr_type(ivl_expr_t net);
/* IVL_EX_NUMBER */
extern const char* ivl_expr_bits(ivl_expr_t net);
/* IVL_EX_SIGNAL, IVL_EX_SFUNC */
extern const char* ivl_expr_name(ivl_expr_t net);
/* IVL_EX_BINARY */
extern char ivl_expr_opcode(ivl_expr_t net);
/* IVL_EX_BINARY */
extern ivl_expr_t ivl_expr_oper1(ivl_expr_t net);
/* IVL_EX_BINARY */
extern ivl_expr_t ivl_expr_oper2(ivl_expr_t net);
/* */
extern ivl_expr_t ivl_expr_oper3(ivl_expr_t net);
/* IVL_EX_CONCAT */
extern ivl_expr_t ivl_expr_parm(ivl_expr_t net, unsigned idx);
/* IVL_EX_CONCAT */
extern unsigned ivl_expr_parms(ivl_expr_t net);
/* IVL_EX_CONCAT */
extern unsigned ivl_expr_repeat(ivl_expr_t net);
/* any expression */
extern int ivl_expr_signed(ivl_expr_t net);
/* IVL_EX_STRING */
extern const char* ivl_expr_string(ivl_expr_t net);
/* any expression */
extern unsigned ivl_expr_width(ivl_expr_t net);
/* LOGIC
* These types and functions support manipulation of logic gates. The
* ivl_logic_t enumeration identifies the various kinds of gates that
* the ivl_net_logic_t can represent. The various functions then
* provide access to the bits of information for a given logic device.
*
* ivl_logic_type
* This method returns the type of logic gate that the cookie
* represents.
*
* ivl_logic_name
* This method returns the complete name of the logic gate. Every
* gate has a complete name (that includes the scope) even if the
* Verilog source doesn't include one. The compiler will choose one
* if necessary.
*
* ivl_logic_basename
* This is the name of the gate without the scope part.
*
* ivl_logic_pins
* ivl_logic_pin
*/
extern const char* ivl_logic_name(ivl_net_logic_t net);
extern const char* ivl_logic_basename(ivl_net_logic_t net);
extern ivl_logic_t ivl_logic_type(ivl_net_logic_t net);
extern ivl_nexus_t ivl_logic_pin(ivl_net_logic_t net, unsigned pin);
extern unsigned ivl_logic_pins(ivl_net_logic_t net);
/* LPM
* These functions support access to the properties of LPM devices.
*
* ivl_lpm_name
* Return the name of the device.
*
* ivl_lpm_type
* Return the ivl_lpm_type_t of the secific LPM device.
*
* ivl_lpm_width
* Return the width of the LPM device. What this means depends on
* the LPM type, but it generally has to do with the width of the
* output data path.
*/
extern const char* ivl_lpm_name(ivl_lpm_t net);
extern ivl_lpm_type_t ivl_lpm_type(ivl_lpm_t net);
extern unsigned ivl_lpm_width(ivl_lpm_t net);
/*
* These are cast functions for the ivl_lpm_t. They cast the object to
* the requested type, checking for errors along the way.
*/
extern ivl_lpm_ff_t ivl_lpm_ff(ivl_lpm_t net);
extern ivl_nexus_t ivl_lpm_ff_clk(ivl_lpm_ff_t net);
extern ivl_nexus_t ivl_lpm_ff_data(ivl_lpm_ff_t net, unsigned idx);
extern ivl_nexus_t ivl_lpm_ff_q(ivl_lpm_ff_t net, unsigned idx);
/* LVAL
* The l-values of assignments are concatenation of ivl_lval_t
* objects. Each l-value has a bunch of connections (in the form of
* ivl_nexus_t objects) and possibly a mux expression. The compiler
* takes care of part selects and nested concatenations. The
* ivl_stmt_lval function pulls ivl_lval_t objects out of the
* statement.
*
* ivl_lval_mux
* If the l-value includes a bit select expression, this method
* returns an ivl_expr_t that represents that
* expression. Otherwise, it returns 0.
*
* ivl_lval_pin
* Return an ivl_nexus_t for the connection of the ivl_lval_t.
*
* ivl_lval_pins
* Return the number of pins for this object.
*/
extern ivl_expr_t ivl_lval_mux(ivl_lval_t net);
extern unsigned ivl_lval_pins(ivl_lval_t net);
extern ivl_nexus_t ivl_lval_pin(ivl_lval_t net, unsigned idx);
/* NEXUS
* connections of signals and nodes is handled by single-bit
* nexus. These functions manage the ivl_nexus_t object. They also
* manage the ivl_nexus_ptr_t objects that are closely related to the
* nexus.
*
* ivl_nexus_name
* Each nexus is given a name, typically derived from the signals
* connected to it, but completely made up if need be. The name of
* every nexus is unique.
*
* ivl_nexus_ptrs
* This function returns the number of pointers that are held by
* the nexus. It should always return at least 1. The pointer
* proper is accessed by index.
*
* ivl_nexus_ptr
* Return a nexus pointer given the nexus and an index.
*
* Once an ivl_nexus_ptr_t is selected by the ivl_nexus_ptr method,
* the properties of the pointer can be accessed by the following
* methods:
*
* ivl_nexus_ptr_pin
* This returns the pin number of the device where this nexus
* points. It is the bit within the signal or logic device that is
* connected to the nexus.
*
* If the target is an LPM device, then this value is zero, and it
* is up to the application to find the pin that referse to this
* nexus. The problem is that LPM devices do not have a pinout per
* se, the pins all have specific names.
*
* ivl_nexus_ptr_log
* If the target object is an ivl_net_logic_t, this method returns
* the object. Otherwise, this method returns 0.
*
* ivl_nexus_ptr_lpm
* If the target object is an ivl_lpm_t, this method returns the
* object. Otherwise, this method returns 0.
*
* ivl_nexus_ptr_sig
* If the target object is an ivl_signal_t, this method returns the
* object. If the target is not a signal, this method returns 0.
*/
extern const char* ivl_nexus_name(ivl_nexus_t net);
extern unsigned ivl_nexus_ptrs(ivl_nexus_t net);
extern ivl_nexus_ptr_t ivl_nexus_ptr(ivl_nexus_t net, unsigned idx);
extern unsigned ivl_nexus_ptr_pin(ivl_nexus_ptr_t net);
extern ivl_net_logic_t ivl_nexus_ptr_log(ivl_nexus_ptr_t net);
extern ivl_lpm_t ivl_nexus_ptr_lpm(ivl_nexus_ptr_t net);
extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net);
/* SCOPE
* Scopes of various sort have these properties. Use these methods to
* access them. Scopes come to exist in the elaborated design
* generally when a module is instantiated, though they also come from
* named blocks, tasks and functions.
*
* (NOTE: Module scopes are *instances* of modules, and not the module
* definition. A definition may apply to many instances.)
*
* ivl_scope_children
* A scope may in turn contain other scopes. This method iterates
* through all the child scopes of a given scope. If the function
* returns any value other then 0, the iteration stops and the
* method returns that value. Otherwise, iteration continues until
* the children run out.
*
* If the scope has no children, this method will return 0 and
* otherwise do nothing.
*
* ivl_scope_log
* ivl_scope_logs
* Scopes have 0 or more logic devices in them. A logic device is
* represented by ivl_logic_t.
*
* ivl_scope_name
* Every scope has a hierarchical name. This name is also a prefix
* of all the names of objects contained within the scope.
*
* ivl_scope_sig
* ivl_scope_sigs
* Scopes have 0 or more signals in them. These signals are
* anything that can become and ivl_signal_t, include synthetic
* signals generated by the compiler.
*/
extern int ivl_scope_children(ivl_scope_t net, ivl_scope_f func);
extern unsigned ivl_scope_logs(ivl_scope_t net);
extern ivl_net_logic_t ivl_scope_log(ivl_scope_t net, unsigned idx);
extern unsigned ivl_scope_lpms(ivl_scope_t net);
extern ivl_lpm_t ivl_scope_lpm(ivl_scope_t, unsigned idx);
extern const char* ivl_scope_name(ivl_scope_t net);
extern unsigned ivl_scope_sigs(ivl_scope_t net);
extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx);
/* SIGNALS
* Signals are named things in the Verilog source, like wires and
* regs, and also named things that are preated as temporaries during
* certain elaboration or optimization steps. A signal may also be a
* port of a module or task.
*
* Signals have a name (obviously) and types. A signal may also be
* signed or unsigned.
*
* ivl_signal_pins
* ivl_signal_pin
* The ivl_signal_pin function returns the nexus connected to the
* signal. If the signal is a vectory, the idx can be a non-zero
* value, and the result is the nexus for the specified bit.
*
* ivl_signal_port
* If the signal is a port to a module, this function returns the
* port direction. If the signal is not a port, it returns
* IVL_SIP_NONE.
*
* ivl_signal_type
*
* ivl_signal_name
* This function returns the fully scoped hierarchical name for the
* signal. The name refers to the entire vector that is the signal.
*
* ivl_signal_basename
* This function returns the name of the signal, without the scope
* information. This is the tail of the signal name.
*
* ivl_signal_attr
* Icarus Verilog supports attaching attributes to signals, with
* the attribute value (a string) associated with a key. This
* function returns the attribute value for the given key. If the
* key does not exist, the function returns 0.
*/
extern ivl_nexus_t ivl_signal_pin(ivl_signal_t net, unsigned idx);
extern unsigned ivl_signal_pins(ivl_signal_t net);
extern ivl_signal_port_t ivl_signal_port(ivl_signal_t net);
extern ivl_signal_type_t ivl_signal_type(ivl_signal_t net);
extern const char* ivl_signal_name(ivl_signal_t net);
extern const char* ivl_signal_basename(ivl_signal_t net);
extern const char* ivl_signal_attr(ivl_signal_t net, const char*key);
/*
* These functions get information about a process. A process is
* an initial or always block within the original Verilog source, that
* is translated into a type and a single statement. (The statement
* may be a compound statement.)
*
* The ivl_process_type function gets the type of the process,
* an "inital" or "always" statement.
*
* The ivl_process_stmt function gets the statement that forms the
* process. See the statement related functions for how to manipulate
* statements.
*/
extern ivl_process_type_t ivl_process_type(ivl_process_t net);
extern ivl_statement_t ivl_process_stmt(ivl_process_t net);
/*
* These functions manage statements of various type. This includes
* all the different kinds of statements (as enumerated in
* ivl_statement_type_t) that might occur in behavioral code.
*
* The ivl_statement_type() function returns the type code for the
* statement. This is the major type, and implies which of the later
* functions are applicable to the statemnt.
*/
extern ivl_statement_type_t ivl_statement_type(ivl_statement_t net);
/*
* The following functions retrieve specific single values from the
* statement. These values are the bits of data and parameters that
* make up the statement. Many of these functions apply to more then
* one type of statement, so the comment in front of them tells which
* statement types can be passed to the function.
*/
/* IVL_ST_BLOCK */
extern unsigned ivl_stmt_block_count(ivl_statement_t net);
/* IVL_ST_BLOCK */
extern ivl_statement_t ivl_stmt_block_stmt(ivl_statement_t net, unsigned i);
/* IVL_ST_CONDIT */
extern ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net);
/* IVL_ST_CONDIT */
extern ivl_statement_t ivl_stmt_cond_false(ivl_statement_t net);
/* IVL_ST_CONDIT */
extern ivl_statement_t ivl_stmt_cond_true(ivl_statement_t net);
/* IVL_ST_DELAY */
extern unsigned long ivl_stmt_delay_val(ivl_statement_t net);
/* IVL_ST_ASSIGN */
extern ivl_lval_t ivl_stmt_lval(ivl_statement_t net, unsigned idx);
/* IVL_ST_ASSIGN */
extern unsigned ivl_stmt_lvals(ivl_statement_t net);
/* IVL_ST_ASSIGN */
extern unsigned ivl_stmt_lwidth(ivl_statement_t net);
/* IVL_ST_STASK */
extern const char* ivl_stmt_name(ivl_statement_t net);
/* IVL_ST_STASK */
extern ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx);
/* IVL_ST_STASK */
extern unsigned ivl_stmt_parm_count(ivl_statement_t net);
/* IVL_ST_ASSIGN */
extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net);
/* IVL_ST_DELAY, IVL_ST_WAIT, IVL_ST_WHILE */
extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
/* target_design
The "target_design" function is called once after the whole design
is processed and available to the target. The target doesn't return
from this function until it is finished with the design.
This function is implemented in the loaded target, and not in the
ivl core. This function is how the target module is invoked. */
typedef int (*target_design_f)(ivl_design_t des);
_END_DECL
/*
* $Log: ivl_target.h,v $
* Revision 1.31 2001/01/06 06:31:58 steve
* declaration initialization for time variables.
*
* Revision 1.30 2000/12/05 06:29:33 steve
* Make signal attributes available to ivl_target API.
*
* Revision 1.29 2000/11/12 17:47:29 steve
* flip-flop pins for ivl_target API.
*
* Revision 1.28 2000/11/11 01:52:09 steve
* change set for support of nmos, pmos, rnmos, rpmos, notif0, and notif1
* change set to correct behavior of bufif0 and bufif1
* (Tim Leight)
*
* Also includes fix for PR#27
*
* Revision 1.27 2000/11/11 00:03:36 steve
* Add support for the t-dll backend grabing flip-flops.
*
* Revision 1.26 2000/10/31 17:49:02 steve
* Support time variables.
*
* Revision 1.25 2000/10/28 22:32:34 steve
* API for concatenation expressions.
*
* Revision 1.24 2000/10/28 17:55:03 steve
* stub for the concat operator.
*
* Revision 1.23 2000/10/25 05:41:24 steve
* Get target signal from nexus_ptr.
*
* Revision 1.22 2000/10/21 16:49:45 steve
* Reduce the target entry points to the target_design.
*
* Revision 1.21 2000/10/18 20:04:39 steve
* Add ivl_lval_t and support for assignment l-values.
*
* Revision 1.20 2000/10/15 04:46:23 steve
* Scopes and processes are accessible randomly from
* the design, and signals and logic are accessible
* from scopes. Remove the target calls that are no
* longer needed.
*
* Add the ivl_nexus_ptr_t and the means to get at
* them from nexus objects.
*
* Give names to methods that manipulate the ivl_design_t
* type more consistent names.
*
* Revision 1.19 2000/10/13 03:39:27 steve
* Include constants in nexus targets.
*
* Revision 1.18 2000/10/08 04:01:54 steve
* Back pointers in the nexus objects into the devices
* that point to it.
*
* Collect threads into a list in the design.
*
* Revision 1.17 2000/10/07 19:45:43 steve
* Put logic devices into scopes.
*
* Revision 1.16 2000/10/06 23:46:50 steve
* ivl_target updates, including more complete
* handling of ivl_nexus_t objects. Much reduced
* dependencies on pointers to netlist objects.
*
* Revision 1.15 2000/10/05 05:03:01 steve
* xor and constant devices.
*
* Revision 1.14 2000/09/30 02:18:15 steve
* ivl_expr_t support for binary operators,
* Create a proper ivl_scope_t object.
*/
#endif
+11 -11
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.6 1999/10/16 20:48:15 steve Exp $"
#ident "$Id: Makefile.in,v 1.9 2001/01/09 03:11:28 steve Exp $"
#
#
SHELL = /bin/sh
@@ -31,8 +31,8 @@ srcdir = @srcdir@
VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
bindir = @bindir@
libdir = @libdir@
includedir = $(prefix)/include
CC = @CC@
@@ -41,7 +41,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CPPFLAGS = @CPPFLAGS@ @DEFS@
CFLAGS = @CFLAGS@
CFLAGS = @CFLAGS@ -I.
LDFLAGS = @LDFLAGS@
all: ivlpp
@@ -55,21 +55,21 @@ ivlpp: $O
$(CC) $(LDFLAGS) $O -o ivlpp
lexor.c: lexor.lex
flex -s -olexor.c lexor.lex
flex -s -olexor.c $(srcdir)/lexor.lex
parse.h parse.c: parse.y
bison --verbose -t -d parse.y -o parse.c
bison --verbose -t -d $(srcdir)/parse.y -o parse.c
install: all installdirs $(bindir)/ivlpp
install: all installdirs $(libdir)/ivl/ivlpp
$(bindir)/ivlpp: ivlpp
$(INSTALL_PROGRAM) ./ivlpp $(bindir)/ivlpp
$(libdir)/ivl/ivlpp: ivlpp
$(INSTALL_PROGRAM) ./ivlpp $(libdir)/ivl/ivlpp
installdirs: ../mkinstalldirs
$(srcdir)/../mkinstalldirs $(bindir)
$(srcdir)/../mkinstalldirs $(libdir)/ivl
uninstall:
rm -f $(bindir)/ivlpp
rm -f $(libdir)/ivl/ivlpp
lexor.o: lexor.c parse.h globals.h
main.o: main.c globals.h
+14 -3
View File
@@ -18,14 +18,14 @@
* 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: globals.h,v 1.2 1999/09/05 22:33:18 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: globals.h,v 1.5 2000/09/13 22:33:13 steve Exp $"
#endif
# include <stdio.h>
extern void reset_lexor(FILE*out, char*paths[]);
extern void define_macro(const char*name, const char*value);
extern void define_macro(const char*name, const char*value, int keyword);
/* These variables contain the include directories to be searched when
an include directive in encountered. */
@@ -35,11 +35,22 @@ extern unsigned include_cnt;
/* This flag is true if #line directives are to be generated. */
extern int line_direct_flag;
extern unsigned error_count;
/* This is the entry to the parser. */
extern int yyparse();
/*
* $Log: globals.h,v $
* Revision 1.5 2000/09/13 22:33:13 steve
* undefined macros are null (with warnings.)
*
* Revision 1.4 2000/08/20 17:49:04 steve
* Clean up warnings and portability issues.
*
* Revision 1.3 2000/06/30 15:49:44 steve
* Handle errors from parser slightly differently.
*
* Revision 1.2 1999/09/05 22:33:18 steve
* Take multiple source files on the command line.
*
+54 -14
View File
@@ -18,8 +18,8 @@
* 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: lexor.lex,v 1.14 1999/10/08 17:27:56 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: lexor.lex,v 1.21 2000/09/13 22:33:13 steve Exp $"
#endif
# include <stdio.h>
@@ -35,6 +35,7 @@ static void output_init();
static void def_match();
static void def_start();
static void def_finish();
static void def_undefine();
static void do_define();
static int is_defined(const char*name);
@@ -115,13 +116,25 @@ W [ \t\b\f]+
that follows it. when the directive ends, the do_include function
performs the include operation. */
^{W}?`include { BEGIN(PPINCLUDE); }
^{W}?`include { yy_push_state(PPINCLUDE); }
<PPINCLUDE>\"[^\"]*\" { include_filename(); }
<PPINCLUDE>[ \t\b\f] { ; }
<PPINCLUDE>\n { istack->lineno += 1; BEGIN(0); do_include(); }
/* Catch single-line comments that share the line with an include
directive. And while I'm at it, I might as well preserve the
comment in the output stream. */
<PPINCLUDE>"//".* { ECHO; }
/* These finish the include directive (EOF or EOL) so I revert the
lexor state and execute the inclusion. */
<PPINCLUDE>\n { istack->lineno += 1; yy_pop_state(); do_include(); }
<PPINCLUDE>\r\n { istack->lineno += 1; yy_pop_state(); do_include(); }
<PPINCLUDE>\n\r { istack->lineno += 1; yy_pop_state(); do_include(); }
<PPINCLUDE><<EOF>> { istack->lineno += 1; yy_pop_state(); do_include(); }
/* Detect the define directive, and match the name. Match any
@@ -129,13 +142,22 @@ 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}? { yy_push_state(PPDEFINE); def_start(); }
<PPDEFINE>.*\n {
do_define();
<PPDEFINE>.* { do_define(); }
<PPDEFINE>(\n|"\r\n"|"\n\r") {
def_finish();
istack->lineno += 1;
fputc('\n', yyout);
BEGIN(0);
yy_pop_state();
}
<PPDEFINE><<EOF>> {
def_finish();
istack->lineno += 1;
fputc('\n', yyout);
yy_pop_state();
}
`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
@@ -194,6 +216,8 @@ W [ \t\b\f]+
struct define_t {
char*name;
char*value;
/* keywords don't get rescanned for fresh values. */
int keyword;
struct define_t*left, *right, *up;
};
@@ -233,8 +257,14 @@ static void def_match()
struct define_t*cur = def_lookup(yytext+1);
if (cur) {
struct include_stack_t*isp
= calloc(1, sizeof(struct include_stack_t));
struct include_stack_t*isp;
if (cur->keyword) {
fprintf(yyout, "%s", cur->value);
return;
}
isp = calloc(1, sizeof(struct include_stack_t));
isp->str = cur->value;
isp->next = istack;
istack->yybs = YY_CURRENT_BUFFER;
@@ -242,7 +272,9 @@ static void def_match()
yy_switch_to_buffer(yy_new_buffer(istack->file, YY_BUF_SIZE));
} else {
fprintf(yyout, "%s", yytext);
fprintf(stderr, "%s:%u: warning: macro %s undefined "
"(and assumed null) at this point.\n",
istack->path, istack->lineno, yytext);
}
}
@@ -253,11 +285,12 @@ static void def_start()
sscanf(yytext, "`define %s", def_name);
}
void define_macro(const char*name, const char*value)
void define_macro(const char*name, const char*value, int keyword)
{
struct define_t*def = malloc(sizeof(struct define_t));
def->name = strdup(name);
def->value = strdup(value);
def->keyword = keyword;
def->left = 0;
def->right = 0;
def->up = 0;
@@ -317,7 +350,14 @@ static void do_define()
*cp = 0;
}
define_macro(def_name, yytext);
define_macro(def_name, yytext, 0);
def_name[0] = 0;
}
static void def_finish()
{
if (def_name[0])
define_macro(def_name, "1", 0);
}
static void def_undefine()
@@ -522,7 +562,7 @@ static int yywrap()
if (line_direct_flag)
fprintf(yyout, "\n#line \"%s\" 0\n", istack->path);
yyrestart(isp->file);
yyrestart(istack->file);
return 0;
}
+51 -5
View File
@@ -16,8 +16,8 @@ const char COPYRIGHT[] =
* 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: main.c,v 1.4 1999/11/29 17:02:21 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: main.c,v 1.8 2000/12/06 05:15:21 steve Exp $"
#endif
const char NOTICE[] =
@@ -52,6 +52,8 @@ unsigned include_cnt = 0;
int line_direct_flag = 0;
unsigned error_count = 0;
int main(int argc, char*argv[])
{
int opt;
@@ -59,11 +61,30 @@ int main(int argc, char*argv[])
char*out_path = 0;
FILE*out;
/* Define preprocessor keywords that I plan to just pass. */
define_macro("celldefine", "`celldefine", 1);
define_macro("default_nettype", "`default_nettype", 1);
define_macro("delay_mode_distributed", "`delay_mode_distributed", 1);
define_macro("delay_mode_unit", "`delay_mode_unit", 1);
define_macro("delay_mode_path", "`delay_mode_path", 1);
define_macro("disable_portfaults", "`disable_portfaults", 1);
define_macro("enable_portfaults", "`enable_portfaults", 1);
define_macro("endcelldefine", "`endcelldefine", 1);
define_macro("endprotect", "`endprotect", 1);
define_macro("nosuppress_faults", "`nosuppress_faults", 1);
define_macro("nounconnected_drive", "`nounconnected_drive", 1);
define_macro("protect", "`protect", 1);
define_macro("resetall", "`resetall", 1);
define_macro("suppress_faults", "`suppress_faults", 1);
define_macro("timescale", "`timescale", 1);
define_macro("unconnected_drive", "`unconnected_drive", 1);
define_macro("uselib", "`uselib", 1);
include_dir = malloc(sizeof(char*));
include_dir[0] = strdup(".");
include_cnt = 1;
while ((opt = getopt(argc, argv, "D:I:Lo:v")) != EOF) switch (opt) {
while ((opt = getopt(argc, argv, "D:I:K:Lo:v")) != EOF) switch (opt) {
case 'D': {
char*tmp = strdup(optarg);
@@ -73,7 +94,7 @@ int main(int argc, char*argv[])
else
val = "1";
define_macro(tmp, val);
define_macro(tmp, val, 0);
free(tmp);
break;
}
@@ -84,6 +105,15 @@ int main(int argc, char*argv[])
include_cnt += 1;
break;
case 'K': {
char*buf = malloc(strlen(optarg) + 2);
buf[0] = '`';
strcpy(buf+1, optarg);
define_macro(optarg, buf, 1);
free(buf);
break;
}
case 'L':
line_direct_flag = 1;
break;
@@ -115,6 +145,7 @@ int main(int argc, char*argv[])
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"
" -K<def> - Define a keyword macro that I just pass\n"
" -L - Emit line number directives\n"
" -o<fil> - Send the output to <fil>\n"
" -v - Print version information\n",
@@ -138,11 +169,26 @@ int main(int argc, char*argv[])
}
reset_lexor(out, argv+optind);
return yyparse();
if (yyparse()) return -1;
return error_count;
}
/*
* $Log: main.c,v $
* Revision 1.8 2000/12/06 05:15:21 steve
* fix portfaults pass values.
*
* Revision 1.7 2000/09/13 22:33:13 steve
* undefined macros are null (with warnings.)
*
* Revision 1.6 2000/08/20 17:49:05 steve
* Clean up warnings and portability issues.
*
* Revision 1.5 2000/06/30 15:49:44 steve
* Handle errors from parser slightly differently.
*
* Revision 1.4 1999/11/29 17:02:21 steve
* include getopt if present.
*
+2 -2
View File
@@ -18,8 +18,8 @@
* 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: parse.y,v 1.1 1999/07/03 17:24:11 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: parse.y,v 1.2 2000/08/20 17:49:05 steve Exp $"
#endif
static void yyerror(const char*msg);
+348 -105
View File
@@ -1,7 +1,7 @@
%{
/*
* Copyright (c) 1998-1999 Stephen Williams ([email protected])
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,8 +18,8 @@
* 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: lexor.lex,v 1.38 1999/11/23 02:49:04 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: lexor.lex,v 1.54 2000/12/12 06:13:44 steve Exp $"
#endif
//# define YYSTYPE lexval
@@ -30,19 +30,55 @@
# include "parse.h"
# include <ctype.h>
# include <string.h>
# include "lexor_keyword.h"
extern FILE*vl_input;
extern string vl_file;
# define YY_USER_INIT reset_lexor();
# define yylval VLlval
/*
* Lexical location information is passed in the yylloc variable to th
* parser. The file names, strings, are kept in a list so that I can
* re-use them. The set_file_name function will return a pointer to
* the name as it exists in the list (and delete the passed string.)
* If the name is new, it will be added to the list.
*/
extern YYLTYPE yylloc;
struct file_name_cell {
const char*text;
struct file_name_cell*next;
};
static struct file_name_cell*file_names = 0;
static const char* set_file_name(char*text)
{
struct file_name_cell*cur = file_names;
while (cur) {
if (strcmp(cur->text, text) == 0) {
delete[]text;
return cur->text;
}
cur = cur->next;
}
cur = new struct file_name_cell;
cur->text = text;
cur->next = file_names;
return text;
}
extern void pform_set_timescale(int, int);
static void reset_lexor();
static void line_directive();
static void line_directive2();
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);
@@ -53,6 +89,8 @@ static verinum*make_unsized_dec(const char*txt);
static verinum*make_unsized_octal(const char*txt);
static verinum*make_unsized_hex(const char*txt);
static void process_timescale(const char*txt);
static int comment_enter;
%}
@@ -97,6 +135,7 @@ W [ \t\b\f\r]+
"~^" { return K_NXOR; }
"^~" { return K_NXOR; }
"~&" { return K_NAND; }
"->" { return K_TRIGGER; }
[}{;:\[\],()#=.@&!?<>%|^~+*/-] { return yytext[0]; }
@@ -106,6 +145,7 @@ W [ \t\b\f\r]+
<CSTRING>\n { BEGIN(0);
yylval.text = strdup(yytext);
VLerror(yylloc, "Missing close quote of string.");
yylloc.first_line += 1;
return STRING; }
<CSTRING>\" { BEGIN(0);
yylval.text = strdup(yytext);
@@ -113,16 +153,16 @@ W [ \t\b\f\r]+
return STRING; }
<CSTRING>. { yymore(); }
<UDPTABLE>\(\?0\) { return '_'; }
<UDPTABLE>\(\?1\) { return '+'; }
<UDPTABLE>\(\?x\) { return '%'; }
<UDPTABLE>\(\?\?\) { return '*'; }
<UDPTABLE>\(01\) { return 'r'; }
<UDPTABLE>\(0x\) { return 'P'; }
<UDPTABLE>\(10\) { return 'f'; }
<UDPTABLE>\(1x\) { return 'N'; }
<UDPTABLE>\(x0\) { return 'F'; }
<UDPTABLE>\(x1\) { return 'R'; }
<UDPTABLE>\(\?0\) { return '_'; }
<UDPTABLE>\(\?1\) { return '+'; }
<UDPTABLE>\(\?[xX]\) { return '%'; }
<UDPTABLE>\(\?\?\) { return '*'; }
<UDPTABLE>\(01\) { return 'r'; }
<UDPTABLE>\(0[xX]\) { return 'P'; }
<UDPTABLE>\(10\) { return 'f'; }
<UDPTABLE>\(1[xX]\) { return 'N'; }
<UDPTABLE>\([xX]0\) { return 'F'; }
<UDPTABLE>\([xX]1\) { return 'R'; }
<UDPTABLE>[bB] { return 'b'; }
<UDPTABLE>[fF] { return 'f'; }
<UDPTABLE>[rR] { return 'r'; }
@@ -130,13 +170,15 @@ W [ \t\b\f\r]+
<UDPTABLE>[pPnN01\?\*\-] { return yytext[0]; }
[a-zA-Z_][a-zA-Z0-9$_]* {
int rc = check_identifier(yytext, yyleng);
int rc = lexor_keyword_code(yytext, yyleng);
if (rc == IDENTIFIER)
yylval.text = strdup(yytext);
else
yylval.text = 0;
return rc; }
return rc;
}
[a-zA-Z_][a-zA-Z0-9$_]*(\.[a-zA-Z_][a-zA-Z0-9$_]*)+ {
yylval.text = strdup(yytext);
@@ -159,26 +201,26 @@ W [ \t\b\f\r]+
yylval.text = strdup(cp);
return PORTNAME; }
[0-9][0-9_]*[ \t]*\'[dD][ \t]*[0-9][0-9_]* {
[0-9][0-9_]*[ \t]*\'[sS]?[dD][ \t]*[0-9][0-9_]* {
yylval.number = make_sized_dec(yytext);
return NUMBER; }
[0-9][0-9_]*[ \t]*\'[bB][ \t]*[0-1xzXZ_\?]+ {
[0-9][0-9_]*[ \t]*\'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ {
yylval.number = make_sized_binary(yytext);
return NUMBER; }
[0-9][0-9_]*[ \t]*\'[oO][ \t]*[0-7xzXZ_\?]+ {
[0-9][0-9_]*[ \t]*\'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ {
yylval.number = make_sized_octal(yytext);
return NUMBER; }
[0-9][0-9_]*[ \t]*\'[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ {
[0-9][0-9_]*[ \t]*\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ {
yylval.number = make_sized_hex(yytext);
return NUMBER; }
\'d[ \t]*[0-9][0-9_]* { yylval.number = make_unsized_dec(yytext);
return NUMBER; }
\'[bB][ \t]*[0-1xzXZ_\?]+ { yylval.number = make_unsized_binary(yytext);
\'[sS]?[dD][ \t]*[0-9][0-9_]* { yylval.number = make_unsized_dec(yytext);
return NUMBER; }
\'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ { yylval.number = make_unsized_binary(yytext);
return NUMBER; }
\'[oO][ \t]*[0-7xzXZ_\?]+ { yylval.number = make_unsized_octal(yytext);
\'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ { yylval.number = make_unsized_octal(yytext);
return NUMBER; }
\'[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { yylval.number = make_unsized_hex(yytext);
\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { yylval.number = make_unsized_hex(yytext);
return NUMBER; }
[0-9][0-9_]* {
@@ -198,6 +240,7 @@ W [ \t\b\f\r]+
}
yylval.number = new verinum(bits, nbits, false);
yylval.number->has_sign(true);
delete[]bits;
return NUMBER; }
@@ -213,10 +256,8 @@ W [ \t\b\f\r]+
/* Notice and handle the timescale directive. */
`timescale { BEGIN(PPTIMESCALE); }
<PPTIMESCALE>. { ; }
<PPTIMESCALE>.* { process_timescale(yytext); }
<PPTIMESCALE>\n {
cerr << yylloc.text << ":" << yylloc.first_line
<< ": Sorry, `timescale not supported." << endl;
yylloc.first_line += 1;
BEGIN(0); }
@@ -234,11 +275,11 @@ W [ \t\b\f\r]+
^`endcelldefine{W}?.* { }
^`endprotect{W}?.* { }
^`nosuppress_faults{W}?.* { }
^`nounconnected_drive{W}?* { }
^`nounconnected_drive{W}?.* { }
^`protect{W}?.* { }
^`resetall{W}?.* { }
^`suppress_faults{W}?.* { }
^`unconnected_drive{W}?* { }
^`unconnected_drive{W}?.* { }
^`uselib{W}?.* { }
@@ -312,22 +353,27 @@ void lex_end_table()
static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
{
assert(tolower(*ptr) == 'b');
bool sign_flag = false;
verinum::V*bits = new verinum::V[size];
if (tolower(ptr[0]) == 's') {
ptr += 1;
sign_flag = true;
}
assert(tolower(*ptr) == 'b');
ptr += 1;
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
unsigned idx = 0;
const char*eptr = ptr + strlen(ptr) - 1;
while ((eptr > ptr) && (idx < size)) {
if (*eptr == '_') {
eptr -= 1;
continue;
}
while ((eptr >= ptr) && (idx < size)) {
switch (*eptr) {
case '_':
break;
case '0':
bits[idx++] = verinum::V0;
break;
@@ -346,10 +392,22 @@ static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
eptr -= 1;
}
/* If we filled up the expected number of bits, but there are
still characters of the number part left, then report a
warning that we are truncating. */
if ((idx >= size) && (eptr >= ptr))
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric binary constant ``" << ptr <<
"'' truncated to " << size << " bits." << endl;
// Zero-extend binary number, except that z or x is extended
// if it is the highest supplied digit.
while (idx < size) {
switch (ptr[1]) {
switch (ptr[0]) {
case '0':
case '1':
bits[idx++] = verinum::V0;
@@ -365,7 +423,10 @@ static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
}
}
return new verinum(bits, size, fixed);
verinum*out = new verinum(bits, size, fixed);
delete[]bits;
out->has_sign(sign_flag);
return out;
}
static verinum*make_sized_binary(const char*txt)
@@ -376,16 +437,21 @@ static verinum*make_sized_binary(const char*txt)
ptr += 1;
assert(*ptr == '\'');
ptr += 1;
assert(tolower(*ptr) == 'b');
return make_binary_with_size(size, true, ptr);
}
static verinum*make_unsized_binary(const char*txt)
{
bool sign_flag = false;
const char*ptr = txt;
assert(*ptr == '\'');
ptr += 1;
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'b');
while (*ptr && ((*ptr == 'b') || (*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
@@ -420,100 +486,114 @@ static verinum*make_unsized_binary(const char*txt)
ptr += 1;
}
return new verinum(bits, size);
verinum*out = new verinum(bits, size);
out->has_sign(sign_flag);
delete[]bits;
return out;
}
static verinum*make_sized_octal(const char*txt)
{
bool sign_flag = false;
char*ptr;
unsigned size = strtoul(txt,&ptr,10);
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
assert(*ptr == '\'');
ptr += 1;
assert(tolower(*ptr) == 'o');
/* We know from the size number how bit to make the verinom
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'o');
ptr += 1;
/* We know from the size number how bit to make the verinum
array, so make it now. */
verinum::V*bits = new verinum::V[size];
verinum::V*bits = new verinum::V[(size+2)/3 * 3];
/* skip white space between size and the base token. */
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
/* Find the end of the digits. ptr already points to the start. */
char*eptr = ptr + strlen(ptr);
/* 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. */
/* Get a pointer to the last character of the number string,
then work back from there (the least significant digit)
forward until I run out of digits or space to put them. */
char*eptr = ptr + strlen(ptr) - 1;
unsigned idx = 0;
while ((eptr > ptr) && ((idx/3) < (size/3))) switch (*--eptr) {
while ((eptr >= ptr) && (idx < size)) {
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;
}
}
if ((eptr > ptr) && (idx < size)) switch (*--eptr) {
case 'x': case 'X':
for ( ; idx < size ; idx += 1)
bits[idx] = verinum::Vx;
break;
case 'z': case 'Z': case '?':
for ( ; idx < size ; idx += 1)
bits[idx] = verinum::Vz;
break;
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;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
{
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;
break;
}
case '_':
break;
default:
bits[idx++] = verinum::V0;
assert(0);
}
eptr -= 1;
}
return new verinum(bits, size, true);
/* If we filled up all the bits and there are still characters
in the number string, then we overflowed. Report a warning
that we are truncating. */
if ((idx >= size) && (eptr >= ptr))
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric octal constant ``" << ptr <<
"'' truncated to " << size << " bits." << endl;
/* If we did not fill up all the bits from the string, then
zero-extend the number. */
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;
}
verinum*out = new verinum(bits, size, true);
delete[]bits;
out->has_sign(sign_flag);
return out;
}
static verinum*make_unsized_octal(const char*txt)
{
bool sign_flag = false;
const char*ptr = txt;
assert(*ptr == '\'');
ptr += 1;
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'o');
ptr += 1;
@@ -555,11 +635,15 @@ static verinum*make_unsized_octal(const char*txt)
ptr += 1;
}
return new verinum(bits, size);
verinum*out = new verinum(bits, size);
out->has_sign(sign_flag);
delete[]bits;
return out;
}
static verinum*make_sized_hex(const char*txt)
{
bool sign_flag = false;
char*ptr;
unsigned size = strtoul(txt,&ptr,10);
@@ -568,6 +652,12 @@ static verinum*make_sized_hex(const char*txt)
assert(*ptr == '\'');
ptr += 1;
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'h');
ptr += 1;
@@ -622,7 +712,15 @@ static verinum*make_sized_hex(const char*txt)
eptr -= 1;
}
// zero extend octal numbers
/* If we filled up the expected number of bits, but there are
still characters of the number part left, then report a
warning that we are truncating. */
if ((idx >= size) && (eptr >= ptr))
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric hex constant ``" << ptr <<
"'' truncated to " << size << " bits." << endl;
// zero extend hex numbers
while (idx < size) switch (ptr[1]) {
case 'x': case 'X':
bits[idx++] = verinum::Vx;
@@ -634,14 +732,23 @@ static verinum*make_sized_hex(const char*txt)
bits[idx++] = verinum::V0;
}
return new verinum(bits, size, true);
verinum*out = new verinum(bits, size, true);
out->has_sign(sign_flag);
delete[]bits;
return out;
}
static verinum*make_unsized_hex(const char*txt)
{
bool sign_flag = false;
const char*ptr = txt;
assert(*ptr == '\'');
ptr += 1;
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'h');
ptr += 1;
@@ -694,7 +801,10 @@ static verinum*make_unsized_hex(const char*txt)
ptr += 1;
}
return new verinum(bits, size);
verinum*out = new verinum(bits, size);
out->has_sign(sign_flag);
delete[]bits;
return out;
}
/*
@@ -703,15 +813,30 @@ static verinum*make_unsized_hex(const char*txt)
*/
static verinum*make_dec_with_size(unsigned size, bool fixed, const char*ptr)
{
bool signed_flag = false;
if (tolower(*ptr) == 's') {
signed_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'd');
ptr += 1;
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
const char*digits = ptr;
/* Convert the decimal number to a binary value, one digit at
a time. Watch out for overflow. */
unsigned long value = 0;
for ( ; *ptr ; ptr += 1)
if (isdigit(*ptr)) {
unsigned long tmp = value * 10 + (*ptr - '0');
if (tmp < value)
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric decimal constant ``"
<< digits << "'' is too large." << endl;
value *= 10;
value += *ptr - '0';
} else {
@@ -726,7 +851,18 @@ static verinum*make_dec_with_size(unsigned size, bool fixed, const char*ptr)
value /= 2;
}
return new verinum(bits, size, fixed);
/* If we run out of bits to hold the value, but there are
still valueable bits in the number, print a warning. */
if (value != 0)
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric decimal constant ``" << digits <<
"'' truncated to " << size << " bits." << endl;
verinum*out = new verinum(bits, size, fixed);
out->has_sign(signed_flag);
delete[]bits;
return out;
}
static verinum*make_sized_dec(const char*txt)
@@ -739,7 +875,6 @@ static verinum*make_sized_dec(const char*txt)
assert(*ptr == '\'');
ptr += 1;
assert(tolower(*ptr) == 'd');
return make_dec_with_size(size, true, ptr);
}
@@ -749,8 +884,111 @@ static verinum*make_unsized_dec(const char*txt)
return make_dec_with_size(INTEGER_WIDTH, false, txt+1);
}
/*
* The timescale parameter has the form:
* " <num> xs / <num> xs"
*/
static void process_timescale(const char*txt)
{
unsigned num;
const char*cp = txt + strspn(txt, " \t");
char*tmp;
const char*ctmp;
static int yywrap()
int unit = 0;
int prec = 0;
num = strtoul(cp, &tmp, 10);
if (num == 0) {
VLerror(yylloc, "Invalid timescale string.");
return;
}
while (num >= 10) {
unit += 1;
num /= 10;
}
if (num != 1) {
VLerror(yylloc, "Invalid timescale unit number.");
return;
}
cp = tmp;
cp += strspn(cp, " \t");
ctmp = cp + strcspn(cp, " \t/");
if (strncmp("s", cp, ctmp-cp) == 0) {
unit -= 0;
} else if (strncmp("ms", cp, ctmp-cp) == 0) {
unit -= 3;
} else if (strncmp("us", cp, ctmp-cp) == 0) {
unit -= 6;
} else if (strncmp("ns", cp, ctmp-cp) == 0) {
unit -= 9;
} else if (strncmp("ps", cp, ctmp-cp) == 0) {
unit -= 12;
} else if (strncmp("fs", cp, ctmp-cp) == 0) {
unit -= 15;
} else {
VLerror(yylloc, "Invalid timescale unit of measurement");
return;
}
cp = ctmp;
cp += strspn(cp, " \t/");
num = strtoul(cp, &tmp, 10);
if (num == 0) {
VLerror(yylloc, "Invalid timescale string.");
return;
}
assert(num);
while (num >= 10) {
prec += 1;
num /= 10;
}
if (num != 1) {
VLerror(yylloc, "Invalid timescale precision number.");
return;
}
cp = tmp;
cp += strspn(cp, " \t");
ctmp = cp + strcspn(cp, " \t\r");
if (strncmp("s", cp, ctmp-cp) == 0) {
prec -= 0;
} else if (strncmp("ms", cp, ctmp-cp) == 0) {
prec -= 3;
} else if (strncmp("us", cp, ctmp-cp) == 0) {
prec -= 6;
} else if (strncmp("ns", cp, ctmp-cp) == 0) {
prec -= 9;
} else if (strncmp("ps", cp, ctmp-cp) == 0) {
prec -= 12;
} else if (strncmp("fs", cp, ctmp-cp) == 0) {
prec -= 15;
} else {
VLerror(yylloc, "Invalid timescale precision units of measurement");
return;
}
pform_set_timescale(unit, prec);
}
int yywrap()
{
return 1;
}
@@ -773,8 +1011,7 @@ static void line_directive()
strncpy(buf, qt1, qt2-qt1);
buf[qt2-qt1] = 0;
delete[]yylloc.text;
yylloc.text = buf;
yylloc.text = set_file_name(buf);
qt2 += 1;
yylloc.first_line = strtoul(qt2,0,0);
@@ -801,13 +1038,19 @@ static void line_directive2()
strncpy(buf, qt1, qt2-qt1);
buf[qt2-qt1] = 0;
delete[]yylloc.text;
yylloc.text = buf;
yylloc.text = set_file_name(buf);
}
static void reset_lexor()
{
yyrestart(vl_input);
yylloc.first_line = 1;
yylloc.text = strdup(vl_file.c_str());
/* Start the file_names list. From here on, as I get a file
name, I will add it to this list. Only add the name if it
is not already in the list. */
file_names = new struct file_name_cell;
file_names->text = strdup(vl_file.c_str());
file_names->next = 0;
yylloc.text = file_names->text;
}
-230
View File
@@ -1,230 +0,0 @@
/* 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;
}
+17 -5
View File
@@ -4,12 +4,10 @@
#include "parse_misc.h"
#include "parse.h"
#include <string.h>
#include "lexor_keyword.h"
%}
struct Keywords {
char *name;
int tokenType;
} Keywords;
struct lexor_keyword { const char*name; int tokenType; };
%%
always, K_always
and, K_and
@@ -51,6 +49,7 @@ input, K_input
integer, K_integer
join, K_join
large, K_large
localparam, K_localparam
macromodule, K_macromodule
medium, K_medium
module, K_module
@@ -72,6 +71,8 @@ pull1, K_pull1
pulldown, K_pulldown
pullup, K_pullup
rcmos, K_rcmos
real, K_real
realtime, K_realtime
reg, K_reg
release, K_release
repeat, K_repeat
@@ -81,6 +82,7 @@ rtran, K_rtran
rtranif0, K_rtranif0
rtranif1, K_rtranif1
scalered, K_scalered
signed, K_signed
small, K_small
specify, K_specify
specparam, K_specparam
@@ -109,4 +111,14 @@ while, K_while
wire, K_wire
wor, K_wor
xnor, K_xnor
xor, K_xor
xor, K_xor
%%
int lexor_keyword_code(const char*str, unsigned nstr)
{
const struct lexor_keyword*rc = check_identifier(str, nstr);
if (rc == 0)
return IDENTIFIER;
else
return rc->tokenType;
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef __lexor_keyword_H
#define __lexor_keyword_H
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: lexor_keyword.h,v 1.1 2000/03/12 17:09:41 steve Exp $"
#endif
extern int lexor_keyword_code (const char*str, unsigned len);
/*
* $Log: lexor_keyword.h,v $
* Revision 1.1 2000/03/12 17:09:41 steve
* Support localparam.
*
*/
#endif
+131
View File
@@ -0,0 +1,131 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: link_const.cc,v 1.7 2000/11/20 01:41:12 steve Exp $"
#endif
# include "netlist.h"
# include "netmisc.h"
/*
* Scan the link for drivers. If there are only constant drivers, then
* the nexus has a known constant value. If there is a supply net,
* then the nexus again has a known constant value.
*/
bool link_drivers_constant(const Link&lnk)
{
const Nexus*nex = lnk.nexus();
bool flag = true;
for (const Link*cur = nex->first_nlink()
; cur ; cur = cur->next_nlink()) {
if (cur == &lnk)
continue;
if (cur->get_dir() == Link::INPUT)
continue;
/* If the link is PASSIVE then it doesn't count as a
driver if its initial value is Vz. This is pertinant
because REGs are PASSIVE but can receive values from
procedural assignments. */
if ((cur->get_dir() == Link::PASSIVE)
&& (cur->get_init() == verinum::Vz))
continue;
if (! dynamic_cast<const NetConst*>(cur->get_obj()))
flag = false;
/* If there is a supply net, then this nexus will have a
constant value independent of any drivers. */
if (const NetNet*sig = dynamic_cast<const NetNet*>(cur->get_obj()))
switch (sig->type()) {
case NetNet::SUPPLY0:
case NetNet::SUPPLY1:
return true;
default:
break;
}
}
return flag;
}
verinum::V driven_value(const Link&lnk)
{
verinum::V val = lnk.get_init();
const Nexus*nex = lnk.nexus();
for (const Link*cur = nex->first_nlink()
; cur ; cur = cur->next_nlink()) {
const NetConst*obj;
const NetNet*sig;
if (obj = dynamic_cast<const NetConst*>(cur->get_obj())) {
val = obj->value(cur->get_pin());
} else if (sig = dynamic_cast<const NetNet*>(cur->get_obj())) {
if (sig->type() == NetNet::SUPPLY0)
return verinum::V0;
if (sig->type() == NetNet::SUPPLY1)
return verinum::V1;
}
}
return val;
}
/*
* $Log: link_const.cc,v $
* Revision 1.7 2000/11/20 01:41:12 steve
* Whoops, return the calculated constant value rom driven_value.
*
* Revision 1.6 2000/11/20 00:58:40 steve
* Add support for supply nets (PR#17)
*
* Revision 1.5 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.4 2000/06/25 19:59:42 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
* Revision 1.3 2000/05/14 17:55:04 steve
* Support initialization of FF Q value.
*
* Revision 1.2 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.1 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
*/
+103 -101
View File
@@ -1,6 +1,6 @@
const char COPYRIGHT[] =
"Copyright (c) 1998-1999 Stephen Williams ([email protected])";
"Copyright (c) 1998-2000 Stephen Williams ([email protected])";
/*
* This source code is free software; you can redistribute it
@@ -18,8 +18,8 @@ const char COPYRIGHT[] =
* 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: main.cc,v 1.26 1999/11/29 17:02:21 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: main.cc,v 1.39 2000/11/22 20:48:32 steve Exp $"
#endif
const char NOTICE[] =
@@ -50,6 +50,7 @@ const char NOTICE[] =
# include "pform.h"
# include "netlist.h"
# include "target.h"
# include "compiler.h"
const char VERSION[] = "$Name: $ $State: Exp $";
@@ -58,6 +59,12 @@ string start_module = "";
map<string,string> flags;
/*
* These are the warning enable flags.
*/
bool warn_implicit = false;
static void parm_to_flagmap(const string&flag)
{
string key, value;
@@ -80,13 +87,10 @@ extern Design* elaborate(const map<string,Module*>&modules,
const string&root);
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 syn_rules(Design*des);
extern void nodangle(Design*des);
extern void xnfio(Design*des);
extern void xnfsyn(Design*des);
typedef void (*net_func)(Design*);
static struct net_func_map {
@@ -94,13 +98,10 @@ static struct net_func_map {
void (*func)(Design*);
} func_table[] = {
{ "cprop", &cprop },
{ "nobufz", &nobufz },
{ "nodangle",&nodangle },
{ "propinit",&propinit },
{ "sigfold", &sigfold },
{ "synth", &synth },
{ "syn-rules", &syn_rules },
{ "xnfio", &xnfio },
{ "xnfsyn", &xnfsyn },
{ 0, 0 }
};
@@ -118,13 +119,18 @@ int main(int argc, char*argv[])
{
bool help_flag = false;
const char* net_path = 0;
const char* out_path = 0;
const char* pf_path = 0;
const char* warn_en = "";
int opt;
unsigned flag_errors = 0;
queue<net_func> net_func_queue;
while ((opt = getopt(argc, argv, "F:f:hN:o:P:s:t:v")) != EOF) switch (opt) {
flags["VPI_MODULE_LIST"] = "system";
flags["-o"] = "a.out";
min_typ_max_flag = TYP;
min_typ_max_warn = 10;
while ((opt = getopt(argc, argv, "F:f:hm:N:o:P:s:T:t:vW:")) != EOF) switch (opt) {
case 'F': {
net_func tmp = name_to_net_func(optarg);
if (tmp == 0) {
@@ -142,11 +148,14 @@ int main(int argc, char*argv[])
case 'h':
help_flag = true;
break;
case 'm':
flags["VPI_MODULE_LIST"] = flags["VPI_MODULE_LIST"]+","+optarg;
break;
case 'N':
net_path = optarg;
break;
case 'o':
out_path = optarg;
flags["-o"] = optarg;
break;
case 'P':
pf_path = optarg;
@@ -154,6 +163,22 @@ int main(int argc, char*argv[])
case 's':
start_module = optarg;
break;
case 'T':
if (strcmp(optarg,"min") == 0) {
min_typ_max_flag = MIN;
min_typ_max_warn = 0;
} else if (strcmp(optarg,"typ") == 0) {
min_typ_max_flag = TYP;
min_typ_max_warn = 0;
} else if (strcmp(optarg,"max") == 0) {
min_typ_max_flag = MAX;
min_typ_max_warn = 0;
} else {
cerr << "Invalid argument (" << optarg << ") to -T flag."
<< endl;
flag_errors += 1;
}
break;
case 't':
target = optarg;
break;
@@ -162,6 +187,9 @@ int main(int argc, char*argv[])
cout << COPYRIGHT << endl;
cout << endl << NOTICE << endl;
return 0;
case 'W':
warn_en = optarg;
break;
default:
flag_errors += 1;
break;
@@ -185,6 +213,15 @@ int main(int argc, char*argv[])
return 1;
}
/* Scan the warnings enable string for warning flags. */
for (const char*cp = warn_en ; *cp ; cp += 1) switch (*cp) {
case 'i':
warn_implicit = true;
break;
default:
break;
}
/* Parse the input. Make the pform. */
map<string,Module*> modules;
map<string,PUdp*> primitives;
@@ -210,6 +247,11 @@ int main(int argc, char*argv[])
return rc;
}
/* If the user did not give a specific module to start with,
then look for the single module that has no ports. If there
are multiple modules with no ports, then give up. */
if (start_module == "") {
for (map<string,Module*>::iterator mod = modules.begin()
; mod != modules.end()
@@ -226,20 +268,36 @@ int main(int argc, char*argv[])
}
}
/* Select a root module, and elaborate the design. */
/* If the previous attempt to find a start module failed, but
there is only one module, then just let the user get away
with it. */
if ((start_module == "") && (modules.size() == 1)) {
map<string,Module*>::iterator mod = modules.begin();
Module*cur = (*mod).second;
start_module = cur->get_name();
}
/* If there is *still* no guess for the root module, then give
up completely, and complain. */
if (start_module == "") {
cerr << "No top level modules, and no -s option." << endl;
return 1;
}
/* On with the process of elaborating the module. */
Design*des = elaborate(modules, primitives, start_module);
if (des == 0) {
cerr << "Unable to elaborate module " << start_module <<
"." << endl;
cerr << start_module << ": error: "
<< "Unable to elaborate module." << endl;
return 1;
}
if (des->errors) {
cerr << des->errors << " error(s) elaborating design." << endl;
cerr << start_module << ": error: " << des->errors
<< " elaborating module." << endl;
return des->errors;
}
@@ -258,24 +316,9 @@ int main(int argc, char*argv[])
}
bool emit_rc;
if (out_path) {
ofstream out;
out.open(out_path);
if (! out.is_open()) {
cerr << "Unable to open " << out_path << " for writing."
<< endl;
return 1;
}
emit_rc = emit(out, des, target);
} else {
emit_rc = emit(cout, des, target);
}
bool emit_rc = emit(des, target);
if (!emit_rc) {
cerr << "internal error: Code generation had errors." << endl;
cerr << "error: Code generation had errors." << endl;
return 1;
}
@@ -284,80 +327,39 @@ 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.39 2000/11/22 20:48:32 steve
* Allow sole module to be a root.
*
* 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.38 2000/09/12 01:17:40 steve
* Version information for vlog_vpi_info.
*
* 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.37 2000/08/09 03:43:45 steve
* Move all file manipulation out of target class.
*
* Revision 1.23 1999/09/22 16:57:23 steve
* Catch parallel blocks in vvm emit.
* Revision 1.36 2000/07/29 17:58:21 steve
* Introduce min:typ:max support.
*
* Revision 1.22 1999/08/03 04:14:49 steve
* Parse into pform arbitrarily complex module
* port declarations.
* Revision 1.35 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Revision 1.21 1999/07/18 05:52:46 steve
* xnfsyn generates DFF objects for XNF output, and
* properly rewrites the Design netlist in the process.
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.20 1999/07/17 22:01:13 steve
* Add the functor interface for functor transforms.
* Revision 1.34 2000/05/13 20:55:47 steve
* Use yacc based synthesizer.
*
* Revision 1.19 1999/07/10 23:29:21 steve
* pform even on parse errors.
* Revision 1.33 2000/05/08 05:29:43 steve
* no need for nobufz functor.
*
* Revision 1.18 1999/06/19 03:46:42 steve
* Add the -v switch.
* Revision 1.32 2000/05/03 22:14:31 steve
* More features of ivl available through iverilog.
*
* Revision 1.17 1999/06/17 05:33:12 steve
* Redundant declaration of pform_parse.
*
* Revision 1.16 1999/06/15 03:44:53 steve
* Get rid of the STL vector template.
*
* Revision 1.15 1999/05/05 03:27:15 steve
* More intelligent selection of module to elaborate.
*
* Revision 1.14 1999/04/23 04:34:32 steve
* Make debug output file parameters.
*
* Revision 1.13 1999/02/01 00:26:49 steve
* Carry some line info to the netlist,
* Dump line numbers for processes.
* Elaborate prints errors about port vector
* width mismatch
* Emit better handles null statements.
*
* Revision 1.12 1999/01/24 01:35:36 steve
* Support null target for generating no output.
*
* Revision 1.11 1998/12/20 02:05:41 steve
* Function to calculate wire initial value.
*
* Revision 1.10 1998/12/09 04:02:47 steve
* Support the include directive.
*
* Revision 1.9 1998/12/07 04:53:17 steve
* Generate OBUF or IBUF attributes (and the gates
* to garry them) where a wire is a pad. This involved
* figuring out enough of the netlist to know when such
* was needed, and to generate new gates and signales
* to handle what's missing.
*
* Revision 1.8 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,
* Signal folding is aware of attributes, and
* the XNF target can dump UDP objects based on LCA
* attributes.
* Revision 1.31 2000/04/12 20:02:53 steve
* Finally remove the NetNEvent and NetPEvent classes,
* Get synthesis working with the NetEvWait class,
* and get started supporting multiple events in a
* wait in vvm.
*/
+24 -3
View File
@@ -16,8 +16,8 @@
* 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: mangle.cc,v 1.2 1999/02/15 05:52:50 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: mangle.cc,v 1.5 2000/12/11 01:06:24 steve Exp $"
#endif
# include "target.h"
@@ -32,7 +32,7 @@ string mangle(const string&str)
string tmp = str;
while (tmp.length() > 0) {
size_t pos = tmp.find_first_of(".<");
size_t pos = tmp.find_first_of(".<\\[]");
if (pos > tmp.length())
pos = tmp.length();
@@ -55,6 +55,18 @@ string mangle(const string&str)
tmp = tmp.substr(1);
res << "_";
break;
case '\\':
res << "$$";
tmp = tmp.substr(1);
break;
case '[':
res << "$lb$";
tmp = tmp.substr(1);
break;
case ']':
res << "$rb$";
tmp = tmp.substr(1);
break;
}
}
res << ends;
@@ -63,6 +75,15 @@ string mangle(const string&str)
/*
* $Log: mangle.cc,v $
* Revision 1.5 2000/12/11 01:06:24 steve
* Mangle [] characters. (PR#67)
*
* Revision 1.4 2000/10/25 23:21:37 steve
* mangle the backslash to a dollar.
*
* Revision 1.3 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 1999/02/15 05:52:50 steve
* Mangle that handles device instance numbers.
*
+46
View File
@@ -0,0 +1,46 @@
#ifndef __named_H
#define __named_H
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: named.h,v 1.2 2000/02/23 02:56:54 steve Exp $"
#endif
# include <string>
/*
* There are lots of places where names are attached to objects. This
* simple template expresses the lot.
*/
template <class T> struct named {
string name;
T parm;
};
/*
* $Log: named.h,v $
* Revision 1.2 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 2000/01/09 05:50:49 steve
* Support named parameter override lists.
*
*/
#endif
+195
View File
@@ -0,0 +1,195 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: net_assign.cc,v 1.6 2000/10/18 20:04:39 steve Exp $"
#endif
# include "netlist.h"
/*
* NetAssign
*/
unsigned count_lval_width(const NetAssign_*idx)
{
unsigned wid = 0;
while (idx) {
wid += idx->lwidth();
idx = idx->more;
}
return wid;
}
NetAssign_::NetAssign_(const string&n, unsigned w)
: NetNode(n, w), bmux_(0)
{
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
pin(idx).set_dir(Link::OUTPUT);
pin(idx).set_name("P", idx);
}
more = 0;
}
NetAssign_::~NetAssign_()
{
assert( more == 0 );
if (bmux_) delete bmux_;
}
void NetAssign_::set_bmux(NetExpr*r)
{
assert(bmux_ == 0);
bmux_ = r;
}
const NetExpr* NetAssign_::bmux() const
{
return bmux_;
}
unsigned NetAssign_::lwidth() const
{
if (bmux_) return 1;
else return pin_count();
}
NetAssignBase::NetAssignBase(NetAssign_*lv, NetExpr*rv)
: lval_(lv), rval_(rv)
{
}
NetAssignBase::~NetAssignBase()
{
if (rval_) delete rval_;
while (lval_) {
NetAssign_*tmp = lval_;
lval_ = tmp->more;
tmp->more = 0;
delete tmp;
}
}
NetExpr* NetAssignBase::rval()
{
return rval_;
}
const NetExpr* NetAssignBase::rval() const
{
return rval_;
}
void NetAssignBase::set_rval(NetExpr*r)
{
if (rval_) delete rval_;
rval_ = r;
}
NetAssign_* NetAssignBase::l_val(unsigned idx)
{
NetAssign_*cur = lval_;
while (idx > 0) {
if (cur == 0)
return cur;
cur = cur->more;
idx -= 1;
}
assert(idx == 0);
return cur;
}
const NetAssign_* NetAssignBase::l_val(unsigned idx) const
{
const NetAssign_*cur = lval_;
while (idx > 0) {
if (cur == 0)
return cur;
cur = cur->more;
idx -= 1;
}
assert(idx == 0);
return cur;
}
unsigned NetAssignBase::l_val_count() const
{
const NetAssign_*cur = lval_;
unsigned cnt = 0;
while (cur) {
cnt += 1;
cur = cur->more;
}
return cnt;
}
unsigned NetAssignBase::lwidth() const
{
unsigned sum = 0;
for (NetAssign_*cur = lval_ ; cur ; cur = cur->more)
sum += cur->lwidth();
return sum;
}
NetAssign::NetAssign(NetAssign_*lv, NetExpr*rv)
: NetAssignBase(lv, rv)
{
}
NetAssign::~NetAssign()
{
}
NetAssignNB::NetAssignNB(NetAssign_*lv, NetExpr*rv)
: NetAssignBase(lv, rv)
{
}
NetAssignNB::~NetAssignNB()
{
}
/*
* $Log: net_assign.cc,v $
* Revision 1.6 2000/10/18 20:04:39 steve
* Add ivl_lval_t and support for assignment l-values.
*
* Revision 1.5 2000/09/20 02:53:15 steve
* Correctly measure comples l-values of assignments.
*
* Revision 1.4 2000/09/10 02:18:16 steve
* elaborate complex l-values
*
* Revision 1.3 2000/09/07 00:06:53 steve
* encapsulate access to the l-value expected width.
*
* Revision 1.2 2000/09/02 23:40:13 steve
* Pull NetAssign_ creation out of constructors.
*
* Revision 1.1 2000/09/02 20:54:20 steve
* Rearrange NetAssign to make NetAssign_ separate.
*
*/
+555
View File
@@ -0,0 +1,555 @@
/*
* Copyright (c) 2000Stephen 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) && !defined(macintosh)
#ident "$Id: net_design.cc,v 1.17 2000/12/16 01:45:48 steve Exp $"
#endif
/*
* This source file contains all the implementations of the Design
* class declared in netlist.h.
*/
# include "netlist.h"
# include "util.h"
# include <strstream>
static string parse_last_name(string&path)
{
unsigned pos = path.rfind('.');
if (pos > path.length()) {
string res = path;
path = "";
return res;
}
string res = path.substr(pos+1, path.length());
path = path.substr(0, pos);
return res;
}
Design:: Design()
: errors(0), root_scope_(0), nodes_(0), procs_(0), lcounter_(0)
{
procs_idx_ = 0;
des_precision_ = 0;
}
Design::~Design()
{
}
string Design::local_symbol(const string&path)
{
strstream res;
res << "_L" << (lcounter_++) << ends;
return path + "." + res.str();
}
void Design::set_precision(int val)
{
if (val < des_precision_)
des_precision_ = val;
}
int Design::get_precision() const
{
return des_precision_;
}
unsigned long Design::scale_to_precision(unsigned long val,
const NetScope*scope) const
{
int units = scope->time_unit();
assert( units >= des_precision_ );
while (units > des_precision_) {
units -= 1;
val *= 10;
}
return val;
}
NetScope* Design::make_root_scope(const string&root)
{
assert(root_scope_ == 0);
root_scope_ = new NetScope(0, root, NetScope::MODULE);
root_scope_->set_module_name(root.c_str());
return root_scope_;
}
NetScope* Design::find_root_scope()
{
assert(root_scope_);
return root_scope_;
}
const NetScope* Design::find_root_scope() const
{
assert(root_scope_);
return root_scope_;
}
/*
* This method locates a scope in the design, given its rooted
* heirarchical name. Each component of the key is used to scan one
* more step down the tree until the name runs out or the search
* fails.
*/
NetScope* Design::find_scope(const string&key) const
{
if (key == root_scope_->name())
return root_scope_;
string path = key;
string root = parse_first_name(path);
NetScope*cur = root_scope_;
if (root != cur->name())
return 0;
while (cur) {
string next = parse_first_name(path);
cur = cur->child(next);
if (path == "") return cur;
}
return cur;
}
/*
* This is a relative lookup of a scope by name. The starting point is
* the scope parameter is the place within which I start looking for
* the scope. If I do not find the scope within the passed scope,
* start looking in parent scopes until I find it, or I run out of
* parent scopes.
*/
NetScope* Design::find_scope(NetScope*scope, const string&name) const
{
assert(scope);
for ( ; scope ; scope = scope->parent()) {
string path = name;
string key = parse_first_name(path);
NetScope*cur = scope;
do {
cur = cur->child(key);
if (cur == 0) break;
key = parse_first_name(path);
} while (key != "");
if (cur) return cur;
}
// Last chance. Look for the name starting at the root.
return find_scope(name);
}
/*
* Find a parameter from within a specified context. If the name is
* not here, keep looking up until I run out of up to look at. The
* method works by scanning scopes, starting with the passed scope and
* working up towards the root, looking for the named parameter. The
* name in this case can be hierarchical, so there is an inner loop to
* follow the scopes of the name down to to key.
*/
const NetExpr* Design::find_parameter(const NetScope*scope,
const string&name) const
{
for ( ; scope ; scope = scope->parent()) {
string path = name;
string key = parse_first_name(path);
const NetScope*cur = scope;
while (path != "") {
cur = cur->child(key);
if (cur == 0) break;
key = parse_first_name(path);
}
if (cur == 0) continue;
if (const NetExpr*res = cur->get_parameter(key))
return res;
}
return 0;
}
/*
* This method runs through the scope, noticing the defparam
* statements that were collected during the elaborate_scope pass and
* applying them to the target parameters. The implementation actually
* works by using a specialized method from the NetScope class that
* does all the work for me.
*/
void Design::run_defparams()
{
root_scope_->run_defparams(this);
}
void NetScope::run_defparams(Design*des)
{
NetScope*cur = sub_;
while (cur) {
cur->run_defparams(des);
cur = cur->sib_;
}
map<string,NetExpr*>::const_iterator pp;
for (pp = defparams.begin() ; pp != defparams.end() ; pp ++ ) {
NetExpr*val = (*pp).second;
string path = (*pp).first;
string name = parse_last_name(path);
NetScope*targ_scope = des->find_scope(this, path);
if (targ_scope == 0) {
cerr << val->get_line() << ": warning: scope of " <<
path << "." << name << " not found." << endl;
continue;
}
val = targ_scope->set_parameter(name, val);
if (val == 0) {
cerr << val->get_line() << ": warning: parameter "
<< name << " not found in " << targ_scope->name()
<< "." << endl;
} else {
delete val;
}
}
}
void Design::evaluate_parameters()
{
root_scope_->evaluate_parameters(this);
}
void NetScope::evaluate_parameters(Design*des)
{
NetScope*cur = sub_;
while (cur) {
cur->evaluate_parameters(des);
cur = cur->sib_;
}
// Evaluate the parameter values. The parameter expressions
// have already been elaborated and replaced by the scope
// scanning code. Now the parameter expression can be fully
// evaluated, or it cannot be evaluated at all.
typedef map<string,NetExpr*>::iterator mparm_it_t;
for (mparm_it_t cur = parameters_.begin()
; cur != parameters_.end() ; cur ++) {
// Get the NetExpr for the parameter.
NetExpr*expr = (*cur).second;
assert(expr);
// If it's already a NetEConst, then this parameter is done.
if (dynamic_cast<const NetEConst*>(expr))
continue;
// Try to evaluate the expression.
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second->get_line() << ": internal error: "
"unable to evaluate parm expression: " <<
*expr << endl;
des->errors += 1;
continue;
}
// The evaluate worked, replace the old expression with
// this constant value.
assert(nexpr);
delete expr;
(*cur).second = nexpr;
}
}
string Design::get_flag(const string&key) const
{
map<string,string>::const_iterator tmp = flags_.find(key);
if (tmp == flags_.end())
return "";
else
return (*tmp).second;
}
/*
* This method looks for a signal (reg, wire, whatever) starting at
* the specified scope. If the name is hierarchical, it is split into
* scope and name and the scope used to find the proper starting point
* for the real search.
*
* It is the job of this function to properly implement Verilog scope
* rules as signals are concerned.
*/
NetNet* Design::find_signal(NetScope*scope, const string&name)
{
assert(scope);
/* If the name has a path attached to it, parse it off and use
that to locate the desired starting scope. */
string path = name;
string key = parse_last_name(path);
if (path != "")
scope = find_scope(scope, path);
/* Now from the starting point, scan upwards until we find the
signal or we find a module boundary. */
while (scope) {
if (NetNet*net = scope->find_signal(key))
return net;
if (scope->type() == NetScope::MODULE)
break;
scope = scope->parent();
}
return 0;
}
NetMemory* Design::find_memory(NetScope*scope, const string&name)
{
assert(scope);
/* If the name has a path attached to it, parse it off and use
that to locate the desired scope. */
string path = name;
string key = parse_last_name(path);
if (path != "")
scope = find_scope(scope, path);
while (scope) {
if (NetMemory*mem = scope->find_memory(key))
return mem;
scope = scope->parent();
}
return 0;
}
void Design::find_symbol(NetScope*scope, const string&name,
NetNet*&sig, NetMemory*&mem)
{
sig = 0;
mem = 0;
/* If the name has a path attached to it, parse it off and use
that to locate the desired scope. Then locate the key
within that scope. */
string path = name;
string key = parse_last_name(path);
if (path != "")
scope = find_scope(scope, path);
/* If there is no path, then just search upwards for the key. */
while (scope) {
if (NetNet*cur = scope->find_signal(key)) {
sig = cur;
return;
}
if (NetMemory*cur = scope->find_memory(key)) {
mem = cur;
return;
}
scope = scope->parent();
}
}
NetFuncDef* Design::find_function(NetScope*scope, const string&name)
{
assert(scope);
NetScope*func = find_scope(scope, name);
if (func && (func->type() == NetScope::FUNC))
return func->func_def();
return 0;
}
NetFuncDef* Design::find_function(const string&key)
{
NetScope*func = find_scope(key);
if (func && (func->type() == NetScope::FUNC))
return func->func_def();
return 0;
}
NetTaskDef* Design::find_task(NetScope*scope, const string&name)
{
NetScope*task = find_scope(scope, name);
if (task && (task->type() == NetScope::TASK))
return task->task_def();
return 0;
}
NetTaskDef* Design::find_task(const string&key)
{
NetScope*task = find_scope(key);
if (task && (task->type() == NetScope::TASK))
return task->task_def();
return 0;
}
void Design::add_node(NetNode*net)
{
assert(net->design_ == 0);
if (nodes_ == 0) {
net->node_next_ = net;
net->node_prev_ = net;
} else {
net->node_next_ = nodes_->node_next_;
net->node_prev_ = nodes_;
net->node_next_->node_prev_ = net;
net->node_prev_->node_next_ = net;
}
nodes_ = net;
net->design_ = this;
}
void Design::del_node(NetNode*net)
{
assert(net->design_ == this);
if (nodes_ == net)
nodes_ = net->node_prev_;
if (nodes_ == net) {
nodes_ = 0;
} else {
net->node_next_->node_prev_ = net->node_prev_;
net->node_prev_->node_next_ = net->node_next_;
}
net->design_ = 0;
}
void Design::add_process(NetProcTop*pro)
{
pro->next_ = procs_;
procs_ = pro;
}
void Design::delete_process(NetProcTop*top)
{
assert(top);
if (procs_ == top) {
procs_ = top->next_;
} else {
NetProcTop*cur = procs_;
while (cur->next_ != top) {
assert(cur->next_);
cur = cur->next_;
}
cur->next_ = top->next_;
}
if (procs_idx_ == top)
procs_idx_ = top->next_;
delete top;
}
/*
* $Log: net_design.cc,v $
* Revision 1.17 2000/12/16 01:45:48 steve
* Detect recursive instantiations (PR#2)
*
* Revision 1.16 2000/09/24 17:41:13 steve
* fix null pointer when elaborating undefined task.
*
* Revision 1.15 2000/08/26 00:54:03 steve
* Get at gate information for ivl_target interface.
*
* Revision 1.14 2000/08/12 17:59:48 steve
* Limit signal scope search at module boundaries.
*
* Revision 1.13 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.12 2000/07/23 02:41:32 steve
* Excessive assert.
*
* Revision 1.11 2000/07/22 22:09:03 steve
* Parse and elaborate timescale to scopes.
*
* Revision 1.10 2000/07/16 04:56:08 steve
* Handle some edge cases during node scans.
*
* Revision 1.9 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.8 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
* Revision 1.7 2000/05/02 03:13:31 steve
* Move memories to the NetScope object.
*
* Revision 1.6 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.5 2000/04/28 16:50:53 steve
* Catch memory word parameters to tasks.
*
* Revision 1.4 2000/04/10 05:26:06 steve
* All events now use the NetEvent class.
*
* Revision 1.3 2000/03/11 03:25:52 steve
* Locate scopes in statements.
*
* Revision 1.2 2000/03/10 06:20:48 steve
* Handle defparam to partial hierarchical names.
*
* Revision 1.1 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
*/
+489
View File
@@ -0,0 +1,489 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: net_event.cc,v 1.12 2000/12/15 17:45:07 steve Exp $"
#endif
# include "netlist.h"
NetEvent::NetEvent(const string&n)
: name_(0)
{
scope_ = 0;
snext_ = 0;
probes_ = 0;
trig_ = 0;
waitref_ = 0;
wlist_ = 0;
name_ = new char[n.length()+1];
strcpy(name_, n.c_str());
}
NetEvent::~NetEvent()
{
assert(waitref_ == 0);
if (scope_) scope_->rem_event(this);
while (probes_) {
NetEvProbe*tmp = probes_->enext_;
delete probes_;
probes_ = tmp;
}
delete[]name_;
}
const char* NetEvent::name() const
{
return name_;
}
string NetEvent::full_name() const
{
assert(scope_);
return scope_->name() + "." + name_;
}
unsigned NetEvent::nprobe() const
{
unsigned cnt = 0;
NetEvProbe*cur = probes_;
while (cur) {
cnt += 1;
cur = cur->enext_;
}
return cnt;
}
NetEvProbe* NetEvent::probe(unsigned idx)
{
NetEvProbe*cur = probes_;
while (cur && idx) {
cur = cur->enext_;
idx -= 1;
}
return cur;
}
unsigned NetEvent::ntrig() const
{
unsigned cnt = 0;
NetEvTrig*cur = trig_;
while (cur) {
cnt += 1;
cur = cur->enext_;
}
return cnt;
}
unsigned NetEvent::nwait() const
{
return waitref_;
}
/*
* A "similar" event is one that has an identical non-nil set of
* probes.
*/
NetEvent* NetEvent::find_similar_event()
{
if (probes_ == 0)
return 0;
struct table_s {
NetEvent*ev;
bool mark;
} *table;
//NetEvent**cand;
//bool*cflg;
unsigned max_cand = 0, ncand = 0;
NetEvProbe*cur = probes_;
/* Get an estimate of the number of candidate events there
are. To get it, count the number of probes that are
connected to my first probe. Since there is no more then
one NetEvent per NetEvProbe, this is the maximum number of
similar events possible.
Once we get that count, allocate the arrays needed to
account for these events. */
for (NetNode*idx = cur->next_node()
; idx && (idx != cur) ; idx = idx->next_node()) {
NetEvProbe*tmp = dynamic_cast<NetEvProbe*>(idx);
if (tmp == 0)
continue;
if (tmp->edge() != cur->edge())
continue;
max_cand += 1;
}
table = new struct table_s[max_cand];
/* First, locate all the candidate events from my first
probe. Look for all the NetEvProbe objects connected to my
probe (that are the same edge) and save the NetEvent that
that probe drives. */
for (NetNode*idx = cur->next_node()
; idx && (idx != cur) ; idx = idx->next_node()) {
NetEvProbe*tmp = dynamic_cast<NetEvProbe*>(idx);
if (tmp == 0)
continue;
if (tmp->edge() != cur->edge())
continue;
table[ncand++].ev = tmp->event();
assert(ncand <= max_cand);
}
/* All the events in the cand array are now known to connect
through at least one NetEvProbe. Now go through all my
remaining probes and check that each candidate event is
also connected (through a NetEvProbe) to me.
By the time I finish this scan, only NetEvents that have
equivilent NetEvProbes remain. These are candidates. The
events may have *more* NetEvProbes then me, I'll catch
those later. */
for (cur = cur->enext_ ; cur && ncand ; cur = cur->enext_) {
for (unsigned idx = 0 ; idx < ncand ; idx += 1)
table[idx].mark = false;
/* For this probe, look for other probes connected to it
and find the event connected to it. Mark that event
as connected to this probe. */
for (NetNode*idx = cur->next_node()
; idx && (idx != cur) ; idx = idx->next_node()) {
NetEvProbe*tmp = dynamic_cast<NetEvProbe*>(idx);
if (tmp == 0)
continue;
if (tmp->edge() != cur->edge())
continue;
for (unsigned srch = 0 ; srch < ncand ; srch += 1)
if (table[srch].ev == tmp->event()) {
table[srch].mark = true;
break;
}
}
/* Look for all the candidates that did not connect to
this probe (cflg is false) and eliminate them. */
for (unsigned idx = 0 ; idx < ncand ; ) {
if (table[idx].mark) {
idx += 1;
continue;
}
for (unsigned tmp = idx ; (tmp+1) < ncand ; tmp += 1)
table[tmp] = table[tmp+1];
ncand -= 1;
}
}
/* Scan the remaining candidates for a similar
NetEvent. Eliminate NetEvent objects that have more
NetEvProbe objects then I, because those have a proper
superset of my probes and were not eliminated by the
previous scan.
As soon as we find a similar event, we're done. */
for (unsigned idx = 0 ; idx < ncand ; idx += 1) {
if (table[idx].ev->nprobe() == nprobe()) {
NetEvent*res = table[idx].ev;
delete[]table;
return res;
}
}
/* Oops, fell off the list without finding a result. return nil. */
delete[]table;
return 0;
}
void NetEvent::replace_event(NetEvent*that)
{
while (wlist_) {
wlist_->obj->replace_event(this, that);
}
}
NetEvTrig::NetEvTrig(NetEvent*ev)
: event_(ev)
{
enext_ = event_->trig_;
event_->trig_ = this;
}
NetEvTrig::~NetEvTrig()
{
if (event_->trig_ == this) {
event_->trig_ = enext_;
} else {
NetEvTrig*cur = event_->trig_;
while (cur->enext_ != this) {
assert(cur->enext_);
cur = cur->enext_;
}
cur->enext_ = this->enext_;
}
}
const NetEvent* NetEvTrig::event() const
{
return event_;
}
NetEvProbe::NetEvProbe(const string&n, NetEvent*tgt,
edge_t t, unsigned p)
: NetNode(n, p), event_(tgt), edge_(t)
{
for (unsigned idx = 0 ; idx < p ; idx += 1) {
pin(idx).set_dir(Link::INPUT);
pin(idx).set_name("P", idx);
}
enext_ = event_->probes_;
event_->probes_ = this;
}
NetEvProbe::~NetEvProbe()
{
if (event_->probes_ == this) {
event_->probes_ = enext_;
} else {
NetEvProbe*cur = event_->probes_;
while (cur->enext_ != this) {
assert(cur->enext_);
cur = cur->enext_;
}
cur->enext_ = this->enext_;
}
}
NetEvProbe::edge_t NetEvProbe::edge() const
{
return edge_;
}
NetEvent* NetEvProbe::event()
{
return event_;
}
const NetEvent* NetEvProbe::event() const
{
return event_;
}
NetEvWait::NetEvWait(NetProc*pr)
: statement_(pr), nevents_(0), events_(0)
{
}
NetEvWait::~NetEvWait()
{
if (events_) {
for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) {
NetEvent*tgt = events_[idx];
tgt->waitref_ -= 1;
struct NetEvent::wcell_*tmp = tgt->wlist_;
if (tmp->obj == this) {
tgt->wlist_ = tmp->next;
delete tmp;
} else {
assert(tmp->next);
while (tmp->next->obj != this) {
tmp = tmp->next;
assert(tmp->next);
}
tmp->next = tmp->next->next;
delete tmp;
}
}
delete[]events_;
}
delete statement_;
}
void NetEvWait::add_event(NetEvent*tgt)
{
assert(tgt);
if (nevents_ == 0) {
events_ = new NetEvent*[1];
} else {
NetEvent**tmp = new NetEvent*[nevents_+1];
for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) {
tmp[idx] = events_[idx];
assert(tmp[idx] != tgt);
}
delete[]events_;
events_ = tmp;
}
events_[nevents_] = tgt;
nevents_ += 1;
// Remember to tell the NetEvent that there is someone
// pointing to it.
tgt->waitref_ += 1;
struct NetEvent::wcell_*tmp = new NetEvent::wcell_;
tmp->obj = this;
tmp->next = tgt->wlist_;
tgt->wlist_ = tmp;
}
void NetEvWait::replace_event(NetEvent*src, NetEvent*repl)
{
unsigned idx;
for (idx = 0 ; idx < nevents_ ; idx += 1) {
if (events_[idx] == src)
break;
}
assert(idx < nevents_);
/* First, remove me from the list held by the src NetEvent. */
assert(src->waitref_ > 0);
src->waitref_ -= 1;
struct NetEvent::wcell_*tmp = src->wlist_;
if (tmp->obj == this) {
src->wlist_ = tmp->next;
delete tmp;
} else {
assert(tmp->next);
while (tmp->next->obj != this) {
tmp = tmp->next;
assert(tmp->next);
}
tmp->next = tmp->next->next;
delete tmp;
}
events_[idx] = repl;
// Remember to tell the replacement NetEvent that there is
// someone pointing to it.
repl->waitref_ += 1;
tmp = new NetEvent::wcell_;
tmp->obj = this;
tmp->next = repl->wlist_;
repl->wlist_ = tmp;
}
unsigned NetEvWait::nevents() const
{
return nevents_;
}
const NetEvent* NetEvWait::event(unsigned idx) const
{
assert(idx < nevents_);
return events_[idx];
}
NetEvent* NetEvWait::event(unsigned idx)
{
assert(idx < nevents_);
return events_[idx];
}
NetProc* NetEvWait::statement()
{
return statement_;
}
/*
* $Log: net_event.cc,v $
* Revision 1.12 2000/12/15 17:45:07 steve
* Remove limits from the similar events search.
*
* Revision 1.11 2000/10/04 16:30:39 steve
* Use char8 instead of string to store name.
*
* Revision 1.10 2000/09/19 03:00:36 steve
* Typo stepping ot next probe in delete.
*
* Revision 1.9 2000/07/29 03:55:38 steve
* fix problem coalescing events w/ probes.
*
* Revision 1.8 2000/05/31 02:26:49 steve
* Globally merge redundant event objects.
*
* Revision 1.7 2000/05/27 19:33:23 steve
* Merge similar probes within a module.
*
* Revision 1.6 2000/04/18 04:50:20 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.5 2000/04/16 23:32:18 steve
* Synthesis of comparator in expressions.
*
* Connect the NetEvent and related classes
* together better.
*
* Revision 1.4 2000/04/12 20:02:53 steve
* Finally remove the NetNEvent and NetPEvent classes,
* Get synthesis working with the NetEvWait class,
* and get started supporting multiple events in a
* wait in vvm.
*
* Revision 1.3 2000/04/12 04:23:58 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.2 2000/04/10 05:26:06 steve
* All events now use the NetEvent class.
*
* Revision 1.1 2000/04/04 03:20:15 steve
* Simulate named event trigger and waits.
*
*/
+125
View File
@@ -0,0 +1,125 @@
/*
* Copyright (c) 2000 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.
*
* 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) && !defined(macintosh)
#ident "$Id: net_force.cc,v 1.2 2000/05/12 01:22:41 steve Exp $"
#endif
/*
* This file contains implementatsion of the NetForce, NetRelease,
* NetCAssign and NetDeassign classes. These are similar or related in
* that they handle the procedural continuous assign and force
* statements.
*/
# include "netlist.h"
# include <assert.h>
/*
* Construct the procedural continuous assignment statement. This is a
* bit different from a normal assignment because the the lval is only
* intermittantly connected. The deassign in particular disconnects
* the signals when they are not being assigned anymore. Because of
* this, there is no other reference to the lval to make it stay put
* so we increment the eref.
*
* XXXX I'm not sure this is the right way. Perhaps I should create
* output pins to connect to the netlist? But that would cause the
* link ring to grow, and that is not quite correct either. Hmm...
*/
NetCAssign::NetCAssign(const string&n, NetNet*l)
: NetNode(n, l->pin_count()), lval_(l)
{
lval_->incr_eref();
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
pin(idx).set_dir(Link::INPUT);
pin(idx).set_name("I", idx);
}
}
NetCAssign::~NetCAssign()
{
lval_->decr_eref();
}
const Link& NetCAssign::lval_pin(unsigned idx) const
{
assert(idx < lval_->pin_count());
return lval_->pin(idx);
}
NetDeassign::NetDeassign(NetNet*l)
: lval_(l)
{
lval_->incr_eref();
}
NetDeassign::~NetDeassign()
{
lval_->decr_eref();
}
const NetNet*NetDeassign::lval() const
{
return lval_;
}
NetForce::NetForce(const string&n, NetNet*l)
: NetNode(n, l->pin_count()), lval_(l)
{
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
pin(idx).set_dir(Link::INPUT);
pin(idx).set_name("I", idx);
}
}
NetForce::~NetForce()
{
}
const Link& NetForce::lval_pin(unsigned idx) const
{
assert(idx < lval_->pin_count());
return lval_->pin(idx);
}
NetRelease::NetRelease(NetNet*l)
: lval_(l)
{
}
NetRelease::~NetRelease()
{
}
const NetNet*NetRelease::lval() const
{
return lval_;
}
/*
* $Log: net_force.cc,v $
* Revision 1.2 2000/05/12 01:22:41 steve
* NetCAssign needs to incr_eref its lval to lock it down.
*
* Revision 1.1 2000/05/11 23:37:27 steve
* Add support for procedural continuous assignment.
*
*/
+374
View File
@@ -0,0 +1,374 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: net_link.cc,v 1.4 2000/10/06 23:46:50 steve Exp $"
#endif
# include "netlist.h"
# include <strstream>
# include <string>
# include <typeinfo>
void connect(Link&l, Link&r)
{
assert(&l != &r);
assert(l.nexus_);
assert(r.nexus_);
/* If the links are already connected, then we're done. */
if (l.nexus_ == r.nexus_)
return;
Nexus*tmp = r.nexus_;
while (Link*cur = tmp->first_nlink()) {
tmp->unlink(cur);
l.nexus_->relink(cur);
}
assert(tmp->list_ == 0);
assert(l.is_linked(r));
delete tmp;
}
Link::Link()
: dir_(PASSIVE), drive0_(STRONG), drive1_(STRONG), init_(verinum::Vx),
inst_(0), next_(0), nexus_(0)
{
(new Nexus()) -> relink(this);
}
Link::~Link()
{
assert(nexus_);
Nexus*tmp = nexus_;
nexus_->unlink(this);
if (tmp->list_ == 0)
delete tmp;
}
Nexus* Link::nexus()
{
return nexus_;
}
const Nexus* Link::nexus() const
{
return nexus_;
}
void Link::set_dir(DIR d)
{
dir_ = d;
}
Link::DIR Link::get_dir() const
{
return dir_;
}
void Link::drive0(Link::strength_t str)
{
drive0_ = str;
}
void Link::drive1(Link::strength_t str)
{
drive1_ = str;
}
Link::strength_t Link::drive0() const
{
return drive0_;
}
Link::strength_t Link::drive1() const
{
return drive1_;
}
void Link::set_init(verinum::V val)
{
init_ = val;
}
verinum::V Link::get_init() const
{
return init_;
}
void Link::cur_link(NetObj*&net, unsigned &pin)
{
net = node_;
pin = pin_;
}
void Link::cur_link(const NetObj*&net, unsigned &pin) const
{
net = node_;
pin = pin_;
}
void Link::unlink()
{
assert(nexus_);
if (! is_linked())
return;
nexus_->unlink(this);
(new Nexus()) -> relink(this);
}
bool Link::is_equal(const Link&that) const
{
return (node_ == that.node_) && (pin_ == that.pin_);
}
bool Link::is_linked() const
{
if (next_)
return true;
if (nexus_->first_nlink() != this)
return true;
return false;
}
bool Link::is_linked(const Link&that) const
{
return nexus_ == that.nexus_;
}
Link* Link::next_nlink()
{
return next_;
}
const Link* Link::next_nlink() const
{
return next_;
}
const NetObj*Link::get_obj() const
{
return node_;
}
NetObj*Link::get_obj()
{
return node_;
}
unsigned Link::get_pin() const
{
return pin_;
}
void Link::set_name(const string&n, unsigned i)
{
name_ = n;
inst_ = i;
}
const string& Link::get_name() const
{
return name_;
}
unsigned Link::get_inst() const
{
return inst_;
}
Nexus::Nexus()
{
name_ = 0;
list_ = 0;
t_cookie_ = 0;
}
Nexus::~Nexus()
{
assert(list_ == 0);
if (name_)
delete[]name_;
}
verinum::V Nexus::get_init() const
{
assert(list_);
for (Link*cur = list_ ; cur ; cur = cur->next_) {
if (cur->get_dir() == Link::OUTPUT)
return verinum::Vx;
if ((cur->get_dir() == Link::PASSIVE)
&& (cur->get_init() != verinum::Vz))
return cur->get_init();
}
return verinum::Vz;
}
void Nexus::unlink(Link*that)
{
if (name_) {
delete[] name_;
name_ = 0;
}
assert(that);
if (list_ == that) {
list_ = that->next_;
that->next_ = 0;
that->nexus_ = 0;
return;
}
Link*cur = list_;
while (cur->next_ != that) {
assert(cur->next_);
cur = cur->next_;
}
cur->next_ = that->next_;
that->nexus_ = 0;
that->next_ = 0;
}
void Nexus::relink(Link*that)
{
if (name_) {
delete[] name_;
name_ = 0;
}
assert(that->nexus_ == 0);
assert(that->next_ == 0);
that->next_ = list_;
that->nexus_ = this;
list_ = that;
}
Link* Nexus::first_nlink()
{
return list_;
}
const Link* Nexus::first_nlink() const
{
return list_;
}
void* Nexus::t_cookie() const
{
return t_cookie_;
}
void* Nexus::t_cookie(void*val)const
{
void*tmp = t_cookie_;
t_cookie_ = val;
return tmp;
}
const char* Nexus::name() const
{
if (name_)
return name_;
const NetNet*sig = 0;
unsigned pin = 0;
for (const Link*cur = first_nlink()
; cur ; cur = cur->next_nlink()) {
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();
}
if (sig == 0) {
const Link*lnk = first_nlink();
const NetObj*obj = lnk->get_obj();
pin = lnk->get_pin();
cerr << "internal error: No signal for nexus of " <<
obj->name() << " pin " << pin << "(" <<
lnk->get_name() << "<" << lnk->get_inst() << ">)"
" type=" << typeid(*obj).name() << "?" << endl;
}
assert(sig);
ostrstream tmp;
tmp << sig->name();
if (sig->pin_count() > 1)
tmp << "<" << pin << ">";
tmp << ends;
name_ = new char[strlen(tmp.str()) + 1];
strcpy(name_, tmp.str());
return name_;
}
/*
* $Log: net_link.cc,v $
* Revision 1.4 2000/10/06 23:46:50 steve
* ivl_target updates, including more complete
* handling of ivl_nexus_t objects. Much reduced
* dependencies on pointers to netlist objects.
*
* Revision 1.3 2000/08/26 00:54:03 steve
* Get at gate information for ivl_target interface.
*
* Revision 1.2 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.1 2000/06/25 19:59:42 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
*/
+105
View File
@@ -0,0 +1,105 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: net_modulo.cc,v 1.1 2000/09/17 21:26:15 steve Exp $"
#endif
# include <typeinfo>
# include <iostream>
# include <iomanip>
# include <cassert>
# include "netlist.h"
NetModulo::NetModulo(const string&n, unsigned wr,
unsigned wa, unsigned wb)
: NetNode(n, wr+wa+wb), width_r_(wr), width_a_(wa), width_b_(wb)
{
unsigned p = 0;
for (unsigned idx = 0 ; idx < width_r_ ; idx += 1, p += 1) {
pin(p).set_dir(Link::OUTPUT);
pin(p).set_name("Result", idx);
}
for (unsigned idx = 0 ; idx < width_a_ ; idx += 1, p += 1) {
pin(p).set_dir(Link::INPUT);
pin(p).set_name("DataA", idx);
}
for (unsigned idx = 0 ; idx < width_b_ ; idx += 1, p += 1) {
pin(p).set_dir(Link::INPUT);
pin(p).set_name("DataB", idx);
}
}
NetModulo::~NetModulo()
{
}
unsigned NetModulo::width_r() const
{
return width_r_;
}
unsigned NetModulo::width_a() const
{
return width_a_;
}
unsigned NetModulo::width_b() const
{
return width_b_;
}
Link& NetModulo::pin_Result(unsigned idx)
{
assert(idx < width_r_);
return pin(idx);
}
const Link& NetModulo::pin_Result(unsigned idx) const
{
assert(idx < width_r_);
return pin(idx);
}
Link& NetModulo::pin_DataA(unsigned idx)
{
assert(idx < width_a_);
return pin(idx+width_r_);
}
const Link& NetModulo::pin_DataA(unsigned idx) const
{
assert(idx < width_a_);
return pin(idx+width_r_);
}
Link& NetModulo::pin_DataB(unsigned idx)
{
assert(idx < width_b_);
return pin(idx+width_r_+width_a_);
}
const Link& NetModulo::pin_DataB(unsigned idx) const
{
assert(idx < width_b_);
return pin(idx+width_r_+width_a_);
}
+105
View File
@@ -0,0 +1,105 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: net_proc.cc,v 1.2 2000/07/27 05:13:44 steve Exp $"
#endif
# include "netlist.h"
# include <assert.h>
NetDisable::NetDisable(NetScope*tgt)
: target_(tgt)
{
}
NetDisable::~NetDisable()
{
}
const NetScope* NetDisable::target() const
{
return target_;
}
NetForever::NetForever(NetProc*p)
: statement_(p)
{
}
NetForever::~NetForever()
{
delete statement_;
}
NetPDelay::NetPDelay(unsigned long d, NetProc*st)
: delay_(d), expr_(0), statement_(st)
{
}
NetPDelay::NetPDelay(NetExpr*d, NetProc*st)
: delay_(0), expr_(d), statement_(st)
{
}
NetPDelay::~NetPDelay()
{
if (expr_) delete expr_;
}
unsigned long NetPDelay::delay() const
{
assert(expr_ == 0);
return delay_;
}
const NetExpr* NetPDelay::expr() const
{
return expr_;
}
NetRepeat::NetRepeat(NetExpr*e, NetProc*p)
: expr_(e), statement_(p)
{
}
NetRepeat::~NetRepeat()
{
delete expr_;
delete statement_;
}
const NetExpr* NetRepeat::expr() const
{
return expr_;
}
/*
* $Log: net_proc.cc,v $
* Revision 1.2 2000/07/27 05:13:44 steve
* Support elaboration of disable statements.
*
* Revision 1.1 2000/07/07 04:53:54 steve
* Add support for non-constant delays in delay statements,
* Support evaluating ! in constant expressions, and
* move some code from netlist.cc to net_proc.cc.
*
*/
+415
View File
@@ -0,0 +1,415 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: net_scope.cc,v 1.11 2000/12/16 01:45:48 steve Exp $"
#endif
# include "netlist.h"
# include <strstream>
/*
* The NetScope class keeps a scope tree organized. Each node of the
* scope tree points to its parent, its right sibling and its leftmost
* child. The root node has no parent or siblings. The node stores the
* name of the scope. The complete hierarchical name of the scope is
* formed by appending the path of scopes from the root to the scope
* in question.
*/
NetScope::NetScope(NetScope*up, const string&n, NetScope::TYPE t)
: type_(t), up_(up), sib_(0), sub_(0)
{
memories_ = 0;
signals_ = 0;
events_ = 0;
if (up) {
time_unit_ = up->time_unit();
time_prec_ = up->time_precision();
sib_ = up_->sub_;
up_->sub_ = this;
} else {
time_unit_ = 0;
time_prec_ = 0;
assert(t == MODULE);
}
switch (t) {
case NetScope::TASK:
task_ = 0;
break;
case NetScope::FUNC:
func_ = 0;
break;
case NetScope::MODULE:
module_name_ = 0;
break;
}
name_ = new char[n.length()+1];
strcpy(name_, n.c_str());
}
NetScope::~NetScope()
{
assert(sib_ == 0);
assert(sub_ == 0);
lcounter_ = 0;
delete[]name_;
if ((type_ == MODULE) && module_name_)
free(module_name_);
}
NetExpr* NetScope::set_parameter(const string&key, NetExpr*expr)
{
NetExpr*&ref = parameters_[key];
NetExpr* res = ref;
ref = expr;
return res;
}
NetExpr* NetScope::set_localparam(const string&key, NetExpr*expr)
{
NetExpr*&ref = localparams_[key];
NetExpr* res = ref;
ref = expr;
return res;
}
const NetExpr* NetScope::get_parameter(const string&key) const
{
map<string,NetExpr*>::const_iterator idx;
idx = parameters_.find(key);
if (idx != parameters_.end())
return (*idx).second;
idx = localparams_.find(key);
if (idx != localparams_.end())
return (*idx).second;
return 0;
}
NetScope::TYPE NetScope::type() const
{
return type_;
}
void NetScope::set_task_def(NetTaskDef*def)
{
assert( type_ == TASK );
assert( task_ == 0 );
task_ = def;
}
NetTaskDef* NetScope::task_def()
{
assert( type_ == TASK );
return task_;
}
const NetTaskDef* NetScope::task_def() const
{
assert( type_ == TASK );
return task_;
}
void NetScope::set_func_def(NetFuncDef*def)
{
assert( type_ == FUNC );
assert( func_ == 0 );
func_ = def;
}
NetFuncDef* NetScope::func_def()
{
assert( type_ == FUNC );
return func_;
}
const NetFuncDef* NetScope::func_def() const
{
assert( type_ == FUNC );
return func_;
}
void NetScope::set_module_name(const char*n)
{
assert(type_ == MODULE);
module_name_ = strdup(n);
}
const char* NetScope::module_name() const
{
assert(type_ == MODULE);
return module_name_;
}
void NetScope::time_unit(int val)
{
time_unit_ = val;
}
void NetScope::time_precision(int val)
{
time_prec_ = val;
}
int NetScope::time_unit() const
{
return time_unit_;
}
int NetScope::time_precision() const
{
return time_prec_;
}
const char* NetScope::basename() const
{
return name_;
}
string NetScope::name() const
{
if (up_)
return up_->name() + "." + name_;
else
return name_;
}
void NetScope::add_event(NetEvent*ev)
{
assert(ev->scope_ == 0);
ev->scope_ = this;
ev->snext_ = events_;
events_ = ev;
}
void NetScope::rem_event(NetEvent*ev)
{
assert(ev->scope_ == this);
ev->scope_ = 0;
if (events_ == ev) {
events_ = ev->snext_;
} else {
NetEvent*cur = events_;
while (cur->snext_ != ev) {
assert(cur->snext_);
cur = cur->snext_;
}
cur->snext_ = ev->snext_;
}
ev->snext_ = 0;
}
NetEvent* NetScope::find_event(const string&name)
{
for (NetEvent*cur = events_; cur ; cur = cur->snext_)
if (cur->name() == name)
return cur;
return 0;
}
void NetScope::add_signal(NetNet*net)
{
if (signals_ == 0) {
net->sig_next_ = net;
net->sig_prev_ = net;
} else {
net->sig_next_ = signals_->sig_next_;
net->sig_prev_ = signals_;
net->sig_next_->sig_prev_ = net;
net->sig_prev_->sig_next_ = net;
}
signals_ = net;
}
void NetScope::rem_signal(NetNet*net)
{
assert(net->scope() == this);
if (signals_ == net)
signals_ = net->sig_prev_;
if (signals_ == net) {
signals_ = 0;
} else {
net->sig_prev_->sig_next_ = net->sig_next_;
net->sig_next_->sig_prev_ = net->sig_prev_;
}
}
NetNet* NetScope::find_signal(const string&key)
{
if (signals_ == 0)
return 0;
string fulname = name()+"."+key;
NetNet*cur = signals_;
do {
if (cur->name() == fulname)
return cur;
cur = cur->sig_prev_;
} while (cur != signals_);
return 0;
}
void NetScope::add_memory(NetMemory*mem)
{
if (memories_ == 0) {
mem->snext_ = mem;
mem->sprev_ = mem;
} else {
mem->snext_ = memories_->snext_;
mem->sprev_ = memories_;
mem->snext_->sprev_ = mem;
mem->sprev_->snext_ = mem;
}
memories_ = mem;
mem->scope_ = this;
}
void NetScope::rem_memory(NetMemory*mem)
{
assert(mem->scope_ == this);
if (memories_ == mem)
memories_ = mem->sprev_;
if (memories_ == mem) {
memories_ = 0;
} else {
mem->sprev_->snext_ = mem->snext_;
mem->snext_->sprev_ = mem->sprev_;
}
mem->scope_ = 0;
}
NetMemory* NetScope::find_memory(const string&key)
{
if (memories_ == 0)
return 0;
string fulname = name()+"."+key;
NetMemory*cur = memories_;
do {
if (cur->name() == fulname)
return cur;
cur = cur->sprev_;
} while (cur != memories_);
return 0;
}
/*
* This method locates a child scope by name. The name is the simple
* name of the child, no heirarchy is searched.
*/
NetScope* NetScope::child(const string&name)
{
if (sub_ == 0) return 0;
NetScope*cur = sub_;
while (cur->name_ != name) {
if (cur->sib_ == 0) return 0;
cur = cur->sib_;
}
return cur;
}
const NetScope* NetScope::child(const string&name) const
{
if (sub_ == 0) return 0;
NetScope*cur = sub_;
while (cur->name_ != name) {
if (cur->sib_ == 0) return 0;
cur = cur->sib_;
}
return cur;
}
NetScope* NetScope::parent()
{
return up_;
}
const NetScope* NetScope::parent() const
{
return up_;
}
string NetScope::local_symbol()
{
strstream res;
res << "_l" << (lcounter_++) << ends;
return res.str();
}
/*
* $Log: net_scope.cc,v $
* Revision 1.11 2000/12/16 01:45:48 steve
* Detect recursive instantiations (PR#2)
*
* Revision 1.10 2000/10/06 23:46:50 steve
* ivl_target updates, including more complete
* handling of ivl_nexus_t objects. Much reduced
* dependencies on pointers to netlist objects.
*
* Revision 1.9 2000/08/27 15:51:50 steve
* t-dll iterates signals, and passes them to the
* target module.
*
* Some of NetObj should return char*, not string.
*
* Revision 1.8 2000/07/30 18:25:44 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.7 2000/07/22 22:09:03 steve
* Parse and elaborate timescale to scopes.
*
* Revision 1.6 2000/05/02 03:13:31 steve
* Move memories to the NetScope object.
*
* Revision 1.5 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.4 2000/04/18 04:50:20 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.3 2000/04/10 05:26:06 steve
* All events now use the NetEvent class.
*
* Revision 1.2 2000/04/09 17:04:56 steve
* uninitialized event_ list.
*
* Revision 1.1 2000/04/04 03:20:15 steve
* Simulate named event trigger and waits.
*
*/
+207
View File
@@ -0,0 +1,207 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: net_udp.cc,v 1.3 2000/12/15 01:24:17 steve Exp $"
#endif
# include "netlist.h"
bool NetUDP::set_table(const string&input, char output)
{
assert((output == '0') || (output == '1')
|| (is_sequential() && (output == '-')));
cm_[input] = output;
if (is_sequential()) {
assert(input.length() == pin_count());
/* XXXX Need to check to make sure that the input vector
contains a legal combination of characters. */
return sequ_glob_(input, output);
} else {
assert(input.length() == (pin_count()-1));
/* XXXX Need to check to make sure that the input vector
contains a legal combination of characters. In
combinational UDPs, only 0, 1, x, and ? are allowed. */
return true;
}
}
void NetUDP::cleanup_table()
{
for (FSM_::iterator idx = fsm_.begin() ; idx != fsm_.end() ; idx++) {
string str = (*idx).first;
state_t_*st = (*idx).second;
assert(str[0] == st->out);
for (unsigned pin = 0 ; pin < pin_count() ; pin += 1) {
if (st->pins[pin].zer && st->pins[pin].zer->out == 'x')
st->pins[pin].zer = 0;
if (st->pins[pin].one && st->pins[pin].one->out == 'x')
st->pins[pin].one = 0;
if (st->pins[pin].xxx && st->pins[pin].xxx->out == 'x')
st->pins[pin].xxx = 0;
}
}
for (FSM_::iterator idx = fsm_.begin() ; idx != fsm_.end() ; ) {
FSM_::iterator cur = idx;
idx ++;
state_t_*st = (*cur).second;
if (st->out != 'x')
continue;
for (unsigned pin = 0 ; pin < pin_count() ; pin += 1) {
if (st->pins[pin].zer)
goto break_label;
if (st->pins[pin].one)
goto break_label;
if (st->pins[pin].xxx)
goto break_label;
}
//delete st;
fsm_.erase(cur);
break_label:;
}
}
char NetUDP::table_lookup(const string&from, char to, unsigned pin) const
{
assert(pin <= pin_count());
assert(from.length() == pin_count());
FSM_::const_iterator idx = fsm_.find(from);
if (idx == fsm_.end())
return 'x';
state_t_*next;
switch (to) {
case '0':
next = (*idx).second->pins[pin].zer;
break;
case '1':
next = (*idx).second->pins[pin].one;
break;
case 'x':
next = (*idx).second->pins[pin].xxx;
break;
default:
assert(0);
next = 0;
}
return next? next->out : 'x';
}
void NetUDP::set_initial(char val)
{
assert(is_sequential());
assert((val == '0') || (val == '1') || (val == 'x'));
init_ = val;
}
NetUDP::state_t_* NetUDP::find_state_(const string&str)
{
map<string,state_t_*>::iterator cur = fsm_.find(str);
if (cur != fsm_.end())
return (*cur).second;
state_t_*st = fsm_[str];
if (st == 0) {
st = new state_t_(pin_count());
st->out = str[0];
fsm_[str] = st;
}
return st;
}
NetUDP_COMB::NetUDP_COMB(const string&n, unsigned pins, bool sequ)
: NetNode(n, pins), sequential_(sequ)
{
pin(0).set_dir(Link::OUTPUT);
pin(0).set_name("O", 0);
for (unsigned idx = 1 ; idx < pins ; idx += 1) {
pin(idx).set_dir(Link::INPUT);
pin(idx).set_name("I", idx-1);
}
}
bool NetUDP_COMB::set_table(const string&input, char output)
{
if ((output != '0') && (output != '1') && (output != 'x'))
return false;
assert((output == '0') || (output == '1') || (output == 'x'));
assert(input.length() == (pin_count()-1));
/* XXXX Need to check to make sure that the input vector
contains a legal combination of characters. In
combinational UDPs, only 0, 1, x, and ? are allowed. */
cm_[input] = output;
return true;
}
void NetUDP_COMB::cleanup_table()
{
}
bool NetUDP_COMB::first(string&inp, char&out) const
{
idx_ = cm_.begin();
if (idx_ == cm_.end())
return false;
inp = (*idx_).first;
out = (*idx_).second;
return true;
}
bool NetUDP_COMB::next(string&inp, char&out) const
{
idx_ ++;
if (idx_ == cm_.end())
return false;
inp = (*idx_).first;
out = (*idx_).second;
return true;
}
/*
* $Log: net_udp.cc,v $
* Revision 1.3 2000/12/15 01:24:17 steve
* Accept x in outputs of primitive. (PR#84)
*
* Revision 1.2 2000/11/04 06:36:24 steve
* Apply sequential UDP rework from Stephan Boettcher (PR#39)
*
* Revision 1.1 2000/03/29 04:37:11 steve
* New and improved combinational primitives.
*
*/
+967 -1321
View File
File diff suppressed because it is too large Load Diff
+1337 -673
View File
File diff suppressed because it is too large Load Diff
+77 -6
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.7 1999/11/28 23:42:02 steve Exp $"
#ident "$Id: netlist.txt,v 1.10 2000/07/23 18:06:15 steve Exp $"
Note that the netlist.h header contains detailed descriptions of how
@@ -60,13 +60,20 @@ 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
object per pin. Each pin is a single bit. The Link objects link to all
the NetNode and NetNet objects' links that are connected together in
the design, and to a Nexus object. 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.
The connected set of links also has common properties that are stored
or access from the Nexus object. All the Links that are connected
together are also connected to a single Nexus object. This object is
useful for accessing the properties and values that come from the
connected set of links. The Nexus object is also handy for iterating
over the connected set of Links.
See the Link class definition in netlist.h for a description of the link
methods, and the Nexus class for nexus global methods.
Currently, a link has 3 possible direction properties:
@@ -229,6 +236,29 @@ can operate globally, with optimizations freely crossing module
boundaries. This makes coding of netlist transform functions such as
constant propagation more effective and easier to write.
SCOPE REPRESENTATION IN NETLISTS
In spite of the literal flattening of the design, scope information is
preserved in the netlist, with the NetScope class. The Design class
keeps a single pointer to the root scope of the design. This is the
scope of the root module. Scopes that are then created within that
(or any nested) module are placed as children of the root scope, and
those children can have further children, and so on.
Each scope in the tree carries its own name, and its relationship to
its parent and children. This makes it possible to walk the tree of
scopes. In practice, the walking of the scopes is handled by recursive
methods.
Each scope also carries the parameters that are applicable to the
scope itself. The parameter expression (possibly evaluated) can be
located by name, given the scope object itself. The scan of the pform
to generate scopes also places the parameters that are declared in the
scope. Overrides are managed during the scan, and once the scan is
complete, defparam overrides are applied.
TASKS IN NETLISTS
The flattening of the design does not include tasks and named
@@ -239,7 +269,48 @@ recurse. (The elaboration process does reserve the right to flatten
some task calls. C++ programmers recognize this as inlining a task.)
TIME SCALE IN NETLISTS
The Design class and the NetScope classes carry time scale and
resolution information of the elaborated design. There is a global
resolution, and there are scope specific units and resolutions. Units
and resolutions are specified as signed integers, and interpreted as
the power of 10 of the value. For example, a resolution "-9" means
that "1" is 1ns (1e-9). The notation supports units from -128 to +127.
It is up to the back-ends to interpret "-4" as "100us".
Delays are expressed in the netlist by integers. The units of these
delays are always given in the units of the design precision. This
allows everything to work with integers, and generally places the
burden of scaling delays into elaboration. This is, after all, a
common task. The Design::get_precision() method gets the global design
precision.
Each NetScope also carries its local time_units and time_precision
values. These are filled in during scope elaboration and are used in
subsequent elaboration phases to arrange for scaling of delays. This
information can also be used by the code generator to scale times back
to the units of the scope, if that is desired.
$Log: netlist.txt,v $
Revision 1.10 2000/07/23 18:06:15 steve
Document time scale in netlists.
Revision 1.9 2000/07/14 06:12:57 steve
Move inital value handling from NetNet to Nexus
objects. This allows better propogation of inital
values.
Clean up constant propagation a bit to account
for regs that are not really values.
Revision 1.8 2000/03/08 04:36:54 steve
Redesign the implementation of scopes and parameters.
I now generate the scopes and notice the parameters
in a separate pass over the pform. Once the scopes
are generated, I can process overrides and evalutate
paremeters before elaboration begins.
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.
+61 -3
View File
@@ -1,7 +1,7 @@
#ifndef __netmisc_H
#define __netmisc_H
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,8 +18,8 @@
* 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 $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: netmisc.h,v 1.10 2000/11/20 00:58:40 steve Exp $"
#endif
# include "netlist.h"
@@ -31,10 +31,68 @@
* enough.
*/
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid);
extern NetNet*pad_to_width(Design*des, const string&p, NetNet*n, unsigned w);
/*
* This local function returns true if all the the possible drivers of
* this link are constant. It will also return true if there are no
* drivers at all.
*/
extern bool link_drivers_constant(const Link&lnk);
/*
* This function returns the value of the constant driving this link,
* or Vz if there is no constant. The results of this function are
* only meaningful if link_drivers_constant(lnk) == true.
*/
extern verinum::V driven_value(const Link&lnk);
/*
* In some cases the lval is accessible as a pointer to the head of
* a list of NetAssign_ objects. This function returns the width of
* the l-value represented by this list.
*/
extern unsigned count_lval_width(const class NetAssign_*first);
/*
* $Log: netmisc.h,v $
* Revision 1.10 2000/11/20 00:58:40 steve
* Add support for supply nets (PR#17)
*
* Revision 1.9 2000/09/20 02:53:15 steve
* Correctly measure comples l-values of assignments.
*
* Revision 1.8 2000/06/25 19:59:42 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
* Revision 1.7 2000/05/14 17:55:04 steve
* Support initialization of FF Q value.
*
* Revision 1.6 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.5 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
* Revision 1.4 2000/03/16 19:03:03 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
* Revision 1.3 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 2000/02/16 03:58:27 steve
* Fix up width matching in structural bitwise operators.
*
* Revision 1.1 1999/09/29 00:42:51 steve
* Allow expanding of additive operators.
*
-73
View File
@@ -1,73 +0,0 @@
/*
* Copyright (c) 1998 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.
*
* 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: nobufz.cc,v 1.1 1998/12/02 04:37:13 steve Exp $"
#endif
/* NOBUFZ Function
* This function transforms the netlist by removing BUFZ nodes that
* have no obvious effect. The assumption here is that the BUFZ node
* transmits information perfectly in one direction, and not at all in
* the other.
*
* A BUFZ will *not* be eliminated if the output link is connected to
* other outputs. The BUFZ protects its input link from the
* double-driving on its output, so the bufz is not meaningless and
* cannot be removed.
*/
# include "netlist.h"
# include <assert.h>
static bool is_a_bufz_node(const NetNode*obj)
{
return dynamic_cast<const NetBUFZ*>(obj);
}
void nobufz(Design*des)
{
des->clear_node_marks();
while (NetNode*obj = des->find_node(&is_a_bufz_node)) {
NetBUFZ*cur = dynamic_cast<NetBUFZ*>(obj);
assert(cur);
/* If there are more output pins on the output size of
the BUFZ, then the BUFZ has a real effect (it
protects its input side) and cannot be eliminated. */
if (count_outputs(cur->pin(0)) == 1) {
connect(cur->pin(0), cur->pin(1));
delete cur;
} else {
cur->set_mark();
}
}
}
/*
* $Log: nobufz.cc,v $
* Revision 1.1 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,
* Signal folding is aware of attributes, and
* the XNF target can dump UDP objects based on LCA
* attributes.
*
*/
+85 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999Stephen Williams (steve@icarus.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
@@ -16,8 +16,8 @@
* 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 $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: nodangle.cc,v 1.10 2000/11/19 20:48:53 steve Exp $"
#endif
/*
@@ -31,29 +31,68 @@
class nodangle_f : public functor_t {
public:
void event(Design*des, NetEvent*ev);
void signal(Design*des, NetNet*sig);
unsigned count_;
};
void nodangle_f::event(Design*des, NetEvent*ev)
{
if (NetEvent*match = ev->find_similar_event()) {
ev->replace_event(match);
}
if (ev->nwait() != 0)
return;
if (ev->ntrig() != 0)
return;
delete ev;
}
void nodangle_f::signal(Design*des, NetNet*sig)
{
if (! sig->local_flag())
return;
/* Cannot delete signals referenced in an expression. */
if (sig->get_eref() > 0)
return;
/* Check to see if the signal is completely unconnected. If
all the bits are unlinked, then delete it. */
unsigned unlinked = 0;
for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1)
if (! sig->pin(idx).is_linked()) unlinked += 1;
if (unlinked == sig->pin_count()) {
delete sig;
return;
}
/* The remaining things can only be done to synthesized
signals, not ones that appear in the original Verilog. */
if (! sig->local_flag())
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()) {
Nexus*nex = sig->pin(idx).nexus();
for (Link*cur = nex->first_nlink()
; cur ; cur = cur->next_nlink()) {
if (cur == &sig->pin(idx))
continue;
NetNet*cursig = dynamic_cast<NetNet*>(cur->get_obj());
if (cursig == 0)
continue;
if (cursig->local_flag())
continue;
significant_flags += 1;
break;
}
@@ -61,18 +100,54 @@ void nodangle_f::signal(Design*des, NetNet*sig)
/* If every pin is connected to another significant signal,
then I can delete this one. */
if (significant_flags == sig->pin_count())
if (significant_flags == sig->pin_count()) {
count_ += 1;
delete sig;
}
}
void nodangle(Design*des)
{
nodangle_f fun;
des->functor(&fun);
do {
fun.count_ = 0;
des->functor(&fun);
} while (fun.count_ > 0);
}
/*
* $Log: nodangle.cc,v $
* Revision 1.10 2000/11/19 20:48:53 steve
* Killing some signals might make others killable.
*
* Revision 1.9 2000/11/18 05:12:45 steve
* Delete unreferenced signals no matter what.
*
* Revision 1.8 2000/06/25 19:59:42 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
* Revision 1.7 2000/05/31 02:26:49 steve
* Globally merge redundant event objects.
*
* Revision 1.6 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.5 2000/04/28 21:00:29 steve
* Over agressive signal elimination in constant probadation.
*
* Revision 1.4 2000/04/18 04:50:20 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.3 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* 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.
+40 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,8 +16,8 @@
* 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 $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: pad_to_width.cc,v 1.5 2000/05/02 00:58:12 steve Exp $"
#endif
# include "netlist.h"
@@ -34,7 +34,9 @@ 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);
co->set_line(*expr);
NetEConcat*cc = new NetEConcat(2);
cc->set_line(*expr);
cc->set(0, co);
cc->set(1, expr);
cc->set_width(wid);
@@ -43,9 +45,44 @@ NetExpr*pad_to_width(NetExpr*expr, unsigned wid)
return expr;
}
NetNet*pad_to_width(Design*des, const string&path, NetNet*net, unsigned wid)
{
NetScope*scope = des->find_scope(path);
assert(scope);
if (net->pin_count() >= wid)
return net;
verinum pad(verinum::V0, wid - net->pin_count());
NetConst*con = new NetConst(des->local_symbol(path), pad);
des->add_node(con);
NetNet*tmp = new NetNet(scope, des->local_symbol(path),
NetNet::WIRE, wid);
tmp->local_flag(true);
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1)
connect(tmp->pin(idx), net->pin(idx));
for (unsigned idx = net->pin_count() ; idx < wid ; idx += 1)
connect(tmp->pin(idx), con->pin(idx-net->pin_count()));
return tmp;
}
/*
* $Log: pad_to_width.cc,v $
* Revision 1.5 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.4 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 2000/02/16 03:58:27 steve
* Fix up width matching in structural bitwise operators.
*
* Revision 1.2 2000/01/01 06:17:25 steve
* Propogate line number information when expanding expressions.
*
* Revision 1.1 1999/09/29 00:42:51 steve
* Allow expanding of additive operators.
*
+664 -240
View File
File diff suppressed because it is too large Load Diff
+6 -3
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
@@ -16,8 +16,8 @@
* 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: parse_misc.cc,v 1.3 1999/09/29 21:15:31 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: parse_misc.cc,v 1.4 2000/02/23 02:56:55 steve Exp $"
#endif
# include "parse_misc.h"
@@ -58,6 +58,9 @@ int VLwrap()
/*
* $Log: parse_misc.cc,v $
* Revision 1.4 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/09/29 21:15:31 steve
* Standardize formatting of warning messages.
*
+6 -3
View File
@@ -1,7 +1,7 @@
#ifndef __parse_misc_H
#define __parse_misc_H
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,8 +18,8 @@
* 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: parse_misc.h,v 1.3 1999/07/10 01:03:18 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: parse_misc.h,v 1.4 2000/02/23 02:56:55 steve Exp $"
#endif
# include <list>
@@ -53,6 +53,9 @@ extern unsigned error_count, warn_count;
/*
* $Log: parse_misc.h,v $
* Revision 1.4 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/07/10 01:03:18 steve
* remove string from lexical phase.
*
+459 -237
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,13 +16,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform.cc,v 1.47 1999/11/23 01:04:57 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: pform.cc,v 1.71 2001/01/10 05:32:44 steve Exp $"
#endif
# include "compiler.h"
# include "pform.h"
# include "parse_misc.h"
# include "PEvent.h"
# include "PUdp.h"
# include <list>
# include <map>
@@ -38,6 +39,8 @@ string vl_file = "";
extern int VLparse();
static Module*pform_cur_module = 0;
static int pform_time_unit = 0;
static int pform_time_prec = 0;
/*
* The scope stack and the following functions handle the processing
@@ -52,6 +55,13 @@ struct scope_name_t {
};
static scope_name_t*scope_stack = 0;
void pform_set_timescale(int unit, int prec)
{
assert(unit >= prec);
pform_time_unit = unit;
pform_time_prec = prec;
}
void pform_push_scope(const string&name)
{
scope_name_t*cur = new scope_name_t;
@@ -109,6 +119,8 @@ void pform_startmodule(const string&name, svector<Module::port_t*>*ports)
}
pform_cur_module = new Module(name, ports);
pform_cur_module->time_unit = pform_time_unit;
pform_cur_module->time_precision = pform_time_prec;
delete ports;
}
@@ -125,6 +137,52 @@ bool pform_expression_is_constant(const PExpr*ex)
return ex->is_constant(pform_cur_module);
}
MIN_TYP_MAX min_typ_max_flag = TYP;
unsigned min_typ_max_warn = 10;
PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max)
{
PExpr*res = 0;
switch (min_typ_max_flag) {
case MIN:
res = min;
delete typ;
delete max;
break;
case TYP:
res = typ;
delete min;
delete max;
break;
case MAX:
res = max;
delete min;
delete max;
break;
}
if (min_typ_max_warn > 0) {
cerr << res->get_line() << ": warning: choosing ";
switch (min_typ_max_flag) {
case MIN:
cerr << "min";
break;
case TYP:
cerr << "typ";
break;
case MAX:
cerr << "max";
break;
}
cerr << " expression." << endl;
min_typ_max_warn -= 1;
}
return res;
}
void pform_make_udp(const char*name, list<string>*parms,
svector<PWire*>*decl, list<string>*table,
Statement*init_expr)
@@ -265,12 +323,79 @@ void pform_make_udp(const char*name, list<string>*parms,
delete init_expr;
}
/*
* 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 char*name,
const svector<PExpr*>*range,
bool signed_flag)
{
assert(range);
assert(range->count() == 2);
PWire*cur = pform_cur_module->get_wire(scoped_name(name));
if (cur == 0) {
VLerror("error: name is not a valid net.");
return;
}
assert((*range)[0]);
assert((*range)[1]);
cur->set_range((*range)[0], (*range)[1]);
cur->set_signed(signed_flag);
}
void pform_set_net_range(list<char*>*names,
svector<PExpr*>*range,
bool signed_flag)
{
assert(range->count() == 2);
for (list<char*>::iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
char*txt = *cur;
pform_set_net_range(txt, range, signed_flag);
free(txt);
}
delete names;
delete range;
}
/*
* This is invoked to make a named event. This is the declaration of
* the event, and not necessarily the use of it.
*/
static void pform_make_event(const char*name, const char*fn, unsigned ln)
{
PEvent*event = new PEvent(name);
event->set_file(fn);
event->set_lineno(ln);
pform_cur_module->events[name] = event;
}
void pform_make_events(list<char*>*names, const char*fn, unsigned ln)
{
list<char*>::iterator cur;
for (cur = names->begin() ; cur != names->end() ; cur++) {
char*txt = *cur;
pform_make_event(txt, fn, ln);
free(txt);
}
delete names;
}
/*
* pform_makegates is called when a list of gates (with the same type)
* are ready to be instantiated. The function runs through the list of
* gates and calls the pform_makegate function to make the individual gate.
*/
void pform_makegate(PGBuiltin::Type type,
struct str_pair_t str,
svector<PExpr*>* delay,
const lgate&info)
{
@@ -285,6 +410,8 @@ void pform_makegate(PGBuiltin::Type type,
if (info.range[0])
cur->set_range(info.range[0], info.range[1]);
cur->strength0(str.str0);
cur->strength1(str.str1);
cur->set_file(info.file);
cur->set_lineno(info.lineno);
@@ -292,10 +419,12 @@ void pform_makegate(PGBuiltin::Type type,
}
void pform_makegates(PGBuiltin::Type type,
svector<PExpr*>*delay, svector<lgate>*gates)
struct str_pair_t str,
svector<PExpr*>*delay,
svector<lgate>*gates)
{
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
pform_makegate(type, delay, (*gates)[idx]);
pform_makegate(type, str, delay, (*gates)[idx]);
}
delete gates;
@@ -303,13 +432,16 @@ void pform_makegates(PGBuiltin::Type type,
/*
* A module is different from a gate in that there are different
* constraints, and sometimes different syntax.
* constraints, and sometimes different syntax. The X_modgate
* functions handle the instantaions of modules (and UDP objects) by
* making PGModule objects.
*/
static void pform_make_modgate(const string&type,
const string&name,
svector<PExpr*>*overrides,
struct parmvalue_t*overrides,
svector<PExpr*>*wires,
const string&fn, unsigned ln)
PExpr*msb, PExpr*lsb,
const char*fn, unsigned ln)
{
if (name == "") {
cerr << fn << ":" << ln << ": Instantiation of " << type
@@ -318,17 +450,36 @@ static void pform_make_modgate(const string&type,
return;
}
PGate*cur = new PGModule(type, name, overrides, wires);
PGModule*cur = new PGModule(type, name, wires);
cur->set_file(fn);
cur->set_lineno(ln);
cur->set_range(msb,lsb);
if (overrides && overrides->by_name) {
unsigned cnt = overrides->by_name->count();
named<PExpr*>*byname = new named<PExpr*>[cnt];
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
portname_t*curp = (*overrides->by_name)[idx];
byname[idx].name = curp->name;
byname[idx].parm = curp->parm;
}
cur->set_parameters(byname, cnt);
} else if (overrides && overrides->by_order) {
cur->set_parameters(overrides->by_order);
}
pform_cur_module->add_gate(cur);
}
static void pform_make_modgate(const string&type,
const string&name,
svector<PExpr*>*overrides,
struct parmvalue_t*overrides,
svector<portname_t*>*bind,
const string&fn, unsigned ln)
PExpr*msb, PExpr*lsb,
const char*fn, unsigned ln)
{
if (name == "") {
cerr << fn << ":" << ln << ": Instantiation of " << type
@@ -338,37 +489,79 @@ static void pform_make_modgate(const string&type,
}
unsigned npins = bind->count();
PGModule::bind_t*pins = new PGModule::bind_t[npins];
named<PExpr*>*pins = new named<PExpr*>[npins];
for (unsigned idx = 0 ; idx < npins ; idx += 1) {
portname_t*curp = (*bind)[idx];
pins[idx].name = curp->name;
pins[idx].parm = curp->parm;
}
PGate*cur = new PGModule(type, name, overrides, pins, npins);
PGModule*cur = new PGModule(type, name, pins, npins);
cur->set_file(fn);
cur->set_lineno(ln);
cur->set_range(msb,lsb);
if (overrides && overrides->by_name) {
unsigned cnt = overrides->by_name->count();
named<PExpr*>*byname = new named<PExpr*>[cnt];
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
portname_t*curp = (*overrides->by_name)[idx];
byname[idx].name = curp->name;
byname[idx].parm = curp->parm;
}
cur->set_parameters(byname, cnt);
} else if (overrides && overrides->by_order) {
cur->set_parameters(overrides->by_order);
}
pform_cur_module->add_gate(cur);
}
void pform_make_modgates(const string&type,
svector<PExpr*>*overrides,
struct parmvalue_t*overrides,
svector<lgate>*gates)
{
if (overrides && overrides->by_order)
for (unsigned idx = 0 ; idx < overrides->by_order->count() ; idx += 1)
if (! pform_expression_is_constant((*overrides->by_order)[idx])) {
VLerror("error: Parameter override expression"
" must be constant.");
return;
}
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
lgate cur = (*gates)[idx];
if (cur.parms_by_name) {
pform_make_modgate(type, cur.name, overrides, cur.parms_by_name,
pform_make_modgate(type, cur.name, overrides,
cur.parms_by_name,
cur.range[0], cur.range[1],
cur.file, cur.lineno);
} else if (cur.parms) {
pform_make_modgate(type, cur.name, overrides, cur.parms, cur.file,
cur.lineno);
/* If there are no parameters, the parser will be
tricked into thinking it is one empty
parameter. This fixes that. */
if ((cur.parms->count() == 1) && (cur.parms[0][0] == 0)) {
delete cur.parms;
cur.parms = new svector<PExpr*>(0);
}
pform_make_modgate(type, cur.name, overrides,
cur.parms,
cur.range[0], cur.range[1],
cur.file, cur.lineno);
} else {
svector<PExpr*>*wires = new svector<PExpr*>(0);
pform_make_modgate(type, cur.name, overrides, wires, cur.file,
cur.lineno);
pform_make_modgate(type, cur.name, overrides,
wires,
cur.range[0], cur.range[1],
cur.file, cur.lineno);
}
}
@@ -376,7 +569,8 @@ void pform_make_modgates(const string&type,
}
PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
svector<PExpr*>*del)
svector<PExpr*>*del,
struct str_pair_t str)
{
svector<PExpr*>*wires = new svector<PExpr*>(2);
(*wires)[0] = lval;
@@ -389,24 +583,69 @@ PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
else
cur = new PGAssign(wires, del);
cur->strength0(str.str0);
cur->strength1(str.str1);
pform_cur_module->add_gate(cur);
return cur;
}
void pform_make_pgassign_list(svector<PExpr*>*alist,
svector<PExpr*>*del,
const string& text,
struct str_pair_t str,
const char* fn,
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);
(*alist)[2*idx+1],
del, str);
tmp->set_file(fn);
tmp->set_lineno(lineno);
}
}
/*
* this function makes the initial assignment to a register as given
* in the source. It handles the case where a reg variable is assigned
* where it it declared:
*
* reg foo = <expr>;
*
* This is equivilent to the combination of statements:
*
* reg foo;
* initital foo = <expr>;
*
* and that is how it is parsed. This syntax is not part of the
* IEEE1364-1994 standard, but is approved by OVI as enhancement
* BTF-B14.
*/
void pform_make_reginit(const struct vlltype&li,
const string&name, PExpr*expr)
{
const string sname = scoped_name(name);
PWire*cur = pform_cur_module->get_wire(sname);
if (cur == 0) {
VLerror(li, "internal error: reginit to non-register?");
delete expr;
return;
}
PEIdent*lval = new PEIdent(sname);
lval->set_file(li.text);
lval->set_lineno(li.first_line);
PAssign*ass = new PAssign(lval, expr);
ass->set_file(li.text);
ass->set_lineno(li.first_line);
PProcess*top = new PProcess(PProcess::PR_INITIAL, ass);
top->set_file(li.text);
top->set_lineno(li.first_line);
pform_cur_module->add_behavior(top);
}
void pform_makewire(const vlltype&li, const string&nm,
NetNet::Type type)
{
@@ -416,7 +655,7 @@ void pform_makewire(const vlltype&li, const string&nm,
if (cur->get_wire_type() != NetNet::IMPLICIT) {
strstream msg;
msg << name << " previously defined at " <<
cur->get_line() << ".";
cur->get_line() << "." << ends;
VLerror(msg.str());
} else {
bool rc = cur->set_wire_type(type);
@@ -431,22 +670,33 @@ void pform_makewire(const vlltype&li, const string&nm,
pform_cur_module->add_wire(cur);
}
void pform_makewire(const vlltype&li, const list<string>*names,
void pform_makewire(const vlltype&li,
svector<PExpr*>*range,
list<char*>*names,
NetNet::Type type)
{
for (list<string>::const_iterator cur = names->begin()
for (list<char*>::iterator cur = names->begin()
; cur != names->end()
; cur ++ )
pform_makewire(li, *cur, type);
; cur ++ ) {
char*txt = *cur;
pform_makewire(li, txt, type);
if (range)
pform_set_net_range(txt, range, false);
free(txt);
}
delete names;
if (range)
delete range;
}
void pform_set_port_type(const string&name, NetNet::PortType pt)
void pform_set_port_type(const string&nm, NetNet::PortType pt)
{
const string name = scoped_name(nm);
PWire*cur = pform_cur_module->get_wire(name);
if (cur == 0) {
VLerror("name is not a port.");
return;
cur = new PWire(name, NetNet::IMPLICIT, pt);
pform_cur_module->add_wire(cur);
}
if (! cur->set_port_type(pt))
@@ -493,17 +743,18 @@ void pform_set_port_type(const string&name, NetNet::PortType pt)
* no output or inout ports.
*/
svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
const svector<PExpr*>*range,
const list<string>*names,
const string& file,
svector<PExpr*>*range,
list<char*>*names,
const char* file,
unsigned lineno)
{
assert(names);
svector<PWire*>*res = new svector<PWire*>(0);
for (list<string>::const_iterator cur = names->begin()
for (list<char*>::iterator cur = names->begin()
; cur != names->end() ; cur ++ ) {
string name = scoped_name(*cur);
char*txt = *cur;
string name = scoped_name(txt);
/* Look for a preexisting wire. If it exists, set the
port direction. If not, create it. */
@@ -522,10 +773,15 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
curw->set_range((*range)[0], (*range)[1]);
svector<PWire*>*tmp = new svector<PWire*>(*res, curw);
free(txt);
delete res;
res = tmp;
}
if (range)
delete range;
delete names;
return res;
}
@@ -555,8 +811,16 @@ void pform_set_function(const string&name, svector<PExpr*>*ra, PFunction *func)
void pform_set_attrib(const string&name, const string&key, const string&value)
{
PWire*cur = pform_cur_module->get_wire(name);
assert(cur);
cur->attributes[key] = value;
if (PWire*cur = pform_cur_module->get_wire(name)) {
cur->attributes[key] = value;
} else if (PGate*cur = pform_cur_module->get_gate(name)) {
cur->attributes[key] = value;
} else {
VLerror("Unable to match name for setting attribute.");
}
}
/*
@@ -581,99 +845,127 @@ void pform_set_type_attrib(const string&name, const string&key,
*/
void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r)
{
PWire*cur = pform_cur_module->get_wire(name);
PWire*cur = pform_cur_module->get_wire(scoped_name(name));
if (cur == 0) {
VLerror(" error: name is not a valid net.");
VLerror("internal error: name is not a valid memory for index.");
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(scoped_name(name));
if (cur == 0) {
VLerror(" error: name is not a valid net.");
return;
}
assert((*range)[0]);
assert((*range)[1]);
cur->set_range((*range)[0], (*range)[1]);
}
void pform_set_net_range(list<string>*names, const svector<PExpr*>*range)
{
assert(range->count() == 2);
for (list<string>::const_iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
pform_set_net_range(*cur, range);
}
}
void pform_set_parameter(const string&name, PExpr*expr)
{
assert(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)
void pform_set_localparam(const string&name, PExpr*expr)
{
for (list<string>::const_iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
pform_set_port_type(*cur, pt);
}
assert(expr);
pform_cur_module->localparams[name] = expr;
}
static void pform_set_reg_integer(const string&nm)
void pform_set_defparam(const string&name, PExpr*expr)
{
assert(expr);
pform_cur_module->defparms[name] = expr;
}
void pform_set_port_type(list<char*>*names,
svector<PExpr*>*range,
NetNet::PortType pt)
{
for (list<char*>::iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
char*txt = *cur;
pform_set_port_type(txt, pt);
if (range)
pform_set_net_range(txt, range, false);
free(txt);
}
delete names;
if (range)
delete range;
}
static void pform_set_reg_integer(const char*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);
cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT);
cur->set_signed(true);
pform_cur_module->add_wire(cur);
} else {
bool rc = cur->set_wire_type(NetNet::INTEGER);
bool rc = cur->set_wire_type(NetNet::REG);
assert(rc);
cur->set_signed(true);
}
assert(cur);
cur->set_range(new PENumber(new verinum(INTEGER_WIDTH-1, INTEGER_WIDTH)),
new PENumber(new verinum(0UL, INTEGER_WIDTH)));
cur->set_signed(true);
}
void pform_set_reg_integer(list<string>*names)
void pform_set_reg_integer(list<char*>*names)
{
for (list<string>::const_iterator cur = names->begin()
for (list<char*>::iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
pform_set_reg_integer(*cur);
char*txt = *cur;
pform_set_reg_integer(txt);
free(txt);
}
delete names;
}
svector<PWire*>* pform_make_udp_input_ports(list<string>*names)
static void pform_set_reg_time(const char*nm)
{
string name = scoped_name(nm);
PWire*cur = pform_cur_module->get_wire(name);
if (cur == 0) {
cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT);
pform_cur_module->add_wire(cur);
} else {
bool rc = cur->set_wire_type(NetNet::REG);
assert(rc);
}
assert(cur);
cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, INTEGER_WIDTH)),
new PENumber(new verinum(0UL, INTEGER_WIDTH)));
}
void pform_set_reg_time(list<char*>*names)
{
for (list<char*>::iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
char*txt = *cur;
pform_set_reg_time(txt);
free(txt);
}
delete names;
}
svector<PWire*>* pform_make_udp_input_ports(list<char*>*names)
{
svector<PWire*>*out = new svector<PWire*>(names->size());
unsigned idx = 0;
for (list<string>::const_iterator cur = names->begin()
for (list<char*>::iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
PWire*pp = new PWire(*cur, NetNet::IMPLICIT, NetNet::PINPUT);
char*txt = *cur;
PWire*pp = new PWire(txt, NetNet::IMPLICIT, NetNet::PINPUT);
(*out)[idx] = pp;
idx += 1;
free(txt);
}
delete names;
@@ -707,6 +999,7 @@ int pform_parse(const char*path, map<string,Module*>&modules,
int rc = VLparse();
if (rc) {
cerr << "I give up." << endl;
error_count += 1;
}
modules = vl_modules;
@@ -717,6 +1010,85 @@ int pform_parse(const char*path, map<string,Module*>&modules,
/*
* $Log: pform.cc,v $
* Revision 1.71 2001/01/10 05:32:44 steve
* Match memories within task scopes. (PR#101)
*
* Revision 1.70 2001/01/06 06:31:59 steve
* declaration initialization for time variables.
*
* Revision 1.69 2001/01/06 02:29:36 steve
* Support arrays of integers.
*
* Revision 1.68 2000/12/11 00:31:43 steve
* Add support for signed reg variables,
* simulate in t-vvm signed comparisons.
*
* Revision 1.67 2000/11/30 17:31:42 steve
* Change LineInfo to store const C strings.
*
* Revision 1.66 2000/10/31 17:49:02 steve
* Support time variables.
*
* Revision 1.65 2000/10/31 17:00:04 steve
* Remove C++ string from variable lists.
*
* Revision 1.64 2000/09/13 16:32:26 steve
* Error message for invalid variable list.
*
* Revision 1.63 2000/07/29 17:58:21 steve
* Introduce min:typ:max support.
*
* Revision 1.62 2000/07/22 22:09:04 steve
* Parse and elaborate timescale to scopes.
*
* Revision 1.61 2000/05/23 16:03:13 steve
* Better parsing of expressions lists will empty expressoins.
*
* Revision 1.60 2000/05/16 04:05:16 steve
* Module ports are really special PEIdent
* expressions, because a name can be used
* many places in the port list.
*
* Revision 1.59 2000/05/08 05:30:20 steve
* Deliver gate output strengths to the netlist.
*
* Revision 1.58 2000/05/06 15:41:57 steve
* Carry assignment strength to pform.
*
* Revision 1.57 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.56 2000/03/12 17:09:41 steve
* Support localparam.
*
* Revision 1.55 2000/03/08 04:36:54 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.54 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.53 2000/02/18 05:15:03 steve
* Catch module instantiation arrays.
*
* Revision 1.52 2000/01/09 05:50:49 steve
* Support named parameter override lists.
*
* Revision 1.51 2000/01/02 01:59:28 steve
* Forgot to handle no overrides at all.
*
* Revision 1.50 2000/01/01 23:47:58 steve
* Fix module parameter override syntax.
*
* Revision 1.49 1999/12/30 19:06:14 steve
* Support reg initial assignment syntax.
*
* Revision 1.48 1999/12/11 05:45:41 steve
* Fix support for attaching attributes to primitive gates.
*
* Revision 1.47 1999/11/23 01:04:57 steve
* A file name of - means standard input.
*
@@ -751,155 +1123,5 @@ int pform_parse(const char*path, map<string,Module*>&modules,
* Revision 1.37 1999/08/03 04:14:49 steve
* Parse into pform arbitrarily complex module
* port declarations.
*
* Revision 1.36 1999/08/01 16:34:50 steve
* Parse and elaborate rise/fall/decay times
* for gates, and handle the rules for partial
* lists of times.
*
* Revision 1.35 1999/07/31 19:15:21 steve
* misspelled comment.
*
* Revision 1.34 1999/07/31 19:14:47 steve
* Add functions up to elaboration (Ed Carter)
*
* Revision 1.33 1999/07/24 02:11:20 steve
* Elaborate task input ports.
*
* Revision 1.32 1999/07/10 01:03:18 steve
* remove string from lexical phase.
*
* Revision 1.31 1999/07/03 02:12:52 steve
* Elaborate user defined tasks.
*
* Revision 1.30 1999/06/24 04:24:18 steve
* Handle expression widths for EEE and NEE operators,
* add named blocks and scope handling,
* add registers declared in named blocks.
*
* Revision 1.29 1999/06/21 01:02:16 steve
* Fix merging of UDP port type in decls.
*
* Revision 1.28 1999/06/17 05:34:42 steve
* Clean up interface of the PWire class,
* Properly match wire ranges.
*
* Revision 1.27 1999/06/15 03:44:53 steve
* Get rid of the STL vector template.
*
* Revision 1.26 1999/06/13 23:51:16 steve
* l-value part select for procedural assignments.
*
* Revision 1.25 1999/06/12 20:35:27 steve
* parse more verilog.
*
* Revision 1.24 1999/06/12 03:42:17 steve
* Assert state of bit range expressions.
*
* Revision 1.23 1999/06/06 20:45:39 steve
* Add parse and elaboration of non-blocking assignments,
* Replace list<PCase::Item*> with an svector version,
* Add integer support.
*
* Revision 1.22 1999/06/02 15:38:46 steve
* Line information with nets.
*
* Revision 1.21 1999/05/31 15:45:59 steve
* makegates infinite loop fixed.
*
* Revision 1.20 1999/05/29 02:36:17 steve
* module parameter bind by name.
*
* Revision 1.19 1999/05/20 04:31:45 steve
* Much expression parsing work,
* mark continuous assigns with source line info,
* replace some assertion failures with Sorry messages.
*
* Revision 1.18 1999/05/16 05:08:42 steve
* Redo constant expression detection to happen
* after parsing.
*
* Parse more operators and expressions.
*
* Revision 1.17 1999/05/10 00:16:58 steve
* Parse and elaborate the concatenate operator
* in structural contexts, Replace vector<PExpr*>
* and list<PExpr*> with svector<PExpr*>, evaluate
* constant expressions with parameters, handle
* memories as lvalues.
*
* Parse task declarations, integer types.
*
* Revision 1.16 1999/05/08 20:19:20 steve
* Parse more things.
*
* Revision 1.15 1999/05/07 04:26:49 steve
* Parse more complex continuous assign lvalues.
*
* Revision 1.14 1999/05/06 04:37:17 steve
* Get rid of list<lgate> types.
*
* Revision 1.13 1999/05/06 04:09:28 steve
* Parse more constant expressions.
*
* Revision 1.12 1999/05/02 23:25:32 steve
* Enforce module instance names.
*
* Revision 1.11 1999/04/19 01:59:37 steve
* Add memories to the parse and elaboration phases.
*
* Revision 1.10 1999/02/21 17:01:57 steve
* Add support for module parameters.
*
* Revision 1.9 1999/02/15 02:06:15 steve
* Elaborate gate ranges.
*
* Revision 1.8 1999/01/25 05:45:56 steve
* Add the LineInfo class to carry the source file
* location of things. PGate, Statement and PProcess.
*
* elaborate handles module parameter mismatches,
* missing or incorrect lvalues for procedural
* assignment, and errors are propogated to the
* top of the elaboration call tree.
*
* Attach line numbers to processes, gates and
* assignment statements.
*
* Revision 1.7 1998/12/09 04:02:47 steve
* Support the include directive.
*
* Revision 1.6 1998/12/01 00:42:14 steve
* Elaborate UDP devices,
* Support UDP type attributes, and
* pass those attributes to nodes that
* are instantiated by elaboration,
* Put modules into a map instead of
* a simple list.
*
* Revision 1.5 1998/11/25 02:35:53 steve
* Parse UDP primitives all the way to pform.
*
* Revision 1.4 1998/11/23 00:20:23 steve
* NetAssign handles lvalues as pin links
* instead of a signal pointer,
* Wire attributes added,
* Ability to parse UDP descriptions added,
* XNF generates EXT records for signals with
* the PAD attribute.
*
* Revision 1.3 1998/11/11 00:01:51 steve
* Check net ranges in declarations.
*
* Revision 1.2 1998/11/07 17:05:06 steve
* Handle procedural conditional, and some
* of the conditional expressions.
*
* Elaborate signals and identifiers differently,
* allowing the netlist to hold signal information.
*
* Revision 1.1 1998/11/03 23:29:03 steve
* Introduce verilog to CVS.
*
*/
+94 -19
View File
@@ -1,7 +1,7 @@
#ifndef __pform_H
#define __pform_H
/*
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -18,11 +18,12 @@
* 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: pform.h,v 1.31 1999/09/10 05:02:09 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: pform.h,v 1.45 2000/12/11 00:31:43 steve Exp $"
#endif
# include "netlist.h"
# include "named.h"
# include "Module.h"
# include "Statement.h"
# include "PGate.h"
@@ -57,6 +58,15 @@ class PGate;
class PExpr;
struct vlltype;
/*
* The min:typ:max expression s selected at parse time using the
* enumeration. When the compiler makes a choise, it also prints a
* warning if min_typ_max_warn > 0.
*/
extern enum MIN_TYP_MAX { MIN, TYP, MAX } min_typ_max_flag;
extern unsigned min_typ_max_warn;
PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max);
/*
* These type are lexical types -- that is, types that are used as
* lexical values to decorate the parse tree during parsing. They are
@@ -65,11 +75,16 @@ struct vlltype;
/* This is information about port name information for named port
connections. */
struct portname_t {
string name;
PExpr*parm;
typedef struct named<PExpr*> portname_t;
struct parmvalue_t {
svector<PExpr*>*by_order;
svector<portname_t*>*by_name;
};
struct str_pair_t { PGate::strength_t str0, str1; };
/* The lgate is gate instantiation information. */
struct lgate {
lgate(int =0)
@@ -84,7 +99,7 @@ struct lgate {
PExpr*range[2];
string file;
const char* file;
unsigned lineno;
};
@@ -114,12 +129,18 @@ extern void pform_pop_scope();
*/
extern void pform_makewire(const struct vlltype&li, const string&name,
NetNet::Type type = NetNet::IMPLICIT);
extern void pform_makewire(const struct vlltype&li, const list<string>*names,
extern void pform_makewire(const struct vlltype&li,
svector<PExpr*>*range,
list<char*>*names,
NetNet::Type type);
extern void pform_set_port_type(list<string>*names, NetNet::PortType);
extern void pform_set_net_range(list<string>*names, const svector<PExpr*>*);
extern void pform_make_reginit(const struct vlltype&li,
const string&name, PExpr*expr);
extern void pform_set_port_type(list<char*>*names, svector<PExpr*>*,
NetNet::PortType);
extern void pform_set_net_range(list<char*>*names, svector<PExpr*>*, bool);
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_reg_integer(list<char*>*names);
extern void pform_set_reg_time(list<char*>*names);
extern void pform_set_task(const string&, PTask*);
extern void pform_set_function(const string&, svector<PExpr*>*, PFunction*);
extern void pform_set_attrib(const string&name, const string&key,
@@ -127,38 +148,45 @@ extern void pform_set_attrib(const string&name, const string&key,
extern void pform_set_type_attrib(const string&name, const string&key,
const string&value);
extern void pform_set_parameter(const string&name, PExpr*expr);
extern void pform_set_localparam(const string&name, PExpr*expr);
extern void pform_set_defparam(const string&name, PExpr*expr);
extern PProcess* pform_make_behavior(PProcess::Type, Statement*);
extern svector<PWire*>* pform_make_udp_input_ports(list<string>*);
extern svector<PWire*>* pform_make_udp_input_ports(list<char*>*);
extern bool pform_expression_is_constant(const PExpr*);
extern void pform_make_events(list<char*>*names,
const char*file, unsigned lineno);
/*
* The makegate function creates a new gate (which need not have a
* name) and connects it to the specified wires.
*/
extern void pform_makegates(PGBuiltin::Type type,
struct str_pair_t str,
svector<PExpr*>*delay,
svector<lgate>*gates);
extern void pform_make_modgates(const string&type,
svector<PExpr*>*overrides,
struct parmvalue_t*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);
svector<PExpr*>*delays,
struct str_pair_t str);
extern void pform_make_pgassign_list(svector<PExpr*>*alist,
svector<PExpr*>*del,
const string& text,
unsigned lineno);
struct str_pair_t str,
const char* fn, 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 string& file,
svector<PExpr*>*range,
list<char*>*names,
const char* file,
unsigned lineno);
@@ -174,6 +202,53 @@ extern void pform_dump(ostream&out, Module*mod);
/*
* $Log: pform.h,v $
* Revision 1.45 2000/12/11 00:31:43 steve
* Add support for signed reg variables,
* simulate in t-vvm signed comparisons.
*
* Revision 1.44 2000/11/30 17:31:42 steve
* Change LineInfo to store const C strings.
*
* Revision 1.43 2000/10/31 17:49:02 steve
* Support time variables.
*
* Revision 1.42 2000/10/31 17:00:05 steve
* Remove C++ string from variable lists.
*
* Revision 1.41 2000/07/29 17:58:21 steve
* Introduce min:typ:max support.
*
* Revision 1.40 2000/05/08 05:30:20 steve
* Deliver gate output strengths to the netlist.
*
* Revision 1.39 2000/05/06 15:41:57 steve
* Carry assignment strength to pform.
*
* Revision 1.38 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.37 2000/03/12 17:09:41 steve
* Support localparam.
*
* Revision 1.36 2000/03/08 04:36:54 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.35 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.34 2000/01/10 22:16:24 steve
* minor type syntax fix for stubborn C++ compilers.
*
* Revision 1.33 2000/01/09 05:50:49 steve
* Support named parameter override lists.
*
* Revision 1.32 1999/12/30 19:06:14 steve
* Support reg initial assignment syntax.
*
* Revision 1.31 1999/09/10 05:02:09 steve
* Handle integers at task parameters.
*
+268 -44
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,8 +16,8 @@
* 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: pform_dump.cc,v 1.45 1999/10/10 01:59:55 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: pform_dump.cc,v 1.66 2001/01/13 22:20:08 steve Exp $"
#endif
/*
@@ -27,6 +27,7 @@
* module in question.
*/
# include "pform.h"
# include "PEvent.h"
# include <iostream>
# include <iomanip>
# include <typeinfo>
@@ -43,6 +44,30 @@ ostream& operator << (ostream&o, const PDelays&d)
return o;
}
ostream& operator<< (ostream&o, PGate::strength_t str)
{
switch (str) {
case PGate::HIGHZ:
o << "highz";
break;
case PGate::WEAK:
o << "weak";
break;
case PGate::PULL:
o << "pull";
break;
case PGate::STRONG:
o << "strong";
break;
case PGate::SUPPLY:
o << "supply";
break;
default:
assert(0);
}
return o;
}
void PExpr::dump(ostream&out) const
{
out << typeid(*this).name();
@@ -58,9 +83,12 @@ void PEConcat::dump(ostream&out) const
return;
}
out << "{" << *parms_[0];
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1)
out << ", " << *parms_[idx];
out << "{";
if (parms_[0]) out << *parms_[0];
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
out << ", ";
if (parms_[idx]) out << *parms_[idx];
}
out << "}";
@@ -70,10 +98,13 @@ void PEConcat::dump(ostream&out) const
void PECallFunction::dump(ostream &out) const
{
out << name_ << "(";
parms_[0]->dump(out);
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
out << ", ";
parms_[idx]->dump(out);
if (parms_.count() > 0) {
if (parms_[0]) parms_[0]->dump(out);
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
out << ", ";
if (parms_[idx]) parms_[idx]->dump(out);
}
}
out << ")";
}
@@ -81,19 +112,25 @@ void PECallFunction::dump(ostream &out) const
void PEEvent::dump(ostream&out) const
{
switch (type_) {
case NetNEvent::ANYEDGE:
case PEEvent::ANYEDGE:
break;
case NetNEvent::POSEDGE:
case PEEvent::POSEDGE:
out << "posedge ";
break;
case NetNEvent::NEGEDGE:
case PEEvent::NEGEDGE:
out << "negedge ";
break;
case NetNEvent::POSITIVE:
case PEEvent::POSITIVE:
out << "positive ";
break;
}
out << *expr_;
}
void PEFNumber::dump(ostream &out) const
{
out << value();
}
void PENumber::dump(ostream&out) const
@@ -182,9 +219,17 @@ void PWire::dump(ostream&out) const
break;
}
if (signed_) {
out << " signed";
}
assert(msb_.count() == lsb_.count());
for (unsigned idx = 0 ; idx < msb_.count() ; idx += 1) {
assert(lsb_[idx] && msb_[idx]);
out << " [" << *msb_[idx] << ":" << *lsb_[idx] << "]";
assert(msb_[idx]);
if (lsb_[idx])
out << " [" << *msb_[idx] << ":" << *lsb_[idx] << "]";
else
out << " [" << *msb_[idx] << "]";
}
out << " " << name_;
@@ -209,7 +254,7 @@ void PWire::dump(ostream&out) const
void PGate::dump_pins(ostream&out) const
{
if (pin_count()) {
out << *pin(0);
if (pin(0)) out << *pin(0);
for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) {
out << ", ";
@@ -247,7 +292,7 @@ void PGate::dump(ostream&out) const
void PGAssign::dump(ostream&out) const
{
out << " assign ";
out << " assign (" << strength0() << "0 " << strength1() << "1) ";
dump_delays(out);
out << " " << *pin(0) << " = " << *pin(1) << ";" << endl;
}
@@ -261,13 +306,32 @@ void PGBuiltin::dump(ostream&out) const
case PGBuiltin::BUFIF1:
out << " bufif1 ";
break;
case PGBuiltin::NOTIF0:
out << " bufif0 ";
break;
case PGBuiltin::NOTIF1:
out << " bufif1 ";
break;
case PGBuiltin::NAND:
out << " nand ";
break;
case PGBuiltin::NMOS:
out << " nmos ";
break;
case PGBuiltin::RNMOS:
out << " rnmos ";
break;
case PGBuiltin::RPMOS:
out << " rpmos ";
break;
case PGBuiltin::PMOS:
out << " pmos ";
break;
default:
out << " builtin gate ";
}
out << "(" << strength0() << "0 " << strength1() << "1) ";
dump_delays(out);
out << " " << get_name();
@@ -283,7 +347,10 @@ void PGBuiltin::dump(ostream&out) const
void PGModule::dump(ostream&out) const
{
out << " " << type_ << " ";
// If parameters are overridden by order, dump them.
if (overrides_) {
assert(parms_ == 0);
out << "#(";
out << *((*overrides_)[0]);
for (unsigned idx = 1 ; idx < overrides_->count() ; idx += 1) {
@@ -291,7 +358,31 @@ void PGModule::dump(ostream&out) const
}
out << ") ";
}
out << get_name() << "(";
// If parameters are overridden by name, dump them.
if (parms_) {
assert(overrides_ == 0);
out << "#(";
out << "." << parms_[0].name << "(" << *parms_[0].parm << ")";
for (unsigned idx = 1 ; idx < nparms_ ; idx += 1) {
out << ", ." << parms_[idx].name << "(" <<
*parms_[idx].parm << ")";
}
out << ") ";
}
out << get_name();
// If the module is arrayed, print the index expressions.
if (msb_ || lsb_) {
out << "[";
if (msb_) out << *msb_;
out << ":";
if (lsb_) out << *lsb_;
out << "]";
}
out << "(";
if (pins_) {
out << "." << pins_[0].name << "(";
if (pins_[0].parm) out << *pins_[0].parm;
@@ -424,6 +515,18 @@ void PCondit::dump(ostream&out, unsigned ind) const
}
}
void PCAssign::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "assign " << *lval_ << " = " << *expr_
<< "; /* " << get_line() << " */" << endl;
}
void PDeassign::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "deassign " << *lval_ << "; /* "
<< get_line() << " */" << endl;
}
void PDelayStatement::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "#" << *delay_ << " /* " <<
@@ -436,6 +539,12 @@ void PDelayStatement::dump(ostream&out, unsigned ind) const
}
}
void PDisable::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "disable " << scope_ << "; /* "
<< get_line() << " */" << endl;
}
void PEventStatement::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "@(" << *(expr_[0]);
@@ -454,6 +563,12 @@ void PEventStatement::dump(ostream&out, unsigned ind) const
}
}
void PForce::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "force " << *lval_ << " = " << *expr_
<< "; /* " << get_line() << " */" << endl;
}
void PForever::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "forever /* " << get_line() << " */" << endl;
@@ -471,11 +586,12 @@ 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;
}
if (ports_)
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
out << setw(ind) << "";
out << "input ";
out << (*ports_)[idx]->name() << ";" << endl;
}
if (statement_)
statement_->dump(out, ind);
@@ -483,6 +599,12 @@ void PFunction::dump(ostream&out, unsigned ind) const
out << setw(ind) << "" << "/* NOOP */" << endl;
}
void PRelease::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "release " << *lval_ << "; /* "
<< get_line() << " */" << endl;
}
void PRepeat::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "repeat (" << *expr_ << ")" << endl;
@@ -514,6 +636,10 @@ void PTask::dump(ostream&out, unsigned ind) const
out << setw(ind) << "" << "/* NOOP */" << endl;
}
void PTrigger::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "-> " << event_ << ";" << endl;
}
void PWhile::dump(ostream&out, unsigned ind) const
{
@@ -549,24 +675,9 @@ void Module::dump(ostream&out) const
continue;
}
switch (cur->wires[0]->get_port_type()) {
case NetNet::PINPUT:
out << " input ." << cur->name << "(";
break;
case NetNet::POUTPUT:
out << " output ." << cur->name << "(";
break;
case NetNet::PINOUT:
out << " inout ." << cur->name << "(";
break;
default:
out << " XXXX ." << cur->name << "(";
break;
}
out << cur->wires[0]->name();
for (unsigned wdx = 1 ; wdx < cur->wires.count() ; wdx += 1) {
out << ", " << cur->wires[wdx]->name();
out << " ." << cur->name << "(" << *cur->expr[0];
for (unsigned wdx = 1 ; wdx < cur->expr.count() ; wdx += 1) {
out << ", " << *cur->expr[wdx];
}
out << ")" << endl;
@@ -582,12 +693,37 @@ void Module::dump(ostream&out) const
out << "/* ERROR */;" << endl;
}
for (parm_iter_t cur = localparams.begin()
; cur != localparams.end() ; cur ++) {
out << " localparam " << (*cur).first << " = ";
if ((*cur).second)
out << *(*cur).second << ";" << endl;
else
out << "/* ERROR */;" << endl;
}
for (parm_iter_t cur = defparms.begin()
; cur != defparms.end() ; cur ++) {
out << " defparam " << (*cur).first << " = ";
if ((*cur).second)
out << *(*cur).second << ";" << endl;
else
out << "/* ERROR */;" << endl;
}
for (map<string,PEvent*>::const_iterator cur = events.begin()
; cur != events.end() ; cur ++ ) {
PEvent*ev = (*cur).second;
out << " event " << ev->name() << "; // "
<< ev->get_line() << endl;
}
// Iterate through and display all the wires.
for (list<PWire*>::const_iterator wire = wires_.begin()
for (map<string,PWire*>::const_iterator wire = wires_.begin()
; wire != wires_.end()
; wire ++ ) {
(*wire)->dump(out);
(*wire).second->dump(out);
}
// Dump the task definitions.
@@ -675,6 +811,94 @@ void PUdp::dump(ostream&out) const
/*
* $Log: pform_dump.cc,v $
* Revision 1.66 2001/01/13 22:20:08 steve
* Parse parameters within nested scopes.
*
* Revision 1.65 2000/12/11 00:31:43 steve
* Add support for signed reg variables,
* simulate in t-vvm signed comparisons.
*
* Revision 1.64 2000/12/10 22:01:36 steve
* Support decimal constants in behavioral delays.
*
* Revision 1.63 2000/11/11 01:52:09 steve
* change set for support of nmos, pmos, rnmos, rpmos, notif0, and notif1
* change set to correct behavior of bufif0 and bufif1
* (Tim Leight)
*
* Also includes fix for PR#27
*
* Revision 1.62 2000/10/14 02:23:02 steve
* Check for missing concat subexpressions (PR#11)
*
* Revision 1.61 2000/07/26 05:08:07 steve
* Parse disable statements to pform.
*
* Revision 1.60 2000/05/23 16:03:13 steve
* Better parsing of expressions lists will empty expressoins.
*
* Revision 1.59 2000/05/16 04:05:16 steve
* Module ports are really special PEIdent
* expressions, because a name can be used
* many places in the port list.
*
* Revision 1.58 2000/05/11 23:37:27 steve
* Add support for procedural continuous assignment.
*
* Revision 1.57 2000/05/06 15:41:57 steve
* Carry assignment strength to pform.
*
* Revision 1.56 2000/05/04 03:37:59 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.55 2000/04/22 04:20:19 steve
* Add support for force assignment.
*
* Revision 1.54 2000/04/12 20:02:53 steve
* Finally remove the NetNEvent and NetPEvent classes,
* Get synthesis working with the NetEvWait class,
* and get started supporting multiple events in a
* wait in vvm.
*
* Revision 1.53 2000/04/12 04:23:58 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.52 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.51 2000/03/12 17:09:41 steve
* Support localparam.
*
* Revision 1.50 2000/03/08 04:36:54 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.49 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.48 2000/02/18 05:15:03 steve
* Catch module instantiation arrays.
*
* Revision 1.47 2000/01/09 20:37:57 steve
* Careful with wires connected to multiple ports.
*
* Revision 1.46 2000/01/09 05:50:49 steve
* Support named parameter override lists.
*
* Revision 1.45 1999/10/10 01:59:55 steve
* Structural case equals device.
*

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