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:
59
src/dev/serial/SConscript
Normal file
59
src/dev/serial/SConscript
Normal 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
48
src/dev/serial/Serial.py
Normal 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"
|
||||
40
src/dev/serial/Terminal.py
Normal file
40
src/dev/serial/Terminal.py
Normal 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
43
src/dev/serial/Uart.py
Normal 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
95
src/dev/serial/serial.cc
Normal 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
158
src/dev/serial/serial.hh
Normal 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
345
src/dev/serial/terminal.cc
Normal 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
141
src/dev/serial/terminal.hh
Normal 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
46
src/dev/serial/uart.cc
Normal 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
80
src/dev/serial/uart.hh
Normal 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
326
src/dev/serial/uart8250.cc
Normal 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
111
src/dev/serial/uart8250.hh
Normal 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__
|
||||
Reference in New Issue
Block a user