Sei sulla pagina 1di 26

// Serial port demo program

//
// Assumptions: 50Mhz clock rate

module SerDemo(input clk, output ser);


// Start signal tells it to start sending bits
reg start;

//The bits of data to send
reg [7:0] data;

/////////////////////////////////////////////////////////////////////////////
// Serial port clock generator
// Generate a 9600 baud clock signal for the serial port by dividing the
// 50Mhz clock by 5208

reg [14:0] clockdiv;

// Count from 0..5207 then reset back to zero
always @(posedge clk)
begin
if (clockdiv == 5207)
clockdiv <= 0;
else
clockdiv <= clockdiv + 1;
end

// The serclock is a short pulse each time we are reset
wire serclock = (clockdiv == 0);

/////////////////////////////////////////////////////////////////////////////
// Serial port state machine
// Only start the state machine when "start" is set. Only advance to the
// next state when serclock is set.

reg [3:0] state;

always @(posedge clk)
begin
case (state)
4'b0000: if (start) state <= 4'b0001;
4'b0001: if (serclock) state <= 4'b0010; // Start bit
4'b0010: if (serclock) state <= 4'b0011; // Bit 0
4'b0011: if (serclock) state <= 4'b0100; // Bit 1
4'b0100: if (serclock) state <= 4'b0101; // Bit 2
4'b0101: if (serclock) state <= 4'b0110; // Bit 3
4'b0110: if (serclock) state <= 4'b0111; // Bit 4
4'b0111: if (serclock) state <= 4'b1000; // Bit 5
4'b1000: if (serclock) state <= 4'b1001; // Bit 6
4'b1001: if (serclock) state <= 4'b1010; // Bit 7
4'b1010: if (serclock) state <= 4'b0000; // Stop bit
default: state <= 4'b0000; // Undefined, skip to stop
endcase
end


///////////////////////////////////////////////////////////////////////////////
// Serial port data
// Ensure that the serial port has the correct data on it in each state

reg outbit;

always @(posedge clk)
begin
case (state)
4'b0000: outbit <= 1; // idle
4'b0001: outbit <= 0; // Start bit
4'b0010: outbit <= data[0]; // Bit 0
4'b0011: outbit <= data[1]; // Bit 1
4'b0100: outbit <= data[2]; // Bit 2
4'b0101: outbit <= data[3]; // Bit 3
4'b0110: outbit <= data[4]; // Bit 4
4'b0111: outbit <= data[5]; // Bit 5
4'b1000: outbit <= data[6]; // Bit 6
4'b1001: outbit <= data[7]; // Bit 7
4'b1010: outbit <= 0; // Stop bit
default: outbit <= 1; // Bad state output idle
endcase
end

// Output register to pin
assign ser = outbit;

///////////////////////////////////////////////////////////////////////////////
// Test by outputting a letter 'd'

always @(posedge clk)
begin
data = 100;
start = 1;
end
endmodule
/*=================================================================*/
/*=== RS232 LIBRARY =============================================*/
/*=================================================================*/

/*
* FILE: RS232.v
* PROGRAMMER: William L. Bahn
*
* CONTENTS:
*
* NAMING CONVENTION:
*/

/*
* William L. Bahn
* FPGA-based RS-232 UART-Lite
*
* Digilent D2 Pin Assignments:
* RXD P202
* TXD P201
* RTS P195
* CTS P199
* DSR P200
*
* BAUD Bit Period Half-Period (cycles @ 50MHz)
* 9600 104.2 us 2604
* 19200 52.1 us 1302
* 38400 26.0 us 651
* 115200 8.68us 217
*/
/* This module operates completely synchronously with the system master
* clock. The following subsidiary waveforms are generated:
*
* BaudTick: A one-clock wide pulse that occurs at twice the Buad rate
* Baud: A square wave at the Baud rate. The BaudTick pulses occur
* at the end of each half of the Baud cycle.
* Sending: The UART is (or will be) sending data.
*
* When the SEND signal is received, a one-shot is fired if the UART is
* not already exporting data. If it is exporting data, the SEND signal
* is ignored. If it is acted upon, the one-shot that
*/
/* Instead of using a counter, the transmit event pipeline uses a second
* shift register that runs in parallel with the one containing the data
* but is loaded with 1's at the same time that the actual data is loaded
* into the data shift register except for the bit corresponding to the
* the Stop Bit. The serial output of the second shiftregister is used to
* decide if the data should still be shifted. All loads and shifts occur
* in conjuction with the rising edge of the Baud clock.
*/

/*
*=========================================================================
* RS-232 PACKET INTERFACE
*=========================================================================
*
* MODULE: RS232wPACKET()
*/

module RS232wPACKET(Test16, Test, ToOther, FromOther,
NoXonXoff, Escape,
Push, Pop,
PacketPushed, PacketPopped,
NoEcho, NoPackets, NoBytes, Full, Lost,
TXD, RXD, RTS, CTS, DSR, rst,
clk);

parameter LO = 1'b0, HI = 1'b1;

parameter WIDTH = 8;
parameter DEPTH = 16;
parameter LOG2DEPTH = 4;

output [15:0] Test; // Test Output Signals
output [15:0] Test16; // Test Output Signals
input [7:0] ToOther; // Data to be sent out RS-232
output [7:0] FromOther; // Data received from RS-232
input NoXonXoff; // Disable XonXoff Flow Control
output Escape; // Flag indicating an ESC character
input Push, Pop; // Push/Pop data to/from RS-232
input PacketPushed; // An outgoing packet is complete
input PacketPopped; // An incoming packet has been retrieved
input NoEcho; // Disable incoming data echo back
output NoPackets; // Input Packet Buffer has no complete
packets.
output NoBytes; // Input Packet Buffer is completely
empty
output Full; // Output Packet Buffer (to RS-232) is full
output Lost; // Indicates incoming data was
lost
input TXD, RTS; // RS-232 external signals
output RXD, CTS, DSR; // RS-232 external signals
input rst, clk; // Master reset and clock

