1.总线功能模型作用:
总线功能模型可以用来产生激励,也可以监视设计的响应。通常,一个总线功能模型实现这两个操作。
2.CPU transactions
task write_cycleinput bit [23:0] wadd, input bit [31:0] wdat); do @ cb) while cb.phi != 2); cb.addr <= wadd; cb.ads <= 1’b0; cb.rw <= 1’b1; cb.data <= wdat; repeat 2) @ cb); cb.ads <= 1’b1; do @cb) while cb.phi != 2 || cb.ready != ’0’); cb.data <= ’z;endtask: write_cycle
2.1 总线功能程序能包含返回值
All of the abstracted transactions shown so far were unidirectional.Data always flowed from the testbench through the bus-functional task where the data was applied to the design and outputs were checked for correctness. What if determining the correctness of the output required visibility over multiple operations? What if only the relevant output values for this testcase were known and the others were to be ignored? Bus-functional tasks can just as easily sample output and return it instead of comparing the output against supplied expected responses. The sampled value can then be processed by the testbench where the value can be dealt with according to the needs of the testcase. For example, Sample 5-50 shows the read operation of the 386SX interface. Notice how the value read is not compared against an expected value. The value read is instead returned through an output argument.
task read_cycleinput bit [23:0] radd, output bit [31:0] rdat); do @cb) while phi != 2); cb.addr <= radd; cb.ads <= 1’b0; cb.rw <= 1’b0; repeat 2) @ cb); cb.ads <= 1’b1; do @cb) while cb.phi != 2 || cb.ready != 1’b0); rdat = cb.data;endtask: read_cycle
2.2 从总线功能任务到总线功能模型
If two or more threads must read from or write to) the design, the operations must be coordinated. To pipeline concurrent operations,it is necessary to put a semaphore around the entire bus-functional model. Much like a semaphore was used to detect concurrent invocation of a non-re-entrant task, it will be used to detect concurrent
invocation of transactions in a non-re-entrant bus-functional model.Sample 5-53 shows how a bus-functional model can be protected against concurrent transactions using a semaphore. It is up to you to decide, should the semaphore detect a concurrent transaction,whether to wait for the bus-functional model to become available or
to terminate with an error.
class i386sx;local semaphore sem; virtual i386sx_if sigs; … virtual task readinput bit [23:0] radd, output bit [31:0] rdat); if !this.sem.try_get1)) …; this.sigs.cb.addr <= radd; … this.sem.put1); endtask: read virtual task writeinput bit [23:0] wdd, input bit [31:0] wdat); if !this.sem.try_get1)) …; this.sigs.cb.addr <= wadd; … this.sem.put1); endtask: writeendclass: i386sx
3.Collect all signals in an interface.
Bus-functional models encapsulated in classes can access physical signals in one of two ways: through hierarchic- al —white-box—references or through a virtual interface. Using hierarchical references would make the bus-functi- onal model class specific to a particular set of interface signals. It would not be possible to reuse the model in a diff- erent testbench or instantiate it more than once in the same testbench without copying it and modifying the referenc- es. The only mechanism that will make bus-functional models reusable within or across testbenches is the virtual interface. This implies that all physical-level signals required by the bus-functional model be encapsulated in an interface .
Specify virtual interface to connect to via the constructor.
All class-encapsulated bus-functional model examples so far had avirtual interface data member that was used to access the physical interface of the bus-functional model. This data member must be set somehow. Module pins are connected when the module is instantiated. This way, the same module may be used more than
once but connected to different signals. Similarly, a virtual interface in a bus-functional model is connected when the bus-functional model is instantiated. Because the bus-functional model is encapsulated in a class, it is instantiated when its constructor is invoked.Therefore, the virtual interface connection is specified as a constructor argument, as shown in Sample 5-60. The virtual interface is connected when a new instance of the bus-functional model is created by calling the constructor and specifying an interface instance it is bound to via a cross-module reference, as shown in Sample 5-61.
//5-60Virtual interface as constructor argument.class mii_mac_bfm; virtual mii_if sigs; … function newvirtual mii_if sigs); this.sigs = sigs; endfunction: newendclass: mii_mac_bfm//Sample 5-61.Binding a virtual interface in a class instance.module tb_top;mii_if if0);…endmoduleprogram test;mii_mac_bfm mac = newtb_top.if0);…endprogram: test
4. Configurable Bus-Functional Models
Configuration parameters should be implemented as properties in a configurationclass. An instance of the configuration class would be passed to the bus-functional model via its constructor, alongside the interface binding. Using a separate configuration class will make it easier to create random configurations and to ensure that
multiple instances of the bus-functional model have an identical configuration. The current configuration should be kept in a local class property to prevent it from being modified without the busfunctional model knowing about it or at the wrong time. If it is possible for a bus-functional model to be reconfigured during a simulation—such as the RS-232 model—a reconfigure method should be provided. That method can check that the configuration is valid,that it is an appropriate time for the bus functional model to be reconfigured—e.g. it is idle—and to perform the necessary operations to notify the bus-functional model tasks of the new configuration. What important safety measure is missing from Sample 5-62?1 1.The entire bus-functional model should be protected using a semaphore to prevent concurrent access to the interface signals. )
class rs232_cfg; int unsigned baud_rate; enum {NONE, ODD, EVEN, MARK, SPACE} parity; bit data8; bit stop2;endclass: rs232_cfgclass rs232; virtual rs232_if sigs; local rs232_cfg cfg; function newvirtual rs232_if sigs, rs232_cfg cfg); this.sigs = sigs; this.cfg = cfg; endfunction: new function void reconfigurers232_cfg cfg); … this.cfg = cfg; endfunction: reconfigure task sendbit [7:0] data); time duration = 1s / this.cfg.baud_rate; int i; this.sigs.tx <= 1’b0; #duration); i = this.sigs.data8) ? 8 : 7; while i– > 0) begin this.sigs.tx <= data[i]; #duration); end … this.sigs.tx <= 1’b1; #duration * this.sigs.stop2+1)); endtask: send …endclass: rs232