예제 #1
0
class syborg_timer(qemu.devclass):
    REG_ID = 0
    REG_LATCH = 1
    REG_DATA_LOW = 2
    REG_DATA_HIGH = 3

    def create(self):
        self.data = 0
        self.offset = qemu.start_time() * 1000000 - qemu.get_clock()

    def read_reg(self, offset):
        offset >>= 2
        if offset == self.REG_ID:
            return 0xc51d0004
        elif offset == self.REG_DATA_LOW:
            return self.data & 0xffffffff
        elif offset == self.REG_DATA_HIGH:
            return (self.data >> 32) & 0xffffffff
        return 0

    def write_reg(self, offset, value):
        offset >>= 2
        if offset == self.REG_LATCH:
            now = qemu.get_clock()
            if value >= 4:
                self.offset = self.data - now
            else:
                self.data = now + self.offset
                while value:
                    self.data /= 1000
                    value -= 1
        elif offset == self.REG_DATA_LOW:
            self.data = (self.data & ~0xffffffff) | value
        elif offset == self.REG_DATA_HIGH:
            self.data = (self.data & 0xffffffff) | (value << 32)

    def save(self, f):
        f.put_s64(self.offset)
        f.put_u64(self.data)

    def load(self, f):
        self.offset = f.get_s64()
        self.data = f.get_u64()

    # Device class properties
    regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
    irqs = 0
    name = "syborg,rtc"
    properties = {}
                if( self.transaction_direction == self.NVMEM_TRANSACTION_READ ):
                    self.nvmemlib.nvmem_read(  self.obj, self.nvmemory_sharedmemory_host_address, self.nvmemhandle, self.transaction_offset, self.transaction_size )
                elif( self.transaction_direction == self.NVMEM_TRANSACTION_WRITE ):
                    self.nvmemlib.nvmem_write(  self.obj, self.nvmemory_sharedmemory_host_address, self.nvmemhandle, self.transaction_offset, self.transaction_size )
                else:
                    error_msg = "syborg_nvmemorydevice: Transaction direction not set!" 
                    sys.exit( error_msg )
                self.transaction_offset_set = 0
                self.transaction_size_set = 0
                self.transaction_direction_set = 0
        elif offset == self.R_NVMEM_SHARED_MEMORY_BASE:
            self.shared_memory_base = value
        elif offset == self.R_NVMEM_SHARED_MEMORY_SIZE:
            self.shared_memory_size = value
        elif offset == self.R_NVMEM_ENABLE:
            if( value > 0 ):
                self.nvmemory_memregion = qemu.memregion( self.shared_memory_base, self.shared_memory_size )
                self.nvmemory_sharedmemory_host_address = self.nvmemory_memregion.region_host_addr()
                print"syborg_nvmemorydevice: host addr: 0x%08x" % (self.nvmemory_sharedmemory_host_address)
        else:
            reg_write_error = "syborg_nvmemorydevice: Illegal register write to: ", offset 
            sys.exit( reg_write_error )

    # Device class properties
    regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
    irqs = 1
    name = "syborg,nvmemorydevice"
    properties = {"drive_size":DEFAULT_DRIVE_SIZE, "sector_size":DEVICE_SECTOR_SIZE, "drive_image_name":DRIVE_NAME}

