Compare commits

...
223 Commits
Author SHA1 Message Date
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
154 changed files with 19913 additions and 7486 deletions
+3
View File
@@ -1,3 +1,4 @@
lexor_keyword.cc
parse.h
parse.cc
parse.cc.output
@@ -7,6 +8,8 @@ dep
configure
Makefile
verilog
gverilog
iverilog
config.status
config.log
config.cache
+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: LineInfo.h,v 1.3 1999/02/15 02:06:15 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: LineInfo.h,v 1.4 2000/02/23 02:56:53 steve Exp $"
#endif
# include <cstdio>
@@ -50,6 +50,9 @@ class LineInfo {
/*
* $Log: LineInfo.h,v $
* 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.
*
+39 -14
View File
@@ -18,12 +18,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.54 2000/05/12 05:23:15 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.0
VERSION = 0.3PRE
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -39,6 +39,7 @@ includedir = $(prefix)/include
CC = @CC@
CXX = @CXX@
INSTALL = @INSTALL@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
STRIP = @STRIP@
@@ -47,7 +48,7 @@ CPPFLAGS = @CPPFLAGS@ @DEFS@
CXXFLAGS = @CXXFLAGS@ -I$(srcdir)
LDFLAGS = @LDFLAGS@
all: ivl verilog
all: ivl verilog iverilog
cd vpi ; $(MAKE) all
cd vvm ; $(MAKE) all
cd ivlpp ; $(MAKE) all
@@ -66,14 +67,18 @@ distclean: clean
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
FF = nodangle.o propinit.o synth.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_net.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_design.o net_event.o net_force.o net_scope.o net_udp.o nexus_from_link.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 Module.o PDelays.o PEvent.o \
PExpr.o PGate.o \
PTask.o PFunction.o PWire.o Statement.o \
$(FF) $(TT)
@@ -91,11 +96,15 @@ verilog: $(srcdir)/verilog.sh
sed -e 's;@$(tmp1)@;@bindir@;' \
-e 's;@$(tmp2)@;@libdir@;' \
-e 's;@$(tmp3)@;@includedir@;' \
-e 's;@dllib@;@DLLIB@;' \
-e 's;@$(tmp4)@;@CXX@;' < $< > $@
ivl: $O
$(CXX) $(CXXFLAGS) -o ivl $O
iverilog: iverilog.c
$(CC) $(CPPFLAGS) -o iverilog -DCXX='"@CXX@"' -DIVL_ROOT='"@libdir@/ivl"' -DIVL_INC='"@includedir@"' -DIVL_LIB='"@libdir@"' -DDLLIB='"@DLLIB@"' iverilog.c
%.o dep/%.d: %.cc
@[ -d dep ] || mkdir dep
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o
@@ -113,28 +122,44 @@ parse.h parse.cc: $(srcdir)/parse.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
lexor_keyword.o dep/lexor_keyword.d: 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 lexor_keyword.gperf > lexor_keyword.cc
install: all installdirs $(bindir)/verilog $(bindir)/iverilog $(libdir)/ivl/ivl $(mandir)/man1/verilog.1 $(mandir)/man1/iverilog.1
cd vpi ; $(MAKE) install
cd vvm ; $(MAKE) install
cd ivlpp ; $(MAKE) install
$(bindir)/verilog: ./verilog
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
$(INSTALL_SCRIPT) ./verilog $(bindir)/verilog
$(bindir)/ivl: ivl
$(INSTALL_PROGRAM) ./ivl $(bindir)/ivl
$(STRIP) $(bindir)/ivl
$(bindir)/iverilog: ./iverilog
$(INSTALL_PROGRAM) ./iverilog $(bindir)/iverilog
$(STRIP) $(bindir)/iverilog
$(libdir)/ivl/ivl: ./ivl
$(INSTALL_PROGRAM) ./ivl $(libdir)/ivl/ivl
$(STRIP) $(libdir)/ivl/ivl
$(mandir)/man1/verilog.1: $(srcdir)/verilog.1
$(INSTALL_DATA) $(srcdir)/verilog.1 $(mandir)/man1/verilog.1
$(mandir)/man1/iverilog.1: $(srcdir)/iverilog.man
$(INSTALL_DATA) $(srcdir)/iverilog.man $(mandir)/man1/iverilog.1
installdirs: mkinstalldirs
$(srcdir)/mkinstalldirs $(bindir) $(mandir)/man1
$(srcdir)/mkinstalldirs $(bindir) $(libdir)/ivl $(mandir)/man1
uninstall:
rm -f $(bindir)/ivl
rm -f $(libdir)/ivl/ivl
rm -f $(bindir)/verilog
rm -f $(bindir)/gverilog
rm -f $(bindir)/iverilog
rm -f $(mandir)/man1/verilog.1
rm -f $(mandir)/man1/iverilog.1
cd vpi ; $(MAKE) uninstall
cd vvm ; $(MAKE) uninstall
cd ivlpp ; $(MAKE) uninstall
+66 -11
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,24 +16,38 @@
* 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.11 2000/03/12 17:09:40 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) {
// Save the list of ports, then scan the list to make
// the implicit wires. Add those wires to the wire map.
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]);
// The port can actually be a list of wires, to
// remember to scan the set. Also note the case
// where a wire may be connected to multiple
// ports, and reuse the link if that happens.
for (unsigned jdx = 0; jdx < cur->wires.count(); jdx += 1) {
PWire*tmp = add_wire(cur->wires[jdx]);
if (tmp != cur->wires[jdx]) {
delete cur->wires[jdx];
cur->wires[jdx] = tmp;
}
}
}
}
}
@@ -53,9 +67,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)
@@ -85,22 +104,58 @@ 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.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.
*
+61 -10
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,14 +18,16 @@
* 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.18 2000/05/02 16:27:38 steve Exp $"
#endif
# include <list>
# include <map>
# include "svector.h"
# include "named.h"
# include <string>
class PEvent;
class PExpr;
class PGate;
class PTask;
@@ -64,6 +66,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,10 +82,19 @@ 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;
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);
@@ -87,20 +105,25 @@ class Module {
// 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_;
svector<port_t*> ports_;
list<PWire*> wires_;
map<string,PWire*> wires_;
list<PGate*> gates_;
list<PProcess*> behaviors_;
map<string,PTask*> tasks_;
@@ -114,6 +137,34 @@ class Module {
/*
* $Log: Module.h,v $
* 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
+133 -10
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.18 2000/05/07 04:37:55 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,70 @@ 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_;
}
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;
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 +179,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;
@@ -128,6 +214,43 @@ bool PETernary::is_constant(Module*) const
/*
* $Log: PExpr.cc,v $
* 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
+162 -44
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.37 2000/05/07 04:37:56 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,7 +66,10 @@ 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 gates, but
// restricted for use as l-values of continuous assignments.
@@ -79,6 +91,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,8 +101,7 @@ 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;
@@ -96,8 +110,10 @@ class PEConcat : 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 NetExpr*elaborate_expr(Design*des, NetScope*) const;
virtual bool is_constant(Module*) const;
private:
@@ -105,28 +121,38 @@ 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:
NetNEvent::Type type_;
PExpr*expr_;
edge_t type_;
PExpr *expr_;
};
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;
@@ -138,15 +164,17 @@ class PEIdent : public PExpr {
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;
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 +198,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 +225,12 @@ 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 bool is_constant(Module*) const;
@@ -219,8 +249,11 @@ class PEUnary : 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 NetEUnary*elaborate_expr(Design*des, NetScope*) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
private:
char op_;
@@ -240,8 +273,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 +285,38 @@ 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_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 +339,12 @@ 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 verinum* eval_const(const Design*des, const string&path) const;
private:
@@ -294,25 +354,83 @@ 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.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.
*
+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: PFunction.cc,v 1.2 1999/08/25 22:22:41 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PFunction.cc,v 1.3 2000/02/23 02:56:53 steve Exp $"
#endif
#include "PTask.h"
@@ -39,6 +39,9 @@ void PFunction::set_output(PWire*o)
/*
* $Log: PFunction.cc,v $
* 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.
*
+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: PTask.cc,v 1.2 1999/07/24 02:11:19 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PTask.cc,v 1.3 2000/02/23 02:56:53 steve Exp $"
#endif
# include "PTask.h"
@@ -33,6 +33,9 @@ PTask::~PTask()
/*
* $Log: PTask.cc,v $
* 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.
*
+24 -5
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.8 2000/03/08 04:36:53 steve Exp $"
#endif
# include "LineInfo.h"
# include "svector.h"
# include <string>
class Design;
class NetScope;
class PWire;
class Statement;
@@ -38,6 +39,12 @@ class PTask : public LineInfo {
explicit PTask(svector<PWire*>*p, Statement*s);
~PTask();
// 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;
void elaborate_1(Design*des, const string&path) const;
void elaborate_2(Design*des, const string&path) const;
@@ -65,9 +72,11 @@ class PFunction : public LineInfo {
void set_output(PWire*);
void elaborate_scope(Design*des, NetScope*scope) const;
/* 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_1(Design *des, NetScope*) const;
void elaborate_2(Design *des, NetScope*) const;
void dump(ostream&, unsigned) const;
@@ -79,6 +88,16 @@ class PFunction : public LineInfo {
/*
* $Log: PTask.h,v $
* 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.
*
+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: PWire.cc,v 1.2 1999/09/10 05:02:09 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PWire.cc,v 1.3 2000/02/23 02:56:54 steve Exp $"
#endif
# include "PWire.h"
@@ -100,6 +100,9 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
/*
* $Log: PWire.cc,v $
* 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.
*
+10 -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.8 2000/05/02 16:27:38 steve Exp $"
#endif
# include "netlist.h"
@@ -58,7 +58,7 @@ class PWire : public LineInfo {
// Write myself to the specified stream.
void dump(ostream&out) const;
void elaborate(Design*, NetScope*scope) const;
void elaborate_sig(Design*, NetScope*scope) const;
private:
string name_;
@@ -82,6 +82,12 @@ class PWire : public LineInfo {
/*
* $Log: PWire.h,v $
* 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.
*
+50 -16
View File
@@ -42,6 +42,12 @@ on a UNIX-like system:
- 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.
2.2 Compilation
Unpack the tar-ball and cd into the verilog-######### directory
@@ -104,6 +110,33 @@ 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 teh 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
@@ -166,6 +199,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
@@ -273,13 +317,6 @@ 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
@@ -295,19 +332,14 @@ current state of support for Verilog.
- 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.
- multiplicative operators (*, /, %) are not supported in
general. They do work if the compiler can evaluate them at compile
time.
assign foo = a * b; // sorry
always @(a or b) foo = a * b; // sorry
@@ -340,15 +372,17 @@ 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]>
Yasuhisa Kato <[email protected]>
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]>
+117 -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.21 2000/05/11 23:37:26 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,60 @@ 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()
{
}
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 +214,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 +235,15 @@ PRepeat::~PRepeat()
delete statement_;
}
PTrigger::PTrigger(const string&e)
: event_(e)
{
}
PTrigger::~PTrigger()
{
}
PWhile::~PWhile()
{
delete cond_;
@@ -163,6 +252,31 @@ PWhile::~PWhile()
/*
* $Log: Statement.cc,v $
* 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
*
+130 -12
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.26 2000/05/11 23:37:26 steve Exp $"
#endif
# include <string>
@@ -30,6 +30,10 @@
class PExpr;
class Statement;
class PEventStatement;
class Design;
class NetCAssign;
class NetDeassign;
class NetScope;
/*
* The PProcess is the root of a behavioral process. Each process gets
@@ -70,6 +74,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;
};
/*
@@ -155,6 +160,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 +210,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 +224,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 +258,55 @@ 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_;
};
/*
* 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 +317,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 +354,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 +381,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 +389,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 +427,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 +437,34 @@ class PWhile : public Statement {
/*
* $Log: Statement.h,v $
* 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
*
+18 -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.3 2000/03/17 21:50:25 steve Exp $"
#endif
/*
@@ -33,8 +33,23 @@
# define INTEGER_WIDTH 32
#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.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.
*
+42
View File
@@ -7,5 +7,47 @@ AC_PROG_CXX
AC_CHECK_TOOL(STRIP, strip, true)
AC_CHECK_HEADERS(getopt.h)
AC_PROG_INSTALL
AC_CHECK_LIB(dl,main,[DLLIB=-ldl])
AC_SUBST(DLLIB)
#######################
## test for underscores
#######################
AC_MSG_CHECKING("for leading and/or trailing underscores")
cat << EOF > underscore.c
void underscore(void){}
EOF
$CC -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"; 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
#######################
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile)
+275 -117
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,53 @@
* 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.9 2000/05/07 04:37:56 steve Exp $"
#endif
# include "netlist.h"
# include "functor.h"
# include <assert.h>
/*
* 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.
*/
static bool all_drivers_constant(const Link&lnk)
{
for (const Link*cur = lnk.next_link()
; *cur != lnk ; cur = cur->next_link()) {
if (cur->get_dir() == Link::INPUT)
continue;
if (cur->get_dir() == Link::PASSIVE)
continue;
if (! dynamic_cast<const NetConst*>(cur->get_obj()))
return false;
}
return true;
}
/*
* 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 all_drivers_constant(lnk) == true.
*/
static verinum::V driven_value(const Link&lnk)
{
for (const Link*cur = lnk.next_link()
; *cur != lnk ; cur = cur->next_link()) {
const NetConst*obj;
if (obj = dynamic_cast<const NetConst*>(cur->get_obj()))
return obj->value(cur->get_pin());
}
return verinum::Vz;
}
/*
* The cprop function below invokes constant propogation where
* possible. The elaboration generates NetConst objects. I can remove
@@ -30,163 +70,281 @@
* 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);
};
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)
&& all_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)
&& all_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(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->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->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;
bool flag = false;
switch (log->type()) {
case NetLogic::XNOR:
flag = const_into_xnor(des, obj, log, pin);
break;
default:
break;
case NetLogic::AND:
// If there is one zero input to an AND gate, we know
// the resulting output is going to be zero and can
// elininate the gate.
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
if (! all_drivers_constant(obj->pin(idx)))
continue;
if (driven_value(obj->pin(idx)) == verinum::V0) {
connect(obj->pin(0), obj->pin(idx));
delete obj;
count += 1;
return;
}
}
/* If the optimization test tells me that a link was
deleted, restart the scan. */
if (flag) obj->pin(0).next_link(cur, pin);
// There are no zero constant drivers. If there are any
// non-constant drivers, give up.
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
if (! all_drivers_constant(obj->pin(idx)))
return;
}
// If there are any non-1 values (Vx or Vz) then the
// result is Vx.
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
if (driven_value(obj->pin(idx)) != verinum::V1) {
connect(obj->pin(0), obj->pin(idx));
delete obj;
count += 1;
return;
}
}
// What's left? The inputs are all 1's, return the first
// input as the output value and remove the gate.
connect(obj->pin(0), obj->pin(1));
delete obj;
count += 1;
return;
default:
break;
}
}
/*
* This function looks to see if the constant is connected to nothing
* 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.
* the now useless signals. This functor is applied after the regular
* functor to clean up dangling constants that might be left behind.
*/
static void dangling_const(Design*des, NetConst*obj)
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)
{
// If there are any links that take input, abort this
// operation.
if (count_inputs(obj->pin(0)) > 0)
return;
// If there are no other drivers, delete all the signals that
// are also dangling.
if (count_outputs(obj->pin(0)) == 1) {
// 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) {
NetObj*cur;
unsigned pin;
obj->pin(0).next_link(cur, pin);
obj->pin(idx).next_link(cur, pin);
while (cur != obj) {
cerr << "cprop: delete dangling signal " << cur->name() <<
"." << endl;
delete cur;
obj->pin(0).next_link(cur, pin);
NetNet*tmp = dynamic_cast<NetNet*>(cur);
if (tmp && tmp->get_eref() > 0)
return;
cur->pin(pin).next_link(cur, pin);
}
}
// 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.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,
+288 -349
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,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: design_dump.cc,v 1.61 1999/11/28 23:42:02 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: design_dump.cc,v 1.85 2000/05/11 23:37:27 steve Exp $"
#endif
/*
@@ -42,6 +42,30 @@ static ostream& operator<< (ostream&o, NetBlock::Type t)
return o;
}
ostream& operator << (ostream&o, Link::strength_t str)
{
switch (str) {
case Link::HIGHZ:
o << "highz";
break;
case Link::WEAK:
o << "weak";
break;
case Link::PULL:
o << "pull";
break;
case Link::STRONG:
o << "strong";
break;
case Link::SUPPLY:
o << "supply";
break;
default:
assert(0);
}
return o;
}
/* Dump a net. This can be a wire or register. */
void NetNet::dump_net(ostream&o, unsigned ind) const
{
@@ -49,6 +73,7 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
pin_count() << "]";
if (local_flag_)
o << " (local)";
o << " (eref=" << get_eref() << ")";
if (scope_)
o << " scope=" << scope_->name();
o << " #(" << rise_time() << "," << fall_time() << "," <<
@@ -56,6 +81,23 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
o << ivalue_[idx-1];
o << endl;
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
if (! pin(idx).is_linked())
continue;
o << setw(ind+4) << "" << "[" << idx << "]:";
unsigned cpin;
const NetObj*cur;
for (pin(idx).next_link(cur, cpin)
; (cur != this) || (cpin != idx)
; cur->pin(cpin).next_link(cur, cpin)) {
o << " " << cur->name() << "[" << cpin << "]";
}
o << endl;
}
dump_obj_attr(o, ind+4);
}
@@ -100,7 +142,9 @@ void NetObj::dump_node_pins(ostream&o, unsigned ind) const
o << " O";
break;
}
o << ":";
o << " (" << pin(idx).drive0() << "0 "
<< pin(idx).drive1() << "1):";
unsigned cpin;
const NetObj*cur;
@@ -132,6 +176,13 @@ void NetAddSub::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetCAssign::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Procedural continuous assign (NetCAssign): "
<< name() << endl;
dump_node_pins(o, ind+4);
}
void NetCLShift::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " <<
@@ -142,8 +193,27 @@ void NetCLShift::dump_node(ostream&o, unsigned ind) const
void NetCompare::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_COMPARE (NetCompare): " <<
name() << endl;
o << setw(ind) << "" << "LPM_COMPARE (NetCompare): " << name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetDivide::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "NET_DIVIDE (NetDivide): " << name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetForce::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "force " << lval_->name() << endl;
dump_node_pins(o, ind+4);
}
void NetMult::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_MULT (NetMult): " << name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
@@ -189,7 +259,10 @@ void NetCaseCmp::dump_node(ostream&o, unsigned ind) const
void NetConst::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "constant " << value_ << ": " << name() << endl;
o << setw(ind) << "" << "constant ";
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
o << value_[idx-1];
o << ": " << name() << endl;
dump_node_pins(o, ind+4);
}
@@ -327,18 +400,7 @@ void NetUDP::dump_sequ_(ostream&o, unsigned ind) const
void NetUDP::dump_comb_(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Combinational UDP: ";
o << " #(" << rise_time() << "," << fall_time() << "," << decay_time() <<
") " << name() << endl;
for (CM_::const_iterator ent = cm_.begin()
; ent != cm_.end() ; ent++) {
o << setw(ind+6) << "" << (*ent).first << " --> " <<
(*ent).second << endl;
}
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
assert(0);
}
void NetUDP::dump_node(ostream&o, unsigned ind) const
@@ -349,27 +411,20 @@ void NetUDP::dump_node(ostream&o, unsigned ind) const
dump_comb_(o, ind);
}
void NetNEvent::dump_node(ostream&o, unsigned ind) const
void NetUDP_COMB::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "event: ";
switch (edge_) {
case ANYEDGE:
o << "anyedge ";
break;
case POSEDGE:
o << "posedge ";
break;
case NEGEDGE:
o << "negedge ";
break;
case POSITIVE:
o << "positive ";
break;
o << setw(ind) << "" << "Combinational primitive: ";
o << " #(" << rise_time() << "," << fall_time() << "," << decay_time() <<
") " << name() << endl;
for (map<string,char>::const_iterator ent = cm_.begin()
; ent != cm_.end() ; ent++) {
o << setw(ind+6) << "" << (*ent).first << " --> " <<
(*ent).second << endl;
}
o << name() << " --> " << fore_ptr()->name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetProcTop::dump(ostream&o, unsigned ind) const
@@ -428,9 +483,7 @@ void NetAssignMem::dump(ostream&o, unsigned ind) const
o << setw(ind) << "";
o << "/* " << get_line() << " */" << endl;
o << setw(ind) << "";
o << memory()->name() << "[";
index()->dump(o);
o << "] = ";
o << memory()->name() << "[" << index()->name() << "] = ";
rval()->dump(o);
o << ";" << endl;
}
@@ -440,9 +493,7 @@ void NetAssignMemNB::dump(ostream&o, unsigned ind) const
o << setw(ind) << "";
o << "/* " << get_line() << " */" << endl;
o << setw(ind) << "";
o << memory()->name() << "[";
index()->dump(o);
o << "] <= ";
o << memory()->name() << "[" << index()->name() << "] <= ";
rval()->dump(o);
o << ";" << endl;
}
@@ -495,6 +546,12 @@ void NetCase::dump(ostream&o, unsigned ind) const
o << setw(ind) << "" << "endcase" << endl;
}
void NetCAssign::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "cassign " << lval_->name() << " = "
<< name() << ";" << endl;
}
void NetCondit::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "if (";
@@ -510,6 +567,60 @@ void NetCondit::dump(ostream&o, unsigned ind) const
}
}
void NetDeassign::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "deassign " << lval_->name() << "; "
<< "/* " << get_line() << " */" << endl;
}
void NetEvProbe::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "";
switch (edge_) {
case ANYEDGE:
o << "anyedge ";
break;
case POSEDGE:
o << "posedge ";
break;
case NEGEDGE:
o << "negedge ";
break;
}
o << setw(ind) << "" << "-> " << event_->full_name() << "; " << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetEvTrig::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "-> " << event_->name() << "; "
<< "// " << get_line() << endl;
}
void NetEvWait::dump(ostream&o, unsigned ind) const
{
assert(nevents() > 0);
o << setw(ind) <<"" << "@(" << event(0)->name();
for (unsigned idx = 1 ; idx < nevents() ; idx += 1)
o << " or " << event(idx)->name();
o << ") // " << get_line() << endl;
if (statement_)
statement_->dump(o, ind+2);
else
o << setw(ind+2) << "" << "/* noop */ ;" << endl;
}
void NetForce::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "force " << lval_->name() << " = "
<< name() << ";" << endl;
}
void NetForever::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "forever" << endl;
@@ -518,7 +629,7 @@ void NetForever::dump(ostream&o, unsigned ind) const
void NetFuncDef::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "function " << name_ << endl;
o << setw(ind) << "" << "function " << scope_->name() << endl;
if (statement_)
statement_->dump(o, ind+2);
else
@@ -536,43 +647,10 @@ void NetPDelay::dump(ostream&o, unsigned ind) const
}
}
void NetPEvent::dump(ostream&o, unsigned ind) const
void NetRelease::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "@(";
svector<const NetNEvent*>*list = back_list();
(*list)[0]->dump_proc(o);
for (unsigned idx = 1 ; idx < list->count() ; idx += 1) {
o << " or ";
(*list)[idx]->dump_proc(o);
}
delete list;
o << ") /* " << name_ << " */";
if (statement_) {
o << endl;
statement_->dump(o, ind+2);
} else {
o << " /* noop */;" << endl;
}
}
void NetNEvent::dump_proc(ostream&o) const
{
switch (edge_) {
case ANYEDGE:
o << "anyedge ";
break;
case POSEDGE:
o << "posedge ";
break;
case NEGEDGE:
o << "negedge ";
break;
case POSITIVE:
o << "positive ";
break;
}
o << name();
o << setw(ind) << "" << "release " << lval_->name() << "; "
<< "/* " << get_line() << " */" << endl;
}
void NetRepeat::dump(ostream&o, unsigned ind) const
@@ -583,7 +661,7 @@ void NetRepeat::dump(ostream&o, unsigned ind) const
void NetScope::dump(ostream&o) const
{
o << name_;
o << name();
switch (type_) {
case BEGIN_END:
o << " sequential block";
@@ -591,11 +669,71 @@ void NetScope::dump(ostream&o) const
case FORK_JOIN:
o << " parallel block";
break;
case FUNC:
o << " function";
break;
case MODULE:
o << " module";
break;
case TASK:
o << " task";
break;
}
o << endl;
/* Dump the parameters for this scope. */
{
map<string,NetExpr*>::const_iterator pp;
for (pp = parameters_.begin()
; pp != parameters_.end() ; pp ++) {
o << " parameter " << (*pp).first << " = " <<
*(*pp).second << ";" << endl;
}
for (pp = localparams_.begin()
; pp != localparams_.end() ; pp ++) {
o << " localparam " << (*pp).first << " = " <<
*(*pp).second << ";" << endl;
}
}
/* Dump the saved defparam assignments here. */
{
map<string,NetExpr*>::const_iterator pp;
for (pp = defparams.begin()
; pp != defparams.end() ; pp ++ ) {
o << " defparam " << (*pp).first << " = " <<
*(*pp).second << ";" << endl;
}
}
/* Dump the events in this scope. */
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) {
o << " event " << cur->name() << "; "
<< "// " << cur->get_line() << endl;
}
// Dump the signals,
if (signals_) {
NetNet*cur = signals_->sig_next_;
do {
cur->dump_net(o, 4);
cur = cur->sig_next_;
} while (cur != signals_->sig_next_);
}
// Dump the memories,
if (memories_) {
NetMemory*cur = memories_->snext_;
do {
cur->dump(o, 4);
cur = cur->snext_;
} while (cur != memories_->snext_);
}
/* Dump any sub-scopes. */
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_)
cur->dump(o);
}
void NetSTask::dump(ostream&o, unsigned ind) const
@@ -729,6 +867,16 @@ void NetEScope::dump(ostream&o) const
o << "<scope=" << scope_->name() << ">";
}
void NetESFunc::dump(ostream&o) const
{
o << name_ << "(";
if (nparms() > 0)
o << *parm(0);
for (unsigned idx = 1 ; idx < nparms() ; idx += 1)
o << ", " << *parm(idx);
o << ")";
}
void NetESignal::dump(ostream&o) const
{
o << name();
@@ -745,13 +893,13 @@ void NetESubSignal::dump(ostream&o) const
void NetEMemory::dump(ostream&o) const
{
o << mem_->name() << "[";
idx_->dump(o);
if (idx_) idx_->dump(o);
o << "]";
}
void NetEParam::dump(ostream&o) const
{
o << "<" << path_ << "." << name_ << ">";
o << "<" << scope_->name() << "." << name_ << ">";
}
void NetETernary::dump(ostream&o) const
@@ -790,42 +938,7 @@ void NetEUnary::dump(ostream&o) const
void Design::dump(ostream&o) const
{
o << "SCOPES:" << endl;
{
map<string,NetScope*>::const_iterator pp;
for (pp = scopes_.begin()
; pp != scopes_.end() ; pp ++)
(*pp).second -> dump(o);
}
o << "ELABORATED PARAMETERS:" << endl;
{
map<string,NetExpr*>::const_iterator pp;
for (pp = parameters_.begin()
; pp != parameters_.end() ; pp ++) {
o << " " << (*pp).first << " = " <<
*(*pp).second << ";" << endl;
}
}
o << "ELABORATED SIGNALS:" << endl;
// Dump the signals,
if (signals_) {
NetNet*cur = signals_->sig_next_;
do {
cur->dump_net(o, 0);
cur = cur->sig_next_;
} while (cur != signals_->sig_next_);
}
o << "ELABORATED MEMORIES:" << endl;
{
map<string,NetMemory*>::const_iterator pp;
for (pp = memories_.begin()
; pp != memories_.end() ; pp ++) {
(*pp).second->dump(o, 0);
}
}
root_scope_->dump(o);
o << "ELABORATED FUNCTION DEFINITIONS:" << endl;
{
@@ -866,256 +979,82 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.61 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
* Revision 1.85 2000/05/11 23:37:27 steve
* Add support for procedural continuous assignment.
*
* Revision 1.60 1999/11/27 19:07:57 steve
* Support the creation of scopes.
* Revision 1.84 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.59 1999/11/24 04:01:58 steve
* Detect and list scope names.
* Revision 1.83 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Revision 1.58 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
* 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.57 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
* Revision 1.82 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.56 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
* Revision 1.81 2000/05/02 03:13:30 steve
* Move memories to the NetScope object.
*
* Revision 1.55 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
* Revision 1.80 2000/05/02 00:58:11 steve
* Move signal tables to the NetScope 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.79 2000/04/28 21:00:29 steve
* Over agressive signal elimination in constant probadation.
*
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
* Revision 1.78 2000/04/23 03:45:24 steve
* Add support for the procedural release statement.
*
* Revision 1.54 1999/11/04 01:12:41 steve
* Elaborate combinational UDP devices.
* Revision 1.77 2000/04/22 04:20:19 steve
* Add support for force assignment.
*
* Revision 1.53 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
* Revision 1.76 2000/04/12 20:02:52 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.52 1999/10/31 20:08:24 steve
* Include subtraction in LPM_ADD_SUB device.
* Revision 1.75 2000/04/12 04:23:57 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Revision 1.51 1999/10/31 04:11:27 steve
* Add to netlist links pin name and instance number,
* and arrange in vvm for pin connections by name
* and instance number.
* 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.
*
* Revision 1.50 1999/10/10 01:59:54 steve
* Structural case equals device.
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.49 1999/10/08 02:00:35 steve
* Fix dump of sase statements.
* Revision 1.74 2000/04/10 05:26:05 steve
* All events now use the NetEvent class.
*
* Revision 1.48 1999/10/07 05:25:33 steve
* Add non-const bit select in l-value of assignment.
* Revision 1.73 2000/04/04 03:20:15 steve
* Simulate named event trigger and waits.
*
* Revision 1.47 1999/10/06 05:06:16 steve
* Move the rvalue into NetAssign_ common code.
* Revision 1.72 2000/04/02 04:26:06 steve
* Remove the useless sref template.
*
* Revision 1.46 1999/10/05 06:19:46 steve
* Add support for reduction NOR.
* Revision 1.71 2000/04/01 21:40:22 steve
* Add support for integer division.
*
* Revision 1.45 1999/09/30 02:43:01 steve
* Elaborate ~^ and ~| operators.
* Revision 1.70 2000/03/29 04:37:10 steve
* New and improved combinational primitives.
*
* Revision 1.44 1999/09/29 18:36:03 steve
* Full case support
*
* Revision 1.43 1999/09/21 00:13:40 steve
* Support parameters that reference other paramters.
*
* Revision 1.42 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
* Revision 1.41 1999/09/19 01:06:36 steve
* dump the repeat count, if applicable.
*
* Revision 1.40 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.39 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.38 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.37 1999/09/01 20:46:19 steve
* Handle recursive functions and arbitrary function
* references to other functions, properly pass
* function parameters and save function results.
*
* Revision 1.36 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.35 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.34 1999/08/01 16:34:50 steve
* Parse and elaborate rise/fall/decay times
* for gates, and handle the rules for partial
* lists of times.
*
* Revision 1.33 1999/07/24 02:11:20 steve
* Elaborate task input ports.
*
* Revision 1.32 1999/07/17 19:50:59 steve
* netlist support for ternary operator.
*
* Revision 1.31 1999/07/03 02:12:51 steve
* Elaborate user defined tasks.
*
* Revision 1.30 1999/06/19 21:06:16 steve
* Elaborate and supprort to vvm the forever
* and repeat statements.
*
* Revision 1.29 1999/06/15 05:38:15 steve
* Handle total lack of signals or nodes.
*
* Revision 1.28 1999/06/09 03:00:05 steve
* Add support for procedural concatenation expression.
*
* Revision 1.27 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.26 1999/05/31 15:46:20 steve
* Compilation warning.
*
* Revision 1.25 1999/05/30 01:11:46 steve
* Exressions are trees that can duplicate, and not DAGS.
*
* Revision 1.24 1999/05/17 04:53:47 steve
* translate the letter synonyms for operators.
*
* Revision 1.23 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.22 1999/05/06 02:29:32 steve
* Excesss endl.
*
* Revision 1.21 1999/05/05 03:04:46 steve
* Fix handling of null delay statements.
*
* Revision 1.20 1999/05/01 20:43:55 steve
* Handle wide events, such as @(a) where a has
* many bits in it.
*
* Add to vvm the binary ^ and unary & operators.
*
* Dump events a bit more completely.
*
* Revision 1.19 1999/05/01 02:57:52 steve
* Handle much more complex event expressions.
*
* Revision 1.18 1999/04/25 00:44:10 steve
* Core handles subsignal expressions.
*
* Revision 1.17 1999/04/19 01:59:36 steve
* Add memories to the parse and elaboration phases.
*
* Revision 1.16 1999/03/15 02:43:32 steve
* Support more operators, especially logical.
*
* Revision 1.15 1999/03/01 03:27:53 steve
* Prevent the duplicate allocation of ESignal objects.
*
* Revision 1.14 1999/02/21 17:01:57 steve
* Add support for module parameters.
*
* Revision 1.13 1999/02/15 02:06:15 steve
* Elaborate gate ranges.
*
* Revision 1.12 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.11 1999/02/03 04:20:11 steve
* Parse and elaborate the Verilog CASE statement.
*
* Revision 1.10 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.9 1998/12/20 02:05:41 steve
* Function to calculate wire initial value.
*
* Revision 1.8 1998/12/14 02:01:34 steve
* Fully elaborate Sequential UDP behavior.
*
* Revision 1.7 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.6 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.5 1998/12/01 00:42:13 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.4 1998/11/23 00:20:22 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/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:56 steve
* Introduce verilog to CVS.
* Revision 1.69 2000/03/12 17:09:40 steve
* Support localparam.
*
* Revision 1.68 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.
*/
+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.
*
+227 -51
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,24 +16,30 @@
* 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.25 2000/05/07 18:20:07 steve Exp $"
#endif
# include "pform.h"
# include "netlist.h"
NetExpr* PExpr::elaborate_expr(Design*des, NetScope*) const
{
cerr << get_line() << ": I do not know how to elaborate expression: "
<< *this << endl;
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 +61,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 +88,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 +142,59 @@ 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(), 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);
NetScope*dscope = des->find_scope(def->name());
assert(dscope);
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);
NetExpr*tmp = parms_[idx]->elaborate_expr(des, scope);
parms[idx] = tmp;
}
/* Look for the return value signal for the called function in
the context of the function definition, not my context. */
NetNet*res = des->find_signal(def->name(), name_);
/* 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 +211,57 @@ 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]);
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 +269,15 @@ 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.
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 "
@@ -207,8 +294,8 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
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);
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 +305,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 +312,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 +340,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 +355,16 @@ 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;
des->errors += 1;
return 0;
NetEMemory*node = new NetEMemory(mem);
node->set_line(*this);
return node;
}
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 +386,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 +438,76 @@ 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 '~':
tmp = new NetEUBits(op_, ip);
tmp->set_line(*this);
break;
}
return tmp;
}
/*
* $Log: elab_expr.cc,v $
* 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.
*
+888 -212
View File
File diff suppressed because it is too large Load Diff
+123
View File
@@ -0,0 +1,123 @@
/*
* 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: elab_pexpr.cc,v 1.3 2000/03/12 18:22:11 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;
}
/*
* 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);
}
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;
}
return tmp;
}
/*
* $Log: elab_pexpr.cc,v $
* 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.
*
*/
+435
View File
@@ -0,0 +1,435 @@
/*
* 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: elab_scope.cc,v 1.4 2000/04/09 17:44:30 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 "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;
}
// Create the new scope as a MODULE with my name.
NetScope*my_scope = new NetScope(sc, get_name(), NetScope::MODULE);
// 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
{
}
/*
* 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.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.
*
*/
+222
View File
@@ -0,0 +1,222 @@
/*
* 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: elab_sig.cc,v 1.1 2000/05/02 16:27:38 steve Exp $"
#endif
# include "Module.h"
# include "PExpr.h"
# include "PGate.h"
# include "PWire.h"
# include "netlist.h"
# include "util.h"
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 ++ ) {
(*wt).second->elaborate_sig(des, scope);
}
// 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);
}
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);
}
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 (mval == 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);
assert(lval);
verinum*rval = ridx_->eval_const(des, path);
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);
sig->set_attributes(attributes);
} else {
NetNet*sig = new NetNet(scope, path + "." +basename, wtype, msb, lsb);
sig->set_line(*this);
sig->port_type(port_type_);
sig->set_attributes(attributes);
verinum::V iv = verinum::Vz;
if (wtype == NetNet::REG)
iv = verinum::Vx;
for (unsigned idx = 0 ; idx < wid ; idx += 1)
sig->set_ival(idx, iv);
}
}
/*
* $Log: elab_sig.cc,v $
* Revision 1.1 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
*/
+875 -596
View File
File diff suppressed because it is too large Load Diff
+156 -83
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,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.45 2000/05/11 23:37:27 steve Exp $"
#endif
/*
@@ -40,6 +40,11 @@ void NetLogic::emit_node(ostream&o, struct target_t*tgt) const
tgt->logic(o, this);
}
void NetUDP_COMB::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->udp_comb(o, this);
}
void NetUDP::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->udp(o, this);
@@ -65,6 +70,11 @@ void NetCaseCmp::emit_node(ostream&o, struct target_t*tgt) const
tgt->net_case_cmp(o, this);
}
void NetCAssign::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_cassign(o, this);
}
void NetCLShift::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_clshift(o, this);
@@ -80,11 +90,26 @@ void NetConst::emit_node(ostream&o, struct target_t*tgt) const
tgt->net_const(o, this);
}
void NetDivide::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_divide(o, this);
}
void NetFF::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_ff(o, this);
}
void NetForce::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_force(o, this);
}
void NetMult::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_mult(o, this);
}
void NetMux::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_mux(o, this);
@@ -95,11 +120,6 @@ void NetRamDq::emit_node(ostream&o, struct target_t*tgt) const
tgt->lpm_ram_dq(o, this);
}
void NetNEvent::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_event(o, this);
}
void NetBUFZ::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->bufz(o, this);
@@ -151,12 +171,27 @@ bool NetCase::emit_proc(ostream&o, struct target_t*tgt) const
return true;
}
bool NetCAssign::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_cassign(o, this);
}
bool NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_condit(o, this);
return true;
}
bool NetDeassign::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_deassign(o, this);
}
bool NetForce::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_force(o, this);
}
bool NetForever::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_forever(o, this);
@@ -174,15 +209,9 @@ void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
if (statement_) statement_->emit_proc(o, tgt);
}
bool NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
bool NetRelease::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_event(o, this);
return true;
}
void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
{
if (statement_) statement_->emit_proc(o, tgt);
return tgt->proc_release(o, this);
}
bool NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
@@ -233,6 +262,27 @@ void NetCondit::emit_recurse_else(ostream&o, struct target_t*tgt) const
else_->emit_proc(o, tgt);
}
void NetEvProbe::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_probe(o, this);
}
bool NetEvTrig::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_trigger(o, this);
}
bool NetEvWait::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_wait(o, this);
}
bool NetEvWait::emit_recurse(ostream&o, struct target_t*tgt) const
{
if (!statement_) return true;
return statement_->emit_proc(o, tgt);
}
void NetForever::emit_recurse(ostream&o, struct target_t*tgt) const
{
if (statement_)
@@ -245,6 +295,33 @@ void NetRepeat::emit_recurse(ostream&o, struct target_t*tgt) const
statement_->emit_proc(o, tgt);
}
void NetScope::emit_scope(ostream&o, struct target_t*tgt) const
{
tgt->scope(o, this);
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_)
tgt->event(o, cur);
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_)
cur->emit_scope(o, tgt);
if (signals_) {
NetNet*cur = signals_->sig_next_;
do {
tgt->signal(o, cur);
cur = cur->sig_next_;
} while (cur != signals_->sig_next_);
}
if (memories_) {
NetMemory*cur = memories_->snext_;
do {
tgt->memory(o, cur);
cur = cur->snext_;
} while (cur != memories_->snext_);
}
}
void NetWhile::emit_proc_recurse(ostream&o, struct target_t*tgt) const
{
proc_->emit_proc(o, tgt);
@@ -256,29 +333,7 @@ bool Design::emit(ostream&o, struct target_t*tgt) const
tgt->start_design(o, this);
// enumerate the scopes
{ map<string,NetScope*>::const_iterator sc;
for (sc = scopes_.begin() ; sc != scopes_.end() ; sc++) {
tgt->scope(o, (*sc).second);
}
}
// emit signals
if (signals_) {
NetNet*cur = signals_->sig_next_;
do {
tgt->signal(o, 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);
}
}
root_scope_->emit_scope(o, tgt);
// emit nodes
@@ -351,6 +406,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);
@@ -389,6 +449,63 @@ bool emit(ostream&o, const Design*des, const char*type)
/*
* $Log: emit.cc,v $
* Revision 1.45 2000/05/11 23:37:27 steve
* Add support for procedural continuous assignment.
*
* 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.43 2000/05/02 03:13:31 steve
* Move memories to the NetScope object.
*
* Revision 1.42 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.41 2000/04/23 03:45:24 steve
* Add support for the procedural release statement.
*
* Revision 1.40 2000/04/22 04:20:19 steve
* Add support for force assignment.
*
* Revision 1.39 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.38 2000/04/10 05:26:06 steve
* All events now use the NetEvent class.
*
* Revision 1.37 2000/04/04 03:20:15 steve
* Simulate named event trigger and waits.
*
* Revision 1.36 2000/04/01 21:40:22 steve
* Add support for integer division.
*
* Revision 1.35 2000/03/29 04:37:11 steve
* New and improved combinational primitives.
*
* Revision 1.34 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.33 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.32 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* 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.
@@ -475,49 +592,5 @@ bool emit(ostream&o, const Design*des, const char*type)
*
* 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.
*
*/
+16 -4
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: eval.cc,v 1.12 1999/11/30 04:48:17 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: eval.cc,v 1.14 2000/03/08 04:36:53 steve Exp $"
#endif
# include "PExpr.h"
@@ -96,7 +96,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;
@@ -142,6 +144,16 @@ verinum* PETernary::eval_const(const Design*des, const string&path) const
/*
* $Log: eval.cc,v $
* 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.
*
+34 -5
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: 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.10 2000/04/28 18:43:23 steve Exp $"
#endif
# include "netlist.h"
@@ -132,12 +132,24 @@ NetEConst* NetEBComp::eval_tree()
}
}
NetEConst* NetEBDiv::eval_tree()
{
eval_sub_tree_();
return 0;
}
NetEConst* NetEBLogic::eval_tree()
{
eval_sub_tree_();
return 0;
}
NetEConst* NetEBMult::eval_tree()
{
eval_sub_tree_();
return 0;
}
/*
* Evaluate the shift operator if possible. For this to work, both
* operands must be constant.
@@ -235,7 +247,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 +269,28 @@ 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();
}
/*
* $Log: eval_tree.cc,v $
* 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.
*
+47
View File
@@ -0,0 +1,47 @@
/*
* 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:
*
* verilog 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!
*/
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:
*
* verilog -X -fpart=XC4010XLPQ160 -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 */
+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:
*
* verilog 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 */
+127
View File
@@ -0,0 +1,127 @@
/*
* 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.1 1999/12/05 21:08:56 steve Exp $"
*/
/*
* 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 = %b", root.acc, root.acc);
#100 value = 63;
reset = 0;
end
endmodule /* main */
+102
View File
@@ -0,0 +1,102 @@
/*
* 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:
*
* verilog -X -fpart=XC4010XLPQ160 -fncf=xnf_add.ncf xnf_add.v
*
* That command causes an xnf_add.xnf and xnf_add.ncf file to be created.
* Next, 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 FPGA Editor to edit the xnf_add.ncd
* file to 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 */
+166 -19
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.14 2000/05/02 00:58:12 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 '+':
@@ -82,7 +81,9 @@ NetNet* NetEBBits::synthesize(Design*des)
NetNet*rsig = right_->synthesize(des);
assert(lsig->pin_count() == rsig->pin_count());
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, lsig->pin_count());
NetNet*osig = new NetNet(lsig->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);
@@ -115,23 +116,139 @@ NetNet* NetEBBits::synthesize(Design*des)
des->add_node(gate);
}
des->add_signal(osig);
return osig;
}
NetNet* NetEBComp::synthesize(Design*des)
{
string path = des->local_symbol("SYNTH");
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
unsigned width = lsig->pin_count();
if (rsig->pin_count() > lsig->pin_count())
width = rsig->pin_count();
NetNet*osig = new NetNet(lsig->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(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(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* 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())
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;
}
@@ -144,7 +261,9 @@ 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());
NetNet*osig = new NetNet(isig->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);
@@ -163,7 +282,7 @@ NetNet* NetEUBits::synthesize(Design*des)
des->add_node(gate);
}
des->add_signal(osig);
return osig;
}
@@ -178,7 +297,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 +309,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 +320,33 @@ NetNet* NetESignal::synthesize(Design*des)
/*
* $Log: expr_synth.cc,v $
* 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.
+153 -12
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.18 2000/05/02 00:58:12 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,61 @@ 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_ff(class Design*, class NetFF*)
{
}
void Design::functor(functor_t*fun)
void functor_t::lpm_logic(class Design*, class NetLogic*)
{
}
void functor_t::lpm_mult(class Design*, class NetMult*)
{
}
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
if (signals_) {
NetNet*cur = signals_->sig_next_;
do {
NetNet*tmp = cur->sig_next_;
fun->signal(this, cur);
fun->signal(des, cur);
cur = tmp;
} while (cur != signals_->sig_next_);
}
}
void Design::functor(functor_t*fun)
{
// Scan the scopes
root_scope_->run_functor(this, fun);
// apply to processes
procs_idx_ = procs_;
@@ -66,7 +110,7 @@ void Design::functor(functor_t*fun)
NetNode*tmp = cur->node_next_;
cur->functor_node(this, fun);
cur = tmp;
} while (cur != nodes_->node_next_);
} while (nodes_ && cur != nodes_->node_next_);
}
}
@@ -75,11 +119,41 @@ 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 NetMult::functor_node(Design*des, functor_t*fun)
{
fun->lpm_mult(des, this);
}
proc_match_t::~proc_match_t()
{
}
@@ -99,6 +173,28 @@ int NetAssign::match_proc(proc_match_t*that)
return that->assign(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::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 +205,63 @@ 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.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.
*
+54 -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,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: functor.h,v 1.3 1999/12/01 06:06:16 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: functor.h,v 1.13 2000/04/20 00:28:03 steve Exp $"
#endif
/*
@@ -35,38 +35,78 @@ 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 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*);
};
struct proc_match_t {
virtual ~proc_match_t();
virtual int assign(class NetAssign*);
virtual int assign_mem(class NetAssignMem*);
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.13 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
* 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.12 2000/04/18 04:50:19 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.1 1999/07/17 22:01:13 steve
* Add the functor interface for functor transforms.
* 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
+395
View File
@@ -0,0 +1,395 @@
/*
* 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: iverilog.c,v 1.12 2000/05/09 00:02:13 steve Exp $"
#endif
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#ifndef IVL_ROOT
# define IVL_ROOT "."
#endif
const char*base = IVL_ROOT;
const char*opath = "a.out";
const char*targ = "vvm";
const char*start = 0;
char warning_flags[16] = "";
char*inc_list = 0;
char*def_list = 0;
char*f_list = 0;
int synth_flag = 0;
int verbose_flag = 0;
char tmp[4096];
static int t_null(char*cmd, unsigned ncmd)
{
int rc;
sprintf(tmp, " | %s/ivl %s", base, warning_flags);
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;
}
if (verbose_flag) {
sprintf(tmp, " -v");
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);
return rc;
}
/*
* 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;
sprintf(tmp, " | %s/ivl %s -o %s.cc -tvvm -Fcprop %s -Fnodangle"
" -fVPI_MODULE_PATH=%s", base, warning_flags, opath,
synth_flag?"-Fsynth":"", base);
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, 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) {
fprintf(stderr, "errors translating Verilog program.\n");
return rc;
}
sprintf(tmp, "%s -O -rdynamic -fno-exceptions -o %s -I%s "
"-L%s %s.cc -lvvm %s", CXX, opath, IVL_INC, IVL_LIB,
opath, DLLIB);
if (verbose_flag)
printf("compile: %s\n", tmp);
rc = system(tmp);
if (rc != 0) {
fprintf(stderr, "errors compiling translated program.\n");
return rc;
}
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 "
"-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, 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);
return rc;
}
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)
{
char*cmd;
unsigned ncmd;
int e_flag = 0;
int opt, idx;
char*cp;
while ((opt = getopt(argc, argv, "B:D:Ef:I:o:Ss:t:vW:")) != EOF) {
switch (opt) {
case 'B':
base = 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 '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 'o':
opath = optarg;
break;
case 'S':
synth_flag = 1;
break;
case 's':
start = optarg;
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) {
fprintf(stderr, "%s: No input files.\n", argv[0]);
return 1;
}
/* 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);
}
/* Add all the 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) {
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);
return system(cmd);
}
if (strcmp(targ,"null") == 0)
return t_null(cmd, ncmd);
else if (strcmp(targ,"vvm") == 0)
return t_vvm(cmd, ncmd);
else if (strcmp(targ,"xnf") == 0)
return t_xnf(cmd, ncmd);
else {
fprintf(stderr, "Unknown target: %s\n", targ);
return 1;
}
return 0;
}
/*
* $Log: iverilog.c,v $
* Revision 1.12 2000/05/09 00:02:13 steve
* Parameterize LD lib in C++ command line.
*
* Revision 1.11 2000/05/05 01:07:42 steve
* Add the -I and -D switches to iverilog.
*
* Revision 1.10 2000/05/04 20:08:20 steve
* Tell ivlpp to generate line number directives.
*
* Revision 1.9 2000/05/03 22:14:31 steve
* More features of ivl available through iverilog.
*
* Revision 1.8 2000/05/01 23:55:22 steve
* Better inc and lib paths for iverilog.
*
* Revision 1.7 2000/04/29 01:20:14 steve
* The -f flag is now in place.
*
* Revision 1.6 2000/04/26 21:11:41 steve
* Mussed up command string mashing.
*
* Revision 1.5 2000/04/26 03:33:32 steve
* Do not set width too small to hold significant bits.
*
* Revision 1.4 2000/04/23 21:14:32 steve
* The -s flag.
*
* Revision 1.3 2000/04/21 22:54:47 steve
* module path in vvm target.
*
* Revision 1.2 2000/04/21 22:51:38 steve
* Support the -tnull target type.
*
* Revision 1.1 2000/04/21 06:41:03 steve
* Add the iverilog driver program.
*
*/
+155
View File
@@ -0,0 +1,155 @@
.TH iverilog 1 "$Date: 2000/05/05 01:07:42 $" Version "$Date: 2000/05/05 01:07:42 $"
.SH NAME
iverilog - Icarus Verilog compiler
.SH SYNOPSIS
.B iverilog
[-ESv] [-Dmacro[=defn]] [-fflag=value] [-Iincludepath] [-mmodule] [-ooutputfilename] [-s topmodule] [-ttype] [-Wclass] sourcefile[s]
.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 -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. (NOT IMPLEMENTED)
.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\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
+6 -6
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.7 2000/01/01 20:57:51 steve Exp $"
#
#
SHELL = /bin/sh
@@ -60,16 +60,16 @@ lexor.c: lexor.lex
parse.h parse.c: parse.y
bison --verbose -t -d parse.y -o parse.c
install: all installdirs $(bindir)/ivlpp
install: all installdirs $(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
+35 -8
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: lexor.lex,v 1.14 1999/10/08 17:27:56 steve Exp $"
#ident "$Id: lexor.lex,v 1.18 2000/04/26 01:35:26 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,23 @@ 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><<EOF>> { istack->lineno += 1; yy_pop_state(); do_include(); }
/* Detect the define directive, and match the name. Match any
@@ -129,13 +140,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 {
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(); }
@@ -318,6 +338,13 @@ static void do_define()
}
define_macro(def_name, yytext);
def_name[0] = 0;
}
static void def_finish()
{
if (def_name[0])
define_macro(def_name, "1");
}
static void def_undefine()
@@ -522,7 +549,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;
}
+107 -42
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.44 2000/03/12 17:09:41 steve Exp $"
#endif
//# define YYSTYPE lexval
@@ -30,6 +30,7 @@
# include "parse.h"
# include <ctype.h>
# include <string.h>
# include "lexor_keyword.h"
extern FILE*vl_input;
extern string vl_file;
@@ -42,7 +43,6 @@ 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);
@@ -97,6 +97,7 @@ W [ \t\b\f\r]+
"~^" { return K_NXOR; }
"^~" { return K_NXOR; }
"~&" { return K_NAND; }
"->" { return K_TRIGGER; }
[}{;:\[\],()#=.@&!?<>%|^~+*/-] { return yytext[0]; }
@@ -113,16 +114,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 +131,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 +162,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 +201,7 @@ W [ \t\b\f\r]+
}
yylval.number = new verinum(bits, nbits, false);
yylval.number->has_sign(true);
delete[]bits;
return NUMBER; }
@@ -312,22 +316,26 @@ 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;
@@ -349,7 +357,7 @@ static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
// 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 +373,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 +387,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,17 +436,27 @@ 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;
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'o');
/* We know from the size number how bit to make the verinom
@@ -506,14 +532,24 @@ static verinum*make_sized_octal(const char*txt)
}
}
return new verinum(bits, size, true);
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 +591,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 +608,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;
@@ -634,14 +680,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 +749,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,6 +761,11 @@ 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;
@@ -726,7 +789,10 @@ static verinum*make_dec_with_size(unsigned size, bool fixed, const char*ptr)
value /= 2;
}
return new verinum(bits, size, fixed);
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 +805,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);
}
-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;
}
+15 -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
@@ -81,6 +80,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 +109,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
+64
View File
@@ -0,0 +1,64 @@
/*
* 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.2 2000/05/07 04:37:56 steve Exp $"
#endif
# include "netlist.h"
# include "netmisc.h"
NetConst* link_const_value(Link&pin, unsigned&idx)
{
NetConst*robj = 0;
unsigned ridx = 0;
for (Link*cur = pin.next_link()
; *cur != pin ; cur = cur->next_link()) {
NetConst*tmp;
if ((tmp = dynamic_cast<NetConst*>(cur->get_obj())) == 0)
continue;
if (robj != 0)
continue;
robj = tmp;
ridx = cur->get_pin();
}
idx = ridx;
return robj;
}
/*
* $Log: link_const.cc,v $
* 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.
*
*/
+53 -10
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.33 2000/05/08 05:29:43 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;
@@ -81,12 +88,9 @@ extern Design* elaborate(const map<string,Module*>&modules,
extern void cprop(Design*des);
extern void propinit(Design*des);
extern void sigfold(Design*des);
extern void synth(Design*des);
extern void nobufz(Design*des);
extern void nodangle(Design*des);
extern void xnfio(Design*des);
extern void xnfsyn(Design*des);
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 },
{ "xnfio", &xnfio },
{ "xnfsyn", &xnfsyn },
{ 0, 0 }
};
@@ -120,11 +121,14 @@ int main(int argc, char*argv[])
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";
while ((opt = getopt(argc, argv, "F:f:hm:N:o:P:s:t:vW:")) != EOF) switch (opt) {
case 'F': {
net_func tmp = name_to_net_func(optarg);
if (tmp == 0) {
@@ -142,6 +146,9 @@ 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;
@@ -162,6 +169,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 +195,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;
@@ -284,6 +303,30 @@ int main(int argc, char*argv[])
/*
* $Log: main.cc,v $
* Revision 1.33 2000/05/08 05:29:43 steve
* no need for nobufz functor.
*
* Revision 1.32 2000/05/03 22:14:31 steve
* More features of ivl available through iverilog.
*
* 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.
*
* Revision 1.30 2000/03/17 21:50:25 steve
* Switch to control warnings.
*
* Revision 1.29 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.28 2000/01/13 05:11:25 steve
* Support for multiple VPI modules.
*
* Revision 1.27 1999/12/30 17:37:14 steve
* Remove the now useless sigfold functor.
*
* Revision 1.26 1999/11/29 17:02:21 steve
* include getopt if present.
*
+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: mangle.cc,v 1.2 1999/02/15 05:52:50 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: mangle.cc,v 1.3 2000/02/23 02:56:54 steve Exp $"
#endif
# include "target.h"
@@ -63,6 +63,9 @@ string mangle(const string&str)
/*
* $Log: mangle.cc,v $
* 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
+530
View File
@@ -0,0 +1,530 @@
/*
* 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.8 2000/05/02 16:27:38 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)
{
}
Design::~Design()
{
}
string Design::local_symbol(const string&path)
{
strstream res;
res << "_L" << (lcounter_++) << ends;
return path + "." + res.str();
}
NetScope* Design::make_root_scope(const string&root)
{
assert(root_scope_ == 0);
root_scope_ = new NetScope(root);
return root_scope_;
}
NetScope* Design::find_root_scope()
{
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 string given a current context as a
* starting point.
*/
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 scope. */
string path = name;
string key = parse_last_name(path);
if (path != "")
scope = find_scope(scope, path);
while (scope) {
if (NetNet*net = scope->find_signal(key))
return net;
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();
}
}
void Design::add_function(const string&key, NetFuncDef*def)
{
funcs_[key] = def;
}
NetFuncDef* Design::find_function(const string&path, const string&name)
{
string root = path;
for (;;) {
string key = root + "." + name;
map<string,NetFuncDef*>::const_iterator cur = funcs_.find(key);
if (cur != funcs_.end())
return (*cur).second;
unsigned pos = root.rfind('.');
if (pos > root.length())
break;
root = root.substr(0, pos);
}
return 0;
}
NetFuncDef* Design::find_function(const string&key)
{
map<string,NetFuncDef*>::const_iterator cur = funcs_.find(key);
if (cur != funcs_.end())
return (*cur).second;
return 0;
}
void Design::add_task(const string&key, NetTaskDef*def)
{
tasks_[key] = def;
}
NetTaskDef* Design::find_task(const string&path, const string&name)
{
string root = path;
for (;;) {
string key = root + "." + name;
map<string,NetTaskDef*>::const_iterator cur = tasks_.find(key);
if (cur != tasks_.end())
return (*cur).second;
unsigned pos = root.rfind('.');
if (pos > root.length())
break;
root = root.substr(0, pos);
}
return 0;
}
NetTaskDef* Design::find_task(const string&key)
{
map<string,NetTaskDef*>::const_iterator cur = tasks_.find(key);
if (cur == tasks_.end())
return 0;
return (*cur).second;
}
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;
}
void Design::clear_node_marks()
{
if (nodes_ == 0)
return;
NetNode*cur = nodes_;
do {
cur->set_mark(false);
cur = cur->node_next_;
} while (cur != nodes_);
}
NetNode* Design::find_node(bool (*func)(const NetNode*))
{
if (nodes_ == 0)
return 0;
NetNode*cur = nodes_->node_next_;
do {
if ((cur->test_mark() == false) && func(cur))
return cur;
cur = cur->node_next_;
} while (cur != nodes_->node_next_);
return 0;
}
/*
* $Log: net_design.cc,v $
* 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.
*
*/
+263
View File
@@ -0,0 +1,263 @@
/*
* 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.6 2000/04/18 04:50:20 steve Exp $"
#endif
# include "netlist.h"
NetEvent::NetEvent(const string&n)
: name_(n)
{
scope_ = 0;
snext_ = 0;
probes_ = 0;
trig_ = 0;
waitref_ = 0;
}
NetEvent::~NetEvent()
{
assert(waitref_ == 0);
if (scope_) scope_->rem_event(this);
while (probes_) {
NetEvProbe*tmp = probes_->enext_;
delete probes_;
tmp = probes_;
}
}
string 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_;
}
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_;
}
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;
}
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;
}
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.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.
*
*/
+303
View File
@@ -0,0 +1,303 @@
/*
* 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.6 2000/05/02 03:13:31 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(const string&n)
: type_(NetScope::MODULE), name_(n), up_(0), sib_(0), sub_(0)
{
memories_ = 0;
signals_ = 0;
events_ = 0;
lcounter_ = 0;
}
NetScope::NetScope(NetScope*up, const string&n, NetScope::TYPE t)
: type_(t), name_(n), up_(up), sib_(0), sub_(0)
{
memories_ = 0;
signals_ = 0;
events_ = 0;
sib_ = up_->sub_;
up_->sub_ = this;
}
NetScope::~NetScope()
{
assert(sib_ == 0);
assert(sub_ == 0);
lcounter_ = 0;
}
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_;
}
string 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.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.
*
*/
+205
View File
@@ -0,0 +1,205 @@
/*
* 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.1 2000/03/29 04:37:11 steve Exp $"
#endif
# include "netlist.h"
NetUDP::NetUDP(const string&n, unsigned pins, bool sequ)
: NetNode(n, pins), sequential_(sequ), init_('x')
{
pin(0).set_dir(Link::OUTPUT);
for (unsigned idx = 1 ; idx < pins ; idx += 1)
pin(idx).set_dir(Link::INPUT);
}
bool NetUDP::set_table(const string&input, char output)
{
assert((output == '0') || (output == '1') || (sequential_ &&
(output == '-')));
if (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 and x are allowed. */
cm_[input] = output;
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(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)
: NetNode(n, pins)
{
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);
}
}
void NetUDP_COMB::set_table(const string&input, char output)
{
assert((output == '0') || (output == '1'));
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 and x are allowed. */
cm_[input] = output;
}
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.1 2000/03/29 04:37:11 steve
* New and improved combinational primitives.
*
*/
+720 -974
View File
File diff suppressed because it is too large Load Diff
+920 -523
View File
File diff suppressed because it is too large Load Diff
+31 -1
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.8 2000/03/08 04:36:54 steve Exp $"
Note that the netlist.h header contains detailed descriptions of how
@@ -229,6 +229,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
@@ -240,6 +263,13 @@ some task calls. C++ programmers recognize this as inlining a task.)
$Log: netlist.txt,v $
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.
+42 -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.6 2000/05/07 04:37:56 steve Exp $"
#endif
# include "netlist.h"
@@ -31,10 +31,49 @@
* 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 function chooses a nexus name for the link. The algorithm is
* such that any signal in the link will have the same nexus name, and
* signals that are not connected together will have a different nexus
* name.
*/
extern string nexus_from_link(const Link*lnk);
/*
* Check to see if the link has a constant value driven to it. If
* there is only a NetConst driving this pin, the return a pointer to
* that NetConst object. Also, return the index of the bit in that
* constant through the idx parameter.
*/
extern NetConst* link_const_value(Link&pin, unsigned&idx);
/*
* $Log: netmisc.h,v $
* 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.
*
+109
View File
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@.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: nexus_from_link.cc,v 1.4 2000/05/07 19:40:26 steve Exp $"
#endif
# include "netmisc.h"
# include <strstream>
# include <string>
# include <typeinfo>
string nexus_from_link(const Link*lnk)
{
const NetNet*sig = dynamic_cast<const NetNet*>(lnk->get_obj());
unsigned pin = lnk->get_pin();
for (const Link*cur = lnk->next_link()
; cur != lnk ; cur = cur->next_link()) {
const NetNet*cursig = dynamic_cast<const NetNet*>(cur->get_obj());
if (cursig == 0)
continue;
if (sig == 0) {
sig = cursig;
pin = cur->get_pin();
continue;
}
if ((cursig->pin_count() == 1) && (sig->pin_count() > 1))
continue;
if ((cursig->pin_count() > 1) && (sig->pin_count() == 1)) {
sig = cursig;
pin = cur->get_pin();
continue;
}
if (cursig->local_flag() && !sig->local_flag())
continue;
if (cursig->name() < sig->name())
continue;
sig = cursig;
pin = cur->get_pin();
}
if (sig == 0) {
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;
return tmp.str();
}
/*
* $Log: nexus_from_link.cc,v $
* Revision 1.4 2000/05/07 19:40:26 steve
* Fix connection of Direction of LMP_CLSHIFT
* to constant values. Remember to add a signal
* to the nexus and connect the receiver in vvm.
*
* Revision 1.3 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.2 2000/03/20 17:40:54 steve
* More complete error message about no signal.
*
* Revision 1.1 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.
*
*/
-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.
*
*/
+43 -5
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.6 2000/05/07 04:37:56 steve Exp $"
#endif
/*
@@ -31,9 +31,20 @@
class nodangle_f : public functor_t {
public:
void event(Design*des, NetEvent*ev);
void signal(Design*des, NetNet*sig);
};
void nodangle_f::event(Design*des, NetEvent*ev)
{
if (ev->nwait() != 0)
return;
if (ev->ntrig() != 0)
return;
delete ev;
}
void nodangle_f::signal(Design*des, NetNet*sig)
{
@@ -42,12 +53,22 @@ void nodangle_f::signal(Design*des, NetNet*sig)
if (sig->get_eref() > 0)
return;
/* Look for a completely unconnected signal. */
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;
}
/* 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()
Link&lnk = sig->pin(idx);
for (Link*cur = lnk.next_link()
; cur != &lnk ; cur = cur->next_link()) {
NetNet*cursig = dynamic_cast<NetNet*>(cur->get_obj());
if (cursig == 0)
@@ -73,6 +94,23 @@ void nodangle(Design*des)
/*
* $Log: nodangle.cc,v $
* 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.
*
+444 -106
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: parse.y,v 1.76 1999/11/15 04:43:52 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: parse.y,v 1.96 2000/05/11 23:37:27 steve Exp $"
#endif
# include "parse_misc.h"
@@ -27,6 +27,13 @@
extern void lex_start_table();
extern void lex_end_table();
/*
* These are the strengths to use for net declaration
* assignments. They are stored here so that scope that contains the
* net_decl_assigns can change them during specific statements.
*/
static struct str_pair_t decl_strength = { PGate::STRONG, PGate::STRONG };
%}
%union {
@@ -34,6 +41,8 @@ extern void lex_end_table();
char*text;
list<string>*strings;
struct str_pair_t drive;
PCase::Item*citem;
svector<PCase::Item*>*citems;
@@ -45,6 +54,7 @@ extern void lex_end_table();
portname_t*portname;
svector<portname_t*>*portnames;
struct parmvalue_t*parmvalue;
PExpr*expr;
svector<PExpr*>*exprs;
@@ -74,19 +84,20 @@ extern void lex_end_table();
%token <number> NUMBER
%token <realtime> REALTIME
%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_SG
%token K_LOR K_LAND K_NAND K_NOR K_NXOR
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER
%token K_always K_and K_assign K_begin K_buf K_bufif0 K_bufif1 K_case
%token K_casex K_casez K_cmos K_deassign K_default K_defparam K_disable
%token K_edge K_else K_end K_endcase K_endfunction K_endmodule
%token K_endprimitive K_endspecify K_endtable K_endtask K_event K_for
%token K_force K_forever K_fork K_function K_highz0 K_highz1 K_if
%token K_initial K_inout K_input K_integer K_join K_large K_macromodule
%token K_initial K_inout K_input K_integer K_join K_large K_localparam
%token K_macromodule
%token K_medium K_module K_nand K_negedge K_nmos K_nor K_not K_notif0
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_primitive
%token K_pull0 K_pull1 K_pulldown K_pullup K_rcmos K_real K_realtime
%token K_reg K_release K_repeat
%token K_rnmos K_rpmos K_rtran K_rtranif0 K_rtranif1 K_scalered
%token K_small K_specify
%token K_signed K_small K_specify
%token K_specparam K_strong0 K_strong1 K_supply0 K_supply1 K_table K_task
%token K_time K_tran K_tranif0 K_tranif1 K_tri K_tri0 K_tri1 K_triand
%token K_trior K_trireg K_vectored K_wait K_wand K_weak0 K_weak1
@@ -95,6 +106,7 @@ extern void lex_end_table();
%token KK_attribute
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
%type <letter> udp_input_sym udp_output_sym
%type <text> udp_input_list udp_sequ_entry udp_comb_entry
%type <strings> udp_entry_list udp_comb_entry_list udp_sequ_entry_list
@@ -115,8 +127,8 @@ extern void lex_end_table();
%type <wires> task_item task_item_list task_item_list_opt
%type <wires> function_item function_item_list
%type <portname> port_name
%type <portnames> port_name_list
%type <portname> port_name parameter_value_byname
%type <portnames> port_name_list parameter_value_byname_list
%type <citem> case_item
%type <citems> case_items
@@ -126,8 +138,8 @@ extern void lex_end_table();
%type <expr> expression expr_primary
%type <expr> lavalue lpvalue
%type <expr> delay_value
%type <exprs> delay delay_opt delay_value_list
%type <expr> delay_value delay_value_simple
%type <exprs> delay1 delay3 delay3_opt
%type <exprs> expression_list
%type <exprs> assign assign_list
@@ -135,6 +147,7 @@ extern void lex_end_table();
%type <nettype> net_type
%type <gatetype> gatetype
%type <porttype> port_type
%type <parmvalue> parameter_value_opt
%type <task> task_body
%type <function> func_body
@@ -185,6 +198,16 @@ block_item_decl
}
| K_reg register_variable_list ';'
{ delete $2; }
| K_reg K_signed range register_variable_list ';'
{ pform_set_net_range($4, $3);
delete $3;
delete $4;
yyerror(@2, "sorry: signed reg not supported.");
}
| K_reg K_signed register_variable_list ';'
{ delete $3;
yyerror(@2, "sorry: signed reg not supported.");
}
| K_integer list_of_variables ';'
{ pform_set_reg_integer($2);
delete $2;
@@ -259,9 +282,8 @@ defparam_assign
delete tmp;
tmp = 0;
}
yyerror(@1, "sorry: defparam assignments not supported.");
pform_set_defparam($1, $3);
delete $1;
delete $3;
}
;
@@ -275,23 +297,67 @@ defparam_assign_list
| defparam_assign_list ',' defparam_assign
;
delay
: '#' delay_value
delay1
: '#' delay_value_simple
{ svector<PExpr*>*tmp = new svector<PExpr*>(1);
(*tmp)[0] = $2;
$$ = tmp;
}
| '#' '(' delay_value_list ')'
{ $$ = $3;
| '#' '(' delay_value ')'
{ svector<PExpr*>*tmp = new svector<PExpr*>(1);
(*tmp)[0] = $3;
$$ = tmp;
}
;
delay_opt
: delay { $$ = $1; }
| { $$ = 0; }
delay3
: '#' delay_value_simple
{ svector<PExpr*>*tmp = new svector<PExpr*>(1);
(*tmp)[0] = $2;
$$ = tmp;
}
| '#' '(' delay_value ')'
{ svector<PExpr*>*tmp = new svector<PExpr*>(1);
(*tmp)[0] = $3;
$$ = tmp;
}
| '#' '(' delay_value ',' delay_value ')'
{ svector<PExpr*>*tmp = new svector<PExpr*>(2);
(*tmp)[0] = $3;
(*tmp)[1] = $5;
$$ = tmp;
}
| '#' '(' delay_value ',' delay_value ',' delay_value ')'
{ svector<PExpr*>*tmp = new svector<PExpr*>(3);
(*tmp)[0] = $3;
(*tmp)[1] = $5;
(*tmp)[1] = $7;
$$ = tmp;
}
;
delay3_opt
: delay3 { $$ = $1; }
| { $$ = 0; }
;
delay_value
: expression
{ PExpr*tmp = $1;
if (! pform_expression_is_constant(tmp))
yyerror(@1, "error: delay expression must "
"be constant.");
$$ = tmp;
}
| expression ':' expression ':' expression
{ yyerror(@1, "sorry: (min:typ:max) not supported.");
$$ = $3;
delete $1;
delete $5;
}
;
delay_value_simple
: NUMBER
{ verinum*tmp = $1;
if (tmp == 0) {
@@ -312,19 +378,6 @@ delay_value
}
;
delay_value_list
: expression
{ svector<PExpr*>*tmp = new svector<PExpr*>(1);
(*tmp)[0] = $1;
$$ = tmp;
}
| delay_value_list ',' expression
{ svector<PExpr*>*tmp = new svector<PExpr*>(*$1, $3);
delete $1;
$$ = tmp;
}
;
description
: module
| udp_primitive
@@ -338,25 +391,61 @@ description
drive_strength
: '(' dr_strength0 ',' dr_strength1 ')'
{ $$.str0 = $2.str0;
$$.str1 = $4.str1;
}
| '(' dr_strength1 ',' dr_strength0 ')'
{ $$.str0 = $4.str0;
$$.str1 = $2.str1;
}
| '(' dr_strength0 ',' K_highz1 ')'
{ $$.str0 = $2.str0;
$$.str1 = PGate::HIGHZ;
}
| '(' dr_strength1 ',' K_highz0 ')'
{ $$.str0 = PGate::HIGHZ;
$$.str1 = $2.str1;
}
| '(' K_highz1 ',' dr_strength0 ')'
{ $$.str0 = $4.str0;
$$.str1 = PGate::HIGHZ;
}
| '(' K_highz0 ',' dr_strength1 ')'
{ $$.str0 = PGate::HIGHZ;
$$.str1 = $4.str1;
}
;
drive_strength_opt
: drive_strength
|
: drive_strength { $$ = $1; }
| { $$.str0 = PGate::STRONG; $$.str1 = PGate::STRONG; }
;
dr_strength0 : K_supply0 | K_strong0 | K_pull0 | K_weak0 ;
dr_strength1 : K_supply1 | K_strong1 | K_pull1 | K_weak1 ;
dr_strength0
: K_supply0 { $$.str0 = PGate::SUPPLY; }
| K_strong0 { $$.str0 = PGate::STRONG; }
| K_pull0 { $$.str0 = PGate::PULL; }
| K_weak0 { $$.str0 = PGate::WEAK; }
;
dr_strength1
: K_supply1 { $$.str1 = PGate::SUPPLY; }
| K_strong1 { $$.str1 = PGate::STRONG; }
| K_pull1 { $$.str1 = PGate::PULL; }
| K_weak1 { $$.str1 = PGate::WEAK; }
;
event_control
: '@' IDENTIFIER
{ yyerror(@1, "sorry: event control not supported.");
$$ = 0;
{ PEIdent*tmpi = new PEIdent($2);
tmpi->set_file(@2.text);
tmpi->set_lineno(@2.first_line);
delete[]$2;
PEEvent*tmpe = new PEEvent(PEEvent::ANYEDGE, tmpi);
PEventStatement*tmps = new PEventStatement(tmpe);
tmps->set_file(@1.text);
tmps->set_lineno(@1.first_line);
$$ = tmps;
}
| '@' '(' event_expression_list ')'
{ PEventStatement*tmp = new PEventStatement(*$3);
@@ -380,11 +469,17 @@ event_expression_list
delete $3;
$$ = tmp;
}
| event_expression_list ',' event_expression
{ svector<PEEvent*>*tmp = new svector<PEEvent*>(*$1, *$3);
delete $1;
delete $3;
$$ = tmp;
}
;
event_expression
: K_posedge expression
{ PEEvent*tmp = new PEEvent(NetNEvent::POSEDGE, $2);
{ PEEvent*tmp = new PEEvent(PEEvent::POSEDGE, $2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
svector<PEEvent*>*tl = new svector<PEEvent*>(1);
@@ -392,7 +487,7 @@ event_expression
$$ = tl;
}
| K_negedge expression
{ PEEvent*tmp = new PEEvent(NetNEvent::NEGEDGE, $2);
{ PEEvent*tmp = new PEEvent(PEEvent::NEGEDGE, $2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
svector<PEEvent*>*tl = new svector<PEEvent*>(1);
@@ -400,7 +495,7 @@ event_expression
$$ = tl;
}
| expression
{ PEEvent*tmp = new PEEvent(NetNEvent::ANYEDGE, $1);
{ PEEvent*tmp = new PEEvent(PEEvent::ANYEDGE, $1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
svector<PEEvent*>*tl = new svector<PEEvent*>(1);
@@ -468,6 +563,16 @@ expression
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| '!' error %prec UNARY_PREC
{ yyerror(@1, "error: Operand of unary ! "
"is not a primary expression.");
$$ = 0;
}
| '^' error %prec UNARY_PREC
{ yyerror(@1, "error: Operand of reduction ^ "
"is not a primary expression.");
$$ = 0;
}
| expression '^' expression
{ PEBinary*tmp = new PEBinary('^', $1, $3);
tmp->set_file(@2.text);
@@ -657,11 +762,11 @@ expr_primary
delete $1;
}
| SYSTEM_IDENTIFIER
{ PEIdent*tmp = new PEIdent($1);
{ PECallFunction*tmp = new PECallFunction($1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
delete $1;
delete $1
}
| identifier '[' expression ']'
{ PEIdent*tmp = new PEIdent($1);
@@ -694,12 +799,6 @@ expr_primary
}
| '(' expression ')'
{ $$ = $2; }
| '(' expression ':' expression ':' expression ')'
{ yyerror(@2, "sorry: (min:typ:max) not supported.");
$$ = $4;
delete $2;
delete $6;
}
| '{' expression_list '}'
{ PEConcat*tmp = new PEConcat(*$2);
tmp->set_file(@2.text);
@@ -854,8 +953,6 @@ gatetype
| K_not { $$ = PGBuiltin::NOT; }
| K_notif0 { $$ = PGBuiltin::NOTIF0; }
| K_notif1 { $$ = PGBuiltin::NOTIF1; }
| K_pulldown { $$ = PGBuiltin::PULLDOWN; }
| K_pullup { $$ = PGBuiltin::PULLUP; }
| K_nmos { $$ = PGBuiltin::NMOS; }
| K_rnmos { $$ = PGBuiltin::RNMOS; }
| K_pmos { $$ = PGBuiltin::PMOS; }
@@ -1051,10 +1148,21 @@ module_item
}
delete $3;
}
| K_trireg charge_strength_opt range_opt delay_opt list_of_variables ';'
| net_type drive_strength { decl_strength = $2;} net_decl_assigns ';'
{ pform_makewire(@1, $4, $1);
/* The strengths are handled in the
net_decl_assigns using the decl_strength that I
set in the rule. Right here, just restore the
defaults for other rules. */
decl_strength.str0 = PGate::STRONG;
decl_strength.str1 = PGate::STRONG;
delete $4;
}
| K_trireg charge_strength_opt range_opt delay3_opt list_of_variables ';'
{ yyerror(@1, "sorry: trireg nets not supported.");
delete $3;
}
| port_type range_opt list_of_variables ';'
{ pform_set_port_type($3, $1);
if ($2) {
@@ -1066,20 +1174,58 @@ module_item
| block_item_decl
| K_defparam defparam_assign_list ';'
| K_event list_of_variables ';'
{ yyerror(@1, "sorry: named events not supported.");
{ pform_make_events($2, @1.text, @1.first_line);
delete $2;
}
| K_parameter parameter_assign_list ';'
| gatetype delay_opt gate_instance_list ';'
{ pform_makegates($1, $2, $3);
| K_localparam localparam_assign_list ';' { }
/* Most gate types have an optional drive strength and optional
three-value delay. These rules handle the different cases. */
| gatetype gate_instance_list ';'
{ pform_makegates($1, decl_strength, 0, $2);
}
| IDENTIFIER delay_opt gate_instance_list ';'
| gatetype delay3 gate_instance_list ';'
{ pform_makegates($1, decl_strength, $2, $3);
}
| gatetype drive_strength gate_instance_list ';'
{ pform_makegates($1, $2, 0, $3);
}
| gatetype drive_strength delay3 gate_instance_list ';'
{ pform_makegates($1, $2, $3, $4);
}
/* Pullup and pulldown devices cannot have delays, and their
strengths are limited. */
| K_pullup gate_instance_list ';'
{ pform_makegates(PGBuiltin::PULLUP, decl_strength, 0, $2);
}
| K_pulldown gate_instance_list ';'
{ pform_makegates(PGBuiltin::PULLDOWN, decl_strength, 0, $2);
}
/* This rule handles instantiations of modules and user defined
primitives. These devices to not have delay lists or strengths,
but then can have parameter lists. */
| IDENTIFIER parameter_value_opt gate_instance_list ';'
{ pform_make_modgates($1, $2, $3);
delete $1;
}
| K_assign drive_strength_opt delay_opt assign_list ';'
{ pform_make_pgassign_list($4, $3, @1.text, @1.first_line); }
/* Continuous assignment can have an optional drive strength, then
an optional delay3 that applies to all the assignments in the
assign_list. */
| K_assign drive_strength_opt delay3_opt assign_list ';'
{ pform_make_pgassign_list($4, $3, $2, @1.text, @1.first_line); }
| K_assign error '=' expression ';'
| K_always statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $2);
tmp->set_file(@1.text);
@@ -1090,6 +1236,12 @@ module_item
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
}
/* The task declaration rule matches the task declaration
header, then pushes the function scope. This causes the
definitions in the task_body to take on the scope of the task
instead of the module. */
| K_task IDENTIFIER ';'
{ pform_push_scope($2); }
task_body
@@ -1101,6 +1253,12 @@ module_item
pform_set_task($2, $5);
delete $2;
}
/* The function declaration rule matches the function declaration
header, then pushes the function scope. This causes the
definitions in the func_body to take on the scope of the function
instead of the module. */
| K_function range_or_type_opt IDENTIFIER ';'
{ pform_push_scope($3); }
func_body
@@ -1112,9 +1270,16 @@ module_item
pform_set_function($3, $2, $6);
delete $3;
}
/* specify blocks are parsed but ignored. */
| K_specify specify_item_list K_endspecify
{
}
/* These rules are for the Icarus VErilog specific $attribute
extensions. Then catch the parameters of the $attribute keyword. */
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')' ';'
{ pform_set_attrib($3, $5, $7);
delete $3;
@@ -1125,6 +1290,7 @@ module_item
{ yyerror(@1, "error: Misformed $attribute parameter list."); }
;
module_item_list
: module_item_list module_item
| module_item
@@ -1136,14 +1302,15 @@ module_item_list
net_decl_assign
: IDENTIFIER '=' expression
{ PEIdent*id = new PEIdent($1);
PGAssign*tmp = pform_make_pgassign(id, $3, 0);
PGAssign*tmp = pform_make_pgassign(id, $3, 0, decl_strength);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = $1;
}
| delay IDENTIFIER '=' expression
| delay1 IDENTIFIER '=' expression
{ PEIdent*id = new PEIdent($2);
PGAssign*tmp = pform_make_pgassign(id, $4, $1);
PGAssign*tmp = pform_make_pgassign(id, $4, $1,
decl_strength);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = $2;
@@ -1202,7 +1369,116 @@ parameter_assign_list
| parameter_assign_list ',' parameter_assign
;
/* The port (of a module) is a fairle complex item. Each port is
/* Localparam assignments and asignment lists are broken into
separate BNF so that I can call slightly different paramter
handling code. They parse the same as parameters, they just
behave differently when someone tries to override them. */
localparam_assign
: IDENTIFIER '=' expression
{ PExpr*tmp = $3;
if (!pform_expression_is_constant(tmp)) {
yyerror(@3, "error: parameter value "
"must be constant.");
delete tmp;
tmp = 0;
}
pform_set_localparam($1, tmp);
delete $1;
}
;
localparam_assign_list
: localparam_assign
| range localparam_assign
{ yywarn(@1, "Ranges in localparam definition "
"are not supported.");
delete $1;
}
| localparam_assign_list ',' localparam_assign
;
/* The parameters of a module instance can be overridden by writing
a list of expressions in a syntax much line a delay list. (The
difference being the list can have any length.) The pform that
attaches the expression list to the module checks that the
expressions are constant.
Although the BNF in IEEE1364-1995 implies that parameter value
lists must be in parentheses, in practice most compilers will
accept simple expressions outside of parentheses if there is only
one value, so I'll accept simple numbers here.
The parameter value by name syntax is OVI enhancement BTF-B06 as
approved by WG1364 on 6/28/1998. */
parameter_value_opt
: '#' '(' expression_list ')'
{ struct parmvalue_t*tmp = new struct parmvalue_t;
tmp->by_order = $3;
tmp->by_name = 0;
$$ = tmp;
}
| '#' '(' parameter_value_byname_list ')'
{ struct parmvalue_t*tmp = new struct parmvalue_t;
tmp->by_order = 0;
tmp->by_name = $3;
$$ = tmp;
}
| '#' NUMBER
{ assert($2);
PENumber*tmp = new PENumber($2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
struct parmvalue_t*lst = new struct parmvalue_t;
lst->by_order = new svector<PExpr*>(1);
(*lst->by_order)[0] = tmp;
lst->by_name = 0;
$$ = lst;
}
| '#' error
{ yyerror(@1, "error: syntax error in parameter value "
"assignment list.");
$$ = 0;
}
|
{ $$ = 0; }
;
parameter_value_byname
: PORTNAME '(' expression ')'
{ portname_t*tmp = new portname_t;
tmp->name = $1;
tmp->parm = $3;
free($1);
$$ = tmp;
}
| PORTNAME '(' ')'
{ portname_t*tmp = new portname_t;
tmp->name = $1;
tmp->parm = 0;
free($1);
$$ = tmp;
}
;
parameter_value_byname_list
: parameter_value_byname
{ svector<portname_t*>*tmp = new svector<portname_t*>(1);
(*tmp)[0] = $1;
$$ = tmp;
}
| parameter_value_byname_list ',' parameter_value_byname
{ svector<portname_t*>*tmp = new svector<portname_t*>(*$1,$3);
delete $1;
$$ = tmp;
}
;
/* The port (of a module) is a fairly complex item. Each port is
handled as a Module::port_t object. A simple port reference has a
name and a PWire object, but more complex constructs are possible
where the name can be attached to a list of PWire objects.
@@ -1390,8 +1666,10 @@ register_variable
}
| IDENTIFIER '=' expression
{ pform_makewire(@1, $1, NetNet::REG);
yyerror(@2, "error: net declaration assignment to reg/integer not allowed.");
delete $3;
if (! pform_expression_is_constant($3))
yyerror(@3, "error: register declaration assignment"
" value must be a constant expression.");
pform_make_reginit(@1, $1, $3);
$$ = $1;
}
| IDENTIFIER '[' expression ':' expression ']'
@@ -1451,11 +1729,51 @@ specparam_list
spec_polarity: '+' | '-' | ;
statement
/* assign and deassign statements are procedural code to do
structural assignments, and to turn that structural assignment
off. This stronger then any other assign, but weaker then the
force assignments. */
: K_assign lavalue '=' expression ';'
{ yyerror(@1, "sorry: procedural continuous assign not supported.");
$$ = 0;
{ PCAssign*tmp = new PCAssign($2, $4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_deassign lavalue';'
{ PDeassign*tmp = new PDeassign($2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
/* Force and release statements are similar to assignments,
syntactically, but they will be elaborated differently. */
| K_force lavalue '=' expression ';'
{ PForce*tmp = new PForce($2, $4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_release lavalue ';'
{ PRelease*tmp = new PRelease($2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
/* begin-end blocks come in a variety of forms, including named and
anonymous. The named blocks can also carry their own reg
variables, which are placed in the scope created by the block
name. These are handled by pushing the scope name then matching
the declarations. The scope is popped at the end of the block. */
| K_begin statement_list K_end
{ PBlock*tmp = new PBlock(PBlock::BL_SEQ, *$2);
tmp->set_file(@1.text);
@@ -1489,32 +1807,12 @@ statement
}
| K_begin error K_end
{ yyerrok; }
| K_deassign lavalue';'
{ yyerror(@1, "sorry:, deassign not supported.");
$$ = 0;
}
| K_disable IDENTIFIER ';'
{ yyerror(@1, "sorry: disable statements not supported.");
delete $2;
$$ = 0;
}
| K_force lavalue '=' expression ';'
{ yyerror(@1, "sorry: procedural force assign not supported.");
$$ = 0;
}
| K_forever statement
{ PForever*tmp = new PForever($2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_fork statement_list K_join
{ PBlock*tmp = new PBlock(PBlock::BL_PAR, *$2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $2;
$$ = tmp;
}
/* fork-join blocks are very similar to begin-end blocks. In fact,
from the parser's perspective there is no real difference. All we
need to do is remember that this is a parallel block so that the
code generator can do the right thing. */
| K_fork ':' IDENTIFIER
{ pform_push_scope($3); }
block_item_decls_opt
@@ -1539,10 +1837,31 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_release lavalue ';'
{ yyerror(@1, "sorry: release not supported.");
| K_disable IDENTIFIER ';'
{ yyerror(@1, "sorry: disable statements not supported.");
delete $2;
$$ = 0;
}
| K_TRIGGER IDENTIFIER ';'
{ PTrigger*tmp = new PTrigger($2);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| K_forever statement
{ PForever*tmp = new PForever($2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_fork statement_list K_join
{ PBlock*tmp = new PBlock(PBlock::BL_PAR, *$2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $2;
$$ = tmp;
}
| K_repeat '(' expression ')' statement
{ PRepeat*tmp = new PRepeat($3, $5);
tmp->set_file(@1.text);
@@ -1622,10 +1941,9 @@ statement
{ $$ = 0;
yyerror(@3, "error: Error in while loop condition.");
}
| delay statement_opt
| delay1 statement_opt
{ PExpr*del = (*$1)[0];
if ($1->count() != 1)
yyerror(@1, "sorry: delay lists not supported here.");
assert($1->count() == 1);
PDelayStatement*tmp = new PDelayStatement(del, $2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
@@ -1653,19 +1971,17 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| lpvalue '=' delay expression ';'
{ PExpr*del = (*$3)[0];
if ($3->count() != 1)
yyerror(@1, "sorry: Delay lists not supported here.");
| lpvalue '=' delay1 expression ';'
{ assert($3->count() == 1);
PExpr*del = (*$3)[0];
PAssign*tmp = new PAssign($1,del,$4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| lpvalue K_LE delay expression ';'
{ PExpr*del = (*$3)[0];
if ($3->count() != 1)
yyerror(@1, "sorry: Delay lists not supported here.");
| lpvalue K_LE delay1 expression ';'
{ assert($3->count() == 1);
PExpr*del = (*$3)[0];
PAssignNB*tmp = new PAssignNB($1,del,$4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
@@ -1677,6 +1993,14 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| lpvalue '=' K_repeat '(' expression ')' event_control expression ';'
{ PAssign*tmp = new PAssign($1,$7,$8);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
yyerror(@3, "sorry: repeat event control not supported.");
delete $5;
$$ = tmp;
}
| lpvalue K_LE event_control expression ';'
{ yyerror(@1, "sorry: Event controls not supported here.");
PAssignNB*tmp = new PAssignNB($1,$4);
@@ -1684,9 +2008,17 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| lpvalue K_LE K_repeat '(' expression ')' event_control expression ';'
{ yyerror(@1, "sorry: Event controls not supported here.");
delete $5;
PAssignNB*tmp = new PAssignNB($1,$8);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_wait '(' expression ')' statement_opt
{ PEventStatement*tmp;
PEEvent*etmp = new PEEvent(NetNEvent::POSITIVE, $3);
PEEvent*etmp = new PEEvent(PEEvent::POSITIVE, $3);
tmp = new PEventStatement(etmp);
tmp->set_statement($5);
$$ = tmp;
@@ -1928,11 +2260,17 @@ udp_input_sym
| '?' { $$ = '?'; }
| 'b' { $$ = 'b'; }
| '*' { $$ = '*'; }
| '%' { $$ = '%'; }
| 'f' { $$ = 'f'; }
| 'F' { $$ = 'F'; }
| 'r' { $$ = 'r'; }
| 'R' { $$ = 'R'; }
| 'n' { $$ = 'n'; }
| 'N' { $$ = 'N'; }
| 'p' { $$ = 'p'; }
| 'P' { $$ = 'P'; }
| '_' { $$ = '_'; }
| '+' { $$ = '+'; }
;
udp_output_sym
+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.
*
+209 -172
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.59 2000/05/08 05:30:20 steve Exp $"
#endif
# include "compiler.h"
# include "pform.h"
# include "parse_misc.h"
# include "PEvent.h"
# include "PUdp.h"
# include <list>
# include <map>
@@ -265,12 +266,32 @@ void pform_make_udp(const char*name, list<string>*parms,
delete init_expr;
}
/*
* 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 string&name, const string&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(const list<string>*names, const string&fn, unsigned ln)
{
list<string>::const_iterator cur;
for (cur = names->begin() ; cur != names->end() ; cur++)
pform_make_event(*cur, fn, ln);
}
/*
* 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 +306,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 +315,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,12 +328,15 @@ 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,
PExpr*msb, PExpr*lsb,
const string&fn, unsigned ln)
{
if (name == "") {
@@ -318,16 +346,35 @@ 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,
PExpr*msb, PExpr*lsb,
const string&fn, unsigned ln)
{
if (name == "") {
@@ -338,37 +385,70 @@ 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);
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 +456,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 +470,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,
struct str_pair_t str,
const string& text,
unsigned lineno)
{
PGAssign*tmp;
for (unsigned idx = 0 ; idx < alist->count()/2 ; idx += 1) {
tmp = pform_make_pgassign((*alist)[2*idx],
(*alist)[2*idx+1], del);
(*alist)[2*idx+1],
del, str);
tmp->set_file(text);
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 +542,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);
@@ -555,8 +681,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.");
}
}
/*
@@ -624,10 +758,23 @@ void pform_set_net_range(list<string>*names, const svector<PExpr*>*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_localparam(const string&name, PExpr*expr)
{
assert(expr);
pform_cur_module->localparams[name] = expr;
}
void pform_set_defparam(const string&name, PExpr*expr)
{
assert(expr);
pform_cur_module->defparms[name] = expr;
}
void pform_set_port_type(list<string>*names, NetNet::PortType pt)
{
for (list<string>::const_iterator cur = names->begin()
@@ -717,6 +864,46 @@ int pform_parse(const char*path, map<string,Module*>&modules,
/*
* $Log: pform.cc,v $
* 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 +938,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.
*
*/
+55 -8
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.40 2000/05/08 05:30:20 steve Exp $"
#endif
# include "netlist.h"
# include "named.h"
# include "Module.h"
# include "Statement.h"
# include "PGate.h"
@@ -65,11 +66,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)
@@ -116,6 +122,8 @@ 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,
NetNet::Type type);
extern void pform_make_reginit(const struct vlltype&li,
const string&name, PExpr*expr);
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_set_reg_idx(const string&name, PExpr*l, PExpr*r);
@@ -127,29 +135,37 @@ 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 bool pform_expression_is_constant(const PExpr*);
extern void pform_make_events(const list<string>*names,
const string&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,
struct str_pair_t str,
const string& text,
unsigned lineno);
@@ -174,6 +190,37 @@ extern void pform_dump(ostream&out, Module*mod);
/*
* $Log: pform.h,v $
* 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.
*
+182 -15
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.58 2000/05/11 23:37:27 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();
@@ -70,10 +95,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) {
parms_[0]->dump(out);
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
out << ", ";
parms_[idx]->dump(out);
}
}
out << ")";
}
@@ -81,19 +109,20 @@ 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 PENumber::dump(ostream&out) const
@@ -247,7 +276,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;
}
@@ -268,6 +297,7 @@ void PGBuiltin::dump(ostream&out) const
out << " builtin gate ";
}
out << "(" << strength0() << "0 " << strength1() << "1) ";
dump_delays(out);
out << " " << get_name();
@@ -283,7 +313,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 +324,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 +481,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_ << " /* " <<
@@ -454,6 +523,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;
@@ -483,6 +558,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 +595,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
{
@@ -582,12 +667,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 +785,63 @@ void PUdp::dump(ostream&out) const
/*
* $Log: pform_dump.cc,v $
* 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.
*
+14 -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: propinit.cc,v 1.1 1998/12/20 02:05:41 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: propinit.cc,v 1.3 2000/05/07 04:37:56 steve Exp $"
#endif
/*
@@ -61,7 +61,7 @@ static void prop_sequdp_output(NetUDP*udp)
/* Take the output value and write it to all the NetNet pins
that are connected to the output pin. */
for (NetObj::Link*lnk = udp->pin(0).next_link()
for (Link*lnk = udp->pin(0).next_link()
; (*lnk) != udp->pin(0) ; lnk = lnk->next_link()) {
if (NetNet*sig = dynamic_cast<NetNet*>(lnk->get_obj()))
@@ -81,6 +81,17 @@ void propinit(Design*des)
/*
* $Log: propinit.cc,v $
* Revision 1.3 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.2 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1998/12/20 02:05:41 steve
* Function to calculate wire initial value.
*
+77 -11
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: set_width.cc,v 1.6 1999/10/05 06:19:46 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: set_width.cc,v 1.13 2000/05/04 03:37:59 steve Exp $"
#endif
/*
@@ -126,10 +126,18 @@ bool NetEBBits::set_width(unsigned w)
*/
bool NetEBComp::set_width(unsigned w)
{
bool flag = true;
return (w == 1);
}
/*
* There is nothing we can do to the operands of a division to make it
* confirm to the requested width. Force the context to pad or truncate.
*/
bool NetEBDiv::set_width(unsigned w)
{
return w == expr_width();
}
bool NetEBLogic::set_width(unsigned w)
{
bool flag;
@@ -139,6 +147,15 @@ bool NetEBLogic::set_width(unsigned w)
return (w == 1);
}
/*
* There is nothing we can do to the operands of a multiply to make it
* confirm to the requested width. Force the context to pad or truncate.
*/
bool NetEBMult::set_width(unsigned w)
{
return w == expr_width();
}
/*
* The shift operator allows the shift amount to have its own
* natural width. The width of the operator result is the width of the
@@ -176,13 +193,34 @@ bool NetEConcat::set_width(unsigned w)
bool NetEConst::set_width(unsigned w)
{
if (w > value_.len())
return false;
if (w > value_.len()) {
verinum tmp (verinum::V0, w);
for (unsigned idx = 0 ; idx < value_.len() ; idx += 1)
tmp.set(idx, value_[idx]);
assert(w <= value_.len());
value_ = verinum(value_, w);
expr_width(w);
return true;
value_ = tmp;
expr_width(w);
return true;
} else {
unsigned use_w = w;
bool flag = true;
// Don't reduce a number too small to hold all the
// significant bits.
for (unsigned idx = w ; idx < value_.len() ; idx += 1)
if (value_[idx] != verinum::V0)
use_w = idx+1;
verinum tmp (verinum::V0, use_w);
for (unsigned idx = 0 ; idx < use_w ; idx += 1)
tmp.set(idx, value_[idx]);
value_ = tmp;
expr_width(use_w);
return use_w == w;
}
}
bool NetEMemory::set_width(unsigned w)
@@ -199,6 +237,11 @@ bool NetEParam::set_width(unsigned)
return false;
}
bool NetESFunc::set_width(unsigned w)
{
return w == expr_width();
}
/*
* The signal should automatically pad with zeros to get to th desired
* width. Do not allow signal bits to be truncated, however.
@@ -244,18 +287,41 @@ bool NetEUnary::set_width(unsigned w)
case '~':
case '-':
flag = expr_->set_width(w);
expr_width(w);
break;
default:
flag = expr_width() == w;
break;
}
expr_width(w);
return flag;
}
/*
* $Log: set_width.cc,v $
* Revision 1.13 2000/05/04 03:37:59 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.12 2000/04/28 18:43:23 steve
* integer division in expressions properly get width.
*
* Revision 1.11 2000/04/26 03:33:32 steve
* Do not set width too small to hold significant bits.
*
* Revision 1.10 2000/04/21 02:46:42 steve
* Many Unary operators have known widths.
*
* Revision 1.9 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.8 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.7 2000/01/01 19:56:51 steve
* Properly expand/shrink constants in expressions.
*
* Revision 1.6 1999/10/05 06:19:46 steve
* Add support for reduction NOR.
*
-189
View File
@@ -1,189 +0,0 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sigfold.cc,v 1.3 1999/11/06 04:51:11 steve Exp $"
#endif
# include "netlist.h"
/*
* Some targets require that a list of connections include exactly one
* signal. This processing step deletes excess signals to meet that
* requirement.
*
* If there is a ring that has more then one signal connected
* together, the following heuristic is used to choose which signal to
* keep:
*
* If the name of signal X is deeper in the design hierarchy then
* signal Y, keep signal Y.
*
* Else, if X is a bus that is not as wide as Y, keep signal Y.
*
* The result of this should be that signals of enclosing modules will
* be preferred over signals of instantiated modules, and bussed
* signals (vectors) will be preferred over scaler signals.
*
* The presence of attributes modifies the folding process, by placing
* restrictions on what is allowed.
*
* If two signals have an attribute key X, they can be folded
* only if X has the same value for both signals.
*
* If signal A has attribute X and signal B does not, then
* signals can be folded if B can take the attribute.
*
* All the pins in a vector have identical attributes.
*/
static unsigned depth(const string&sym)
{
unsigned cnt = 0;
for (unsigned idx = 0 ; idx < sym.length() ; idx += 1)
if (sym[idx] == '.')
cnt += 1;
return cnt;
}
static bool is_any_signal(const NetNet*)
{
return true;
}
static void clear_extra_signals(NetNet*net, unsigned npin)
{
const unsigned mydepth = depth(net->name());
NetObj*cur = net;
unsigned pin = npin;
for (net->pin(pin).next_link(cur, pin) ; cur != net ; ) {
// sig is the node I am going to try to subsume.
NetNet*sig = dynamic_cast<NetNet*>(cur);
// Skip the node if it isn't even a signal.
if (sig == 0) {
cur->pin(pin).next_link(cur, pin);
continue;
}
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig)) {
cerr << "internal warning: sigfold found NetTmp--"
"deleting it." << endl;
// save the next link, ...
NetObj*nxt;
unsigned pnxt;
cur->pin(pin).next_link(nxt, pnxt);
// disconnect the target signal, ...
sig->pin(pin).unlink();
// And onward.
cur = nxt;
pin = pnxt;
continue;
}
// Skip the node if it has incompatible attributes.
if (! net->has_compat_attributes(*sig)) {
// SPECIAL CASE!
if (sig->has_compat_attributes(*net)) {
net->pin(npin).unlink();
return;
}
cur->pin(pin).next_link(cur, pin);
continue;
}
// Skip the node if it is higher up.
if (depth(sig->name()) < mydepth) {
cur->pin(pin).next_link(cur, pin);
continue;
}
// Skip the node if it is a larger vector.
if (sig->pin_count() > net->pin_count()) {
cur->pin(pin).next_link(cur, pin);
continue;
}
// save the next link, ...
NetObj*nxt;
unsigned pnxt;
cur->pin(pin).next_link(nxt, pnxt);
// disconnect the target signal, ...
sig->pin(pin).unlink();
// And onward.
cur = nxt;
pin = pnxt;
}
}
static void delete_if_unconnected(NetNet*net)
{
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1)
if (net->pin(idx).is_linked())
return;
delete net;
}
void sigfold(Design*des)
{
des->clear_signal_marks();
while (NetNet*obj = des->find_signal(&is_any_signal)) {
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
clear_extra_signals(obj, idx);
obj->set_mark();
}
// After the disconnect step, I may have signals that are not
// connected to anything. Delete those.
des->clear_signal_marks();
while (NetNet*obj = des->find_signal(&is_any_signal)) {
obj->set_mark();
delete_if_unconnected(obj);
}
}
/*
* $Log: sigfold.cc,v $
* Revision 1.3 1999/11/06 04:51:11 steve
* Catch NetTmp objects.
*
* Revision 1.2 1998/12/02 04:37:13 steve
* Add the nobufz function to eliminate bufz objects,
* Object links are marked with direction,
* constant propagation is more careful with wide links,
* Signal folding is aware of attributes, and
* the XNF target can dump UDP objects based on LCA
* attributes.
*
* Revision 1.1 1998/11/16 05:03:53 steve
* Add the sigfold function that unlinks excess
* signal nodes, and add the XNF target.
*
*/
-164
View File
@@ -1,164 +0,0 @@
#ifndef __sref_H
#define __sref_H
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version. In order to redistribute the software in
* binary form, you will need a Picture Elements Binary Software
* License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sref.h,v 1.4 1999/08/05 04:58:17 steve Exp $"
#endif
# include <assert.h>
# include "svector.h"
/*
* The sref class is a reference with automatic reference counting. It
* implementes a many-to-one linkage where T1 is the many type and T2
* is the one type.
*/
template <class T1, class T2> class sref;
template <class T1, class T2> class sref_back;
template <class T1, class T2> class sref_back {
friend class sref<T1,T2>;
public:
sref_back() : sback_(0) { }
~sref_back() { assert(sback_ == 0); }
svector<const T2*>* back_list() const;
svector<T2*>* back_list();
private:
void desert_(sref<T1,T2>*);
sref<T1,T2>*sback_;
};
template <class T1, class T2> class sref {
friend class sref_back<T1,T2>;
public:
sref(T1*d) : dest_(d) { insert_(); }
virtual ~sref() { dest_->desert_(this); }
T1*fore_ptr() { return dest_; }
const T1*fore_ptr() const { return dest_; }
private:
T1*dest_;
sref<T1,T2>*next_;
void insert_()
{ if (dest_->sback_ == 0) {
next_ = this;
dest_->sback_ = this;
} else {
next_ = dest_->sback_->next_;
dest_->sback_->next_ = this;
}
}
};
template <class T1,class T2>
svector<const T2*>* sref_back<T1,T2>::back_list() const
{
if (sback_ == 0) return 0;
unsigned cnt = 1;
sref<T1,T2>*cur = sback_->next_;
while (cur != sback_) {
cnt += 1;
cur = cur->next_;
}
svector<const T2*>* result = new svector<const T2*>(cnt);
(*result)[0] = dynamic_cast<const T2*>(sback_);
cur = sback_->next_;
cnt = 1;
while (cur != sback_) {
(*result)[cnt] = dynamic_cast<const T2*>(cur);
cnt += 1;
cur = cur->next_;
}
return result;
}
template <class T1,class T2>
svector<T2*>* sref_back<T1,T2>::back_list()
{
if (sback_ == 0) return 0;
unsigned cnt = 1;
sref<T1,T2>*cur = sback_->next_;
while (cur != sback_) {
cnt += 1;
cur = cur->next_;
}
svector<T2*>* result = new svector<T2*>(cnt);
(*result)[0] = dynamic_cast<T2*>(sback_);
cur = sback_->next_;
cnt = 1;
while (cur != sback_) {
(*result)[cnt] = dynamic_cast<T2*>(cur);
cnt += 1;
cur = cur->next_;
}
return result;
}
template <class T1, class T2> void sref_back<T1,T2>::desert_(sref<T1,T2>*item)
{
if (item == sback_)
sback_ = item->next_;
if (item == sback_) {
sback_ = 0;
} else {
sref<T1,T2>*cur = sback_;
while (cur->next_ != item) {
assert(cur->next_);
cur = cur->next_;
}
cur->next_ = item->next_;
}
}
/*
* $Log: sref.h,v $
* Revision 1.4 1999/08/05 04:58:17 steve
* Fix compile error with gcc 2.95
*
* Revision 1.3 1999/07/18 21:17:51 steve
* Add support for CE input to XNF DFF, and do
* complete cleanup of replaced design nodes.
*
* Revision 1.2 1999/07/18 05:52:47 steve
* xnfsyn generates DFF objects for XNF output, and
* properly rewrites the Design netlist in the process.
*
* Revision 1.1 1999/05/01 02:57:53 steve
* Handle much more complex event expressions.
*
*/
#endif
+5 -2
View File
@@ -20,8 +20,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: svector.h,v 1.4 1999/06/15 03:44:53 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: svector.h,v 1.5 2000/02/23 02:56:55 steve Exp $"
#endif
# include <assert.h>
@@ -97,6 +97,9 @@ template <class TYPE> class svector {
/*
* $Log: svector.h,v $
* Revision 1.5 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.4 1999/06/15 03:44:53 steve
* Get rid of the STL vector template.
*
+201 -25
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: synth.cc,v 1.3 1999/12/01 06:06:16 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: synth.cc,v 1.9 2000/04/16 22:57:34 steve Exp $"
#endif
/*
@@ -30,6 +30,78 @@
# include "functor.h"
# include "netlist.h"
/*
* This functor scans the behavioral code, looking for expressions to
* synthesize. Although it uses the proc_match_t class, it doesn't
* actually match anything, but transforms expressions into structural
* netlists. The product of this should be a process where all the
* expressions have been reduced to a signal ident, which references
* the NetNet of the now synthesized expression.
*/
class do_expr : public proc_match_t {
public:
do_expr(Design*d)
: des_(d) { }
private:
Design*des_;
virtual int assign(NetAssign*);
virtual int event_wait(NetEvWait*);
//virtual int assign_mem(NetAssignMem*);
virtual int condit(NetCondit*);
};
int do_expr::assign(NetAssign*stmt)
{
if (dynamic_cast<NetESignal*>(stmt->rval()))
return 0;
NetNet*tmp = stmt->rval()->synthesize(des_);
if (tmp == 0)
return 0;
NetESignal*tmpe = new NetESignal(tmp);
stmt->set_rval(tmpe);
return 0;
}
int do_expr::condit(NetCondit*stmt)
{
/* synthesize the condition expression, if necessary. */
if (! dynamic_cast<NetESignal*>(stmt->expr())) {
NetNet*tmp = stmt->expr()->synthesize(des_);
if (tmp) {
NetESignal*tmpe = new NetESignal(tmp);
stmt->set_expr(tmpe);
}
}
/* Now recurse through the if and else clauses. */
if (NetProc*tmp = stmt->if_clause())
tmp->match_proc(this);
if (NetProc*tmp = stmt->else_clause())
tmp->match_proc(this);
return 0;
}
int do_expr::event_wait(NetEvWait*stmt)
{
NetProc*tmp = stmt->statement();
if (tmp)
return tmp->match_proc(this);
else
return 0;
}
/*
* This transform recognizes the following patterns:
*
@@ -39,6 +111,14 @@
* always @(posedge CLK) if (CE) Q = D;
* always @(negedge CLK) if (CE) Q = D;
*
* These are memory assignments:
*
* always @(posedge CLK) M[a] = D
* always @(negedge CLK) M[a] = D
*
* always @(posedge CLK) if (CE) M[a] = D;
* always @(negedge CLK) if (CE) M[a] = D;
*
* The r-value of the assignments must be identifiers (i.e. wires or
* registers) and the CE must be single-bit identifiers. The generated
* device will be wide enough to accomodate Q and D.
@@ -47,8 +127,8 @@ class match_dff : public proc_match_t {
public:
match_dff(Design*d, NetProcTop*t)
: des_(d), top_(t), pclk_(0), nclk_(0), con_(0), ce_(0),
asn_(0), d_(0)
: des_(d), top_(t), wclk_(0), eclk_(0), pclk_(0), con_(0), ce_(0),
asn_(0), asm_(0), d_(0)
{ }
~match_dff() { }
@@ -56,18 +136,26 @@ class match_dff : public proc_match_t {
void make_it();
private:
void make_dff_();
void make_ram_();
virtual int assign(NetAssign*);
virtual int assign_mem(NetAssignMem*);
virtual int condit(NetCondit*);
virtual int pevent(NetPEvent*);
virtual int event_wait(NetEvWait*);
Design*des_;
NetProcTop*top_;
NetPEvent*pclk_;
NetNEvent*nclk_;
NetEvWait*wclk_;
NetEvent *eclk_;
NetEvProbe*pclk_;
NetCondit *con_;
NetNet*ce_;
NetAssign *asn_;
NetAssignMem*asm_;
NetNet*d_;
};
@@ -76,7 +164,7 @@ int match_dff::assign(NetAssign*as)
{
if (!pclk_)
return 0;
if (asn_)
if (asn_ || asm_)
return 0;
asn_ = as;
@@ -87,11 +175,26 @@ int match_dff::assign(NetAssign*as)
return 1;
}
int match_dff::assign_mem(NetAssignMem*as)
{
if (!pclk_)
return 0;
if (asn_ || asm_)
return 0;
asm_ = as;
d_ = asm_->rval()->synthesize(des_);
if (d_ == 0)
return 0;
return 1;
}
int match_dff::condit(NetCondit*co)
{
if (!pclk_)
return 0;
if (con_ || asn_)
if (con_ || asn_ || asm_)
return 0;
con_ = co;
@@ -104,27 +207,34 @@ int match_dff::condit(NetCondit*co)
return con_->if_clause()->match_proc(this);
}
int match_dff::pevent(NetPEvent*pe)
int match_dff::event_wait(NetEvWait*evw)
{
if (pclk_ || con_ || asn_)
if (evw->nevents() != 1)
return 0;
pclk_ = pe;
wclk_ = evw;
eclk_ = evw->event(0);
// ... there must be a single event source, ...
svector<class NetNEvent*>*neb = pclk_->back_list();
if (neb == 0)
if (eclk_->nprobe() != 1)
return 0;
if (neb->count() != 1) {
delete neb;
return 0;
}
nclk_ = (*neb)[0];
delete neb;
return pclk_->statement()->match_proc(this);
pclk_ = eclk_->probe(0);
return wclk_->statement()->match_proc(this);
}
void match_dff::make_it()
{
if (asn_) {
assert(asm_ == 0);
make_dff_();
} else {
assert(asm_);
make_ram_();
}
}
void match_dff::make_dff_()
{
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
@@ -133,16 +243,53 @@ void match_dff::make_it()
connect(ff->pin_Q(idx), asn_->pin(idx));
}
connect(ff->pin_Clock(), nclk_->pin(0));
connect(ff->pin_Clock(), pclk_->pin(0));
if (ce_) connect(ff->pin_Enable(), ce_->pin(0));
ff->attribute("LPM_FFType", "DFF");
if (nclk_->type() == NetNEvent::NEGEDGE)
if (pclk_->edge() == NetEvProbe::NEGEDGE)
ff->attribute("Clock:LPM_Polarity", "INVERT");
des_->add_node(ff);
}
void match_dff::make_ram_()
{
NetMemory*mem = asm_->memory();
NetNet*adr = asm_->index();
NetRamDq*ram = new NetRamDq(des_->local_symbol(mem->name()), mem,
adr->pin_count());
for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1)
connect(adr->pin(idx), ram->pin_Address(idx));
for (unsigned idx = 0 ; idx < ram->width() ; idx += 1)
connect(ram->pin_Data(idx), d_->pin(idx));
if (ce_)
connect(ram->pin_WE(), ce_->pin(0));
assert(pclk_->edge() == NetEvProbe::POSEDGE);
connect(ram->pin_InClock(), pclk_->pin(0));
ram->absorb_partners();
des_->add_node(ram);
}
class match_block : public proc_match_t {
public:
match_block(Design*d, NetProcTop*t)
: des_(d), top_(t)
{ }
~match_block() { }
private:
Design*des_;
NetProcTop*top_;
};
class synth_f : public functor_t {
public:
@@ -174,12 +321,20 @@ void synth_f::process(class Design*des, class NetProcTop*top)
*/
void synth_f::proc_always_(class Design*des)
{
do_expr expr_pat(des);
top_->statement()->match_proc(&expr_pat);
match_dff dff_pat(des, top_);
if (top_->statement()->match_proc(&dff_pat)) {
dff_pat.make_it();
des->delete_process(top_);
return;
}
match_block block_pat(des, top_);
if (top_->statement()->match_proc(&block_pat)) {
cerr << "XXXX: recurse and return here" << endl;
}
}
@@ -191,6 +346,27 @@ void synth(Design*des)
/*
* $Log: synth.cc,v $
* Revision 1.9 2000/04/16 22:57:34 steve
* Catch expressions that are part of conditionals.
*
* Revision 1.8 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.7 2000/04/02 04:26:07 steve
* Remove the useless sref template.
*
* Revision 1.6 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.5 2000/02/13 04:35:43 steve
* Include some block matching from Larry.
*
* Revision 1.4 1999/12/05 02:24:09 steve
* Synthesize LPM_RAM_DQ for writes into memories.
*
* Revision 1.3 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
+23 -5
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: t-null.cc,v 1.8 1999/10/05 03:26:37 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: t-null.cc,v 1.11 2000/04/12 04:23:58 steve Exp $"
#endif
# include "netlist.h"
@@ -35,12 +35,11 @@ static class target_null_t : public target_t {
void task_def(ostream&, const NetTaskDef*) { }
void net_assign(ostream&os, const NetAssign*) { }
void net_assign_nb(ostream&os, const NetAssignNB*) { }
void net_const(ostream&, const NetConst*) { }
void net_esignal(ostream&, const NetESignal*) { }
void net_event(ostream&, const NetNEvent*) { }
bool proc_block(ostream&, const NetBlock*) { return true; }
void proc_condit(ostream&, const NetCondit*) { }
void proc_delay(ostream&, const NetPDelay*) { }
void proc_event(ostream&, const NetPEvent*) { }
void proc_forever(ostream&, const NetForever*) { }
void proc_repeat(ostream&, const NetRepeat*) { }
void proc_stask(ostream&, const NetSTask*) { }
@@ -51,6 +50,25 @@ static class target_null_t : public target_t {
extern const struct target tgt_null = { "null", &target_null_obj };
/*
* $Log: t-null.cc,v $
* Revision 1.11 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.10 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.9 2000/02/14 06:04:52 steve
* Unary reduction operators do not set their operand width
*
* Revision 1.8 1999/10/05 03:26:37 steve
* null target ignore assignment nodes.
*
+19 -33
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: t-verilog.cc,v 1.8 1999/09/22 16:57:24 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: t-verilog.cc,v 1.10 2000/04/12 04:23:58 steve Exp $"
#endif
/*
@@ -45,7 +45,6 @@ class target_verilog : public target_t {
virtual void start_process(ostream&os, const NetProcTop*);
virtual bool proc_block(ostream&os, const NetBlock*);
virtual void proc_delay(ostream&os, const NetPDelay*);
virtual void proc_event(ostream&os, const NetPEvent*);
virtual void proc_stask(ostream&os, const NetSTask*);
virtual void end_design(ostream&os, const Design*);
private:
@@ -192,35 +191,6 @@ void target_verilog::proc_delay(ostream&os, const NetPDelay*net)
indent_ -= 4;
}
void target_verilog::proc_event(ostream&os, const NetPEvent*net)
{
os << setw(indent_) << "" << "@";
#if 0
unsigned sidx;
const NetNet*sig = find_link_signal(net, 0, sidx);
switch (net->edge()) {
case NetNEvent::ANYEDGE:
os << mangle(sig->name()) << "[" << sidx << "]";
break;
case NetNEvent::POSEDGE:
os << "(posedge " << mangle(sig->name()) << "[" << sidx << "])";
break;
case NetNEvent::NEGEDGE:
os << "(negedge " << mangle(sig->name()) << "[" << sidx << "])";
break;
}
#else
os << endl;
os << "#error \"proc_event temporarily out of order\"";
#endif
os << endl;
indent_ += 4;
net->emit_proc_recurse(os, this);
indent_ -= 4;
}
static void vtask_parm(ostream&os, const NetExpr*ex)
{
@@ -272,6 +242,22 @@ const struct target tgt_verilog = {
/*
* $Log: t-verilog.cc,v $
* Revision 1.10 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.9 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.8 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
+1788 -813
View File
File diff suppressed because it is too large Load Diff
+341 -72
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,14 +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: t-xnf.cc,v 1.18 1999/11/19 03:02:25 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: t-xnf.cc,v 1.28 2000/05/08 05:29:43 steve Exp $"
#endif
/* XNF BACKEND
* This target supports generating Xilinx Netlist Format netlists for
* use by Xilinx tools, and other tools that accepts Xilinx designs.
*
* The code generator automatically detects ports to top level modules
* and generates SIG records that make the XNF useable as a schematic.
*
* FLAGS
* The XNF backend uses the following flags from the command line to
* affect the generated file:
@@ -77,11 +80,17 @@ class target_xnf : public target_t {
public:
void start_design(ostream&os, const Design*);
void end_design(ostream&os, const Design*);
void memory(ostream&os, const NetMemory*);
void signal(ostream&os, const NetNet*);
void lpm_add_sub(ostream&os, const NetAddSub*);
void lpm_compare(ostream&os, const NetCompare*);
void lpm_compare_eq_(ostream&os, const NetCompare*);
void lpm_compare_ge_(ostream&os, const NetCompare*);
void lpm_compare_le_(ostream&os, const NetCompare*);
void lpm_ff(ostream&os, const NetFF*);
void lpm_mux(ostream&os, const NetMux*);
void lpm_ram_dq(ostream&os, const NetRamDq*);
void net_const(ostream&os, const NetConst*);
void logic(ostream&os, const NetLogic*);
@@ -90,13 +99,13 @@ class target_xnf : public target_t {
private:
static string mangle(const string&);
static string choose_sig_name(const NetObj::Link*lnk);
static string choose_sig_name(const Link*lnk);
static void draw_pin(ostream&os, const string&name,
const NetObj::Link&lnk);
const Link&lnk);
static void draw_sym_with_lcaname(ostream&os, string lca,
const NetNode*net);
static void draw_xor(ostream&os, const NetAddSub*, unsigned idx);
enum adder_type {FORCE0, LOWER, UPPER, DOUBLE };
enum adder_type {FORCE0, LOWER, DOUBLE, LOWER_W_CO, EXAMINE_CI };
static void draw_carry(ostream&os, const NetAddSub*, unsigned idx,
enum adder_type);
@@ -128,12 +137,13 @@ string target_xnf::mangle(const string&name)
* nexus to decide which name to use if there are lots of attached
* signals.
*/
string target_xnf::choose_sig_name(const NetObj::Link*lnk)
string target_xnf::choose_sig_name(const Link*lnk)
{
assert(lnk->is_linked());
const NetNet*sig = dynamic_cast<const NetNet*>(lnk->get_obj());
unsigned pin = lnk->get_pin();
for (const NetObj::Link*cur = lnk->next_link()
for (const Link*cur = lnk->next_link()
; cur != lnk ; cur = cur->next_link()) {
const NetNet*cursig = dynamic_cast<const NetNet*>(cur->get_obj());
@@ -176,7 +186,7 @@ string target_xnf::choose_sig_name(const NetObj::Link*lnk)
}
void target_xnf::draw_pin(ostream&os, const string&name,
const NetObj::Link&lnk)
const Link&lnk)
{
bool inv = false;
string use_name = name;
@@ -187,11 +197,11 @@ void target_xnf::draw_pin(ostream&os, const string&name,
char type;
switch (lnk.get_dir()) {
case NetObj::Link::INPUT:
case NetObj::Link::PASSIVE:
case Link::INPUT:
case Link::PASSIVE:
type = 'I';
break;
case NetObj::Link::OUTPUT:
case Link::OUTPUT:
type = 'O';
break;
}
@@ -295,6 +305,14 @@ void scrape_pad_info(string str, char&dir, unsigned&num)
num = val;
}
/*
* Memories are handled by the lpm_ram_dq method, so there is nothing
* to do here.
*/
void target_xnf::memory(ostream&, const NetMemory*)
{
}
/*
* Look for signals that have attributes that are pertinent to XNF
* files. The most obvious are those that have the PAD attribute.
@@ -308,6 +326,37 @@ void scrape_pad_info(string str, char&dir, unsigned&num)
*/
void target_xnf::signal(ostream&os, const NetNet*net)
{
/* Look for signals that are ports to the root module. If they
are, the write a SIG record and generate a pin name so that
this module can be used as a macro. */
if (const NetScope*scope = net->scope()) do {
if (scope->parent())
break;
if (net->port_type() == NetNet::NOT_A_PORT)
break;
string mname = mangle(net->name());
string pname = mname.substr(mname.find('/')+1, mname.length());
if (net->pin_count() == 1) {
os << "SIG, " << mangle(net->name()) << ", PIN="
<< pname << endl;
} else for (unsigned idx = 0; idx < net->pin_count(); idx += 1) {
os << "SIG, " << mangle(net->name()) << "<" << idx
<< ">, PIN=" << pname << idx << endl;
}
} while (0);
/* Now look to see if a PAD attribute is attached, and if so
write out PAD information to the XNF and the ncf files. */
string pad = net->attribute("PAD");
if (pad == "")
return;
@@ -364,44 +413,43 @@ void target_xnf::draw_carry(ostream &os, const NetAddSub*gate, unsigned idx,
"LIBVER=2.0.0" << endl;
// Less significant bit addends, if any
if ( type == LOWER || type == DOUBLE ) {
if ( type == LOWER || type == DOUBLE || type == LOWER_W_CO ) {
draw_pin(os, "A0", gate->pin_DataA(idx));
draw_pin(os, "B0", gate->pin_DataB(idx));
}
// More significant bit addends, if any
if ( type == UPPER || type == DOUBLE ) {
unsigned int i = (type==UPPER)?idx:(idx+1);
draw_pin(os, "A1", gate->pin_DataA(i));
draw_pin(os, "B1", gate->pin_DataB(i));
if ( type == DOUBLE ) {
draw_pin(os, "A1", gate->pin_DataA(idx+1));
draw_pin(os, "B1", gate->pin_DataB(idx+1));
}
// Carry input
if ( type != FORCE0 && type != UPPER ) {
os << " PIN, CIN, I, " << name_cout << "<" <<
idx << ">" << endl;
// All but FORCE0 cells have carry input
if ( type != FORCE0 ) {
os << " PIN, CIN, I, " << name_cout << "<" << idx << ">" << endl;
}
// Connect the Cout0 to a signal so that I can connect
// it to the adder.
if ( type == LOWER || type == DOUBLE ) {
switch (type) {
case LOWER:
case DOUBLE:
os << " PIN, COUT0, O, " << name_cout << "<" << (idx+1) <<
">" << endl;
break;
case EXAMINE_CI:
case LOWER_W_CO:
draw_pin(os, "COUT0", gate->pin_Cout());
break;
}
// Connect the Cout, this will connect to the next Cin
if ( type == FORCE0 || type == UPPER || type == DOUBLE ) {
if ( type == FORCE0 || type == DOUBLE ) {
unsigned int to = (type==FORCE0)?(0):(idx+2);
if (type==UPPER) to=idx+1;
os << " PIN, COUT, O, " << name_cout << "<" << to <<
">" << endl;
}
// Carry In for mode UPPER comes from a strange place
if ( type == UPPER ) {
os << " PIN, A0, I, " << name_cout << "<dummy>" << endl;
}
// These are the mode inputs from the CY_xx pseudo-device
for (unsigned cn = 0 ; cn < 8 ; cn += 1) {
os << " PIN, C" << cn << ", I, " << name << "/C"
@@ -409,26 +457,24 @@ void target_xnf::draw_carry(ostream &os, const NetAddSub*gate, unsigned idx,
}
os << "END" << endl;
// Complete the dummy force used above
if ( type == UPPER ) {
os << "PWR, 0, " << name_cout << "<dummy>" << endl;
}
// On to the CY_xx pseudo-device itself
os << "SYM, " << name_cym << "<" << (idx) << ">, ";
switch (type) {
case FORCE0:
case FORCE0:
os << "CY4_37, CYMODE=FORCE-0" << endl;
break;
case LOWER:
case LOWER:
os << "CY4_01, CYMODE=ADD-F-CI" << endl;
break;
case UPPER:
os << "CY4_03, CYMODE=ADD-G-F1" << endl;
case LOWER_W_CO:
os << "CY4_01, CYMODE=ADD-F-CI" << endl;
break;
case DOUBLE:
case DOUBLE:
os << "CY4_02, CYMODE=ADD-FG-CI" << endl;
break;
case EXAMINE_CI:
os << "CY4_42, CYMODE-EXAMINE-CI" << endl;
break;
}
for (unsigned cn = 0 ; cn < 8 ; cn += 1) {
os << " PIN, C" << cn << ", O, " << name << "/C"
@@ -454,33 +500,170 @@ void target_xnf::lpm_add_sub(ostream&os, const NetAddSub*gate)
{
unsigned width = gate->width();
// Don't handle carry output yet
// assert (count_outputs(gate->pin_Cout())==0);
unsigned carry_width = width-1;
/* Make the force-0 cary mode object to initialize the bottom
/* Make the force-0 carry mode object to initialize the bottom
bits of the carry chain. Label this with the width instead
of the bit position so that symbols don't clash. */
if (carry_width%2) {
draw_carry(os, gate, width, FORCE0);
} else {
draw_carry(os, gate, 0, UPPER);
}
draw_carry(os, gate, width+1, FORCE0);
/* Now make the 2 bit adders that chain from the cin
initializer and up. Save the tail bit (if there is one) for
later. */
for (unsigned idx = 1-(carry_width%2) ; idx < carry_width-1 ; idx += 2) {
initializer and up. Save the tail bits for later. */
for (unsigned idx = 0 ; idx < width-2 ; idx += 2)
draw_carry(os, gate, idx, DOUBLE);
/* Always have one or two tail bits. The situation gets a
little tricky if we want the carry output, so handle that
here.
If the carry-out is connected, and there are an even number
of data bits, we need to see the cout from the CLB. This is
done by configuring the top CLB CY device as ADD-FG-CI (to
activate cout) and create an extra CLB CY device on top of
the carry chain configured EXAMINE-CI to put the carry into
the G function block.
IF the carry-out is connected and there are an odd number
of data bits, then the top CLB can be configured to carry
the top bit in the F unit and deliver the carry out through
the G unit.
If the carry-out is not connected, then configure this top
CLB as ADD-F-CI. The draw_xor for the top bit will include
the F carry if needed. */
if (gate->pin_Cout().is_linked()) {
if (width%2 == 0) {
draw_carry(os, gate, width-2, DOUBLE);
draw_carry(os, gate, width, EXAMINE_CI);
} else {
draw_carry(os, gate, width-1, LOWER_W_CO);
}
} else {
if (width%2 == 0)
draw_carry(os, gate, width-2, LOWER);
else
draw_carry(os, gate, width-1, LOWER);
}
/* Always have a tail bit */
draw_carry(os, gate, carry_width-1, LOWER);
for (unsigned idx = 0 ; idx < width ; ++idx) {
/* Now draw all the single bit (plus carry in) adders from XOR
gates. This puts the F and G units to use. */
for (unsigned idx = 0 ; idx < width ; idx += 1)
draw_xor(os, gate, idx);
}
/*
* In XNF, comparators are done differently depending on the type of
* comparator being implemented. So, here we dispatch to the correct
* code generator.
*/
void target_xnf::lpm_compare(ostream&os, const NetCompare*dev)
{
if (dev->pin_AEB().is_linked()) {
lpm_compare_eq_(os, dev);
return;
}
if (dev->pin_AGEB().is_linked()) {
lpm_compare_ge_(os, dev);
return;
}
if (dev->pin_ALEB().is_linked()) {
lpm_compare_le_(os, dev);
return;
}
assert(0);
}
/*
* To compare that vectors are equal (identity comparator) generate
* XNOR gates to compare each pair of bits, then generate an AND gate
* to combine the bitwise results. This is pretty much the best way to
* do an identity compare in Xilinx CLBs.
*/
void target_xnf::lpm_compare_eq_(ostream&os, const NetCompare*dev)
{
string mname = mangle(dev->name());
/* Draw XNOR gates for each bit pair. These gates to the
bitwise comparison. */
for (unsigned idx = 0 ; idx < dev->width() ; idx += 1) {
os << "SYM, " << mname << "/cmp<" << idx << ">, "
<< "XNOR, LIBVER=2.0.0" << endl;
os << " PIN, O, O, " << mname << "/bit<" << idx << ">"
<< endl;
draw_pin(os, "I0", dev->pin_DataA(idx));
draw_pin(os, "I1", dev->pin_DataB(idx));
os << "END" << endl;
}
/* Now draw an AND gate to combine all the bitwise
comparisons. If there are more the 5 bits of data, then we
are going to have generate a nested AND to combine the
results. */
if (dev->width() > 5) {
for (unsigned idx = 0 ; idx < dev->width() ; idx += 5) {
if ((idx+1) >= dev->width()) break;
os << "SYM, " << mname << "/nest<" << idx
<< ">, AND, LIBVER=2.0.0" << endl;
os << " PIN, O, O, " << mname << "/nbit<" << idx
<< ">" << endl;
os << " PIN, I0, I, " << mname << "/bit<" << idx+0
<< ">" << endl;
os << " PIN, I1, I, " << mname << "/bit<" << idx+1
<< ">" << endl;
if ((idx+2) >= dev->width()) goto gate_out;
os << " PIN, I2, I, " << mname << "/bit<" << idx+2
<< ">" << endl;
if ((idx+3) >= dev->width()) goto gate_out;
os << " PIN, I3, I, " << mname << "/bit<" << idx+3
<< ">" << endl;
if ((idx+4) >= dev->width()) goto gate_out;
os << " PIN, I4, I, " << mname << "/bit<" << idx+4
<< ">" << endl;
gate_out:
os << "END" << endl;
}
os << "SYM, " << mname << ", AND, LIBVER=2.0.0" << endl;
draw_pin(os, "O", dev->pin_AEB());
for (unsigned idx = 0 ; idx < dev->width() ; idx += 5) {
if ((idx+1) == dev->width())
os << " PIN, I" << idx/5 << ", I " << mname
<< "/bit<" << idx << ">" << endl;
else
os << " PIN, I" << idx/5 << ", I " << mname
<< "/nbit<" << idx << ">" << endl;
}
os << "END" << endl;
} else {
os << "SYM, " << mname << ", AND, LIBVER=2.0.0" << endl;
draw_pin(os, "O", dev->pin_AEB());
for (unsigned idx = 0 ; idx < dev->width() ; idx += 1) {
os << " PIN, I" << idx << ", I, " << mname << "/bit<"
<< idx << ">" << endl;
}
os << "END" << endl;
}
}
void target_xnf::lpm_compare_ge_(ostream&os, const NetCompare*dev)
{
cerr << "XXXX GE not supported yet" << endl;
}
void target_xnf::lpm_compare_le_(ostream&os, const NetCompare*dev)
{
cerr << "XXXX LE not supported yet" << endl;
}
void target_xnf::lpm_ff(ostream&os, const NetFF*net)
@@ -545,17 +728,43 @@ void target_xnf::lpm_mux(ostream&os, const NetMux*net)
}
void target_xnf::lpm_ram_dq(ostream&os, const NetRamDq*ram)
{
assert(ram->count_partners() == 1);
const NetMemory*mem = ram->mem();
for (unsigned idx = 0 ; idx < ram->width() ; idx += 1) {
os << "SYM, " << mangle(ram->name())
<< "<" << idx << ">, RAMS" << endl;
draw_pin(os, "O", ram->pin_Q(idx));
draw_pin(os, "D", ram->pin_Data(idx));
draw_pin(os, "WE", ram->pin_WE());
draw_pin(os, "WCLK", ram->pin_InClock());
for (unsigned adr = 0 ; adr < ram->awidth() ; adr += 1) {
strstream tmp;
tmp << "A" << adr << ends;
draw_pin(os, tmp.str(), ram->pin_Address(adr));
}
os << "END" << endl;
}
}
void target_xnf::net_const(ostream&os, const NetConst*c)
{
verinum::V v=c->value();
assert(v==verinum::V0 || v==verinum::V1);
const NetObj::Link& lnk = c->pin(0);
// Code parallels draw_pin above, some smart c++ guru should
// find a way to make a method out of this.
unsigned cpin;
const NetObj*cur;
for (unsigned idx = 0 ; idx < c->pin_count() ; idx += 1) {
verinum::V v=c->value(idx);
assert(v==verinum::V0 || v==verinum::V1);
const Link& lnk = c->pin(idx);
// Code parallels draw_pin above, some smart c++ guru should
// find a way to make a method out of this.
unsigned cpin;
const NetObj*cur;
os << " PWR, " << v << ", " << choose_sig_name(&lnk) << endl;
os << " PWR, " << v << ", " << choose_sig_name(&lnk) << endl;
}
}
/*
@@ -598,21 +807,46 @@ void target_xnf::logic(ostream&os, const NetLogic*net)
case NetLogic::XOR:
os << "XOR";
break;
case NetLogic::BUFIF0:
case NetLogic::BUFIF1:
os << "TBUF";
break;
default:
cerr << "XNF: Unhandled logic type." << endl;
cerr << "internal error: XNF: Unhandled logic type." << endl;
break;
}
os << ", LIBVER=2.0.0" << endl;
/* All of these kinds of devices have an output on pin 0. */
draw_pin(os, "O", net->pin(0));
if (net->pin_count() == 2) {
/* Most devices have inputs called I<N> for all the remaining
pins. The TBUF devices are slightly different, but
essentially the same structure. */
switch (net->type()) {
case NetLogic::BUFIF0:
assert(net->pin_count() == 3);
draw_pin(os, "I", net->pin(1));
draw_pin(os, "~T", net->pin(2));
break;
case NetLogic::BUFIF1:
assert(net->pin_count() == 3);
draw_pin(os, "I", net->pin(1));
} else for (unsigned idx = 1 ; idx < net->pin_count() ; idx += 1) {
string name = "I";
assert(net->pin_count() <= 11);
name += (char)('0'+idx-1);
draw_pin(os, name, net->pin(idx));
draw_pin(os, "T", net->pin(2));
break;
default:
if (net->pin_count() == 2) {
draw_pin(os, "I", net->pin(1));
} else for (unsigned idx = 1; idx < net->pin_count(); idx += 1) {
string name = "I";
assert(net->pin_count() <= 11);
name += (char)('0'+idx-1);
draw_pin(os, name, net->pin(idx));
}
break;
}
os << "END" << endl;
@@ -623,7 +857,7 @@ void target_xnf::bufz(ostream&os, const NetBUFZ*net)
static int warned_once=0;
if (!warned_once) {
cerr << "Warning: BUFZ object found for xnf output."
" Try -Fnobufz." << endl;
<< endl;
warned_once=1;
}
os << "SYM, " << mangle(net->name()) << ", BUF, LIBVER=2.0.0" << endl;
@@ -653,6 +887,41 @@ extern const struct target tgt_xnf = { "xnf", &target_xnf_obj };
/*
* $Log: t-xnf.cc,v $
* Revision 1.28 2000/05/08 05:29:43 steve
* no need for nobufz functor.
*
* Revision 1.27 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.26 2000/04/23 23:03:13 steve
* automatically generate macro interface code.
*
* Revision 1.25 2000/04/23 21:15:07 steve
* Emit code for the bufif devices.
*
* Revision 1.24 2000/04/20 02:34:47 steve
* Generate code for identity compare. Use gates.
*
* Revision 1.23 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.22 1999/12/17 03:38:46 steve
* NetConst can now hold wide constants.
*
* Revision 1.21 1999/12/16 18:54:32 steve
* Capture the carry out of carry-chain addition.
*
* Revision 1.20 1999/12/16 02:42:15 steve
* Simulate carry output on adders.
*
* Revision 1.19 1999/12/05 19:30:43 steve
* Generate XNF RAMS from synthesized memories.
*
* Revision 1.18 1999/11/19 03:02:25 steve
* Detect flip-flops connected to opads and turn
* them into OUTFF devices. Inprove support for
+133 -8
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: target.cc,v 1.28 1999/11/28 23:42:03 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: target.cc,v 1.39 2000/05/11 23:37:27 steve Exp $"
#endif
# include "target.h"
@@ -35,6 +35,12 @@ void target_t::scope(ostream&, const NetScope*)
{
}
void target_t::event(ostream&, const NetEvent*ev)
{
cerr << ev->get_line() << ": error: target (" << typeid(*this).name()
<< "): Unhandled event <" << ev->full_name() << ">." << endl;
}
void target_t::signal(ostream&os, const NetNet*)
{
}
@@ -73,6 +79,12 @@ void target_t::udp(ostream&os, const NetUDP*)
"Unhandled UDP." << endl;
}
void target_t::udp_comb(ostream&os, const NetUDP_COMB*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled combinational primitive." << endl;
}
void target_t::lpm_add_sub(ostream&, const NetAddSub*)
{
cerr << "target (" << typeid(*this).name() << "): "
@@ -91,12 +103,24 @@ void target_t::lpm_compare(ostream&, const NetCompare*)
"Unhandled NetCompare." << endl;
}
void target_t::lpm_divide(ostream&, const NetDivide*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetDivide." << endl;
}
void target_t::lpm_ff(ostream&, const NetFF*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetFF." << endl;
}
void target_t::lpm_mult(ostream&, const NetMult*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetMult." << endl;
}
void target_t::lpm_mux(ostream&, const NetMux*)
{
cerr << "target (" << typeid(*this).name() << "): "
@@ -125,16 +149,30 @@ void target_t::net_case_cmp(ostream&os, const NetCaseCmp*)
"Unhandled case compare node." << endl;
}
bool target_t::net_cassign(ostream&os, const NetCAssign*dev)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetCAssign node." << endl;
return false;
}
void target_t::net_const(ostream&os, const NetConst*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled CONSTANT node." << endl;
}
void target_t::net_event(ostream&os, const NetNEvent*net)
bool target_t::net_force(ostream&os, const NetForce*dev)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled EVENT net node." << endl;
"Unhandled NetForce node." << endl;
return false;
}
void target_t::net_probe(ostream&os, const NetEvProbe*net)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled probe trigger node" << endl;
net->dump_node(cerr, 4);
}
@@ -181,6 +219,13 @@ void target_t::proc_case(ostream&os, const NetCase*cur)
cur->dump(cerr, 6);
}
bool target_t::proc_cassign(ostream&os, const NetCAssign*dev)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled proc_cassign." << endl;
return false;
}
void target_t::proc_condit(ostream&os, const NetCondit*condit)
{
cerr << "target (" << typeid(*this).name() << "): "
@@ -188,17 +233,25 @@ void target_t::proc_condit(ostream&os, const NetCondit*condit)
condit->dump(cerr, 6);
}
bool target_t::proc_deassign(ostream&os, const NetDeassign*dev)
{
cerr << dev->get_line() << ": internal error: "
<< "target (" << typeid(*this).name() << "): "
<< "Unhandled proc_deassign." << endl;
return false;
}
void target_t::proc_delay(ostream&os, const NetPDelay*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled proc_delay." << endl;
}
void target_t::proc_event(ostream&os, const NetPEvent*net)
bool target_t::proc_force(ostream&os, const NetForce*dev)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled proc_event." << endl;
net->dump(cerr, 4);
"Unhandled proc_force." << endl;
return false;
}
void target_t::proc_forever(ostream&os, const NetForever*)
@@ -207,12 +260,27 @@ void target_t::proc_forever(ostream&os, const NetForever*)
"Unhandled proc_forever." << endl;
}
bool target_t::proc_release(ostream&os, const NetRelease*dev)
{
cerr << dev->get_line() << ": internal error: "
<< "target (" << typeid(*this).name() << "): "
<< "Unhandled proc_release." << endl;
return false;
}
void target_t::proc_repeat(ostream&os, const NetRepeat*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled proc_repeat." << endl;
}
bool target_t::proc_trigger(ostream&os, const NetEvTrig*tr)
{
cerr << tr->get_line() << ": error: target (" << typeid(*this).name()
<< "): Unhandled event trigger." << endl;
return false;
}
void target_t::proc_stask(ostream&os, const NetSTask*)
{
cerr << "target (" << typeid(*this).name() << "): "
@@ -225,6 +293,13 @@ void target_t::proc_utask(ostream&os, const NetUTask*)
"Unhandled proc_utask." << endl;
}
bool target_t::proc_wait(ostream&os, const NetEvWait*tr)
{
cerr << tr->get_line() << ": error: target (" << typeid(*this).name()
<< "): Unhandled event wait." << endl;
return false;
}
void target_t::proc_while(ostream&os, const NetWhile*net)
{
cerr << "target (" << typeid(*this).name() << "): "
@@ -270,6 +345,12 @@ void expr_scan_t::expr_scope(const NetEScope*)
"unhandled expr_scope." << endl;
}
void expr_scan_t::expr_sfunc(const NetESFunc*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
"unhandled expr_sfunc." << endl;
}
void expr_scan_t::expr_signal(const NetESignal*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
@@ -308,6 +389,50 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
/*
* $Log: target.cc,v $
* Revision 1.39 2000/05/11 23:37:27 steve
* Add support for procedural continuous assignment.
*
* Revision 1.38 2000/05/04 03:37:59 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.37 2000/04/23 03:45:24 steve
* Add support for the procedural release statement.
*
* Revision 1.36 2000/04/22 04:20:19 steve
* Add support for force assignment.
*
* Revision 1.35 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.34 2000/04/10 05:26:06 steve
* All events now use the NetEvent class.
*
* Revision 1.33 2000/04/04 03:20:15 steve
* Simulate named event trigger and waits.
*
* Revision 1.32 2000/04/01 21:40:23 steve
* Add support for integer division.
*
* Revision 1.31 2000/03/29 04:37:11 steve
* New and improved combinational primitives.
*
* Revision 1.30 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
* Revision 1.29 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.28 1999/11/28 23:42:03 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
+45 -109
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: target.h,v 1.27 1999/11/28 23:42:03 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: target.h,v 1.38 2000/05/11 23:37:27 steve Exp $"
#endif
# include "netlist.h"
@@ -59,6 +59,9 @@ struct target_t {
anything else is called. */
virtual void scope(ostream&os, const NetScope*);
/* Output an event object. Called for each named event in the scope. */
virtual void event(ostream&os, const NetEvent*);
/* Output a signal (called for each signal) */
virtual void signal(ostream&os, const NetNet*);
@@ -73,7 +76,9 @@ struct target_t {
virtual void lpm_add_sub(ostream&os, const NetAddSub*);
virtual void lpm_clshift(ostream&os, const NetCLShift*);
virtual void lpm_compare(ostream&os, const NetCompare*);
virtual void lpm_divide(ostream&os, const NetDivide*);
virtual void lpm_ff(ostream&os, const NetFF*);
virtual void lpm_mult(ostream&os, const NetMult*);
virtual void lpm_mux(ostream&os, const NetMux*);
virtual void lpm_ram_dq(ostream&os, const NetRamDq*);
@@ -81,11 +86,14 @@ struct target_t {
virtual void logic(ostream&os, const NetLogic*);
virtual void bufz(ostream&os, const NetBUFZ*);
virtual void udp(ostream&os, const NetUDP*);
virtual void udp_comb(ostream&os, const NetUDP_COMB*);
virtual void net_assign(ostream&os, const NetAssign*);
virtual void net_assign_nb(ostream&os, const NetAssignNB*);
virtual void net_case_cmp(ostream&os, const NetCaseCmp*);
virtual bool net_cassign(ostream&os, const NetCAssign*);
virtual void net_const(ostream&os, const NetConst*);
virtual void net_event(ostream&os, const NetNEvent*);
virtual bool net_force(ostream&os, const NetForce*);
virtual void net_probe(ostream&os, const NetEvProbe*);
/* Output a process (called for each process). It is up to the
target to recurse if desired. */
@@ -98,14 +106,18 @@ struct target_t {
virtual void proc_assign_mem_nb(ostream&os, const NetAssignMemNB*);
virtual bool proc_block(ostream&os, const NetBlock*);
virtual void proc_case(ostream&os, const NetCase*);
virtual bool proc_cassign(ostream&os, const NetCAssign*);
virtual void proc_condit(ostream&os, const NetCondit*);
virtual bool proc_deassign(ostream&os, const NetDeassign*);
virtual bool proc_force(ostream&os, const NetForce*);
virtual void proc_forever(ostream&os, const NetForever*);
virtual bool proc_release(ostream&os, const NetRelease*);
virtual void proc_repeat(ostream&os, const NetRepeat*);
virtual bool proc_trigger(ostream&os, const NetEvTrig*);
virtual void proc_stask(ostream&os, const NetSTask*);
virtual void proc_utask(ostream&os, const NetUTask*);
virtual bool proc_wait(ostream&os, const NetEvWait*);
virtual void proc_while(ostream&os, const NetWhile*);
virtual void proc_event(ostream&os, const NetPEvent*);
virtual void proc_delay(ostream&os, const NetPDelay*);
/* Done with the design. */
@@ -121,6 +133,7 @@ struct expr_scan_t {
virtual void expr_ident(const NetEIdent*);
virtual void expr_memory(const NetEMemory*);
virtual void expr_scope(const NetEScope*);
virtual void expr_sfunc(const NetESFunc*);
virtual void expr_signal(const NetESignal*);
virtual void expr_subsignal(const NetESubSignal*);
virtual void expr_ternary(const NetETernary*);
@@ -146,119 +159,42 @@ extern const struct target *target_table[];
/*
* $Log: target.h,v $
* Revision 1.27 1999/11/28 23:42:03 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
* Revision 1.38 2000/05/11 23:37:27 steve
* Add support for procedural continuous assignment.
*
* Revision 1.26 1999/11/27 19:07:58 steve
* Support the creation of scopes.
* Revision 1.37 2000/05/04 03:37:59 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.25 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
* Revision 1.36 2000/04/23 03:45:25 steve
* Add support for the procedural release statement.
*
* Revision 1.24 1999/11/14 23:43:46 steve
* Support combinatorial comparators.
* Revision 1.35 2000/04/22 04:20:20 steve
* Add support for force assignment.
*
* Revision 1.23 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
* Revision 1.34 2000/04/12 04:23:58 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Revision 1.22 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
* 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.
*
* 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.
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
* Revision 1.33 2000/04/10 05:26:06 steve
* All events now use the NetEvent class.
*
* Revision 1.21 1999/11/01 02:07:41 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
* Revision 1.32 2000/04/04 03:20:15 steve
* Simulate named event trigger and waits.
*
* Revision 1.20 1999/10/10 01:59:55 steve
* Structural case equals device.
*
* Revision 1.19 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.18 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.17 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.16 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.15 1999/07/17 19:51:00 steve
* netlist support for ternary operator.
*
* Revision 1.14 1999/07/17 03:39:11 steve
* simplified process scan for targets.
*
* Revision 1.13 1999/07/03 02:12:52 steve
* Elaborate user defined tasks.
*
* Revision 1.12 1999/06/19 21:06:16 steve
* Elaborate and supprort to vvm the forever
* and repeat statements.
*
* Revision 1.11 1999/06/09 03:00:06 steve
* Add support for procedural concatenation expression.
*
* Revision 1.10 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.9 1999/05/12 04:03:20 steve
* emit NetAssignMem objects in vvm target.
*
* Revision 1.8 1999/05/01 02:57:53 steve
* Handle much more complex event expressions.
*
* Revision 1.7 1999/04/25 00:44:10 steve
* Core handles subsignal expressions.
*
* Revision 1.6 1999/04/19 01:59:37 steve
* Add memories to the parse and elaboration phases.
*
* Revision 1.5 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.4 1998/12/01 00:42:15 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:35 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: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:06 steve
* Introduce verilog to CVS.
* Revision 1.31 2000/04/01 21:40:23 steve
* Add support for integer division.
*
* Revision 1.30 2000/03/29 04:37:11 steve
* New and improved combinational primitives.
*/
#endif
+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: targets.cc,v 1.4 1999/05/01 02:57:53 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: targets.cc,v 1.5 2000/02/23 02:56:56 steve Exp $"
#endif
# include "target.h"
@@ -37,6 +37,9 @@ const struct target *target_table[] = {
/*
* $Log: targets.cc,v $
* Revision 1.5 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
* Revision 1.4 1999/05/01 02:57:53 steve
* Handle much more complex event expressions.
*
+45
View File
@@ -0,0 +1,45 @@
/*
* 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: util.cc,v 1.1 2000/04/28 16:50:53 steve Exp $"
#endif
# include "util.h"
string parse_first_name(string&path)
{
unsigned pos = path.find('.');
if (pos > path.length()) {
string res = path;
path = "";
return res;
}
string res = path.substr(0, pos);
path = path.substr(pos+1, path.length());
return res;
}
/*
* $Log: util.cc,v $
* Revision 1.1 2000/04/28 16:50:53 steve
* Catch memory word parameters to tasks.
*
*/
+40
View File
@@ -0,0 +1,40 @@
#ifndef __util_H
#define __util_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: util.h,v 1.1 2000/04/29 04:53:44 steve Exp $"
#endif
# include <string>
/*
* This function returns the first name of a hierarchical path, and
* sets the parameter to what's left. If there is no path, then the
* parameter is set to "".
*/
extern string parse_first_name(string&path);
/*
* $Log: util.h,v $
* Revision 1.1 2000/04/29 04:53:44 steve
* missing header file.
*
*/
#endif
+2
View File
@@ -31,6 +31,8 @@ Defines macro \fImacro\fP as \fIdefn\fP.
.B -I\fIincludepath\fP
Append path \fIincludepath\fP to list of paths searched for include files.
.TP 8
.B -m\fImodule\fP
Add this module to the list of modules to be loaded by the simulation.
.B -X
Generate XNF files as output. Default is VVM-format.
.TP 8
+4 -3
View File
@@ -21,7 +21,7 @@
# Added support for functors, especially for the XNF target. <[email protected]>
# Setup variables
execPath=@bindir@
execPath=@libdir@/ivl
execIVLPP=${execPath}/ivlpp
execIVL=${execPath}/ivl
execCpp=@CXX@
@@ -46,7 +46,7 @@ flags=""
#fi
# Try to extract given parameters
parameter=`getopt D:I:Xxf:o:s:t: "$@"`
parameter=`getopt D:I:Xxf:m:o:s:t: "$@"`
eval set -- "${parameter}"
while true ; do
@@ -55,6 +55,7 @@ while true ; do
-I) extIncPath="${extIncPath} -I $2" ; shift 2 ;;
-X) target="xnf" ; shift ;;
-f) flags="$flags -f$2" ; shift 2 ;;
-m) flags="$flags -m$2" ; shift 2 ;;
-o) outputFile=$2 ; shift 2 ;;
-s) topModule="-s $2 " ; shift 2 ;;
-t) target="$2" ; shift 2 ;;
@@ -115,7 +116,7 @@ case "${target}" in
"xnf") mv ${tmpCCFile} ${outputFile} ;;
"vvm") ${execCpp} -rdynamic -I${includedir} -L${libdir} ${tmpCCFile} -o ${outputFile} -lvvm -ldl ;
"vvm") ${execCpp} -rdynamic -I${includedir} -L${libdir} ${tmpCCFile} -o ${outputFile} -lvvm @dllib@ ;
if test $? -ne 0 ; then
echo "C++ compilation failed. Terminating compilation."
rm -f ${tmpCCFile}
+28 -12
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: verinum.cc,v 1.12 1999/11/06 16:00:17 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: verinum.cc,v 1.16 2000/02/23 04:43:43 steve Exp $"
#endif
# include "verinum.h"
@@ -25,12 +25,12 @@
# include <cassert>
verinum::verinum()
: bits_(0), nbits_(0), has_len_(false), string_flag_(false)
: bits_(0), nbits_(0), has_len_(false), has_sign_(false), string_flag_(false)
{
}
verinum::verinum(const V*bits, unsigned nbits, bool has_len)
: has_len_(has_len), string_flag_(false)
: has_len_(has_len), has_sign_(false), string_flag_(false)
{
nbits_ = nbits;
bits_ = new V [nbits];
@@ -40,7 +40,7 @@ verinum::verinum(const V*bits, unsigned nbits, bool has_len)
}
verinum::verinum(const string&str)
: has_len_(true), string_flag_(true)
: has_len_(true), has_sign_(false), string_flag_(true)
{
nbits_ = str.length() * 8;
bits_ = new V [nbits_];
@@ -61,7 +61,7 @@ verinum::verinum(const string&str)
}
verinum::verinum(verinum::V val, unsigned n)
: has_len_(true), string_flag_(false)
: has_len_(true), has_sign_(false), string_flag_(false)
{
nbits_ = n;
bits_ = new V[nbits_];
@@ -70,7 +70,7 @@ verinum::verinum(verinum::V val, unsigned n)
}
verinum::verinum(unsigned long val, unsigned n)
: has_len_(true), string_flag_(false)
: has_len_(true), has_sign_(false), string_flag_(false)
{
nbits_ = n;
bits_ = new V[nbits_];
@@ -86,6 +86,7 @@ verinum::verinum(const verinum&that)
nbits_ = that.nbits_;
bits_ = new V[nbits_];
has_len_ = that.has_len_;
has_sign_ = that.has_sign_;
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1)
bits_[idx] = that.bits_[idx];
}
@@ -97,6 +98,7 @@ verinum::verinum(const verinum&that, unsigned nbits)
nbits_ = nbits;
bits_ = new V[nbits_];
has_len_ = true;
has_sign_ = false;
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1)
bits_[idx] = that.bits_[idx];
}
@@ -116,6 +118,7 @@ verinum& verinum::operator= (const verinum&that)
bits_[idx] = that.bits_[idx];
has_len_ = that.has_len_;
has_sign_ = that.has_sign_;
string_flag_ = that.string_flag_;
return *this;
}
@@ -164,8 +167,9 @@ signed long verinum::as_long() const
signed long val = 0;
// Extend the sign bit to fill the long.
if (bits_[nbits_-1] == V1)
// Extend the sign bit to fill the long. (But only for signed
// numbers.)
if (has_sign_ && (bits_[nbits_-1] == V1))
val = -1;
for (unsigned idx = nbits_ ; idx > 0 ; idx -= 1) {
@@ -391,7 +395,7 @@ static verinum::V add_with_carry(verinum::V l, verinum::V r, verinum::V&c)
return verinum::V0;
}
verinum not(const verinum&left)
verinum v_not(const verinum&left)
{
verinum val = left;
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
@@ -441,7 +445,7 @@ verinum operator + (const verinum&left, const verinum&right)
verinum operator - (const verinum&left, const verinum&r)
{
verinum right = not(r);
verinum right = v_not(r);
unsigned min = left.len();
if (right.len() < min) min = right.len();
@@ -467,6 +471,18 @@ verinum operator - (const verinum&left, const verinum&r)
/*
* $Log: verinum.cc,v $
* Revision 1.16 2000/02/23 04:43:43 steve
* Some compilers do not accept the not symbol.
*
* Revision 1.15 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
* Revision 1.14 2000/01/07 03:45:49 steve
* Initial support for signed constants.
*
* Revision 1.13 2000/01/06 05:57:06 steve
* Only sign-extend unsized numbers.
*
* Revision 1.12 1999/11/06 16:00:17 steve
* Put number constants into a static table.
*
+17 -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: verinum.h,v 1.8 1999/11/06 16:00:17 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: verinum.h,v 1.11 2000/02/23 04:43:43 steve Exp $"
#endif
# include <string>
@@ -56,6 +56,9 @@ class verinum {
// in some way.
bool has_len() const { return has_len_; }
bool has_sign(bool flag) { has_sign_ = flag; return has_sign_; }
bool has_sign() const { return has_sign_; }
// A number is "defined" if there are no x or z bits in its value.
bool is_defined() const;
@@ -82,6 +85,7 @@ class verinum {
V* bits_;
unsigned nbits_;
bool has_len_;
bool has_sign_;
// These are some convenience flags that help us do a better
// job of pretty-printing values.
@@ -98,8 +102,19 @@ extern verinum::V operator <= (const verinum&left, const verinum&right);
extern verinum operator + (const verinum&left, const verinum&right);
extern verinum operator - (const verinum&left, const verinum&right);
extern verinum v_not(const verinum&left);
/*
* $Log: verinum.h,v $
* Revision 1.11 2000/02/23 04:43:43 steve
* Some compilers do not accept the not symbol.
*
* Revision 1.10 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
* Revision 1.9 2000/01/07 03:45:49 steve
* Initial support for signed constants.
*
* Revision 1.8 1999/11/06 16:00:17 steve
* Put number constants into a static table.
*
+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: verireal.cc,v 1.1 1999/06/15 02:50:02 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: verireal.cc,v 1.2 2000/02/23 02:56:56 steve Exp $"
#endif
# include "verireal.h"
@@ -92,6 +92,9 @@ verireal::~verireal()
/*
* $Log: verireal.cc,v $
* Revision 1.2 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1999/06/15 02:50:02 steve
* Add lexical support for real numbers.
*
+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: verireal.h,v 1.1 1999/06/15 02:50:02 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: verireal.h,v 1.2 2000/02/23 02:56:56 steve Exp $"
#endif
class verireal {
@@ -37,6 +37,9 @@ class verireal {
/*
* $Log: verireal.h,v $
* Revision 1.2 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1999/06/15 02:50:02 steve
* Add lexical support for real numbers.
*
+1
View File
@@ -1,3 +1,4 @@
Makefile
sys_readmem_lex.c
system.vpi
dep
+7 -3
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.7 1999/11/07 20:33:30 steve Exp $"
#ident "$Id: Makefile.in,v 1.10 2000/05/04 03:37:59 steve Exp $"
#
#
SHELL = /bin/sh
@@ -52,11 +52,15 @@ all: system.vpi
$(CC) -Wall $(CPPFLAGS) -I$(srcdir) -MD -c $< -o $*.o
mv $*.d dep
O = sys_table.o sys_display.o sys_finish.o sys_vcd.o
O = sys_table.o sys_display.o sys_finish.o sys_random.o \
sys_readmem.o sys_readmem_lex.o sys_vcd.o
system.vpi: $O
$(CC) -shared -o $@ $O
sys_readmem_lex.c: sys_readmem_lex.lex
flex -t -Preadmem sys_readmem_lex.lex > sys_readmem_lex.c
clean:
rm -f *.o dep/*.d
@@ -64,7 +68,7 @@ install: all installdirs $(libdir)/ivl/system.vpi \
$(includedir)/vpi_user.h
$(libdir)/ivl/system.vpi: ./system.vpi
$(INSTALL_PROGRAM) ./system.vpi $(libdir)/ivl/system.vpi
$(INSTALL_DATA) ./system.vpi $(libdir)/ivl/system.vpi
$(includedir)/vpi_user.h: $(srcdir)/vpi_user.h
$(INSTALL_DATA) $(srcdir)/vpi_user.h $(includedir)/vpi_user.h
+210 -39
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: sys_display.c,v 1.9 1999/11/07 02:25:07 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: sys_display.c,v 1.15 2000/05/09 00:02:29 steve Exp $"
#endif
# include "vpi_user.h"
@@ -55,7 +55,7 @@ static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
* well so that I can look for arguments as I move forward through the
* string.
*/
static int format_str(char*fmt, int argc, vpiHandle*argv)
static int format_str(unsigned int mcd, char*fmt, int argc, vpiHandle*argv)
{
s_vpi_value value;
char buf[256];
@@ -73,7 +73,7 @@ static int format_str(char*fmt, int argc, vpiHandle*argv)
cnt = sizeof buf - 1;
strncpy(buf, cp, cnt);
buf[cnt] = 0;
vpi_printf("%s", buf);
vpi_mcd_printf(mcd, "%s", buf);
cp += cnt;
} else if (*cp == '%') {
@@ -90,27 +90,31 @@ static int format_str(char*fmt, int argc, vpiHandle*argv)
case 'B':
value.format = vpiBinStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
vpi_mcd_printf(mcd, "%s", value.value.str);
cp += 1;
break;
case 'd':
case 'D':
value.format = vpiDecStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
vpi_mcd_printf(mcd, "%s", value.value.str);
cp += 1;
break;
case 'h':
case 'H':
case 'x':
case 'X':
if (idx >= argc) {
vpi_printf("%s", "\nRAN OUT OF VALUES\n");
exit(1);
}
value.format = vpiHexStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
vpi_mcd_printf(mcd, "%s", value.value.str);
cp += 1;
break;
case 'm':
vpi_printf("%s", vpi_get_str(vpiFullName, argv[idx]));
vpi_mcd_printf(mcd, "%s", vpi_get_str(vpiFullName, argv[idx]));
idx += 1;
cp += 1;
break;
@@ -118,22 +122,22 @@ static int format_str(char*fmt, int argc, vpiHandle*argv)
case 'O':
value.format = vpiOctStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
vpi_mcd_printf(mcd, "%s", value.value.str);
cp += 1;
break;
case 't':
case 'T':
value.format = vpiDecStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
vpi_mcd_printf(mcd, "%s", value.value.str);
cp += 1;
break;
case '%':
vpi_printf("%%");
vpi_mcd_printf(mcd, "%%");
cp += 1;
break;
default:
vpi_printf("%c", *cp);
vpi_mcd_printf(mcd, "%c", *cp);
cp += 1;
break;
}
@@ -145,11 +149,11 @@ static int format_str(char*fmt, int argc, vpiHandle*argv)
case 0:
break;
case 'n':
vpi_printf("\n");
vpi_mcd_printf(mcd, "\n");
cp += 1;
break;
default:
vpi_printf("%c", *cp);
vpi_mcd_printf(mcd, "%c", *cp);
cp += 1;
}
}
@@ -158,7 +162,7 @@ static int format_str(char*fmt, int argc, vpiHandle*argv)
return idx;
}
static void do_display(struct strobe_cb_info*info)
static void do_display(unsigned int mcd, struct strobe_cb_info*info)
{
s_vpi_value value;
int idx;
@@ -169,38 +173,39 @@ static void do_display(struct strobe_cb_info*info)
switch (vpi_get(vpiType, item)) {
case 0:
vpi_printf(" ");
vpi_mcd_printf(mcd, " ");
break;
case vpiConstant:
if (vpi_get(vpiConstType, item) == vpiStringConst) {
value.format = vpiStringVal;
vpi_get_value(item, &value);
idx += format_str(value.value.str,
idx += format_str(mcd, value.value.str,
info->nitems-idx-1,
info->items+idx+1);
} else {
value.format = vpiBinStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
vpi_mcd_printf(mcd, "%s", value.value.str);
}
break;
case vpiNet:
case vpiReg:
case vpiMemoryWord:
value.format = vpiBinStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
vpi_mcd_printf(mcd, "%s", value.value.str);
break;
case vpiTimeVar:
value.format = vpiTimeVal;
vpi_get_value(item, &value);
vpi_printf("%u", value.value.time->low);
vpi_mcd_printf(mcd, "%u", value.value.time->low);
break;
default:
vpi_printf("?");
vpi_mcd_printf(mcd, "?");
break;
}
}
@@ -215,7 +220,7 @@ static int sys_display_calltf(char *name)
array_from_iterator(&info, argv);
do_display(&info);
do_display(1, &info);
free(info.items);
@@ -237,7 +242,7 @@ static int strobe_cb(p_cb_data cb)
{
struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data;
do_display(info);
do_display(1, info);
vpi_printf("\n");
@@ -289,7 +294,7 @@ static vpiHandle *monitor_callbacks = 0;
static int monitor_cb_2(p_cb_data cb)
{
do_display(&monitor_info);
do_display(1, &monitor_info);
vpi_printf("\n");
monitor_scheduled = 0;
return 0;
@@ -299,11 +304,14 @@ static int monitor_cb_1(p_cb_data cause)
{
struct t_cb_data cb;
struct t_vpi_time time;
/* The user_data of the callback is a pointer to the callback
handle. I use this to reschedule the callback if needed. */
vpiHandle*cbh = (vpiHandle*) (cause->user_data);
/* Reschedule this event so that it happens for the next
trigger on this variable. */
cb = *cause;
vpi_register_cb(&cb);
*cbh = vpi_register_cb(&cb);
if (monitor_scheduled) return 0;
@@ -362,6 +370,11 @@ static int sys_monitor_calltf(char*name)
switch (vpi_get(vpiType, monitor_info.items[idx])) {
case vpiNet:
case vpiReg:
/* Monitoring reg and net values involves setting
a collback for value changes. pass the storage
pointer for the callback itself as user_data so
that the callback can refresh itself. */
cb.user_data = (char*)(monitor_callbacks+idx);
cb.obj = monitor_info.items[idx];
monitor_callbacks[idx] = vpi_register_cb(&cb);
break;
@@ -372,6 +385,125 @@ static int sys_monitor_calltf(char*name)
return 0;
}
/*
* Implement the $fopen system function.
*/
static int sys_fopen_calltf(char *name)
{
s_vpi_value val, value;
vpiHandle call_handle = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, call_handle);
vpiHandle item = vpi_scan(argv);
if (item == 0) {
vpi_printf("%s: file name parameter missing.\n", name);
return 0;
}
if (vpi_get(vpiType, item) != vpiConstant) {
vpi_printf("ERROR: %s parameter must be a constant\n", name);
vpi_free_object(argv);
return 0;
}
if (vpi_get(vpiConstType, item) != vpiStringConst) {
vpi_printf("ERROR: %s parameter must be a constant\n", name);
vpi_free_object(argv);
return 0;
}
value.format = vpiStringVal;
vpi_get_value(item, &value);
val.format = vpiIntVal;
val.value.integer = vpi_mcd_open( value.value.str );
vpi_put_value(call_handle, &val, 0, vpiNoDelay);
return 0;
}
static int sys_fopen_sizetf(char*x)
{
return 32;
}
/* Implement $fdisplay and $fwrite.
* Perhaps this could be merged into sys_display_calltf.
*/
static int sys_fdisplay_calltf(char *name)
{
struct strobe_cb_info info;
unsigned int mcd;
int type;
s_vpi_value value;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item = vpi_scan(argv);
if (item == 0) {
vpi_printf("%s: mcd parameter missing.\n", name);
return 0;
}
type = vpi_get(vpiType, item);
if (type != vpiReg && type != vpiReadVal) {
vpi_printf("ERROR: %s mcd parameter must be of integral, got vpiType=%d\n",
name, type);
vpi_free_object(argv);
return 0;
}
value.format = vpiIntVal;
vpi_get_value(item, &value);
mcd = value.value.integer;
array_from_iterator(&info, argv);
do_display(mcd, &info);
free(info.items);
if (strcmp(name,"$fdisplay") == 0)
vpi_mcd_printf(mcd, "\n");
return 0;
}
/*
* Implement $fclose system function
*/
static int sys_fclose_calltf(char *name)
{
unsigned int mcd;
int type;
s_vpi_value value;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item = vpi_scan(argv);
if (item == 0) {
vpi_printf("%s: mcd parameter missing.\n", name);
return 0;
}
type = vpi_get(vpiType, item);
if (type != vpiReg && type != vpiReadVal) {
vpi_printf("ERROR: %s mcd parameter must be of integral type, got vpiType=%d\n",
name, type);
vpi_free_object(argv);
return 0;
}
value.format = vpiIntVal;
vpi_get_value(item, &value);
mcd = value.value.integer;
vpi_mcd_close(mcd);
return 0;
}
void sys_display_register()
{
s_vpi_systf_data tf_data;
@@ -407,11 +539,64 @@ void sys_display_register()
tf_data.sizetf = 0;
tf_data.user_data = "$monitor";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysFunc;
tf_data.tfname = "$fopen";
tf_data.calltf = sys_fopen_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = sys_fopen_sizetf;
tf_data.user_data = "$fopen";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$fclose";
tf_data.calltf = sys_fclose_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$fclose";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$fdisplay";
tf_data.calltf = sys_fdisplay_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$fdisplay";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$fwrite";
tf_data.calltf = sys_fdisplay_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$fwrite";
vpi_register_systf(&tf_data);
vpi_mcd_init();
}
/*
* $Log: sys_display.c,v $
* Revision 1.15 2000/05/09 00:02:29 steve
* Remove test print.
*
* Revision 1.14 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.13 2000/04/21 02:00:35 steve
* exit if hex value is missing.
*
* Revision 1.12 2000/03/31 07:08:39 steve
* allow cancelling of cbValueChange events.
*
* Revision 1.11 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
* Revision 1.10 2000/02/13 19:18:27 steve
* Accept memory words as parameter to $display.
*
* Revision 1.9 1999/11/07 02:25:07 steve
* Add the $monitor implementation.
*
@@ -429,19 +614,5 @@ void sys_display_register()
* persistent, rewrite the simulation scheduler
* in C (to interface with VPI) and add VPI support
* for callbacks.
*
* Revision 1.4 1999/10/10 14:50:50 steve
* Add Octal dump format.
*
* Revision 1.3 1999/10/08 17:47:49 steve
* Add the %t formatting escape.
*
* Revision 1.2 1999/09/29 01:41:18 steve
* Support the $write system task, and have the
* vpi_scan function free iterators as needed.
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
+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: sys_finish.c,v 1.3 1999/08/28 02:10:44 steve Exp $"
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: sys_finish.c,v 1.4 2000/02/23 02:56:56 steve Exp $"
#endif
# include "vpi_user.h"
@@ -42,6 +42,9 @@ void sys_finish_register()
/*
* $Log: sys_finish.c,v $
* Revision 1.4 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/08/28 02:10:44 steve
* Call the right vpiFinish code.
*

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