📄 8251_8055_verilog.txt
字号:
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]. “商业化”的虚拟模块之二: Intel 8085a 微处理器的行为描述模块
/****************************************************************************
Intel 8085a 微处理器仿真模块的Verilog源代码
注意:作者不能保证本模块的完整和精确,使用本模块者如遇问题一切责任自负
*****************************************************************************/
module intel_8085a
(clock, x2, resetff, sodff, sid, trap, rst7p5, rst6p5, rst5p5,
intr, intaff, ad, a, s0, aleff, writeout, readout, s1,iomout,
ready, nreset, clockff, hldaff, hold);
reg [8:1] dflags;
initial dflags = 'b011;
// diag flags:
// 1 = trace instructions
// 2 = trace IN and OUT instructions
// 3 = trace instruction count
output
resetff, sodff, intaff, s0, aleff,
writeout, readout, s1, iomout, clockff, hldaff;
inout[7:0] ad, a;
input
clock, x2, sid, trap,
rst7p5, rst6p5, rst5p5,
intr, ready, nreset, hold;
reg[15:0]
pc, // program counter
sp, // stack pointer
addr; // address output
reg[8:0]
intmask; // interrupt mask and status
reg[7:0]
acc, // accumulator
regb, // general
regc, // general
regd, // general
rege, // general
regh, // general
regl, // general
ir, // instruction
data; // data output
reg
aleff, // address latch enable
s0ff, // status line 0
s1ff, // status line 1
hldaff, // hold acknowledge
holdff, // internal hold
intaff, // interrupt acknowledge
trapff, // trap interrupt request
trapi, // trap execution for RIM instruction
inte, // previous state of interrupt enable flag
int, // interrupt acknowledge in progress
validint, // interrupt pending
haltff, // halt request
resetff, // reset output
clockff, // clock output
sodff, // serial output data
read, // read request signal
write, // write request signal
iomff, // i/o memory select
acontrol, // address output control
dcontrol, // data output control
s, // data source control
cs, // sign condition code
cz, // zero condition code
cac, // aux carry condition code
cp, // parity condition code
cc; // carry condition code
wire
s0 = s0ff & ~haltff,
s1 = s1ff & ~haltff;
tri[7:0]
ad = dcontrol ? (s ? data : addr[7:0]) : 'bz,
a = acontrol ? addr[15:8] : 'bz;
tri
readout = acontrol ? read : 'bz,
writeout = acontrol ? write : 'bz,
iomout = acontrol ? iomff : 'bz;
event
ec1, // clock 1 event
ec2; // clock 2 event
// internal clock generation
always begin
@(posedge clock) -> ec1;
@(posedge clock) -> ec2;
end
integer instruction; // instruction count
initial instruction = 0;
always begin:run_processor
#1 reset_sequence;
fork
execute_instructions; // Instructions executed
wait(!nreset) // in parallel with reset
@ec2 disable run_processor; // control. Reset will
join // disable run_processor
end // and all tasks and
// functions enabled from
// it when nreset set to 0.
task reset_sequence;
begin
wait(!nreset)
fork
begin
$display("Performing 8085(%m) reset sequence");
read = 1;
write = 1;
resetff = 1;
dcontrol = 0;
@ec1 // synchronized with clock 1 event
pc = 0;
ir = 0;
intmask[3:0] = 7;
intaff = 1;
acontrol = 0;
aleff = 0;
intmask[7:5] = 0;
sodff = 0;
trapff = 0;
trapi = 0;
iomff = 0;
haltff = 0;
holdff = 0;
hldaff = 0;
validint = 0;
int = 0;
disable check_reset;
end
begin:check_reset
wait(nreset) // Check, in parallel with the
disable run_processor; // reset sequence, that nreset
end // remains at 0.
join
wait(nreset) @ec1 @ec2 resetff = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -