/*
- * Copyright (c) 2010-2012 ARM Limited
+ * Copyright (c) 2010-2012, 2015 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* Ali Saidi
*/
-#include "base/vnc/vncinput.hh"
-#include "base/bitmap.hh"
+#include "dev/arm/pl111.hh"
+
#include "base/output.hh"
#include "base/trace.hh"
+#include "base/vnc/vncinput.hh"
#include "debug/PL111.hh"
#include "debug/Uart.hh"
#include "dev/arm/amba_device.hh"
-#include "dev/arm/gic.hh"
-#include "dev/arm/pl111.hh"
+#include "dev/arm/base_gic.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
+#include "sim/system.hh"
// clang complains about std::set being overloaded with Packet::set if
// we open up the entire namespace std
using std::vector;
-using namespace AmbaDev;
-
// initialize clcd registers
Pl111::Pl111(const Params *p)
: AmbaDmaDevice(p), lcdTiming0(0), lcdTiming1(0), lcdTiming2(0),
clcdCrsrPalette1(0), clcdCrsrXY(0), clcdCrsrClip(0), clcdCrsrImsc(0),
clcdCrsrIcr(0), clcdCrsrRis(0), clcdCrsrMis(0),
pixelClock(p->pixel_clock),
- vnc(p->vnc), bmp(NULL), width(LcdMaxWidth), height(LcdMaxHeight),
+ converter(PixelConverter::rgba8888_le), fb(LcdMaxWidth, LcdMaxHeight),
+ vnc(p->vnc), bmp(&fb), pic(NULL),
+ width(LcdMaxWidth), height(LcdMaxHeight),
bytesPerPixel(4), startTime(0), startAddr(0), maxAddr(0), curAddr(0),
- waterMark(0), dmaPendingNum(0), readEvent(this), fillFifoEvent(this),
- dmaDoneEvent(maxOutstandingDma, this), intEvent(this)
+ waterMark(0), dmaPendingNum(0),
+ readEvent([this]{ readFramebuffer(); }, name()),
+ fillFifoEvent([this]{ fillFifo(); }, name()),
+ dmaDoneEventAll(maxOutstandingDma, this),
+ dmaDoneEventFree(maxOutstandingDma),
+ intEvent([this]{ generateInterrupt(); }, name()),
+ enableCapture(p->enable_capture)
{
pioSize = 0xFFFF;
- pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()), true);
-
- const int buffer_size = LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t);
dmaBuffer = new uint8_t[buffer_size];
memset(lcdPalette, 0, sizeof(lcdPalette));
memset(cursorImage, 0, sizeof(cursorImage));
memset(dmaBuffer, 0, buffer_size);
+ for (int i = 0; i < maxOutstandingDma; ++i)
+ dmaDoneEventFree[i] = &dmaDoneEventAll[i];
+
if (vnc)
- vnc->setFramebufferAddr(dmaBuffer);
+ vnc->setFrameBuffer(&fb);
}
Pl111::~Pl111()
pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
- pkt->allocate();
DPRINTF(PL111, " read register %#x size=%d\n", daddr, pkt->getSize());
data = clcdCrsrMis;
break;
default:
- if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) {
+ if (readId(pkt, AMBA_ID, pioAddr)) {
// Hack for variable size accesses
- data = pkt->get<uint32_t>();
+ data = pkt->getLE<uint32_t>();
break;
} else if (daddr >= CrsrImage && daddr <= 0xBFC) {
// CURSOR IMAGE
data = lcdPalette[index];
break;
} else {
- panic("Tried to read CLCD register at offset %#x that \
- doesn't exist\n", daddr);
+ panic("Tried to read CLCD register at offset %#x that "
+ "doesn't exist\n", daddr);
break;
}
}
switch(pkt->getSize()) {
case 1:
- pkt->set<uint8_t>(data);
+ pkt->setLE<uint8_t>(data);
break;
case 2:
- pkt->set<uint16_t>(data);
+ pkt->setLE<uint16_t>(data);
break;
case 4:
- pkt->set<uint32_t>(data);
+ pkt->setLE<uint32_t>(data);
break;
default:
panic("CLCD controller read size too big?\n");
switch(pkt->getSize()) {
case 1:
- data = pkt->get<uint8_t>();
+ data = pkt->getLE<uint8_t>();
break;
case 2:
- data = pkt->get<uint16_t>();
+ data = pkt->getLE<uint16_t>();
break;
case 4:
- data = pkt->get<uint32_t>();
+ data = pkt->getLE<uint32_t>();
break;
default:
panic("PL111 CLCD controller write size too big?\n");
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(PL111, " write register %#x value %#x size=%d\n", daddr,
- pkt->get<uint8_t>(), pkt->getSize());
+ pkt->getLE<uint8_t>(), pkt->getSize());
switch (daddr) {
case LcdTiming0:
lcdPalette[index] = data;
break;
} else {
- panic("Tried to write PL111 register at offset %#x that \
- doesn't exist\n", daddr);
+ panic("Tried to write PL111 register at offset %#x that "
+ "doesn't exist\n", daddr);
break;
}
}
return pioDelay;
}
+PixelConverter
+Pl111::pixelConverter() const
+{
+ unsigned rw, gw, bw;
+ unsigned offsets[3];
+
+ switch (lcdControl.lcdbpp) {
+ case bpp24:
+ rw = gw = bw = 8;
+ offsets[0] = 0;
+ offsets[1] = 8;
+ offsets[2] = 16;
+ break;
+
+ case bpp16m565:
+ rw = 5;
+ gw = 6;
+ bw = 5;
+ offsets[0] = 0;
+ offsets[1] = 5;
+ offsets[2] = 11;
+ break;
+
+ default:
+ panic("Unimplemented video mode\n");
+ }
+
+ if (lcdControl.bgr) {
+ return PixelConverter(
+ bytesPerPixel,
+ offsets[2], offsets[1], offsets[0],
+ rw, gw, bw,
+ LittleEndianByteOrder);
+ } else {
+ return PixelConverter(
+ bytesPerPixel,
+ offsets[0], offsets[1], offsets[2],
+ rw, gw, bw,
+ LittleEndianByteOrder);
+ }
+}
+
void
Pl111::updateVideoParams()
{
- if (lcdControl.lcdbpp == bpp24) {
- bytesPerPixel = 4;
- } else if (lcdControl.lcdbpp == bpp16m565) {
- bytesPerPixel = 2;
- }
+ if (lcdControl.lcdbpp == bpp24) {
+ bytesPerPixel = 4;
+ } else if (lcdControl.lcdbpp == bpp16m565) {
+ bytesPerPixel = 2;
+ }
- if (vnc) {
- if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr)
- vnc->setFrameBufferParams(VideoConvert::bgr8888, width,
- height);
- else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr)
- vnc->setFrameBufferParams(VideoConvert::rgb8888, width,
- height);
- else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr)
- vnc->setFrameBufferParams(VideoConvert::bgr565, width,
- height);
- else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr)
- vnc->setFrameBufferParams(VideoConvert::rgb565, width,
- height);
- else
- panic("Unimplemented video mode\n");
- }
+ fb.resize(width, height);
+ converter = pixelConverter();
- if (bmp)
- delete bmp;
-
- if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr)
- bmp = new Bitmap(VideoConvert::bgr8888, width, height, dmaBuffer);
- else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr)
- bmp = new Bitmap(VideoConvert::rgb8888, width, height, dmaBuffer);
- else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr)
- bmp = new Bitmap(VideoConvert::bgr565, width, height, dmaBuffer);
- else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr)
- bmp = new Bitmap(VideoConvert::rgb565, width, height, dmaBuffer);
- else
- panic("Unimplemented video mode\n");
+ // Workaround configuration bugs where multiple display
+ // controllers are attached to the same VNC server by reattaching
+ // enabled devices. This isn't ideal, but works as long as only
+ // one display controller is active at a time.
+ if (lcdControl.lcdpwr && vnc)
+ vnc->setFrameBuffer(&fb);
}
void
// Updating base address, interrupt if we're supposed to
lcdRis.baseaddr = 1;
if (!intEvent.scheduled())
- schedule(intEvent, nextCycle());
+ schedule(intEvent, clockEdge());
curAddr = 0;
startTime = curTick();
// due to assertion in scheduling state
++dmaPendingNum;
- assert(!dmaDoneEvent[dmaPendingNum-1].scheduled());
+ assert(!dmaDoneEventFree.empty());
+ DmaDoneEvent *event(dmaDoneEventFree.back());
+ dmaDoneEventFree.pop_back();
+ assert(!event->scheduled());
// We use a uncachable request here because the requests from the CPU
// will be uncacheable as well. If we have uncacheable and cacheable
// requests in the memory system for the same address it won't be
// pleased
dmaPort.dmaAction(MemCmd::ReadReq, curAddr + startAddr, dmaSize,
- &dmaDoneEvent[dmaPendingNum-1], curAddr + dmaBuffer,
+ event, curAddr + dmaBuffer,
0, Request::UNCACHEABLE);
curAddr += dmaSize;
}
" have taken %d\n", curTick() - startTime, maxFrameTime);
lcdRis.underflow = 1;
if (!intEvent.scheduled())
- schedule(intEvent, nextCycle());
+ schedule(intEvent, clockEdge());
}
assert(!readEvent.scheduled());
+ fb.copyIn(dmaBuffer, converter);
if (vnc)
vnc->setDirty();
- DPRINTF(PL111, "-- write out frame buffer into bmp\n");
+ if (enableCapture) {
+ DPRINTF(PL111, "-- write out frame buffer into bmp\n");
- assert(bmp);
- pic->seekp(0);
- bmp->write(pic);
+ if (!pic)
+ pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()),
+ true);
+
+ assert(pic);
+ pic->stream()->seekp(0);
+ bmp.write(*pic->stream());
+ }
// schedule the next read based on when the last frame started
// and the desired fps (i.e. maxFrameTime), we turn the
return;
if (!fillFifoEvent.scheduled())
- schedule(fillFifoEvent, nextCycle());
+ schedule(fillFifoEvent, clockEdge());
}
void
-Pl111::serialize(std::ostream &os)
+Pl111::serialize(CheckpointOut &cp) const
{
DPRINTF(PL111, "Serializing ARM PL111\n");
SERIALIZE_SCALAR(width);
SERIALIZE_SCALAR(bytesPerPixel);
- SERIALIZE_ARRAY(dmaBuffer, height * width);
+ SERIALIZE_ARRAY(dmaBuffer, buffer_size);
SERIALIZE_SCALAR(startTime);
SERIALIZE_SCALAR(startAddr);
SERIALIZE_SCALAR(maxAddr);
vector<Tick> dma_done_event_tick;
dma_done_event_tick.resize(maxOutstandingDma);
for (int x = 0; x < maxOutstandingDma; x++) {
- dma_done_event_tick[x] = dmaDoneEvent[x].scheduled() ?
- dmaDoneEvent[x].when() : 0;
+ dma_done_event_tick[x] = dmaDoneEventAll[x].scheduled() ?
+ dmaDoneEventAll[x].when() : 0;
}
- arrayParamOut(os, "dma_done_event_tick", dma_done_event_tick);
+ SERIALIZE_CONTAINER(dma_done_event_tick);
}
void
-Pl111::unserialize(Checkpoint *cp, const std::string §ion)
+Pl111::unserialize(CheckpointIn &cp)
{
DPRINTF(PL111, "Unserializing ARM PL111\n");
UNSERIALIZE_SCALAR(width);
UNSERIALIZE_SCALAR(bytesPerPixel);
- UNSERIALIZE_ARRAY(dmaBuffer, height * width);
+ UNSERIALIZE_ARRAY(dmaBuffer, buffer_size);
UNSERIALIZE_SCALAR(startTime);
UNSERIALIZE_SCALAR(startAddr);
UNSERIALIZE_SCALAR(maxAddr);
vector<Tick> dma_done_event_tick;
dma_done_event_tick.resize(maxOutstandingDma);
- arrayParamIn(cp, section, "dma_done_event_tick", dma_done_event_tick);
+ UNSERIALIZE_CONTAINER(dma_done_event_tick);
+ dmaDoneEventFree.clear();
for (int x = 0; x < maxOutstandingDma; x++) {
if (dma_done_event_tick[x])
- schedule(dmaDoneEvent[x], dma_done_event_tick[x]);
+ schedule(dmaDoneEventAll[x], dma_done_event_tick[x]);
+ else
+ dmaDoneEventFree.push_back(&dmaDoneEventAll[x]);
}
+ assert(maxOutstandingDma - dmaDoneEventFree.size() == dmaPendingNum);
if (lcdControl.lcdpwr) {
updateVideoParams();
+ fb.copyIn(dmaBuffer, converter);
if (vnc)
vnc->setDirty();
}