Patchwork [18/18] tcx: convert to memory API

login
register
mail settings
Submitter Avi Kivity
Date Oct. 17, 2011, 2:02 p.m.
Message ID <1318860167-14014-19-git-send-email-avi@redhat.com>
Download mbox | patch
Permalink /patch/120229/
State New
Headers show

Comments

Avi Kivity - Oct. 17, 2011, 2:02 p.m.
Signed-off-by: Avi Kivity <avi@redhat.com>
---
 hw/tcx.c |  152 ++++++++++++++++++++++++++++++++++---------------------------
 1 files changed, 85 insertions(+), 67 deletions(-)
Blue Swirl - Oct. 17, 2011, 7:13 p.m.
On Mon, Oct 17, 2011 at 2:02 PM, Avi Kivity <avi@redhat.com> wrote:
> Signed-off-by: Avi Kivity <avi@redhat.com>
> ---
>  hw/tcx.c |  152 ++++++++++++++++++++++++++++++++++---------------------------
>  1 files changed, 85 insertions(+), 67 deletions(-)
>
> diff --git a/hw/tcx.c b/hw/tcx.c
> index 309600d..cd24100 100644
> --- a/hw/tcx.c
> +++ b/hw/tcx.c
> @@ -40,7 +40,15 @@
>     DisplayState *ds;
>     uint8_t *vram;
>     uint32_t *vram24, *cplane;
> -    ram_addr_t vram_offset, vram24_offset, cplane_offset;
> +    MemoryRegion vram_mem;
> +    MemoryRegion vram_8bit;
> +    MemoryRegion vram_24bit;
> +    MemoryRegion vram_cplane;
> +    MemoryRegion dac;
> +    MemoryRegion tec;
> +    MemoryRegion thc24;
> +    MemoryRegion thc8;
> +    ram_addr_t vram24_offset, cplane_offset;
>     uint32_t vram_size;
>     uint32_t palette[256];
>     uint8_t r[256], g[256], b[256];
> @@ -56,7 +64,7 @@ static void tcx_set_dirty(TCXState *s)
>     unsigned int i;
>
>     for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
> -        cpu_physical_memory_set_dirty(s->vram_offset + i);
> +        memory_region_set_dirty(&s->vram_mem, i);
>     }
>  }
>
> @@ -65,8 +73,8 @@ static void tcx24_set_dirty(TCXState *s)
>     unsigned int i;
>
>     for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
> -        cpu_physical_memory_set_dirty(s->vram24_offset + i);
> -        cpu_physical_memory_set_dirty(s->cplane_offset + i);
> +        memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i);
> +        memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i);
>     }
>  }
>
> @@ -174,16 +182,18 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
>     }
>  }
>
> -static inline int check_dirty(ram_addr_t page, ram_addr_t page24,
> +static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
>                               ram_addr_t cpage)
>  {
>     int ret;
>     unsigned int off;
>
> -    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
> +    ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
>     for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
> -        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
> -        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
> +        ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
> +                                       DIRTY_MEMORY_VGA);
> +        ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
> +                                       DIRTY_MEMORY_VGA);

Like memory_region_set_dirty(), this should be changed to take a range
so that the for loops and PAGE_SIZEs can be dropped.

