// example 4 <' extend sys { // ‘sys’ is a unit that is automatically generated by Specman. During the // generation of ‘sys’ all its fields, including other unit instances, are // generated. These unit instances generate other unit instances until // all the unit instances in your hierarchy are generated. In this case, for // example, the generation of ‘sys’ leads to the generation of “chip_env”, // which is an instance of “chip_env_u”. In its turn, the generation of // “chip_env_u”, causes the generation of “packet_generator”, which is // an instance of “packet_generator_u”, and of “packet_driver”, which is // an instance of “packet_driver_u”. Other units might be instantiated by // these units, or directly by “chip_env”. // Verisity recommends that you do not make ‘sys’ the root of your // hierarchy.In other words, sys should instantiate only one unit, in this case // “chip_env_u”, and this unit should start all the other branches of your // hierarchy. Following this suggestion is supposed to make integration of // several environments easier. chip_env : chip_env_u is instance; }; unit chip_env_u { //... event clk_sys is rise('clk_sys')@ sim; // When the signal “clk_sys” in the design goes from '0' to '1' this event will be emitted // (see more in the "temporal expressions" section below). The events for the main clocks // in your design should be located at the root of the hierarchy since they are used by almost all // units and therefore must be easily accessible from anywhere. //... packet_generator : packet_generator_u is instance; packet_driver : packet_driver_u is instance; // It is recommended to separate between the “generator”and the “driver”. // The generator is responsible for the generation of ‘high level’ data // structures, such as packets. The driver translates the ‘high level’ data // structures into bits and bytes and implements the physical level // protocols. This divide, which might seem a bit forced and unnecessary // sometimes, should be strictly kept for better code reuse (see more below). //... }; unit packet_generator_u { // unlike a struct, which may be generated on the fly using the ‘gen’ command (see below in this example), // a unit can not be generated on the fly. It is generated once when the simulation starts and // destroyed when the simulation ends. However, a unit is not just a degraded struct since there are // some statements that can be placed only inside a unit. p_env : chip_env_u; // This means that “p_env” is a pointer to a “chip_env_u” unit. // Note that “p_env” is not an actual “chip_env_u” unit. To define a // real “chip_env_u” unit, you must add ‘is instance’ at the end as // shown above in the extension to ‘sys’ keep p_env == get_enclosing_unit (chip_env_u); // The unit “packet_generator_u” is instantiated by “chip_env_u”. // Since the hierarchy of units is fixed (units are static objects), it can // always get a pointer to its father by calling the global E method // “get_enclosing_unit()”. In this case when the pointer “p_env” is // generated, it is assigned with a reference to the father. p_driver : packet_driver_u; // This is another pointer, this time to the object “packet_driver” keep p_driver == p_env.packet_driver; // “p_env” is generated before “p_driver” since it is located higher in the file. // Since “p_env” already references the object “chip_env” we can use it in // order to initialize the pointer to the driver. //... !last_packet_time : time; // The exclamation mark means that this field should not be assigned a random value when the unit is // generated. The default value is zero. event rdy_to_send is true('ready_for_pkt' === '1') @ p_env.clk_sys; // When the signal “ready_for_pkt” in the design will be '1' at the system clock edge, this // event will be emitted (see more in the "temporal expressions" section below). The event “clk_sys” // is a part of “chip_env_u”. Therefore it is accessed through the pointer “p_env”. packet_gen()@ rdy_to_send is{ // A method defined in this way is called TCM or Time Consuming Method. Unlike regular // method a TCM is not executed in zero simulation time: It can wait on events from the DUT or from // E. The event “rdy_to_send” is called the sampling event. When this event occurs, the TCM wakes up // and proceeds along its line of execution until it encounters a time consuming action such as ‘wait’ // or ‘sync’. while(TRUE) { // Written in this form the while will run until the simulation ends. var packet : packet_s; // This is only a declaration, i.e., it is only used by the compiler. if sys.time – last_packet_time >= 10 { // sys is an object that exists in every Specman simulation (more about it later). sys.time holds // the simulator time. Note that this line will be evaluated only when “rdy_to_send” occurs. gen packet; // Only here the packet is really generated and the different fields are given a random value. packet_driver.drive_packet(packet); // This line calls the method “drive_packet()” of “packet_driver” which is an instance of // “packet_driver_u”. }else{ wait cycle; // wait until the next time my_event happens before you check the condition again. }; }; }; run() is also { // The method “run()” is a predefined method of every struct or unit. // This means that even though not defined in the code above, it is already defined automatically by E. // The “run()” method of all the units in the design is automatically executed after the simulation // starts running. In this case it starts the TCM “packet_generator” that will continue to // generate packets until the simulation ends. //... start packet_gen(); // A TCM is a separate execution thread that has to be launched. The TCM “packet_gen()” will now // work in parallel with other processes in the system until the simulation ends. }; }; unit packet_driver_u { //... drive_packet()@ p_env.clk_sys is { //... }; }; '>