aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/Hardware/EmUARTDragonball.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SrcShared/Hardware/EmUARTDragonball.cpp')
-rw-r--r--SrcShared/Hardware/EmUARTDragonball.cpp936
1 files changed, 936 insertions, 0 deletions
diff --git a/SrcShared/Hardware/EmUARTDragonball.cpp b/SrcShared/Hardware/EmUARTDragonball.cpp
new file mode 100644
index 0000000..40d6ac3
--- /dev/null
+++ b/SrcShared/Hardware/EmUARTDragonball.cpp
@@ -0,0 +1,936 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 1998-2001 Palm, Inc. or its subsidiaries.
+ All rights reserved.
+
+ This file is part of the Palm OS Emulator.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+\* ===================================================================== */
+
+#include "EmCommon.h"
+#include "EmUARTDragonball.h"
+
+#include "EmHAL.h" // EmHAL, EmUARTDeviceType
+#include "EmTransportSerial.h" // EmTransportSerial
+#include "Logging.h" // LogAppendMsg
+#include "Preferences.h" // gEmuPrefs
+#include "ErrorHandling.h" // ReportErrCommPort
+
+
+/*
+ This module contains the routines for handling serial I/O. It
+ is responsible for responding to changes in state enacted by
+ software (from either the OS or user), and for dealing with
+ the actual transmission and reception of serial data.
+
+ There are four ways in which serial activity could occur: something
+ could write to a UART register, something could read from a UART
+ register, a byte could be received from the host serial port, or
+ a byte could be sent out the host serial port. Here is what
+ happens on each of those events.
+
+ Something reads a UART register:
+ - If the register is the RX_DATA register, clear the DATA_READY bit
+ - Make sure the state is up-to-date (including interrupts)
+ - Return the register contents
+
+ Something writes to a UART register:
+ - Update the writable parts of the register
+ - React to any changes
+ - Make sure the state is up-to-date (including interrupts)
+
+ Data appears at the host serial port:
+ - Post the byte to the RX FIFO (if there is room)
+ - Make sure the state is up-to-date (including interrupts)
+
+ Data needs to be sent to the host serial port:
+ - Send the first byte in the TX FIFO
+ - Make sure the state is up-to-date (including interrupts)
+*/
+
+
+// ======================================================================
+// Private functions
+// ======================================================================
+
+static const int kMaxFifoSize = 64;
+
+static Bool PrvPinBaud (EmTransportSerial::Baud& newBaud);
+static Bool PrvPinBaud (EmTransportSerial::Baud& newBaud,
+ EmTransportSerial::Baud testBaud);
+
+#define PRINTF if (!LogSerial ()) ; else LogAppendMsg
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::EmUARTDragonball
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: type - the type of UART to emulate. The Dragonball
+ * and DragonballEZ UARTs are similar enough that we
+ * can handle them both here with just a few tests in
+ * the places where they differ.
+ *
+ * RETURNED: nothing
+ *
+ ***********************************************************************/
+
+EmUARTDragonball::EmUARTDragonball (UART_Type type, int uartNum) :
+ fUARTNum (uartNum),
+ fState (type),
+ fRxFIFO (this->PrvFIFOSize (true)),
+ fTxFIFO (this->PrvFIFOSize (false))
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::~EmUARTDragonball
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: none.
+ *
+ * RETURNED: nothing
+ *
+ ***********************************************************************/
+
+EmUARTDragonball::~EmUARTDragonball (void)
+{
+ // All line drivers are effectively disabled, so close the transports.
+
+ for (EmUARTDeviceType ii = kUARTBegin; ii < kUARTEnd; ++ii)
+ {
+ EmTransport* transport = gEmuPrefs->GetTransportForDevice (ii);
+
+ if (transport)
+ {
+ transport->Close ();
+ }
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::StateChanged
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: none.
+ *
+ * RETURNED: nothing
+ *
+ ***********************************************************************/
+
+void EmUARTDragonball::StateChanged (State& newState, Bool sendTxData)
+{
+ EmAssert (fState.UART_TYPE == newState.UART_TYPE);
+
+ // (Changing the configuration is the only place where we assume that
+ // the transport we're using is a serial transport.)
+
+ EmTransportSerial::ConfigSerial config;
+ EmTransport* transport = this->GetTransport ();
+ EmTransportSerial* serTransport = dynamic_cast<EmTransportSerial*> (transport);
+
+ if (serTransport)
+ {
+ serTransport->GetConfig (config);
+ }
+
+
+ // ========== RX_ENABLE ==========
+ //
+ // This bit enables the receiver block. While this bit is low, the receiver is disabled and the
+ // receive FIFO is flushed. This bit resets to 0.
+
+ if (fState.RX_ENABLE != newState.RX_ENABLE)
+ {
+ if (newState.RX_ENABLE == 0)
+ {
+ fRxFIFO.Clear ();
+ }
+ }
+
+
+ // ========== TX_ENABLE ==========
+ //
+ // This bit enables the transmitter block. While this bit is low, the transmitter is disabled and
+ // the transmit FIFO is flushed. This bit resets to 0.
+
+ if (fState.TX_ENABLE != newState.TX_ENABLE)
+ {
+ if (newState.TX_ENABLE == 0)
+ {
+ fTxFIFO.Clear ();
+ }
+ }
+
+
+ // ========== PARITY_EN ==========
+ //
+ // This bit controls the parity generator in the transmitter and parity checker in the receiver.
+ // When this bit is high, they are enabled. When it is low, they are disabled.
+ //
+ // ========== ODD_EVEN ==========
+ //
+ // This bit controls the sense of the parity generator and checker. When this bit is high, odd
+ // parity is generated and expected. When this bit is low, even parity is generated and
+ // expected. This bit has no function if PARITY EN is low.
+
+ if (newState.PARITY_EN == 0)
+ {
+ config.fParity = EmTransportSerial::kNoParity;
+ }
+ else if (newState.ODD_EVEN)
+ {
+ config.fParity = EmTransportSerial::kOddParity;
+ }
+ else
+ {
+ config.fParity = EmTransportSerial::kEvenParity;
+ }
+
+
+ // ========== STOP_BITS =========
+ //
+ // This bit controls the number of stop bits transmitted after a character. When this bit is high,
+ // two stop bits are sent. When this bit is low, one stop bit is sent. This bit has no effect on the
+ // receiver, which expects one or more stop bits.
+
+ config.fStopBits = newState.STOP_BITS ? 2 : 1;
+
+
+ // ========== CHAR8_7 ==========
+ //
+ // This bit controls the character length. While high, the transmitter and receiver are in 8-bit
+ // mode. While low, they are in 7-bit mode. The transmitter then ignores B7 and the receiver
+ // sets B7 to 0.
+
+ config.fDataBits = newState.CHAR8_7 ? 8 : 7;
+
+
+ // ========== DIVIDE ==========
+ //
+ // These bits control the clock frequency produced by the baud rate generator.
+ //
+ // 000 = Divide by 1.
+ // 001 = Divide by 2.
+ // 010 = Divide by 4.
+ // 011 = Divide by 8.
+ // 100 = Divide by 16.
+ // 101 = Divide by 32.
+ // 110 = Divide by 64.
+ // 111 = Divide by 128.
+ //
+ // ========== PRESCALER ==========
+ //
+ // These bits control the division value of the baud generator prescaler. The division value is
+ // determined by the following formula:
+ //
+ // Prescaler division value = 65 (decimal) - PRESCALER
+
+ // Baud rate is sysClockFreq / preScaler / divider / 16
+ //
+ // (Using sysClockFreq / (preScaler * divider * 16) might get closer to the
+ // intended baud (as would using floating point), but does it mirror what
+ // the hardware actually does?)
+
+ int32 sysClockFreq = EmHAL::GetSystemClockFrequency ();
+ config.fBaud = sysClockFreq / (65 - newState.PRESCALER) / (1 << newState.DIVIDE) / 16;
+
+ // "newRate" is only approximate to within 0.1%. Pin the value to an
+ // exact value.
+ //
+ // !!! What to do if we can't pin to a valid value?
+
+ (void) PrvPinBaud (config.fBaud);
+
+
+ // ========== IGNORE_CTS ==========
+ //
+ // When this bit is high, it forces the CTS signal that is presented to the transmitter to always
+ // be asserted, which effectively ignores the external pin.
+
+ config.fHwrHandshake = newState.IGNORE_CTS == 0;
+
+
+ // ========== RTS_CONT ==========
+ //
+ // This bit selects the function of the RTS pin.
+ //
+ // 0 = RTS pin is controlled by the RTS bit.
+ // 1 = RTS pin is controlled by the receiver FIFO. When the FIFO is full (one slot is
+ // remaining), RTS is negated.
+ //
+ // ========== RTS ==========
+ //
+ // This bit controls the RTS pin while the RTS CONT bit is 0.
+ //
+ // 0 = RTS pin is 1.
+ // 1 = RTS pin is 0.
+
+ if (fState.RTS_CONT != newState.RTS_CONT ||
+ fState.RTS != newState.RTS)
+ {
+ if (serTransport)
+ {
+ if (newState.RTS_CONT)
+ {
+ serTransport->SetRTS (EmTransportSerial::kRTSAuto);
+ }
+ else
+ {
+ if (newState.RTS)
+ {
+ serTransport->SetRTS (EmTransportSerial::kRTSOn);
+ }
+ else
+ {
+ serTransport->SetRTS (EmTransportSerial::kRTSOff);
+ }
+ }
+ }
+ }
+
+
+ // ========== UART_ENABLE ==========
+ //
+ // This bit enables the UART module. When this bit is low, the UART module is disabled and
+ // in low-power mode. While this bit is high, the UART module is active. This bit resets to 0.
+
+ // ========== IRDA_ENABLE ==========
+ //
+ // This bit enables the IrDA interface.
+ //
+ // 0 = Normal NRZ operation.
+ // 1 = IRDA operation.
+
+ if (fState.UART_ENABLE != newState.UART_ENABLE ||
+ fState.IRDA_ENABLE != newState.IRDA_ENABLE)
+ {
+ // Nothing to do here.
+ }
+
+ // Establish the new settings. Do this only when the UART is
+ // enabled, to help reduce the thrashing on the host serial port,
+ // and to help prevent the installation of invalid settings (which
+ // could appear in the UART registers as it's being configured).
+
+ if (newState.UART_ENABLE)
+ {
+ if (serTransport)
+ {
+ serTransport->SetConfig (config);
+ }
+ }
+
+ // ========== SEND_BREAK ==========
+ //
+ // This bit forces the transmitter to immediately send continuous zeros creating a break
+ // character.
+
+ if (fState.SEND_BREAK != newState.SEND_BREAK)
+ {
+ if (serTransport)
+ {
+ serTransport->SetBreak (newState.SEND_BREAK);
+ }
+ }
+
+
+ // ========== TX_DATA ==========
+ //
+ // These bits are the parallel transmit-data inputs. In 7-bit mode, D7 is ignored and in 8-bit
+ // mode, all of the bits are used. Data is transmitted LSB first. A new character is transmitted
+ // when these bits are written and have passed through the FIFO.
+
+ // ========== LOOP ==========
+ //
+ // This bit controls loopback for system testing purposes. When this bit is high, the receiver
+ // input is internally connected to the transmitter and ignores the RXD pin. The TXD pin is
+ // unaffected by this bit.
+
+ if (sendTxData && newState.UART_ENABLE && newState.TX_ENABLE)
+ {
+ if (newState.LOOP == 0)
+ {
+ if (transport && transport->CanWrite ()) // The host serial port is open
+ {
+ // With or without hardware handshaking, we'll put data
+ // in the FIFO, and let the host's handshaking take care
+ // of when the data is removed from the FIFO.
+
+ if (fTxFIFO.GetFree () > 0) // There's room in the FIFO
+ {
+ fTxFIFO.Put (newState.TX_DATA); // so add the data
+
+ // Call TransmitTxFIFO here to send the data we
+ // just queued up. Doing this is important on the Mac in
+ // order to send out the data quickly instead of later at
+ // idle time.
+
+ this->TransmitTxFIFO (transport);
+ }
+ }
+ else // The host serial port is NOT open
+ {
+ if (config.fHwrHandshake) // Reflects the state of the IGNORE_CTS bit.
+ {
+ // With hardware handshaking, data is sent only when CTS
+ // is asserted. With no host serial port, we define that
+ // CTS is never asserted, so the data clogs up the FIFO.
+
+ if (fTxFIFO.GetFree () > 0) // There's room in the FIFO
+ {
+ fTxFIFO.Put (newState.TX_DATA); // so add the data
+
+ // Serial port is closed, so don't call Platform::TransmitTxFIFO.
+ }
+ }
+ else
+ {
+ // With no hardware handshaking, data is sent whenever it's
+ // ready. With nowhere to go, we can drop it on the floor.
+ }
+ }
+ }
+ else // We're in loopback mode.
+ {
+ if (fRxFIFO.GetFree () > 0)
+ {
+ fRxFIFO.Put (newState.TX_DATA);
+ }
+ }
+ }
+
+
+ // Update the state in case any of the above operations have side-effects.
+
+ UpdateState (newState, false);
+
+
+ // Remember this for next time.
+
+ fState = newState;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::UpdateState
+ *
+ * DESCRIPTION: Receive any data, and update the FIFO state registers.
+ *
+ * PARAMETERS: none.
+ *
+ * RETURNED: nothing
+ *
+ ***********************************************************************/
+
+void EmUARTDragonball::UpdateState (State& state, Bool refreshRxData)
+{
+ EmAssert (fState.UART_TYPE == state.UART_TYPE);
+
+ // Update the RxFIFO if there's been any buffered data.
+
+ EmTransport* transport = this->GetTransport ();
+ if (transport)
+ {
+ this->ReceiveRxFIFO (transport);
+ }
+
+ // === RX_FIFO_FULL ===
+ //
+ // This read-only bit indicates that the receiver FIFO is full and may generate an overrun. This
+ // bit generates a maskable interrupt.
+ //
+ // Further, from the overview section of the manual:
+ //
+ // If your software has a short interrupt
+ // latency time, the FIFO FULL interrupt in the Receiver register can be enabled. The FIFO has
+ // one remaining space available when this interrupt is generated.
+
+ state.RX_FIFO_FULL = fRxFIFO.GetFree () == 0;
+
+
+ // === RX_FIFO_HALF ===
+ //
+ // This read-only bit indicates that the receiver FIFO has four or fewer slots remaining in the
+ // FIFO. This bit generates a maskable interrupt.
+
+ state.RX_FIFO_HALF = fRxFIFO.GetFree () <= this->PrvLevelMarker (true);
+
+
+ // === DATA_READY ===
+ //
+ // This read-only bit indicates that at least one byte is present in the receive FIFO. The
+ // character bits are valid only while this bit is set. This bit generates a maskable interrupt.
+
+ state.DATA_READY = fRxFIFO.GetUsed () > 0;
+
+
+ // === OLD_DATA === // non-68328 only
+ //
+ // This read-only bit indicates that data in the FIFO is older than 30 bit times. It is useful in
+ // situations where the FIFO FULL or FIFO HALF interrupts are used. If there is data in the
+ // FIFO, but below the interrupt threshold, a maskable interrupt can be generated to alert the
+ // software that unread data is present. This bit clears when the character bits are read.
+
+ // Not supported right now.
+
+
+ // === OVRUN ===
+ //
+ // When this read-only bit is high, it indicates that the receiver overwrote data in the FIFO. The
+ // character with this bit set is valid, but at least one previous character was lost. In normal
+ // circumstances, this bit should never be set. It indicates that your software is not keeping up
+ // with the incoming data rate. This bit is updated and valid for each received character.
+
+ // !!! TBD
+
+
+ // === FRAME_ERROR ===
+ //
+ // While high, this read-only bit indicates that the current character had a framing error
+ // (missing stop bit), indicating the possibility of corrupted data. This bit is updated for each
+ // character read from the FIFO.
+
+ // !!! TBD
+
+
+ // === BREAK ===
+ //
+ // When this read-only bit is high, it indicates that the current character was detected as a
+ // BREAK. The data bits are all 0 and the stop bit was also 0. The FRAME ERROR bit will
+ // always be set when this bit is set. If odd parity is selected, PARITY ERROR will also be set
+ // along with this bit. This bit is updated and valid with each character read from the FIFO.
+
+ // !!! TBD
+
+ // === PARITY_ERROR ===
+ //
+ // When this read-only bit is high, it indicates that the current character was detected with a
+ // parity error, indicating the possibility of corrupted data. This bit is updated and valid with
+ // each character read from the FIFO. While parity is disabled, this bit always reads zero.
+
+ // !!! TBD
+
+ // === RX_DATA ===
+ //
+ // These read-only bits are the top receive character in the FIFO. They have no meaning if the
+ // DATA READY bit is 0. In 7-bit mode, the MSB is forced to 0 and in 8-bit mode, all bits are
+ // active.
+
+ if (state.DATA_READY && state.UART_ENABLE && state.RX_ENABLE && refreshRxData)
+ {
+ state.RX_DATA = fRxFIFO.Get ();
+
+ if (state.CHAR8_7 == 0)
+ {
+ state.RX_DATA &= 0x07F;
+ }
+
+ PRINTF ("UART: Put 0x%02X into RX_DATA.", (uint32) (uint8) state.RX_DATA);
+ }
+
+
+ // === TX_FIFO_EMPTY ===
+ //
+ // This read-only bit indicates that the transmit FIFO is empty. This bit generates a maskable
+ // interrupt.
+
+ state.TX_FIFO_EMPTY = fTxFIFO.GetUsed () == 0;
+
+
+ // === TX_FIFO_HALF ===
+ //
+ // This read-only bit indicates that the transmit FIFO is less than half full. This bit generates a
+ // maskable interrupt.
+
+ state.TX_FIFO_HALF = fTxFIFO.GetUsed () < this->PrvLevelMarker (false);
+
+
+ // === TX_AVAIL ===
+ //
+ // This read-only bit indicates that the transmit FIFO has at least one slot available for data.
+ // This bit generates a maskable interrupt.
+
+ state.TX_AVAIL = fTxFIFO.GetFree () > 0;
+
+
+ // === BUSY === // non-68328 only
+ //
+ // When this bit is high, it indicates that the transmitter is busy sending a character. This signal
+ // is asserted while the transmitter state machine is not idle or the FIFO has data in it.
+
+ state.BUSY = !state.TX_FIFO_EMPTY;
+
+
+ // === CTS_STATUS ===
+ //
+ // This bit indicates the current status of the CTS pin. A "snapshot" of the pin is taken
+ // immediately before this bit is presented to the data bus. While the IGNORE CTS bit is high,
+ // this bit can serve as a general-purpose input.
+ //
+ // Note that this pin is ACTIVE LOW! That's why the Boolean expression is negated below.
+ //
+ // For now, say that it's clear to send if the FIFO is empty
+ //
+ // !!! TBD - could be better?
+
+ state.CTS_STATUS = !(fTxFIFO.GetUsed () == 0);
+
+
+ // === CTS_DELTA ===
+ //
+ // When this bit is high, it indicates that the CTS pin changed state and generates a maskable
+ // interrupt. The current state of the CTS pin is available on the CTS STATUS bit. You can
+ // generate an immediate interrupt by setting this bit high. The CTS interrupt is cleared by
+ // writing 0 to this bit.
+
+ // Not supported right now.
+
+
+ // Remember this for next time.
+
+ fState = state;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::TransmitTxFIFO
+ *
+ * DESCRIPTION: Transmit any bytes in the TX FIFO out the serial port.
+ * Assumes that the serial port is open.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmUARTDragonball::TransmitTxFIFO (EmTransport* transport)
+{
+ EmAssert (transport);
+
+ if (transport->CanWrite ())
+ {
+ // Write out any outgoing bytes.
+
+ ErrCode err = errNone;
+ char buffer[kMaxFifoSize];
+ long spaceInTxFIFO = fTxFIFO.GetUsed ();
+
+ if (spaceInTxFIFO > 0)
+ {
+ for (long ii = 0; ii < spaceInTxFIFO; ++ii)
+ {
+ buffer[ii] = fTxFIFO.Get ();
+ }
+
+ if (LogSerialData ())
+ LogAppendData (buffer, spaceInTxFIFO, "UART: Transmitted data:");
+ else
+ PRINTF ("UART: Transmitted %ld serial bytes.", spaceInTxFIFO);
+
+ err = transport->Write (spaceInTxFIFO, buffer);
+ }
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::ReceiveRxFIFO
+ *
+ * DESCRIPTION: Fills up the RX FIFO with as many bytes as it can from
+ * the host serial port. Assumes that the serial port is
+ * open.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmUARTDragonball::ReceiveRxFIFO (EmTransport* transport)
+{
+ EmAssert (transport);
+
+ if (transport->CanRead ())
+ {
+ // Buffer up any incoming bytes.
+
+ ErrCode err = errNone;
+ char buffer[kMaxFifoSize];
+ long spaceInRxFIFO = fRxFIFO.GetFree ();
+
+ // See how many bytes are waiting.
+
+ long bytesToBuffer = transport->BytesInBuffer (fRxFIFO.GetMaxSize ());
+
+ // See if we have that much room in the FIFO. If not, limit our read
+ // to that many bytes.
+
+ if (bytesToBuffer > spaceInRxFIFO)
+ {
+ bytesToBuffer = spaceInRxFIFO;
+ }
+
+ // If there is data waiting in the wings, and the hardware says it's
+ // OK to receive data, and there's room in the RxFIFO, then receive it.
+ //
+ // It's OK to receive data if RTS_CONT is 1. That means that the FIFO
+ // controls whether or not it's OK to receive data, and that check
+ // is taken care of with "bytesToBuffer > 0".
+ //
+ // If RTS_CONT is zero, then it's OK to receive data if RTS is 1. That
+ // mean that the /RTS pin is zero, which means OK to receive.
+
+ if (bytesToBuffer > 0 && (fState.RTS_CONT == 1 || fState.RTS == 1))
+ {
+ // If there are still bytes to be read, read them in and insert them
+ // into the RX FIFO. If the buffer was previously empty, Hardware::Cycle
+ // will notice that there are now bytes in there and update the
+ // UART registers.
+ //
+ // !!! TBD: Hardware::Cycle is called after every opcode execution.
+ // Since it is very rare that serial bytes are coming in, the overhead
+ // incurred for checking to see if there are serial bytes does not pay
+ // off. We may want to figure out a way to update the UART registers
+ // here, and take the check out of Hardware::Cycle. I'd do that here,
+ // but (a) Hardware::Cycle takes a "sleeping" parameter that I'd have
+ // to determine here, and (b) the similar solution on Windows is more
+ // difficult, as I'd have to stop the CPU thread, update the registers,
+ // and restart the thread.
+
+ err = transport->Read (bytesToBuffer, buffer);
+
+ if (err == errNone)
+ {
+ // not quite the correct phrase for IR over serial (over TCP)
+ if (LogSerialData ())
+ LogAppendData (buffer, bytesToBuffer, "UART: Received data:");
+ else
+ PRINTF ("UART: Received %ld serial bytes.", bytesToBuffer);
+
+ for (long ii = 0; ii < bytesToBuffer; ++ii)
+ {
+ fRxFIFO.Put (buffer[ii]);
+ } // end loop that puts bytes into FIFO
+ } // end no-error-from-EmTransport::Read
+ } // end BytesInBuffer-returned-non-zero
+ } // end is-serial-port-open
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::GetTransport
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: .
+ *
+ * RETURNED: .
+ *
+ ***********************************************************************/
+
+EmTransport* EmUARTDragonball::GetTransport (void)
+{
+ EmUARTDeviceType type = EmHAL::GetUARTDevice (fUARTNum);
+ EmTransport* transport = gEmuPrefs->GetTransportForDevice (type);
+
+ return transport;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::PrvFIFOSize
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: .
+ *
+ * RETURNED: .
+ *
+ ***********************************************************************/
+
+int EmUARTDragonball::PrvFIFOSize (Bool forRX)
+{
+ int size;
+
+ switch (fState.UART_TYPE)
+ {
+ case kUART_Dragonball:
+ size = 8;
+ break;
+
+ case kUART_DragonballEZ:
+ if (forRX)
+ {
+ size = 12;
+ }
+ else
+ {
+ size = 8;
+ }
+ break;
+
+ case kUART_DragonballVZ:
+ if (this->fUARTNum == 0)
+ {
+ if (forRX)
+ {
+ size = 12;
+ }
+ else
+ {
+ size = 8;
+ }
+ }
+ else
+ {
+ size = 64;
+ }
+ break;
+
+ default:
+ EmAssert (false);
+ size = 8;
+ break;
+ }
+
+ return size;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::PrvLevelMarker
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: .
+ *
+ * RETURNED: .
+ *
+ ***********************************************************************/
+
+int EmUARTDragonball::PrvLevelMarker (Bool forRX)
+{
+ int level = (forRX ? fRxFIFO.GetMaxSize () : fTxFIFO.GetMaxSize ()) / 2;
+
+ switch (fState.UART_TYPE)
+ {
+ case kUART_Dragonball:
+ break;
+
+ case kUART_DragonballEZ:
+ break;
+
+ case kUART_DragonballVZ:
+ if (this->fUARTNum == 1)
+ {
+ int marker = forRX ? fState.TXFIFO_LEVEL_MARKER : fState.RXFIFO_LEVEL_MARKER;
+
+ if (marker != 0)
+ {
+ level = marker * 4;
+ }
+ }
+ break;
+
+ default:
+ EmAssert (false);
+ break;
+ }
+
+ return level;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvPinBaud
+ *
+ * DESCRIPTION: Pins the given baud value to the test baud value if the
+ * former is sufficiently close to the latter.
+ *
+ * PARAMETERS: newBaud - the value to possibly alter.
+ *
+ * testBaud - the value to pin to.
+ *
+ * RETURNED: newBaud is changed in place. If it is changed, the
+ * function returns true. Otherwise, it returns false.
+ *
+ ***********************************************************************/
+
+Bool PrvPinBaud (EmTransportSerial::Baud& newBaud)
+{
+ Bool pinned = false;
+
+ if (!pinned) pinned = PrvPinBaud (newBaud, 150);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 300);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 600);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 1200);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 1800);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 2400);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 3600);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 4800);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 7200);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 9600);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 14400);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 19200);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 28800);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 38400);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 57600);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 115200);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 230400);
+
+ return pinned;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvPinBaud
+ *
+ * DESCRIPTION: Pins the given baud value to the test baud value if the
+ * former is sufficiently close to the latter.
+ *
+ * PARAMETERS: newBaud - the value to possibly alter.
+ *
+ * testBaud - the value to pin to.
+ *
+ * RETURNED: newBaud is changed in place. If it is changed, the
+ * function returns true. Otherwise, it returns false.
+ *
+ ***********************************************************************/
+
+Bool PrvPinBaud (EmTransportSerial::Baud& newBaud, EmTransportSerial::Baud testBaud)
+{
+ // Pin to within 2%. The Dragonball reference says that the uBaud
+ // register should be accurate to within 0.1%, but let's give it
+ // some slop.
+
+ if (newBaud > (testBaud - (testBaud / 50)) &&
+ newBaud < (testBaud + (testBaud / 50)))
+ {
+ newBaud = testBaud;
+ return true;
+ }
+
+ return false;
+}