dev: Move generic serial devices to src/dev/serial

Change-Id: I104227fc460f8b561e7375b329a541c1fce881b2
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Curtis Dunham <curtis.dunham@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/4291
Reviewed-by: Gabe Black <gabeblack@google.com>
This commit is contained in:
Andreas Sandberg
2017-07-20 11:58:06 +01:00
parent 74d3f8a176
commit 20de3bb759
24 changed files with 75 additions and 38 deletions

59
src/dev/serial/SConscript Normal file
View File

@@ -0,0 +1,59 @@
# -*- mode:python -*-
# Copyright (c) 2017 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2006 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.
#
# Authors: Andreas Sandberg
Import('*')
if env['TARGET_ISA'] == 'null':
Return()
SimObject('Serial.py')
SimObject('Terminal.py')
SimObject('Uart.py')
Source('serial.cc')
Source('terminal.cc')
Source('uart.cc')
Source('uart8250.cc')
DebugFlag('Terminal')
DebugFlag('TerminalVerbose')
DebugFlag('Uart')

48
src/dev/serial/Serial.py Normal file
View File

@@ -0,0 +1,48 @@
# Copyright (c) 2014, 2017 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# 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.
#
# Authors: Andreas Sandberg
from m5.params import *
from m5.SimObject import SimObject
class SerialDevice(SimObject):
type = 'SerialDevice'
abstract = True
cxx_header = "dev/serial/serial.hh"
class SerialNullDevice(SerialDevice):
type = 'SerialNullDevice'
cxx_header = "dev/serial/serial.hh"

View File

@@ -0,0 +1,40 @@
# Copyright (c) 2005-2007 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.
#
# Authors: Nathan Binkert
from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
from Serial import SerialDevice
class Terminal(SerialDevice):
type = 'Terminal'
cxx_header = "dev/serial/terminal.hh"
intr_control = Param.IntrControl(Parent.any, "interrupt controller")
port = Param.TcpPort(3456, "listen port")
number = Param.Int(0, "terminal number")
output = Param.Bool(True, "Enable output dump to file")

43
src/dev/serial/Uart.py Normal file
View File

@@ -0,0 +1,43 @@
# Copyright (c) 2005-2007 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.
#
# Authors: Nathan Binkert
from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice
from Serial import SerialDevice
class Uart(BasicPioDevice):
type = 'Uart'
abstract = True
cxx_header = "dev/serial/uart.hh"
platform = Param.Platform(Parent.any, "Platform this device is part of.")
device = Param.SerialDevice(Parent.any, "The terminal")
class Uart8250(Uart):
type = 'Uart8250'
cxx_header = "dev/serial/uart8250.hh"

95
src/dev/serial/serial.cc Normal file
View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 2014, 2017 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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.
*
* Authors: Andreas Sandberg
*/
#include "dev/serial/serial.hh"
#include "base/misc.hh"
#include "params/SerialDevice.hh"
#include "params/SerialNullDevice.hh"
SerialDevice::SerialDevice(const SerialDeviceParams *p)
: SimObject(p), interfaceCallback(nullptr)
{
}
SerialDevice::~SerialDevice()
{
}
void
SerialDevice::regInterfaceCallback(Callback *c)
{
// This can happen if the user has connected multiple UARTs to the
// same terminal. In that case, each of them tries to register
// callbacks.
if (interfaceCallback)
fatal("A UART has already been associated with this device.\n");
interfaceCallback = c;
}
void
SerialDevice::notifyInterface()
{
assert(dataAvailable());
// Registering a callback is optional.
if (interfaceCallback)
interfaceCallback->process();
}
SerialNullDevice::SerialNullDevice(const SerialNullDeviceParams *p)
: SerialDevice(p)
{
}
uint8_t
SerialNullDevice::readData()
{
panic("SerialNullDevice does not have pending data.\n");
}
SerialNullDevice *
SerialNullDeviceParams::create()
{
return new SerialNullDevice(this);
}

