From 54b49f933abe452a48bf13c9c948946672bb784b Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Sat, 26 Jun 2004 21:26:28 -0400 Subject: [PATCH] rewrote uart and renamed console.cc to simconsole to reduce confusion base/traceflags.py: removed TsunamiUart/TlaserUart and added a plain Uart dev/alpha_console.cc: updated for new simconsole dev/platform.hh: added a uart member to platform dev/simconsole.cc: dev/simconsole.hh: removed lots of legacy code, it should all be ours now. converted tabs to 8 spaces added our copyright dev/tsunami.cc: uses simconsole.hh rather than console.hh dev/tsunami_cchip.cc: dev/tsunami_io.cc: never needed console.hh dev/tsunami_io.hh: this does need eventq.hh and it just happend to be working whenn console.hh was included everywhere dev/tsunamireg.h: added a couple more 8250/16550 uart defines dev/uart.cc: new uart code, rewritten to support both tlaser and tsunami (both a 8250 and 8530 uart). dev/uart.hh: updated for new uart, legacy code removed --HG-- rename : dev/console.cc => dev/simconsole.cc rename : dev/console.hh => dev/simconsole.hh rename : dev/tsunami_uart.cc => dev/uart.cc rename : dev/tsunami_uart.hh => dev/uart.hh extra : convert_revision : e663352d49d4c2d3c95643030cf73c0e85ba2f08 --- base/traceflags.py | 3 +- dev/alpha_console.cc | 4 +- dev/platform.hh | 4 + dev/{console.cc => simconsole.cc} | 155 +++-------- dev/{console.hh => simconsole.hh} | 67 ++--- dev/tsunami.cc | 2 +- dev/tsunami_cchip.cc | 1 - dev/tsunami_io.cc | 1 - dev/tsunami_io.hh | 1 + dev/tsunami_uart.cc | 308 --------------------- dev/tsunamireg.h | 8 + dev/uart.cc | 433 ++++++++++++++++++++++++++++++ dev/{tsunami_uart.hh => uart.hh} | 45 ++-- 13 files changed, 556 insertions(+), 476 deletions(-) rename dev/{console.cc => simconsole.cc} (72%) rename dev/{console.hh => simconsole.hh} (62%) delete mode 100644 dev/tsunami_uart.cc create mode 100644 dev/uart.cc rename dev/{tsunami_uart.hh => uart.hh} (78%) diff --git a/base/traceflags.py b/base/traceflags.py index 14e28219a..363d44ffb 100644 --- a/base/traceflags.py +++ b/base/traceflags.py @@ -63,7 +63,6 @@ baseFlags = [ 'Console', 'ConsolePoll', 'ConsoleVerbose', - 'TlaserUart', 'AlphaConsole', 'Flow', 'Interrupt', @@ -114,7 +113,7 @@ baseFlags = [ 'IdeCtrl', 'IdeDisk', 'Tsunami', - 'TsunamiUart' + 'Uart' ] # diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc index e94ca82ea..86851ff8b 100644 --- a/dev/alpha_console.cc +++ b/dev/alpha_console.cc @@ -40,7 +40,7 @@ #include "cpu/base_cpu.hh" #include "cpu/exec_context.hh" #include "dev/alpha_console.hh" -#include "dev/console.hh" +#include "dev/simconsole.hh" #include "dev/simple_disk.hh" #include "dev/tlaser_clock.hh" #include "mem/bus/bus.hh" @@ -226,7 +226,7 @@ AlphaConsole::write(MemReqPtr &req, const uint8_t *data) break; case offsetof(AlphaAccess, outputChar): - console->out((char)(val & 0xff), false); + console->out((char)(val & 0xff)); break; case offsetof(AlphaAccess, bootStrapImpure): diff --git a/dev/platform.hh b/dev/platform.hh index f0e3d291b..7920480bc 100644 --- a/dev/platform.hh +++ b/dev/platform.hh @@ -39,6 +39,7 @@ class PciConfigAll; class IntrControl; class SimConsole; +class Uart; class Platform : public SimObject { @@ -50,6 +51,9 @@ class Platform : public SimObject /** Pointer to the PCI configuration space */ PciConfigAll *pciconfig; + /** Pointer to the UART, set by the uart */ + Uart *uart; + int interrupt_frequency; public: diff --git a/dev/console.cc b/dev/simconsole.cc similarity index 72% rename from dev/console.cc rename to dev/simconsole.cc index b9bcbb3d1..a15057402 100644 --- a/dev/console.cc +++ b/dev/simconsole.cc @@ -1,8 +1,33 @@ -/* $Id$ */ - +/* + * Copyright (c) 2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* @file - * User Console Definitions + * Implements the user interface to a serial console */ #include @@ -20,10 +45,11 @@ #include "base/misc.hh" #include "base/socket.hh" #include "base/trace.hh" -#include "dev/console.hh" +#include "dev/simconsole.hh" #include "mem/functional_mem/memory_control.hh" #include "sim/builder.hh" #include "targetarch/ev5.hh" +#include "dev/uart.hh" #include "dev/platform.hh" using namespace std; @@ -48,17 +74,17 @@ SimConsole::Event::process(int revent) SimConsole::SimConsole(const string &name, const string &file, int num) : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1), - listener(NULL), txbuf(16384), rxbuf(16384), outfile(NULL), + listener(NULL), txbuf(16384), rxbuf(16384), outfile(NULL) #if TRACING_ON == 1 - linebuf(16384), + , linebuf(16384) #endif - _status(0), _enable(0), intr(NULL), platform(NULL) { if (!file.empty()) outfile = new ofstream(file.c_str()); if (outfile) outfile->setf(ios::unitbuf); + } SimConsole::~SimConsole() @@ -130,7 +156,8 @@ SimConsole::data() len = read(buf, sizeof(buf)); if (len) { rxbuf.write((char *)buf, len); - raiseInt(ReceiveInterrupt); + // Inform the UART there is data available + uart->dataAvailable(); } } @@ -138,7 +165,7 @@ size_t SimConsole::read(uint8_t *buf, size_t len) { if (in_fd < 0) - panic("SimConsole(read): Console not properly attached.\n"); + panic("Console not properly attached.\n"); size_t ret; do { @@ -147,7 +174,7 @@ SimConsole::read(uint8_t *buf, size_t len) if (ret < 0) - DPRINTFN("SimConsole(read): Read failed.\n"); + DPRINTFN("Read failed.\n"); if (ret <= 0) { detach(); @@ -162,7 +189,7 @@ size_t SimConsole::write(const uint8_t *buf, size_t len) { if (out_fd < 0) - panic("SimConsole(write): Console not properly attached.\n"); + panic("Console not properly attached.\n"); size_t ret; for (;;) { @@ -172,33 +199,12 @@ SimConsole::write(const uint8_t *buf, size_t len) break; if (errno != EINTR) - detach(); + detach(); } return ret; } -void -SimConsole::configTerm() -{ - struct termios ios; - - if (isatty(out_fd)) { - if (tcgetattr(out_fd, &ios) < 0) { - panic( "tcgetattr\n"); - } - ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON); - ios.c_oflag &= ~(OPOST); - ios.c_oflag &= (ONLCR); - ios.c_lflag &= ~(ISIG|ICANON|ECHO); - ios.c_cc[VMIN] = 1; - ios.c_cc[VTIME] = 0; - if (tcsetattr(out_fd, TCSANOW, &ios) < 0) { - panic( "tcsetattr\n"); - } - } -} - #define MORE_PENDING (ULL(1) << 61) #define RECEIVE_SUCCESS (ULL(0) << 62) #define RECEIVE_NONE (ULL(2) << 62) @@ -216,9 +222,6 @@ SimConsole::in(uint8_t &c) empty = rxbuf.empty(); } - if (empty) - clearInt(ReceiveInterrupt); - DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d, return: %d\n", isprint(c) ? c : ' ', c, !empty, ret); @@ -245,7 +248,7 @@ SimConsole::console_in() } void -SimConsole::out(char c, bool raise_int) +SimConsole::out(char c) { #if TRACING_ON == 1 if (DTRACE(Console)) { @@ -277,90 +280,20 @@ SimConsole::out(char c, bool raise_int) if (outfile) outfile->write(&c, 1); - if (raise_int) - raiseInt(TransmitInterrupt); - - DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x", + DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x\n", isprint(c) ? c : ' ', (int)c); - if (raise_int) - DPRINTF(ConsoleVerbose, "status: %#x\n", _status); - else - DPRINTF(ConsoleVerbose, "\n"); -} - -inline bool -MaskStatus(int status, int mask) -{ return (status & mask) != 0; } - -int -SimConsole::clearInt(int i) -{ - int old = _status; - _status &= ~i; - //if (MaskStatus(old, _enable) != MaskStatus(_status, _enable) && intr) - platform->clearConsoleInt(); - - return old; -} - -void -SimConsole::raiseInt(int i) -{ - //int old = _status; - _status |= i; - //if (MaskStatus(old, _enable) != MaskStatus(_status, _enable) && intr) - platform->postConsoleInt(); -} - -void -SimConsole::initInt(IntrControl *i) -{ - if (intr) - panic("Console has already been initialized."); - - intr = i; } -void -SimConsole::setInt(int bits) -{ - int old; - - if (bits & ~(TransmitInterrupt | ReceiveInterrupt)) - panic("An interrupt was not set!"); - - old = _enable; - _enable |= bits; - - //if (MaskStatus(_status, old) != MaskStatus(_status, _enable) && intr) { - if (intr) { - if (MaskStatus(_status, _enable)) - platform->postConsoleInt(); - else - platform->clearConsoleInt(); - } -} - -void -SimConsole::setPlatform(Platform *p) -{ - platform = p; - platform->cons = this; -} void SimConsole::serialize(ostream &os) { - SERIALIZE_SCALAR(_status); - SERIALIZE_SCALAR(_enable); } void SimConsole::unserialize(Checkpoint *cp, const std::string §ion) { - UNSERIALIZE_SCALAR(_status); - UNSERIALIZE_SCALAR(_enable); } @@ -368,7 +301,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole) SimObjectParam listener; SimObjectParam intr_control; - SimObjectParam platform; Param output; Param append_name; Param number; @@ -379,7 +311,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole) INIT_PARAM(listener, "console listener"), INIT_PARAM(intr_control, "interrupt controller"), - INIT_PARAM(platform, "platform"), INIT_PARAM_DFLT(output, "file to dump output to", ""), INIT_PARAM_DFLT(append_name, "append name() to filename", true), INIT_PARAM_DFLT(number, "console number", 0) @@ -401,10 +332,6 @@ CREATE_SIM_OBJECT(SimConsole) SimConsole *console = new SimConsole(getInstanceName(), filename, number); ((ConsoleListener *)listener)->add(console); - ((SimConsole *)console)->initInt(intr_control); - ((SimConsole *)console)->setPlatform(platform); - //((SimConsole *)console)->setInt(SimConsole::TransmitInterrupt | - // SimConsole::ReceiveInterrupt); return console; } diff --git a/dev/console.hh b/dev/simconsole.hh similarity index 62% rename from dev/console.hh rename to dev/simconsole.hh index 87be9ccbc..138e2e36a 100644 --- a/dev/console.hh +++ b/dev/simconsole.hh @@ -1,4 +1,30 @@ -/* $Id$ */ +/* + * Copyright (c) 2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* @file * User Console Interface @@ -16,8 +42,13 @@ #include "sim/sim_object.hh" class ConsoleListener; +class Uart; + class SimConsole : public SimObject { + public: + Uart *uart; + protected: class Event : public PollEvent { @@ -36,8 +67,6 @@ class SimConsole : public SimObject int number; int in_fd; int out_fd; - - protected: ConsoleListener *listener; public: @@ -68,18 +97,6 @@ class SimConsole : public SimObject void write(uint8_t c) { write(&c, 1); } size_t write(const uint8_t *buf, size_t len); - void configTerm(); - - protected: - // interrupt status/enable - int _status; - int _enable; - - // interrupt handle - IntrControl *intr; - // Platform so we can post interrupts - Platform *platform; - public: ///////////////// // OS interface @@ -102,24 +119,10 @@ class SimConsole : public SimObject uint64_t console_in(); // Send a character to the console - void out(char c, bool raise_int = true); - - enum { - TransmitInterrupt = 1, - ReceiveInterrupt = 2 - }; - - // Read the current interrupt status of this console. - int intStatus() { return _status; } - - // Set the interrupt enable bits. - int clearInt(int i); - void raiseInt(int i); - - void initInt(IntrControl *i); - void setInt(int bits); + void out(char c); - void setPlatform(Platform *p); + //Ask the console if data is available + bool dataAvailable() { return !rxbuf.empty(); } virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); diff --git a/dev/tsunami.cc b/dev/tsunami.cc index 1cdd7d726..c44da69b7 100644 --- a/dev/tsunami.cc +++ b/dev/tsunami.cc @@ -31,7 +31,7 @@ #include #include "cpu/intr_control.hh" -#include "dev/console.hh" +#include "dev/simconsole.hh" #include "dev/etherdev.hh" #include "dev/ide_ctrl.hh" #include "dev/tlaser_clock.hh" diff --git a/dev/tsunami_cchip.cc b/dev/tsunami_cchip.cc index a64f643a2..0fbfcb56f 100644 --- a/dev/tsunami_cchip.cc +++ b/dev/tsunami_cchip.cc @@ -35,7 +35,6 @@ #include #include "base/trace.hh" -#include "dev/console.hh" #include "dev/tsunami_cchip.hh" #include "dev/tsunamireg.h" #include "dev/tsunami.hh" diff --git a/dev/tsunami_io.cc b/dev/tsunami_io.cc index ea530b3d2..4c798a852 100644 --- a/dev/tsunami_io.cc +++ b/dev/tsunami_io.cc @@ -37,7 +37,6 @@ #include #include "base/trace.hh" -#include "dev/console.hh" #include "dev/tsunami_io.hh" #include "dev/tsunami.hh" #include "mem/bus/bus.hh" diff --git a/dev/tsunami_io.hh b/dev/tsunami_io.hh index e6a545689..75e5d764c 100644 --- a/dev/tsunami_io.hh +++ b/dev/tsunami_io.hh @@ -36,6 +36,7 @@ #include "dev/io_device.hh" #include "base/range.hh" #include "dev/tsunami.hh" +#include "sim/eventq.hh" /** How often the RTC interrupts */ static const int RTC_RATE = 1024; diff --git a/dev/tsunami_uart.cc b/dev/tsunami_uart.cc deleted file mode 100644 index c6da02cf4..000000000 --- a/dev/tsunami_uart.cc +++ /dev/null @@ -1,308 +0,0 @@ -/* $Id$ */ - -/* @file - * Tsunami UART - */ - -/* - * Copyright (C) 1998 by the Board of Trustees - * of Leland Stanford Junior University. - * Copyright (C) 1998 Digital Equipment Corporation - * - * This file is part of the SimOS distribution. - * See LICENSE file for terms of the license. - * - */ - -#include -#include - -#include "base/inifile.hh" -#include "base/str.hh" // for to_number -#include "base/trace.hh" -#include "dev/console.hh" -#include "dev/tsunami_uart.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional_mem/memory_control.hh" -#include "sim/builder.hh" -#include "targetarch/ev5.hh" - -using namespace std; - -#define CONS_INT_TX 0x01 // interrupt enable / state bits -#define CONS_INT_RX 0x02 - - -TsunamiUart::IntrEvent::IntrEvent(TsunamiUart *u) - : Event(&mainEventQueue), uart(u) -{ - DPRINTF(TsunamiUart, "UART Interrupt Event Initilizing\n"); -} - -const char * -TsunamiUart::IntrEvent::description() -{ - return "tsunami uart interrupt delay event"; -} - -void -TsunamiUart::IntrEvent::process() -{ - if (UART_IER_THRI & uart->IER) { - DPRINTF(TsunamiUart, "UART InterEvent, interrupting\n"); - uart->cons->raiseInt(CONS_INT_TX); - } - else - DPRINTF(TsunamiUart, "UART InterEvent, not interrupting\n"); - -} - -void -TsunamiUart::IntrEvent::scheduleIntr() -{ - DPRINTF(TsunamiUart, "Scheduling IER interrupt\n"); - if (!scheduled()) - schedule(curTick + 300); - else - reschedule(curTick + 300); -} - - - -TsunamiUart::TsunamiUart(const string &name, SimConsole *c, - MemoryController *mmu, Addr a, - HierParams *hier, Bus *bus) - : PioDevice(name), addr(a), cons(c), status_store(0), valid_char(false), - intrEvent(this) -{ - mmu->add_child(this, Range(addr, addr + size)); - - if (bus) { - pioInterface = newPioInterface(name, hier, bus, this, - &TsunamiUart::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); - } - - IER = 0; -} - -Fault -TsunamiUart::read(MemReqPtr &req, uint8_t *data) -{ - Addr daddr = req->paddr - (addr & PA_IMPL_MASK); - DPRINTF(TsunamiUart, " read register %#x\n", daddr); - - switch (req->size) { - case sizeof(uint64_t): - *(uint64_t *)data = 0; - break; - case sizeof(uint32_t): - *(uint32_t *)data = 0; - break; - case sizeof(uint16_t): - *(uint16_t *)data = 0; - break; - case sizeof(uint8_t): - *(uint8_t *)data = 0; - break; - } - - - switch(daddr) { - case 0x5: // Status Register - { - int status = cons->intStatus(); - if (!valid_char) { - valid_char = cons->in(next_char); - if (!valid_char) - status &= ~CONS_INT_RX; - } else { - status |= CONS_INT_RX; - } - - if (status_store == 3) { - // RR3 stuff? Don't really understand it, btw - status_store = 0; - if (status & CONS_INT_TX) { - *data = (1 << 4); - return No_Fault; - } else if (status & CONS_INT_RX) { - *data = (1 << 5); - return No_Fault; - } else { - DPRINTF(TsunamiUart, "spurious read\n"); - return No_Fault; - } - } else { - int reg = (1 << 2) | (1 << 5) | (1 << 6); - if (status & CONS_INT_RX) - reg |= (1 << 0); - *data = reg; - return No_Fault; - } - break; - } - - case 0x0: // Data register (RX) - DPRINTF(TsunamiUart, "read data register \'%c\' %#02x\n", - isprint(next_char) ? next_char : ' ', next_char); - - *data = next_char; - valid_char = false; - return No_Fault; - - case 0x1: // Interrupt Enable Register - // This is the lovely way linux checks there is actually a serial - // port at the desired address - if (IER == 0) - *data = 0; - else if (IER == 0x0F) - *data = 0x0F; - else - *data = 0; - return No_Fault; - case 0x2: - // High two bits need to be clear for an 8250 (simple) serial port - // Low bit of IIR is 0 for a pending interrupt, 1 otherwise. - int status = cons->intStatus(); - status = (status & 0x1) | (status >> 1); - *data = (~status) & 0x1 ; - return No_Fault; - } - *data = 0; - // panic("%s: read daddr=%#x type=read *data=%#x\n", name(), daddr, *data); - - return No_Fault; -} - -Fault -TsunamiUart::write(MemReqPtr &req, const uint8_t *data) -{ - Addr daddr = req->paddr - (addr & PA_IMPL_MASK); - - DPRINTF(TsunamiUart, " write register %#x value %#x\n", daddr, *(uint8_t*)data); - - switch (daddr) { - case 0x3: - status_store = *data; - switch (*data) { - case 0x03: // going to read RR3 - return No_Fault; - - case 0x28: // Ack of TX - { - if ((cons->intStatus() & CONS_INT_TX) == 0) - panic("Ack of transmit, though there was no interrupt"); - - cons->clearInt(CONS_INT_TX); - return No_Fault; - } - - case 0x00: - case 0x01: - case 0x12: - // going to write data??? - return No_Fault; - - default: - DPRINTF(TsunamiUart, "writing status register %#x \n", - *(uint8_t *)data); - return No_Fault; - } - - case 0x0: // Data register (TX) - char ourchar; - ourchar = *(uint8_t *)data; - if ((isprint(ourchar) || iscntrl(ourchar)) && (ourchar != 0x0C)) - cons->out(ourchar); - cons->clearInt(CONS_INT_TX); - intrEvent.scheduleIntr(); - return No_Fault; - break; - case 0x1: // IER - IER = *(uint8_t*)data; - DPRINTF(TsunamiUart, "writing to IER [%#x]\n", IER); - if (UART_IER_THRI & IER) - cons->raiseInt(CONS_INT_TX); - else { - cons->clearInt(CONS_INT_TX); - if (intrEvent.scheduled()) - intrEvent.deschedule(); - } - return No_Fault; - break; - case 0x4: // MCR - DPRINTF(TsunamiUart, "writing to MCR %#x\n", *(uint8_t*)data); - return No_Fault; - - } - - return No_Fault; -} - -Tick -TsunamiUart::cacheAccess(MemReqPtr &req) -{ - return curTick + 1000; -} - -void -TsunamiUart::serialize(ostream &os) -{ - SERIALIZE_SCALAR(status_store); - SERIALIZE_SCALAR(next_char); - SERIALIZE_SCALAR(valid_char); - SERIALIZE_SCALAR(IER); - Tick intrwhen; - if (intrEvent.scheduled()) - intrwhen = intrEvent.when(); - else - intrwhen = 0; - SERIALIZE_SCALAR(intrwhen); - - -} - -void -TsunamiUart::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(status_store); - UNSERIALIZE_SCALAR(next_char); - UNSERIALIZE_SCALAR(valid_char); - UNSERIALIZE_SCALAR(IER); - Tick intrwhen; - UNSERIALIZE_SCALAR(intrwhen); - if (intrwhen != 0) - intrEvent.schedule(intrwhen); - -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiUart) - - SimObjectParam console; - SimObjectParam mmu; - Param addr; - SimObjectParam io_bus; - SimObjectParam hier; - - -END_DECLARE_SIM_OBJECT_PARAMS(TsunamiUart) - -BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiUart) - - INIT_PARAM(console, "The console"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(TsunamiUart) - -CREATE_SIM_OBJECT(TsunamiUart) -{ - return new TsunamiUart(getInstanceName(), console, mmu, addr, hier, io_bus); -} - -REGISTER_SIM_OBJECT("TsunamiUart", TsunamiUart) diff --git a/dev/tsunamireg.h b/dev/tsunamireg.h index 2e4e873a0..876c6bf18 100644 --- a/dev/tsunamireg.h +++ b/dev/tsunamireg.h @@ -140,7 +140,15 @@ // UART Defines +#define UART_IER_RDI 0x01 #define UART_IER_THRI 0x02 #define UART_IER_RLSI 0x04 + +#define UART_LSR_TEMT 0x40 +#define UART_LSR_THRE 0x20 +#define UART_LSR_DR 0x01 + +#define UART_MCR_LOOP 0x10 + #endif // __TSUNAMIREG_H__ diff --git a/dev/uart.cc b/dev/uart.cc new file mode 100644 index 000000000..30dde1984 --- /dev/null +++ b/dev/uart.cc @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Implements a 8250 UART + */ + +#include +#include + +#include "base/inifile.hh" +#include "base/str.hh" // for to_number +#include "base/trace.hh" +#include "dev/simconsole.hh" +#include "dev/uart.hh" +#include "dev/platform.hh" +#include "mem/bus/bus.hh" +#include "mem/bus/pio_interface.hh" +#include "mem/bus/pio_interface_impl.hh" +#include "mem/functional_mem/memory_control.hh" +#include "sim/builder.hh" +#include "targetarch/ev5.hh" + +using namespace std; + +Uart::IntrEvent::IntrEvent(Uart *u) + : Event(&mainEventQueue), uart(u) +{ + DPRINTF(Uart, "UART Interrupt Event Initilizing\n"); +} + +const char * +Uart::IntrEvent::description() +{ + return "uart interrupt delay event"; +} + +void +Uart::IntrEvent::process() +{ + if (UART_IER_THRI & uart->IER) { + DPRINTF(Uart, "UART InterEvent, interrupting\n"); + uart->platform->postConsoleInt(); + uart->status |= TX_INT; + } + else + DPRINTF(Uart, "UART InterEvent, not interrupting\n"); + +} + +void +Uart::IntrEvent::scheduleIntr() +{ + DPRINTF(Uart, "Scheduling IER interrupt\n"); + if (!scheduled()) + schedule(curTick + 300); + else + reschedule(curTick + 300); +} + +Uart::Uart(const string &name, SimConsole *c, MemoryController *mmu, Addr a, + Addr s, HierParams *hier, Bus *bus, Platform *p) + : PioDevice(name), addr(a), size(s), cons(c), intrEvent(this), platform(p) +{ + mmu->add_child(this, Range(addr, addr + size)); + + + if (bus) { + pioInterface = newPioInterface(name, hier, bus, this, + &Uart::cacheAccess); + pioInterface->addAddrRange(addr, addr + size - 1); + } + + readAddr = 0; + IER = 0; + DLAB = 0; + LCR = 0; + MCR = 0; + status = 0; + + // set back pointers + cons->uart = this; + platform->uart = this; + +} + +Fault +Uart::read(MemReqPtr &req, uint8_t *data) +{ + Addr daddr = req->paddr - (addr & PA_IMPL_MASK); + DPRINTF(Uart, " read register %#x\n", daddr); + + + +#ifdef ALPHA_TLASER + + switch (req->size) { + case sizeof(uint64_t): + *(uint64_t *)data = 0; + break; + case sizeof(uint32_t): + *(uint32_t *)data = 0; + break; + case sizeof(uint16_t): + *(uint16_t *)data = 0; + break; + case sizeof(uint8_t): + *(uint8_t *)data = 0; + break; + } + + switch (daddr) { + case 0x80: // Status Register + if (readAddr == 3) { + readAddr = 0; + if (status & TX_INT) + *data = (1 << 4); + else if (status & RX_INT) + *data = (1 << 5); + else + DPRINTF(Uart, "spurious read\n"); + + } else { + *data = (1 << 2); + if (status & RX_INT) + *data |= (1 << 0); + } + break; + + case 0xc0: // Data register (RX) + if (!cons->dataAvailable()) + panic("No data to read"); + + cons->in(*data); + + if (!cons->dataAvailable()) { + platform->clearConsoleInt(); + status &= ~RX_INT; + } + + DPRINTF(Uart, "read data register \'%c\' %2x\n", + isprint(*data) ? *data : ' ', *data); + break; + } + + +#else + + + assert(req->size == 1); + + switch (daddr) { + case 0x0: + if (!(LCR & 0x80)) { // read byte + //assert(cons->dataAvailable()); + if (cons->dataAvailable()) + cons->in(*data); + else { + *(uint8_t*)data = 0; + // A limited amount of these are ok. + DPRINTF(Uart, "empty read of RX register\n"); + } + + if (cons->dataAvailable()) + platform->postConsoleInt(); + else + { + status &= ~RX_INT; + platform->clearConsoleInt(); + } + } else { // dll divisor latch + ; + } + break; + case 0x1: + if (!(LCR & 0x80)) { // Intr Enable Register(IER) + *(uint8_t*)data = IER; + } else { // DLM divisor latch MSB + ; + } + break; + case 0x2: // Intr Identification Register (IIR) + if (status) + *(uint8_t*)data = 1; + else + *(uint8_t*)data = 0; + break; + case 0x3: // Line Control Register (LCR) + *(uint8_t*)data = LCR; + break; + case 0x4: // Modem Control Register (MCR) + break; + case 0x5: // Line Status Register (LSR) + uint8_t lsr; + lsr = 0; + // check if there are any bytes to be read + if (cons->dataAvailable()) + lsr = UART_LSR_DR; + lsr |= UART_LSR_TEMT | UART_LSR_THRE; + *(uint8_t*)data = lsr; + break; + case 0x6: // Modem Status Register (MSR) + *(uint8_t*)data = 0; + break; + case 0x7: // Scratch Register (SCR) + *(uint8_t*)data = 0; // doesn't exist with at 8250. + break; + default: + panic("Tried to access a UART port that doesn't exist\n"); + break; + } + +#endif + return No_Fault; + +} + +Fault +Uart::write(MemReqPtr &req, const uint8_t *data) +{ + Addr daddr = req->paddr - (addr & PA_IMPL_MASK); + + DPRINTF(Uart, " write register %#x value %#x\n", daddr, *(uint8_t*)data); + +#ifdef ALPHA_TLASER + + switch (daddr) { + case 0x80: + readAddr = *data; + switch (*data) { + case 0x28: // Ack of TX + if ((status & TX_INT) == 0) + panic("Ack of transmit, though there was no interrupt"); + + status &= ~TX_INT; + platform->clearConsoleInt(); + break; + case 0x00: + case 0x01: + case 0x03: // going to read RR3 + case 0x12: + break; + default: + DPRINTF(Uart, "writing status register %#x \n", + *(uint64_t *)data); + break; + } + break; + + case 0xc0: // Data register (TX) + cons->out(*(uint64_t *)data); + platform->postConsoleInt(); + status |= TX_INT; + break; + } + + +#else + switch (daddr) { + case 0x0: + if (!(LCR & 0x80)) { // write byte + cons->out(*(uint64_t *)data); + platform->clearConsoleInt(); + status &= ~TX_INT; + if (UART_IER_THRI & IER) + intrEvent.scheduleIntr(); + } else { // dll divisor latch + ; + } + break; + case 0x1: + if (!(LCR & 0x80)) { // Intr Enable Register(IER) + IER = *(uint8_t*)data; + if ((UART_IER_THRI & IER) || ((UART_IER_RDI & IER) && cons->dataAvailable())) + platform->postConsoleInt(); + else + { + platform->clearConsoleInt(); + if (intrEvent.scheduled()) + intrEvent.deschedule(); + + } + if (!(UART_IER_THRI & IER)) + status &= ~TX_INT; + if (!((UART_IER_RDI & IER) && cons->dataAvailable())) + status &= ~RX_INT; + } else { // DLM divisor latch MSB + ; + } + break; + case 0x2: // FIFO Control Register (FCR) + break; + case 0x3: // Line Control Register (LCR) + LCR = *(uint8_t*)data; + break; + case 0x4: // Modem Control Register (MCR) + if (*(uint8_t*)data == (UART_MCR_LOOP | 0x0A)) + MCR = 0x9A; + break; + case 0x7: // Scratch Register (SCR) + // We are emulating a 8250 so we don't have a scratch reg + break; + default: + panic("Tried to access a UART port that doesn't exist\n"); + break; + } +#endif + + return No_Fault; +} + +void +Uart::dataAvailable() +{ +#ifdef ALPHA_TLASER + platform->postConsoleInt(); + status |= RX_INT; +#else + + // if the kernel wants an interrupt when we have data + if (IER & UART_IER_RDI) + { + platform->postConsoleInt(); + status |= RX_INT; + } + +#endif +} + +Tick +Uart::cacheAccess(MemReqPtr &req) +{ + return curTick + 1000; +} + +void +Uart::serialize(ostream &os) +{ +#ifdef ALPHA_TLASER + SERIALIZE_SCALAR(readAddr); + SERIALIZE_SCALAR(status); +#else + SERIALIZE_SCALAR(status); + SERIALIZE_SCALAR(IER); + SERIALIZE_SCALAR(DLAB); + SERIALIZE_SCALAR(LCR); + SERIALIZE_SCALAR(MCR); + Tick intrwhen; + if (intrEvent.scheduled()) + intrwhen = intrEvent.when(); + else + intrwhen = 0; + SERIALIZE_SCALAR(intrwhen); +#endif +} + +void +Uart::unserialize(Checkpoint *cp, const std::string §ion) +{ +#ifdef ALPHA_TLASER + UNSERIALIZE_SCALAR(readAddr); + UNSERIALIZE_SCALAR(status); +#else + UNSERIALIZE_SCALAR(status); + UNSERIALIZE_SCALAR(IER); + UNSERIALIZE_SCALAR(DLAB); + UNSERIALIZE_SCALAR(LCR); + UNSERIALIZE_SCALAR(MCR); + Tick intrwhen; + UNSERIALIZE_SCALAR(intrwhen); + if (intrwhen != 0) + intrEvent.schedule(intrwhen); +#endif + +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart) + + SimObjectParam console; + SimObjectParam mmu; + SimObjectParam platform; + Param addr; + Param size; + SimObjectParam io_bus; + SimObjectParam hier; + + +END_DECLARE_SIM_OBJECT_PARAMS(Uart) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Uart) + + INIT_PARAM(console, "The console"), + INIT_PARAM(mmu, "Memory Controller"), + INIT_PARAM(platform, "Pointer to platfrom"), + INIT_PARAM(addr, "Device Address"), + INIT_PARAM_DFLT(size, "Device size", 0x8), + INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL), + INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) + +END_INIT_SIM_OBJECT_PARAMS(Uart) + +CREATE_SIM_OBJECT(Uart) +{ + return new Uart(getInstanceName(), console, mmu, addr, size, hier, io_bus, + platform); +} + +REGISTER_SIM_OBJECT("Uart", Uart) diff --git a/dev/tsunami_uart.hh b/dev/uart.hh similarity index 78% rename from dev/tsunami_uart.hh rename to dev/uart.hh index 14ee42e8b..83e1a758c 100644 --- a/dev/tsunami_uart.hh +++ b/dev/uart.hh @@ -27,7 +27,7 @@ */ /* @file - * Tsunami UART + * Defines a 8250 UART */ #ifndef __TSUNAMI_UART_HH__ @@ -38,45 +38,60 @@ #include "dev/io_device.hh" class SimConsole; +class Platform; -/* - * Tsunami UART - */ -class TsunamiUart : public PioDevice +const int RX_INT = 0x1; +const int TX_INT = 0x2; + + +class Uart : public PioDevice { + private: Addr addr; - static const Addr size = 0x8; + Addr size; + SimConsole *cons; protected: - SimConsole *cons; - int status_store; - uint8_t next_char; - bool valid_char; - uint8_t IER; + int readAddr; // tlaser only + uint8_t IER, DLAB, LCR, MCR; + int status; class IntrEvent : public Event { protected: - TsunamiUart *uart; + Uart *uart; public: - IntrEvent(TsunamiUart *u); + IntrEvent(Uart *u); virtual void process(); virtual const char *description(); void scheduleIntr(); }; IntrEvent intrEvent; + Platform *platform; public: - TsunamiUart(const string &name, SimConsole *c, MemoryController *mmu, - Addr a, HierParams *hier, Bus *bus); + Uart(const string &name, SimConsole *c, MemoryController *mmu, + Addr a, Addr s, HierParams *hier, Bus *bus, Platform *p); Fault read(MemReqPtr &req, uint8_t *data); Fault write(MemReqPtr &req, const uint8_t *data); + /** + * Inform the uart that there is data available. + */ + void dataAvailable(); + + + /** + * Return if we have an interrupt pending + * @return interrupt status + */ + bool intStatus() { return status ? true : false; } + virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); -- 2.30.2