diff mbox

[v1,1/4] m68k: Add NeXTcube framebuffer device emulation

Message ID 20180630083357.23489-2-huth@tuxfamily.org (mailing list archive)
State New, archived
Headers show

Commit Message

Thomas Huth June 30, 2018, 8:33 a.m. UTC
The NeXTcube uses a linear framebuffer with 4 greyscale colors and
a fixed resolution of 1120 * 832.
This code has been taken from Bryce Lanham's GSoC 2011 NeXT branch at

 https://github.com/blanham/qemu-NeXT/blob/next-cube/hw/next-fb.c

and altered to fit the latest interface of the current QEMU (e.g.
the device has been "qdev"-ified etc.).

Signed-off-by: Thomas Huth <huth@tuxfamily.org>
---
 default-configs/m68k-softmmu.mak |   2 +
 hw/display/Makefile.objs         |   1 +
 hw/display/next-fb.c             | 152 +++++++++++++++++++++++++++++++
 include/hw/m68k/next-cube.h      |   8 ++
 4 files changed, 163 insertions(+)
 create mode 100644 hw/display/next-fb.c
 create mode 100644 include/hw/m68k/next-cube.h

Comments

Richard Henderson June 30, 2018, 4 p.m. UTC | #1
On 06/30/2018 01:33 AM, Thomas Huth wrote:
> +    uint32_t pal[4] = { 0xFFFFFFFF, 0xFFAAAAAA, 0xFF555555, 0xFF000000 };

static const.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~
Peter Maydell June 30, 2018, 4:12 p.m. UTC | #2
On 30 June 2018 at 09:33, Thomas Huth <huth@tuxfamily.org> wrote:
> The NeXTcube uses a linear framebuffer with 4 greyscale colors and
> a fixed resolution of 1120 * 832.
> This code has been taken from Bryce Lanham's GSoC 2011 NeXT branch at
>
>  https://github.com/blanham/qemu-NeXT/blob/next-cube/hw/next-fb.c
>
> and altered to fit the latest interface of the current QEMU (e.g.
> the device has been "qdev"-ified etc.).
>
> Signed-off-by: Thomas Huth <huth@tuxfamily.org>

> +static void nextfb_realize(DeviceState *dev, Error **errp)
> +{
> +    NeXTFbState *s = NEXTFB(dev);
> +
> +    memory_region_allocate_system_memory(&s->fb_mr, NULL, "next.video",
> +                                         0x1CB100);

memory_region_allocate_system_memory() is for allocating
a machine model's main memory, not for things like video
framebuffer RAM. (See the doc comment in memory.h.)

> +    memory_region_add_subregion(get_system_memory(), 0xB000000, &s->fb_mr);

Devices shouldn't directly add memory regions into
system memory. Instead they should expose sysbus
memory regions which the board model then maps into
the right place.

> +
> +    s->invalidate = 1;
> +    s->cols = 1120;
> +    s->rows = 832;
> +
> +    s->con = graphic_console_init(dev, 0, &nextfb_ops, s);
> +    qemu_console_resize(s->con, s->cols, s->rows);
> +}
> +
> +static void nextfb_class_init(ObjectClass *oc, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +
> +    set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
> +    dc->realize = nextfb_realize;

Worth having at least a comment to say this device has
no mutable state and so needs no reset function or
vmstate.

> +}
> +
> +static const TypeInfo nextfb_info = {
> +    .name          = TYPE_NEXTFB,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(NeXTFbState),
> +    .class_init    = nextfb_class_init,
> +};
> +
> +static void nextfb_register_types(void)
> +{
> +    type_register_static(&nextfb_info);
> +}
> +
> +type_init(nextfb_register_types)
> +
> +void nextfb_init(void)
> +{
> +    DeviceState *dev;
> +
> +    dev = qdev_create(NULL, TYPE_NEXTFB);
> +    qdev_init_nofail(dev);
> +}

This is so simple it's not really worth having, I think.
Just have the board model code create the device...

> diff --git a/include/hw/m68k/next-cube.h b/include/hw/m68k/next-cube.h
> new file mode 100644
> index 0000000000..cf07243bda
> --- /dev/null
> +++ b/include/hw/m68k/next-cube.h
> @@ -0,0 +1,8 @@
> +
> +#ifndef NEXT_CUBE_H
> +#define NEXT_CUBE_H
> +
> +/* next-fb.c */
> +void nextfb_init(void);
> +
> +#endif /* NEXT_CUBE_H */

New header files should have copyright and license comment headers
too, though in this case if you drop the nextfb_init() function
then the header isn't needed any more.

thanks
-- PMM
Thomas Huth June 30, 2018, 7:47 p.m. UTC | #3
Am Sat, 30 Jun 2018 17:12:01 +0100
schrieb Peter Maydell <peter.maydell@linaro.org>:

