--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// 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 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "uart.h"
+
+namespace SA1100 {
+
+Uart::Uart(std::function<void(const char*)>& output) : mSink(output) {
+ initRegisters();
+}
+
+void Uart::initRegisters() {
+ mUTCR0 = 0;
+ mUTCR1 = 0;
+ mUTCR2 = 0;
+ mUTCR3 = 0;
+ mUTDR = 0;
+
+ mUTSR0 = UTSR0_TFS; // Transmit FIFO service request
+ mUTSR1 = UTSR1_TNF; // Transmit FIFO not full
+ mTxFifo.clear();
+ mRxFifo.clear();
+ mNextTxCycle = 0;
+ mTxBuffer.clear();
+}
+
+void Uart::reset() {
+ // bit 7 sets 0 on reset.
+ mUTCR0 &= ~(1 << 7);
+
+ // bit 4, 5, 6, 7 set 0 on reset.
+ mUTCR1 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4));
+
+ // bit 0, 1, 6, 7 set 0 on reset.
+ mUTCR3 &= ~((1 << 7) | (1 << 6) | (1 << 1) | (1 << 0));
+
+ // bit 0, 1, 5, 6, 7 set 0 on reset.
+ mUTSR0 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 1) | (1 << 0));
+
+ // bit 0, 1, 5, 6, 7 set 0 on reset.
+ mUTSR1 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 1) | (1 << 0));
+
+ mTxFifo.clear();
+ mRxFifo.clear();
+ mNextTxCycle = 0;
+ mTxBuffer.clear();
+}
+
+void Uart::run(int64_t passedCycles) {
+ if (mUTCR3 & UTCR3_TXE) {
+ if (!mTxFifo.empty()) {
+ if (mNextTxCycle == 0) {
+ mNextTxCycle = passedCycles + 16000;
+ }
+ while (!mTxFifo.empty() && passedCycles >= mNextTxCycle) {
+ uint8_t ch = mTxFifo.front();
+ mTxFifo.erase(mTxFifo.begin());
+
+ if (ch & 0x80) {
+ ch = 0x20;
+ }
+ mTxBuffer.push_back(static_cast<char>(ch));
+ if (ch == '\n' || ch == '\r' || mTxBuffer.size() >= 120) {
+ flushTxBuffer();
+ }
+
+ if (mTxFifo.size() <= 4) {
+ mUTSR0 |= UTSR0_TFS;
+ }
+ if (mTxFifo.size() < 8) {
+ mUTSR1 |= UTSR1_TNF;
+ }
+
+ if (!mTxFifo.empty()) {
+ mNextTxCycle += 16000;
+ if (mNextTxCycle <= passedCycles) {
+ mNextTxCycle = passedCycles + 16000;
+ }
+ } else {
+ mNextTxCycle = 0;
+ }
+ }
+ }
+ }
+
+ if (mUTCR3 & UTCR3_RXE) {
+ switch (mRxFifo.size()) {
+ case 0:
+ mUTSR1 &= ~UTSR1_RNE;
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ // :SA-1110 Developer's Manual: p.338: Wei 2003-Jun-29:
+ //
+ // If receiver is enabled, receive FIFO not empty, 3 frame times elapsed
+ // without receiving data, request interrupt.
+ //
+ // :NOTE: Wei 2004-Jun-29:
+ //
+ // However, I don't see the reasone that I should implement a
+ // time-critical operation like this (3 frame times), thus, whenever the
+ // rx fifo isn't empty, ARMware will set the RID bit in UTSR0 up.
+ mUTSR0 |= UTSR0_RID;
+
+ mUTSR1 |= UTSR1_RNE;
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ default:
+ // :SA-1110 Developer's Manual: p.338: Wei 2003-Jun-29:
+ //
+ // Receive FIFO is one- to two-thirds full (contains 5, 6, 7, or 8 entries
+ // of data) or more, and receiver operation is enabled, DMA service
+ // request signalled, and interrupt request signalled if not masked (if
+ // RIE=1).
+ //
+ // :NOTE: Wei 2004-Jun-29:
+ //
+ // And I choice 8 elements as the delimiter.
+ mUTSR0 |= (UTSR0_RFS | UTSR0_RID);
+
+ mUTSR1 |= UTSR1_RNE;
+ break;
+ }
+ }
+}
+
+inline void Uart::txData() {
+ // :NOTE: Wei 2004-Jun-10:
+ //
+ // Becuase of using fifo[0], fifo has to reside in a consecutive memory
+ // blocks. This is why I use std::vector rather than std::deque for mTxFifo.
+ std::string output;
+
+ for (std::vector<uint8_t>::iterator iter = mTxFifo.begin();
+ iter != mTxFifo.end(); ++iter) {
+ if ((*iter) & 0x80) {
+ (*iter) = 0x20;
+ }
+ }
+
+ if (0xd == mTxFifo.back()) {
+ output.append(reinterpret_cast<char const*>(&(mTxFifo[0])), mTxFifo.size());
+ mNeedAppendMore = true;
+ } else {
+ if (true == mNeedAppendMore) {
+ output.append(reinterpret_cast<char const*>(&(mTxFifo[0])),
+ mTxFifo.size());
+ mSink(output.c_str());
+ mNeedAppendMore = false;
+ } else {
+ if (false == output.empty()) {
+ mSink(output.c_str());
+ }
+
+ std::string lala = std::string(
+ reinterpret_cast<char const*>(&(mTxFifo[0])), mTxFifo.size());
+ mSink(lala.c_str());
+ }
+ }
+}
+
+void Uart::flushTxBuffer() {
+ if (!mTxBuffer.empty()) {
+ mSink(mTxBuffer.c_str());
+ mTxBuffer.clear();
+ }
+}
+
+uint32_t Uart::read32(const uint32_t address) {
+ switch (address) {
+ case UTCR0:
+ return static_cast<uint32_t>(mUTCR0);
+
+ case UTCR1:
+ return static_cast<uint32_t>(mUTCR1);
+
+ case UTCR2:
+ return static_cast<uint32_t>(mUTCR2);
+
+ case UTCR3:
+ return static_cast<uint32_t>(mUTCR3);
+
+ case UTDR: {
+ if (true == mRxFifo.empty()) {
+ assert(0 == (mUTSR1 & UTSR1_RNE));
+ return static_cast<uint32_t>(0);
+ } else {
+ assert(UTSR1_RNE == (mUTSR1 & UTSR1_RNE));
+ uint8_t const ch = mRxFifo.front();
+
+ mRxFifo.pop_front();
+
+ switch (mRxFifo.size()) {
+ case 0:
+ mUTSR0 &= ~(UTSR0_RID | UTSR0_RFS);
+
+ mUTSR1 &= ~UTSR1_RNE;
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ mUTSR0 &= ~UTSR0_RFS;
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ default:
+ break;
+ }
+ return static_cast<uint32_t>(ch);
+ }
+ }
+
+ case UTSR0:
+ return static_cast<uint32_t>(mUTSR0);
+
+ case UTSR1:
+ // :NOTE: Wei 2004-Jan-03:
+ //
+ // Bit 6, 7 are reserved.
+ //
+ // However, this is a read-only register, thus I don't have to do the mask
+ // operation.
+ return static_cast<uint32_t>(mUTSR1);
+
+ default:
+ return 0;
+ }
+}
+
+void Uart::write32(const uint32_t address, const uint32_t value) {
+ switch (address) {
+ case UTCR0:
+ // :NOTE: Wei 2004-Jan-03:
+ //
+ // Bit 7 is reserved.
+ mUTCR0 = static_cast<uint8_t>(value & ~(1 << 7));
+ break;
+
+ case UTCR1:
+ // :NOTE: Wei 2004-Jan-03:
+ //
+ // Bit 4, 5, 6, 7 are reserved.
+ mUTCR1 = static_cast<uint8_t>(value &
+ ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4)));
+ break;
+
+ case UTCR2:
+ mUTCR2 = static_cast<uint8_t>(value);
+ break;
+
+ case UTCR3: {
+ uint8_t const diff = (mUTCR3 ^ value);
+
+ if ((diff & UTCR3_TXE) && (0 == (value & UTCR3_TXE))) {
+ if (mTxFifo.size() != 0) {
+ // :SA-1110 Developer's Manual: p.332: Wei 2003-Jun-29:
+ //
+ // If the TXE bit is cleared to zero, all entries within the transmit
+ // FIFO are reset.
+ mTxFifo.clear();
+
+ mUTSR0 |= UTSR0_TFS; // Enable Transmit FIFO service request
+ mUTSR1 |= UTSR1_TNF; // Transmit FIFO not full
+ mNextTxCycle = 0;
+ mTxBuffer.clear();
+ }
+ }
+
+ if ((diff & UTCR3_RXE) && (0 == (value & UTCR3_RXE))) {
+ // :SA-1110 Developer's Manual: p.332: Wei 2003-Jun-29:
+ //
+ // If the RXE bit is cleared to zero, all entries within the receive FIFO
+ // are reset
+ if (false == mRxFifo.empty()) {
+ mRxFifo.clear();
+
+ mUTSR0 &= ~(UTSR0_RID | UTSR0_RFS);
+ mUTSR1 &= ~UTSR1_RNE;
+ }
+ }
+
+ // :NOTE: Wei 2004-Jan-03:
+ //
+ // Bit 6, 7 are reserved.
+ mUTCR3 = static_cast<uint8_t>(value & ~((1 << 7) | (1 << 6)));
+ } break;
+
+ case UTDR:
+ mTxFifo.push_back(static_cast<uint8_t>(value & 0xFF));
+ if (mTxFifo.size() > 4) {
+ mUTSR0 &= ~UTSR0_TFS; // clear TFS (transmit FIFO is more than half full)
+ }
+ if (mTxFifo.size() >= 8) {
+ mUTSR1 &= ~UTSR1_TNF; // clear TNF (transmit FIFO is full)
+ }
+ break;
+
+ case UTSR0:
+ // :SA-1110 Developer's Manual: p.336: Wei 2003-Jun-07:
+ //
+ // Writing a one to a sticky status bit clears it; writing a zero has no
+ // effect. Read-only flags are set and cleared by hardware; writes have no
+ // effect.
+
+ // :NOTE: Wei 2004-Jan-03:
+ //
+ // Bit 6, 7 are reserved.
+ // bits 0, 1, 5 are read-only.
+ mUTSR0 &= ~(value & UTSR0_READ_WRITE_BITS);
+ break;
+
+ case UTSR1:
+ // :NOTE: Wei 2004-Jan-01:
+ //
+ // read-only register.
+ return;
+
+ default:
+ break;
+ }
+}
+} // namespace SA1100
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// 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 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef UART_H
+#define UART_H
+
+#include <cassert>
+#include <cstdint>
+#include <deque>
+#include <functional>
+#include <string>
+#include <vector>
+
+namespace SA1100 {
+
+class IntController;
+
+class Uart {
+public:
+ Uart(std::function<void(const char*)>& output);
+ void reset();
+
+ void run(int64_t passedCycles);
+ void flushTxBuffer();
+
+ inline int64_t getNextTxEventCycle() const {
+ return (mUTCR3 & UTCR3_TXE) && !mTxFifo.empty() ? mNextTxCycle : 0;
+ }
+
+ inline uint32_t getInterruptStatus() const { return mUTSR0; }
+ inline uint32_t getCtrlRegister() const { return mUTCR3; }
+
+ uint32_t read32(const uint32_t address);
+ void write32(const uint32_t address, const uint32_t value);
+
+private:
+ void initRegisters();
+
+ void txData();
+ void rxData();
+
+ enum {
+ UTCR3_RXE = (1 << 0), // Receiver enable.
+ UTCR3_TXE = (1 << 1), // Transmitter enable.
+ UTCR3_BRK = (1 << 2), // Break.
+ UTCR3_RIE = (1 << 3), // Receive FIFO interrupt enable.
+ UTCR3_TIE = (1 << 4), // Transmit FIFO interrupt enable.
+ UTCR3_LBM = (1 << 5) // Loopback mode.
+ };
+
+ enum {
+ UTSR0_TFS = (1 << 0), // Transmit FIFO service request
+ UTSR0_RFS = (1 << 1), // Receive FIFO service request
+ UTSR0_RID = (1 << 2), // Receiver idle.
+ UTSR0_RBB = (1 << 3), // Receiver begin of break.
+ UTSR0_REB = (1 << 4), // Receiver end of break.
+ UTSR0_EIF = (1 << 5), // Error in FIFO (read-only).
+
+ UTSR0_READ_WRITE_BITS = (UTSR0_RID | UTSR0_RBB | UTSR0_REB),
+ };
+
+ enum {
+ UTSR1_TBY = (1 << 0), // Transmitter busy flag
+ UTSR1_RNE = (1 << 1), // Receive FIFO not empty
+ UTSR1_TNF = (1 << 2), // Transmit FIFO not full
+ UTSR1_PRE = (1 << 3), // Parity error
+ UTSR1_FRE = (1 << 4), // Framing error
+ UTSR1_ROR = (1 << 5) // Receive FIFO overrun
+ };
+
+ enum {
+ UTCR0 = 0x80050000,
+ UTCR1 = 0x80050004,
+ UTCR2 = 0x80050008,
+ UTCR3 = 0x8005000C,
+ UTDR = 0x80050014,
+ UTSR0 = 0x8005001C,
+ UTSR1 = 0x80050020
+ };
+
+ uint8_t mUTCR0; // UART control register 0
+ uint8_t mUTCR1; // UART control register 1
+ uint8_t mUTCR2; // UART control register 2
+ uint8_t mUTCR3; // UART control register 3
+ uint8_t mUTDR; // UART data register
+ uint8_t mUTSR0; // UART status register 0
+ uint8_t mUTSR1; // UART status register 1
+
+ std::vector<uint8_t> mTxFifo;
+ std::deque<uint8_t> mRxFifo;
+ bool mNeedAppendMore = false;
+ std::function<void(const char*)>& mSink;
+ std::string mTxBuffer;
+ int64_t mNextTxCycle = 0;
+
+ friend class IntController;
+};
+
+} // namespace SA1100
+
+#endif // UART_H