>     }
>     return ret;
>  }
> @@ -192,16 +202,17 @@ static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
>                                ram_addr_t page_max, ram_addr_t page24,
>                               ram_addr_t cpage)
>  {
> -    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
> -                                    VGA_DIRTY_FLAG);
> -    page_min -= ts->vram_offset;
> -    page_max -= ts->vram_offset;
> -    cpu_physical_memory_reset_dirty(page24 + page_min * 4,
> -                                    page24 + page_max * 4 + TARGET_PAGE_SIZE,
> -                                    VGA_DIRTY_FLAG);
> -    cpu_physical_memory_reset_dirty(cpage + page_min * 4,
> -                                    cpage + page_max * 4 + TARGET_PAGE_SIZE,
> -                                    VGA_DIRTY_FLAG);
> +    memory_region_reset_dirty(&ts->vram_mem,
> +                              page_min, page_max + TARGET_PAGE_SIZE,
> +                              DIRTY_MEMORY_VGA);
> +    memory_region_reset_dirty(&ts->vram_mem,
> +                              page24 + page_min * 4,
> +                              page24 + page_max * 4 + TARGET_PAGE_SIZE,
> +                              DIRTY_MEMORY_VGA);
> +    memory_region_reset_dirty(&ts->vram_mem,
> +                              cpage + page_min * 4,
> +                              cpage + page_max * 4 + TARGET_PAGE_SIZE,
> +                              DIRTY_MEMORY_VGA);
>  }
>
>  /* Fixed line length 1024 allows us to do nice tricks not possible on
> @@ -216,7 +227,7 @@ static void tcx_update_display(void *opaque)
>
>     if (ds_get_bits_per_pixel(ts->ds) == 0)
>         return;
> -    page = ts->vram_offset;
> +    page = 0;
>     y_start = -1;
>     page_min = -1;
>     page_max = 0;
> @@ -242,7 +253,7 @@ static void tcx_update_display(void *opaque)
>     }
>
>     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
> -        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
> +        if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
>             if (y_start < 0)
>                 y_start = y;
>             if (page < page_min)
> @@ -279,8 +290,9 @@ static void tcx_update_display(void *opaque)
>     }
>     /* reset modified pages */
>     if (page_max >= page_min) {
> -        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
> -                                        VGA_DIRTY_FLAG);
> +        memory_region_reset_dirty(&ts->vram_mem,
> +                                  page_min, page_max + TARGET_PAGE_SIZE,
> +                                  DIRTY_MEMORY_VGA);
>     }
>  }
>
> @@ -294,7 +306,7 @@ static void tcx24_update_display(void *opaque)
>
>     if (ds_get_bits_per_pixel(ts->ds) != 32)
>             return;
> -    page = ts->vram_offset;
> +    page = 0;
>     page24 = ts->vram24_offset;
>     cpage = ts->cplane_offset;
>     y_start = -1;
> @@ -309,7 +321,7 @@ static void tcx24_update_display(void *opaque)
>
>     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
>             page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
> -        if (check_dirty(page, page24, cpage)) {
> +        if (check_dirty(ts, page, page24, cpage)) {
>             if (y_start < 0)
>                 y_start = y;
>             if (page < page_min)
> @@ -421,18 +433,20 @@ static void tcx_reset(DeviceState *d)
>     s->r[255] = s->g[255] = s->b[255] = 255;
>     update_palette_entries(s, 0, 256);
>     memset(s->vram, 0, MAXX*MAXY);
> -    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
> -                                    MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
> +    memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
> +                              DIRTY_MEMORY_VGA);
>     s->dac_index = 0;
>     s->dac_state = 0;
>  }
>
> -static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
> +static uint64_t tcx_dac_readl(void *opaque, target_phys_addr_t addr,
> +                              unsigned size)
>  {
>     return 0;
>  }
>
> -static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
> +static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val,
> +                           unsigned size)
>  {
>     TCXState *s = opaque;
>
> @@ -468,77 +482,77 @@ static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
>     return;
>  }
>
> -static CPUReadMemoryFunc * const tcx_dac_read[3] = {
> -    NULL,
> -    NULL,
> -    tcx_dac_readl,
> +static const MemoryRegionOps tcx_dac_ops = {
> +    .read = tcx_dac_readl,
> +    .write = tcx_dac_writel,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
>  };
>
> -static CPUWriteMemoryFunc * const tcx_dac_write[3] = {
> -    NULL,
> -    NULL,
> -    tcx_dac_writel,
> -};
> -
> -static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
> +static uint64_t dummy_readl(void *opaque, target_phys_addr_t addr,
> +                            unsigned size)
>  {
>     return 0;
>  }
>
> -static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
> -                             uint32_t val)
> +static void dummy_writel(void *opaque, target_phys_addr_t addr,
> +                         uint64_t val, unsigned size)
>  {
>  }
>
> -static CPUReadMemoryFunc * const tcx_dummy_read[3] = {
> -    NULL,
> -    NULL,
> -    tcx_dummy_readl,
> -};
> -
> -static CPUWriteMemoryFunc * const tcx_dummy_write[3] = {
> -    NULL,
> -    NULL,
> -    tcx_dummy_writel,
> +static const MemoryRegionOps dummy_ops = {
> +    .read = dummy_readl,
> +    .write = dummy_writel,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
>  };
>
>  static int tcx_init1(SysBusDevice *dev)
>  {
>     TCXState *s = FROM_SYSBUS(TCXState, dev);
> -    int io_memory, dummy_memory;
> -    ram_addr_t vram_offset;
> +    ram_addr_t vram_offset = 0;
>     int size;
>     uint8_t *vram_base;
>
> -    vram_offset = qemu_ram_alloc(NULL, "tcx.vram", s->vram_size * (1 + 4 + 4));
> -    vram_base = qemu_get_ram_ptr(vram_offset);
> -    s->vram_offset = vram_offset;
> +    memory_region_init_ram(&s->vram_mem, NULL, "tcx.vram",
> +                           s->vram_size * (1 + 4 + 4));
> +    vram_base = memory_region_get_ram_ptr(&s->vram_mem);
>
>     /* 8-bit plane */
>     s->vram = vram_base;
>     size = s->vram_size;
> -    sysbus_init_mmio(dev, size, s->vram_offset);
> +    memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
> +                             &s->vram_mem, vram_offset, size);
> +    sysbus_init_mmio_region(dev, &s->vram_8bit);
>     vram_offset += size;
>     vram_base += size;
>
>     /* DAC */
> -    io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s,
> -                                       DEVICE_NATIVE_ENDIAN);
> -    sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory);
> +    memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
> +    sysbus_init_mmio_region(dev, &s->dac);
>
>     /* TEC (dummy) */
> -    dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write,
> -                                          s, DEVICE_NATIVE_ENDIAN);
> -    sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory);
> +    memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
> +    sysbus_init_mmio_region(dev, &s->tec);
>     /* THC: NetBSD writes here even with 8-bit display: dummy */
> -    sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory);
> +    memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
> +                          TCX_THC_NREGS_24);
> +    sysbus_init_mmio_region(dev, &s->thc24);
>
>     if (s->depth == 24) {
>         /* 24-bit plane */
>         size = s->vram_size * 4;
>         s->vram24 = (uint32_t *)vram_base;
>         s->vram24_offset = vram_offset;
> -        sysbus_init_mmio(dev, size, vram_offset);
> +        memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
> +                                 &s->vram_mem, vram_offset, size);
> +        sysbus_init_mmio_region(dev, &s->vram_24bit);
>         vram_offset += size;
>         vram_base += size;
>
> @@ -546,14 +560,18 @@ static int tcx_init1(SysBusDevice *dev)
>         size = s->vram_size * 4;
>         s->cplane = (uint32_t *)vram_base;
>         s->cplane_offset = vram_offset;
> -        sysbus_init_mmio(dev, size, vram_offset);
> +        memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
> +                                 &s->vram_mem, vram_offset, size);
> +        sysbus_init_mmio_region(dev, &s->vram_cplane);
>
>         s->ds = graphic_console_init(tcx24_update_display,
>                                      tcx24_invalidate_display,
>                                      tcx24_screen_dump, NULL, s);
>     } else {
>         /* THC 8 bit (dummy) */
> -        sysbus_init_mmio(dev, TCX_THC_NREGS_8, dummy_memory);
> +        memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
> +                              TCX_THC_NREGS_8);
> +        sysbus_init_mmio_region(dev, &s->thc8);
>
>         s->ds = graphic_console_init(tcx_update_display,
>                                      tcx_invalidate_display,
> --
> 1.7.6.3
>
>
>
Avi Kivity - Oct. 17, 2011, 8:48 p.m.
On 10/17/2011 09:13 PM, Blue Swirl wrote:
> >
> > -    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
> > +    ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
> >     for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
> > -        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
> > -        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
> > +        ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
> > +                                       DIRTY_MEMORY_VGA);
> > +        ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
> > +                                       DIRTY_MEMORY_VGA);
>
> Like memory_region_set_dirty(), this should be changed to take a range
> so that the for loops and PAGE_SIZEs can be dropped.