qemu.register_device(syborg_nvmemorydevice)
class syborg_usbtest(qemu.devclass):
    REG_ID = 0
    REG_INT_ENABLE = 1
    REG_DATA_TYPE = 2
    REG_DMA_ADDR = 3
    REG_DMA_SIZE = 4

    def loadIMG(self):
        self.buf = open('test1.BMP', 'rb').read()
        self.bufC = open('test.BMP', 'rb').read()
        self.bmpsize = os.path.getsize('test1.BMP')
        self.Csize = os.path.getsize('test.BMP')

    def timertick(self):
        if self.cha == 0:
            compSize = self.bmpsize
            buf = self.buf
            self.cha = 1
        else:
            compSize = self.Csize
            buf = self.bufC
            self.cha = 0
        if self.dma_size < compSize:
            self.dma_size = 0
        else:
            for x in buf:
                ch = ord(x)
                if self.dma_size > 0:
                    self.dma_writeb(self.dma_addr, ch)
                    self.dma_addr += 1
                    self.dma_size -= 1
        self.set_irq_level(0, self.int_enable)

    def timer_on(self):
        self.ptimer = qemu.ptimer(self.timertick, 1)
        self.ptimer.run(0)

    def timer_off(self):
        self.ptimer.stop()
        self.set_irq_level(0, self.int_enable)

    def capturedata(self):
        if self.dma_size < self.Csize:
            self.dma_size = 0
        else:
            for x in self.bufC:
                ch = ord(x)
                if self.dma_size > 0:
                    self.dma_writeb(self.dma_addr, ch)
                    self.dma_addr += 1
                    self.dma_size -= 1
        self.set_irq_level(0, self.int_enable)

    def create(self):
        self.int_enable = 1
        self.dma_addr = 0
        self.dma_size = 0
        self.cha = 0
        self.loadIMG()

    def write_reg(self, offset, value):
        offset >>= 2
        if offset == self.REG_INT_ENABLE:
            self.int_enable = value
            if value == 1:
                if self.data_type == 0:
                    self.timer_on()
                elif self.data_type == 1:
                    self.capturedata()
            else:
                if self.data_type == 0:
                    self.timer_off()
                elif self.data_type == 1:
                    self.set_irq_level(0, self.int_enable)
        elif offset == self.REG_DATA_TYPE:
            self.data_type = value
        elif offset == self.REG_DMA_ADDR:
            self.dma_addr = value
        elif offset == self.REG_DMA_SIZE:
            self.dma_size = value

    def read_reg(self, offset):
        offset >>= 2
        if offset == self.REG_ID:
            return 0xc600f000
        elif offset == self.REG_INT_ENABLE:
            return self.int_enable
        elif offset == self.REG_DMA_ADDR:
            return self.dma_addr
        elif offset == self.REG_DMA_SIZE:
            return self.dma_size
        return 0

    def save(self, f):
        f.put_u32(self.int_enable)
        f.put_u32(self.dma_addr)
        f.put_u32(self.dma_size)

    def load(self, f):
        self.int_enable = f.get_u32()
        self.dma_addr = f.get_u32()
        self.dma_size = f.get_u32()

    # Device class properties
    regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
    irqs = 1
    name = "syborg,usbtest"
    properties = {"chardev": None}
예제 #4
0
class syborg_interrupt(qemu.devclass):
  REG_ID            = 0
  REG_STATUS        = 1
  REG_CURRENT       = 2
  REG_DISABLE_ALL   = 3
  REG_DISABLE       = 4
  REG_ENABLE        = 5
  REG_TOTAL         = 6

  def update(self):
    self.pending = self.level & self.enabled
    self.set_irq_level(0, len(self.pending) > 0)

  def set_input(self, n, level):
    if level:
      if n in self.level:
        return
      self.level.add(n)
    else:
      if n not in self.level:
        return
      self.level.discard(n)
    self.update()

  def create(self):
    self.num_inputs = self.properties["num-interrupts"]
    self.enabled = set()
    self.level = set()
    self.pending = set()
    self.create_interrupts(self.set_input, self.num_inputs)

  def read_reg(self, offset):
    offset >>= 2
    if offset == self.REG_ID:
      return 0xc51d0000
    elif offset == self.REG_STATUS:
      return len(self.pending)
    elif offset == self.REG_CURRENT:
      for i in range(self.num_inputs):
        if i in self.pending:
          return i
      return 0xffffffff
    elif offset == self.REG_TOTAL:
      return self.num_inputs
    return 0

  def write_reg(self, offset, value):
    offset >>= 2
    if offset == self.REG_DISABLE_ALL:
      self.enabled = set()
    elif offset == self.REG_DISABLE:
      if (value < self.num_inputs):
        self.enabled.discard(value)
    elif offset == self.REG_ENABLE:
      if (value < self.num_inputs):
        self.enabled.add(value)
    self.update()

  def save(self, f):
    f.put_u32(self.num_inputs)
    for i in range(self.num_inputs):
      val = 0
      if i in self.enabled:
        val |= 1
      if i in self.level:
        val |= 2
      f.put_u32(val)

  def load(self, f):
    val = f.get_u32()
    if val != self.num_inputs:
      raise ValueError, "Incorrect number of IRQs"
    self.level = set()
    self.enabled = set()
    for i in range(self.num_inputs):
      val = f.get_u32()
      if (val & 1) != 0:
        self.enabled.add(i)
      if (val & 2) != 0:
        self.level.add(i)
    self.update()

  # Device class properties
  regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
  irqs = 1
  name = "syborg,interrupt"
  properties = {"num-interrupts":64}
