VNC/ARM: Use VNC server and add support to boot into X11

This commit is contained in:
Ali Saidi 2011-02-11 18:29:36 -06:00
parent d33c1d9592
commit d4df9e763c
12 changed files with 1066 additions and 463 deletions

View file

@ -69,6 +69,7 @@ if env['FULL_SYSTEM']:
Source('pcidev.cc')
Source('pktfifo.cc')
Source('platform.cc')
Source('ps2.cc')
Source('simple_disk.cc')
Source('sinic.cc')
Source('terminal.cc')

View file

@ -52,6 +52,14 @@ class AmbaDevice(BasicPioDevice):
abstract = True
amba_id = Param.UInt32("ID of AMBA device for kernel detection")
class AmbaIntDevice(AmbaDevice):
type = 'AmbaIntDevice'
abstract = True
gic = Param.Gic(Parent.any, "Gic to use for interrupting")
int_num = Param.UInt32("Interrupt number that connects to GIC")
int_delay = Param.Latency("100ns",
"Time between action and interrupt generation by device")
class AmbaDmaDevice(DmaDevice):
type = 'AmbaDmaDevice'
abstract = True
@ -94,16 +102,17 @@ class Sp804(AmbaDevice):
clock1 = Param.Clock('1MHz', "Clock speed of the input")
amba_id = 0x00141804
class Pl050(AmbaDevice):
class Pl050(AmbaIntDevice):
type = 'Pl050'
gic = Param.Gic(Parent.any, "Gic to use for interrupting")
int_num = Param.UInt32("Interrupt number that connects to GIC")
int_delay = Param.Latency("100ns", "Time between action and interrupt generation by UART")
vnc = Param.VncServer(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'
amba_id = 0x00141050
class Pl111(AmbaDmaDevice):
type = 'Pl111'
clock = Param.Clock('24MHz', "Clock speed of the input")
vnc = Param.VncServer(Parent.any, "Vnc server for remote frame buffer display")
amba_id = 0x00141111
class RealView(Platform):
@ -121,7 +130,7 @@ class RealViewPBX(RealView):
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
clcd = Pl111(pio_addr=0x10020000, int_num=55)
kmi0 = Pl050(pio_addr=0x10006000, int_num=52)
kmi1 = Pl050(pio_addr=0x10007000, int_num=53)
kmi1 = Pl050(pio_addr=0x10007000, int_num=53, is_mouse=True)
l2x0_fake = IsaFake(pio_addr=0x1f002000, pio_size=0xfff)
flash_fake = IsaFake(pio_addr=0x40000000, pio_size=0x4000000)
@ -140,7 +149,7 @@ class RealViewPBX(RealView):
aaci_fake = AmbaFake(pio_addr=0x10004000)
mmc_fake = AmbaFake(pio_addr=0x10005000)
rtc_fake = AmbaFake(pio_addr=0x10017000, amba_id=0x41031)
cf0_fake = IsaFake(pio_addr=0x18000000, pio_size=0xfff)
# Attach I/O devices that are on chip
@ -175,6 +184,7 @@ class RealViewPBX(RealView):
self.mmc_fake.pio = bus.port
self.rtc_fake.pio = bus.port
self.flash_fake.pio = bus.port
self.cf0_fake.pio = bus.port
# Reference for memory map and interrupt number
# RealView Emulation Baseboard User Guide (ARM DUI 0143B)
@ -187,7 +197,7 @@ class RealViewEB(RealView):
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
clcd = Pl111(pio_addr=0x10020000, int_num=23)
kmi0 = Pl050(pio_addr=0x10006000, int_num=20)
kmi1 = Pl050(pio_addr=0x10007000, int_num=21)
kmi1 = Pl050(pio_addr=0x10007000, int_num=21, is_mouse=True)
l2x0_fake = IsaFake(pio_addr=0x1f002000, pio_size=0xfff, warn_access="1")
dmac_fake = AmbaFake(pio_addr=0x10030000)

View file

@ -47,11 +47,19 @@
#include "mem/packet_access.hh"
const uint64_t AmbaVendor = ULL(0xb105f00d00000000);
AmbaDevice::AmbaDevice(const Params *p)
: BasicPioDevice(p), ambaId(AmbaVendor | p->amba_id)
{
}
AmbaIntDevice::AmbaIntDevice(const Params *p)
: AmbaDevice(p), intNum(p->int_num), gic(p->gic), intDelay(p->int_delay)
{
}
AmbaDmaDevice::AmbaDmaDevice(const Params *p)
: DmaDevice(p), ambaId(AmbaVendor | p->amba_id),
pioAddr(p->pio_addr), pioSize(0),

View file

@ -55,6 +55,7 @@
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "params/AmbaDevice.hh"
#include "params/AmbaIntDevice.hh"
#include "params/AmbaDmaDevice.hh"
namespace AmbaDev {
@ -81,6 +82,18 @@ class AmbaDevice : public BasicPioDevice
AmbaDevice(const Params *p);
};
class AmbaIntDevice : public AmbaDevice
{
protected:
int intNum;
Gic *gic;
Tick intDelay;
public:
typedef AmbaIntDeviceParams Params;
AmbaIntDevice(const Params *p);
};
class AmbaDmaDevice : public DmaDevice
{
protected:

View file

@ -37,21 +37,31 @@
* (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: William Wang
* Authors: Ali Saidi
* William Wang
*/
#include "base/trace.hh"
#include "base/vnc/vncserver.hh"
#include "dev/arm/amba_device.hh"
#include "dev/arm/kmi.hh"
#include "dev/ps2.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
Pl050::Pl050(const Params *p)
: AmbaDevice(p), control(0x00), status(0x43), kmidata(0x00), clkdiv(0x00),
intreg(0x00), intNum(p->int_num), gic(p->gic), intDelay(p->int_delay),
intEvent(this)
: AmbaIntDevice(p), control(0), status(0x43), clkdiv(0), interrupts(0),
rawInterrupts(0), ackNext(false), shiftDown(false), vnc(p->vnc),
driverInitialized(false), intEvent(this)
{
pioSize = 0xfff;
if (vnc) {
if (!p->is_mouse)
vnc->setKeyboard(this);
else
vnc->setMouse(this);
}
}
Tick
@ -62,28 +72,39 @@ Pl050::read(PacketPtr pkt)
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
DPRINTF(Pl050, " read register %#x size=%d\n", daddr, pkt->getSize());
// use a temporary data since the KMI registers are read/written with
// different size operations
//
uint32_t data = 0;
switch (daddr) {
case kmiCr:
DPRINTF(Pl050, "Read Commmand: %#x\n", (uint32_t)control);
data = control;
break;
case kmiStat:
if (rxQueue.empty())
status.rxfull = 0;
else
status.rxfull = 1;
DPRINTF(Pl050, "Read Status: %#x\n", (uint32_t)status);
data = status;
break;
case kmiData:
data = kmidata;
if (rxQueue.empty()) {
data = 0;
} else {
data = rxQueue.front();
rxQueue.pop_front();
}
DPRINTF(Pl050, "Read Data: %#x\n", (uint32_t)data);
updateIntStatus();
break;
case kmiClkDiv:
data = clkdiv;
break;
case kmiISR:
data = intreg;
data = interrupts;
DPRINTF(Pl050, "Read Interrupts: %#x\n", (uint32_t)interrupts);
break;
default:
if (AmbaDev::readId(pkt, ambaId, pioAddr)) {
@ -123,47 +144,22 @@ Pl050::write(PacketPtr pkt)
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(Pl050, " write register %#x value %#x size=%d\n", daddr,
pkt->get<uint8_t>(), pkt->getSize());
// use a temporary data since the KMI registers are read/written with
// different size operations
//
uint32_t data = 0;
switch (pkt->getSize()) {
case 1:
data = pkt->get<uint8_t>();
break;
case 2:
data = pkt->get<uint16_t>();
break;
case 4:
data = pkt->get<uint32_t>();
break;
default:
panic("KMI write size too big?\n");
break;
}
assert(pkt->getSize() == sizeof(uint8_t));
switch (daddr) {
case kmiCr:
control = data;
break;
case kmiStat:
panic("Tried to write PL050 register(read only) at offset %#x\n",
daddr);
DPRINTF(Pl050, "Write Commmand: %#x\n", (uint32_t)pkt->get<uint8_t>());
control = pkt->get<uint8_t>();
updateIntStatus();
break;
case kmiData:
kmidata = data;
DPRINTF(Pl050, "Write Data: %#x\n", (uint32_t)pkt->get<uint8_t>());
processCommand(pkt->get<uint8_t>());
updateIntStatus();
break;
case kmiClkDiv:
clkdiv = data;
break;
case kmiISR:
panic("Tried to write PL050 register(read only) at offset %#x\n",
daddr);
clkdiv = pkt->get<uint8_t>();
break;
default:
warn("Tried to write PL050 at offset %#x that doesn't exist\n", daddr);
@ -173,15 +169,199 @@ Pl050::write(PacketPtr pkt)
return pioDelay;
}
void
Pl050::processCommand(uint8_t byte)
{
using namespace Ps2;
if (ackNext) {
ackNext--;
rxQueue.push_back(Ack);
updateIntStatus();
return;
}
switch (byte) {
case Ps2Reset:
rxQueue.push_back(Ack);
rxQueue.push_back(SelfTestPass);
break;
case SetResolution:
case SetRate:
case SetStatusLed:
case SetScaling1_1:
case SetScaling1_2:
rxQueue.push_back(Ack);
ackNext = 1;
break;
case ReadId:
rxQueue.push_back(Ack);
if (params()->is_mouse)
rxQueue.push_back(MouseId);
else
rxQueue.push_back(KeyboardId);
break;
case TpReadId:
if (!params()->is_mouse)
break;
// We're not a trackpoint device, this should make the probe go away
rxQueue.push_back(Ack);
rxQueue.push_back(0);
rxQueue.push_back(0);
// fall through
case Disable:
case Enable:
rxQueue.push_back(Ack);
break;
case StatusRequest:
rxQueue.push_back(Ack);
rxQueue.push_back(0);
rxQueue.push_back(2); // default resolution
rxQueue.push_back(100); // default sample rate
break;
case TouchKitId:
ackNext = 2;
rxQueue.push_back(Ack);
rxQueue.push_back(TouchKitId);
rxQueue.push_back(1);
rxQueue.push_back('A');
driverInitialized = true;
break;
default:
panic("Unknown byte received: %d\n", byte);
}
updateIntStatus();
}
void
Pl050::updateIntStatus()
{
if (!rxQueue.empty())
rawInterrupts.rx = 1;
else
rawInterrupts.rx = 0;
interrupts.tx = rawInterrupts.tx & control.txint_enable;
interrupts.rx = rawInterrupts.rx & control.rxint_enable;
DPRINTF(Pl050, "rawInterupts=%#x control=%#x interrupts=%#x\n",
(uint32_t)rawInterrupts, (uint32_t)control, (uint32_t)interrupts);
if (interrupts && !intEvent.scheduled())
schedule(intEvent, curTick() + intDelay);
}
void
Pl050::generateInterrupt()
{
if (intreg.rxintr || intreg.txintr) {
if (interrupts) {
gic->sendInt(intNum);
DPRINTF(Pl050, " -- Generated\n");
DPRINTF(Pl050, "Generated interrupt\n");
}
}
void
Pl050::mouseAt(uint16_t x, uint16_t y, uint8_t buttons)
{
using namespace Ps2;
// If the driver hasn't initialized the device yet, no need to try and send
// it anything. Similarly we can get vnc mouse events orders of maginture
// faster than m5 can process them. Only queue up two sets mouse movements
// and don't add more until those are processed.
if (!driverInitialized || rxQueue.size() > 10)
return;
// We shouldn't be here unless a vnc server called us in which case
// we should have a pointer to it
assert(vnc);
// Convert screen coordinates to touchpad coordinates
uint16_t _x = (2047.0/vnc->videoWidth()) * x;
uint16_t _y = (2047.0/vnc->videoHeight()) * y;
rxQueue.push_back(buttons);
rxQueue.push_back(_x >> 7);
rxQueue.push_back(_x & 0x7f);
rxQueue.push_back(_y >> 7);
rxQueue.push_back(_y & 0x7f);
updateIntStatus();
}
void
Pl050::keyPress(uint32_t key, bool down)
{
using namespace Ps2;
std::list<uint8_t> keys;
// convert the X11 keysym into ps2 codes
keySymToPs2(key, down, shiftDown, keys);
// Insert into our queue of charecters
rxQueue.splice(rxQueue.end(), keys);
updateIntStatus();
}
void
Pl050::serialize(std::ostream &os)
{
uint8_t ctrlreg = control;
SERIALIZE_SCALAR(ctrlreg);
uint8_t stsreg = status;
SERIALIZE_SCALAR(stsreg);
SERIALIZE_SCALAR(clkdiv);
uint8_t ints = interrupts;
SERIALIZE_SCALAR(ints);
uint8_t raw_ints = rawInterrupts;
SERIALIZE_SCALAR(raw_ints);
SERIALIZE_SCALAR(ackNext);
SERIALIZE_SCALAR(shiftDown);
SERIALIZE_SCALAR(driverInitialized);
arrayParamOut(os, "rxQueue", rxQueue);
}
void
Pl050::unserialize(Checkpoint *cp, const std::string &section)
{
uint8_t ctrlreg;
UNSERIALIZE_SCALAR(ctrlreg);
control = ctrlreg;
uint8_t stsreg;
UNSERIALIZE_SCALAR(stsreg);
status = stsreg;
UNSERIALIZE_SCALAR(clkdiv);
uint8_t ints;
UNSERIALIZE_SCALAR(ints);
interrupts = ints;
uint8_t raw_ints;
UNSERIALIZE_SCALAR(raw_ints);
rawInterrupts = raw_ints;
UNSERIALIZE_SCALAR(ackNext);
UNSERIALIZE_SCALAR(shiftDown);
UNSERIALIZE_SCALAR(driverInitialized);
arrayParamIn(cp, section, "rxQueue", rxQueue);
}
Pl050 *
Pl050Params::create()
{

View file

@ -48,13 +48,16 @@
#ifndef __DEV_ARM_PL050_HH__
#define __DEV_ARM_PL050_HH__
#include <list>
#include "base/range.hh"
#include "dev/io_device.hh"
#include "base/vnc/vncserver.hh"
#include "dev/arm/amba_device.hh"
#include "params/Pl050.hh"
class Gic;
class Pl050 : public AmbaDevice
class Pl050 : public AmbaIntDevice, public VncKeyboard, public VncMouse
{
protected:
static const int kmiCr = 0x000;
@ -63,34 +66,68 @@ class Pl050 : public AmbaDevice
static const int kmiClkDiv = 0x00C;
static const int kmiISR = 0x010;
// control register
uint8_t control;
BitUnion8(ControlReg)
Bitfield<0> force_clock_low;
Bitfield<1> force_data_low;
Bitfield<2> enable;
Bitfield<3> txint_enable;
Bitfield<4> rxint_enable;
Bitfield<5> type;
EndBitUnion(ControlReg)
// status register
uint8_t status;
/** control register
*/
ControlReg control;
// received data (read) or data to be transmitted (write)
uint8_t kmidata;
/** KMI status register */
BitUnion8(StatusReg)
Bitfield<0> data_in;
Bitfield<1> clk_in;
Bitfield<2> rxparity;
Bitfield<3> rxbusy;
Bitfield<4> rxfull;
Bitfield<5> txbusy;
Bitfield<6> txempty;
EndBitUnion(StatusReg)
// clock divisor register
StatusReg status;
/** clock divisor register
* This register is just kept around to satisfy reads after driver does
* writes. The divsor does nothing, as we're not actually signaling ps2
* serial commands to anything.
*/
uint8_t clkdiv;
BitUnion8(IntReg)
Bitfield<0> txintr;
Bitfield<1> rxintr;
EndBitUnion(IntReg)
BitUnion8(InterruptReg)
Bitfield<0> rx;
Bitfield<1> tx;
EndBitUnion(InterruptReg)
/** interrupt mask register. */
IntReg intreg;
/** interrupt status register. */
InterruptReg interrupts;
/** Interrupt number to generate */
int intNum;
/** raw interrupt register (unmasked) */
InterruptReg rawInterrupts;
/** Gic to use for interrupting */
Gic *gic;
/** If the controller should ignore the next data byte and acknowledge it.
* The driver is attempting to setup some feature we don't care about
*/
int ackNext;
/** Delay before interrupting */
Tick intDelay;
/** is the shift key currently down */
bool shiftDown;
/** The vnc server we're connected to (if any) */
VncServer *vnc;
/** If the linux driver has initialized the device yet and thus can we send
* mouse data */
bool driverInitialized;
/** Update the status of the interrupt registers and schedule an interrupt
* if required */
void updateIntStatus();
/** Function to generate interrupt */
void generateInterrupt();
@ -98,6 +135,15 @@ class Pl050 : public AmbaDevice
/** Wrapper to create an event out of the thing */
EventWrapper<Pl050, &Pl050::generateInterrupt> intEvent;
/** Receive queue. This list contains all the pending commands that
* need to be sent to the driver
*/
std::list<uint8_t> rxQueue;
/** Handle a command sent to the kmi and respond appropriately
*/
void processCommand(uint8_t byte);
public:
typedef Pl050Params Params;
const Params *
@ -111,12 +157,11 @@ class Pl050 : public AmbaDevice
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
/**
* Return if we have an interrupt pending
* @return interrupt status
* @todo fix me when implementation improves
*/
virtual bool intStatus() { return false; }
virtual void mouseAt(uint16_t x, uint16_t y, uint8_t buttons);
virtual void keyPress(uint32_t key, bool down);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif
#endif // __DEV_ARM_PL050_HH__

View file

@ -35,9 +35,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: William Wang
* Ali Saidi
*/
#include "base/bitmap.hh"
#include "base/output.hh"
#include "base/trace.hh"
#include "base/vnc/vncserver.hh"
#include "dev/arm/amba_device.hh"
#include "dev/arm/gic.hh"
#include "dev/arm/pl111.hh"
@ -50,20 +54,27 @@ using namespace AmbaDev;
Pl111::Pl111(const Params *p)
: AmbaDmaDevice(p), lcdTiming0(0), lcdTiming1(0), lcdTiming2(0),
lcdTiming3(0), lcdUpbase(0), lcdLpbase(0), lcdControl(0), lcdImsc(0),
lcdRis(0), lcdMis(0), lcdIcr(0), lcdUpcurr(0), lcdLpcurr(0),
lcdRis(0), lcdMis(0),
clcdCrsrCtrl(0), clcdCrsrConfig(0), clcdCrsrPalette0(0),
clcdCrsrPalette1(0), clcdCrsrXY(0), clcdCrsrClip(0), clcdCrsrImsc(0),
clcdCrsrIcr(0), clcdCrsrRis(0), clcdCrsrMis(0), clock(p->clock),
height(0), width(0), startTime(0), startAddr(0), maxAddr(0), curAddr(0),
vncserver(p->vnc), bmp(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)
{
pioSize = 0xFFFF;
pic = simout.create("framebuffer.bmp", true);
dmaBuffer = new uint8_t[LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t)];
memset(lcdPalette, 0, sizeof(lcdPalette));
memset(cursorImage, 0, sizeof(cursorImage));
memset(dmaBuffer, 0, sizeof(dmaBuffer));
memset(frameBuffer, 0, sizeof(frameBuffer));
if (vncserver)
vncserver->setFramebufferAddr(dmaBuffer);
}
// read registers and frame buffer
@ -75,111 +86,105 @@ Pl111::read(PacketPtr pkt)
uint32_t data = 0;
if ((pkt->getAddr()& 0xffff0000) == pioAddr) {
assert(pkt->getAddr() >= pioAddr &&
pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getAddr() >= pioAddr &&
pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
Addr daddr = pkt->getAddr()&0xFFFF;
pkt->allocate();
DPRINTF(PL111, " read register %#x size=%d\n", daddr, pkt->getSize());
DPRINTF(PL111, " read register %#x size=%d\n", daddr, pkt->getSize());
switch (daddr) {
case LcdTiming0:
data = lcdTiming0;
switch (daddr) {
case LcdTiming0:
data = lcdTiming0;
break;
case LcdTiming1:
data = lcdTiming1;
break;
case LcdTiming2:
data = lcdTiming2;
break;
case LcdTiming3:
data = lcdTiming3;
break;
case LcdUpBase:
data = lcdUpbase;
break;
case LcdLpBase:
data = lcdLpbase;
break;
case LcdControl:
data = lcdControl;
break;
case LcdImsc:
data = lcdImsc;
break;
case LcdRis:
data = lcdRis;
break;
case LcdMis:
data = lcdMis;
break;
case LcdIcr:
panic("LCD register at offset %#x is Write-Only\n", daddr);
break;
case LcdUpCurr:
data = curAddr;
break;
case LcdLpCurr:
data = curAddr;
break;
case ClcdCrsrCtrl:
data = clcdCrsrCtrl;
break;
case ClcdCrsrConfig:
data = clcdCrsrConfig;
break;
case ClcdCrsrPalette0:
data = clcdCrsrPalette0;
break;
case ClcdCrsrPalette1:
data = clcdCrsrPalette1;
break;
case ClcdCrsrXY:
data = clcdCrsrXY;
break;
case ClcdCrsrClip:
data = clcdCrsrClip;
break;
case ClcdCrsrImsc:
data = clcdCrsrImsc;
break;
case ClcdCrsrIcr:
panic("CLCD register at offset %#x is Write-Only\n", daddr);
break;
case ClcdCrsrRis:
data = clcdCrsrRis;
break;
case ClcdCrsrMis:
data = clcdCrsrMis;
break;
default:
if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) {
// Hack for variable size accesses
data = pkt->get<uint32_t>();
break;
case LcdTiming1:
data = lcdTiming1;
} else if (daddr >= CrsrImage && daddr <= 0xBFC) {
// CURSOR IMAGE
int index;
index = (daddr - CrsrImage) >> 2;
data= cursorImage[index];
break;
case LcdTiming2:
data = lcdTiming2;
} else if (daddr >= LcdPalette && daddr <= 0x3FC) {
// LCD Palette
int index;
index = (daddr - LcdPalette) >> 2;
data = lcdPalette[index];
break;
case LcdTiming3:
data = lcdTiming3;
break;
case LcdUpBase:
data = lcdUpbase;
break;
case LcdLpBase:
data = lcdLpbase;
break;
case LcdControl:
data = lcdControl;
break;
case LcdImsc:
warn("LCD interrupt set/clear function not supported\n");
data = lcdImsc;
break;
case LcdRis:
warn("LCD Raw interrupt status function not supported\n");
data = lcdRis;
break;
case LcdMis:
warn("LCD Masked interrupt status function not supported\n");
data = lcdMis;
break;
case LcdIcr:
panic("LCD register at offset %#x is Write-Only\n", daddr);
break;
case LcdUpCurr:
data = lcdUpcurr;
break;
case LcdLpCurr:
data = lcdLpcurr;
break;
case ClcdCrsrCtrl:
data = clcdCrsrCtrl;
break;
case ClcdCrsrConfig:
data = clcdCrsrConfig;
break;
case ClcdCrsrPalette0:
data = clcdCrsrPalette0;
break;
case ClcdCrsrPalette1:
data = clcdCrsrPalette1;
break;
case ClcdCrsrXY:
data = clcdCrsrXY;
break;
case ClcdCrsrClip:
data = clcdCrsrClip;
break;
case ClcdCrsrImsc:
data = clcdCrsrImsc;
break;
case ClcdCrsrIcr:
panic("CLCD register at offset %#x is Write-Only\n", daddr);
break;
case ClcdCrsrRis:
data = clcdCrsrRis;
break;
case ClcdCrsrMis:
data = clcdCrsrMis;
break;
default:
if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) {
// Hack for variable size accesses
data = pkt->get<uint32_t>();
break;
} else if (daddr >= CrsrImage && daddr <= 0xBFC) {
// CURSOR IMAGE
int index;
index = (daddr - CrsrImage) >> 2;
data= cursorImage[index];
break;
} else if (daddr >= LcdPalette && daddr <= 0x3FC) {
// LCD Palette
int index;
index = (daddr - LcdPalette) >> 2;
data = lcdPalette[index];
break;
} else {
panic("Tried to read CLCD register at offset %#x that \
} else {
panic("Tried to read CLCD register at offset %#x that \
doesn't exist\n", daddr);
break;
}
break;
}
}
@ -226,119 +231,133 @@ Pl111::write(PacketPtr pkt)
break;
}
if ((pkt->getAddr()& 0xffff0000) == pioAddr) {
assert(pkt->getAddr() >= pioAddr &&
pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getAddr() >= pioAddr &&
pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(PL111, " write register %#x value %#x size=%d\n", daddr,
pkt->get<uint8_t>(), pkt->getSize());
DPRINTF(PL111, " write register %#x value %#x size=%d\n", daddr,
pkt->get<uint8_t>(), pkt->getSize());
switch (daddr) {
case LcdTiming0:
lcdTiming0 = data;
// width = 16 * (PPL+1)
width = (lcdTiming0.ppl + 1) << 4;
break;
case LcdTiming1:
lcdTiming1 = data;
// height = LPP + 1
height = (lcdTiming1.lpp) + 1;
break;
case LcdTiming2:
lcdTiming2 = data;
break;
case LcdTiming3:
lcdTiming3 = data;
break;
case LcdUpBase:
lcdUpbase = data;
DPRINTF(PL111, "####### Upper panel base set to: %#x #######\n", lcdUpbase);
break;
case LcdLpBase:
warn("LCD dual screen mode not supported\n");
lcdLpbase = data;
DPRINTF(PL111, "###### Lower panel base set to: %#x #######\n", lcdLpbase);
break;
case LcdControl:
int old_lcdpwr;
old_lcdpwr = lcdControl.lcdpwr;
lcdControl = data;
switch (daddr) {
case LcdTiming0:
lcdTiming0 = data;
// width = 16 * (PPL+1)
width = (lcdTiming0.ppl + 1) << 4;
DPRINTF(PL111, "LCD power is:%d\n", lcdControl.lcdpwr);
// LCD power enable
if (lcdControl.lcdpwr && !old_lcdpwr) {
updateVideoParams();
DPRINTF(PL111, " lcd size: height %d width %d\n", height, width);
waterMark = lcdControl.watermark ? 8 : 4;
startDma();
}
break;
case LcdImsc:
lcdImsc = data;
if (lcdImsc.vcomp)
panic("Interrupting on vcomp not supported\n");
lcdMis = lcdImsc & lcdRis;
if (!lcdMis)
gic->clearInt(intNum);
break;
case LcdRis:
panic("LCD register at offset %#x is Read-Only\n", daddr);
break;
case LcdMis:
panic("LCD register at offset %#x is Read-Only\n", daddr);
break;
case LcdIcr:
lcdRis = lcdRis & ~data;
lcdMis = lcdImsc & lcdRis;
if (!lcdMis)
gic->clearInt(intNum);
break;
case LcdUpCurr:
panic("LCD register at offset %#x is Read-Only\n", daddr);
break;
case LcdLpCurr:
panic("LCD register at offset %#x is Read-Only\n", daddr);
break;
case ClcdCrsrCtrl:
clcdCrsrCtrl = data;
break;
case ClcdCrsrConfig:
clcdCrsrConfig = data;
break;
case ClcdCrsrPalette0:
clcdCrsrPalette0 = data;
break;
case ClcdCrsrPalette1:
clcdCrsrPalette1 = data;
break;
case ClcdCrsrXY:
clcdCrsrXY = data;
break;
case ClcdCrsrClip:
clcdCrsrClip = data;
break;
case ClcdCrsrImsc:
clcdCrsrImsc = data;
break;
case ClcdCrsrIcr:
clcdCrsrIcr = data;
break;
case ClcdCrsrRis:
panic("CLCD register at offset %#x is Read-Only\n", daddr);
break;
case ClcdCrsrMis:
panic("CLCD register at offset %#x is Read-Only\n", daddr);
break;
default:
if (daddr >= CrsrImage && daddr <= 0xBFC) {
// CURSOR IMAGE
int index;
index = (daddr - CrsrImage) >> 2;
cursorImage[index] = data;
break;
case LcdTiming1:
lcdTiming1 = data;
// height = LPP + 1
height = (lcdTiming1.lpp) + 1;
} else if (daddr >= LcdPalette && daddr <= 0x3FC) {
// LCD Palette
int index;
index = (daddr - LcdPalette) >> 2;
lcdPalette[index] = data;
break;
case LcdTiming2:
lcdTiming2 = data;
break;
case LcdTiming3:
lcdTiming3 = data;
break;
case LcdUpBase:
lcdUpbase = data;
break;
case LcdLpBase:
warn("LCD dual screen mode not supported\n");
lcdLpbase = data;
break;
case LcdControl:
int old_lcdpwr;
old_lcdpwr = lcdControl.lcdpwr;
lcdControl = data;
// LCD power enable
if (lcdControl.lcdpwr&&!old_lcdpwr) {
DPRINTF(PL111, " lcd size: height %d width %d\n", height, width);
waterMark = lcdControl.watermark ? 8 : 4;
readFramebuffer();
}
break;
case LcdImsc:
warn("LCD interrupt mask set/clear not supported\n");
lcdImsc = data;
break;
case LcdRis:
warn("LCD register at offset %#x is Read-Only\n", daddr);
break;
case LcdMis:
warn("LCD register at offset %#x is Read-Only\n", daddr);
break;
case LcdIcr:
warn("LCD interrupt clear not supported\n");
lcdIcr = data;
break;
case LcdUpCurr:
warn("LCD register at offset %#x is Read-Only\n", daddr);
break;
case LcdLpCurr:
warn("LCD register at offset %#x is Read-Only\n", daddr);
break;
case ClcdCrsrCtrl:
clcdCrsrCtrl = data;
break;
case ClcdCrsrConfig:
clcdCrsrConfig = data;
break;
case ClcdCrsrPalette0:
clcdCrsrPalette0 = data;
break;
case ClcdCrsrPalette1:
clcdCrsrPalette1 = data;
break;
case ClcdCrsrXY:
clcdCrsrXY = data;
break;
case ClcdCrsrClip:
clcdCrsrClip = data;
break;
case ClcdCrsrImsc:
clcdCrsrImsc = data;
break;
case ClcdCrsrIcr:
clcdCrsrIcr = data;
break;
case ClcdCrsrRis:
warn("CLCD register at offset %#x is Read-Only\n", daddr);
break;
case ClcdCrsrMis:
warn("CLCD register at offset %#x is Read-Only\n", daddr);
break;
default:
if (daddr >= CrsrImage && daddr <= 0xBFC) {
// CURSOR IMAGE
int index;
index = (daddr - CrsrImage) >> 2;
cursorImage[index] = data;
break;
} else if (daddr >= LcdPalette && daddr <= 0x3FC) {
// LCD Palette
int index;
index = (daddr - LcdPalette) >> 2;
lcdPalette[index] = data;
break;
} else {
panic("Tried to write PL111 register at offset %#x that \
} else {
panic("Tried to write PL111 register at offset %#x that \
doesn't exist\n", daddr);
break;
}
break;
}
}
@ -346,18 +365,76 @@ Pl111::write(PacketPtr pkt)
return pioDelay;
}
void
Pl111::updateVideoParams()
{
if (lcdControl.lcdbpp == bpp24) {
bytesPerPixel = 4;
} else if (lcdControl.lcdbpp == bpp16m565) {
bytesPerPixel = 2;
}
if (vncserver) {
if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr)
vncserver->setFrameBufferParams(VideoConvert::bgr8888, width,
height);
else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr)
vncserver->setFrameBufferParams(VideoConvert::rgb8888, width,
height);
else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr)
vncserver->setFrameBufferParams(VideoConvert::bgr565, width,
height);
else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr)
vncserver->setFrameBufferParams(VideoConvert::rgb565, width,
height);
else
panic("Unimplemented video mode\n");
}
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");
}
void
Pl111::startDma()
{
if (dmaPendingNum != 0 || readEvent.scheduled())
return;
readFramebuffer();
}
void
Pl111::readFramebuffer()
{
// initialization for dma read from frame buffer to dma buffer
uint32_t length = height*width;
if (startAddr != lcdUpbase) {
uint32_t length = height * width;
if (startAddr != lcdUpbase)
startAddr = lcdUpbase;
}
// Updating base address, interrupt if we're supposed to
lcdRis.baseaddr = 1;
if (!intEvent.scheduled())
schedule(intEvent, nextCycle());
curAddr = 0;
startTime = curTick();
maxAddr = static_cast<Addr>(length*sizeof(uint32_t));
dmaPendingNum =0 ;
maxAddr = static_cast<Addr>(length * bytesPerPixel);
DPRINTF(PL111, " lcd frame buffer size of %d bytes \n", maxAddr);
dmaPendingNum = 0;
fillFifo();
}
@ -369,11 +446,16 @@ Pl111::fillFifo()
// concurrent dma reads need different dma done events
// due to assertion in scheduling state
++dmaPendingNum;
DPRINTF(PL111, " ++ DMA pending number %d read addr %#x\n",
dmaPendingNum, curAddr);
assert(!dmaDoneEvent[dmaPendingNum-1].scheduled());
dmaRead(curAddr + startAddr, dmaSize, &dmaDoneEvent[dmaPendingNum-1],
curAddr + dmaBuffer);
// 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, 0,
Request::UNCACHEABLE);
curAddr += dmaSize;
}
}
@ -381,27 +463,34 @@ Pl111::fillFifo()
void
Pl111::dmaDone()
{
Tick maxFrameTime = lcdTiming2.cpl*height*clock;
Tick maxFrameTime = lcdTiming2.cpl * height * clock;
--dmaPendingNum;
DPRINTF(PL111, " -- DMA pending number %d\n", dmaPendingNum);
if (maxAddr == curAddr && !dmaPendingNum) {
if ((curTick() - startTime) > maxFrameTime)
if ((curTick() - startTime) > maxFrameTime) {
warn("CLCD controller buffer underrun, took %d cycles when should"
" have taken %d\n", curTick() - startTime, maxFrameTime);
lcdRis.underflow = 1;
if (!intEvent.scheduled())
schedule(intEvent, nextCycle());
}
// double buffering so the vnc server doesn't see a tear in the screen
memcpy(frameBuffer, dmaBuffer, maxAddr);
assert(!readEvent.scheduled());
if (vncserver)
vncserver->setDirty();
DPRINTF(PL111, "-- write out frame buffer into bmp\n");
writeBMP(frameBuffer);
assert(bmp);
pic->seekp(0);
bmp->write(pic);
DPRINTF(PL111, "-- schedule next dma read event at %d tick \n",
maxFrameTime + curTick());
schedule(readEvent, nextCycle(startTime + maxFrameTime));
if (lcdControl.lcden)
schedule(readEvent, nextCycle(startTime + maxFrameTime));
}
if (dmaPendingNum > (maxOutstandingDma - waterMark))
@ -409,9 +498,9 @@ Pl111::dmaDone()
if (!fillFifoEvent.scheduled())
schedule(fillFifoEvent, nextCycle());
}
Tick
Pl111::nextCycle()
{
@ -431,33 +520,6 @@ Pl111::nextCycle(Tick beginTick)
return nextTick;
}
// write out the frame buffer into a bitmap file
void
Pl111::writeBMP(uint32_t* frameBuffer)
{
fstream pic;
// write out bmp head
std::string filename = "./m5out/frameBuffer.bmp";
pic.open(filename.c_str(), ios::out|ios::binary);
Bitmap bm(pic, height, width);
DPRINTF(PL111, "-- write out data into bmp\n");
// write out frame buffer data
for (int i = height -1; i >= 0; --i) {
for (int j = 0; j< width; ++j) {
uint32_t pixel = frameBuffer[i*width + j];
pic.write(reinterpret_cast<char*>(&pixel),
sizeof(uint32_t));
DPRINTF(PL111, " write pixel data %#x at addr %#x\n",
pixel, i*width + j);
}
}
pic.close();
}
void
Pl111::serialize(std::ostream &os)
{
@ -490,9 +552,6 @@ Pl111::serialize(std::ostream &os)
uint8_t lcdMis_serial = lcdMis;
SERIALIZE_SCALAR(lcdMis_serial);
uint8_t lcdIcr_serial = lcdIcr;
SERIALIZE_SCALAR(lcdIcr_serial);
SERIALIZE_ARRAY(lcdPalette, LcdPaletteSize);
SERIALIZE_ARRAY(cursorImage, CrsrImageSize);
@ -518,9 +577,9 @@ Pl111::serialize(std::ostream &os)
SERIALIZE_SCALAR(clock);
SERIALIZE_SCALAR(height);
SERIALIZE_SCALAR(width);
SERIALIZE_SCALAR(bytesPerPixel);
SERIALIZE_ARRAY(dmaBuffer, height*width);
SERIALIZE_ARRAY(frameBuffer, height*width);
SERIALIZE_ARRAY(dmaBuffer, height * width);
SERIALIZE_SCALAR(startTime);
SERIALIZE_SCALAR(startAddr);
SERIALIZE_SCALAR(maxAddr);
@ -569,10 +628,6 @@ Pl111::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(lcdMis_serial);
lcdMis = lcdMis_serial;
uint8_t lcdIcr_serial;
UNSERIALIZE_SCALAR(lcdIcr_serial);
lcdIcr = lcdIcr_serial;
UNSERIALIZE_ARRAY(lcdPalette, LcdPaletteSize);
UNSERIALIZE_ARRAY(cursorImage, CrsrImageSize);
@ -602,25 +657,29 @@ Pl111::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(clock);
UNSERIALIZE_SCALAR(height);
UNSERIALIZE_SCALAR(width);
UNSERIALIZE_SCALAR(bytesPerPixel);
UNSERIALIZE_ARRAY(dmaBuffer, height*width);
UNSERIALIZE_ARRAY(frameBuffer, height*width);
UNSERIALIZE_ARRAY(dmaBuffer, height * width);
UNSERIALIZE_SCALAR(startTime);
UNSERIALIZE_SCALAR(startAddr);
UNSERIALIZE_SCALAR(maxAddr);
UNSERIALIZE_SCALAR(curAddr);
UNSERIALIZE_SCALAR(waterMark);
UNSERIALIZE_SCALAR(dmaPendingNum);
updateVideoParams();
if (vncserver)
vncserver->setDirty();
}
void
Pl111::generateInterrupt()
{
DPRINTF(PL111, "Generate Interrupt: lcdImsc=0x%x lcdRis=0x%x lcdMis=0x%x\n",
lcdImsc, lcdRis, lcdMis);
(uint32_t)lcdImsc, (uint32_t)lcdRis, (uint32_t)lcdMis);
lcdMis = lcdImsc & lcdRis;
if (lcdMis.ffufie || lcdMis.nbupie || lcdMis.vtcpie || lcdMis.ahmeie) {
if (lcdMis.underflow || lcdMis.baseaddr || lcdMis.vcomp || lcdMis.ahbmaster) {
gic->sendInt(intNum);
DPRINTF(PL111, " -- Generated\n");
}
@ -639,15 +698,4 @@ Pl111Params::create()
return new Pl111(this);
}
// bitmap class ctor
Bitmap::Bitmap(std::fstream& bmp, uint16_t h, uint16_t w)
{
Magic magic = {{'B','M'}};
Header header = {sizeof(Color)*w*h , 0, 0, 54};
Info info = {sizeof(Info), w, h, 1, sizeof(Color)*8, 0,
( sizeof(Color) *(w*h) ), 1, 1, 0, 0};
bmp.write(reinterpret_cast<char*>(&magic), sizeof(magic));
bmp.write(reinterpret_cast<char*>(&header), sizeof(header));
bmp.write(reinterpret_cast<char*>(&info), sizeof(info));
}

View file

@ -35,6 +35,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: William Wang
* Ali Saidi
*/
@ -55,6 +56,8 @@
using namespace std;
class Gic;
class VncServer;
class Bitmap;
class Pl111: public AmbaDmaDevice
{
@ -96,58 +99,69 @@ class Pl111: public AmbaDmaDevice
static const int dmaSize = 8; // 64 bits
static const int maxOutstandingDma = 16; // 16 deep FIFO of 64 bits
enum LcdMode {
bpp1 = 0,
bpp2,
bpp4,
bpp8,
bpp16,
bpp24,
bpp16m565,
bpp12
};
BitUnion8(InterruptReg)
Bitfield<1> ffufie;
Bitfield<2> nbupie;
Bitfield<3> vtcpie;
Bitfield<4> ahmeie;
Bitfield<1> underflow;
Bitfield<2> baseaddr;
Bitfield<3> vcomp;
Bitfield<4> ahbmaster;
EndBitUnion(InterruptReg)
BitUnion32(TimingReg0)
Bitfield<7,2> ppl;
Bitfield<15,8> hsw;
Bitfield<23,16> hfp;
Bitfield<31,24> hbp;
Bitfield<7,2> ppl;
Bitfield<15,8> hsw;
Bitfield<23,16> hfp;
Bitfield<31,24> hbp;
EndBitUnion(TimingReg0)
BitUnion32(TimingReg1)
Bitfield<9,0> lpp;
Bitfield<15,10> vsw;
Bitfield<23,16> vfp;
Bitfield<31,24> vbp;
Bitfield<9,0> lpp;
Bitfield<15,10> vsw;
Bitfield<23,16> vfp;
Bitfield<31,24> vbp;
EndBitUnion(TimingReg1)
BitUnion32(TimingReg2)
Bitfield<4,0> pcdlo;
Bitfield<5> clksel;
Bitfield<10,6> acb;
Bitfield<11> avs;
Bitfield<12> ihs;
Bitfield<13> ipc;
Bitfield<14> ioe;
Bitfield<25,16> cpl;
Bitfield<26> bcd;
Bitfield<31,27> pcdhi;
Bitfield<4,0> pcdlo;
Bitfield<5> clksel;
Bitfield<10,6> acb;
Bitfield<11> avs;
Bitfield<12> ihs;
Bitfield<13> ipc;
Bitfield<14> ioe;
Bitfield<25,16> cpl;
Bitfield<26> bcd;
Bitfield<31,27> pcdhi;
EndBitUnion(TimingReg2)
BitUnion32(TimingReg3)
Bitfield<6,0> led;
Bitfield<16> lee;
Bitfield<6,0> led;
Bitfield<16> lee;
EndBitUnion(TimingReg3)
BitUnion32(ControlReg)
Bitfield<0> lcden;
Bitfield<3,1> lcdbpp;
Bitfield<4> lcdbw;
Bitfield<5> lcdtft;
Bitfield<6> lcdmono8;
Bitfield<7> lcddual;
Bitfield<8> bgr;
Bitfield<9> bebo;
Bitfield<10> bepo;
Bitfield<11> lcdpwr;
Bitfield<13,12> lcdvcomp;
Bitfield<16> watermark;
Bitfield<0> lcden;
Bitfield<3,1> lcdbpp;
Bitfield<4> lcdbw;
Bitfield<5> lcdtft;
Bitfield<6> lcdmono8;
Bitfield<7> lcddual;
Bitfield<8> bgr;
Bitfield<9> bebo;
Bitfield<10> bepo;
Bitfield<11> lcdpwr;
Bitfield<13,12> lcdvcomp;
Bitfield<16> watermark;
EndBitUnion(ControlReg)
/** Horizontal axis panel control register */
@ -180,15 +194,6 @@ class Pl111: public AmbaDmaDevice
/** Masked interrupt status register */
InterruptReg lcdMis;
/** Interrupt clear register */
InterruptReg lcdIcr;
/** Upper panel current address value register - ro */
int lcdUpcurr;
/** Lower panel current address value register - ro */
int lcdLpcurr;
/** 256x16-bit color palette registers
* 256 palette entries organized as 128 locations of two entries per word */
int lcdPalette[LcdPaletteSize];
@ -228,17 +233,26 @@ class Pl111: public AmbaDmaDevice
/** Clock speed */
Tick clock;
/** Frame buffer height - lines per panel */
uint16_t height;
/** VNC server */
VncServer *vncserver;
/** Helper to write out bitmaps */
Bitmap *bmp;
/** Picture of what the current frame buffer looks like */
std::ostream *pic;
/** Frame buffer width - pixels per line */
uint16_t width;
/** CLCDC supports up to 1024x768 */
uint8_t dmaBuffer[LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t)];
/** Frame buffer height - lines per panel */
uint16_t height;
/** Double buffering */
uint32_t frameBuffer[LcdMaxWidth * LcdMaxHeight];
/** Bytes per pixel */
uint8_t bytesPerPixel;
/** CLCDC supports up to 1024x768 */
uint8_t *dmaBuffer;
/** Start time for frame buffer dma read */
Tick startTime;
@ -258,12 +272,12 @@ class Pl111: public AmbaDmaDevice
/** Number of pending dma reads */
int dmaPendingNum;
/** Send updated parameters to the vnc server */
void updateVideoParams();
/** DMA framebuffer read */
void readFramebuffer();
/** Write framebuffer to a bmp file */
void writeBMP(uint32_t*);
/** Generate dma framebuffer read event */
void generateReadEvent();
@ -273,6 +287,9 @@ class Pl111: public AmbaDmaDevice
/** fillFIFO event */
void fillFifo();
/** start the dmas off after power is enabled */
void startDma();
/** DMA done event */
void dmaDone();
@ -289,7 +306,7 @@ class Pl111: public AmbaDmaDevice
/** DMA done event */
vector<EventWrapper<Pl111, &Pl111::dmaDone> > dmaDoneEvent;
/** Wrapper to create an event out of the thing */
/** Wrapper to create an event out of the interrupt */
EventWrapper<Pl111, &Pl111::generateInterrupt> intEvent;
public:
@ -312,57 +329,6 @@ class Pl111: public AmbaDmaDevice
* @param range_list range list to populate with ranges
*/
void addressRanges(AddrRangeList &range_list);
/**
* Return if we have an interrupt pending
* @return interrupt status
* @todo fix me when implementation improves
*/
virtual bool intStatus() { return false; }
};
// write frame buffer into a bitmap picture
class Bitmap
{
public:
Bitmap(std::fstream& bmp, uint16_t h, uint16_t w);
private:
struct Magic
{
unsigned char magic_number[2];
} magic;
struct Header
{
uint32_t size;
uint16_t reserved1;
uint16_t reserved2;
uint32_t offset;
} header;
struct Info
{
uint32_t Size;
uint32_t Width;
uint32_t Height;
uint16_t Planes;
uint16_t BitCount;
uint32_t Compression;
uint32_t SizeImage;
uint32_t XPelsPerMeter;
uint32_t YPelsPerMeter;
uint32_t ClrUsed;
uint32_t ClrImportant;
} info;
struct Color
{
unsigned char b;
unsigned char g;
unsigned char r;
unsigned char a;
} color;
};
#endif

View file

@ -68,6 +68,27 @@ RealViewCtrl::read(PacketPtr pkt)
case Flash:
pkt->set<uint32_t>(0);
break;
case Clcd:
pkt->set<uint32_t>(0x00001F00);
break;
case Osc0:
pkt->set<uint32_t>(0x00012C5C);
break;
case Osc1:
pkt->set<uint32_t>(0x00002CC0);
break;
case Osc2:
pkt->set<uint32_t>(0x00002C75);
break;
case Osc3:
pkt->set<uint32_t>(0x00020211);
break;
case Osc4:
pkt->set<uint32_t>(0x00002C75);
break;
case Lock:
pkt->set<uint32_t>(sysLock);
break;
default:
panic("Tried to read RealView I/O at offset %#x that doesn't exist\n", daddr);
break;
@ -85,6 +106,15 @@ RealViewCtrl::write(PacketPtr pkt)
Addr daddr = pkt->getAddr() - pioAddr;
switch (daddr) {
case Flash:
case Clcd:
case Osc0:
case Osc1:
case Osc2:
case Osc3:
case Osc4:
break;
case Lock:
sysLock.lockVal = pkt->get<uint16_t>();
break;
default:
panic("Tried to write RVIO at offset %#x that doesn't exist\n", daddr);

View file

@ -40,6 +40,7 @@
#ifndef __DEV_ARM_RV_HH__
#define __DEV_ARM_RV_HH__
#include "base/bitunion.hh"
#include "base/range.hh"
#include "dev/io_device.hh"
#include "params/RealViewCtrl.hh"
@ -86,6 +87,14 @@ class RealViewCtrl : public BasicPioDevice
TestOsc4 = 0xD0
};
// system lock value
BitUnion32(SysLockReg)
Bitfield<15,0> lockVal;
Bitfield<16> locked;
EndBitUnion(SysLockReg)
SysLockReg sysLock;
public:
typedef RealViewCtrlParams Params;
const Params *
@ -120,4 +129,3 @@ class RealViewCtrl : public BasicPioDevice
#endif // __DEV_ARM_RV_HH__

200
src/dev/ps2.cc Normal file
View file

@ -0,0 +1,200 @@
/*
* Copyright (c) 2011 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: Ali Saidi
*/
#include <list>
#include "x11keysym/keysym.h"
#include "base/misc.hh"
#include "dev/ps2.hh"
namespace Ps2 {
/** Table to convert simple key symbols (0x00XX) into ps2 bytes. Lower byte
* is the scan code to send and upper byte is if a modifier is required to
* generate it. The table generates us keyboard codes, (e.g. the guest is
* supposed to recognize the keyboard as en_US). A new table would be required
* for another locale.
*/
static const uint16_t keySymToPs2Byte[128] = {
// 0 / 8 1 / 9 2 / A 3 / B 4 / C 5 / D 6 / E 7 / F
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00-0x07
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x08-0x0f
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x10-0x17
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x18-0x1f
0x0029, 0x0116, 0x0152, 0x0126, 0x0125, 0x012e, 0x013d, 0x0052, // 0x20-0x27
0x0146, 0x0145, 0x013e, 0x0155, 0x0041, 0x004e, 0x0049, 0x004a, // 0x28-0x2f
0x0045, 0x0016, 0x001e, 0x0026, 0x0025, 0x002e, 0x0036, 0x003d, // 0x30-0x37
0x003e, 0x0046, 0x014c, 0x004c, 0x0141, 0x0055, 0x0149, 0x014a, // 0x38-0x3f
0x011e, 0x011c, 0x0132, 0x0121, 0x0123, 0x0124, 0x012b, 0x0134, // 0x40-0x47
0x0133, 0x0143, 0x013b, 0x0142, 0x014b, 0x013a, 0x0131, 0x0144, // 0x48-0x4f
0x014d, 0x0115, 0x012d, 0x011b, 0x012c, 0x013c, 0x012a, 0x011d, // 0x50-0x57
0x0122, 0x0135, 0x011a, 0x0054, 0x005d, 0x005b, 0x0136, 0x014e, // 0x58-0x5f
0x000e, 0x001c, 0x0032, 0x0021, 0x0023, 0x0024, 0x002b, 0x0034, // 0x60-0x67
0x0033, 0x0043, 0x003b, 0x0042, 0x004b, 0x003a, 0x0031, 0x0044, // 0x68-0x6f
0x004d, 0x0015, 0x002d, 0x001b, 0x002c, 0x003c, 0x002a, 0x001d, // 0x70-0x77
0x0022, 0x0035, 0x001a, 0x0154, 0x015d, 0x015b, 0x010e, 0x0000 // 0x78-0x7f
};
const uint8_t ShiftKey = 0x12;
const uint8_t BreakKey = 0xf0;
const uint8_t ExtendedKey = 0xe0;
const uint32_t UpperKeys = 0xff00;
void
keySymToPs2(uint32_t key, bool down, bool &cur_shift,
std::list<uint8_t> &keys)
{
if (key <= XK_asciitilde) {
uint16_t tmp = keySymToPs2Byte[key];
uint8_t code = tmp & 0xff;
bool shift = tmp >> 8;
if (down) {
if (!cur_shift && shift) {
keys.push_back(ShiftKey);
cur_shift = true;
}
keys.push_back(code);
} else {
if (cur_shift && !shift) {
keys.push_back(BreakKey);
keys.push_back(ShiftKey);
cur_shift = false;
}
keys.push_back(BreakKey);
keys.push_back(code);
}
} else {
if ((key & UpperKeys) == UpperKeys) {
bool extended = false;
switch (key) {
case XK_BackSpace:
keys.push_back(0x66);
break;
case XK_Tab:
keys.push_back(0x0d);
break;
case XK_Return:
keys.push_back(0x5a);
break;
case XK_Escape:
keys.push_back(0x76);
break;
case XK_Delete:
extended = true;
keys.push_back(0x71);
break;
case XK_Home:
extended = true;
keys.push_back(0x6c);
break;
case XK_Left:
extended = true;
keys.push_back(0x6b);
break;
case XK_Right:
extended = true;
keys.push_back(0x74);
break;
case XK_Down:
extended = true;
keys.push_back(0x72);
break;
case XK_Up:
extended = true;
keys.push_back(0x75);
break;
case XK_Page_Up:
extended = true;
keys.push_back(0x7d);
break;
case XK_Page_Down:
extended = true;
keys.push_back(0x7a);
break;
case XK_End:
extended = true;
keys.push_back(0x69);
break;
case XK_Shift_L:
keys.push_back(0x12);
if (down)
cur_shift = true;
else
cur_shift = false;
break;
case XK_Shift_R:
keys.push_back(0x59);
if (down)
cur_shift = true;
else
cur_shift = false;
break;
case XK_Control_L:
keys.push_back(0x14);
break;
case XK_Control_R:
extended = true;
keys.push_back(0x14);
break;
default:
warn("Unknown extended key %#x\n", key);
return;
}
if (extended) {
if (down) {
keys.push_front(ExtendedKey);
} else {
keys.push_front(BreakKey);
keys.push_front(ExtendedKey);
}
} else {
if (!down)
keys.push_front(BreakKey);
}
} // upper keys
} // extended keys
return;
}
} /* namespace Ps2 */

94
src/dev/ps2.hh Normal file
View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2011 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: Ali Saidi
*/
#ifndef __DEV_PS2_HH__
#define __DEV_PS2_HH__
#include <stdint.h>
#include "base/bitunion.hh"
/** @file misc functions and constants required to interface with or emulate ps2
* devices
*/
namespace Ps2 {
enum {
Ps2Reset = 0xff,
SelfTestPass = 0xAA,
SetStatusLed = 0xed,
SetResolution = 0xe8,
StatusRequest = 0xe9,
SetScaling1_2 = 0xe7,
SetScaling1_1 = 0xe6,
ReadId = 0xf2,
TpReadId = 0xe1,
Ack = 0xfa,
SetRate = 0xf3,
Enable = 0xf4,
Disable = 0xf6,
KeyboardId = 0xab,
TouchKitId = 0x0a,
MouseId = 0x00,
};
/** A bitfield that represents the first byte of a mouse movement packet
*/
BitUnion8(Ps2MouseMovement)
Bitfield<0> leftButton;
Bitfield<1> rightButton;
Bitfield<2> middleButton;
Bitfield<3> one;
Bitfield<4> xSign;
Bitfield<5> ySign;
Bitfield<6> xOverflow;
Bitfield<7> yOverflow;
EndBitUnion(Ps2MouseMovement)
/** Convert an x11 key symbol into a set of ps2 charecters.
* @param key x11 key symbol
* @param down if the key is being pressed or released
* @param cur_shift if device has already sent a shift
* @param keys list of keys command to send to emulate the x11 key symbol
*/
void keySymToPs2(uint32_t key, bool down, bool &cur_shift,
std::list<uint8_t> &keys);
} /* namespace Ps2 */
#endif // __DEV_PS2_HH__