158
src/dev/serial/serial.hh Normal file
View File

@@ -0,0 +1,158 @@
/*
* Copyright (c) 2014, 2017 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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.
*
* Authors: Andreas Sandberg
*/
#ifndef __DEV_SERIAL_HH__
#define __DEV_SERIAL_HH__
#include "base/callback.hh"
#include "sim/sim_object.hh"
struct SerialDeviceParams;
struct SerialNullDeviceParams;
/**
* Base class for serial devices such as terminals.
*
* This class provides a unified interface that all serial (RS232 or
* similar) devices must implement. A device can be wired to exactly
* one host serial interface (serial port model).
*
* SerialDevices are passive devices that are <i>driven</i> by the
* serial interface using the writeData(c) (the interface sends a
* character) and readData() (the interface reads a character)
* methods. Serial devices need to override these methods to
* communicate with the host interface layer.
*
* To implement basic flow control, serial devices must implement the
* dataAvailable() method. This method returns true if a valid
* character can be read using the readData() method. When data
* becomes available, the serial device must call the
* notifyInterface() method to send a callback to the interface layer.
*
* To send a character (host to device), the interface layer calls
* writeData(char) to send a character to the serial device.
*
* To read a character (device to host), the interface layer calls
* dataAvailable() to determine if there is a character pending. If
* there is data available, it immediately calls readData() to get the
* character. The receive loop in the serial device typically looks
* like this:
*
* \code{.cc}
* while (device.dataAvailable()) {
* printf("%c", (int)device.readData());
* }
* \endcode
*
* To avoid polling, the interface layer may register a data available
* callback using the regInterfaceCallback() method. The device uses
* this callback to notify the interface layer whenever there is new
* data pending. Note that devices will normally only notify the
* interface layer when there is a state transition in the
* device. E.g., the dataAvailable() transitions from false to
* true. This means that there can be multiple pending characters when
* the interface layer receives the callback.
*/
class SerialDevice : public SimObject
{
public:
SerialDevice(const SerialDeviceParams *p);
~SerialDevice();
public: // Serial device API (UART->Device)
/**
* Register a data available callback into the host interface layer.
*
* Serial devices need to call the underlying host interface layer
* to inform it of state change such as pending data that can be
* read from the device by the interface layer using the readData()
* method. The interface layer may use this method to register a
* callback that informs it of pending data.
*
* @param c Callback instance from interface layer.
*/
void regInterfaceCallback(Callback *c);
/**
* Check if there is pending data from the serial device.
*
* @return true if there is data pending that can be read using
* the readData() method.
*/
virtual bool dataAvailable() const = 0;
/**
* Transmit a character from the host interface to the device.
*
* @param c Received data.
*/
virtual void writeData(uint8_t c) = 0;
/**
* Read a character from the device.
*
* @return Character from the device's output buffer, undefined if
* no data is pending.
*/
virtual uint8_t readData() = 0;
protected:
/** Notify the host interface of pending data. */
void notifyInterface();
private:
/** Currently regisxtered host interface layer callback */
Callback *interfaceCallback;
};
/**
* Dummy serial device that discards all data sent to it.
*/
class SerialNullDevice : public SerialDevice
{
public:
SerialNullDevice(const SerialNullDeviceParams *p);
public:
bool dataAvailable() const override { return false; }
void writeData(uint8_t c) override {};
uint8_t readData() override;
};
#endif // __DEV_SERIAL_HH__

345
src/dev/serial/terminal.cc Normal file
View File

@@ -0,0 +1,345 @@
/*
* Copyright (c) 2001-2005 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.
*
* Authors: Nathan Binkert
* Ali Saidi
*/
/* @file
* Implements the user interface to a serial terminal
*/
#include <sys/ioctl.h>
#if defined(__FreeBSD__)
#include <termios.h>
#else
#include <sys/termios.h>
#endif
#include "dev/serial/terminal.hh"
#include <poll.h>
#include <unistd.h>
#include <cctype>
#include <cerrno>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include "base/atomicio.hh"
#include "base/misc.hh"
#include "base/output.hh"
#include "base/socket.hh"
#include "base/trace.hh"
#include "debug/Terminal.hh"
#include "debug/TerminalVerbose.hh"
#include "dev/platform.hh"
#include "dev/serial/uart.hh"
using namespace std;
/*
* Poll event for the listen socket
*/
Terminal::ListenEvent::ListenEvent(Terminal *t, int fd, int e)
: PollEvent(fd, e), term(t)
{
}
void
Terminal::ListenEvent::process(int revent)
{
term->accept();
}
/*
* Poll event for the data socket
*/
Terminal::DataEvent::DataEvent(Terminal *t, int fd, int e)
: PollEvent(fd, e), term(t)
{
}
void
Terminal::DataEvent::process(int revent)
{
// As a consequence of being called from the PollQueue, we might
// have been called from a different thread. Migrate to "our"
// thread.
EventQueue::ScopedMigration migrate(term->eventQueue());
if (revent & POLLIN)
term->data();
else if (revent & POLLNVAL)
term->detach();
}
/*
* Terminal code
*/
Terminal::Terminal(const Params *p)
: SerialDevice(p), listenEvent(NULL), dataEvent(NULL),
number(p->number), data_fd(-1), txbuf(16384), rxbuf(16384),
outfile(p->output ? simout.findOrCreate(p->name) : NULL)
#if TRACING_ON == 1
, linebuf(16384)
#endif
{
if (outfile)
outfile->stream()->setf(ios::unitbuf);
if (p->port)
listen(p->port);
}
Terminal::~Terminal()
{
if (data_fd != -1)
::close(data_fd);
if (listenEvent)
delete listenEvent;
if (dataEvent)
delete dataEvent;
}
///////////////////////////////////////////////////////////////////////
// socket creation and terminal attach
//
void
Terminal::listen(int port)
{
if (ListenSocket::allDisabled()) {
warn_once("Sockets disabled, not accepting terminal connections");
return;
}
while (!listener.listen(port, true)) {
DPRINTF(Terminal,
": can't bind address terminal port %d inuse PID %d\n",
port, getpid());
port++;
}
int p1, p2;
p2 = name().rfind('.') - 1;
p1 = name().rfind('.', p2);
ccprintf(cerr, "Listening for %s connection on port %d\n",
name().substr(p1+1,p2-p1), port);
listenEvent = new ListenEvent(this, listener.getfd(), POLLIN);
pollQueue.schedule(listenEvent);
}
void
Terminal::accept()
{
if (!listener.islistening())
panic("%s: cannot accept a connection if not listening!", name());
int fd = listener.accept(true);
if (data_fd != -1) {
char message[] = "terminal already attached!\n";
atomic_write(fd, message, sizeof(message));
::close(fd);
return;
}
data_fd = fd;
dataEvent = new DataEvent(this, data_fd, POLLIN);
pollQueue.schedule(dataEvent);
stringstream stream;
ccprintf(stream, "==== m5 slave terminal: Terminal %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 terminal %d\n", number);
char buf[1024];
for (size_t i = 0; i < txbuf.size(); i += sizeof(buf)) {
const size_t chunk_len(std::min(txbuf.size() - i, sizeof(buf)));
txbuf.peek(buf, i, chunk_len);
write((const uint8_t *)buf, chunk_len);
}
}
void
Terminal::detach()
{
if (data_fd != -1) {
::close(data_fd);
data_fd = -1;
}
pollQueue.remove(dataEvent);
delete dataEvent;
dataEvent = NULL;
DPRINTFN("detach terminal %d\n", number);
}
void
Terminal::data()
{
uint8_t buf[1024];
int len;
len = read(buf, sizeof(buf));
if (len) {
rxbuf.write((char *)buf, len);
notifyInterface();
}
}
size_t
Terminal::read(uint8_t *buf, size_t len)
{
if (data_fd < 0)
panic("Terminal not properly attached.\n");
ssize_t ret;
do {
ret = ::read(data_fd, buf, len);
} while (ret == -1 && errno == EINTR);
if (ret < 0)
DPRINTFN("Read failed.\n");
if (ret <= 0) {
detach();
return 0;
}
return ret;
}
// Terminal output.
size_t
Terminal::write(const uint8_t *buf, size_t len)
{
if (data_fd < 0)
panic("Terminal not properly attached.\n");
ssize_t ret = atomic_write(data_fd, buf, len);
if (ret < len)
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)
uint8_t
Terminal::readData()
{
uint8_t c;
assert(!rxbuf.empty());
rxbuf.read((char *)&c, 1);
DPRINTF(TerminalVerbose, "in: \'%c\' %#02x more: %d\n",
isprint(c) ? c : ' ', c, !rxbuf.empty());
return c;
}
uint64_t
Terminal::console_in()
{
uint64_t value;
if (dataAvailable()) {
value = RECEIVE_SUCCESS | readData();
if (!rxbuf.empty())
value |= MORE_PENDING;
} else {
value = RECEIVE_NONE;
}
DPRINTF(TerminalVerbose, "console_in: return: %#x\n", value);
return value;
}
void
Terminal::writeData(uint8_t c)
{
#if TRACING_ON == 1
if (DTRACE(Terminal)) {
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(Terminal, "%s\n", buffer);
delete [] buffer;
} else {
linebuf.write(&c, 1);
}
}
last = c;
}
#endif
txbuf.write(&c, 1);
if (data_fd >= 0)
write(c);
if (outfile)
outfile->stream()->put((char)c);
DPRINTF(TerminalVerbose, "out: \'%c\' %#02x\n",
isprint(c) ? c : ' ', (int)c);
}
Terminal *
TerminalParams::create()
{
return new Terminal(this);
}

141
src/dev/serial/terminal.hh Normal file
View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2001-2005 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.
*
* Authors: Nathan Binkert
* Ali Saidi
*/
/* @file
* User Terminal Interface
*/
#ifndef __DEV_TERMINAL_HH__
#define __DEV_TERMINAL_HH__
#include <iostream>
#include "base/callback.hh"
#include "base/circlebuf.hh"
#include "base/pollevent.hh"
#include "base/socket.hh"
#include "cpu/intr_control.hh"
#include "dev/serial/serial.hh"
#include "params/Terminal.hh"
#include "sim/sim_object.hh"
class OutputStream;
class TerminalListener;
class Terminal : public SerialDevice
{
protected:
class ListenEvent : public PollEvent
{
protected:
Terminal *term;
public:
ListenEvent(Terminal *t, int fd, int e);
void process(int revent);
};
friend class ListenEvent;
ListenEvent *listenEvent;
class DataEvent : public PollEvent
{
protected:
Terminal *term;
public:
DataEvent(Terminal *t, int fd, int e);
void process(int revent);
};
friend class DataEvent;
DataEvent *dataEvent;
protected:
int number;
int data_fd;
public:
typedef TerminalParams Params;
Terminal(const Params *p);
~Terminal();
protected:
ListenSocket listener;
void listen(int port);
void accept();
protected:
CircleBuf<char> txbuf;
CircleBuf<char> rxbuf;
OutputStream *outfile;
#if TRACING_ON == 1
CircleBuf<char> linebuf;
#endif
public:
///////////////////////
// Terminal Interface
void data();
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 detach();
public: // SerialDevice interface
uint8_t readData() override;
void writeData(uint8_t c) override;
bool dataAvailable() const override { return !rxbuf.empty(); }
public:
/////////////////
// OS interface
// get a character from the terminal 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();
};
#endif // __DEV_TERMINAL_HH__