// IPB = Input Packet Buffer
// OPB = Outpuer Packet Buffer
// UART = UART

// Internal Data Path
wire [7:0] UART_FromOther, IPB_DataIn;
wire [7:0] OPB_DataOut, UART_ToOther;

// Control
wire UART_FF, UART_EF;
wire UART_Push, UART_Pop;
wire IPB_Push, IPB_Pop;
wire OPB_Push, OPB_Pop;
wire IPB_FF, IPB_AF, IPB_HF, IPB_AE, IPB_EF;
wire OPB_FF, OPB_AF, OPB_HF, OPB_AE, OPB_EF;
wire IPB_PacketPushed, OPB_PacketPopped;
wire [(LOG2DEPTH-1):0] IPB_Lines, OPB_Lines;

// Glue Logic
assign NoPackets = ((IPB_Lines == 0)? HI : LO);
assign OPB_NoPackets = ((OPB_Lines == 0)? HI : LO);
assign NoBytes = IPB_EF;
assign Full = OPB_FF;
assign IPB_Pop = Pop;
assign OPB_Push = Push;

// Test Signal Assignments
assign Test[0] = UART_EF;
assign Test[1] = UART_FF;
assign Test[2] = UART_Push;
assign Test[3] = UART_Pop;
assign Test[4] = PacketPushed;
assign Test[5] = PacketPopped;
assign Test[6] = IPB_PacketPushed;
assign Test[7] = OPB_PacketPopped;
assign Test[8] = NoBytes;
assign Test[9] = IPB_FF;
assign Test[10] = OPB_EF;
assign Test[11] = Escape;
assign Test[12] = IPB_Push;
assign Test[13] = IPB_Pop;
assign Test[14] = OPB_Push;
assign Test[15] = OPB_Pop;

// Structural Definition
RS232wECHO UARTwE
(
.Test16(Test16),
.ToOther(UART_ToOther), .FromOther(UART_FromOther),
.NoXonXoff(NoXonXoff), .Escape(Escape),
.Push(UART_Push), .Pop(UART_Pop), .NoEcho(NoEcho),
.Empty(UART_EF), .Full(UART_FF), .Lost(Lost),
.TXD(TXD), .RXD(RXD), .RTS(RTS), .CTS(CTS), .DSR(DSR),
.rst(rst), .clk(clk)
);

PacketBuffer16 PACK_IN
(
.DataOut(FromOther), .DataIn(IPB_DataIn),
.PacketIn(IPB_PacketPushed), .PacketOut(PacketPopped),
.Lines(IPB_Lines),
.FF(IPB_FF), .AF(IPB_AF), .HF(IPB_HF), .AE(IPB_AE),
.EF(IPB_EF),
.Push(IPB_Push), .Pop(IPB_Pop),
.Dump(rst), .Clk(clk)
);

RS232_PACKET_CTLR_R RCTL
(
.OutputData(IPB_DataIn), .InputData(UART_FromOther),
.Push(IPB_Push), .Pop(UART_Pop),
.PacketPushed(IPB_PacketPushed), .Full(IPB_FF),
.Empty(UART_EF)
);

PacketBuffer16 PACK_OUT
(
.DataOut(OPB_DataOut), .DataIn(ToOther),
.PacketIn(PacketPushed), .PacketOut(OPB_PacketPopped),
.Lines(OPB_Lines),
.FF(OPB_FF), .AF(OPB_AF), .HF(OPB_HF), .AE(OPB_AE),
.EF(OPB_EF),
.Push(OPB_Push), .Pop(OPB_Pop),
.Dump(rst), .Clk(clk)
);

RS232_PACKET_CTLR_T TCTL
(
.OutputData(UART_ToOther), .InputData(OPB_DataOut),
.Push(UART_Push), .Pop(OPB_Pop),
.PacketPopped(OPB_PacketPopped),
.NoPackets(OPB_NoPackets), .Full(UART_FF), .Empty(OPB_EF)
);


endmodule

/*
*=========================================================================
* RS-232 RECEIVE PACKET CONTROLLER
*=========================================================================
*
* MODULE: RS232_PACKET_CTLR_R()
*
* The receive-side controller handles traffic coming from the RS-232 UART
* and transfers the characters to the Output Packet Buffer with the
* following modifications:
*
* CR characters are discarded.
* LF characters are replaced by NUL characters.
* A 'PacketPushed' is asserted when the NUL character is pushed.
*
* The 'NoPackets' output from the controller means that no complete packets
* are contained in the Output Packet Buffer while a 'NoBytes' output means
* that the Output Packet Buffer is completely empty.
*
* The controller gates the transfer of characters when the Packet Buffer is
* full. If this happens when there are no complete lines in the buffer and
* when the higher level logic is waiting for a complete line, this will
* cause a Packet Buffer Stall.
*
*/

module RS232_PACKET_CTLR_R
(
OutputData, InputData, Push, Pop, PacketPushed, Full, Empty
);

parameter LO = 1'b0, HI = 1'b1;
parameter
NUL = 8'h00,
LINEFEED = 8'h0A,
CARRIAGE_RETURN = 8'h0D,
ESCAPE = 8'h1B;

output [7:0] OutputData; // Data to Input Packet Buffer
input [7:0] InputData; // Data from UART
output Push; // Push command
to Input Packet Buffer
output Pop; // Pop
command to UART
output PacketPushed; // Complete packet has been
transferred
input Full; // FF from Input
Packet Buffer
input Empty; // EF from UART Receive Buffer

reg Packet, Keep;
reg [7:0] OutputData;
wire Transfer;

assign Transfer = (((Full == LO)&&(Empty == LO))? HI : LO);