Agree.  Lets' keep it outside this conversion patchset though.

What would the API look like?  accept a range, return true if any of the
pages in the range are dirty?
Blue Swirl - Oct. 18, 2011, 6:08 p.m.
On Mon, Oct 17, 2011 at 8:48 PM, Avi Kivity <avi@redhat.com> wrote:
> On 10/17/2011 09:13 PM, Blue Swirl wrote:
>> >
>> > -    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
>> > +    ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
>> >     for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
>> > -        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
>> > -        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
>> > +        ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
>> > +                                       DIRTY_MEMORY_VGA);
>> > +        ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
>> > +                                       DIRTY_MEMORY_VGA);
>>
>> Like memory_region_set_dirty(), this should be changed to take a range
>> so that the for loops and PAGE_SIZEs can be dropped.
>
> Agree.  Lets' keep it outside this conversion patchset though.

Yes.

> What would the API look like?  accept a range, return true if any of the
> pages in the range are dirty?

That would be 1:1 conversion but maybe better approach would be to
return the first dirty address (or zero if not found), then various
bitmap speedups may be available.
Avi Kivity - Oct. 18, 2011, 7:40 p.m.
On 10/18/2011 08:08 PM, Blue Swirl wrote:
>
> > What would the API look like?  accept a range, return true if any of the
> > pages in the range are dirty?
>
> That would be 1:1 conversion but maybe better approach would be to
> return the first dirty address (or zero if not found), then various
> bitmap speedups may be available.