예제 #5
0
class syborg_pointer(qemu.devclass):
    REG_ID = 0
    REG_LATCH = 1
    REG_FIFO_COUNT = 2
    REG_X = 3
    REG_Y = 4
    REG_Z = 5
    REG_BUTTONS = 6
    REG_INT_ENABLE = 7
    REG_FIFO_SIZE = 8

    class fifo_entry:
        def __init__(self, x, y, z, buttons):
            self.x = x
            self.y = y
            self.z = z
            self.buttons = buttons

    def update_irq(self):
        self.set_irq_level(0, (len(self.fifo) > 0) and self.int_enabled)

    def event(self, x, y, z, buttons):
        if len(self.fifo) < self.fifo_size:
            self.fifo.append(self.fifo_entry(x, y, z, buttons))
        self.update_irq()

    def create(self):
        self.absolute = self.properties["absolute"]
        self.fifo_size = self.properties["fifo-size"]
        self.fifo = []
        self.current = self.fifo_entry(0, 0, 0, 0)
        self.int_enabled = False
        qemu.register_mouse(self.event, self.absolute, self.name)

    def read_reg(self, offset):
        offset >>= 2
        if offset == self.REG_ID:
            return 0xc51d0006 if self.absolute else 0xc51d0005
        elif offset == self.REG_FIFO_COUNT:
            return len(self.fifo)
        elif offset == self.REG_X:
            return self.current.x
        elif offset == self.REG_Y:
            return self.current.y
        elif offset == self.REG_Z:
            return self.current.z
        elif offset == self.REG_BUTTONS:
            return self.current.buttons
        elif offset == self.REG_INT_ENABLE:
            return self.int_enabled
        elif offset == self.REG_FIFO_SIZE:
            return self.fifo_size
        return 0

    def write_reg(self, offset, value):
        offset >>= 2
        if offset == self.REG_LATCH:
            if len(self.fifo) == 0:
                return
            self.current = self.fifo.pop(0)
            self.update_irq()
        elif offset == self.REG_INT_ENABLE:
            self.int_enabled = ((value & 1) != 0)
            self.update_irq()

    def save(self, f):
        f.put_u32(self.fifo_size)
        f.put_u32(self.int_enabled)
        f.put_u32(len(self.fifo) + 1)
        for d in [self.current] + self.fifo:
            f.put_u32(d.x)
            f.put_u32(d.y)
            f.put_u32(d.z)
            f.put_u32(d.buttons)

    def load(self, f):
        if self.fifo_size != f.get_u32():
            raise ValueError, "fifo size mismatch"
        self.int_enabled = f.get_u32()
        n = f.get_u32()
        self.fifo = []
        while n > 0:
            x = f.get_u32()
            y = f.get_u32()
            z = f.get_u32()
            buttons = f.get_u32()
            self.fifo.append(self.fifo_entry(x, y, z, buttons))
            n -= 1
        self.current = self.fifo.pop(0)

    # Device class properties
    regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
    irqs = 1
    name = "syborg,pointer"
    properties = {"fifo-size": 16, "absolute": 1}
                if( self.transaction_direction == self.NVMEM_TRANSACTION_READ ):
                    self.nvmemlib.nvmem_read(  self.obj, self.nvmemory_sharedmemory_host_address, self.nvmemhandle, self.transaction_offset, self.transaction_size )
                elif( self.transaction_direction == self.NVMEM_TRANSACTION_WRITE ):
                    self.nvmemlib.nvmem_write(  self.obj, self.nvmemory_sharedmemory_host_address, self.nvmemhandle, self.transaction_offset, self.transaction_size )
                else:
                    error_msg = "syborg_nvmemorydevice: Transaction direction not set!" 
                    sys.exit( error_msg )
                self.transaction_offset_set = 0
                self.transaction_size_set = 0
                self.transaction_direction_set = 0
        elif offset == self.R_NVMEM_SHARED_MEMORY_BASE:
            self.shared_memory_base = value
        elif offset == self.R_NVMEM_SHARED_MEMORY_SIZE:
            self.shared_memory_size = value
        elif offset == self.R_NVMEM_ENABLE:
            if( value > 0 ):
                self.nvmemory_memregion = qemu.memregion( self.shared_memory_base, self.shared_memory_size )
                self.nvmemory_sharedmemory_host_address = self.nvmemory_memregion.region_host_addr()
                print"syborg_nvmemorydevice: host addr: 0x%08x" % (self.nvmemory_sharedmemory_host_address)
        else:
            reg_write_error = "syborg_nvmemorydevice: Illegal register write to: ", offset 
            sys.exit( reg_write_error )

    # Device class properties
    regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
    irqs = 1
    name = "syborg,nvmemorydevice"
    properties = {"drive_size":DEFAULT_DRIVE_SIZE, "sector_size":DEVICE_SECTOR_SIZE, "drive_image_name":DRIVE_NAME}