always @ (InputData)
begin
case (InputData)
LINEFEED:
begin
OutputData <= NUL;
Packet <= HI;
Keep <= HI;
end
CARRIAGE_RETURN:
begin
OutputData <= NUL;
Packet <= LO;
Keep <= LO;
end
default:
begin
OutputData <= InputData;
Packet <= LO;
Keep <= HI;
end
endcase
end

assign PacketPushed = ((Transfer == HI)? Packet : LO);
assign Push = ((Transfer == HI)&&(Keep == HI));
assign Pop = Transfer;

endmodule

/*
*=========================================================================
* RS-232 OUTPUT PACKET CONTROLLER
*=========================================================================
*
* MODULE: RS232_PACKET_CTLR_T()
*
* The transmit-side controller handles traffic coming from Output Packet
* Buffer destined for the RS-232 UART and transfers the characters to the
* UART with following modifications:
*
* NUL characters are discarded.
* A 'PacketPopped' is asserted when the NULL character is popped.
*
* The controller sits IDLE until it is sensed that a complete packet in
* the Output Packet Buffer. It then commences transferring characters to
* the UART until the NUL character is encountered.
*
* The controller gates the transfer of characters when the UART's buffer is
* full.
*/

module RS232_PACKET_CTLR_T (OutputData, InputData,
Push, Pop, PacketPopped,

NoPackets, Full, Empty);

parameter LO = 1'b0, HI = 1'b1;
parameter
NUL = 8'h00,
LINEFEED = 8'h0A,
CARRIAGE_RETURN = 8'h0D,
ESCAPE = 8'h1B;

output [7:0] OutputData; // Data to Input Packet Buffer
input [7:0] InputData; // Data from UART
output Push; // Push command
to Input Packet Buffer
output Pop; // Pop
command to UART
output PacketPopped; // Complete packet has
been transferred
input NoPackets; // Output Packet Buffer has no packets
input Full; // FF from UART
Transmit Buffer
input Empty; // EF from Output Packet Buffer

reg Packet, Keep;
reg [7:0] OutputData;
wire Transfer;

assign Transfer = (( (NoPackets == LO)
&&(Full == LO)
&&(Empty == LO) )? HI
: LO);

always @ (InputData)
begin
case (InputData)
NUL:
begin
OutputData <= NUL;
Packet <= HI;
Keep <= LO;
end
default:
begin
OutputData <= InputData;
Packet <= LO;
Keep <= HI;
end
endcase
end

assign PacketPopped = ((Transfer == HI)? Packet : LO);
assign Push = ((Transfer == HI)&&(Keep == HI));
assign Pop = Transfer;

endmodule

module RS232wECHO
(
Test16, ToOther, FromOther, NoXonXoff, Escape, Push, Pop, NoEcho,
Empty, Full, Lost, TXD, RXD, RTS, CTS, DSR, rst, clk
);

parameter LO = 1'b0, HI = 1'b1;
parameter XON = 8'h11;
parameter XOFF = 8'h13;

output [15:0] Test16;
input [7:0] ToOther; // Data to be sent out RS-232
output [7:0] FromOther; // Data received from RS-232
input NoXonXoff; // Disable XonXoff Flow Control
output Escape; // Flag indicating an ESC character
input Push, Pop; // Push/Pop data to/from RS-232
input NoEcho; // Disable incoming data echo back
output Empty; // FIFO coming from RS-232 is empty
output Full; // FIFO going to RS-232 is full
output Lost; // Indicated incoming data was
lost
input TXD, RTS; // RS-232 external signals
output RXD, CTS, DSR; // RS-232 external signals
input rst, clk; // Master reset and clock

// Internal Data Path
wire [7:0] ToOther_C;
wire [7:0] Transmit, Received;

// Control
wire PO_FF, PI_EF;
wire CI_FF, CI_AF, CI_HF, CI_AE ;
wire CO_AF, CO_HF, CO_AE, CO_EF;
wire Transfer_CT, Transfer_PT, Transfer_R;
wire Pop_PHY, Push_PHY, Pop_CORE, Push_CORE;
wire MuxEcho;

wire _CTS, _DSR;
//assign CTS = RTS;
//assign DSR = HI;
wire [1:0] Test;
assign CTS = Test[0];
assign DSR = Test[1];

wire Drop;
RS232wFIFO PHY
(
.Test16(Test16),
.ToOther(Transmit), .FromOther(Received),
.NoXonXoff(NoXonXoff), .Escape(Escape),
.Push(Push_PHY), .Pop(Pop_PHY),
.Empty(PI_EF), .Full(PO_FF), .Lost(Lost),
.TXD(TXD), .RXD(RXD), .RTS(RTS), .CTS(_CTS), .DSR(_DSR),
.rst(rst), .clk(clk)
);

assign Drop = ((Received == XON)||(Received == XOFF))? HI : LO;

RS232_ECHO_CTLR ECHO
(
.Test(Test), .Drop(Drop),
.Pop_PHY(Pop_PHY), .Push_PHY(Push_PHY),
.Pop_CORE(Pop_CORE), .Push_CORE(Push_CORE),
.MuxEcho(MuxEcho), .NoEcho(NoEcho),
.PI_EF(PI_EF), .PO_FF(PO_FF), .CI_FF(CI_FF), .CO_EF(CO_EF)
);

FIFO16x8 CORE_OUT // Data going from FPGA to HOST
(
.DataOut(ToOther_C), .DataIn(ToOther),
.FF(Full), .AF(CO_AF), .HF(CO_HF), .AE(CO_AE), .EF(CO_EF),
.Push(Push), .Pop(Pop_CORE), .Dump(rst), .Clk(clk)
);

FIFO16x8 CORE_IN // Data coming from HOST to FPGA
(
.DataOut(FromOther), .DataIn(Received),
.FF(CI_FF), .AF(CI_AF), .HF(CI_HF), .AE(CI_AE), .EF(Empty),
.Push(Push_CORE), .Pop(Pop), .Dump(rst), .Clk(clk)
);

MUX2x8 ECHOSWITCH
(
.Q(Transmit), .D1(Received), .D0(ToOther_C), .Sel(MuxEcho)
);

endmodule

/*
* RS-232 Echo Controller
*
* This module controls the transfers between the Physical Layer FIFO's and
* the FIFO's that the User sees at the core interface. There are two types
* of transfers - Outgoing transfers that move data from the Core Layer's
* Outgoing FIFO to the Physical Layer's Outgoing FIFO and Incoming transfers
* that move data from the Physical Layer's Incoming FIFO to the Core Layer's
* Incoming FIFO. An incoming transfer can also cause a copy of the data from
* the to be Physical Layer's Incoming FIFO to be pushed into the Physical
* Layer's Outgoing FIFO if the Echo bit is asserted.
*
* To simplify the control logic, Incoming and Outgoing transfers are
serviced
* in a mutually exclusive mode and are only serviced if all of the
conditions
* necessary to complete a transfer are present. Since transfers where not
all
* of the conditions are met are not performed at all, they may be performed
* later once all of the conditions are met. This ensures that no data is
lost
* internally and, as long as the FIFO's that accept external data do not
* overflow, no data will be lost at all.
*
* The conditions that must be met to declare a pending transfer are:
*
* Outgoing Transfer:
* The Core Layer Outgoing FIFO must not be empty.
* The Physical Layer Outgoing FIFO must not be full.
*
* Incoming Transfer:
* The Physical Layer Incoming FIFO must not be empty.
* The Core Layer Incoming FIFO must not be full.
* If the Echo bit is asserted:
* The Physical Layer Outgoing FIFO must not be full.
*
* While both types of transfers can be pending at the same time, the
Incoming
* Transfer has priority.
*
*/

module RS232_ECHO_CTLR (Test, Pop_PHY, Push_PHY, Pop_CORE, Push_CORE,
MuxEcho, Drop, NoEcho, PI_EF, PO_FF, CI_FF, CO_EF);

parameter LO = 1'b0, HI = 1'b1;

output [1:0] Test;
output Push_PHY, Pop_PHY, Push_CORE, Pop_CORE, MuxEcho;
input NoEcho, Drop;
input PO_FF, PI_EF, CI_FF, CO_EF;

reg MuxEcho;
reg Push_PHY, Pop_PHY;
reg Push_CORE, Pop_CORE;

wire Pending_T, Pending_R;
assign Pending_T = (CO_EF==LO)&&(PO_FF==LO);
assign Pending_R =
(PI_EF==LO)&&(CI_FF==LO)&&((NoEcho==LO)?(PO_FF==LO):HI);

assign Test[0] = MuxEcho;
assign Test[1] = Pop_PHY;

always @ (Pending_R or Pending_T or Drop or NoEcho)
begin
if (Pending_R == HI) // Transfer from PHY to CORE
begin
Pop_CORE <= LO;
Pop_PHY <= HI;
if (Drop == LO)
begin // Keep the character
MuxEcho <= ~NoEcho;
Push_PHY <= ~NoEcho;
Push_CORE <= HI;
end
else
begin // Drop the character
MuxEcho <= LO;
Push_PHY <= LO;
Push_CORE <= LO;
end
end
else if (Pending_T == HI) // Transfer from CORE to PHY
begin
MuxEcho <= LO;
Pop_CORE <= HI;
Push_PHY <= HI;
Pop_PHY <= LO;
Push_CORE <= LO;
end
else
begin // No Traffic
MuxEcho <= LO;
Pop_CORE <= LO;
Push_PHY <= LO;
Pop_PHY <= LO;
Push_CORE <= LO;
end
end

endmodule

/*
*=========================================================================
* RS232 INTERFACE WITH FIFO
*=========================================================================
*
* This module brings together the Physical Layer module and adds an input
* and an output FIFO plus a controller to handle the interaction.
*
* Because there is now the potential for the Receive FIFO to fill up, the
* module looks for an ESC character and takes the 'Escape' output HI
* if it is detected. This output is NOT latched, meaning that the higher
* level logic must be ready to act upon it at all times. The ESC character
* is also handled normally like any other character as far as being placed
* in the data stream is concerned.
*
*/

module RS232wFIFO(Test16, ToOther, FromOther,
NoXonXoff, Escape, Push, Pop, Empty, Full, Lost, TXD, RXD, RTS, CTS, DSR,
rst, clk);

parameter LO = 1'b0, HI = 1'b1;
parameter ESCAPE = 8'h1B;

output [15:0] Test16;
input [7:0] ToOther;
output [7:0] FromOther;
output Escape;
input NoXonXoff; // Disable XonXoff Flow Control
input Push, Pop;
output Empty, Full, Lost;
input TXD, RTS;
output RXD, CTS, DSR;
input rst, clk;

wire [7:0] Transmit, Received;
wire FF_I, AF_I, HF_I, AE_I;
wire AF_O, HF_O, AE_O, EF_O;
wire Push_I;
wire Pop_O;

wire _CTS, _DSR;
assign CTS = RTS;
assign DSR = HI;

assign Escape = ((Received == ESCAPE)? HI : LO);
wire [7:0] NormalData;

RS232PHY PHY
(
.ToDTE(Transmit), .FromDTE(Received), .Send(Send),
.Sending(Sending), .Receiving(Receiving),
.TXD(TXD), .RXD(RXD), .RTS(RTS), .CTS(_CTS), .DSR(_DSR),
.rst(rst), .clk(clk)
);

