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
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 */
--
2.17.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~
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
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
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
© 2016 - 2026 Red Hat, Inc.