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 | |
---|---|
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.