> On 30 June 2018 at 09:33, Thomas Huth <huth@tuxfamily.org> wrote:
> > The NeXTcube uses a linear framebuffer with 4 greyscale colors and
> > a fixed resolution of 1120 * 832.
> > This code has been taken from Bryce Lanham's GSoC 2011 NeXT branch
> > at
> >
> >  https://github.com/blanham/qemu-NeXT/blob/next-cube/hw/next-fb.c
> >
> > and altered to fit the latest interface of the current QEMU (e.g.
> > the device has been "qdev"-ified etc.).
> >
> > Signed-off-by: Thomas Huth <huth@tuxfamily.org>  
> 
> > +static void nextfb_realize(DeviceState *dev, Error **errp)
> > +{
> > +    NeXTFbState *s = NEXTFB(dev);
> > +
> > +    memory_region_allocate_system_memory(&s->fb_mr, NULL,
> > "next.video",
> > +                                         0x1CB100);  
> 
> memory_region_allocate_system_memory() is for allocating
> a machine model's main memory, not for things like video
> framebuffer RAM. (See the doc comment in memory.h.)

That comment recommends memory_region_allocate_aux_memory(), but
that function does not exist (anymore)?

> > +    memory_region_add_subregion(get_system_memory(), 0xB000000,
> > &s->fb_mr);  
> 
> Devices shouldn't directly add memory regions into
> system memory. Instead they should expose sysbus
> memory regions which the board model then maps into
> the right place.

Ok, ... so just to make sure that I've got you right: The device
should call memory_region_init_ram() in it's realize function and the
board code should then call sysbus_mmio_map() with that region, right?

 Thomas
Peter Maydell June 30, 2018, 8:06 p.m. UTC | #4
On 30 June 2018 at 20:47, Thomas Huth <huth@tuxfamily.org> wrote:
> Am Sat, 30 Jun 2018 17:12:01 +0100
> schrieb Peter Maydell <peter.maydell@linaro.org>:
>
>> On 30 June 2018 at 09:33, Thomas Huth <huth@tuxfamily.org> wrote:
>> > The NeXTcube uses a linear framebuffer with 4 greyscale colors and
>> > a fixed resolution of 1120 * 832.
>> > This code has been taken from Bryce Lanham's GSoC 2011 NeXT branch
>> > at
>> >
>> >  https://github.com/blanham/qemu-NeXT/blob/next-cube/hw/next-fb.c
>> >
>> > and altered to fit the latest interface of the current QEMU (e.g.
>> > the device has been "qdev"-ified etc.).
>> >
>> > Signed-off-by: Thomas Huth <huth@tuxfamily.org>
>>
>> > +static void nextfb_realize(DeviceState *dev, Error **errp)
>> > +{
>> > +    NeXTFbState *s = NEXTFB(dev);
>> > +
>> > +    memory_region_allocate_system_memory(&s->fb_mr, NULL,
>> > "next.video",
>> > +                                         0x1CB100);
>>
>> memory_region_allocate_system_memory() is for allocating
>> a machine model's main memory, not for things like video
>> framebuffer RAM. (See the doc comment in memory.h.)
>
> That comment recommends memory_region_allocate_aux_memory(), but
> that function does not exist (anymore)?

Oops, good catch. That's a leftover comment that should have
been updated -- we changed the function name during discussion
of the patchset, I think, but I forgot to fix the comment.
I'll send a patch to fix that next week.

You want memory_region_init_ram() (which does both the MR
init and the mark-this-ram-for-migration).

>> > +    memory_region_add_subregion(get_system_memory(), 0xB000000,
>> > &s->fb_mr);
>>
>> Devices shouldn't directly add memory regions into
>> system memory. Instead they should expose sysbus
>> memory regions which the board model then maps into
>> the right place.
>
> Ok, ... so just to make sure that I've got you right: The device
> should call memory_region_init_ram() in it's realize function and the
> board code should then call sysbus_mmio_map() with that region, right?

The device should call memory_region_init_ram() and then
sysbus_init_mmio(); then the board code can call
sysbus_mmio_map().

I have a feeling that for framebuffer devices you should
also do something involving DIRTY_MEMORY_VGA, but I'm
not really familiar enough with the display code to say
for sure.

thanks
-- PMM
diff mbox

Patch

diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak
index 60f7cdfbf2..d3248a6506 100644
--- a/default-configs/m68k-softmmu.mak
+++ b/default-configs/m68k-softmmu.mak
@@ -2,3 +2,5 @@ 
 
 CONFIG_COLDFIRE=y
 CONFIG_PTIMER=y
+CONFIG_NEXTCUBE=y
+CONFIG_FRAMEBUFFER=y
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index fb8408c6d0..c91a660ad2 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -34,6 +34,7 @@  obj-$(CONFIG_RASPI) += bcm2835_fb.o
 obj-$(CONFIG_SM501) += sm501.o
 obj-$(CONFIG_TCX) += tcx.o
 obj-$(CONFIG_CG3) += cg3.o
+obj-$(CONFIG_NEXTCUBE) += next-fb.o
 
 obj-$(CONFIG_VGA) += vga.o
 
diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c
new file mode 100644
index 0000000000..f4248405df
--- /dev/null
+++ b/hw/display/next-fb.c
@@ -0,0 +1,152 @@ 
+/*
+ * NeXT Cube/Station Framebuffer Emulation
+ *
+ * Copyright (c) 2011 Bryce Lanham
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "hw/display/framebuffer.h"
+#include "ui/console.h"
+#define BITS 8
+#include "ui/pixel_ops.h"
+#include "hw/m68k/next-cube.h"
+
+#define TYPE_NEXTFB "next-fb"
+#define NEXTFB(obj) OBJECT_CHECK(NeXTFbState, (obj), TYPE_NEXTFB)
+
+struct NeXTFbState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion fb_mr;
+    MemoryRegionSection fbsection;
+    QemuConsole *con;
+
+    uint32_t pitch;
+    uint32_t cols;
+    uint32_t rows;
+    int invalidate;
+};
+typedef struct NeXTFbState NeXTFbState;
+
+static void nextfb_draw_line(void *opaque, uint8_t *d, const uint8_t *s,
+                             int width, int pitch)
+{
+    NeXTFbState *nfbstate = NEXTFB(opaque);
+    uint32_t pal[4] = { 0xFFFFFFFF, 0xFFAAAAAA, 0xFF555555, 0xFF000000 };
+    uint32_t *buf = (uint32_t *)d;
+    int i = 0;
+
+    for (i = 0; i < nfbstate->cols / 4; i++) {
+        int j = i * 4;
+        uint8_t src = s[i];
+        buf[j + 3] = pal[src & 0x3];
+        src >>= 2;
+        buf[j + 2] = pal[src & 0x3];
+        src >>= 2;
+        buf[j + 1] = pal[src & 0x3];
+        src >>= 2;
+        buf[j + 0] = pal[src & 0x3];
+    }
+}
+
+static void nextfb_update(void *opaque)
+{
+    NeXTFbState *s = NEXTFB(opaque);
+    int dest_width = 4;
+    int src_width;
+    int first = 0;
+    int last  = 0;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+
+    src_width = s->cols / 4 + 8;
+    dest_width = s->cols * 4;
+
+    if (s->invalidate) {
+        framebuffer_update_memory_section(&s->fbsection, &s->fb_mr, 0,
+                                          s->cols, src_width);
+        s->invalidate = 0;
+    }
+
+    framebuffer_update_display(surface, &s->fbsection, 1120, 832,
+                               src_width, dest_width, 0, 1, nextfb_draw_line,
+                               s, &first, &last);
+
+    dpy_gfx_update(s->con, 0, 0, 1120, 832);
+}
+
+static void nextfb_invalidate(void *opaque)
+{
+    NeXTFbState *s = NEXTFB(opaque);
+    s->invalidate = 1;
+}
+
+static const GraphicHwOps nextfb_ops = {
+    .invalidate  = nextfb_invalidate,
+    .gfx_update  = nextfb_update,
+};
+
+static void nextfb_realize(DeviceState *dev, Error **errp)
+{
+    NeXTFbState *s = NEXTFB(dev);
+
+    memory_region_allocate_system_memory(&s->fb_mr, NULL, "next.video",
+                                         0x1CB100);
+    memory_region_add_subregion(get_system_memory(), 0xB000000, &s->fb_mr);
+
+    s->invalidate = 1;
+    s->cols = 1120;
+    s->rows = 832;
+
+    s->con = graphic_console_init(dev, 0, &nextfb_ops, s);
+    qemu_console_resize(s->con, s->cols, s->rows);
+}
+
+static void nextfb_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+    dc->realize = nextfb_realize;
+}
+
+static const TypeInfo nextfb_info = {
+    .name          = TYPE_NEXTFB,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(NeXTFbState),
+    .class_init    = nextfb_class_init,
+};
+
+static void nextfb_register_types(void)
+{
+    type_register_static(&nextfb_info);
+}
+
+type_init(nextfb_register_types)
+
+void nextfb_init(void)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, TYPE_NEXTFB);
+    qdev_init_nofail(dev);
+}
diff --git a/include/hw/m68k/next-cube.h b/include/hw/m68k/next-cube.h
new file mode 100644
index 0000000000..cf07243bda
--- /dev/null
+++ b/include/hw/m68k/next-cube.h
@@ -0,0 +1,8 @@ 
+
+#ifndef NEXT_CUBE_H
+#define NEXT_CUBE_H
+
+/* next-fb.c */
+void nextfb_init(void);
+
+#endif /* NEXT_CUBE_H */