Hi all:
this is a sample tutorial for "How to write a UART testbench in SystemC".
1.what's "UART" ?
You can reference the UART Agenda firstly... or from
WiKi
Refs:
UART Agenda ,
Serial UART information
2. How and How to work?
2-1. TX/RX (transfer/receiver)
this is an asynchronous timing Sequence for UART TX/RX transition. In data (transfer/Receive),we should define our sample and receive rate to catch/push the accurate data. and it depend on our Baud rate and local clk frequency. in this formulation we can calculate out the clock numbers for UART per bit.
// Calculate number of clocks per UART bit clocks_per_bit = (int)(clk_freq_hz/uart_baud);
Example timing sequence for RX :
start_Bit(1) -> star_Bit(0) -> Data_bit(D0) -> Data_bit(D1) ... -> Data_bit(7) ->
Stop_Bit(0) -> Stop_Bit(1).
2-2. Baud rate set
it define our bit resolution
Ex: baud rate for RS232 Display should < %3, if we define our Fclk=12Mhz,
smod=1. and we can find a good data resolution rage from XXX to XXX.
Black Box Interface *.h (UART_Test_Bench)
class UartSC
: public sc_core::sc_module
{
public:
// Constructor
UartSC (sc_core::sc_module_name name);
// The ports
sc_in < bool > clk;
sc_in < bool > uarttx;
sc_out < bool > uartrx;
// Init function
void initUart (int clk_freq_hz, int uart_baud) ;
// Transmit (from ORPSoC) handling function
void checkTx();
private:
int clocks_per_bit;
uint8_t current_char;
int counter;
int bits_received;
}; // UartSC ()
define our sensitive type
UartSC::UartSC (sc_core::sc_module_name name):
sc_module (name)
{
SC_METHOD (checkTx);
dont_initialize();
sensitive << clk.pos();
//sensitive << uarttx;
}
define our TX method
// Maybe do this with threads instead?!
void
UartSC::checkTx () {
#ifdef UART_SC_DEBUG
//printf("Uart TX activity: level is : 0x%x\n", uarttx.read()&1);
#endif
// Check the number of bits received
if (bits_received==0)
{
// Check if tx is low
if ((uarttx.read()&1) == 0)
{
// Line pulled low, begin receive of new char
current_char = 0;
// Start
counter = 1;
bits_received++; // We got the start bit
#ifdef UART_SC_DEBUG
cout << "UartSC checkTx: got start bit at time " << sc_time_stamp() << endl;
#endif
}
}
else if (bits_received > 0 && bits_received < 9)
{
// Check the counter - see if it's time to sample the line
// We do an extra half-bit delay on first bit read
if ( ((bits_received==1) &&
(counter == (clocks_per_bit + (clocks_per_bit/2)))) ||
((bits_received > 1) && (counter == clocks_per_bit)) )
{
//printf("UartSC checkTx: read bit %d as 0x%x at time", bits_received, uarttx.read()&1);
//cout << sc_time_stamp() << endl;
// Shift in the current value of the tx into our char
current_char |= ((uarttx.read() & 1) << (bits_received-1));
// Reset the counter
counter = 1;
// Increment bit number
bits_received++;
}
else
counter++;
}
else if (bits_received == 9)
{
// Now check for stop bit 1
if (counter == clocks_per_bit)
{
// Check that the value is 1 - this should be the stop bit
if ((uarttx.read() & 1) != 1)
{
printf("UART TX framing error at time\n");
cout << sc_time_stamp() << endl;
// Perhaps do something else here to deal with this
bits_received = 0;
counter = 0;
}
else
{
// Print the char
#ifdef UART_SC_DEBUG
printf("Char received: 0x%2x time: ", current_char);
cout << sc_time_stamp() << endl;
#endif
// cout'ing the char didn't work for some systems - jb 090613ol
//cout << current_char;
printf("%c",current_char);
bits_received = 0;
counter = 0;
}
}
else
counter++;
}
}
Ref: http://opencores.org/openrisc,orpsocv21