'Console',
'ConsolePoll',
'ConsoleVerbose',
- 'TlaserUart',
'AlphaConsole',
'Flow',
'Interrupt',
'IdeCtrl',
'IdeDisk',
'Tsunami',
- 'TsunamiUart'
+ 'Uart'
]
#
#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"
break;
case offsetof(AlphaAccess, outputChar):
- console->out((char)(val & 0xff), false);
+ console->out((char)(val & 0xff));
break;
case offsetof(AlphaAccess, bootStrapImpure):
+++ /dev/null
-/* $Id$ */
-
-
-/* @file
- * User Console Definitions
- */
-
-#include <sys/ioctl.h>
-#include <sys/termios.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <poll.h>
-#include <unistd.h>
-
-#include <iostream>
-#include <fstream>
-#include <sstream>
-#include <string>
-
-#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<ConsoleListener *> listener;
- SimObjectParam<IntrControl *> intr_control;
- SimObjectParam<Platform *> platform;
- Param<string> output;
- Param<bool> append_name;
- Param<int> 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<int> 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)
+++ /dev/null
-/* $Id$ */
-
-/* @file
- * User Console Interface
- */
-
-#ifndef __CONSOLE_HH__
-#define __CONSOLE_HH__
-
-#include <iostream>
-
-#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<SimConsole *> 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__
class PciConfigAll;
class IntrControl;
class SimConsole;
+class Uart;
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:
--- /dev/null
+/*
+ * 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 <sys/ioctl.h>
+#include <sys/termios.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+
+#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<ConsoleListener *> listener;
+ SimObjectParam<IntrControl *> intr_control;
+ Param<string> output;
+ Param<bool> append_name;
+ Param<int> 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<int> 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)
--- /dev/null
+/*
+ * 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 <iostream>
+
+#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<SimConsole *> 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__
#include <vector>
#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"
#include <vector>
#include "base/trace.hh"
-#include "dev/console.hh"
#include "dev/tsunami_cchip.hh"
#include "dev/tsunamireg.h"
#include "dev/tsunami.hh"
#include <vector>
#include "base/trace.hh"
-#include "dev/console.hh"
#include "dev/tsunami_io.hh"
#include "dev/tsunami.hh"
#include "mem/bus/bus.hh"
#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;
+++ /dev/null
-/* $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 <string>
-#include <vector>
-
-#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, 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<SimConsole *> console;
- SimObjectParam<MemoryController *> mmu;
- Param<Addr> addr;
- SimObjectParam<Bus*> io_bus;
- SimObjectParam<HierParams *> 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)
+++ /dev/null
-/*
- * 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__
// 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__
--- /dev/null
+/*
+ * 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 <string>
+#include <vector>
+
+#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, 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<SimConsole *> console;
+ SimObjectParam<MemoryController *> mmu;
+ SimObjectParam<Platform *> platform;
+ Param<Addr> addr;
+ Param<Addr> size;
+ SimObjectParam<Bus*> io_bus;
+ SimObjectParam<HierParams *> 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)
--- /dev/null
+/*
+ * 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__