分享

国外经典Verilog代码

 guitarhua 2014-10-07

/*                                                            *

 * Examples from "The Verilog Hardware Description Language", *

 * by D.E. Thomas and P.R. Moorby                             *

 *                                                            */

 

 

 

//Example 1.2.  NAND Latch To Be Simulated.

module ffNand;

    wire q, qBar;

    reg  preset, clear;

 

    nand #1

        g1 (q, qBar, preset),

        g2 (qBar, q, clear);

 

    initial

        begin

            // two slashes introduce a single line comment

            $monitor ($time,,

                "Preset = %b clear = %b q = %b qBar = %b",

                preset, clear, q, qBar);

            //waveform for simulating the nand flip flop

            #10 preset = 0; clear = 1;

            #10 preset = 1;

            #10 clear = 0;

            #10 clear = 1;

            #10 $finish;

        end

endmodule

 

 

 

//Example 1.4.  A 16-Bit Counter.

module m16 (value, clock, fifteen, altFifteen);

    output [3:0] value;

    output       fifteen,

                 altFifteen;

    input        clock;

 

    dEdgeFF    a (value[0], clock, ~value[0]),

               b (value[1], clock, value[1] ^  value[0]),

               c (value[2], clock, value[2] ^ &value[1:0]),

               d (value[3], clock, value[3] ^ &value[2:0]);

 

    assign fifteen = value[0] & value[1] & value[2] & value[3];

    assign altFifteen = &value;

endmodule

 

 

 

//Example 1.5.  A D-Type Edge-Triggered Flip Flop.

module dEdgeFF (q, clock, data);

    output q;

    reg    q;

    input  clock, data;

 

    initial

        q = 0;

 

    always

        @(negedge clock) #10 q = data;

 

endmodule

 

 

 

//Example 1.6.  A Clock For the Counter.

module m555 (clock);

    output clock;

    reg    clock;

 

    initial

        #5 clock = 1;

 

    always

        #50 clock = ~ clock;

endmodule

 

 

 

//Example 1.7.  The Top-Level Module of the Counter.

module board;

    wire [3:0] count;

    wire       clock,

               f,

               af;

 

    m16  counter (count, clock, f, af);

    m555 clockGen (clock);

 

    always @(posedge clock)

        $display ($time,,,"count=%d, f=%d, af=%d", count, f, af);

endmodule

 

 

 

//Example 1.8. The Counter Module Described With Behavioral Statements.

module m16Behav (value, clock, fifteen, altFifteen);

    output [3:0] value;

    reg    [3:0] value;

    output       fifteen,

                 altFifteen;

    reg          fifteen,

                 altFifteen;

    input        clock;

 

    initial

        value = 0;

 

    always

        begin

            @(negedge clock)  #10 value = value + 1;

            if (value == 15)

                begin

                    altFifteen = 1;

                    fifteen = 1;

                end

            else

                begin

                    altFifteen = 0;

                    fifteen = 0;

                end

        end

endmodule

 

 

 

//Example 1.9.  Top Level of the Fibonacci Number Generator.

module top();

    wire        flag, numProduced, numConsumed;

    wire [15:0] number, numberOut;

 

    nandLatch    ready (flag, , numConsumed, numProduced);

    numberGen    ng (number, numProduced, flag);

    fibNumberGen fng (number, flag, numConsumed, numberOut);

endmodule

 

 

 

//Example 1.10.  A NAND Latch.

module nandLatch (q, qBar, set, reset);

    output q, qBar;

    input  set, reset;

 

    nand #2

        (q, qBar, set),

        (qBar, q, reset);

endmodule

 

 

 

//Example 1.11.  The Seed-Number Generator.

module numberGen (number, numProduced, flag);

    output [15:0] number;

    output        numProduced;

    input         flag;

 

    reg        numProduced;

    reg [15:0] number;

 

    initial

        begin

            number = 3;

            numProduced = 1;

        end

 

    always

        begin

            wait (flag == 1)

                #100 number = number + 1;

            numProduced = 0;

            #10 numProduced = 1;

        end

endmodule

 

 

 

//Example 1.12.  The Fibonacci Number Generator Module.

module fibNumberGen (startingValue, flag, numConsumed, fibNum);

    input [15:0]  startingValue;

    input         flag;

    output        numConsumed;

    output [15:0] fibNum;

 

    reg           numConsumed;

    reg [15:0]    myValue;

    reg [15:0]    fibNum;

 

    initial

        begin

            numConsumed = 0;

            #10 numConsumed = 1;

            $monitor ($time,,

                "fibNum=%d, startingValue=%d", 

                    fibNum, startingValue);

        end

 

    always

        begin

            wait (flag == 0)

                myValue = startingValue;

            numConsumed = 0;

            #10 numConsumed = 1;    //signal ready for input

 

            for (fibNum = 0; myValue != 0; myValue = myValue - 1)

                fibNum = fibNum + myValue;

            $display ("%d, fibNum=%d", $time, fibNum);

        end

endmodule

 

 

 

//Example 2.1.  A Divide Module.

module divide (ddInput, dvInput, quotient, go, done);

    parameter 

        DvLen =    15,

        DdLen =    31,

        QLen =     15,

        HiDdMin    = 16;

 

    input [DdLen:0] ddInput;

    input [DvLen:0] dvInput;

    output [QLen:0] quotient;

    input           go;

    output          done;

 

    reg [DdLen:0] dividend;

    reg           done;

    reg [QLen:0]  quotient;

    reg           negDivisor, 

                  negDividend;

    reg [DvLen:0] divisor;

 

    always

        begin

            done = 0;

            wait (go);

            divisor = dvInput;

            dividend = ddInput;

            quotient = 0;

            if (divisor)

                begin

                    negDivisor = divisor[DvLen];

                    if (negDivisor)

                        divisor = - divisor;

                    negDividend = dividend[DdLen];

                    if (negDividend)

                        dividend = - dividend;

                    repeat (DvLen + 1)

                        begin

                            quotient = quotient << 1;

                            dividend = dividend << 1;

                            dividend[DdLen:HiDdMin] = 

                                dividend[DdLen:HiDdMin]  - divisor;

                            if (! dividend [DdLen])

                                quotient = quotient + 1;

                            else    

                                dividend[DdLen:HiDdMin] = 

                                    dividend[DdLen:HiDdMin]  + divisor;

                        end

                    if (negDivisor != negDividend)

                        quotient = - quotient;

                end

            done = 1;

            wait (~go);

        end

endmodule

 

 

 

//Example 2.5.  The Mark-1 Processor With If-Else-If.