46
src/dev/serial/uart.cc Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2004-2005 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.
*
* Authors: Ali Saidi
*/
/** @file
* Implements a base class for UARTs
*/
#include "dev/serial/uart.hh"
Uart::Uart(const Params *p, Addr pio_size)
: BasicPioDevice(p, pio_size),
platform(p->platform), device(p->device),
callbackDataAvail(this)
{
status = 0;
// setup serial device callbacks
device->regInterfaceCallback(&callbackDataAvail);
}

80
src/dev/serial/uart.hh Normal file
View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2004-2005 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.
*
* Authors: Ali Saidi
*/
/** @file
* Base class for UART
*/
#ifndef __UART_HH__
#define __UART_HH__
#include "base/callback.hh"
#include "dev/io_device.hh"
#include "dev/serial/serial.hh"
#include "params/Uart.hh"
class Platform;
const int RX_INT = 0x1;
const int TX_INT = 0x2;
class Uart : public BasicPioDevice
{
protected:
int status;
Platform *platform;
SerialDevice *device;
public:
typedef UartParams Params;
Uart(const Params *p, Addr pio_size);
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
/**
* Inform the uart that there is data available.
*/
virtual void dataAvailable() = 0;
/**
* Return if we have an interrupt pending
* @return interrupt status
*/
bool intStatus() { return status ? true : false; }
protected:
MakeCallback<Uart, &Uart::dataAvailable> callbackDataAvail;
};
#endif // __UART_HH__

326
src/dev/serial/uart8250.cc Normal file
View File

@@ -0,0 +1,326 @@
/*
* Copyright (c) 2005 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.
*
* Authors: Ali Saidi
*/
/** @file
* Implements a 8250 UART
*/
#include "dev/serial/uart8250.hh"
#include <string>
#include <vector>
#include "base/inifile.hh"
#include "base/trace.hh"
#include "config/the_isa.hh"
#include "debug/Uart.hh"
#include "dev/platform.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
using namespace std;
using namespace TheISA;
void
Uart8250::processIntrEvent(int intrBit)
{
if (intrBit & IER) {
DPRINTF(Uart, "UART InterEvent, interrupting\n");
platform->postConsoleInt();
status |= intrBit;
lastTxInt = curTick();
}
else
DPRINTF(Uart, "UART InterEvent, not interrupting\n");
}
/* The linux serial driver (8250.c about line 1182) loops reading from
* the device until the device reports it has no more data to
* read. After a maximum of 255 iterations the code prints "serial8250
* too much work for irq X," and breaks out of the loop. Since the
* simulated system is so much slower than the actual system, if a
* user is typing on the keyboard it is very easy for them to provide
* input at a fast enough rate to not allow the loop to exit and thus
* the error to be printed. This magic number provides a delay between
* the time the UART receives a character to send to the simulated
* system and the time it actually notifies the system it has a
* character to send to alleviate this problem. --Ali
*/
void
Uart8250::scheduleIntr(Event *event)
{
static const Tick interval = 225 * SimClock::Int::ns;
DPRINTF(Uart, "Scheduling IER interrupt for %s, at cycle %lld\n",
event->name(), curTick() + interval);
if (!event->scheduled())
schedule(event, curTick() + interval);
else
reschedule(event, curTick() + interval);
}
Uart8250::Uart8250(const Params *p)
: Uart(p, 8), IER(0), DLAB(0), LCR(0), MCR(0), lastTxInt(0),
txIntrEvent([this]{ processIntrEvent(TX_INT); }, "TX"),
rxIntrEvent([this]{ processIntrEvent(RX_INT); }, "RX")
{
}
Tick
Uart8250::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 1);
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(Uart, " read register %#x\n", daddr);
switch (daddr) {
case 0x0:
if (!(LCR & 0x80)) { // read byte
if (device->dataAvailable())
pkt->set(device->readData());
else {
pkt->set((uint8_t)0);
// A limited amount of these are ok.
DPRINTF(Uart, "empty read of RX register\n");
}
status &= ~RX_INT;
platform->clearConsoleInt();
if (device->dataAvailable() && (IER & UART_IER_RDI))
scheduleIntr(&rxIntrEvent);
} else { // dll divisor latch
;
}
break;
case 0x1:
if (!(LCR & 0x80)) { // Intr Enable Register(IER)
pkt->set(IER);
} else { // DLM divisor latch MSB
;
}
break;
case 0x2: // Intr Identification Register (IIR)
DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
if (status & RX_INT) /* Rx data interrupt has a higher priority */
pkt->set(IIR_RXID);
else if (status & TX_INT) {
pkt->set(IIR_TXID);
//Tx interrupts are cleared on IIR reads
status &= ~TX_INT;
} else
pkt->set(IIR_NOPEND);
break;
case 0x3: // Line Control Register (LCR)
pkt->set(LCR);
break;
case 0x4: // Modem Control Register (MCR)
pkt->set(MCR);
break;
case 0x5: // Line Status Register (LSR)
uint8_t lsr;
lsr = 0;
// check if there are any bytes to be read
if (device->dataAvailable())
lsr = UART_LSR_DR;
lsr |= UART_LSR_TEMT | UART_LSR_THRE;
pkt->set(lsr);
break;
case 0x6: // Modem Status Register (MSR)
pkt->set((uint8_t)0);
break;
case 0x7: // Scratch Register (SCR)
pkt->set((uint8_t)0); // doesn't exist with at 8250.
break;
default:
panic("Tried to access a UART port that doesn't exist\n");
break;
}
/* uint32_t d32 = *data;
DPRINTF(Uart, "Register read to register %#x returned %#x\n", daddr, d32);
*/
pkt->makeAtomicResponse();
return pioDelay;
}
Tick
Uart8250::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 1);
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(Uart, " write register %#x value %#x\n", daddr, pkt->get<uint8_t>());
switch (daddr) {
case 0x0:
if (!(LCR & 0x80)) { // write byte
device->writeData(pkt->get<uint8_t>());
platform->clearConsoleInt();
status &= ~TX_INT;
if (UART_IER_THRI & IER)
scheduleIntr(&txIntrEvent);
} else { // dll divisor latch
;
}
break;
case 0x1:
if (!(LCR & 0x80)) { // Intr Enable Register(IER)
IER = pkt->get<uint8_t>();
if (UART_IER_THRI & IER)
{
DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n");
if (curTick() - lastTxInt > 225 * SimClock::Int::ns) {
DPRINTF(Uart, "-- Interrupting Immediately... %d,%d\n",
curTick(), lastTxInt);
txIntrEvent.process();
} else {
DPRINTF(Uart, "-- Delaying interrupt... %d,%d\n",
curTick(), lastTxInt);
scheduleIntr(&txIntrEvent);
}
}
else
{
DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
if (txIntrEvent.scheduled())
deschedule(txIntrEvent);
if (status & TX_INT)
platform->clearConsoleInt();
status &= ~TX_INT;
}
if ((UART_IER_RDI & IER) && device->dataAvailable()) {
DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n");
scheduleIntr(&rxIntrEvent);
} else {
DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n");
if (rxIntrEvent.scheduled())
deschedule(rxIntrEvent);
if (status & RX_INT)
platform->clearConsoleInt();
status &= ~RX_INT;
}
} else { // DLM divisor latch MSB
;
}
break;
case 0x2: // FIFO Control Register (FCR)
break;
case 0x3: // Line Control Register (LCR)
LCR = pkt->get<uint8_t>();
break;
case 0x4: // Modem Control Register (MCR)
if (pkt->get<uint8_t>() == (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;
}
pkt->makeAtomicResponse();
return pioDelay;
}
void
Uart8250::dataAvailable()
{
// if the kernel wants an interrupt when we have data
if (IER & UART_IER_RDI)
{
platform->postConsoleInt();
status |= RX_INT;
}
}
AddrRangeList
Uart8250::getAddrRanges() const
{
AddrRangeList ranges;
ranges.push_back(RangeSize(pioAddr, pioSize));
return ranges;
}
void
Uart8250::serialize(CheckpointOut &cp) const
{
SERIALIZE_SCALAR(status);
SERIALIZE_SCALAR(IER);
SERIALIZE_SCALAR(DLAB);
SERIALIZE_SCALAR(LCR);
SERIALIZE_SCALAR(MCR);
Tick rxintrwhen;
if (rxIntrEvent.scheduled())
rxintrwhen = rxIntrEvent.when();
else
rxintrwhen = 0;
Tick txintrwhen;
if (txIntrEvent.scheduled())
txintrwhen = txIntrEvent.when();
else
txintrwhen = 0;
SERIALIZE_SCALAR(rxintrwhen);
SERIALIZE_SCALAR(txintrwhen);
}
void
Uart8250::unserialize(CheckpointIn &cp)
{
UNSERIALIZE_SCALAR(status);
UNSERIALIZE_SCALAR(IER);
UNSERIALIZE_SCALAR(DLAB);
UNSERIALIZE_SCALAR(LCR);
UNSERIALIZE_SCALAR(MCR);
Tick rxintrwhen;
Tick txintrwhen;
UNSERIALIZE_SCALAR(rxintrwhen);
UNSERIALIZE_SCALAR(txintrwhen);
if (rxintrwhen != 0)
schedule(rxIntrEvent, rxintrwhen);
if (txintrwhen != 0)
schedule(txIntrEvent, txintrwhen);
}
Uart8250 *
Uart8250Params::create()
{
return new Uart8250(this);
}

111
src/dev/serial/uart8250.hh Normal file
View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 2005 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.
*
* Authors: Ali Saidi
*/
/** @file
* Defines a 8250 UART
*/
#ifndef __DEV_UART8250_HH__
#define __DEV_UART8250_HH__
#include "dev/io_device.hh"
#include "dev/serial/uart.hh"
#include "params/Uart8250.hh"
/* UART8250 Interrupt ID Register
* bit 0 Interrupt Pending 0 = true, 1 = false
* bit 2:1 ID of highest priority interrupt
* bit 7:3 zeroes
*/
const uint8_t IIR_NOPEND = 0x1;
// Interrupt IDs
const uint8_t IIR_MODEM = 0x00; /* Modem Status (lowest priority) */
const uint8_t IIR_TXID = 0x02; /* Tx Data */
const uint8_t IIR_RXID = 0x04; /* Rx Data */
const uint8_t IIR_LINE = 0x06; /* Rx Line Status (highest priority)*/
const uint8_t UART_IER_RDI = 0x01;
const uint8_t UART_IER_THRI = 0x02;
const uint8_t UART_IER_RLSI = 0x04;
const uint8_t UART_LSR_TEMT = 0x40;
const uint8_t UART_LSR_THRE = 0x20;
const uint8_t UART_LSR_DR = 0x01;
const uint8_t UART_MCR_LOOP = 0x10;
class Terminal;
class Platform;
class Uart8250 : public Uart
{
protected:
uint8_t IER, DLAB, LCR, MCR;
Tick lastTxInt;
void processIntrEvent(int intrBit);
void scheduleIntr(Event *event);
EventFunctionWrapper txIntrEvent;
EventFunctionWrapper rxIntrEvent;
public:
typedef Uart8250Params Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
Uart8250(const Params *p);
Tick read(PacketPtr pkt) override;
Tick write(PacketPtr pkt) override;
AddrRangeList getAddrRanges() const override;
/**
* Inform the uart that there is data available.
*/
void dataAvailable() override;
/**
* Return if we have an interrupt pending
* @return interrupt status
*/
virtual bool intStatus() { return status ? true : false; }
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
};
#endif // __TSUNAMI_UART_HH__