Ah, an iterator.  Yes, it would allow switching from iteration on scan
lines to iteration on actual dirty ranges.

Perhaps

    void memory_region_for_each_dirty_range(MemoryRegion *mr,
                                            target_phys_addr_t start,
                                            uint64_t size,
                                            void (*dirty)(void *opaque,
target_phys_addr_t start, uint64_t size),
                                            void *opaque);
Blue Swirl - Oct. 18, 2011, 7:59 p.m.
On Tue, Oct 18, 2011 at 7:40 PM, Avi Kivity <avi@redhat.com> wrote:
> On 10/18/2011 08:08 PM, Blue Swirl wrote:
>>
>> > What would the API look like?  accept a range, return true if any of the
>> > pages in the range are dirty?
>>
>> That would be 1:1 conversion but maybe better approach would be to
>> return the first dirty address (or zero if not found), then various
>> bitmap speedups may be available.
>
> Ah, an iterator.  Yes, it would allow switching from iteration on scan
> lines to iteration on actual dirty ranges.
>
> Perhaps
>
>    void memory_region_for_each_dirty_range(MemoryRegion *mr,
>                                            target_phys_addr_t start,
>                                            uint64_t size,
>                                            void (*dirty)(void *opaque,
> target_phys_addr_t start, uint64_t size),
>                                            void *opaque);

That approach could be better for the bitmap conversions, though there
is no way to exit the loop if needed and there is no status available
to the caller (for example about end of last block for bitmap
conversion).

Patch

diff --git a/hw/tcx.c b/hw/tcx.c
index 309600d..cd24100 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -40,7 +40,15 @@ 
     DisplayState *ds;
     uint8_t *vram;
     uint32_t *vram24, *cplane;
-    ram_addr_t vram_offset, vram24_offset, cplane_offset;
+    MemoryRegion vram_mem;
+    MemoryRegion vram_8bit;
+    MemoryRegion vram_24bit;
+    MemoryRegion vram_cplane;
+    MemoryRegion dac;
+    MemoryRegion tec;
+    MemoryRegion thc24;
+    MemoryRegion thc8;
+    ram_addr_t vram24_offset, cplane_offset;
     uint32_t vram_size;
     uint32_t palette[256];
     uint8_t r[256], g[256], b[256];
@@ -56,7 +64,7 @@  static void tcx_set_dirty(TCXState *s)
     unsigned int i;
 
     for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