FIFO16x8 FIFO_IN
(
.DataOut(FromOther), .DataIn(Received),
.FF(FF_I), .AF(AF_I), .HF(HF_I), .AE(AE_I), .EF(Empty),
.Push(Push_I), .Pop(Pop), .Dump(rst), .Clk(clk)
);

FIFO16x8 FIFO_OUT
(
.DataOut(NormalData), .DataIn(ToOther),
.FF(Full), .AF(AF_O), .HF(HF_O), .AE(AE_O), .EF(EF_O),
.Push(Push), .Pop(Pop_O), .Dump(rst), .Clk(clk)
);

wire Suspend;
wire BypassRequest, Bypass;
wire [7:0] BypassData;

assign Transmit = (Bypass == HI)? BypassData : NormalData;

RS232_XON_XOFF_CTLR XONOFF
(
.Test8(Test16[15:8]),
.NoXonXoff(NoXonXoff),
.ReceivedData(Received),
.Suspend(Suspend),
.TX_AF(AF_O), .TX_AE(AE_O), // was .TX_AE(AF_O),
.RX_AF(AF_I), .RX_AE(AE_I), // was .RX_AE(AF_I),
.BypassRequest(BypassRequest),
.BypassData(BypassData),
.Bypass(Bypass),
.rst(rst), .clk(clk)
);
wire [7:0] TestTemp;
RS232_TRANSMIT_CTLR TXCTLR
(
//.Test8(Test16[7:0]),
.Test8(TestTemp),
.Send(Send), .Pop(Pop_O), .Empty(EF_O), .Busy(Sending),
.Suspend(Suspend), .BypassRequest(BypassRequest),
.Bypass(Bypass),
.rst(rst), .clk(clk)
);

RS232_RECEIVE_CTLR RXCTLR
(
.Push(Push_I), .Lost(Lost), .Full(FF_I), .Busy(Receiving),
.rst(rst), .clk(clk)
);

assign Test16[7] = Full;
assign Test16[6] = AF_O;
//assign TestTemp[5] = HF_O;
assign Test16[5] = AE_O;
assign Test16[4] = EF_O;
assign Test16[3] = FF_I;
assign Test16[2] = AF_I;
//assign TestTemp[0] = HF_I;
assign Test16[1] = AE_I;
assign Test16[0] = Empty;

endmodule

/*
*=========================================================================
* RS-232 SOFTWARE FLOW CONTROL (Xon/Xoff) CONTROLLER
*=========================================================================
*
* MODULE: RS232_XON_XOFF_CTLR()
*
* This module processes the necessary data and produces the necessary
* signals to effect bidirectional software flow control. In order to
* avoid a situation in which both the HOST and the FPGA "simultaneously"
* block each other and hence can't send the signal to unblock the other,
* The transmission and reception of Xon/Xoff codes are nonblockable.
*
* HOST -> FPGA Flow Control
*
* This involves detecting Xon/Xoff characters sent by the HOST and asserting
* the Suspend flag to the Physical Layer Transmit Module accordingly.
*
* FPGA -> HOST Flow Control
*
* This involves detecting when the receive FIFO is near the ends of its
* capacity (either almost full or almost empty) and sending Xon/Xoff codes
* to the HOST as appropriate.
*
* When the HOST is unblocked (as tracked by an internal register) and the
* input FIFO is almost full, an Xoff code is sent to the HOST which places
* it in a blocked state. It remains this way until the FIFO is almost empty
* at which time an Xon code is sent which unblocks it.
*
* In order to make sure that only one code is sent, a handshaking protocol
* is used to bypass the normal transmission pipeline.
*
* Event Pipeline
* The XonXoff Controller starts in the Unblocked State.
* The Input FIFO raises its AE flag.
* The XonXoff Controller enters the Blocking state.
* The XonXoff Controller sets the BypassData to XOFF.
* The XonXoff Controller asserts the BypassRequest flag.
* The TX Controller asserts the Bypass flag.
* The XonXoff Controller relaxes the BypassRequest flag.
* The XonXoff Controller enters the Blocked state.
* The Input FIFO raises its AE flag (AE has already
fallen).
* The XonXoff Controller enters the Unblocking state.
* The XonXoff Controller sets the BypassData to XOFF.
* The XonXoff Controller asserts the BypassRequest flag.
* The TX Controller asserts the Bypass flag.
* The XonXoff Controller relaxes the BypassRequest flag.
* The XonXoff Controller enters the Unblocked.
*

*
* Upon a reset event, the FIFOs are cleared, the suspend flag is cleared,
* and the HOST is assumed to be unblocked.
*/

module RS232_XON_XOFF_CTLR
(
Test8,
NoXonXoff,
ReceivedData, Suspend,
TX_AF, TX_AE,
RX_AF, RX_AE,
BypassRequest, BypassData,
Bypass,
rst, clk
);

output [7:0] Test8;
input NoXonXoff; // Disable XonXoff Flow Control
input [7:0] ReceivedData; // Data from UART RX PHY
output Suspend; // Suspend command to UART TX CONTROLLER
input TX_AF, TX_AE; // Transmit FIFO Status Flags
input RX_AF, RX_AE; // Receive FIFO Status Flags
output BypassRequest; // Bypass Request to UART TX CONTROLLER
output [7:0] BypassData; // Bypass Data to UART TX PHY
input Bypass; // Bypass Acknowledgement from UART TX
CONTROLLER
input rst, clk; // Master clock and reset

parameter LO = 1'b0, HI = 1'b1;
parameter XON = 8'h11;
parameter XOFF = 8'h13;

reg [7:0] BypassData;
reg BypassRequest;
reg Suspend;

// Blocking FPGA Transmission based on Xon/Xoff codes from HOST
always @ (posedge clk)
begin
if (rst == 1)
Suspend <= LO;
else if (NoXonXoff == HI)
Suspend <= LO;
else if (ReceivedData == XOFF)
Suspend <= HI;
else if (ReceivedData == XON)
Suspend <= LO;
else
Suspend <= Suspend;
end

// Sending Xon/Xoff codes to HOST based on status of Input FIFO
parameter
S_UNBLOCKED = 2'b00,
S_BLOCKING = 2'b01,
S_BLOCKED = 2'b10,
S_UNBLOCKING = 2'b11;

// These FF's are HI if the HOST is cleared to send
wire Host_CTS, TX_CTSb, RX_CTSb;

RSFF FF_TX (.Q(TX_CTSb), .S(TX_AF), .R(TX_AE), .rst(rst), .clk(clk));
RSFF FF_RX (.Q(RX_CTSb), .S(RX_AF), .R(RX_AE), .rst(rst), .clk(clk));
assign Host_CTS = ((TX_CTSb == LO)&&(RX_CTSb == LO))? HI : LO;
//assign Host_CTS = (RX_NCTS == LO)? HI : LO;

// Xon/Xoff State Machine
reg [1:0] State;
reg [1:0] Next_State;

always @ (posedge clk)
begin
if ((NoXonXoff == HI)||(rst == 1))
State <= S_UNBLOCKED;
else
State <= Next_State;
end

always @ (State or RX_AF or RX_AE or Bypass or Host_CTS)
begin
case (State)
S_UNBLOCKED:
begin
BypassData = XON;
BypassRequest = LO;
Next_State = (Host_CTS == LO)?
S_BLOCKING : State;
end
S_BLOCKING:
begin
BypassData = XOFF;
BypassRequest = HI;
Next_State = (Bypass == HI)? S_BLOCKED
: State;
end
S_BLOCKED:
begin
BypassData = XOFF;
BypassRequest = LO;
Next_State = (Host_CTS == HI)?
S_UNBLOCKING : State;
end
S_UNBLOCKING:
begin
BypassData = XON;
BypassRequest = HI;
Next_State = (Bypass == HI)?
S_UNBLOCKED : State;
end
default:
begin
BypassData = XON;
BypassRequest = LO;
Next_State = S_UNBLOCKED;
end
endcase
end

assign Test8[7] = RX_AE;
assign Test8[6] = RX_AF;
assign Test8[5] = Bypass;
assign Test8[4] = Suspend;
assign Test8[3] = NoXonXoff;
assign Test8[2] = BypassRequest;
assign Test8[1] = State[1];
assign Test8[0] = State[0];

endmodule

module RS232_TRANSMIT_CTLR
(
Test8, Send, Pop, Empty, Busy,
Suspend, BypassRequest, Bypass,
rst, clk

);

parameter LO = 1'b0, HI = 1'b1;

output [7:0] Test8;
output Send, Pop;
input Empty, Busy, rst, clk;
input Suspend, BypassRequest;
output Bypass;

parameter
IDLE = 2'b00,
INIT = 2'b01,
POP = 2'b10,
BUSY = 2'b11;

reg [1:0] State;
reg [1:0] Next_State;

reg BypassSend, Next_BypassSend;

always @ (posedge clk)
begin
if (rst == 1)
begin
State <= IDLE;
BypassSend <= LO;
end
else
begin
State <= Next_State;
BypassSend <= Next_BypassSend;
end
end

reg Send_int, Pop_int;

assign Send = Send_int;
assign Pop = Pop_int;
assign Bypass = BypassSend;

always @
(
State or Empty or Busy or Suspend or
BypassSend or BypassRequest
)
begin
case (State)
IDLE:
begin
Send_int = LO;
Pop_int = LO;
Next_BypassSend = BypassRequest;
if (BypassRequest == HI)
Next_State = INIT;
else if (Suspend == HI)
Next_State = IDLE;
else if (Empty == LO)
Next_State = INIT;
else
Next_State = State;
end
INIT:
begin
Send_int = HI;
Pop_int = LO;
Next_BypassSend = BypassSend;
Next_State = (Busy == HI)? POP:INIT;
end
POP:
begin
Send_int = LO;
Pop_int = (BypassSend)? LO : HI;
Next_BypassSend = BypassSend;
Next_State = BUSY;
end
BUSY:
begin
Send_int = LO;
Pop_int = LO;
Next_BypassSend = BypassSend;
Next_State = (Busy == LO)? IDLE:BUSY;
end
default:
begin
Send_int = LO;
Pop_int = LO;
Next_BypassSend = BypassSend;
Next_State = IDLE;
end
endcase
end

assign Test8[7] = Send_int;
assign Test8[6] = Pop_int;
assign Test8[5] = BypassRequest;
assign Test8[4] = Bypass;
assign Test8[3] = Next_State[1];
assign Test8[2] = Next_State[0];
assign Test8[1] = State[1];
assign Test8[0] = State[0];

endmodule

module RS232_RECEIVE_CTLR (Push, Lost, Full, Busy, rst, clk);

parameter LO = 1'b0, HI = 1'b1;

output Push, Lost;
input Full, Busy, rst, clk;

parameter
IDLE = 2'b00,
BUSY = 2'b01,
PUSH = 2'b10;

reg [1:0] State;
reg [1:0] Next_State;

always @ (posedge clk)
begin
if (rst == 1)
State <= IDLE;
else
State <= Next_State;
end

reg Push_int, Lost_int;

assign Lost = Lost_int;
assign Push = Push_int;

always @ (State or Busy or Full)
begin
case (State)
IDLE:
begin
Lost_int = LO;
Push_int = LO;
Next_State = (Busy == HI)? BUSY:IDLE;
end
BUSY:
begin
Lost_int = LO;
Push_int = LO;
Next_State = (Busy == LO)? PUSH:BUSY;
end
PUSH:
begin
Lost_int = (Full == HI)? HI:LO;
Push_int = (Full == LO)? HI:LO;
Next_State = IDLE;
end
default:
begin
Lost_int = LO;
Push_int = LO;
Next_State = IDLE;
end
endcase
end