qemu.register_device(syborg_nvmemorydevice)
예제 #7
0
class syborg_timer(qemu.devclass):
    REG_ID = 0
    REG_RUNNING = 1
    REG_ONESHOT = 2
    REG_LIMIT = 3
    REG_VALUE = 4
    REG_INT_ENABLE = 5
    REG_INT_STATUS = 6
    REG_FREQ = 7

    def update(self):
        self.set_irq_level(0, (self.int_status & self.int_enable) != 0)

    def timer_tick(self):
        self.int_status |= 1
        if (self.oneshot):
            self.running = False
        self.update()

    def create(self):
        self.freq = self.properties["frequency"]
        if self.freq == 0:
            raise ValueError, "Zero/unset frequency"
        self.timer = qemu.ptimer(self.timer_tick, self.freq)
        self.running = False
        self.oneshot = False
        self.int_status = 0
        self.int_enable = 0
        self.limit = 0

    def read_reg(self, offset):
        offset >>= 2
        if offset == self.REG_ID:
            return 0xc51d0003
        elif offset == self.REG_RUNNING:
            return 1 if self.running else 0
        elif offset == self.REG_ONESHOT:
            return 1 if self.oneshot else 0
        elif offset == self.REG_LIMIT:
            return self.limit
        elif offset == self.REG_VALUE:
            return self.timer.count
        elif offset == self.REG_INT_ENABLE:
            return self.int_enable
        elif offset == self.REG_INT_STATUS:
            return self.int_status
        elif offset == self.REG_FREQ:
            return self.freq
        return 0

    def write_reg(self, offset, value):
        offset >>= 2
        if offset == self.REG_RUNNING:
            if self.running != (value != 0):
                self.running = (value != 0)
                if self.running:
                    self.timer.run(self.oneshot)
                else:
                    self.timer.stop()
        elif offset == self.REG_ONESHOT:
            if self.running:
                self.timer.stop()
            self.oneshot = (value != 0)
            if self.running:
                self.timer.run(self.oneshot)
        elif offset == self.REG_LIMIT:
            self.limit = value
            self.timer.set_limit(value, True)
        elif offset == self.REG_VALUE:
            self.timer.count = value
        elif offset == self.REG_INT_ENABLE:
            self.int_enable = value & 1
            self.update()
        elif offset == self.REG_INT_STATUS:
            self.int_status &= ~value
            self.update()

    def save(self, f):
        f.put_u32(self.running)
        f.put_u32(self.oneshot)
        f.put_u32(self.limit)
        f.put_u32(self.int_status)
        f.put_u32(self.int_enable)
        self.timer.put(f)

    def load(self, f):
        self.running = (f.get_u32() != 0)
        self.oneshot = (f.get_u32() != 0)
        self.limit = f.get_u32()
        self.int_status = f.get_u32()
        self.int_enable = f.get_u32()
        self.timer.get(f)

    # Device class properties
    regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
    irqs = 1
    name = "syborg,timer"
    properties = {"frequency": 0}