-        cpu_physical_memory_set_dirty(s->vram_offset + i);
+        memory_region_set_dirty(&s->vram_mem, i);
     }
 }
 
@@ -65,8 +73,8 @@  static void tcx24_set_dirty(TCXState *s)
     unsigned int i;
 
     for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
-        cpu_physical_memory_set_dirty(s->vram24_offset + i);
-        cpu_physical_memory_set_dirty(s->cplane_offset + i);
+        memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i);
+        memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i);
     }
 }
 
@@ -174,16 +182,18 @@  static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
     }
 }
 
-static inline int check_dirty(ram_addr_t page, ram_addr_t page24,
+static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
                               ram_addr_t cpage)
 {
     int ret;
     unsigned int off;
 
-    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
+    ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
     for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
-        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
-        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
+        ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
+                                       DIRTY_MEMORY_VGA);
+        ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
+                                       DIRTY_MEMORY_VGA);
     }
     return ret;
 }
@@ -192,16 +202,17 @@  static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
                                ram_addr_t page_max, ram_addr_t page24,
                               ram_addr_t cpage)
 {
-    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
-                                    VGA_DIRTY_FLAG);
-    page_min -= ts->vram_offset;
-    page_max -= ts->vram_offset;
-    cpu_physical_memory_reset_dirty(page24 + page_min * 4,
-                                    page24 + page_max * 4 + TARGET_PAGE_SIZE,
-                                    VGA_DIRTY_FLAG);
-    cpu_physical_memory_reset_dirty(cpage + page_min * 4,
-                                    cpage + page_max * 4 + TARGET_PAGE_SIZE,
-                                    VGA_DIRTY_FLAG);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              page_min, page_max + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              page24 + page_min * 4,
+                              page24 + page_max * 4 + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              cpage + page_min * 4,
+                              cpage + page_max * 4 + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
 }
 
 /* Fixed line length 1024 allows us to do nice tricks not possible on
@@ -216,7 +227,7 @@  static void tcx_update_display(void *opaque)
 
     if (ds_get_bits_per_pixel(ts->ds) == 0)
         return;
-    page = ts->vram_offset;
+    page = 0;
     y_start = -1;
     page_min = -1;
     page_max = 0;
@@ -242,7 +253,7 @@  static void tcx_update_display(void *opaque)
     }
 
     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
-        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
+        if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
             if (y_start < 0)
                 y_start = y;
             if (page < page_min)
@@ -279,8 +290,9 @@  static void tcx_update_display(void *opaque)
     }
     /* reset modified pages */
     if (page_max >= page_min) {
-        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
-                                        VGA_DIRTY_FLAG);
+        memory_region_reset_dirty(&ts->vram_mem,
+                                  page_min, page_max + TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
     }
 }
 
@@ -294,7 +306,7 @@  static void tcx24_update_display(void *opaque)
 
     if (ds_get_bits_per_pixel(ts->ds) != 32)
             return;
-    page = ts->vram_offset;
+    page = 0;
     page24 = ts->vram24_offset;
     cpage = ts->cplane_offset;
     y_start = -1;
@@ -309,7 +321,7 @@  static void tcx24_update_display(void *opaque)
 
     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
             page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
-        if (check_dirty(page, page24, cpage)) {
+        if (check_dirty(ts, page, page24, cpage)) {
             if (y_start < 0)
                 y_start = y;
             if (page < page_min)
@@ -421,18 +433,20 @@  static void tcx_reset(DeviceState *d)
     s->r[255] = s->g[255] = s->b[255] = 255;
     update_palette_entries(s, 0, 256);
     memset(s->vram, 0, MAXX*MAXY);
-    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
-                                    MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
+    memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
+                              DIRTY_MEMORY_VGA);
     s->dac_index = 0;
     s->dac_state = 0;
 }
 
-static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t tcx_dac_readl(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     return 0;
 }
 
-static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val,
+                           unsigned size)
 {
     TCXState *s = opaque;
 
@@ -468,77 +482,77 @@  static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     return;
 }
 
