From 54b49f933abe452a48bf13c9c948946672bb784b Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Sat, 26 Jun 2004 21:26:28 -0400 Subject: 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/console.cc | 497 --------------------------------------------------- dev/console.hh | 162 ----------------- dev/platform.hh | 4 + dev/simconsole.cc | 424 +++++++++++++++++++++++++++++++++++++++++++ dev/simconsole.hh | 165 +++++++++++++++++ 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/tsunami_uart.hh | 91 ---------- dev/tsunamireg.h | 8 + dev/uart.cc | 433 ++++++++++++++++++++++++++++++++++++++++++++ dev/uart.hh | 106 +++++++++++ 16 files changed, 1145 insertions(+), 1065 deletions(-) delete mode 100644 dev/console.cc delete mode 100644 dev/console.hh create mode 100644 dev/simconsole.cc create mode 100644 dev/simconsole.hh delete mode 100644 dev/tsunami_uart.cc delete mode 100644 dev/tsunami_uart.hh create mode 100644 dev/uart.cc create mode 100644 dev/uart.hh 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/console.cc b/dev/console.cc deleted file mode 100644 index b9bcbb3d1..000000000 --- a/dev/console.cc +++ /dev/null @@ -1,497 +0,0 @@ -/* $Id$ */ - - -/* @file - * User Console Definitions - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "base/misc.hh" -#include "base/socket.hh" -#include "base/trace.hh" -#include "dev/console.hh" -#include "mem/functional_mem/memory_control.hh" -#include "sim/builder.hh" -#include "targetarch/ev5.hh" -#include "dev/platform.hh" - -using namespace std; - -//////////////////////////////////////////////////////////////////////// -// -// - -SimConsole::Event::Event(SimConsole *c, int fd, int e) - : PollEvent(fd, e), cons(c) -{ -} - -void -SimConsole::Event::process(int revent) -{ - if (revent & POLLIN) - cons->data(); - else if (revent & POLLNVAL) - cons->detach(); -} - -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), -#if TRACING_ON == 1 - 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() -{ - close(); - - if (outfile) - delete outfile; -} - -void -SimConsole::close() -{ - if (in_fd != -1) - ::close(in_fd); - - if (out_fd != in_fd && out_fd != -1) - ::close(out_fd); -} - -void -SimConsole::attach(int in, int out, ConsoleListener *l) -{ - in_fd = in; - out_fd = out; - listener = l; - - event = new Event(this, in, POLLIN); - pollQueue.schedule(event); - - stringstream stream; - ccprintf(stream, "==== m5 slave console: Console %d ====", number); - - // we need an actual carriage return followed by a newline for the - // terminal - stream << "\r\n"; - - write((const uint8_t *)stream.str().c_str(), stream.str().size()); - - - DPRINTFN("attach console %d\n", number); - - txbuf.readall(out); -} - -void -SimConsole::detach() -{ - close(); - in_fd = -1; - out_fd = -1; - - pollQueue.remove(event); - - if (listener) { - listener->add(this); - listener = NULL; - } - - DPRINTFN("detach console %d\n", number); -} - -void -SimConsole::data() -{ - uint8_t buf[1024]; - int len; - - len = read(buf, sizeof(buf)); - if (len) { - rxbuf.write((char *)buf, len); - raiseInt(ReceiveInterrupt); - } -} - -size_t -SimConsole::read(uint8_t *buf, size_t len) -{ - if (in_fd < 0) - panic("SimConsole(read): Console not properly attached.\n"); - - size_t ret; - do { - ret = ::read(in_fd, buf, len); - } while (ret == -1 && errno == EINTR); - - - if (ret < 0) - DPRINTFN("SimConsole(read): Read failed.\n"); - - if (ret <= 0) { - detach(); - return 0; - } - - return ret; -} - -// Console output. -size_t -SimConsole::write(const uint8_t *buf, size_t len) -{ - if (out_fd < 0) - panic("SimConsole(write): Console not properly attached.\n"); - - size_t ret; - for (;;) { - ret = ::write(out_fd, buf, len); - - if (ret >= 0) - break; - - if (errno != EINTR) - 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) -#define RECEIVE_ERROR (ULL(3) << 62) - -bool -SimConsole::in(uint8_t &c) -{ - bool empty, ret; - - empty = rxbuf.empty(); - ret = !empty; - if (!empty) { - rxbuf.read((char *)&c, 1); - empty = rxbuf.empty(); - } - - if (empty) - clearInt(ReceiveInterrupt); - - DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d, return: %d\n", - isprint(c) ? c : ' ', c, !empty, ret); - - return ret; -} - -uint64_t -SimConsole::console_in() -{ - uint8_t c; - uint64_t value; - - if (in(c)) { - value = RECEIVE_SUCCESS | c; - if (!rxbuf.empty()) - value |= MORE_PENDING; - } else { - value = RECEIVE_NONE; - } - - DPRINTF(ConsoleVerbose, "console_in: return: %#x\n", value); - - return value; -} - -void -SimConsole::out(char c, bool raise_int) -{ -#if TRACING_ON == 1 - if (DTRACE(Console)) { - static char last = '\0'; - - if (c != '\n' && c != '\r' || - last != '\n' && last != '\r') { - if (c == '\n' || c == '\r') { - int size = linebuf.size(); - char *buffer = new char[size + 1]; - linebuf.read(buffer, size); - buffer[size] = '\0'; - DPRINTF(Console, "%s\n", buffer); - delete [] buffer; - } else { - linebuf.write(c); - } - } - - last = c; - } -#endif - - txbuf.write(c); - - if (out_fd >= 0) - write(c); - - if (outfile) - outfile->write(&c, 1); - - if (raise_int) - raiseInt(TransmitInterrupt); - - DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x", - 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); -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole) - - SimObjectParam listener; - SimObjectParam intr_control; - SimObjectParam platform; - Param output; - Param append_name; - Param number; - -END_DECLARE_SIM_OBJECT_PARAMS(SimConsole) - -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) - -END_INIT_SIM_OBJECT_PARAMS(SimConsole) - -CREATE_SIM_OBJECT(SimConsole) -{ - string filename = output; - if (filename.empty()) { - if (!outputDirectory.empty()) - filename = outputDirectory + getInstanceName(); - } else { - if (append_name) - filename += "." + getInstanceName(); - if (!outputDirectory.empty()) - filename = outputDirectory + filename; - } - - 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; -} - -REGISTER_SIM_OBJECT("SimConsole", SimConsole) - -//////////////////////////////////////////////////////////////////////// -// -// - -ConsoleListener::ConsoleListener(const string &name) - : SimObject(name), event(NULL) -{} - -ConsoleListener::~ConsoleListener() -{ - if (event) - delete event; -} - -void -ConsoleListener::Event::process(int revent) -{ - listener->accept(); -} - -/////////////////////////////////////////////////////////////////////// -// socket creation and console attach -// - -void -ConsoleListener::listen(int port) -{ - while (!listener.listen(port, true)) { - DPRINTF(Console, - ": can't bind address console port %d inuse PID %d\n", - port, getpid()); - port++; - } - - ccprintf(cerr, "Listening for console connection on port %d\n", port); - - event = new Event(this, listener.getfd(), POLLIN); - pollQueue.schedule(event); -} - -void -ConsoleListener::add(SimConsole *cons) -{ ConsoleList.push_back(cons);} - -void -ConsoleListener::accept() -{ - if (!listener.islistening()) - panic("%s: cannot accept a connection if not listening!", name()); - - int sfd = listener.accept(true); - if (sfd != -1) { - iter_t i = ConsoleList.begin(); - iter_t end = ConsoleList.end(); - if (i == end) { - close(sfd); - } else { - (*i)->attach(sfd, this); - i = ConsoleList.erase(i); - } - } -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) - - Param port; - -END_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) - -BEGIN_INIT_SIM_OBJECT_PARAMS(ConsoleListener) - - INIT_PARAM_DFLT(port, "listen port", 3456) - -END_INIT_SIM_OBJECT_PARAMS(ConsoleListener) - -CREATE_SIM_OBJECT(ConsoleListener) -{ - ConsoleListener *listener = new ConsoleListener(getInstanceName()); - listener->listen(port); - - return listener; -} - -REGISTER_SIM_OBJECT("ConsoleListener", ConsoleListener) diff --git a/dev/console.hh b/dev/console.hh deleted file mode 100644 index 87be9ccbc..000000000 --- a/dev/console.hh +++ /dev/null @@ -1,162 +0,0 @@ -/* $Id$ */ - -/* @file - * User Console Interface - */ - -#ifndef __CONSOLE_HH__ -#define __CONSOLE_HH__ - -#include - -#include "base/circlebuf.hh" -#include "cpu/intr_control.hh" -#include "base/pollevent.hh" -#include "base/socket.hh" -#include "sim/sim_object.hh" - -class ConsoleListener; -class SimConsole : public SimObject -{ - protected: - class Event : public PollEvent - { - protected: - SimConsole *cons; - - public: - Event(SimConsole *c, int fd, int e); - void process(int revent); - }; - - friend class Event; - Event *event; - - protected: - int number; - int in_fd; - int out_fd; - - protected: - ConsoleListener *listener; - - public: - SimConsole(const std::string &name, const std::string &file, int num); - ~SimConsole(); - - protected: - CircleBuf txbuf; - CircleBuf rxbuf; - std::ostream *outfile; -#if TRACING_ON == 1 - CircleBuf linebuf; -#endif - - public: - /////////////////////// - // Terminal Interface - - void attach(int fd, ConsoleListener *l = NULL) { attach(fd, fd, l); } - void attach(int in, int out, ConsoleListener *l = NULL); - void detach(); - - void data(); - - void close(); - void read(uint8_t &c) { read(&c, 1); } - size_t read(uint8_t *buf, size_t len); - 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 - - // Get a character from the console. - bool in(uint8_t &value); - - // get a character from the console in the console specific format - // corresponds to GETC: - // retval<63:61> - // 000: success: character received - // 001: success: character received, more pending - // 100: failure: no character ready - // 110: failure: character received with error - // 111: failure: character received with error, more pending - // retval<31:0> - // character read from console - // - // Interrupts are cleared when the buffer is empty. - 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 setPlatform(Platform *p); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -class ConsoleListener : public SimObject -{ - protected: - class Event : public PollEvent - { - protected: - ConsoleListener *listener; - - public: - Event(ConsoleListener *l, int fd, int e) - : PollEvent(fd, e), listener(l) {} - void process(int revent); - }; - - friend class Event; - Event *event; - - typedef std::list list_t; - typedef list_t::iterator iter_t; - list_t ConsoleList; - - protected: - ListenSocket listener; - - public: - ConsoleListener(const std::string &name); - ~ConsoleListener(); - - void add(SimConsole *cons); - - void accept(); - void listen(int port); -}; - -#endif // __CONSOLE_HH__ 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/simconsole.cc b/dev/simconsole.cc new file mode 100644 index 000000000..a15057402 --- /dev/null +++ b/dev/simconsole.cc @@ -0,0 +1,424 @@ +/* + * 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 the user interface to a serial console + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "base/misc.hh" +#include "base/socket.hh" +#include "base/trace.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; + +//////////////////////////////////////////////////////////////////////// +// +// + +SimConsole::Event::Event(SimConsole *c, int fd, int e) + : PollEvent(fd, e), cons(c) +{ +} + +void +SimConsole::Event::process(int revent) +{ + if (revent & POLLIN) + cons->data(); + else if (revent & POLLNVAL) + cons->detach(); +} + +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) +#if TRACING_ON == 1 + , linebuf(16384) +#endif +{ + if (!file.empty()) + outfile = new ofstream(file.c_str()); + + if (outfile) + outfile->setf(ios::unitbuf); + +} + +SimConsole::~SimConsole() +{ + close(); + + if (outfile) + delete outfile; +} + +void +SimConsole::close() +{ + if (in_fd != -1) + ::close(in_fd); + + if (out_fd != in_fd && out_fd != -1) + ::close(out_fd); +} + +void +SimConsole::attach(int in, int out, ConsoleListener *l) +{ + in_fd = in; + out_fd = out; + listener = l; + + event = new Event(this, in, POLLIN); + pollQueue.schedule(event); + + stringstream stream; + ccprintf(stream, "==== m5 slave console: Console %d ====", number); + + // we need an actual carriage return followed by a newline for the + // terminal + stream << "\r\n"; + + write((const uint8_t *)stream.str().c_str(), stream.str().size()); + + + DPRINTFN("attach console %d\n", number); + + txbuf.readall(out); +} + +void +SimConsole::detach() +{ + close(); + in_fd = -1; + out_fd = -1; + + pollQueue.remove(event); + + if (listener) { + listener->add(this); + listener = NULL; + } + + DPRINTFN("detach console %d\n", number); +} + +void +SimConsole::data() +{ + uint8_t buf[1024]; + int len; + + len = read(buf, sizeof(buf)); + if (len) { + rxbuf.write((char *)buf, len); + // Inform the UART there is data available + uart->dataAvailable(); + } +} + +size_t +SimConsole::read(uint8_t *buf, size_t len) +{ + if (in_fd < 0) + panic("Console not properly attached.\n"); + + size_t ret; + do { + ret = ::read(in_fd, buf, len); + } while (ret == -1 && errno == EINTR); + + + if (ret < 0) + DPRINTFN("Read failed.\n"); + + if (ret <= 0) { + detach(); + return 0; + } + + return ret; +} + +// Console output. +size_t +SimConsole::write(const uint8_t *buf, size_t len) +{ + if (out_fd < 0) + panic("Console not properly attached.\n"); + + size_t ret; + for (;;) { + ret = ::write(out_fd, buf, len); + + if (ret >= 0) + break; + + if (errno != EINTR) + detach(); + } + + return ret; +} + +#define MORE_PENDING (ULL(1) << 61) +#define RECEIVE_SUCCESS (ULL(0) << 62) +#define RECEIVE_NONE (ULL(2) << 62) +#define RECEIVE_ERROR (ULL(3) << 62) + +bool +SimConsole::in(uint8_t &c) +{ + bool empty, ret; + + empty = rxbuf.empty(); + ret = !empty; + if (!empty) { + rxbuf.read((char *)&c, 1); + empty = rxbuf.empty(); + } + + DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d, return: %d\n", + isprint(c) ? c : ' ', c, !empty, ret); + + return ret; +} + +uint64_t +SimConsole::console_in() +{ + uint8_t c; + uint64_t value; + + if (in(c)) { + value = RECEIVE_SUCCESS | c; + if (!rxbuf.empty()) + value |= MORE_PENDING; + } else { + value = RECEIVE_NONE; + } + + DPRINTF(ConsoleVerbose, "console_in: return: %#x\n", value); + + return value; +} + +void +SimConsole::out(char c) +{ +#if TRACING_ON == 1 + if (DTRACE(Console)) { + static char last = '\0'; + + if (c != '\n' && c != '\r' || + last != '\n' && last != '\r') { + if (c == '\n' || c == '\r') { + int size = linebuf.size(); + char *buffer = new char[size + 1]; + linebuf.read(buffer, size); + buffer[size] = '\0'; + DPRINTF(Console, "%s\n", buffer); + delete [] buffer; + } else { + linebuf.write(c); + } + } + + last = c; + } +#endif + + txbuf.write(c); + + if (out_fd >= 0) + write(c); + + if (outfile) + outfile->write(&c, 1); + + DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x\n", + isprint(c) ? c : ' ', (int)c); + +} + + +void +SimConsole::serialize(ostream &os) +{ +} + +void +SimConsole::unserialize(Checkpoint *cp, const std::string §ion) +{ +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole) + + SimObjectParam listener; + SimObjectParam intr_control; + Param output; + Param append_name; + Param number; + +END_DECLARE_SIM_OBJECT_PARAMS(SimConsole) + +BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole) + + INIT_PARAM(listener, "console listener"), + INIT_PARAM(intr_control, "interrupt controller"), + 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) + +END_INIT_SIM_OBJECT_PARAMS(SimConsole) + +CREATE_SIM_OBJECT(SimConsole) +{ + string filename = output; + if (filename.empty()) { + if (!outputDirectory.empty()) + filename = outputDirectory + getInstanceName(); + } else { + if (append_name) + filename += "." + getInstanceName(); + if (!outputDirectory.empty()) + filename = outputDirectory + filename; + } + + SimConsole *console = new SimConsole(getInstanceName(), filename, number); + ((ConsoleListener *)listener)->add(console); + + return console; +} + +REGISTER_SIM_OBJECT("SimConsole", SimConsole) + +//////////////////////////////////////////////////////////////////////// +// +// + +ConsoleListener::ConsoleListener(const string &name) + : SimObject(name), event(NULL) +{} + +ConsoleListener::~ConsoleListener() +{ + if (event) + delete event; +} + +void +ConsoleListener::Event::process(int revent) +{ + listener->accept(); +} + +/////////////////////////////////////////////////////////////////////// +// socket creation and console attach +// + +void +ConsoleListener::listen(int port) +{ + while (!listener.listen(port, true)) { + DPRINTF(Console, + ": can't bind address console port %d inuse PID %d\n", + port, getpid()); + port++; + } + + ccprintf(cerr, "Listening for console connection on port %d\n", port); + + event = new Event(this, listener.getfd(), POLLIN); + pollQueue.schedule(event); +} + +void +ConsoleListener::add(SimConsole *cons) +{ ConsoleList.push_back(cons);} + +void +ConsoleListener::accept() +{ + if (!listener.islistening()) + panic("%s: cannot accept a connection if not listening!", name()); + + int sfd = listener.accept(true); + if (sfd != -1) { + iter_t i = ConsoleList.begin(); + iter_t end = ConsoleList.end(); + if (i == end) { + close(sfd); + } else { + (*i)->attach(sfd, this); + i = ConsoleList.erase(i); + } + } +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) + + Param port; + +END_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) + +BEGIN_INIT_SIM_OBJECT_PARAMS(ConsoleListener) + + INIT_PARAM_DFLT(port, "listen port", 3456) + +END_INIT_SIM_OBJECT_PARAMS(ConsoleListener) + +CREATE_SIM_OBJECT(ConsoleListener) +{ + ConsoleListener *listener = new ConsoleListener(getInstanceName()); + listener->listen(port); + + return listener; +} + +REGISTER_SIM_OBJECT("ConsoleListener", ConsoleListener) diff --git a/dev/simconsole.hh b/dev/simconsole.hh new file mode 100644 index 000000000..138e2e36a --- /dev/null +++ b/dev/simconsole.hh @@ -0,0 +1,165 @@ +/* + * 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 + */ + +#ifndef __CONSOLE_HH__ +#define __CONSOLE_HH__ + +#include + +#include "base/circlebuf.hh" +#include "cpu/intr_control.hh" +#include "base/pollevent.hh" +#include "base/socket.hh" +#include "sim/sim_object.hh" + +class ConsoleListener; +class Uart; + +class SimConsole : public SimObject +{ + public: + Uart *uart; + + protected: + class Event : public PollEvent + { + protected: + SimConsole *cons; + + public: + Event(SimConsole *c, int fd, int e); + void process(int revent); + }; + + friend class Event; + Event *event; + + protected: + int number; + int in_fd; + int out_fd; + ConsoleListener *listener; + + public: + SimConsole(const std::string &name, const std::string &file, int num); + ~SimConsole(); + + protected: + CircleBuf txbuf; + CircleBuf rxbuf; + std::ostream *outfile; +#if TRACING_ON == 1 + CircleBuf linebuf; +#endif + + public: + /////////////////////// + // Terminal Interface + + void attach(int fd, ConsoleListener *l = NULL) { attach(fd, fd, l); } + void attach(int in, int out, ConsoleListener *l = NULL); + void detach(); + + void data(); + + void close(); + void read(uint8_t &c) { read(&c, 1); } + size_t read(uint8_t *buf, size_t len); + void write(uint8_t c) { write(&c, 1); } + size_t write(const uint8_t *buf, size_t len); + + public: + ///////////////// + // OS interface + + // Get a character from the console. + bool in(uint8_t &value); + + // get a character from the console in the console specific format + // corresponds to GETC: + // retval<63:61> + // 000: success: character received + // 001: success: character received, more pending + // 100: failure: no character ready + // 110: failure: character received with error + // 111: failure: character received with error, more pending + // retval<31:0> + // character read from console + // + // Interrupts are cleared when the buffer is empty. + uint64_t console_in(); + + // Send a character to the console + void out(char c); + + //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); +}; + +class ConsoleListener : public SimObject +{ + protected: + class Event : public PollEvent + { + protected: + ConsoleListener *listener; + + public: + Event(ConsoleListener *l, int fd, int e) + : PollEvent(fd, e), listener(l) {} + void process(int revent); + }; + + friend class Event; + Event *event; + + typedef std::list list_t; + typedef list_t::iterator iter_t; + list_t ConsoleList; + + protected: + ListenSocket listener; + + public: + ConsoleListener(const std::string &name); + ~ConsoleListener(); + + void add(SimConsole *cons); + + void accept(); + void listen(int port); +}; + +#endif // __CONSOLE_HH__ 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/tsunami_uart.hh b/dev/tsunami_uart.hh deleted file mode 100644 index 14ee42e8b..000000000 --- a/dev/tsunami_uart.hh +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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 - * Tsunami UART - */ - -#ifndef __TSUNAMI_UART_HH__ -#define __TSUNAMI_UART_HH__ - -#include "dev/tsunamireg.h" -#include "base/range.hh" -#include "dev/io_device.hh" - -class SimConsole; - -/* - * Tsunami UART - */ -class TsunamiUart : public PioDevice -{ - private: - Addr addr; - static const Addr size = 0x8; - - - protected: - SimConsole *cons; - int status_store; - uint8_t next_char; - bool valid_char; - uint8_t IER; - - class IntrEvent : public Event - { - protected: - TsunamiUart *uart; - public: - IntrEvent(TsunamiUart *u); - virtual void process(); - virtual const char *description(); - void scheduleIntr(); - }; - - IntrEvent intrEvent; - - public: - TsunamiUart(const string &name, SimConsole *c, MemoryController *mmu, - Addr a, HierParams *hier, Bus *bus); - - Fault read(MemReqPtr &req, uint8_t *data); - Fault write(MemReqPtr &req, const uint8_t *data); - - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __TSUNAMI_UART_HH__ 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/uart.hh b/dev/uart.hh new file mode 100644 index 000000000..83e1a758c --- /dev/null +++ b/dev/uart.hh @@ -0,0 +1,106 @@ +/* + * 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 + * Defines a 8250 UART + */ + +#ifndef __TSUNAMI_UART_HH__ +#define __TSUNAMI_UART_HH__ + +#include "dev/tsunamireg.h" +#include "base/range.hh" +#include "dev/io_device.hh" + +class SimConsole; +class Platform; + +const int RX_INT = 0x1; +const int TX_INT = 0x2; + + +class Uart : public PioDevice +{ + + private: + Addr addr; + Addr size; + SimConsole *cons; + + + protected: + int readAddr; // tlaser only + uint8_t IER, DLAB, LCR, MCR; + int status; + + class IntrEvent : public Event + { + protected: + Uart *uart; + public: + IntrEvent(Uart *u); + virtual void process(); + virtual const char *description(); + void scheduleIntr(); + }; + + IntrEvent intrEvent; + Platform *platform; + + public: + 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); + + /** + * Return how long this access will take. + * @param req the memory request to calcuate + * @return Tick when the request is done + */ + Tick cacheAccess(MemReqPtr &req); +}; + +#endif // __TSUNAMI_UART_HH__ -- cgit v1.2.3