module mark1;

    reg [31:0] m [0:8191];    // 8192 x 32 bit memory

    reg [12:0] pc;            // 13 bit program counter

    reg [31:0] acc;           // 32 bit accumulator

    reg [15:0] ir;            // 16 bit instruction register

 

    always 

        begin

            ir = m [pc];                //fetch an instruction

            if (ir[15:13] == 3'b000)    //begin decoding

                pc = m [ir [12:0]];     //and executing

            else if (ir[15:13] == 3'b001)

                pc = pc + m [ir [12:0]];

            else if (ir[15:13] == 3'b010)

                acc = -m [ir [12:0]];

            else if (ir[15:13] == 3'b011)

                m [ir [12:0]] = acc;

            else if ((ir[15:13] == 3'b101) || (ir[15:13] == 3'b100))

                acc = acc - m [ir [12:0]];

            else if (ir[15:13] == 3'b110)

                if (acc < 0) pc = pc + 1;

            #1 pc = pc + 1; //increment program counter and time

        end                 

endmodule

 

 

 

//Example 2.6.  The Mark-1 With a Case Statement.

module mark1Case;

    reg [31:0] m [0:8191];    // 8192 x 32 bit memory 

    reg [12:0] pc;            // 13 bit program counter 

    reg [31:0] acc;           // 32 bit accumulator

    reg [15:0] ir;            // 16 bit instruction register

 

    always

        begin

            ir = m [pc];

            case (ir [15:13])

                3'b000 : pc = m [ir [12:0]];

                3'b001 : pc = pc + m [ir [12:0]];

                3'b010 : acc = -m [ir [12:0]];

                3'b011 : m [ir [12:0]] = acc;

                3'b100,

                3'b101 : acc = acc - m [ir [12:0]];

                3'b110 : if (acc < 0) pc = pc + 1;

            endcase

            pc = pc + 1;

        end

endmodule

 

 

 

//Example 2.8.  The Mark-1 With a Multiply Instruction.

module mark1Mult;

    reg [31:0] m [0:8191];    // 8192 x 32 bit memory 

    reg [12:0] pc;            // 13 bit program counter 

    reg [31:0] acc;           // 32 bit accumulator

    reg [15:0] ir;            // 16 bit instruction register

 

    always 

        begin

            ir = m [pc];

            case (ir [15:13])

                3'b000 : pc = m [ir [12:0]];

                3'b001 : pc = pc + m [ir [12:0]];

                3'b010 : acc = -m [ir [12:0]];

                3'b011 : m [ir [12:0]] = acc;

                3'b100,    

                3'b101 : acc = acc - m [ir [12:0]];

                3'b110 : if (acc < 0) pc = pc + 1;

                3'b111 : acc = acc * m [ir [12:0]]; //multiply

            endcase

            #1 pc = pc + 1;

        end

endmodule

 

 

 

//Example 2.9.  A Task Specification.

module mark1Task;

    reg [31:0] m [0:8191];    // 8192 x 32 bit memory 

    reg [12:0] pc;            // 13 bit program counter 

    reg [31:0] acc;           // 32 bit accumulator

    reg [15:0] ir;            // 16 bit instruction register

 

    always 

        begin

            ir = m [pc];

            case (ir [15:13])

                3'b000 : pc = m [ir [12:0]];

                3'b001 : pc = pc + m [ir [12:0]];

                3'b010 : acc = -m [ir [12:0]];

                3'b011 : m [ir [12:0]] = acc;

                3'b100,    

                3'b101 : acc = acc - m [ir [12:0]];

                3'b110 : if (acc < 0) pc = pc + 1;

                3'b111 : multiply(acc, m [ir [12:0]]);

            endcase

            pc = pc + 1;

        end

 

    task multiply;

        inout [31:0] a;

        input [31:0] b;

 

        reg [15:0] mcnd, mpy; //multiplicand and multiplier

        reg [31:0] prod;      //product

 

        begin

            mpy  = b[15:0];

            mcnd = a[15:0];

            prod = 0;

            repeat (16)

                begin

                    if (mpy[0])

                        prod = prod + {mcnd, 16'h0000};

                    prod = prod >> 1;

                    mpy = mpy >> 1;

                end

            a = prod;

        end

    endtask

endmodule

 

 

 

//Example 2.10.  A Function Specification.

module mark1Fun;

    reg [31:0] m [0:8191];    // 8192 x 32 bit memory 

    reg [12:0] pc;            // 13 bit program counter 

    reg [31:0] acc;           // 32 bit accumulator

    reg [15:0] ir;            // 16 bit instruction register

 

    always 

        begin

            ir = m [pc];

            case (ir [15:13])

                3'b000 : pc = m [ir [12:0]];

                3'b001 : pc = pc + m [ir [12:0]];

                3'b010 : acc = -m [ir [12:0]];

                3'b011 : m [ir [12:0]] = acc;

                3'b100,    

                3'b101 : acc = acc - m [ir [12:0]];

                3'b110 : if (acc < 0) pc = pc + 1;

                3'b111 : acc = multiply(acc, m [ir [12:0]]);

            endcase

            pc = pc + 1;

        end

 

function [31:0] multiply;

    input [31:0] a;

    input [31:0] b;

 

    reg [15:0] mcnd,mpy;

 

    begin

        mpy  = b[15:0];

        mcnd = a[15:0];

        multiply = 0;

        repeat (16)

            begin

                if (mpy[0])

                    multiply = multiply + {mcnd, 16'h0000};

                multiply = multiply >> 1;

                mpy = mpy >> 1;

            end

    end

endfunction

endmodule

 

 

 

 

//Example 2.11.  The Multiply as a Separate Module.

module mark1Mod;

    reg [31:0] m [0:8191];    // 8192 x 32 bit memory 

    reg [12:0] pc;            // 13 bit program counter 

    reg [31:0] acc;           // 32 bit accumulator

    reg [15:0] ir;            // 16 bit instruction register

 

    reg  [31:0] mcnd;

    reg         go;

    wire [31:0] prod;

    wire        done;

 

    multiply mul (prod, acc, mcnd, go, done);

 

    always

        begin

            go = 0;

            ir = m [pc];

            case (ir [15:13])

                3'b000 : pc = m [ir [12:0]];

                3'b001 : pc = pc + m [ir [12:0]];

                3'b010 : acc = -m [ir [12:0]];

                3'b011 : m [ir [12:0]] = acc;

                3'b100,    

                3'b101 : acc = acc - m [ir [12:0]];

                3'b110 : if (acc < 0) pc = pc + 1;

                3'b111 : begin

                             mcnd = m [ir [12:0]];

                             go = 1;

                             wait (done);

                             acc = prod;

                         end

            endcase

            pc = pc + 1;

        end

endmodule

 

module multiply (prod, mpy, mcnd, go, done);

    output [31:0] prod;

    input  [31:0] mpy, mcnd;

    input         go;

    output        done;

 

    reg [31:0]    prod;

    reg [15:0]    myMpy;

    reg           done;

 

    always

        begin

            done = 0;

            wait (go);

            myMpy  = mpy[15:0];

            prod = 0;

            repeat (16)

                begin

                    if (myMpy[0])

                        prod = prod + {mcnd, 16'h0000};

                    prod = prod >> 1;

                    myMpy = myMpy >> 1;

                end

            done = 1;

            wait (~go);

        end

endmodule

 

 

 

//Example 3.4.  Fibonacci Number Generator Using Named Events.

module topNE();

    wire [15:0] number, numberOut;

 

    numberGenNE    ng(number);

    fibNumberGenNE fng(number, numberOut);

endmodule

 

module numberGenNE(number);

    output [15:0] number;

    reg    [15:0] number;

    event         ready;

 

    initial

        number = 3;

 

    always

        begin

            #100 number = number + 1;

            -> ready; //generate event signal

        end

endmodule

 

module fibNumberGenNE(startingValue, fibNum);

    input  [15:0] startingValue;

    output [15:0] fibNum;

 

    reg [15:0] myValue;

    reg [15:0] fibNum;

 

    always

        begin

            @ng.ready            //accept event signal

                myValue = startingValue;

            for (fibNum = 0; myValue != 0; myValue = myValue - 1)

                fibNum = fibNum + myValue;

            $display ("%d, fibNum=%d", $time, fibNum);

        end

endmodule

 

 

 

//Example 3.6  The Consumer With Fully Interlocked Handshake.

module consumer(dataIn, prodReady, consReady);

    input [7:0] dataIn;

    input       prodReady;

    output      consReady;

 

    reg         consReady;

    reg [7:0]   dataInCopy;

 

    always

        begin

            consReady = 1;    // indicate consumer ready

            forever

                begin

                    wait (prodReady)

                        dataInCopy = dataIn;

                    consReady = 0;    // indicate value consumed

                    //...munch on data

                    wait (!prodReady)     // complete handshake

                        consReady = 1;

                end

        end

endmodule

 

 

 

//Example 3.7.  The Producer With Fully Interlocked Handshake.

module producer(dataOut, prodReady, consReady);

    output [7:0] dataOut;

    output       prodReady;

    input        consReady;

 

    reg          prodReady;

    reg [7:0]    dataOut,

                 temp;

 

    always

        begin

            prodReady = 0;    // indicate nothing to transfer

            forever

                begin

                    // ... produce data and put into "temp"

                    wait (consReady)    // wait for consumer ready

                        dataOut = $random;

                    prodReady = 1;    //indicate ready to transfer

                    wait (!consReady)     //finish handshake

                        prodReady = 0;

                end

        end

endmodule

 

 

 

//Example 3.8.  The Producer-Consumer Module.

module ProducerConsumer;

    wire [7:0] data;

    wire       pReady, cReady;

    

    producer   p(data, pReady, cReady);

    consumer   c(data, pReady, cReady);

endmodule

 

 

 

//Example 3.10.  Using Disable Statement to Model a Reset.

module numberGenDisable (number, reset);

    output [15:0] number;

    input         reset;

    event         ready;

    reg [15:0]    number;

 

    always

        begin :generator

            number = 3;

            forever

                begin

                    #100 number = number + 1;

                    -> ready;

                end

        end

 

    always

        @(negedge reset)  disable generator;

endmodule

 

 

 

//Example 3.11.  Flip Flop With Quasi-Continuous Assignment.

module dFlop (preset, clear, q, clock, d);

    input  preset, clear, clock, d;

    output q;

    reg    q;

 

    always 

        @(clear or preset)

            begin

                if (!clear)

                    #10    assign q = 0;

                else if (!preset)

                    #10    assign q = 1;

                else

                    #10    deassign q;

            end

 

    always 

        @(negedge clock)

            #10    q = d;

endmodule

 

 

 

//Example 3.13.  The Fibonacci Number Generator With Reset.

module numberGenFork (number, reset);

    output [15:0]    number;

    input            reset;

    event            ready;

    reg    [15:0]    number;

 

    always

        begin 

            number = 3;

            fork : generator

                begin

                    #100 number = number + 1;

                    -> ready;

                end

                @(negedge reset)  

                    disable generator;

            join

        end

endmodule

 

 

 

//Example 4.1.  A One-Bit Full Adder

module fullAdder(cOut, sum, aIn, bIn, cIn);

    output cOut, sum;

    input  aIn, bIn, cIn;

 

    wire   x2;

 

    nand   (x2, aIn, bIn),

           (cOut, x2, x8);

    xnor   (x9, x5, x6);

    nor    (x5, x1, x3),

           (x1, aIn, bIn);

    or     (x8, x1, x7);

    not    (sum, x9),

           (x3, x2),

           (x6, x4),

           (x4, cIn),

           (x7, x6);

endmodule

 

 

 

//Example 4.2.  Wire AND Example.

module andOfComplements (a, b, c, d);

    input   a, b;

    output  c, d;

 

    wand    c;

    wire    d;

 

    not (c, a);

    not (c, b);

 

    not (d, a);

    not (d, b);

endmodule

 

 

 

//Example 4.3.  Illustration of Continuous Assignment.

module oneBitFullAdder(cOut, sum, aIn, bIn, cIn);

    output cOut, sum;

    input  aIn, bIn, cIn;

 

    assign sum = aIn ^ bIn ^ cIn,

           cOut = (aIn & bIn) | (bIn & cIn) | (aIn & cIn);

 

endmodule

 

 

 

//Example 4.4.  Function Call From Continuous Assignment.

module multiplexor(a, b, c, d, select, e);

    input       a, b, c, d;

    input [1:0] select;

    output      e;

 

    assign e = mux (a, b, c,d, select);

 

    function    mux;

        input       a, b, c, d;

        input [1:0] select;

 

        case (select)

            2'b00:   mux = a;

            2'b01:   mux = b;

            2'b10:   mux = c;

            2'b11:   mux = d;

            default: mux = 'bx;

        endcase

    endfunction

endmodule

 

 

 

//Example 4.5.  Combined Net and Continuous Assignment.

module modXor (AXorB, a, b);

    parameter size = 8, delay = 15;

 

    output [size-1:0] AXorB;

    input  [size-1:0] a, b;

 

    wire   [size-1:0] #delay AXorB = a ^ b;

endmodule

 

 

 

//Example 4.6.  Net and Continuous Assignment Delays.

module wandOfAssigns (a, b, c);

    input  a, b;

    output c;

 

    wand #10 c;

 

    assign #5 c = ~a;

    assign #3 c = ~b;

endmodule

 

 

 

//Example 4.7.  Continuous Assignment to an Inout.

module bufferDriver (busLine, bufferedVal, bufInput, busEnable);

    inout  busLine;

    input  bufInput, busEnable;

    output bufferedVal;

 

    assign bufferedVal = busLine,

           busLine = (busEnable) ? bufInput : 1'bz;

endmodule

 

 

 

//Example 4.10.  A Tristate Latch.

module triStateLatch (qOut, nQOut, clock, data, enable);

    output qOut, nQOut;

    input  clock, data, enable;

    tri    qOut, nQOut;

 

    not    #5          (ndata, data);

    nand   #(3,5)      d(wa, data, clock),

                       nd(wb, ndata, clock);

    nand   #(12, 15)   qQ(q, nq, wa),

                       nQ(nq, q, wb);

    bufif1 #(3, 7, 13) qDrive (qOut, q, enable),

                       nQDrive(nQOut, nq, enable);

endmodule

 

 

 

//Example 4.11.  Illustration of Min, Typical, and Max Delays.

module IOBuffer (bus, in, out, dir);

    inout  bus;

    input  in, dir;

    output out;

 

    parameter

        R_Min = 3, R_Typ = 4, R_Max = 5,

        F_Min = 3, F_Typ = 5, F_Max = 7,

        Z_Min = 12, Z_Typ = 15, Z_Max = 17;

 

    bufif1 #(R_Min: R_Typ: R_Max, 

             F_Min: F_Typ: F_Max,

             Z_Min: Z_Typ: Z_Max)

            (bus, out, dir);

 

    buf    #(R_Min: R_Typ: R_Max, 

             F_Min: F_Typ: F_Max)

            (in, bus);

endmodule

 

 

 

//Example 5.1.  A User-Defined Combinational Primitive.

primitive carry(carryOut, carryIn, aIn, bIn);

    output carryOut;

    input  carryIn,

           aIn,

           bIn;

 

    table

        0    00    :    0;

        0    01    :    0;

        0    10    :    0;

        0    11    :    1;

        1    00    :    0;

        1    01    :    1;

        1    10    :    1;

        1    11    :    1;

    endtable

endprimitive

 

 

 

//Example 5.2.  A Carry Primitive.

primitive carryX(carryOut, carryIn, aIn, bIn);

    output carryOut;

    input  aIn,

           bIn,

           carryIn;

 

    table

        0    00    :    0;

        0    01    :    0;

        0    10    :    0;

        0    11    :    1;

        1    00    :    0;

        1    01    :    1;

        1    10    :    1;

        1    11    :    1;

        0    0x    :    0;

        0    x0    :    0;

        x    00    :    0;

        1    1x    :    1;

        1    x1    :    1;

        x    11    :    1;

    endtable

endprimitive

 

 

 

//Example 5.3.  A Carry Primitive With Shorthand Notation.

primitive carryAbbrev(carryOut, carryIn, aIn, bIn);

    output carryOut;

    input  aIn,

           bIn,

           carryIn;

 

    table

        0    0?    :    0;

        0    ?0    :    0;

            00    :    0;

            11    :    1;

        1    ?1    :    1;

        1    1?    :    1;

    endtable

endprimitive

 

 

 

//Example 5.4.  A User-Defined Sequential Primitive.

primitive latch (q, clock, data);

    output q;

    reg    q;

    input  clock, data;

    table

//        clock    data   state   output

            0        1    : ? :    1;

            0        0    : ? :    0;

            1        ?    : ? :    -;

    endtable

endprimitive

 

 

 

//Example 5.5.  Edge-Sensitive Behavior.

primitive dEdgeFF_Prim (q, clock, data);

    output q;

    reg    q;

    input  clock, data;

 

    table

//          clock    data      state   output

            (01)      0        : ? :    0;

            (01)      1        : ? :    1;

            (0x)      1        : 1 :    1;

            (0x)      0        : 0 :    0;

            (?0)      ?        : ? :    -;

                    (??)      : ? :    -;

    endtable

endprimitive

 

 

 

//Example 5.6.  Edge-Sensitive Behavior With Shorthand Notation.

primitive dEdgeFFShort (q, clock, data);

    output q;

    reg    q;

    input  clock, data;

 

    table

//        clock      data  state   output

            r         0    : ? :    0;

            r         1    : ? :    1;

            (0x)      0    : 1 :    1;

            (0x)      1    : 1 :    1;

            (?0)      ?    : ? :    -;

                     *    : ? :    -;

    endtable

endprimitive

 

 

 

//Example 5.7.  A JK Flip Flop Example.

primitive jkEdgeFF (q, clock, j, k, preset, clear);

    output q; reg q;

    input  clock, j, k, preset, clear;

 

    table

    //clock          jk    pc    state   output

    // preset logic

                        01    : ? :    1;

                        *1    : 1 :    1;

 

    // clear logic

                        10    : ? :    0;

                        1*    : 0 :    0;

 

    // normal clocking cases

        r            00    11    : ? :    -;

        r            01    11    : ? :    0;

        r            10    11    : ? :    1;

        r            11    11    : 0 :    1;

        r            11    11    : 1 :    0;

        f            ??    ??    : ? :    -;

 

    // j and k transition cases

        b            *?    ??    : ? :    -;

        b            ?*    ??    : ? :    -;

 

    //cases reducing pessimism

        p            00    11    : ? :    -;

        p            0?    1?    : 0 :    -;

        p            ?0    ?1    : 1 :    -;

        (x0)         ??    ??    : ? :    -;

        (1x)         00    11    : ? :    -;

        (1x)         0?    1?    : 0 :    -;

        (1x)         ?0    ?1    : 1 :    -;

        x            *0    ?1    : 1 :    -;

        x            0*    1?    : 0 :    -;

    endtable

endprimitive

 

 

 

//Example 6.1.  MOS Shift Register.

//Dynamic MOS serial shift register circuit description 

module shreg (out, in, phase1, phase2);

    /* IO port declarations, where 'out' is the inverse

    of 'in' controlled by the dual-phased clock */

 

    output out;       //shift register output

    input  in,        //shift register input

           phase1,    //clocks

           phase2;

 

    tri    wb1, wb2, out; //tri nets pulled up to VDD

    pullup //depletion mode pullup devices

           (wb1), (wb2), (out);

 

    trireg (medium) wa1, wa2, wa3; //charge storage nodes

 

    supply0 gnd; //ground supply

 

    nmos #3 //pass devices and their interconnections

            a1(wa1,in,phase1), b1(wb1,gnd,wa1),

            a2(wa2,wb1,phase2), b2(wb2,gnd,wa2),

            a3(wa3,wb2,phase1), gout(out,gnd,wa3);

endmodule

 

 

 

 

//Example 6.2.  Simulating the MOS Shift Register.

module waveShReg;

    wire shiftout;      //net to receive circuit output value

    reg  shiftin;       //register to drive value into circuit

    reg  phase1,phase2; //clock driving values

 

    parameter d = 100;  //define the waveform time step

 

    shreg cct (shiftout, shiftin, phase1, phase2);

 

    initial

        begin :main

            shiftin = 0; //initialize waveform input stimulus

            phase1 = 0;

            phase2 = 0;

            setmon;      // setup the monitoring information

            repeat(2)    //shift data in

                clockcct;

        end

 

task setmon;        //display header and setup monitoring

    begin

        $display("        time   clks   in  out  wa1-3  wb1-2");

        $monitor ($time,,,,phase1, phase2,,,,,,shiftin,,,, shiftout,,,,,

            cct.wa1, cct.wa2, cct.wa3,,,,,cct.wb1, cct.wb2);

    end

endtask

 

task clockcct; //produce dual-phased clock pulse

    begin

        #d phase1 = 1; //time step defined by parameter d

        #d phase1 = 0;

        #d phase2 = 1;

        #d phase2 = 0;

    end

endtask

endmodule

 

 

 

//Example 6.3.  A Static RAM Cell.

//description of a MOS static RAM cell

module sram(dataOut, address, dataIn, write);

    output dataOut;

    input  address, dataIn, write;

 

    tri w1, w3, w4, w43;

 

    bufif1

        g1(w1, dataIn, write);

    tranif1

        g2(w4, w1, address);

    not (pull0, pull1)

        g3(w3, w4), g4(w4, w3);

    buf

        g5(dataOut, w1);

endmodule

 

//waveform for testing the static RAM cell

module wave_sram;

    wire dataOut;

    reg  address, dataIn, write;

 

    //make the sram a submodule and define the interconnections

    sram cell(dataOut, address, dataIn, write);

 

    //define the waveform to drive the circuit

    parameter d = 100;

    initial

        begin

            #d dis;

            #d address = 1;

            #d dis;

            #d dataIn = 1;

            #d dis;

            #d write = 1;

            #d dis;

            #d write = 0;

            #d dis;

            #d write = 'bx;

            #d dis;

            #d address = 'bx;

            #d dis;

            #d address = 1;

            #d dis;

            #d write = 0;

            #d dis;

        end

 

task dis;            //display the circuit state

    $display($time,,

    "addr=%v d_in=%v write=%v d_out=%v",

        address, dataIn, write, dataOut,

        " (134)=%b%b%b  w134=%v %v %v",

        cell.w1, cell.w3, cell.w4,

        cell.w1, cell.w3, cell.w4);

endtask

endmodule

 

 

 

//THE MINISIM EXAMPLE

module 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'd2

 

parameter

    DebugFlags =               'b11000, //set to 1 for message

//                               |||||

//  loading                   <--+||||

//  event value changes      <----+|||

//  wire calculation        <------+||

//  evaluation             <--------+|

//  scheduling           <-----------+

 

    IndexSize = 16,     //maximum size for index pointers

    MaxElements = 50,   //maximum number of elements

    TypeSize = 12;      //maximum number of types

 

reg [IndexSize-1:0]

    eventElement,             //output value change element

    evalElement,              //evaluation element on fanout

    fo0Index[1:MaxElements],  //first fanout index of eventElement

    fo1Index[1:MaxElements],  //second fanout index of eventElement

    currentList,              //current time scheduled event list

    nextList,                 //unit delay scheduled event list

    schedList[1:MaxElements]; //scheduled event list index

reg [TypeSize-1:0]

    eleType[1:MaxElements]; //element type

reg

    fo0TermNum[1:MaxElements],   //first fanout input terminal number

    fo1TermNum[1:MaxElements],   //second fanout input terminal number

    schedPresent[1:MaxElements]; //element is in scheduled event list flags

reg [15:0]

    eleStrength[1:MaxElements], //element strength indication

    outVal[1:MaxElements],      //element output value

    in0Val[1:MaxElements],      //element first input value

    in1Val[1:MaxElements],      //element second input value

    in0, in1, out, oldIn0;      //temporary value storage

 

integer pattern, simTime; //time keepers

 

initial

  begin

    // initialize variables

    pattern = 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 simulate

    $display("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(1, `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),

        `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 simulate

    $display("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 loaded

input [TypeSize-1:0] type;         //type of element

input [15:0] strengthCoercion;     //strength specification of element

input [15:0] oVal, i0Val, i1Val;   //output and input values

input [IndexSize-1:0] fo0, fo1;    //fanout element indexes

input fo0Term, fo1Term;            //fanout element input terminal indicators

  begin

    if (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;

    schedPresent[loadAtIndex] = 0;

  end

endtask

 

// Given a type number, return a type string

function [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";

    endcase

endfunction

 

// Setup a value change on an element.

task setupStim;

input [IndexSize-1:0] vcElement; //element index

input [15:0] newVal;           //new element value

  begin

    if (! schedPresent[vcElement])

      begin

        schedList[vcElement] = currentList;

        currentList = vcElement;

        schedPresent[vcElement] = 1;

      end

    outVal[vcElement] = newVal;

  end

endtask

 

// 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)

      begin

        pattern = pattern + 1;

        setupStim(vcElement, `Strong0);

        executeEvents;

        pattern = pattern + 1;

        setupStim(vcElement, `Strong1);

        executeEvents;

      end

endtask

 

// 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. Continue this loop

// until no more events to execute.

// For each event executed, evaluate the two fanout elements if present.

task executeEvents;

reg [15:0] newVal;

  begin

    simTime = 0;

    while (currentList)

      begin

        eventElement = currentList;

        currentList = schedList[eventElement];

        schedPresent[eventElement] = 0;

        newVal = outVal[eventElement];

        if (DebugFlags[3])

            $display(

                "At %0d,%0d Element %0d, type %0s, changes to %s(%b_%b)",

                pattern, simTime,

                eventElement, typeString(eleType[eventElement]),

                valString(newVal), newVal[15:8], newVal[7:0]);

        if (fo0Index[eventElement]) evalFo(0);

        if (fo1Index[eventElement]) evalFo(1);

        if (! currentList) // if empty move to next time unit

          begin

            currentList = nextList;

            nextList = 0;

            simTime = simTime + 1;

          end

      end

  end

endtask

 

// Evaluate a fanout element by testing its type and calling the

// appropriate evaluation routine.

task evalFo;

input fanout; //first or second fanout indicator

  begin

    evalElement = fanout ? fo1Index[eventElement] : 

                           fo0Index[eventElement];

    if (DebugFlags[1])

        $display("Evaluating Element %0d type is %0s",

            evalElement, typeString(eleType[evalElement]));

    case (eleType[evalElement])

      `Nand: evalNand(fanout);

      `DEdgeFF: evalDEdgeFF(fanout);

      `Wire: evalWire(fanout);

    endcase

  end

endtask

 

// Store output value of event element into

// input value of evaluation element.

task storeInVal;

input fanout; //first or second fanout indicator

  begin

    // store new input value

    if (fanout ? fo1TermNum[eventElement] : fo0TermNum[eventElement])

        in1Val[evalElement] = outVal[eventElement];

    else

        in0Val[evalElement] = outVal[eventElement];

  end

endtask

 

// Convert a given full strength value to three-valued logic (0, 1 or X)

function [1:0] log3;

input [15:0] inVal;

    casez (inVal)

      16'b00000000_00000000: log3 = `ValX;

      16'b???????0_00000000: log3 = `Val0;

      16'b00000000_???????0: log3 = `Val1;

      default:               log3 = `ValX;

    endcase

endfunction

 

// Convert a given full strength value to four-valued logic (0, 1, X or Z),

// returning a 1 character string

function [8:1] valString;

input [15:0] inVal;

    case (log3(inVal))

      `Val0: valString = "0";

      `Val1: valString = "1";

      `ValX: valString = (inVal & 16'b11111110_11111110) ? "X" : "Z";

    endcase

endfunction

 

// Coerce a three-valued logic output value to a full output strength value

// for the scheduling of the evaluation element

function [15:0] strengthVal;

input [1:0] logVal;

    case (logVal)

      `Val0: strengthVal = eleStrength[evalElement] & 16'b11111111_00000000;

      `Val1: strengthVal = eleStrength[evalElement] & 16'b00000000_11111111;

      `ValX: strengthVal = fillBits(eleStrength[evalElement]);

    endcase

endfunction

 

// 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;

  begin

    fillBits = val;

    if (log3(val) == `ValX)

      begin

        casez (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;

        endcase

        casez (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;

       endcase

     end

  end

endfunction

 

// Evaluate a 'Nand' gate primitive.

task evalNand;

input fanout; //first or second fanout indicator

  begin

    storeInVal(fanout);

    // calculate new output value

    in0 = log3(in0Val[evalElement]);

    in1 = log3(in1Val[evalElement]);

    out = ((in0 == `Val0) || (in1 == `Val0)) ?

        strengthVal(`Val1) :

        ((in0 == `ValX) || (in1 == `ValX)) ?

            strengthVal(`ValX):

            strengthVal(`Val0);

    // schedule if output value is different

    if (out != outVal[evalElement])

        schedule(out);

  end

endtask

 

// Evaluate a D positive edge-triggered flip flop

task evalDEdgeFF;

input fanout; //first or second fanout indicator

    // check value change is on clock input

    if (fanout ? (fo1TermNum[eventElement] == 0) :

                 (fo0TermNum[eventElement] == 0))

      begin

        // get old clock value

        oldIn0 = log3(in0Val[evalElement]);

        storeInVal(fanout);

        in0 = log3(in0Val[evalElement]);

        // test for positive edge on clock input

        if ((oldIn0 == `Val0) && (in0 == `Val1))

          begin

            out = strengthVal(log3(in1Val[evalElement]));

            if (out != outVal[evalElement])

              schedule(out);

          end

      end

    else

        storeInVal(fanout); // store data input value

endtask

 

// Evaluate a wire with full strength values

task evalWire;

input fanout;

reg [7:0] mask;

  begin

    storeInVal(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])

        $display("in0 = %b_%b\nin1 = %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]);

  end

endtask

 

// 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 value

    casez (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;

    endcase

endfunction

 

// Schedule the evaluation element to change to a new value.

// If the element is already scheduled then just insert the new value.

task schedule;

input [15:0] newVal; // new value to change to

  begin

    if (DebugFlags[0])

        $display(

            "Element %0d, type %0s, scheduled to change to %s(%b_%b)",

            evalElement, typeString(eleType[evalElement]),

            valString(newVal), newVal[15:8], newVal[7:0]);

    if (! schedPresent[evalElement])

      begin

        schedList[evalElement] = nextList;

        schedPresent[evalElement] = 1;

        nextList = evalElement;

      end

    outVal[evalElement] = newVal;

  end

endtask

endmodule

 

/*******************  PLEASE NOTE:  ************************************

 

The values printed out in the book section 7.1.3 have the wrong

format. The 0 and 1 strength bits need to be swapped around. For

example, the first value printed in the book should read

1(00000000_01000000) and not 1(0100000_00000000). The value format you

get from running the above minisim description through Verilog should

be correct.

 

Here is a listing of the results:

 

Loading toggle circuit

Loading element 1, type DEdgeFF, with initial value 1(00000000_01000000)

Loading element 2, type DEdgeFF, with initial value 1(00000000_01000000)

Loading element 3, type Nand, with initial value 0(01000000_00000000)

Loading element 4, type DEdgeFF, with initial value 1(00000000_01000000)

Applying 2 clocks to input element 1

At 1,0 Element 1, type DEdgeFF, changes to 0(01000000_00000000)

At 2,0 Element 1, type DEdgeFF, changes to 1(00000000_01000000)

At 2,1 Element 4, type DEdgeFF, changes to 0(01000000_00000000)

At 2,2 Element 3, type Nand, changes to 1(00000000_01000000)

At 3,0 Element 1, type DEdgeFF, changes to 0(01000000_00000000)

At 4,0 Element 1, type DEdgeFF, changes to 1(00000000_01000000)

At 4,1 Element 4, type DEdgeFF, changes to 1(00000000_01000000)

At 4,2 Element 3, type Nand, changes to 0(01000000_00000000)

Changing element 2 to value 0 and applying 1 clock

At 5,0 Element 1, type DEdgeFF, changes to 0(01000000_00000000)

At 5,0 Element 2, type DEdgeFF, changes to 0(01000000_00000000)

At 5,1 Element 3, type Nand, changes to 1(00000000_01000000)

At 6,0 Element 1, type DEdgeFF, changes to 1(00000000_01000000)

 

Loading open-collector and pullup circuit

Loading element 1, type DEdgeFF, with initial value 1(00000000_01000000)

Loading element 2, type DEdgeFF, with initial value 0(01000000_00000000)

Loading element 3, type Nand, with initial value 0(01000000_00000000)

Loading element 4, type Nand, with initial value Z(00000000_00000001)

Loading element 5, type Wire, with initial value 0(01000000_00000000)

Loading element 6, type DEdgeFF, with initial value 1(00000000_00100000)

Loading element 7, type Wire, with initial value 0(01000000_00000000)

Changing element 1 to value 0

At 7,0 Element 1, type DEdgeFF, changes to 0(01000000_00000000)

At 7,1 Element 3, type Nand, changes to Z(00000000_00000001)

At 7,2 Element 5, type Wire, changes to Z(00000000_00000001)

At 7,3 Element 7, type Wire, changes to 1(00000000_00100000)

Changing element 2 to value 1

At 8,0 Element 2, type DEdgeFF, changes to 1(00000000_01000000)

At 8,1 Element 4, type Nand, changes to 0(01000000_00000000)

At 8,2 Element 5, type Wire, changes to 0(01000000_00000000)

At 8,3 Element 7, type Wire, changes to 0(01000000_00000000)

Changing element 2 to value X

At 9,0 Element 2, type DEdgeFF, changes to X(01111111_01111111)

At 9,1 Element 4, type Nand, changes to X(01111111_00000001)

At 9,2 Element 5, type Wire, changes to X(01111111_00000001)

At 9,3 Element 7, type Wire, changes to X(01111111_00111111)

*****************************************************************/

 

 

 

 

//THE 8251A EXAMPLE

//Cadence Design Systems, Inc. does not guarantee

//the accuracy or completeness of this model.

//Anyone using this does so at their own risk.

//Intel and MCS are trademarks of the Intel Corporation.

module I8251A(dbus,rcd,gnd,txc_,write_,chipsel_,comdat_,read_,rxrdy,

             txrdy,syndet,cts_,txe,txd,clk,reset,dsr_,rts_,dtr_,rxc_,vcc);

 

    parameter [7:0] instance_id = 8'h00;

 

    parameter [8:1] dflags     =      8'b00000100; // Defaults for diagnostics

    //                                      |||||

    // diagnostic dflags:                   |||||

    // bit 5 (16)  operation event trace  <-+||||

    // bit 4 (8)  communication errors   <---+||| (parity, frame, overrun)

    // bit 3 (4)  timing check          <-----+||

    // bit 2 (2) = print receiving     <-------+|

    // bit 1 (1) = print transmitting <---------+

 

    /* timing constants, for A. C. timing check, only non-zero times 

       are specified, in nano-sec */

 

    /* read cycle */

    `define TRR  250

    `define TRD  200

    `define TDF  100  // max. time used

 

    /* write cycle */

    `define TWW  250

    `define TDW  150

    `define TWD  20

    `define TRV  6  // in terms of clock cycles

 

    /* other timing */

    `define TTXRDY 8 // 8 clock cycles

 

 

    input

        rcd, // receive data

        rxc_, // receive clock

        txc_, // transmit clock

        chipsel_, // chip selected when low

        comdat_,  // command/data_ select

        read_, write_,

        dsr_, // data set ready

        cts_, // clear to send

        reset,// reset when high

        clk, // at least 30 times of the transmit/receive data bit rates

        gnd,

        vcc;

 

    output

        rxrdy, // receive data ready when high

        txd, // transmit data line

        txrdy, // transmit buffer ready to accept another byte to transfer

        txe, // transmit buffer empty

        rts_, // request to send 

        dtr_; // data terminal ready

 

    inout[7:0]

        dbus;

 

    inout

        syndet; //outside synchonous detect or output to indicate syn det

 

    supply0

        gnd;

    supply1

        vcc;

 

    reg

        txd,

        rxrdy,

        txe,

        dtr_,

        rts_;

 

    reg[7:0]

        receivebuf,

        rdata,

        status;

 

    reg

        recvdrv,

        statusdrv;

 

    assign

        // if recvdrv 1 dbus is driven by rdata

        dbus = recvdrv ? rdata : 8'bz,

        dbus = statusdrv ? status : 8'bz;

 

    reg[7:0]

        command,

        tdata_out,  // data being transmitted serially

        tdata_hold, // data to be transmitted next if tdata_out is full

        sync1, sync2, // synchronous data bytes

        modreg;

    and  (txrdy,status[0],command[0], ~ cts_);

 

    reg transmitter_reset, // set to 1 upon a reset, cleared upon write data

        tdata_out_full,  // 1 if data in tdata_out has not been transmitted.

        tdata_hold_full, // 1 if data in tdata_hold has not been transferred to

                         //   tdata_out for serial transmission.

        tdata_hold_cts;  // 1 if tdata_hold_full and it was cts when data was

                         //   transferred to tdata_hold.

                         // 0 if tdata_hold is empty or is full but was filled

                         //   while it was not cts.

 

    reg tdata_out_wait;  // 0 if a stop bit was just sent and we do not need

                         //   to wait for a negedge on txc before transmitting

 

    reg[7:0]   syncmask;

    nmos  syndet_gate1(syndet,status[6], ~ modreg[6]);

 

    reg   sync_to_receive; // 1(2) if looking for 1st(2nd) sync on rxd

    reg   syncs_received;  // 1 if sync chars received, 0 if looking for sync(s)

    reg   rec_sync_index; // indicating the syn. character to be matched

   

    integer  breakcount_period; // number of clock periods to count as break

 

    reg   sync_to_transmit;  // 1(2) if 1st(2nd) sync char should be sent next

 

    reg[7:0]  data_mask;    // masks off the data bits (if char size is not 8)

    // temporary registers

    reg[1:0] csel;          // indicates what next write means if comdat_=1:

                            // (0=mode instruction,1=sync1,2=sync2,3=command)

    reg[5:0]

        baudmx,

        tbaudcnt,

        rbaudcnt; // baud rate 

    reg[7:0]

        tstoptotal; // no. of tranmit clock pulses for stop bit (0 if sync mode)

    reg[3:0]

        databits;   // no. of data bits in a character (5,6,7 or 8)

 

    reg

        rdatain; // a data byte is read in if 1

 

    reg was_cts_when_received;  // 0: if cts_ was high when char was received

                                // 1: if cts_ was low when char was received

                                //    (and so char was sent before shutdown)

 

    event

        resete,

        start_receiver_e;

 

    reg receive_in_progress;

 

 

    event txende;

 

 

 

                /*** COMMUNICATION ERRORS ***/

 

    task frame_error;

        begin

            if(dflags[4])

                $display("I8251A (%h) at %d: *** frame error",

                                                          instance_id, $time);

            status[5]=1;

        end

    endtask

 

    task parity_error;

        begin

            if(dflags[4])

                $display("I8251A (%h) at %d: *** parity error on data: %b",

                                              instance_id, $time, receivebuf);

            status[3]=1;

        end

    endtask

 

    task overrun_error;

        begin

            if(dflags[4])

                $display("I8251A (%h) at %d: *** overrun error",

                                                          instance_id, $time);

            status[4]=1;

        end

    endtask

 

 

 

                /*** TIMING VIOLATIONS ***/

 

    integer

        time_dbus_setup,

        time_write_begin,

        time_write_end,

        time_read_begin,

        time_read_end,

        between_write_clks; // to check between write recovery

    reg reset_signal_in;    // to check the reset signal pulse width

 

    initial

    begin

        time_dbus_setup  = -9999;

        time_write_begin = -9999;

        time_write_end   = -9999;

        time_read_begin  = -9999;

        time_read_end    = -9999;

        between_write_clks = `TRV; // start: TRV clk periods since last write

 

    end

 

 

 

                /** Timing analysis for read cycles **/

 

    always @(negedge read_) 

        if (chipsel_==0)

        begin

            time_read_begin=$time;

            read_address_watch;

        end

 

       /* Timing violation: read pulse must be TRR ns */

 

    always @(posedge read_)

        if (chipsel_==0)

        begin

            disable read_address_watch;

            time_read_end=$time;

 

            if(dflags[3] && (($time-time_read_begin) < `TRR))

                $display("I8251A (%h) at %d: *** read pulse width violation",

                                                           instance_id, $time);

        end

 

       /* Timing violation: address (comdat_ and chipsel_) must be stable */

       /*                   stable throughout read                        */

 

    task read_address_watch;

        @(comdat_ or chipsel_) // if the "address" changes

            if (read_==0)      //    and read_ did not change at the same time

                if (dflags[3])

                    $display("I8251A (%h) at %d: *** address hold error on read",

                                                          instance_id, $time);

    endtask

 

                /** Timing analysis for write cycles **/

 

    always @(negedge write_) 

        if (chipsel_==0)

        begin

            time_write_begin=$time;

            write_address_watch;

        end

 

 

       /* Timing violation: read pulse must be TRR ns */

       /* Timing violation: TDW ns bus setup time before posedge write_ */

       /* Timing violation: TWD ns bus hold  time after  posedge write_ */

 

    always @(posedge write_)

        if (chipsel_==0)

        begin

            disable write_address_watch;

            time_write_end=$time;

 

            if(dflags[3] && (($time-time_write_begin) < `TWW))

                $display("I8251A (%h) at %d: *** write pulse width violation",

                                                           instance_id, $time);

 

            if(dflags[3] && (($time-time_dbus_setup) < `TDW))

                $display("I8251A (%h) at %d: *** data setup violation on write",

                                                           instance_id, $time);

        end

 

    always @dbus

        begin

            time_dbus_setup=$time;

 

            if(dflags[3] && (($time-time_write_end < `TWD)))

                $display("I8251A (%h) at %d: *** data hold violation on write",

                                                           instance_id, $time);

        end

 

 

       /* Timing violation: address (comdat_ and chipsel_) must be stable */

       /*                   stable throughout write                       */

 

    task write_address_watch;

        @(comdat_ or chipsel_) // if the "address" changes

            if (write_==0)     //    and write_ did not change at the same time

                if (dflags[3])

                   $display("I8251A (%h) at %d: *** address hold error on write",

                                                          instance_id, $time);

    endtask

 

 

        /* Timing violation: minimum of TRV clk cycles between writes */

 

    always @(negedge write_)

        if (chipsel_== 0)

        begin

            time_write_begin=$time;

            if(dflags[3] && between_write_clks < `TRV)

               $display("I8251A (%h) at %d: *** between write recovery violation",

                                                           instance_id, $time);

            between_write_clks = 0;

        end

 

    always @(negedge write_)

        repeat (`TRV) @(posedge clk)

            between_write_clks = between_write_clks + 1;

 

 

 

                /** Timing analysis for reset sequence **/

 

       /* Timing violation: reset pulse must be 6 clk cycles */

 

    always @(posedge reset)

        begin :reset_block

        reset_signal_in=1;

        repeat(6) @(posedge clk);

        reset_signal_in=0;

        // external reset

        -> resete;

        end

 

    always @(negedge reset)

        begin

        if(dflags[3] && (reset_signal_in==1))

            $display("I8251A (%h) at %d: *** reset pulse too short",

                                                           instance_id, $time);

        disable reset_block;

        end

 

 

 

 

                /*** BEHAVIORAL DESCRIPTION ***/

 

 

        /* Reset sequence */

 

    initial

        begin // power-on reset

        reset_signal_in=0;

        ->resete;

        end

 

    always @resete

        begin

        if(dflags[5])

            $display("I8251A (%h) at %d: performing reset sequence",

                                                           instance_id, $time);

        csel=0;

        transmitter_reset=1;

        tdata_out_full=0;

        tdata_out_wait=0;

        tdata_hold_full=0;

        tdata_hold_cts=0;

        rdatain=0;

        status=4;  // only txe is set

        txe=1;

        statusdrv=0;

        recvdrv=0;

        txd=1; // line at mark state upon reset until data is transmitted

        // assign not allowed for status, etc.

        rxrdy=0;

        command=0;

        dtr_=1;

        rts_=1;

        status[6]=0; // syndet is reset to output low 

        sync_to_transmit=1;     // transmit sync char #1 when sync are transmt'd

        sync_to_receive=1;

        between_write_clks = `TRV;

        receive_in_progress=0;

        disable read_address_watch;

        disable write_address_watch;

        disable trans1;

        disable trans2;

        disable trans3;

        disable trans4;

        disable rcv_blk;

        disable sync_hunt_blk;

        disable double_sync_hunt_blk;

        disable parity_sync_hunt_blk;

        disable syn_receive_internal;

        disable asyn_receive;

        disable break_detect_blk;

        disable break_delay_blk;

        end

 

 

    always @(negedge read_) 

        if (chipsel_==0)

        begin

            #(`TRD) // time for data to show on the data bus

 

            if (comdat_==0)     // 8251A DATA ==> DATA BUS

            begin

                recvdrv=1;

                rdatain=0; // no receive byte is ready

                rxrdy=0;

                status[1]=0;

            end

            else                // 8251A STATUS ==> DATA BUS

            begin

                statusdrv=1;

                if (modreg [1:0] == 2'b00) // if sync mode

                    status[6]=0;           //     reset syndet upon status read

                                           // Note: is only reset upon reset

                                           //       or rxd=1 in async mode

            end

        end

 

    always @(posedge read_)

        begin

            #(`TDF)  // data from read stays on the bus after posedge read_

            recvdrv=0;

            statusdrv=0;

        end

 

 

    always @(negedge write_)

    begin

        if((chipsel_==0) && (comdat_==0))

        begin

            txe=0;

            status[2]=0; // transmitter not empty after receiving data

            status[0]=0; // transmitter not ready after receiving data

        end

    end

 

 

    always @(posedge write_)          // read the command/data from the CPU

        if (chipsel_==0)

        begin

            if (comdat_==0)       // DATA BUS ==> 8251A DATA

            begin

                case (command[0] & ~ cts_)

                0:                    // if it is not clear to send

                begin

                    tdata_hold=dbus;

                    tdata_hold_full=1;//    then mark the data as received and

                    tdata_hold_cts=0; //    that it should be sent when cts

                end

                1:                    // if it is clear to send ...

                if(transmitter_reset) // ... and this is 1st data since reset

                begin

                    transmitter_reset=0;

                    tdata_out=dbus;

                    tdata_out_wait=1; //    then wait for a negedge on txc

                    tdata_out_full=1; //         and transmit the data

                    tdata_hold_full=0;

                    tdata_hold_cts=0;

                    repeat(`TTXRDY) @(posedge clk);

                    status[0]=1;      //         and set the txrdy status bit

                end

                else                  // ... and a sync/data char is being sent

                begin

                    tdata_hold=dbus;  //    then mark the data as being received

                    tdata_hold_full=1;//    and that it should be transmitted if

                    tdata_hold_cts=1; //    it becomes not cts,

                                      //    but do not set the txrdy status bit

                end

                endcase

            end

            else                  // DATA BUS ==> CONTROL

            begin

                case (csel)

                0:                // case 0:  MODE INSTRUCTION

                begin

                    modreg=dbus; 

                    if(modreg[1:0]==0)    // synchronous mode

                    begin

                        csel=1;

                        baudmx=1;

                        tstoptotal=0; // no stop bit for synch. op.

                    end

                    else

                    begin                 // asynchronous mode

                        csel=3;

                        baudmx=1; // 1X baud rate

                        if(modreg[1:0]==2'b10)baudmx=16;

                        if(modreg[1:0]==2'b11)baudmx=64;

                        // set up the stop bits in clocks

                        tstoptotal=baudmx;

                        if(modreg[7:6]==2'b10)tstoptotal=

                                   tstoptotal+baudmx/2;

                        if(modreg[7:6]==2'b11)tstoptotal=

                                   tstoptotal+tstoptotal;

                    end

                    databits=modreg[3:2]+5; // bits per char

                    data_mask=255 >> (3-modreg[3:2]);

                end

 

                1:                // case 1:  1st SYNC CHAR - SYNC MODE

                begin

                    sync1=dbus; 

                    /* the syn. character will be adjusted to the most

                       significant bit to simplify syn. hunt, 

                       syncmask is also set to test the top data bits  */

                    case (modreg[3:2])

                    0:

                    begin

                        sync1=sync1<< 3;

                        syncmask=8'b11111000;

                    end

 

                    1:

                    begin

                        sync1=sync1<< 2;

                        syncmask=8'b11111100;

                    end

 

                    2:

                    begin

                        sync1=sync1<< 1;

                        syncmask=8'b11111110;

                    end

                    3:

                        syncmask=8'b11111111;

                    endcase

 

                    if(modreg[7]==0)

                        csel=2;   // if in double sync char mode, get 2 syncs

                    else

                        csel=3;   // if in single sync char mode, get 1 sync

                end

 

                2:                // case 2:  2nd SYNC CHAR - SYNC MODE

                begin

                    sync2=dbus;

                    case (modreg[3:2])

                    0: sync2=sync2<< 3;

                    1: sync2=sync2<< 2;

                    2: sync2=sync2<< 1;

                    endcase

 

                    csel=3;

                end

 

                3:             // case 3:  COMMAND INSTRUCTION - SYNC/ASYNC MODE

                begin

                    status[0]=0; // Trick: force delay txrdy pin if command[0]=1

                    command=dbus;

                    dtr_= ! command[1];

 

                    if(command[3])           // if send break command

                        assign txd=0;        //    set txd=0 (ignores/overrides

                    else                     //    later non-assign assignments)

                        deassign txd;

 

                    if(command[4]) status[5:3]=0; // Clear Frame/Parity/Overrun

                    rts_= ! command[5];

                    if(command[6]) ->resete;      // internal reset

 

                    if(modreg[1:0]==0 && command[7])

                    begin                    // if sync mode and enter hunt

                        disable              //    disable the sync receiver

                            syn_receive_internal;

                        disable

                            syn_receive_external;

 

                        receivebuf=8'hff;    //    reset recieve buffer 1's

                        -> start_receiver_e; //    restart sync mode receiver

                    end

 

                    if(receive_in_progress==0)

                        -> start_receiver_e;

 

                    repeat(`TTXRDY) @(posedge clk);

                    status[0]=1;

                end

                endcase  

            end

        end

 

 

    reg [7:0] serial_data;

    reg parity_bit;

 

 

    always wait (tdata_out_full==1)

    begin :trans1

 

        if(dflags[1])

            $display("I8251A (%h) at %d: transmitting data: %b",

               instance_id, $time, tdata_out);

 

        if (tdata_out_wait)                 // if the data arrived any old time

            @(negedge txc_);                //     wait for a negedge on txc_

                                            // but if a stop bit was just sent

                                            //     do not wait

        serial_data=tdata_out;

 

        if (tstoptotal != 0)                // if async mode ...

        begin

           txd=0;                           //    then send a start bit 1st

           repeat(baudmx) @(negedge txc_);

        end

 

        repeat(databits)                    // send all start, data bits

        begin

            txd=serial_data[0];

            repeat(baudmx) @(negedge txc_);

            serial_data=serial_data>> 1;

        end

 

        if (modreg [4])                     // if parity is enabled ...

        begin

            parity_bit= ^ (tdata_out & data_mask);

            if(modreg[5]==0)parity_bit= ~parity_bit; // odd parity

 

            txd=parity_bit;

            repeat(baudmx) @(negedge txc_); //    then send the parity bit

        end

 

        if(tstoptotal != 0)                 // if sync mode

        begin

            txd=1;                          //    then send out the stop bit(s)

            repeat(tstoptotal) @(negedge txc_);

        end

 

        tdata_out_full=0;// block this routine until data/sync char to be sent

                         // is immediately transferred to tdata_out.

 

        ->txende;        // decide what data should be sent (data/sync/stop bit)

    end

 

    event transmit_held_data_e,

          transmitter_idle_e;

 

    always @txende                    // end of transmitted data/sync character

    begin :trans2

 

        case (command[0] & ~ cts_)

        0:                           // if it is not now cts

                                     //   but data was received while it was cts

        if (tdata_hold_full && tdata_hold_cts)

            -> transmit_held_data_e; // then send the data char

        else

            -> transmitter_idle_e;   // else send sync char(s) or 1 stop bit

 

        1:                           // if it is now cts

        if (tdata_hold_full)         //    if a character has been received

                                     //       but not yet transmitted ...

            -> transmit_held_data_e; //       then send the data char

 

        else                         //    else (no character has been received)

            -> transmitter_idle_e;   //       send sync char(s) or 1 stop bit

        endcase

    end

 

 

    always @transmitter_idle_e     // if there are no data chars to send ...

    begin :trans3

        status[2]=1;               //       mark transmitter as being empty

        txe=1;

 

 

        if (tstoptotal != 0 ||     //        if async mode or after a reset

          command[0]==0 || cts_==1)//           or TxEnable=false or cts_=false

        begin

            if(dflags[1])

                $display("I8251A (%h) at %d: transmitting data: 1 (stop bit)",

                                                           instance_id, $time);

 

            txd=1;                 //            then  send out 1 stop bit

            tdata_out=1;           //                  and make any writes

                                   //                  go to tdata_hold

            repeat(baudmx) @(negedge txc_);

            -> txende;

        end

        else                       //        if sync mode

        case (sync_to_transmit)

        1:                         //         ... send 1st sync char now

            begin

            tdata_out=sync1 >> (8-databits);

            tdata_out_wait=0;      //             without waiting on negedge txc

            tdata_out_full=1;

            if(modreg[7]==0)       //             if double sync mode

                sync_to_transmit=2;//                send 2nd sync after 1st

            end

        2:                         //         ... send 2nd sync char now

            begin

            tdata_out=sync2 >> (8-databits);

            tdata_out_wait=0;      //             without waiting on negedge txc

            tdata_out_full=1;

            sync_to_transmit=1;    //             send 1st sync char next

            end

        endcase

    end

 

 

    always @ transmit_held_data_e  //    if a character has been received

    begin :trans4

        tdata_out=tdata_hold;      //        but not transmitted ...

        tdata_out_wait=0;          //        then do not wait on negedge txc

        tdata_out_full=1;          //             and send the char immediately

        tdata_hold_full=0;

        repeat(`TTXRDY) @(posedge clk);

        status[0]=1;               //        and set the txrdy status bit

    end

 

 

 

 

 

     /******************** RECEIVER PORTION OF THE 8251A  ********************/

 

                             // data is received at leading edge of the clock

 

    event  break_detect_e,   //

           break_delay_e;    //

 

    event  hunt_sync1_e,     // hunt for the 1st sync char

           hunt_sync2_e,     // hunt for the 2nd sync char (double sync mode)

           sync_hunted_e,    // sync char(s) was found (on a bit aligned basis)

           external_syndet_watche;// external sync mode: whenever syndet pin

                                  // goes high, set the syndet status bit

 

 

    always @start_receiver_e

    begin :rcv_blk

        receive_in_progress=1;

 

        case(modreg[1:0])

        2'b00:

            if(modreg[6]==0)              // if internal syndet mode ...

            begin

                if(dflags[5])

                   $display("I8251A (%h) at %d: starting internal sync receiver",

                                                           instance_id, $time);

 

                if(dflags[5] && command[7])

                   $display("I8251A (%h) at %d: hunting for syncs",

                                                           instance_id, $time);

 

                if(modreg[7]==1)          //   if enter hunt mode

                begin

                    if(dflags[5])

                        $display("I8251A (%h) at %d: receiver waiting on syndet",

                                                           instance_id, $time);

 

                    -> hunt_sync1_e;      //      start search for sync char(s)

                                          //      & wait for syncs to be found

                    @(posedge syndet);

 

                    if(dflags[5])

                       $display("I8251A (%h) at %d: receiver DONE waiting on syndet",

                                                           instance_id, $time);

                end

 

                syn_receive_internal;     //   start sync mode receiver

            end

            else                          // if external syndet mode ...

            begin

                if(dflags[5])

                   $display("I8251A (%h) at %d: starting external sync receiver",

                                                           instance_id, $time);

 

                if(dflags[5] && command[7])

                   $display("I8251A (%h) at %d: hunting for syncs",

                                                           instance_id, $time);

 

                -> external_syndet_watche;//    whenever syndet pin goes to 1

                                          //        set syndet status bit

 

                if (command[7]==1)        //    if enter hunt mode

                begin :external_syn_hunt_blk

                   fork

                      syn_receive_external;//      assemble chars while waiting

 

                      @(posedge syndet)   //       after rising edge of syndet

                        @(negedge syndet) //       wait for falling edge

                                          //       before starting char assembly

                          disable external_syn_hunt_blk;

                    join

                end

 

            syn_receive_external;         //   start external sync mode receiver

            end

 

        default:                          // if async mode ...

            begin

                if(dflags[5])

                   $display("I8251A (%h) at %d: starting asynchronous receiver",

                                                           instance_id, $time);

 

                -> break_detect_e;        //     start check for rcd=0 too long

                asyn_receive;             //     and start async mode receiver

            end

        endcase

    end

 

 

                /**** EXTERNAL SYNCHRONOUS MODE RECEIVE ****/

 

    task syn_receive_external;

    forever

    begin

        repeat(databits)   // Whether in hunt mode or not, assemble a character

        begin

            @(posedge rxc_)

            receivebuf={rcd, receivebuf[7:1]};

        end

 

        get_and_check_parity;    // reveive and check parity bit, if any

 

        mark_char_received;      // set rxrdy line, if enabled

    end

    endtask

 

    always @external_syndet_watche

        @(posedge rxc_)

            status[6]=1;

 

                /**** INTERNAL SYNCHRONOUS MODE RECEIVE ****/

 

 

                /* Hunt for the sync char(s)                     */

                /* (if in synchronous internal sync detect mode) */

                /* Syndet is set high when the sync(s) are found */

 

    always @ hunt_sync1_e      // search for 1st sync char in the data stream

    begin :sync_hunt_blk

        while(!(((receivebuf ^ sync1) & syncmask)===8'b00000000))

        begin

            @(posedge rxc_)

            receivebuf={rcd, receivebuf[7:1]};

        end

        if(modreg[7]==0)       // if double sync mode

            -> hunt_sync2_e;   //     check for 2nd sync char directly after 1st

        else

            -> sync_hunted_e;  // if single sync mode, sync hunt is complete

    end

 

    always @ hunt_sync2_e // find the second synchronous character

    begin :double_sync_hunt_blk

        repeat(databits)

        begin

            @(posedge rxc_)

            receivebuf={rcd, receivebuf[7:1]};

        end

        if(((receivebuf ^ sync2) & syncmask)===8'b00000000)

            ->sync_hunted_e;   // if sync2 followed syn1, sync hunt is complete

        else

            ->hunt_sync1_e;    // else hunt for sync1 again

 

        // Note: the data stream [sync1 sync1 sync2] will have sync detected.

        // Suppose sync1=11001100:

        // then [1100 1100 1100 sync2] will NOT be detected.

        // In general: never let a suffix of sync1 also be a prefix of sync1.

    end

 

    always @ sync_hunted_e

    begin :parity_sync_hunt_blk

        get_and_check_parity;

        status[6]=1;            // set syndet status bit (sync chars detected)

    end

 

    task syn_receive_internal;

    forever

    begin

        repeat(databits)   // no longer in hunt mode so read entire chars and

        begin              // then look for syncs (instead of on bit boundaries)

            @(posedge rxc_)

            receivebuf={rcd, receivebuf[7:1]};

        end

 

 

        case (sync_to_receive)

        2:                                // if looking for 2nd sync char ...

        begin

            if(((receivebuf ^ sync2)

                         & syncmask)===0)

            begin                         // ... and 2nd sync char is found

                sync_to_receive=1;        //    then look for 1st sync (or data)

                status[6]=1;              //         and mark sync detected

            end

            else if(((receivebuf ^ sync1)

                         & syncmask)===0)

            begin                         // ... and 1st sync char is found

                sync_to_receive=2;        //    then look for 2nd sync char

            end

        end

        1:                                // but if looking for 1st or data ...

        begin

            if(((receivebuf ^ sync1)      // ... and 1st sync is found

                         & syncmask)===0)

            begin

                if(modreg[7]==0)          //     if double sync mode

                    sync_to_receive=2;    //         look for 2nd sync to follow

                else                      //     else look for 1st or data

                    status[6]=1;          //          and mark sync detected

            end

            else ;                        // ... and data was found, do nothing

        end

        endcase

 

        get_and_check_parity;    // reveive and check parity bit, if any

 

        mark_char_received;

    end

    endtask

 

 

 

    task get_and_check_parity;

    begin

        receivebuf=receivebuf >> (8-databits);

        if (modreg[4]==1)

        begin

            @(posedge rxc_)

            if((^receivebuf ^ modreg[5] ^ rcd) != 1)

                parity_error;

        end

    end

    endtask

 

 

    task mark_char_received;

    begin

        if (command[2]==1)       // if receiving is enabled

        begin

            rxrdy=1;

            status[1]=1;         //    set receive ready status bit

            if (rdatain==1)      //    if previous data was not read

                overrun_error;   //        overrun error

 

            rdata=receivebuf;    //    latch the data

            rdatain=1;           //    mark data as not having been read

        end

 

        if(dflags[2])

            $display("I8251A (%h) at %d: received data: %b",

                                               instance_id, $time, receivebuf);

    end

    endtask

 

 

          /************** ASYNCHRONOUS MODE RECEIVER **************/

 

 

 

                /* Check for break detection (rcd low through 2 */

                /* receive sequences) in the asynchronous mode. */

 

    always @ break_detect_e

    begin :break_detect_blk

        #1  /* to be sure break_delay_blk is waiting on break_deley_e

               after it triggered break_detect_e  */

 

        if(rcd==0)

        begin

            -> break_delay_e;//start + databits + parity    + stop bit

            breakcount_period =  1   + databits + modreg[4] + (tstoptotal != 0);

 

                    // the number of rxc periods needed for 2 receive sequences

            breakcount_period = 2 * breakcount_period * baudmx;

 

                                  // If rcd stays low through 2 consecutive

                                  // (start,data,parity,stop) sequences ...

            repeat(breakcount_period)

                @(posedge rxc_);

            status[6]=1;          // ... then set break detect (status[6]) high

        end

    end

 

    always @break_delay_e

    begin : break_delay_blk

        @(posedge rcd)            // but if rcd goes high during that time ...

        begin :break_delay_blk

            disable break_detect_blk;

            status[6]=0;          // ... then set the break detect low

            @(negedge rcd)        //     and when rcd goes low again ...

            -> break_detect_e;    //     ... start the break detection again

        end

    end

 

 

                /**** ASYNCHRONOUS MODE RECEIVE TASK ****/

 

    task asyn_receive;

    forever

        @(negedge rcd) // the receive line went to zero, maybe a start bit 

        begin

            rbaudcnt = baudmx / 2;

            if(baudmx==1)

                rbaudcnt=1;

            repeat(rbaudcnt) @(posedge rxc_); // after half a bit ...

 

            if (rcd == 0)                     // if it is still a start bit

            begin

                rbaudcnt=baudmx;

                repeat(databits)              //     receive the data bits

                begin

                    repeat(rbaudcnt) @(posedge rxc_);

                    #1 receivebuf= {rcd, receivebuf[7:1]};

                end

 

                repeat(rbaudcnt) @(posedge rxc_);

 

 

                // shift the data to the low part

                receivebuf=receivebuf >> (8-databits);

 

                if (modreg[4]==1)            // if parity is enabled

                begin

                    if((^receivebuf ^ modreg[5] ^ rcd) != 1)

                        parity_error;        //     check for a parity error

 

                    repeat(rbaudcnt) @(posedge rxc_);

                end

 

                #1 if (rcd==0)               // if middle of stop bit is 0

                    frame_error;             //     frame error (should be 1)

 

                mark_char_received;

            end

        end

    endtask

endmodule



 


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多