-static CPUReadMemoryFunc * const tcx_dac_read[3] = {
-    NULL,
-    NULL,
-    tcx_dac_readl,
+static const MemoryRegionOps tcx_dac_ops = {
+    .read = tcx_dac_readl,
+    .write = tcx_dac_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
-static CPUWriteMemoryFunc * const tcx_dac_write[3] = {
-    NULL,
-    NULL,
-    tcx_dac_writel,
-};
-
-static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t dummy_readl(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
 {
     return 0;
 }
 
-static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
+static void dummy_writel(void *opaque, target_phys_addr_t addr,
+                         uint64_t val, unsigned size)
 {
 }
 
-static CPUReadMemoryFunc * const tcx_dummy_read[3] = {
-    NULL,
-    NULL,
-    tcx_dummy_readl,
-};
-
-static CPUWriteMemoryFunc * const tcx_dummy_write[3] = {
-    NULL,
-    NULL,
-    tcx_dummy_writel,
+static const MemoryRegionOps dummy_ops = {
+    .read = dummy_readl,
+    .write = dummy_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static int tcx_init1(SysBusDevice *dev)
 {
     TCXState *s = FROM_SYSBUS(TCXState, dev);
-    int io_memory, dummy_memory;
-    ram_addr_t vram_offset;
+    ram_addr_t vram_offset = 0;
     int size;
     uint8_t *vram_base;
 
-    vram_offset = qemu_ram_alloc(NULL, "tcx.vram", s->vram_size * (1 + 4 + 4));
-    vram_base = qemu_get_ram_ptr(vram_offset);
-    s->vram_offset = vram_offset;
+    memory_region_init_ram(&s->vram_mem, NULL, "tcx.vram",
+                           s->vram_size * (1 + 4 + 4));
+    vram_base = memory_region_get_ram_ptr(&s->vram_mem);
 
     /* 8-bit plane */
     s->vram = vram_base;
     size = s->vram_size;
-    sysbus_init_mmio(dev, size, s->vram_offset);
+    memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
+                             &s->vram_mem, vram_offset, size);
+    sysbus_init_mmio_region(dev, &s->vram_8bit);
     vram_offset += size;
     vram_base += size;
 
     /* DAC */
-    io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory);
+    memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
+    sysbus_init_mmio_region(dev, &s->dac);
 
     /* TEC (dummy) */
-    dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write,
-                                          s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory);
+    memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
+    sysbus_init_mmio_region(dev, &s->tec);
     /* THC: NetBSD writes here even with 8-bit display: dummy */
-    sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory);
+    memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
+                          TCX_THC_NREGS_24);
+    sysbus_init_mmio_region(dev, &s->thc24);
 
     if (s->depth == 24) {
         /* 24-bit plane */
         size = s->vram_size * 4;
         s->vram24 = (uint32_t *)vram_base;
         s->vram24_offset = vram_offset;
-        sysbus_init_mmio(dev, size, vram_offset);
+        memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
+                                 &s->vram_mem, vram_offset, size);
+        sysbus_init_mmio_region(dev, &s->vram_24bit);
         vram_offset += size;
         vram_base += size;
 
@@ -546,14 +560,18 @@  static int tcx_init1(SysBusDevice *dev)
         size = s->vram_size * 4;
         s->cplane = (uint32_t *)vram_base;
         s->cplane_offset = vram_offset;
-        sysbus_init_mmio(dev, size, vram_offset);
+        memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
+                                 &s->vram_mem, vram_offset, size);
+        sysbus_init_mmio_region(dev, &s->vram_cplane);
 
         s->ds = graphic_console_init(tcx24_update_display,
                                      tcx24_invalidate_display,
                                      tcx24_screen_dump, NULL, s);
     } else {
         /* THC 8 bit (dummy) */
-        sysbus_init_mmio(dev, TCX_THC_NREGS_8, dummy_memory);
+        memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
+                              TCX_THC_NREGS_8);
+        sysbus_init_mmio_region(dev, &s->thc8);
 
         s->ds = graphic_console_init(tcx_update_display,
                                      tcx_invalidate_display,