dev: Refactor UART->Terminal interface
The UART models currently assume that they are always wired to a terminal. While true at the moment, this isn't necessarily a valid assumption. This change introduces the SerialDevice class that defines the interface for serial devices. Currently, Terminal is the only class that implements this interface. Change-Id: I74fefafbbaf5ac1ec0d4ec0b5a0f4b246fdad305 Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-by: Curtis Dunham <curtis.dunham@arm.com> Reviewed-on: https://gem5-review.googlesource.com/4289 Reviewed-by: Gabe Black <gabeblack@google.com>
This commit is contained in:
@@ -44,6 +44,7 @@ if env['TARGET_ISA'] == 'null':
|
||||
|
||||
SimObject('BadDevice.py')
|
||||
SimObject('Platform.py')
|
||||
SimObject('Serial.py')
|
||||
SimObject('Terminal.py')
|
||||
SimObject('Uart.py')
|
||||
|
||||
@@ -53,6 +54,7 @@ Source('mc146818.cc')
|
||||
Source('pixelpump.cc')
|
||||
Source('platform.cc')
|
||||
Source('ps2.cc')
|
||||
Source('serial.cc')
|
||||
Source('terminal.cc')
|
||||
Source('uart.cc')
|
||||
Source('uart8250.cc')
|
||||
|
||||
44
src/dev/Serial.py
Normal file
44
src/dev/Serial.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# 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.hh"
|
||||
@@ -29,8 +29,9 @@
|
||||
from m5.SimObject import SimObject
|
||||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
from Serial import SerialDevice
|
||||
|
||||
class Terminal(SimObject):
|
||||
class Terminal(SerialDevice):
|
||||
type = 'Terminal'
|
||||
cxx_header = "dev/terminal.hh"
|
||||
intr_control = Param.IntrControl(Parent.any, "interrupt controller")
|
||||
|
||||
@@ -29,13 +29,14 @@
|
||||
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/uart.hh"
|
||||
platform = Param.Platform(Parent.any, "Platform this device is part of.")
|
||||
terminal = Param.Terminal(Parent.any, "The terminal")
|
||||
device = Param.SerialDevice(Parent.any, "The terminal")
|
||||
|
||||
class Uart8250(Uart):
|
||||
type = 'Uart8250'
|
||||
|
||||
@@ -233,7 +233,7 @@ AlphaBackdoor::write(PacketPtr pkt)
|
||||
break;
|
||||
|
||||
case offsetof(AlphaAccess, outputChar):
|
||||
terminal->out((char)(val & 0xff));
|
||||
terminal->writeData((char)(val & 0xff));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
#include "debug/Uart.hh"
|
||||
#include "dev/arm/amba_device.hh"
|
||||
#include "dev/arm/base_gic.hh"
|
||||
#include "dev/terminal.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
#include "params/Pl011.hh"
|
||||
@@ -81,12 +80,12 @@ Pl011::read(PacketPtr pkt)
|
||||
switch(daddr) {
|
||||
case UART_DR:
|
||||
data = 0;
|
||||
if (term->dataAvailable()) {
|
||||
data = term->in();
|
||||
if (device->dataAvailable()) {
|
||||
data = device->readData();
|
||||
// Since we don't simulate a FIFO for incoming data, we
|
||||
// assume it's empty and clear RXINTR and RTINTR.
|
||||
clearInterrupts(UART_RXINTR | UART_RTINTR);
|
||||
if (term->dataAvailable()) {
|
||||
if (device->dataAvailable()) {
|
||||
DPRINTF(Uart, "Re-raising interrupt due to more data "
|
||||
"after UART_DR read\n");
|
||||
dataAvailable();
|
||||
@@ -97,7 +96,7 @@ Pl011::read(PacketPtr pkt)
|
||||
data =
|
||||
UART_FR_CTS | // Clear To Send
|
||||
// Given we do not simulate a FIFO we are either empty or full.
|
||||
(!term->dataAvailable() ? UART_FR_RXFE : UART_FR_RXFF) |
|
||||
(!device->dataAvailable() ? UART_FR_RXFE : UART_FR_RXFF) |
|
||||
UART_FR_TXFE; // TX FIFO empty
|
||||
|
||||
DPRINTF(Uart,
|
||||
@@ -199,7 +198,7 @@ Pl011::write(PacketPtr pkt)
|
||||
if ((data & 0xFF) == 0x04 && endOnEOT)
|
||||
exitSimLoop("UART received EOT", 0);
|
||||
|
||||
term->out(data & 0xFF);
|
||||
device->writeData(data & 0xFF);
|
||||
// We're supposed to clear TXINTR when this register is
|
||||
// written to, however. since we're also infinitely fast, we
|
||||
// need to immediately raise it again.
|
||||
@@ -229,7 +228,7 @@ Pl011::write(PacketPtr pkt)
|
||||
case UART_ICR:
|
||||
DPRINTF(Uart, "Clearing interrupts 0x%x\n", data);
|
||||
clearInterrupts(data);
|
||||
if (term->dataAvailable()) {
|
||||
if (device->dataAvailable()) {
|
||||
DPRINTF(Uart, "Re-raising interrupt due to more data after "
|
||||
"UART_ICR write\n");
|
||||
dataAvailable();
|
||||
|
||||
73
src/dev/serial.cc
Normal file
73
src/dev/serial.cc
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.hh"
|
||||
|
||||
#include "base/misc.hh"
|
||||
#include "params/SerialDevice.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();
|
||||
}
|
||||
|
||||
143
src/dev/serial.hh
Normal file
143
src/dev/serial.hh
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
#endif // __DEV_SERIAL_HH__
|
||||
@@ -107,7 +107,7 @@ Terminal::DataEvent::process(int revent)
|
||||
* Terminal code
|
||||
*/
|
||||
Terminal::Terminal(const Params *p)
|
||||
: SimObject(p), termDataAvail(NULL), listenEvent(NULL), dataEvent(NULL),
|
||||
: 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
|
||||
@@ -133,16 +133,6 @@ Terminal::~Terminal()
|
||||
delete dataEvent;
|
||||
}
|
||||
|
||||
void
|
||||
Terminal::regDataAvailCallback(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 (termDataAvail)
|
||||
fatal("Terminal already has already been associated with a UART.\n");
|
||||
termDataAvail = c;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// socket creation and terminal attach
|
||||
@@ -233,9 +223,7 @@ Terminal::data()
|
||||
len = read(buf, sizeof(buf));
|
||||
if (len) {
|
||||
rxbuf.write((char *)buf, len);
|
||||
// Inform the UART there is data available
|
||||
assert(termDataAvail);
|
||||
termDataAvail->process();
|
||||
notifyInterface();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +270,7 @@ Terminal::write(const uint8_t *buf, size_t len)
|
||||
#define RECEIVE_ERROR (ULL(3) << 62)
|
||||
|
||||
uint8_t
|
||||
Terminal::in()
|
||||
Terminal::readData()
|
||||
{
|
||||
uint8_t c;
|
||||
|
||||
@@ -301,7 +289,7 @@ Terminal::console_in()
|
||||
uint64_t value;
|
||||
|
||||
if (dataAvailable()) {
|
||||
value = RECEIVE_SUCCESS | in();
|
||||
value = RECEIVE_SUCCESS | readData();
|
||||
if (!rxbuf.empty())
|
||||
value |= MORE_PENDING;
|
||||
} else {
|
||||
@@ -314,7 +302,7 @@ Terminal::console_in()
|
||||
}
|
||||
|
||||
void
|
||||
Terminal::out(char c)
|
||||
Terminal::writeData(uint8_t c)
|
||||
{
|
||||
#if TRACING_ON == 1
|
||||
if (DTRACE(Terminal)) {
|
||||
@@ -343,7 +331,7 @@ Terminal::out(char c)
|
||||
write(c);
|
||||
|
||||
if (outfile)
|
||||
outfile->stream()->write(&c, 1);
|
||||
outfile->stream()->put((char)c);
|
||||
|
||||
DPRINTF(TerminalVerbose, "out: \'%c\' %#02x\n",
|
||||
isprint(c) ? c : ' ', (int)c);
|
||||
|
||||
@@ -43,30 +43,15 @@
|
||||
#include "base/pollevent.hh"
|
||||
#include "base/socket.hh"
|
||||
#include "cpu/intr_control.hh"
|
||||
#include "dev/serial.hh"
|
||||
#include "params/Terminal.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class OutputStream;
|
||||
class TerminalListener;
|
||||
|
||||
class Terminal : public SimObject
|
||||
class Terminal : public SerialDevice
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Register a data available callback into the transport layer.
|
||||
*
|
||||
* The terminal needs to call the underlying transport layer to
|
||||
* inform it of available data. The transport layer uses this
|
||||
* method to register a callback that informs it of pending data.
|
||||
*
|
||||
* @param c Callback instance from transport layer.
|
||||
*/
|
||||
void regDataAvailCallback(Callback *c);
|
||||
|
||||
protected:
|
||||
/** Currently registered transport layer callbacks */
|
||||
Callback *termDataAvail;
|
||||
|
||||
protected:
|
||||
class ListenEvent : public PollEvent
|
||||
{
|
||||
@@ -129,13 +114,15 @@ class Terminal : public SimObject
|
||||
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.
|
||||
uint8_t in();
|
||||
|
||||
// get a character from the terminal in the console specific format
|
||||
// corresponds to GETC:
|
||||
// retval<63:61>
|
||||
@@ -149,12 +136,6 @@ class Terminal : public SimObject
|
||||
//
|
||||
// Interrupts are cleared when the buffer is empty.
|
||||
uint64_t console_in();
|
||||
|
||||
// Send a character to the terminal
|
||||
void out(char c);
|
||||
|
||||
// Ask the terminal if data is available
|
||||
bool dataAvailable() { return !rxbuf.empty(); }
|
||||
};
|
||||
|
||||
#endif // __DEV_TERMINAL_HH__
|
||||
|
||||
@@ -34,18 +34,17 @@
|
||||
|
||||
#include "dev/uart.hh"
|
||||
|
||||
#include "dev/platform.hh"
|
||||
#include "dev/terminal.hh"
|
||||
#include "dev/serial.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
Uart::Uart(const Params *p, Addr pio_size)
|
||||
: BasicPioDevice(p, pio_size),
|
||||
platform(p->platform), term(p->terminal),
|
||||
platform(p->platform), device(p->device),
|
||||
callbackDataAvail(this)
|
||||
{
|
||||
status = 0;
|
||||
|
||||
// setup terminal callbacks
|
||||
term->regDataAvailCallback(&callbackDataAvail);
|
||||
// setup serial device callbacks
|
||||
device->regInterfaceCallback(&callbackDataAvail);
|
||||
}
|
||||
|
||||
@@ -35,8 +35,9 @@
|
||||
#ifndef __UART_HH__
|
||||
#define __UART_HH__
|
||||
|
||||
#include "base/callback.hh"
|
||||
#include "dev/io_device.hh"
|
||||
#include "dev/terminal.hh"
|
||||
#include "dev/serial.hh"
|
||||
#include "params/Uart.hh"
|
||||
|
||||
class Platform;
|
||||
@@ -49,7 +50,7 @@ class Uart : public BasicPioDevice
|
||||
protected:
|
||||
int status;
|
||||
Platform *platform;
|
||||
Terminal *term;
|
||||
SerialDevice *device;
|
||||
|
||||
public:
|
||||
typedef UartParams Params;
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include "config/the_isa.hh"
|
||||
#include "debug/Uart.hh"
|
||||
#include "dev/platform.hh"
|
||||
#include "dev/terminal.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
|
||||
@@ -108,8 +107,8 @@ Uart8250::read(PacketPtr pkt)
|
||||
switch (daddr) {
|
||||
case 0x0:
|
||||
if (!(LCR & 0x80)) { // read byte
|
||||
if (term->dataAvailable())
|
||||
pkt->set(term->in());
|
||||
if (device->dataAvailable())
|
||||
pkt->set(device->readData());
|
||||
else {
|
||||
pkt->set((uint8_t)0);
|
||||
// A limited amount of these are ok.
|
||||
@@ -118,7 +117,7 @@ Uart8250::read(PacketPtr pkt)
|
||||
status &= ~RX_INT;
|
||||
platform->clearConsoleInt();
|
||||
|
||||
if (term->dataAvailable() && (IER & UART_IER_RDI))
|
||||
if (device->dataAvailable() && (IER & UART_IER_RDI))
|
||||
scheduleIntr(&rxIntrEvent);
|
||||
} else { // dll divisor latch
|
||||
;
|
||||
@@ -154,7 +153,7 @@ Uart8250::read(PacketPtr pkt)
|
||||
uint8_t lsr;
|
||||
lsr = 0;
|
||||
// check if there are any bytes to be read
|
||||
if (term->dataAvailable())
|
||||
if (device->dataAvailable())
|
||||
lsr = UART_LSR_DR;
|
||||
lsr |= UART_LSR_TEMT | UART_LSR_THRE;
|
||||
pkt->set(lsr);
|
||||
@@ -190,7 +189,7 @@ Uart8250::write(PacketPtr pkt)
|
||||
switch (daddr) {
|
||||
case 0x0:
|
||||
if (!(LCR & 0x80)) { // write byte
|
||||
term->out(pkt->get<uint8_t>());
|
||||
device->writeData(pkt->get<uint8_t>());
|
||||
platform->clearConsoleInt();
|
||||
status &= ~TX_INT;
|
||||
if (UART_IER_THRI & IER)
|
||||
@@ -225,7 +224,7 @@ Uart8250::write(PacketPtr pkt)
|
||||
status &= ~TX_INT;
|
||||
}
|
||||
|
||||
if ((UART_IER_RDI & IER) && term->dataAvailable()) {
|
||||
if ((UART_IER_RDI & IER) && device->dataAvailable()) {
|
||||
DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n");
|
||||
scheduleIntr(&rxIntrEvent);
|
||||
} else {
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
from VirtIO import VirtIODeviceBase
|
||||
from Serial import SerialDevice
|
||||
|
||||
class VirtIOConsole(VirtIODeviceBase):
|
||||
type = 'VirtIOConsole'
|
||||
@@ -48,4 +49,4 @@ class VirtIOConsole(VirtIODeviceBase):
|
||||
qRecvSize = Param.Unsigned(16, "Receive queue size (descriptors)")
|
||||
qTransSize = Param.Unsigned(16, "Transmit queue size (descriptors)")
|
||||
|
||||
terminal = Param.Terminal(Parent.any, "The terminal")
|
||||
device = Param.SerialDevice("Serial device attached to this device")
|
||||
|
||||
@@ -47,7 +47,7 @@ VirtIOConsole::VirtIOConsole(Params *params)
|
||||
: VirtIODeviceBase(params, ID_CONSOLE, sizeof(Config), F_SIZE),
|
||||
qRecv(params->system->physProxy, params->qRecvSize, *this),
|
||||
qTrans(params->system->physProxy, params->qTransSize, *this),
|
||||
term(*params->terminal), callbackDataAvail(qRecv)
|
||||
device(*params->device), callbackDataAvail(qRecv)
|
||||
{
|
||||
registerQueue(qRecv);
|
||||
registerQueue(qTrans);
|
||||
@@ -55,7 +55,7 @@ VirtIOConsole::VirtIOConsole(Params *params)
|
||||
config.cols = 80;
|
||||
config.rows = 24;
|
||||
|
||||
term.regDataAvailCallback(&callbackDataAvail);
|
||||
device.regInterfaceCallback(&callbackDataAvail);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,11 +81,11 @@ VirtIOConsole::TermRecvQueue::trySend()
|
||||
// get free descriptors (i.e., there are buffers available to
|
||||
// send) from the guest.
|
||||
VirtDescriptor *d;
|
||||
while (parent.term.dataAvailable() && (d = consumeDescriptor())) {
|
||||
while (parent.device.dataAvailable() && (d = consumeDescriptor())) {
|
||||
DPRINTF(VIOConsole, "Got descriptor (len: %i)\n", d->size());
|
||||
size_t len(0);
|
||||
while (parent.term.dataAvailable() && len < d->size()) {
|
||||
uint8_t in(parent.term.in());
|
||||
while (parent.device.dataAvailable() && len < d->size()) {
|
||||
uint8_t in(parent.device.readData());
|
||||
d->chainWrite(len, &in, sizeof(uint8_t));
|
||||
++len;
|
||||
}
|
||||
@@ -108,7 +108,7 @@ VirtIOConsole::TermTransQueue::onNotifyDescriptor(VirtDescriptor *desc)
|
||||
uint8_t data[size];
|
||||
desc->chainRead(0, data, size);
|
||||
for (int i = 0; i < desc->size(); ++i)
|
||||
parent.term.out(data[i]);
|
||||
parent.device.writeData(data[i]);
|
||||
|
||||
// Tell the guest that we are done with this descriptor.
|
||||
produceDescriptor(desc, 0);
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
#ifndef __DEV_VIRTIO_CONSOLE_HH__
|
||||
#define __DEV_VIRTIO_CONSOLE_HH__
|
||||
|
||||
#include "dev/serial.hh"
|
||||
#include "dev/virtio/base.hh"
|
||||
#include "dev/terminal.hh"
|
||||
|
||||
struct VirtIOConsoleParams;
|
||||
|
||||
@@ -147,7 +147,7 @@ class VirtIOConsole : public VirtIODeviceBase
|
||||
TermTransQueue qTrans;
|
||||
|
||||
protected:
|
||||
Terminal &term;
|
||||
SerialDevice &device;
|
||||
MakeCallback<VirtIOConsole::TermRecvQueue,
|
||||
&VirtIOConsole::TermRecvQueue::trySend> callbackDataAvail;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user