Donald E. Thomas - The Verilog Hardware Description Language, Fifth Edition (798541), страница 51
Текст из файла (страница 51)
Wethen convert these strength values into three-valued logic and store them in in0 andin1. Next, out is set as per the three-valued NAND of the two values. Finally, if therewas a change in out, then we schedule the output to change.Switch Level Modeling267Consider evaluating a wire which is driven by two inputs as shown inExample 10.6. This example parallels the above evalNand task, except that within thetask, we deal with the strengths. Specifically, function getMast, shown in// Evaluate a wire with full strength valuestask evalWire;(inputfanout);reg[7:0]mask;beginstoreInVal(fanout);in0 = in0Val[evalElement];in1 = in1Val[evalElement];mask = getMask(in0[15:8]) &getMask(in0[7:0]) &getMask(in1[15:8]) & getMask(in1[7:0]);out = fillBits((in0 | in1) &{mask, mask});if (out != outVal[evalElement])schedule(out);if(DebugFlags[2])"in0 = %b_%b\ninl = %b_%b\nmask= %b %b\nout = %b_%b",in0[15:8],in0[7:0],in1[15:8],in1[7:0])mask,mask, out[15:8],out[7:0]);endendtaskExample 10.6 The evalWire TaskExample 10.7, is called to develop a mask for the final result and function fillBits,shown in Example 10.8, actually constructs the strength bytes for the result.Let’s consider the following example presented in the previous section.
In this case,we have ambiguous strengths on both outputs driving the wire.0000_0000:0110_0000 =10110_0000:0000_0000 =00111_1110:0111_1110 =xoutput 1 — in0output 2 —in1result on netFollowing along in task evalWire, we see that in0 and in1 are each loaded with thetwo strength bytes for the inputs to the wires. A mask is generated by calling getMaskfour times, each with a different strength byte. The results are AND-ed together andput in mask. The results, in order, are:The Verilog Hardware Description Language268// Given either a 0-strength or 1-strength half of a strength value// return a masking pattern for use in a wire evaluation.function [7:0] getMask(input [7:0] halfVal); //half a full strength valuecasez (halfVal)8'b???????1: getMask = 8'b11111111;8'b??????10: getMask = 8'b11111110;8'b?????100: getMask = 8'b11111100;8'b????1000: getMask = 8'b11111000;8'b???10000: getMask = 8'b11110000;8'b??100000: getMask = 8'b11100000;8'b?1000000: getMask = 8'b11000000;8'b10000000: getMask = 8'b10000000;8'b00000000: getMask = 8'b11111111;endcaseendfunctionExample 10.7 The getMask Function1111_11111110_00001110_00001111_11111110_0000maskTwo copies of mask concatenated together are then ANDed with the result of ORing the inputs in0 and in1 together.0110_0000:0110_0000 OR of in0 and in11110 0000:1110 0000 mask, mask0110_0000:0110_0000result passed to fillBitsThis result is passed to fillBits which will determine that this value is x and will thenexecute the two casez statements.
In the first casez, fillBits will be set to0111_1111:0110_0000, and the second casez will OR in the value0000_0000:0111_1111. fillBits will have the final value:0111_1111:0111_1111.This result, if different from the previous value on the wire, is scheduled.References: casez 3.4.4Switch Level Modeling// Given an incomplete strength value, fill the missing strength bits.// The filling is only necessary when the value is unknown.function [15:0] fillBits;(input [15:0] val);beginfillBits = val;if (log3(val) == `ValX)begincasez (val)16'b1???????_????????: fillBits = fillBits | 16'b11111111_00000001;16'b01??????_????????: fillBits = fillBits | 16'b01111111_00000001;16'b001?????_????????: fillBits = fillBits | 16'b00111111_00000001;16'b0001????_????????: fillBits = fillBits | 16'b00011111_00000001;16'b00001???_????????: fillBits = fillBits | 16'b00001111_00000001;16'b000001??_????????: fillBits = fillBits | 16'b00000111_00000001;16'b0000001?_????????: fillBits = fillBits | 16'b00000011_00000001;endcasecasez (val)16'b????????_1???????: fillBits = fillBits | 16'b00000001_11111111;16'b????????_01??????: fillBits = fillBits | 16'b00000001_01111111;16'b????????_001?????: fillBits = fillBits | 16'b00000001_00111111;16'b????????_0001????: fillBits = fillBits | 16'b00000001_00011111;16'b????????_00001???: fillBits = fillBits | 16'b00000001_00001111;16'b????????_000001??: fillBits = fillBits | 16'b00000001_00000111;16'b????????_0000001?: fillBits = fillBits | 16'b00000001_00000011;endcaseendendendfunctionExample 10.8 The fillBits Function269270The Verilog Hardware Description Language10.4 The miniSim Example10.4.1 OverviewMiniSim is a description of a very simplifiedgate level simulator.
Only three primitiveshave been included: a NAND gate, a D positive edge-triggered flip flop, and a wire thathandles the full strength algebra that is usedin Verilog. All primitive timing is unit delay,and a record is kept of the stimulus patternnumber and simulation time within eachpattern. Each primitive is limited to twoinputs and one output that has a maximumfanout of two.Two circuits are illustrated.
The firstto be loaded and simulated is a flip floptoggle circuit (Figure 10.5). The secondcircuit (Figure 10.6) has two open-collector gates wired together with a pullup, and illustrates some cases whencombining signal strengths.Switch Level Modeling10.4.2 The miniSim Sourcemodule miniSim;// element types being modeled`define Nand 0`define DEdgeFF 1`define Wire 2// literal values with strength:// format is 8 0-strength bits in decreasing strength order// followed by 8 1-strength bits in decreasing strength order`define Strong0 16'b01000000_00000000`define Strong1 16'b00000000_01000000`define StrongX 16'b01111111_01111111`define Pull0 16'b00100000_00000000`define Pull1 16'b00000000_00100000`define Highz0 16'b00000001_00000000`define Highz1 16'b00000000_00000001// three-valued logic set`define Val0 3'd0`define Val1 3'd1`define ValX 3'd2parameter//set DebugFlags to 1 for messageDebugFlags='b11000,//// loading// event changes// wire calc// evaluation// schedulingIndexSize = 16, //maximum size for index pointersMaxElements = 50, //maximum number of elementsTypeSize = 12; //maximum number of typesreg [IndexSize-1:0]eventElement,//output value change elementevalElement,//element on fanoutfo0Index[1:MaxElements], //first fanout index of eventElementfo1Index[1:MaxElements], //second fanout index of eventElementcurrentList,//current time scheduled event list271The Verilog Hardware Description Language272nextList,//unit delay scheduled event listschedList[1:MaxElements]; //scheduled event list indexreg [TypeSize-1:0]eleType[1:MaxElements]; //element typeregfo0TermNum[1:MaxElements], //first fanout input terminal numberfo1TermNum[1:MaxElements], //second fanout input terminal numberschedPresent[1:MaxElements]; //element is in scheduled event list flagsreg [15:0]eleStrength[1:MaxElements], //element strength indicationoutVal[1:MaxElements], //element output valuein0Val[1:MaxElements], //element first input valuein1Val[1:MaxElements], //element second input valuein0, in1, out, oldIn0; //temporary value storageinteger pattern, simTime; //time keepersinitialbegin// initialize variablespattern = 0;currentList = 0;nextList = 0;display("Loading toggle circuit");loadElement(1, `DEdgeFF, 0, `Strong1,0,0,4,0,0,0);loadElement(2, `DEdgeFF, 0, `Strong1,0,0,3,0,0,0);loadElement(3, `Nand, (`Strong0|`Strong1),`Strong0; `Strong1,`Strong1, 4,0,1,0);loadElement(4, `DEdgeFF, (`Strong0|`Strong1),`Strong1,`Strong1,`Strong0, 3,0,1,0);// apply stimulus and simulatedisplay("Applying 2 clocks to input element 1");applyClock(2, 1);display("Changing element 2 to value 0 and applying 1 clock");setupStim(2, `Strong0);applyClock(1, 1);display("\nLoading open-collector and pullup circuit");loadElement(l, `DEdgeFF, 0, `Strong1,0,0,3,0,0,0);loadElement(2, `DEdgeFF, 0, `Strong0,0,0, 4,0,0,0);loadElement(3, `Nand, (`Strong0|`Highz1),`Strong0, `Strong1, `Strong1, 5,0,0,0);loadElement(4, `Nand, (`Strong0|`Highz1),Switch Level Modeling`Highz1,`Strong0,`Strong1, 5,0,1,0);loadElement(5, `Wire, 0,`Strong0,`Strong0,`Highz1, 7,0,1,0);loadElement(6, `DEdgeFF, 0, `Pull1,0,0,7,0,0,0);loadElement(7, `Wire, 0,`Strong0,`Pull1,`Strong0, 0,0,0,0);// apply stimulus and simulatedisplay("Changing element 1 to value 0");pattern = pattern + 1;setupStim(1, `Strong0);executeEvents;display("Changing element 2 to value 1");pattern = pattern + 1;setupStim(2, `Strong1);executeEvents;display("Changing element 2 to value X");pattern = pattern + 1;setupStim(2, `StrongX);executeEvents;end// Initialize data structure for a given element.task loadElement;input [IndexSize-1:0] loadAtIndex; //element index being loadedinput [TypeSize-1:0] type;//type of elementinput [15:0] strengthCoercion; //strength specification of elementinput [15:0] oVal, i0Val, i1Val; //output and input valuesinput [IndexSize-1:0] fo0, fo1; //fanout element indexesinput fo0Term, fo1Term;//fanout element input terminal indicatorsbeginif(DebugFlags[4])display("Loading element %0d, type %0s, with initial value %s(%b_%b)",loadAtIndex, typeString(type),valString(oVal), oVal[15:8], oVal[7:0]);eleType[loadAtIndex] = type;eleStrength[loadAtIndex] = strengthCoercion;outVal[loadAtIndex] = oVal;in0Val[loadAtIndex] = i0Val;in1Val[loadAtIndex] = i1Val;fo0Index[loadAtIndex] = fo0;fo1Index[loadAtIndex] = fo1;fo0TermNum[loadAtIndex] = fo0Term;fo1TermNum[loadAtIndex] = fo1Term;273The Verilog Hardware Description Language274schedPresent[loadAtIndex] = 0;endendtask// Given a type number, return a type stringfunction [32*8:1] typeString;input [TypeSize-1:0] type;case (type)`Nand: typeString = "Nand";`DEdgeFF: typeString = "DEdgeFF";`Wire: typeString = "Wire";default: typeString = "*** Unknown element type";endcaseendfunction// Setup a value change on an element,task setupStim;input [IndexSize-1:0] vcElement; //element indexinput [15:0] newVal;//new element valuebeginif (! schedPresent[vcElement])beginschedList[vcElement] = currentList;currentList = vcElement;schedPresent[vcElement] = 1;endoutVal[vcElement] = newVal;endendtask// Setup and simulate a given number of clock pulses to a given element.task applyClock;input [7:0] nClocks;input [IndexSize-1:0] vcElement;repeat(nClocks)beginpattern = pattern + 1;setupStim(vcElement, `Strong0);executeEvents;pattern = pattern + 1;setupStim(vcElement, `Strong1);executeEvents;endendtaskSwitch Level Modeling// Execute all events in the current event list.// Then move the events in the next event list to the current event// list and loop back to execute these events.