class syborg_keyboard(qemu.devclass):
    REG_ID = 0
    REG_DATA = 1
    REG_FIFO_COUNT = 2
    REG_INT_ENABLE = 3
    REG_FIFO_SIZE = 4

    def update_irq(self):
        self.set_irq_level(0, (len(self.fifo) > 0) and self.int_enabled)

    def event(self, keycode):
        if (keycode == 0xe0) and not self.extension_bit:
            self.extension_bit = 0x80
            return
        val = (keycode & 0x7f) | self.extension_bit
        if (keycode & 0x80) != 0:
            val |= 0x80000000
        self.extension_bit = 0
        if len(self.fifo) < self.fifo_size:
            self.fifo.append(val)
        self.update_irq()

    def create(self):
        self.fifo_size = self.properties["fifo-size"]
        self.fifo = []
        self.int_enabled = False
        self.extension_bit = 0
        qemu.register_keyboard(self.event)

    def read_reg(self, offset):
        offset >>= 2
        if offset == self.REG_ID:
            return 0xc51d0002
        elif offset == self.REG_DATA:
            if len(self.fifo) == 0:
                return 0xffffffff
            val = self.fifo.pop(0)
            self.update_irq()
            return val
        elif offset == self.REG_FIFO_COUNT:
            return len(self.fifo)
        elif offset == self.REG_INT_ENABLE:
            return self.int_enabled
        elif offset == self.REG_FIFO_SIZE:
            return self.fifo_size
        return 0

    def write_reg(self, offset, value):
        offset >>= 2
        if offset == self.REG_INT_ENABLE:
            self.int_enabled = ((value & 1) != 0)
            self.update_irq()

    def save(self, f):
        f.put_u32(self.fifo_size)
        f.put_u32(self.int_enabled)
        f.put_u32(self.extension_bit)
        f.put_u32(len(self.fifo))
        for x in self.fifo:
            f.put_u32(x)

    def load(self, f):
        if self.fifo_size != f.get_u32():
            raise ValueError, "fifo size mismatch"
        self.int_enabled = f.get_u32()
        self.extension_bit = f.get_u32()
        n = f.get_u32()
        self.fifo = []
        while n > 0:
            self.fifo.append(f.get_u32())
            n -= 1

    # Device class properties
    regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
    irqs = 1
    name = "syborg,keyboard"
    properties = {"fifo-size": 16}
