Services and Modeling for Embedded Software Development
Embecosm divider strip
Prev  Next

8.4.2.  UartSyncSC Module Class Implementation

The custom constructor passes the name and _isLittleEndian flag to the base class constructor. The clock rate is saved in the state variable, clockRate.

UartSyncSC::UartSyncSC( sc_core::sc_module_name  name,
                        unsigned long int        _clockRate,
                        bool                     _isLittleEndian ) :
  UartSC( name, _isLittleEndian ),
  clockRate( _clockRate )
{

}       /* UartSyncSC() */
	  

The new version of busThread adds only one line to the version in the base class. A call to wait( charDelay ) is added when the transmit request is received (notified on the SystemC event, txReceived).

    wait( txReceived );                         // Wait for a Tx request
    wait( charDelay );                          // Wait baud delay
    tx.write( regs.thr );                       // Send char to terminal
	  

The new version of busReadWrite draws most of its functionality from the base class version. However it then synchronizes with a time delay for the read or write access. Since the thread is now synchronous, a time delay of zero is returned with the transaction.

void
UartSyncSC::busReadWrite( tlm::tlm_generic_payload &payload,
                          sc_core::sc_time         &delay )
{
  UartSC::busReadWrite( payload, delay );       // base function

  switch( payload.get_command() ) {
  case tlm::TLM_READ_COMMAND:
    wait( sc_core::sc_time( UART_READ_NS, sc_core::SC_NS ));
    delay = sc_core::SC_ZERO_TIME;
    break;

    <code for write commands etc>

	  

The new version of busWrite similarly relies on the base class for most of its functionality.

void
UartSyncSC::busWrite( unsigned char  uaddr,
                      unsigned char  wdata )
{
  UartSC::busWrite( uaddr, wdata );
	  

However any change to the divisor latch or line control register could change the baud rate or the number of bits in each Tx transmission, and hence the modeled delay to send a character.

The function identifies if this has happened and if so calls resetCharDelay to recalculate the delay.

  switch( uaddr ) {
  case UART_BUF:                // Only change if divisorLatch update (DLAB=1)
  case UART_IER:
    if( isSet( regs.lcr, UART_LCR_DLAB ) ) {
      resetCharDelay();
    }
    break;

  case UART_LCR:
    resetCharDelay();           // Could change baud delay
    break;
	  

The time taken to put a character on the Tx line is the product of the time taken to put one bit on the line (the inverse of the baud rate) and the bits required for the character (start bit, data bits, optional parity bit, stop bit(s)). The baud rate is determined by the input clock rate and the 16-bit divisor latch.

[Note]Note

The divisor latch for a 16450 divides the input clock to yield an internal clock 16x the baud rate (i.e. not the actual baud rate itself).

The 16450 specification supports an input clock up to 24 MHz, so the 16 bit divisor latch can yield an internal clock for rates down to 50 baud. However for a software model this limitation can be ignored. Faster input clocks can be specified, but it will not be possible to configure a 16-bit divisor latch for very low baud rates.

The number of bits to send a character is determined by the line control registers. There is always a stop bit, there can be 5-8 data bits, an optional parity bit and 1, 1.5 or 2 stop bits. The resetCharDelay function calculates the total delay.

The implementation of the UART module class with synchronized timing, UartSyncSC may be found in sys-models/sync-soc/UartSyncSC.cpp in the distribution.

Embecosm divider strip