endmodule

/*
*=========================================================================
* RS232 PHYSICAL LAYER IMPLEMENTATION
*=========================================================================
*/
module RS232PHY(ToDTE, FromDTE, Send, Sending, Receiving, TXD, RXD, RTS, CTS,
DSR, rst, clk);

parameter LO = 1'b0, HI = 1'b1;

input [7:0] ToDTE;
output [7:0] FromDTE;
input Send;
output Sending, Receiving;
input TXD, RTS;
output RXD, CTS, DSR;
input rst, clk;

wire [3:0] rate; // Baud Rate Selector
wire b, b_r, b_f; // Baud clock, rising edge, falling edge
wire b2, b2_r, b2_f; // 2x Baud clock, rising edge, falling edge
assign rate = 4'd9; // Selects 115200 baud

//assign CTS = RTS;
//assign DSR = HI;

assign CTS = Receiving;
assign DSR = Sending;

RS232BAUDCLK BAUD
(
.b(b), .b2(b2),
.b_r(b_r), .b_f(b_f), .b2_r(b2_r), .b2_f(b2_f), .rate(rate),
.rst(rst), .clk(clk)
);

RS232TXPHY TXPHY
(
.SerialOut(RXD), .DataIn(ToDTE), .Send(Send),
.Sending(Sending),
.b_r(b_r), .rst(rst), .clk(clk)
);

RS232RXPHY RXPHY
(
.SerialIn(TXD), .DataOut(FromDTE), .Receiving(Receiving),
.b(b), .b2_r(b2_r), .b2_f(b2_f), .rst(rst), .clk(clk)
);

endmodule

/*
*=========================================================================
* RS232 TRANSMITTER PHYSICAL LAYER IMPLEMENTATION
*=========================================================================
* This module is used to generate and send single packets of serialized
* data over an RS-232 serial link.
*
* The User should query the status of the Sending bit before asserting
* the Send command since such commands will be ignored if the Sending bit
* is already HI. Another approach is to assert the Send bit and the look
* for a rising edge of Sending after that as an acknowledgement.
*
* Upon receiving an actionable Send command, the DataIn is captured so
* that the User can set up for the next data value if desired. The Send
* but must be relaxed and reasserted for every data value to be sent.
*
* SendCmd - HI when Send is asserted and not already Sending
* SendFlag - HI from valid SendCmd until Sending actually starts
* SendLoad - HI for first clock cycle of SendCmd
* Sending - HI from first rising baud clock edge
*
*/

module RS232TXPHY(SerialOut, DataIn, Send, Sending, b_r, rst, clk);

parameter LO = 1'b0, HI = 1'b1;

output SerialOut;
input [7:0] DataIn;
input Send;
input b_r, rst, clk;
output Sending;

// Send Trigger
wire SendCmd;
wire SendFlag;
wire SendLoad;
wire Sending;

// Transmit Shift Registers
wire [9:0] QTX, QTXTR;
wire TXshift, TXout;
wire [9:0] TXpacket, TXtrack;
wire [7:0] Data;
wire TXtrackSO;

assign SendCmd = ((Send==HI)&&(Sending==LO));
assign SendLoad = ((Send==HI)&&(SendFlag==LO));

OneShot SendTrap
(
.Q(SendFlag), .Start(SendCmd), .Stop(Sending),
.rst(rst), .clk(clk)
);

assign SendInit = ((SendFlag==HI)&&(b_r==HI));
assign SendDone = ((Sending==HI)&&(TXtrackSO==LO)&&(b_r==HI));

OneShot MMVTX
(
.Q(Sending), .Start(SendInit), .Stop(SendDone),
.rst(rst), .clk(clk)
);

Reg8 TXREG
(
.Q(Data), .D(DataIn),
.en(SendLoad), .rst(rst), .clk(clk)
);

assign TXpacket = {HI,Data,LO};
assign TXtrack = {LO,8'b11111111,HI};
assign TXshift = ((TXtrackSO==HI)&&(b_r==HI));
assign SerialOut = (Sending==HI)? TXout : HI;

ShiftReg10 TXSR
(
.Sout(TXout), .Sin(HI),
.Q(QTX), .D(TXpacket),
.Shift(TXshift), .Load(SendInit),
.rst(rst), .clk(clk)
);

ShiftReg10 TXTR
(
.Sout(TXtrackSO), .Sin(LO),
.Q(QTXTR), .D(TXtrack),
.Shift(TXshift), .Load(SendInit),
.rst(rst), .clk(clk)
);

endmodule

/*
*=========================================================================
* RS232 RECEIVER PHYSICAL LAYER IMPLEMENTATION
*=========================================================================
* The data on TXD is buffered because it is asynchronous to the master
* clock. This ensures that the data used by the various parts of the
* logic is consistent and has no setup/hold time issues.
*
* RecInit is asserted with the first rising edge of the Baud2 clk
* following the beginning of the Start Bit. This signal is used to
* fire a one-shot that determines the Receiving bit. At the same time,
* the phase of the Baud clk is captured and a pattern of all 1's is
* placed in the receiver's tracking shift register.
*
* As long as the receiver is in the receiving mode, the bits are shifted
* in with every falling edge of the Baud2 clock that is on the proper
* phase of the Baud clk.
*
* The tracking register's serial output is used to detect when shifting
* should cease, which is with the first rising edge of the Baud2 clk
* that occurs after a LO has been shifted into the serial output of the
* tracking register.
*
*/

module RS232RXPHY(SerialIn, DataOut, Receiving, b, b2_r, b2_f, rst, clk);

parameter LO = 1'b0, HI = 1'b1;

input SerialIn;
output [7:0] DataOut;
input b, b2_r, b2_f, rst, clk;
output Receiving;

// Receive Trigger
wire Phase;
wire [9:0] RXpacket, RXtrack;
assign RXtrack = {HI,8'b11111111,HI};
wire RXout, RXtrackSO;

wire RecInit;
wire RecDone;
wire Receiving;
wire TXin;

DFFRen TX_IN
(
.Q(TXin), .D(SerialIn),
.en(HI), .rst(rst), .clk(clk)
);

assign RecInit = ((TXin == LO)&&(Receiving == LO)&&(b2_r== HI));
assign RecDone = ((Receiving == HI)&&(RXtrackSO == LO)&&(b2_r== HI));

DFFRen PHASE
(
.Q(Phase), .D(~b),
.en(RecInit), .rst(rst), .clk(clk)
);

OneShot MMVRX
(
.Q(Receiving), .Start(RecInit), .Stop(RecDone),
.rst(rst), .clk(clk)
);

// Receive Shift Registers
wire [9:0] QRX, QRXTR;
wire RXshift;
assign QRX = 10'b0;

assign RXshift = ((RXtrackSO == HI)&&(b==Phase)&&(b2_f==HI));

ShiftReg10 RXSR
(
.Sout(RXout), .Sin(TXin),
.Q(RXpacket), .D(QRX),
.Shift(RXshift), .Load(RecInit),
.rst(rst), .clk(clk)
);

ShiftReg10 RXTR
(
.Sout(RXtrackSO), .Sin(LO),
.Q(QRXTR), .D(RXtrack),
.Shift(RXshift), .Load(RecInit),
.rst(rst), .clk(clk)
);

Reg8 RXREG
(
.Q(DataOut), .D(RXpacket[8:1]),
.en(RecDone), .rst(rst), .clk(clk)
);

endmodule

/*
*=========================================================================
* BAUD RATE GENERATOR
*=========================================================================
* The Transmit and Receive Physical Layer modules sync to a free
* running Baud Clock. The receiver samples each bit somewhere between
* 1/3 and 2/3 of the bit duration. This is accomplished using a clock that
* is running at twice the baud rate. The actual baud clock is derived from
* this 2x clock by transitioning on its rising edges.
*
* To avoid using global clock resources, all components are completely
* synchronous with the system master clock. Hence the Baud Rate Generator
* provides the same enable bits that are used to generate the two clocks.
*
* Signal: b Baud Clock
* b_r HI when b will transition from LO to HI on next clk
* b_f HI when b will transition from HI to LO on next clk
* b2 2x Baud Clock
* b2_r HI when b will transition from LO to HI on next clk
* b2_f HI when b will transition from HI to LO on next clk
*
* The baud rate divisor is equal to the number of master clock cycles the
* corresponds to one half cycle of the 2x Baud Clock. This
*
* BAUD_DIVISOR = ((MASTER_FREQUENCY)/(BAUD_RATE))/4
*
* This formular will result in a trunctation instead of a rounding, but
* that is acceptable.
*
*=========================================================================
*/

module RS232BAUDCLK (b, b2, b_r, b_f, b2_r, b2_f, rate, rst, clk);

parameter CLK_FREQ = 50000000;

parameter LO = 1'b0, HI = 1'b1;
input [3:0] rate;
input rst, clk;
output b, b_r, b_f; // Baud clock, rising edge, falling edge
output b2, b2_r, b2_f; // 2x Baud clock, rising edge, falling edge

parameter
BAUD_300 = 4'd0,
BAUD_600 = 4'd1,
BAUD_1200 = 4'd2,
BAUD_2400 = 4'd3,
BAUD_4800 = 4'd4,
BAUD_9600 = 4'd5,
BAUD_19200 = 4'd6,
BAUD_38400 = 4'd7,
BAUD_57600 = 4'd8,
BAUD_155200 = 4'd9;

// Baud Rate Divisor Selection
wire [15:0] Baud_Divisor;
reg [15:0] Baud_Divisor_int;
assign Baud_Divisor = Baud_Divisor_int;
always @ (rate)
begin
case (rate)
BAUD_300 : Baud_Divisor_int = ((CLK_FREQ/300)/4);
BAUD_600 : Baud_Divisor_int = ((CLK_FREQ/600)/4);
BAUD_1200 : Baud_Divisor_int = ((CLK_FREQ/1200)/4);
BAUD_2400 : Baud_Divisor_int = ((CLK_FREQ/2400)/4);
BAUD_4800 : Baud_Divisor_int = ((CLK_FREQ/4800)/4);
BAUD_9600 : Baud_Divisor_int = ((CLK_FREQ/9600)/4);
BAUD_19200 : Baud_Divisor_int = ((CLK_FREQ/19200)/4);
BAUD_38400 : Baud_Divisor_int = ((CLK_FREQ/38400)/4);
BAUD_57600 : Baud_Divisor_int = ((CLK_FREQ/57600)/4);
BAUD_155200: Baud_Divisor_int = ((CLK_FREQ/115200)/4);
default : Baud_Divisor_int = ((CLK_FREQ/9600)/4);
endcase
end

// Combinatorial logic to determine transitions
wire tick;
assign b2_r = (b2 == LO) && (tick);
assign b2_f = (b2 == HI) && (tick);
assign b_r = (b == LO) && (b2_r == HI);
assign b_f = (b == HI) && (b2_r == HI);

// Baud Clock Generators
PulseGen16 RS232_CLK (.Q(tick), .Period(Baud_Divisor), .en(HI),
.rst(rst), .clk(clk));
DFFRen BAUD2_CLK (.Q(b2), .D(~b2), .en(tick), .rst(rst), .clk(clk));
DFFRen BAUD_CLK (.Q(b), .D(~b), .en(b2_r), .rst(rst), .clk(clk));

endmodule

Potrebbero piacerti anche