예제 #9
0
class syborg_serial(qemu.devclass):
    REG_ID = 0
    REG_DATA = 1
    REG_FIFO_COUNT = 2
    REG_INT_ENABLE = 3
    REG_DMA_TX_ADDR = 4
    REG_DMA_TX_COUNT = 5  # triggers dma
    REG_DMA_RX_ADDR = 6
    REG_DMA_RX_COUNT = 7  # triggers dma

    def update_irq(self):
        level = 2  # TX DMA complete
        if len(self.fifo) > 0:
            level |= 1  # FIFO not empty
        if self.dma_rx_count == 0:
            level |= 4  # RX DMA complete
        self.set_irq_level(0, (level & self.int_enable) != 0)

    def can_receive(self):
        return self.fifo_size - len(self.fifo)

    def receive(self, buf):
        for x in buf:
            ch = ord(x)
            if self.dma_rx_count > 0:
                self.dma_writeb(self.dma_rx_addr, ch)
                self.dma_rx_addr += 1
                self.dma_rx_count -= 1
            else:
                self.fifo.append(ch)
        self.update_irq()

    def do_dma_tx(self, count):
        # TODO: Optimize block transmits.
        while count > 0:
            ch = self.dma_readb(self.dma_tx_addr)
            self.chardev.write(ch)
            self.dma_tx_addr += 1
            count -= 1
        self.update_irq()

    def dma_rx_start(self, count):
        while (count > 0) and (len(self.fifo) > 0):
            ch = self.fifo.pop(0)
            self.dma_writeb(self.dma_rx_addr, ch)
            self.dma_rx_addr += 1
            count -= 1
        self.dma_rx_count = count
        self.update_irq()

    def create(self):
        self.fifo_size = self.properties["fifo-size"]
        self.chardev = self.properties["chardev"]
        self.fifo = []
        self.int_enable = 0
        self.chardev.set_handlers(self.can_receive, self.receive)
        self.dma_tx_addr = 0
        self.dma_rx_addr = 0
        self.dma_rx_count = 0

    def read_reg(self, offset):
        offset >>= 2
        if offset == self.REG_ID:
            return 0xc51d0001
        elif offset == self.REG_DATA:
            if len(self.fifo) == 0:
                return 0xffffffff
            val = self.fifo.pop(0)
            self.update_irq()
            return val
        elif offset == self.REG_FIFO_COUNT:
            return len(self.fifo)
        elif offset == self.REG_INT_ENABLE:
            return self.int_enable
        elif offset == self.REG_DMA_TX_ADDR:
            return self.dma_tx_addr
        elif offset == self.REG_DMA_TX_COUNT:
            return 0
        elif offset == self.REG_DMA_RX_ADDR:
            return self.dma_rx_addr
        elif offset == self.REG_DMA_RX_COUNT:
            return self.dma_rx_count
        return 0

    def write_reg(self, offset, value):
        offset >>= 2
        if offset == self.REG_DATA:
            self.chardev.write(value)
        elif offset == self.REG_INT_ENABLE:
            self.int_enable = value & 7
            self.update_irq()
        elif offset == self.REG_DMA_TX_ADDR:
            self.dma_tx_addr = value
        elif offset == self.REG_DMA_TX_COUNT:
            self.do_dma_tx(value)
        elif offset == self.REG_DMA_RX_ADDR:
            self.dma_rx_addr = value
        elif offset == self.REG_DMA_RX_COUNT:
            self.dma_rx_start(value)

    def save(self, f):
        f.put_u32(self.fifo_size)
        f.put_u32(self.int_enable)
        f.put_u32(self.dma_tx_addr)
        f.put_u32(self.dma_rx_addr)
        f.put_u32(self.dma_rx_count)
        f.put_u32(len(self.fifo))
        for x in self.fifo:
            f.put_u32(x)

    def load(self, f):
        if self.fifo_size != f.get_u32():
            raise ValueError, "fifo size mismatch"
        self.int_enable = f.get_u32()
        self.dma_tx_addr = f.get_u32()
        self.dma_rx_addr = f.get_u32()
        self.dma_rx_count = f.get_u32()
        n = f.get_u32()
        self.fifo = []
        while n > 0:
            self.fifo.append(f.get_u32())
            n -= 1

    # Device class properties
    regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
    irqs = 1
    name = "syborg,serial"
    properties = {"fifo-size": 16, "chardev": None, "target": ""}
