⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 8251_8055_verilog.txt

📁 8251和8055的verilog源码
💻 TXT
📖 第 1 页 / 共 4 页
字号:

/*****************************************************************************
通用串行异步收发器8251的Verilog 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 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -