Gabe Black has uploaded this change for review. (
https://gem5-review.googlesource.com/9721
Change subject: dev: arm: Minor reworking of the KMI device.
......................................................................
dev: arm: Minor reworking of the KMI device.
This reworking was an attempt to make the KMI slightly more realistic by
modeling contention for the actual PS/2 bus to the slave device, although
that bus might not actually physically exist in modern hardware. This was
to hopefully poke various interrupts in a more realistic way, occasionally
deasserting the TX empty interrupt while a byte was waiting to be sent, and
not instantaneously responding to received commands.
Unfortunately it looks like additional realism doesn't help in KVM mode
since
the problem there seems to be with how timers are managed and timeouts in
the
kernel. This change is therefore mostly for posterity, and in case we decide
that it's actually something we want.
Change-Id: I726d686422d4491b4e30e846389f229c9b520e3d
---
M src/dev/arm/RealView.py
M src/dev/arm/kmi.cc
M src/dev/arm/kmi.hh
3 files changed, 122 insertions(+), 44 deletions(-)
diff --git a/src/dev/arm/RealView.py b/src/dev/arm/RealView.py
index a59e171..818ff2a 100644
--- a/src/dev/arm/RealView.py
+++ b/src/dev/arm/RealView.py
@@ -468,6 +468,8 @@
vnc = Param.VncInput(Parent.any, "Vnc server for remote frame buffer
display")
is_mouse = Param.Bool(False, "Is this interface a mouse, if not a
keyboard")
int_delay = '1us'
+ comm_delay = Param.Latency(
+ '1us', "Time to transmit/receive one byte from the peripheral")
amba_id = 0x00141050
def generateDeviceTree(self, state):
diff --git a/src/dev/arm/kmi.cc b/src/dev/arm/kmi.cc
index 8b373b8..acb1737 100644
--- a/src/dev/arm/kmi.cc
+++ b/src/dev/arm/kmi.cc
@@ -55,7 +55,9 @@
: AmbaIntDevice(p, 0xfff), control(0), status(0x43), clkdiv(0),
rawInterrupts(0), ackNext(false), shiftDown(false),
vnc(p->vnc), driverInitialized(false),
- intEvent([this]{ generateInterrupt(); }, name())
+ intEvent([this]{ generateInterrupt(); }, name()),
+ commEvent([this]{ commByte(); }, name()), commDelay(p->comm_delay),
+ rxBuf(0), rxFull(false), txBuf(0), txFull(false)
{
if (vnc) {
if (!p->is_mouse)
@@ -65,6 +67,63 @@
}
}
+uint8_t
+Pl050::finishRx()
+{
+ if (!rxFull) {
+ warn("Tried to read PS/2 data but RX buffer is empty.\n");
+ return 0;
+ }
+ rxFull = false;
+ scheduleComm();
+ updateIntStatus();
+ return rxBuf;
+}
+
+void
+Pl050::startTx(uint8_t val)
+{
+ if (txFull) {
+ warn("Tried to send PS/2 data but TX buffer is already full.\n");
+ return;
+ }
+ txFull = true;
+ txBuf = val;
+ scheduleComm();
+ updateIntStatus();
+}
+
+void
+Pl050::scheduleComm()
+{
+ // If there are more bytes to transmit and/or receive, make sure an
+ // event is scheduled for them.
+ bool pending = (txFull || (!rxFull && !rxQueue.empty()));
+ if (pending && !commEvent.scheduled())
+ schedule(commEvent, curTick() + commDelay);
+}
+
+void
+Pl050::commByte()
+{
+ // Give preference to transmiting bytes.
+ if (txFull) {
+ // The byte has now been "transmitted" to the slave device and can
+ // be processed.
+ processByte(txBuf);
+ txFull = false;
+ } else if (!rxFull && !rxQueue.empty()) {
+ // The RX buffer is empty, and there are bytes the slave device is
+ // waiting to send us. Receive one into our RX buffer.
+ rxBuf = rxQueue.front();
+ rxQueue.pop_front();
+ rxFull = true;
+ }
+
+ scheduleComm();
+ updateIntStatus();
+}
+
Tick
Pl050::read(PacketPtr pkt)
{
@@ -80,23 +139,15 @@
data = control;
break;
case kmiStat:
- if (rxQueue.empty())
- status.rxfull = 0;
- else
- status.rxfull = 1;
+ status.rxfull = rxFull;
+ status.txempty = !txFull;
DPRINTF(Pl050, "Read Status: %#x\n", (uint32_t)status);
data = status;
break;
case kmiData:
- if (rxQueue.empty()) {
- data = 0;
- } else {
- data = rxQueue.front();
- rxQueue.pop_front();
- }
- DPRINTF(Pl050, "Read Data: %#x\n", (uint32_t)data);
- updateIntStatus();
+ data = finishRx();
+ DPRINTF(Pl050, "Read Data: %#x\n", data);
break;
case kmiClkDiv:
data = clkdiv;
@@ -144,21 +195,20 @@
Addr daddr = pkt->getAddr() - pioAddr;
assert(pkt->getSize() == sizeof(uint8_t));
-
+ uint8_t data = pkt->get<uint8_t>();
switch (daddr) {
case kmiCr:
- DPRINTF(Pl050, "Write Commmand: %#x\n",
(uint32_t)pkt->get<uint8_t>());
- control = pkt->get<uint8_t>();
+ DPRINTF(Pl050, "Write Commmand: %#x\n", data);
+ control = data;
updateIntStatus();
break;
case kmiData:
- DPRINTF(Pl050, "Write Data: %#x\n", (uint32_t)pkt->get<uint8_t>());
- processCommand(pkt->get<uint8_t>());
- updateIntStatus();
+ DPRINTF(Pl050, "Write Data: %#x\n", data);
+ startTx(data);
break;
case kmiClkDiv:
- clkdiv = pkt->get<uint8_t>();
+ clkdiv = data;
break;
default:
warn("Tried to write PL050 at offset %#x that doesn't exist\n",
daddr);
@@ -169,14 +219,13 @@
}
void
-Pl050::processCommand(uint8_t byte)
+Pl050::processByte(uint8_t byte)
{
using namespace Ps2;
if (ackNext) {
ackNext--;
rxQueue.push_back(Ack);
- updateIntStatus();
return;
}
@@ -199,8 +248,10 @@
rxQueue.push_back(KeyboardId);
break;
case TpReadId:
- if (!params()->is_mouse)
+ if (!params()->is_mouse) {
+ rxQueue.push_back(0xfe);
break;
+ }
// We're not a trackpoint device, this should make the probe go
away
rxQueue.push_back(Ack);
rxQueue.push_back(0);
@@ -229,27 +280,38 @@
driverInitialized = true;
break;
default:
- panic("Unknown byte received: %d\n", byte);
+ rxQueue.push_back(0xfe);
+ warn("\n\nUnknown byte received: %d\n\n\n", byte);
+ break;
+ //panic("Unknown byte received: %d\n", byte);
}
-
- updateIntStatus();
}
void
Pl050::updateIntStatus()
{
- const bool old_interrupt(getInterrupt());
+ const bool old_int = getInterrupt();
- if (!rxQueue.empty())
- rawInterrupts.rx = 1;
- else
- rawInterrupts.rx = 0;
+ rawInterrupts.rx = rxFull ? 1 : 0;
+ rawInterrupts.tx = !txFull ? 1 : 0;
- if ((!old_interrupt && getInterrupt()) && !intEvent.scheduled()) {
- schedule(intEvent, curTick() + intDelay);
- } else if (old_interrupt && !(getInterrupt())) {
- gic->clearInt(intNum);
+ const bool new_int = getInterrupt();
+
+ // If whether we need an interrupt hasn't changed, stop now.
+ if (old_int == new_int)
+ return;
+
+ if (new_int) {
+ // If we need an interrupt now, make sure one is scheduled.
+ if (!intEvent.scheduled())
+ schedule(intEvent, curTick() + intDelay);
+ } else {
+ // If we don't need an interrupt, make sure it's cleared and not
+ // scheduled for later.
+ gic->clearInt(intNum);
+ if (intEvent.scheduled())
+ deschedule(intEvent);
}
}
@@ -259,10 +321,8 @@
DPRINTF(Pl050, "Generate Interrupt: rawInt=%#x ctrl=%#x int=%#x\n",
rawInterrupts, control, getInterrupt());
- if (getInterrupt()) {
- gic->sendInt(intNum);
- DPRINTF(Pl050, " -- Generated\n");
- }
+ gic->sendInt(intNum);
+ DPRINTF(Pl050, " -- Generated\n");
}
void
@@ -291,7 +351,7 @@
rxQueue.push_back(_y >> 7);
rxQueue.push_back(_y & 0x7f);
- updateIntStatus();
+ scheduleComm();
}
@@ -307,7 +367,7 @@
// Insert into our queue of charecters
rxQueue.splice(rxQueue.end(), keys);
- updateIntStatus();
+ scheduleComm();
}
void
diff --git a/src/dev/arm/kmi.hh b/src/dev/arm/kmi.hh
index 0593165..03b2c72 100644
--- a/src/dev/arm/kmi.hh
+++ b/src/dev/arm/kmi.hh
@@ -136,14 +136,30 @@
/** Wrapper to create an event out of the thing */
EventFunctionWrapper intEvent;
- /** Receive queue. This list contains all the pending commands that
+ /** Event which represents completing one tx or rx. */
+ EventFunctionWrapper commEvent;
+
+ Tick commDelay;
+ void scheduleComm();
+ void commByte();
+
+ /** Receive queue. This list contains all the pending responses that
* need to be sent to the driver
*/
std::list<uint8_t> rxQueue;
- /** Handle a command sent to the kmi and respond appropriately
+ uint8_t rxBuf;
+ bool rxFull;
+
+ uint8_t txBuf;
+ bool txFull;
+
+ uint8_t finishRx();
+ void startTx(uint8_t val);
+
+ /** Handle a byte sent to the kmi and respond appropriately
*/
- void processCommand(uint8_t byte);
+ void processByte(uint8_t byte);
public:
typedef Pl050Params Params;
--
To view, visit https://gem5-review.googlesource.com/9721
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: I726d686422d4491b4e30e846389f229c9b520e3d
Gerrit-Change-Number: 9721
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev