通用串行异步收发器8251的VerilogHDL源代码

 

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

通用串行异步收发器8251Verilog HDL源代码

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

 

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

       read_, rxrdy, txrdy, syndet, cts_, txe, txd, 

                  clk, reset, dsr_,rts_,dtr_,rxc_,vcc);

 

/* 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 cycle

 

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/rexeibe data bit rates

       gnd,

       vcc;

output  rxrdy, //receive data ready when high

txd,  //transmit data lone 

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;

 

//*****ADD BY FWN

reg [3:0] dflags;

reg [7:0] instance_id;

reg read,chipel_;

//*****

 

reg     recvdrv,    statusdrv;

 

// if recvdrv 1 dbus is driven by rdata

assign  dbus = recvdrv ? rdata : 8'bz; //*****:,->;

assign   dbus = statusdrv ? status : 8'bz ; //*****:->; assign abscent

 

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 lookinf for sync

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 wheb char was received

                            //    (and so char was sent before shutdown)

event   resete, start_receiver_e,hunt_sysnc1_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 data: %b",

                    instance_id, $time, receivebuf);

status[3]=1;

end

endtask

 

task overrun_error;

begin

if(dflags[4])

$display("I8251A (%h) at %d: *** oerrun 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 ready", 

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

end

 

always @dbus

begin

time_dbus_setup = $time;

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

$display("I8251A (%h) at %d: *** datahold 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 ( chipel_==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);

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);// lack of ;

 

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;         //  syndat is reset to output low

sync_to_transmit=1;  //transmit sync char #1 when sync are transmit

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 ready

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

begin 

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

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

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              //synchronous mode

begin

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'b11111110;

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 txtdy pin if command[0]

command=dbus;

dtr_= ! command[1];

 

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

                    assign txd=0;   // set txd=0  (ignores/override ***** only

                                    // candence synerngy support assign,deassign 

else             // later non-assign assignment

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

     // disasble the sync receiver

disable syn_receive_external;

 

receivebuf=8'hff;      //  reset receive 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,databits

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 its is not now cts

                       //but data was received while it was c

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 its is now cts

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

//but now yet ransmitted ...

->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;                        // mard transmitter as being empty

    txe=1;

if (tstoptotal !=0 || command[0] ==0 ||cts_ ==1)

      // if async mode or after areset 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 and make any writes 

tdata_out=1;            // go to tdata_hold

            repeat(baudmx) @(negedge txc_);

                ->txende;

        end

else                // if sync mode

case (sync_to_transmit)

1:

        begin

            tdata_out=sync1 >> (8-databits);

            tdata_out_wait=0;   // without waiting on negedge t

            tdata_out_full=1;

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

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

        end

2:

        begin

            tdata_out =sync2 >> (8-databits);

            tdata_out_wait =0 ;     // without waiting on negedge t

            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 *****add () 

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 abit 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 receive",

                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

                    @(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

        begin

            if(dflags[5])

                $display("I8251A (%h) at %d : starting external sync receive", 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)

            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

                                                // begore starting char assemble

                    disable external_syn_hunt_blk;

                join

            end

 

        syn_receive_external;   // start external sync mode receiving

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

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;   //receive and check parity bit, if any

        mark_char_received; //set rxrdy line, if enalbed

    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_sysnc1_e)    //search for 1st sync char in the data stream

begin :sync_hunt_blk

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

    begin

        @(posedge rxc_)

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

    end

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

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

    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'b0000_0000)

        ->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 ofr 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:

    begin

        if ((( receivebuf ^ sync1) & syncmask) ===0) // ... and 1st sync is found 

        begin

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

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

            else

                status[6]=1;    //else look for 1st or data and mark sync detected 

        end

        else;   //and data was found , do nothing

    end

    endcase

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

    mark_char_received;

end

endtask

 

 

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

task syn_receive_external;

forever

begin

// have not found the original programs

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;    //set receive read status bit

    status[1]=1;    //if previous data was not read

    if(rdatain == 1)

        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 : receive 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_clk is waiting on break_delay_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 sequence 

        breakcount_period  = 2* breakcount_period*baudmx;

        //if rcd stays low through 2 consecutive 

        // (start ,data,prity ,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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fpga和matlab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值