예제 #10
0
class syborg_fb(qemu.devclass):
  REG_ID            = 0
  REG_BASE          = 1
  REG_HEIGHT        = 2
  REG_WIDTH         = 3
  REG_ORIENTATION   = 4
  REG_BLANK         = 5
  REG_INT_MASK      = 6
  REG_INT_CAUSE     = 7
  REG_BPP           = 8
  REG_COLOR_ORDER   = 9
  REG_BYTE_ORDER    = 10
  REG_PIXEL_ORDER   = 11
  REG_ROW_PITCH     = 12
  REG_ENABLED       = 13
  REG_PALETTE       = 0x100

  INT_VSYNC         = (1 << 0)
  INT_BASE_UPDATE   = (1 << 1)

  def update_irq(self):
    self.set_irq_level(0, (self.int_status & self.int_enable) != 0)

  def do_update(self):
    old_status = self.int_status
    if self.need_int:
      self.int_status |= self.INT_BASE_UPDATE
      self.need_int = False
    if self.render.blank == 0:
      self.int_status |= self.INT_VSYNC
    if self.int_status != old_status:
      self.update_irq()
    return self.enabled

  def create(self):
    self.enabled = False
    self.int_status = 0
    self.int_enable = 0
    self.need_int = True

    width = self.properties["width"]
    height = self.properties["height"]
    self.render = qemu.render(self.name, width, height)
    self.render.update = self.do_update

  def read_reg(self, offset):
    offset >>= 2
    if offset == self.REG_ID:
      return 0xc51d0006
    elif offset == self.REG_BASE:
      return self.render.base;
    elif offset == self.REG_WIDTH:
      return self.render.width;
    elif offset == self.REG_HEIGHT:
      return self.render.height;
    elif offset == self.REG_ORIENTATION:
      return self.render.orientation;
    elif offset == self.REG_BLANK:
      return self.render.blank;
    elif offset == self.REG_INT_MASK:
      return self.int_enable;
    elif offset == self.REG_INT_CAUSE:
      return self.int_status;
    elif offset == self.REG_BPP:
      return self.render.bpp;
    elif offset == self.REG_COLOR_ORDER:
      return self.render.color_order;
    elif offset == self.REG_BYTE_ORDER:
      return self.render.byte_order;
    elif offset == self.REG_PIXEL_ORDER:
      return self.render.pixel_order;
    elif offset == self.REG_ROW_PITCH:
      return self.render.row_pitch;
    elif offset == self.REG_ENABLED:
      return 1 if self.enabled else 0;
    elif (offset >= self.REG_PALETTE) and (offset < self.REG_PALETTE + 256):
      return self.render.palette[offset - self.REG_PALETTE];
    return 0

  def write_reg(self, offset, value):
    offset >>= 2
    if offset == self.REG_BASE:
      self.render.base = value;
      self.need_int = True
    elif offset == self.REG_WIDTH:
      self.render.width = value;
    elif offset == self.REG_HEIGHT:
      self.render.height = value;
    elif offset == self.REG_ORIENTATION:
      self.render.orientation = value;
    elif offset == self.REG_BLANK:
      self.render.blank = value;
    elif offset == self.REG_INT_CAUSE:
      self.int_status &= ~value;
      self.update_irq()
    elif offset == self.REG_INT_MASK:
      self.int_enable = value & 3;
      self.update_irq()
    elif offset == self.REG_BPP:
      self.render.bpp = value;
    elif offset == self.REG_COLOR_ORDER:
      self.render.color_order = value;
    elif offset == self.REG_BYTE_ORDER:
      self.render.byte_order = value;
    elif offset == self.REG_PIXEL_ORDER:
      self.render.pixel_order = value;
    elif offset == self.REG_ROW_PITCH:
      self.render.row_pitch = value;
    elif offset == self.REG_ENABLED:
      self.enabled = value != 0;
    elif (offset >= self.REG_PALETTE) and (offset < self.REG_PALETTE + 256):
      self.render.palette[offset - self.REG_PALETTE] = value;

  def save(self, f):
    f.put_u32(1 if self.need_int else 0)
    f.put_u32(self.int_status)
    f.put_u32(self.int_enable)
    f.put_u32(1 if self.enabled else 0)
    self.render.put(f)

  def load(self, f):
    self.need_int = (f.get_u32() != 0)
    self.int_status = f.get_u32();
    self.int_enable = f.get_u32();
    self.enabled = (f.get_u32() != 0)
    self.render.get(f)

  # Device class properties
  regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
  irqs = 1
  name = "syborg,framebuffer"
  properties = {"width":0, "height":0}