• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Keine Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revision89ea03a7dc83ca36b670ba7f787802791fcb04b1 (tree)
Zeit2019-09-09 17:48:34
AutorPeter Maydell <peter.maydell@lina...>
CommiterPeter Maydell

Log Message

Add the m68k next-cube machine
-----BEGIN PGP SIGNATURE-----

iQJHBAABCAAxFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAl1zzaUTHGh1dGhAdHV4
ZmFtaWx5Lm9yZwAKCRAu2dd0/nAttSW4D/0diba+8qhfQnucHFd75xNWetnRoCw2
PwcQ5U3DVDFAH7JhmUeBnVMeZccs2DappHRoWD1yoCgcwYX83UDlNitZvNi+wp2p
81oeD6rzY93684xSHc7WHeaCaUoxyCNyTAwZ885CalLO/Jxgwa6VQ5Y3K1kKWblf
Xne3a0WejRlB+yWxmV9MkG5+34R68RHYD0V5j7L+PWjXczc4kjX4mjTHYJzPtYv+
WOpPI+aBdoDu+UgjheAbCWIoxz3tIupVOx0tofqv3lGwyOUqGzi63WLUMf50zlZM
Gs/4l9uxF80C7Ie7sDUnqaOFVRqOCuqPT/Ui9Ojn4iB+0Cs4ZWQ8OTDd4mAsKfIw
T/3uGvk0+ROyJFhdxG8Tsycb5grSBC5rbUgYusr3MxyDLSr8uWthAlNgEMnnQ05b
XhYgFKi0aW0iuAvEbzMSptpEXD5OKE59ONAKG3i83l8Noy0IuQG7BHNSeOcNwbHA
VQLEJoq0TCMZMmRB7J4y1F9ax/dNiZENEt2uaS4QXd6cxdoo+HYnL3QaxT1oM85m
QfLDMo4t0OF5RRXEQkTt0g6zAluRM7QGO5KfPp3P4sPnpUccZWmwf9icIohEv5Bc
kVB2vUXBV6768IB75U3UX+pdu1OcESeXgW3u+mVxQtELWhsYRdqyFHjwQZypXh5u
NFqAgzzNlXGowg==
=syaC
-----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/huth-gitlab/tags/m68k-pull-2019-09-07' into staging

Add the m68k next-cube machine

# gpg: Signature made Sat 07 Sep 2019 16:32:53 BST
# gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5
# gpg: issuer "huth@tuxfamily.org"
# gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full]
# gpg: aka "Thomas Huth <thuth@redhat.com>" [full]
# gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full]
# gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown]
# Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5

* remotes/huth-gitlab/tags/m68k-pull-2019-09-07:

.travis.yml: Let the avocado job run the NeXTcube tests
tests/acceptance: Add test of NeXTcube framebuffer using OCR
m68k: Add an entry for the NeXTcube machine to the MAINTAINERS file
m68k: Add serial controller to the NeXTcube machine
escc: introduce a selector for the register bit
m68k: Add NeXTcube machine
m68k: Add NeXTcube keyboard device
m68k: Add NeXTcube framebuffer device emulation

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Ändern Zusammenfassung

Diff

--- a/.travis.yml
+++ b/.travis.yml
@@ -232,15 +232,20 @@ matrix:
232232
233233 # Acceptance (Functional) tests
234234 - env:
235- - CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu,ppc64-softmmu"
235+ - CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu,ppc64-softmmu,m68k-softmmu"
236236 - TEST_CMD="make check-acceptance"
237237 after_failure:
238238 - cat tests/results/latest/job.log
239239 addons:
240240 apt:
241241 packages:
242+ - python3-pil
242243 - python3-pip
243244 - python3.5-venv
245+ - tesseract-ocr
246+ - tesseract-ocr-eng
247+
248+
244249 # Using newer GCC with sanitizers
245250 - addons:
246251 apt:
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -910,6 +910,13 @@ F: hw/char/mcf_uart.c
910910 F: hw/net/mcf_fec.c
911911 F: include/hw/m68k/mcf*.h
912912
913+NeXTcube
914+M: Thomas Huth <huth@tuxfamily.org>
915+S: Odd Fixes
916+F: hw/m68k/next-*.c
917+F: hw/display/next-fb.c
918+F: include/hw/m68k/next-cube.h
919+
913920 MicroBlaze Machines
914921 -------------------
915922 petalogix_s3adsp1800
--- a/default-configs/m68k-softmmu.mak
+++ b/default-configs/m68k-softmmu.mak
@@ -6,3 +6,4 @@ CONFIG_SEMIHOSTING=y
66 #
77 CONFIG_AN5206=y
88 CONFIG_MCF5208=y
9+CONFIG_NEXTCUBE=y
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -45,14 +45,21 @@
4545 * mouse and keyboard ports don't implement all functions and they are
4646 * only asynchronous. There is no DMA.
4747 *
48- * Z85C30 is also used on PowerMacs. There are some small differences
49- * between Sparc version (sunzilog) and PowerMac (pmac):
48+ * Z85C30 is also used on PowerMacs and m68k Macs.
49+ *
50+ * There are some small differences between Sparc version (sunzilog)
51+ * and PowerMac (pmac):
5052 * Offset between control and data registers
5153 * There is some kind of lockup bug, but we can ignore it
5254 * CTS is inverted
5355 * DMA on pmac using DBDMA chip
5456 * pmac can do IRDA and faster rates, sunzilog can only do 38400
5557 * pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz
58+ *
59+ * Linux driver for m68k Macs is the same as for PowerMac (pmac_zilog),
60+ * but registers are grouped by type and not by channel:
61+ * channel is selected by bit 0 of the address (instead of bit 1)
62+ * and register is selected by bit 1 of the address (instead of bit 0).
5663 */
5764
5865 /*
@@ -172,6 +179,16 @@ static void handle_kbd_command(ESCCChannelState *s, int val);
172179 static int serial_can_receive(void *opaque);
173180 static void serial_receive_byte(ESCCChannelState *s, int ch);
174181
182+static int reg_shift(ESCCState *s)
183+{
184+ return s->bit_swap ? s->it_shift + 1 : s->it_shift;
185+}
186+
187+static int chn_shift(ESCCState *s)
188+{
189+ return s->bit_swap ? s->it_shift : s->it_shift + 1;
190+}
191+
175192 static void clear_queue(void *opaque)
176193 {
177194 ESCCChannelState *s = opaque;
@@ -436,8 +453,8 @@ static void escc_mem_write(void *opaque, hwaddr addr,
436453 int newreg, channel;
437454
438455 val &= 0xff;
439- saddr = (addr >> serial->it_shift) & 1;
440- channel = (addr >> (serial->it_shift + 1)) & 1;
456+ saddr = (addr >> reg_shift(serial)) & 1;
457+ channel = (addr >> chn_shift(serial)) & 1;
441458 s = &serial->chn[channel];
442459 switch (saddr) {
443460 case SERIAL_CTRL:
@@ -547,8 +564,8 @@ static uint64_t escc_mem_read(void *opaque, hwaddr addr,
547564 uint32_t ret;
548565 int channel;
549566
550- saddr = (addr >> serial->it_shift) & 1;
551- channel = (addr >> (serial->it_shift + 1)) & 1;
567+ saddr = (addr >> reg_shift(serial)) & 1;
568+ channel = (addr >> chn_shift(serial)) & 1;
552569 s = &serial->chn[channel];
553570 switch (saddr) {
554571 case SERIAL_CTRL:
@@ -832,6 +849,7 @@ static void escc_realize(DeviceState *dev, Error **errp)
832849 static Property escc_properties[] = {
833850 DEFINE_PROP_UINT32("frequency", ESCCState, frequency, 0),
834851 DEFINE_PROP_UINT32("it_shift", ESCCState, it_shift, 0),
852+ DEFINE_PROP_BOOL("bit_swap", ESCCState, bit_swap, false),
835853 DEFINE_PROP_UINT32("disabled", ESCCState, disabled, 0),
836854 DEFINE_PROP_UINT32("chnBtype", ESCCState, chn[0].type, 0),
837855 DEFINE_PROP_UINT32("chnAtype", ESCCState, chn[1].type, 0),
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -38,6 +38,7 @@ common-obj-$(CONFIG_RASPI) += bcm2835_fb.o
3838 common-obj-$(CONFIG_SM501) += sm501.o
3939 common-obj-$(CONFIG_TCX) += tcx.o
4040 common-obj-$(CONFIG_CG3) += cg3.o
41+common-obj-$(CONFIG_NEXTCUBE) += next-fb.o
4142
4243 obj-$(CONFIG_VGA) += vga.o
4344
--- /dev/null
+++ b/hw/display/next-fb.c
@@ -0,0 +1,146 @@
1+/*
2+ * NeXT Cube/Station Framebuffer Emulation
3+ *
4+ * Copyright (c) 2011 Bryce Lanham
5+ *
6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7+ * of this software and associated documentation files (the "Software"), to deal
8+ * in the Software without restriction, including without limitation the rights
9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+ * THE SOFTWARE.
23+ */
24+#include "qemu/osdep.h"
25+#include "qapi/error.h"
26+#include "ui/console.h"
27+#include "hw/hw.h"
28+#include "hw/boards.h"
29+#include "hw/loader.h"
30+#include "hw/display/framebuffer.h"
31+#include "ui/pixel_ops.h"
32+#include "hw/m68k/next-cube.h"
33+
34+#define NEXTFB(obj) OBJECT_CHECK(NeXTFbState, (obj), TYPE_NEXTFB)
35+
36+struct NeXTFbState {
37+ SysBusDevice parent_obj;
38+
39+ MemoryRegion fb_mr;
40+ MemoryRegionSection fbsection;
41+ QemuConsole *con;
42+
43+ uint32_t cols;
44+ uint32_t rows;
45+ int invalidate;
46+};
47+typedef struct NeXTFbState NeXTFbState;
48+
49+static void nextfb_draw_line(void *opaque, uint8_t *d, const uint8_t *s,
50+ int width, int pitch)
51+{
52+ NeXTFbState *nfbstate = NEXTFB(opaque);
53+ static const uint32_t pal[4] = {
54+ 0xFFFFFFFF, 0xFFAAAAAA, 0xFF555555, 0xFF000000
55+ };
56+ uint32_t *buf = (uint32_t *)d;
57+ int i = 0;
58+
59+ for (i = 0; i < nfbstate->cols / 4; i++) {
60+ int j = i * 4;
61+ uint8_t src = s[i];
62+ buf[j + 3] = pal[src & 0x3];
63+ src >>= 2;
64+ buf[j + 2] = pal[src & 0x3];
65+ src >>= 2;
66+ buf[j + 1] = pal[src & 0x3];
67+ src >>= 2;
68+ buf[j + 0] = pal[src & 0x3];
69+ }
70+}
71+
72+static void nextfb_update(void *opaque)
73+{
74+ NeXTFbState *s = NEXTFB(opaque);
75+ int dest_width = 4;
76+ int src_width;
77+ int first = 0;
78+ int last = 0;
79+ DisplaySurface *surface = qemu_console_surface(s->con);
80+
81+ src_width = s->cols / 4 + 8;
82+ dest_width = s->cols * 4;
83+
84+ if (s->invalidate) {
85+ framebuffer_update_memory_section(&s->fbsection, &s->fb_mr, 0,
86+ s->cols, src_width);
87+ s->invalidate = 0;
88+ }
89+
90+ framebuffer_update_display(surface, &s->fbsection, s->cols, s->rows,
91+ src_width, dest_width, 0, 1, nextfb_draw_line,
92+ s, &first, &last);
93+
94+ dpy_gfx_update(s->con, 0, 0, s->cols, s->rows);
95+}
96+
97+static void nextfb_invalidate(void *opaque)
98+{
99+ NeXTFbState *s = NEXTFB(opaque);
100+ s->invalidate = 1;
101+}
102+
103+static const GraphicHwOps nextfb_ops = {
104+ .invalidate = nextfb_invalidate,
105+ .gfx_update = nextfb_update,
106+};
107+
108+static void nextfb_realize(DeviceState *dev, Error **errp)
109+{
110+ NeXTFbState *s = NEXTFB(dev);
111+
112+ memory_region_init_ram(&s->fb_mr, OBJECT(dev), "next-video", 0x1CB100,
113+ &error_fatal);
114+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->fb_mr);
115+
116+ s->invalidate = 1;
117+ s->cols = 1120;
118+ s->rows = 832;
119+
120+ s->con = graphic_console_init(dev, 0, &nextfb_ops, s);
121+ qemu_console_resize(s->con, s->cols, s->rows);
122+}
123+
124+static void nextfb_class_init(ObjectClass *oc, void *data)
125+{
126+ DeviceClass *dc = DEVICE_CLASS(oc);
127+
128+ set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
129+ dc->realize = nextfb_realize;
130+
131+ /* Note: This device does not any state that we have to reset or migrate */
132+}
133+
134+static const TypeInfo nextfb_info = {
135+ .name = TYPE_NEXTFB,
136+ .parent = TYPE_SYS_BUS_DEVICE,
137+ .instance_size = sizeof(NeXTFbState),
138+ .class_init = nextfb_class_init,
139+};
140+
141+static void nextfb_register_types(void)
142+{
143+ type_register_static(&nextfb_info);
144+}
145+
146+type_init(nextfb_register_types)
--- a/hw/m68k/Kconfig
+++ b/hw/m68k/Kconfig
@@ -7,3 +7,8 @@ config MCF5208
77 bool
88 select COLDFIRE
99 select PTIMER
10+
11+config NEXTCUBE
12+ bool
13+ select FRAMEBUFFER
14+ select ESCC
--- a/hw/m68k/Makefile.objs
+++ b/hw/m68k/Makefile.objs
@@ -1,2 +1,3 @@
11 obj-$(CONFIG_AN5206) += an5206.o mcf5206.o
22 obj-$(CONFIG_MCF5208) += mcf5208.o mcf_intc.o
3+obj-$(CONFIG_NEXTCUBE) += next-kbd.o next-cube.o
--- /dev/null
+++ b/hw/m68k/next-cube.c
@@ -0,0 +1,978 @@
1+/*
2+ * NeXT Cube System Driver
3+ *
4+ * Copyright (c) 2011 Bryce Lanham
5+ *
6+ * This code is free software; you can redistribute it and/or modify
7+ * it under the terms of the GNU General Public License as published
8+ * by the Free Software Foundation; either version 2 of the License,
9+ * or (at your option) any later version.
10+ */
11+
12+#include "qemu/osdep.h"
13+#include "cpu.h"
14+#include "exec/hwaddr.h"
15+#include "exec/address-spaces.h"
16+#include "sysemu/sysemu.h"
17+#include "sysemu/qtest.h"
18+#include "hw/irq.h"
19+#include "hw/m68k/next-cube.h"
20+#include "hw/boards.h"
21+#include "hw/loader.h"
22+#include "hw/scsi/esp.h"
23+#include "hw/sysbus.h"
24+#include "hw/char/escc.h" /* ZILOG 8530 Serial Emulation */
25+#include "hw/block/fdc.h"
26+#include "hw/qdev-properties.h"
27+#include "qapi/error.h"
28+#include "ui/console.h"
29+#include "target/m68k/cpu.h"
30+
31+/* #define DEBUG_NEXT */
32+#ifdef DEBUG_NEXT
33+#define DPRINTF(fmt, ...) \
34+ do { printf("NeXT: " fmt , ## __VA_ARGS__); } while (0)
35+#else
36+#define DPRINTF(fmt, ...) do { } while (0)
37+#endif
38+
39+#define TYPE_NEXT_MACHINE MACHINE_TYPE_NAME("next-cube")
40+#define NEXT_MACHINE(obj) OBJECT_CHECK(NeXTState, (obj), TYPE_NEXT_MACHINE)
41+
42+#define ENTRY 0x0100001e
43+#define RAM_SIZE 0x4000000
44+#define ROM_FILE "Rev_2.5_v66.bin"
45+
46+typedef struct next_dma {
47+ uint32_t csr;
48+
49+ uint32_t saved_next;
50+ uint32_t saved_limit;
51+ uint32_t saved_start;
52+ uint32_t saved_stop;
53+
54+ uint32_t next;
55+ uint32_t limit;
56+ uint32_t start;
57+ uint32_t stop;
58+
59+ uint32_t next_initbuf;
60+ uint32_t size;
61+} next_dma;
62+
63+typedef struct {
64+ MachineState parent;
65+
66+ uint32_t int_mask;
67+ uint32_t int_status;
68+
69+ uint8_t scsi_csr_1;
70+ uint8_t scsi_csr_2;
71+ next_dma dma[10];
72+ qemu_irq *scsi_irq;
73+ qemu_irq scsi_dma;
74+ qemu_irq scsi_reset;
75+ qemu_irq *fd_irq;
76+
77+ uint32_t scr1;
78+ uint32_t scr2;
79+
80+ uint8_t rtc_ram[32];
81+} NeXTState;
82+
83+/* Thanks to NeXT forums for this */
84+/*
85+static const uint8_t rtc_ram3[32] = {
86+ 0x94, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
87+ 0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x7B, 0x00,
88+ 0x00, 0x00, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00,
89+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x13
90+};
91+*/
92+static const uint8_t rtc_ram2[32] = {
93+ 0x94, 0x0f, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00,
94+ 0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x4b, 0x00,
95+ 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
96+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x7e,
97+};
98+
99+#define SCR2_RTCLK 0x2
100+#define SCR2_RTDATA 0x4
101+#define SCR2_TOBCD(x) (((x / 10) << 4) + (x % 10))
102+
103+static void nextscr2_write(NeXTState *s, uint32_t val, int size)
104+{
105+ static int led;
106+ static int phase;
107+ static uint8_t old_scr2;
108+ static uint8_t rtc_command;
109+ static uint8_t rtc_value;
110+ static uint8_t rtc_status = 0x90;
111+ static uint8_t rtc_return;
112+ uint8_t scr2_2;
113+
114+ if (size == 4) {
115+ scr2_2 = (val >> 8) & 0xFF;
116+ } else {
117+ scr2_2 = val & 0xFF;
118+ }
119+
120+ if (val & 0x1) {
121+ DPRINTF("fault!\n");
122+ led++;
123+ if (led == 10) {
124+ DPRINTF("LED flashing, possible fault!\n");
125+ led = 0;
126+ }
127+ }
128+
129+ if (scr2_2 & 0x1) {
130+ /* DPRINTF("RTC %x phase %i\n", scr2_2, phase); */
131+ if (phase == -1) {
132+ phase = 0;
133+ }
134+ /* If we are in going down clock... do something */
135+ if (((old_scr2 & SCR2_RTCLK) != (scr2_2 & SCR2_RTCLK)) &&
136+ ((scr2_2 & SCR2_RTCLK) == 0)) {
137+ if (phase < 8) {
138+ rtc_command = (rtc_command << 1) |
139+ ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
140+ }
141+ if (phase >= 8 && phase < 16) {
142+ rtc_value = (rtc_value << 1) | ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
143+
144+ /* if we read RAM register, output RT_DATA bit */
145+ if (rtc_command <= 0x1F) {
146+ scr2_2 = scr2_2 & (~SCR2_RTDATA);
147+ if (s->rtc_ram[rtc_command] & (0x80 >> (phase - 8))) {
148+ scr2_2 |= SCR2_RTDATA;
149+ }
150+
151+ rtc_return = (rtc_return << 1) |
152+ ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
153+ }
154+ /* read the status 0x30 */
155+ if (rtc_command == 0x30) {
156+ scr2_2 = scr2_2 & (~SCR2_RTDATA);
157+ /* for now status = 0x98 (new rtc + FTU) */
158+ if (rtc_status & (0x80 >> (phase - 8))) {
159+ scr2_2 |= SCR2_RTDATA;
160+ }
161+
162+ rtc_return = (rtc_return << 1) |
163+ ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
164+ }
165+ /* read the status 0x31 */
166+ if (rtc_command == 0x31) {
167+ scr2_2 = scr2_2 & (~SCR2_RTDATA);
168+ /* for now 0x00 */
169+ if (0x00 & (0x80 >> (phase - 8))) {
170+ scr2_2 |= SCR2_RTDATA;
171+ }
172+ rtc_return = (rtc_return << 1) |
173+ ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
174+ }
175+
176+ if ((rtc_command >= 0x20) && (rtc_command <= 0x2F)) {
177+ scr2_2 = scr2_2 & (~SCR2_RTDATA);
178+ /* for now 0x00 */
179+ time_t time_h = time(NULL);
180+ struct tm *info = localtime(&time_h);
181+ int ret = 0;
182+
183+ switch (rtc_command) {
184+ case 0x20:
185+ ret = SCR2_TOBCD(info->tm_sec);
186+ break;
187+ case 0x21:
188+ ret = SCR2_TOBCD(info->tm_min);
189+ break;
190+ case 0x22:
191+ ret = SCR2_TOBCD(info->tm_hour);
192+ break;
193+ case 0x24:
194+ ret = SCR2_TOBCD(info->tm_mday);
195+ break;
196+ case 0x25:
197+ ret = SCR2_TOBCD((info->tm_mon + 1));
198+ break;
199+ case 0x26:
200+ ret = SCR2_TOBCD((info->tm_year - 100));
201+ break;
202+
203+ }
204+
205+ if (ret & (0x80 >> (phase - 8))) {
206+ scr2_2 |= SCR2_RTDATA;
207+ }
208+ rtc_return = (rtc_return << 1) |
209+ ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
210+ }
211+
212+ }
213+
214+ phase++;
215+ if (phase == 16) {
216+ if (rtc_command >= 0x80 && rtc_command <= 0x9F) {
217+ s->rtc_ram[rtc_command - 0x80] = rtc_value;
218+ }
219+ /* write to x30 register */
220+ if (rtc_command == 0xB1) {
221+ /* clear FTU */
222+ if (rtc_value & 0x04) {
223+ rtc_status = rtc_status & (~0x18);
224+ s->int_status = s->int_status & (~0x04);
225+ }
226+ }
227+ }
228+ }
229+ } else {
230+ /* else end or abort */
231+ phase = -1;
232+ rtc_command = 0;
233+ rtc_value = 0;
234+ }
235+ s->scr2 = val & 0xFFFF00FF;
236+ s->scr2 |= scr2_2 << 8;
237+ old_scr2 = scr2_2;
238+}
239+
240+static uint32_t mmio_readb(NeXTState *s, hwaddr addr)
241+{
242+ switch (addr) {
243+ case 0xc000:
244+ return (s->scr1 >> 24) & 0xFF;
245+ case 0xc001:
246+ return (s->scr1 >> 16) & 0xFF;
247+ case 0xc002:
248+ return (s->scr1 >> 8) & 0xFF;
249+ case 0xc003:
250+ return (s->scr1 >> 0) & 0xFF;
251+
252+ case 0xd000:
253+ return (s->scr2 >> 24) & 0xFF;
254+ case 0xd001:
255+ return (s->scr2 >> 16) & 0xFF;
256+ case 0xd002:
257+ return (s->scr2 >> 8) & 0xFF;
258+ case 0xd003:
259+ return (s->scr2 >> 0) & 0xFF;
260+ case 0x14020:
261+ DPRINTF("MMIO Read 0x4020\n");
262+ return 0x7f;
263+
264+ default:
265+ DPRINTF("MMIO Read B @ %"HWADDR_PRIx"\n", addr);
266+ return 0x0;
267+ }
268+}
269+
270+static uint32_t mmio_readw(NeXTState *s, hwaddr addr)
271+{
272+ switch (addr) {
273+ default:
274+ DPRINTF("MMIO Read W @ %"HWADDR_PRIx"\n", addr);
275+ return 0x0;
276+ }
277+}
278+
279+static uint32_t mmio_readl(NeXTState *s, hwaddr addr)
280+{
281+ switch (addr) {
282+ case 0x7000:
283+ /* DPRINTF("Read INT status: %x\n", s->int_status); */
284+ return s->int_status;
285+
286+ case 0x7800:
287+ DPRINTF("MMIO Read INT mask: %x\n", s->int_mask);
288+ return s->int_mask;
289+
290+ case 0xc000:
291+ return s->scr1;
292+
293+ case 0xd000:
294+ return s->scr2;
295+
296+ default:
297+ DPRINTF("MMIO Read L @ %"HWADDR_PRIx"\n", addr);
298+ return 0x0;
299+ }
300+}
301+
302+static void mmio_writeb(NeXTState *s, hwaddr addr, uint32_t val)
303+{
304+ switch (addr) {
305+ case 0xd003:
306+ nextscr2_write(s, val, 1);
307+ break;
308+ default:
309+ DPRINTF("MMIO Write B @ %x with %x\n", (unsigned int)addr, val);
310+ }
311+
312+}
313+
314+static void mmio_writew(NeXTState *s, hwaddr addr, uint32_t val)
315+{
316+ DPRINTF("MMIO Write W\n");
317+}
318+
319+static void mmio_writel(NeXTState *s, hwaddr addr, uint32_t val)
320+{
321+ switch (addr) {
322+ case 0x7000:
323+ DPRINTF("INT Status old: %x new: %x\n", s->int_status, val);
324+ s->int_status = val;
325+ break;
326+ case 0x7800:
327+ DPRINTF("INT Mask old: %x new: %x\n", s->int_mask, val);
328+ s->int_mask = val;
329+ break;
330+ case 0xc000:
331+ DPRINTF("SCR1 Write: %x\n", val);
332+ break;
333+ case 0xd000:
334+ nextscr2_write(s, val, 4);
335+ break;
336+
337+ default:
338+ DPRINTF("MMIO Write l @ %x with %x\n", (unsigned int)addr, val);
339+ }
340+}
341+
342+static uint64_t mmio_readfn(void *opaque, hwaddr addr, unsigned size)
343+{
344+ NeXTState *ns = NEXT_MACHINE(opaque);
345+
346+ switch (size) {
347+ case 1:
348+ return mmio_readb(ns, addr);
349+ case 2:
350+ return mmio_readw(ns, addr);
351+ case 4:
352+ return mmio_readl(ns, addr);
353+ default:
354+ g_assert_not_reached();
355+ }
356+}
357+
358+static void mmio_writefn(void *opaque, hwaddr addr, uint64_t value,
359+ unsigned size)
360+{
361+ NeXTState *ns = NEXT_MACHINE(opaque);
362+
363+ switch (size) {
364+ case 1:
365+ mmio_writeb(ns, addr, value);
366+ break;
367+ case 2:
368+ mmio_writew(ns, addr, value);
369+ break;
370+ case 4:
371+ mmio_writel(ns, addr, value);
372+ break;
373+ default:
374+ g_assert_not_reached();
375+ }
376+}
377+
378+static const MemoryRegionOps mmio_ops = {
379+ .read = mmio_readfn,
380+ .write = mmio_writefn,
381+ .valid.min_access_size = 1,
382+ .valid.max_access_size = 4,
383+ .endianness = DEVICE_NATIVE_ENDIAN,
384+};
385+
386+static uint32_t scr_readb(NeXTState *s, hwaddr addr)
387+{
388+ switch (addr) {
389+ case 0x14108:
390+ DPRINTF("FD read @ %x\n", (unsigned int)addr);
391+ return 0x40 | 0x04 | 0x2 | 0x1;
392+ case 0x14020:
393+ DPRINTF("SCSI 4020 STATUS READ %X\n", s->scsi_csr_1);
394+ return s->scsi_csr_1;
395+
396+ case 0x14021:
397+ DPRINTF("SCSI 4021 STATUS READ %X\n", s->scsi_csr_2);
398+ return 0x40;
399+
400+ /*
401+ * These 4 registers are the hardware timer, not sure which register
402+ * is the latch instead of data, but no problems so far
403+ */
404+ case 0x1a000:
405+ return 0xff & (clock() >> 24);
406+ case 0x1a001:
407+ return 0xff & (clock() >> 16);
408+ case 0x1a002:
409+ return 0xff & (clock() >> 8);
410+ case 0x1a003:
411+ /* Hack: We need to have this change consistently to make it work */
412+ return 0xFF & clock();
413+
414+ default:
415+ DPRINTF("BMAP Read B @ %x\n", (unsigned int)addr);
416+ return 0;
417+ }
418+}
419+
420+static uint32_t scr_readw(NeXTState *s, hwaddr addr)
421+{
422+ DPRINTF("BMAP Read W @ %x\n", (unsigned int)addr);
423+ return 0;
424+}
425+
426+static uint32_t scr_readl(NeXTState *s, hwaddr addr)
427+{
428+ DPRINTF("BMAP Read L @ %x\n", (unsigned int)addr);
429+ return 0;
430+}
431+
432+#define SCSICSR_ENABLE 0x01
433+#define SCSICSR_RESET 0x02 /* reset scsi dma */
434+#define SCSICSR_FIFOFL 0x04
435+#define SCSICSR_DMADIR 0x08 /* if set, scsi to mem */
436+#define SCSICSR_CPUDMA 0x10 /* if set, dma enabled */
437+#define SCSICSR_INTMASK 0x20 /* if set, interrupt enabled */
438+
439+static void scr_writeb(NeXTState *s, hwaddr addr, uint32_t value)
440+{
441+ switch (addr) {
442+ case 0x14108:
443+ DPRINTF("FDCSR Write: %x\n", value);
444+
445+ if (value == 0x0) {
446+ /* qemu_irq_raise(s->fd_irq[0]); */
447+ }
448+ break;
449+ case 0x14020: /* SCSI Control Register */
450+ if (value & SCSICSR_FIFOFL) {
451+ DPRINTF("SCSICSR FIFO Flush\n");
452+ /* will have to add another irq to the esp if this is needed */
453+ /* esp_puflush_fifo(esp_g); */
454+ /* qemu_irq_pulse(s->scsi_dma); */
455+ }
456+
457+ if (value & SCSICSR_ENABLE) {
458+ DPRINTF("SCSICSR Enable\n");
459+ /*
460+ * qemu_irq_raise(s->scsi_dma);
461+ * s->scsi_csr_1 = 0xc0;
462+ * s->scsi_csr_1 |= 0x1;
463+ * qemu_irq_pulse(s->scsi_dma);
464+ */
465+ }
466+ /*
467+ * else
468+ * s->scsi_csr_1 &= ~SCSICSR_ENABLE;
469+ */
470+
471+ if (value & SCSICSR_RESET) {
472+ DPRINTF("SCSICSR Reset\n");
473+ /* I think this should set DMADIR. CPUDMA and INTMASK to 0 */
474+ /* qemu_irq_raise(s->scsi_reset); */
475+ /* s->scsi_csr_1 &= ~(SCSICSR_INTMASK |0x80|0x1); */
476+
477+ }
478+ if (value & SCSICSR_DMADIR) {
479+ DPRINTF("SCSICSR DMAdir\n");
480+ }
481+ if (value & SCSICSR_CPUDMA) {
482+ DPRINTF("SCSICSR CPUDMA\n");
483+ /* qemu_irq_raise(s->scsi_dma); */
484+
485+ s->int_status |= 0x4000000;
486+ } else {
487+ s->int_status &= ~(0x4000000);
488+ }
489+ if (value & SCSICSR_INTMASK) {
490+ DPRINTF("SCSICSR INTMASK\n");
491+ /*
492+ * int_mask &= ~0x1000;
493+ * s->scsi_csr_1 |= value;
494+ * s->scsi_csr_1 &= ~SCSICSR_INTMASK;
495+ * if (s->scsi_queued) {
496+ * s->scsi_queued = 0;
497+ * next_irq(s, NEXT_SCSI_I, level);
498+ * }
499+ */
500+ } else {
501+ /* int_mask |= 0x1000; */
502+ }
503+ if (value & 0x80) {
504+ /* int_mask |= 0x1000; */
505+ /* s->scsi_csr_1 |= 0x80; */
506+ }
507+ DPRINTF("SCSICSR Write: %x\n", value);
508+ /* s->scsi_csr_1 = value; */
509+ return;
510+ /* Hardware timer latch - not implemented yet */
511+ case 0x1a000:
512+ default:
513+ DPRINTF("BMAP Write B @ %x with %x\n", (unsigned int)addr, value);
514+ }
515+}
516+
517+static void scr_writew(NeXTState *s, hwaddr addr, uint32_t value)
518+{
519+ DPRINTF("BMAP Write W @ %x with %x\n", (unsigned int)addr, value);
520+}
521+
522+static void scr_writel(NeXTState *s, hwaddr addr, uint32_t value)
523+{
524+ DPRINTF("BMAP Write L @ %x with %x\n", (unsigned int)addr, value);
525+}
526+
527+static uint64_t scr_readfn(void *opaque, hwaddr addr, unsigned size)
528+{
529+ NeXTState *ns = NEXT_MACHINE(opaque);
530+
531+ switch (size) {
532+ case 1:
533+ return scr_readb(ns, addr);
534+ case 2:
535+ return scr_readw(ns, addr);
536+ case 4:
537+ return scr_readl(ns, addr);
538+ default:
539+ g_assert_not_reached();
540+ }
541+}
542+
543+static void scr_writefn(void *opaque, hwaddr addr, uint64_t value,
544+ unsigned size)
545+{
546+ NeXTState *ns = NEXT_MACHINE(opaque);
547+
548+ switch (size) {
549+ case 1:
550+ scr_writeb(ns, addr, value);
551+ break;
552+ case 2:
553+ scr_writew(ns, addr, value);
554+ break;
555+ case 4:
556+ scr_writel(ns, addr, value);
557+ break;
558+ default:
559+ g_assert_not_reached();
560+ }
561+}
562+
563+static const MemoryRegionOps scr_ops = {
564+ .read = scr_readfn,
565+ .write = scr_writefn,
566+ .valid.min_access_size = 1,
567+ .valid.max_access_size = 4,
568+ .endianness = DEVICE_NATIVE_ENDIAN,
569+};
570+
571+#define NEXTDMA_SCSI(x) (0x10 + x)
572+#define NEXTDMA_FD(x) (0x10 + x)
573+#define NEXTDMA_ENTX(x) (0x110 + x)
574+#define NEXTDMA_ENRX(x) (0x150 + x)
575+#define NEXTDMA_CSR 0x0
576+#define NEXTDMA_NEXT 0x4000
577+#define NEXTDMA_LIMIT 0x4004
578+#define NEXTDMA_START 0x4008
579+#define NEXTDMA_STOP 0x400c
580+#define NEXTDMA_NEXT_INIT 0x4200
581+#define NEXTDMA_SIZE 0x4204
582+
583+static void dma_writel(void *opaque, hwaddr addr, uint64_t value,
584+ unsigned int size)
585+{
586+ NeXTState *next_state = NEXT_MACHINE(opaque);
587+
588+ switch (addr) {
589+ case NEXTDMA_ENRX(NEXTDMA_CSR):
590+ if (value & DMA_DEV2M) {
591+ next_state->dma[NEXTDMA_ENRX].csr |= DMA_DEV2M;
592+ }
593+
594+ if (value & DMA_SETENABLE) {
595+ /* DPRINTF("SCSI DMA ENABLE\n"); */
596+ next_state->dma[NEXTDMA_ENRX].csr |= DMA_ENABLE;
597+ }
598+ if (value & DMA_SETSUPDATE) {
599+ next_state->dma[NEXTDMA_ENRX].csr |= DMA_SUPDATE;
600+ }
601+ if (value & DMA_CLRCOMPLETE) {
602+ next_state->dma[NEXTDMA_ENRX].csr &= ~DMA_COMPLETE;
603+ }
604+
605+ if (value & DMA_RESET) {
606+ next_state->dma[NEXTDMA_ENRX].csr &= ~(DMA_COMPLETE | DMA_SUPDATE |
607+ DMA_ENABLE | DMA_DEV2M);
608+ }
609+ /* DPRINTF("RXCSR \tWrite: %x\n",value); */
610+ break;
611+ case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
612+ next_state->dma[NEXTDMA_ENRX].next_initbuf = value;
613+ break;
614+ case NEXTDMA_ENRX(NEXTDMA_NEXT):
615+ next_state->dma[NEXTDMA_ENRX].next = value;
616+ break;
617+ case NEXTDMA_ENRX(NEXTDMA_LIMIT):
618+ next_state->dma[NEXTDMA_ENRX].limit = value;
619+ break;
620+ case NEXTDMA_SCSI(NEXTDMA_CSR):
621+ if (value & DMA_DEV2M) {
622+ next_state->dma[NEXTDMA_SCSI].csr |= DMA_DEV2M;
623+ }
624+ if (value & DMA_SETENABLE) {
625+ /* DPRINTF("SCSI DMA ENABLE\n"); */
626+ next_state->dma[NEXTDMA_SCSI].csr |= DMA_ENABLE;
627+ }
628+ if (value & DMA_SETSUPDATE) {
629+ next_state->dma[NEXTDMA_SCSI].csr |= DMA_SUPDATE;
630+ }
631+ if (value & DMA_CLRCOMPLETE) {
632+ next_state->dma[NEXTDMA_SCSI].csr &= ~DMA_COMPLETE;
633+ }
634+
635+ if (value & DMA_RESET) {
636+ next_state->dma[NEXTDMA_SCSI].csr &= ~(DMA_COMPLETE | DMA_SUPDATE |
637+ DMA_ENABLE | DMA_DEV2M);
638+ /* DPRINTF("SCSI DMA RESET\n"); */
639+ }
640+ /* DPRINTF("RXCSR \tWrite: %x\n",value); */
641+ break;
642+
643+ case NEXTDMA_SCSI(NEXTDMA_NEXT):
644+ next_state->dma[NEXTDMA_SCSI].next = value;
645+ break;
646+
647+ case NEXTDMA_SCSI(NEXTDMA_LIMIT):
648+ next_state->dma[NEXTDMA_SCSI].limit = value;
649+ break;
650+
651+ case NEXTDMA_SCSI(NEXTDMA_START):
652+ next_state->dma[NEXTDMA_SCSI].start = value;
653+ break;
654+
655+ case NEXTDMA_SCSI(NEXTDMA_STOP):
656+ next_state->dma[NEXTDMA_SCSI].stop = value;
657+ break;
658+
659+ case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
660+ next_state->dma[NEXTDMA_SCSI].next_initbuf = value;
661+ break;
662+
663+ default:
664+ DPRINTF("DMA write @ %x w/ %x\n", (unsigned)addr, (unsigned)value);
665+ }
666+}
667+
668+static uint64_t dma_readl(void *opaque, hwaddr addr, unsigned int size)
669+{
670+ NeXTState *next_state = NEXT_MACHINE(opaque);
671+
672+ switch (addr) {
673+ case NEXTDMA_SCSI(NEXTDMA_CSR):
674+ DPRINTF("SCSI DMA CSR READ\n");
675+ return next_state->dma[NEXTDMA_SCSI].csr;
676+ case NEXTDMA_ENRX(NEXTDMA_CSR):
677+ return next_state->dma[NEXTDMA_ENRX].csr;
678+ case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
679+ return next_state->dma[NEXTDMA_ENRX].next_initbuf;
680+ case NEXTDMA_ENRX(NEXTDMA_NEXT):
681+ return next_state->dma[NEXTDMA_ENRX].next;
682+ case NEXTDMA_ENRX(NEXTDMA_LIMIT):
683+ return next_state->dma[NEXTDMA_ENRX].limit;
684+
685+ case NEXTDMA_SCSI(NEXTDMA_NEXT):
686+ return next_state->dma[NEXTDMA_SCSI].next;
687+ case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
688+ return next_state->dma[NEXTDMA_SCSI].next_initbuf;
689+ case NEXTDMA_SCSI(NEXTDMA_LIMIT):
690+ return next_state->dma[NEXTDMA_SCSI].limit;
691+ case NEXTDMA_SCSI(NEXTDMA_START):
692+ return next_state->dma[NEXTDMA_SCSI].start;
693+ case NEXTDMA_SCSI(NEXTDMA_STOP):
694+ return next_state->dma[NEXTDMA_SCSI].stop;
695+
696+ default:
697+ DPRINTF("DMA read @ %x\n", (unsigned int)addr);
698+ return 0;
699+ }
700+
701+ /*
702+ * once the csr's are done, subtract 0x3FEC from the addr, and that will
703+ * normalize the upper registers
704+ */
705+}
706+
707+static const MemoryRegionOps dma_ops = {
708+ .read = dma_readl,
709+ .write = dma_writel,
710+ .impl.min_access_size = 4,
711+ .valid.min_access_size = 4,
712+ .valid.max_access_size = 4,
713+ .endianness = DEVICE_NATIVE_ENDIAN,
714+};
715+
716+/*
717+ * TODO: set the shift numbers as values in the enum, so the first switch
718+ * will not be needed
719+ */
720+void next_irq(void *opaque, int number, int level)
721+{
722+ M68kCPU *cpu = opaque;
723+ int shift = 0;
724+ NeXTState *ns = NEXT_MACHINE(qdev_get_machine());
725+
726+ /* first switch sets interupt status */
727+ /* DPRINTF("IRQ %i\n",number); */
728+ switch (number) {
729+ /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
730+ case NEXT_FD_I:
731+ shift = 7;;
732+ break;
733+ case NEXT_KBD_I:
734+ shift = 3;
735+ break;
736+ case NEXT_PWR_I:
737+ shift = 2;
738+ break;
739+ case NEXT_ENRX_I:
740+ shift = 9;
741+ break;
742+ case NEXT_ENTX_I:
743+ shift = 10;
744+ break;
745+ case NEXT_SCSI_I:
746+ shift = 12;
747+ break;
748+ case NEXT_CLK_I:
749+ shift = 5;
750+ break;
751+
752+ /* level 5 - scc (serial) */
753+ case NEXT_SCC_I:
754+ shift = 17;
755+ break;
756+
757+ /* level 6 - audio etherrx/tx dma */
758+ case NEXT_ENTX_DMA_I:
759+ shift = 28;
760+ break;
761+ case NEXT_ENRX_DMA_I:
762+ shift = 27;
763+ break;
764+ case NEXT_SCSI_DMA_I:
765+ shift = 26;
766+ break;
767+ case NEXT_SND_I:
768+ shift = 23;
769+ break;
770+ case NEXT_SCC_DMA_I:
771+ shift = 21;
772+ break;
773+
774+ }
775+ /*
776+ * this HAS to be wrong, the interrupt handlers in mach and together
777+ * int_status and int_mask and return if there is a hit
778+ */
779+ if (ns->int_mask & (1 << shift)) {
780+ DPRINTF("%x interrupt masked @ %x\n", 1 << shift, cpu->env.pc);
781+ /* return; */
782+ }
783+
784+ /* second switch triggers the correct interrupt */
785+ if (level) {
786+ ns->int_status |= 1 << shift;
787+
788+ switch (number) {
789+ /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
790+ case NEXT_FD_I:
791+ case NEXT_KBD_I:
792+ case NEXT_PWR_I:
793+ case NEXT_ENRX_I:
794+ case NEXT_ENTX_I:
795+ case NEXT_SCSI_I:
796+ case NEXT_CLK_I:
797+ m68k_set_irq_level(cpu, 3, 27);
798+ break;
799+
800+ /* level 5 - scc (serial) */
801+ case NEXT_SCC_I:
802+ m68k_set_irq_level(cpu, 5, 29);
803+ break;
804+
805+ /* level 6 - audio etherrx/tx dma */
806+ case NEXT_ENTX_DMA_I:
807+ case NEXT_ENRX_DMA_I:
808+ case NEXT_SCSI_DMA_I:
809+ case NEXT_SND_I:
810+ case NEXT_SCC_DMA_I:
811+ m68k_set_irq_level(cpu, 6, 30);
812+ break;
813+ }
814+ } else {
815+ ns->int_status &= ~(1 << shift);
816+ cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
817+ }
818+}
819+
820+static void next_serial_irq(void *opaque, int n, int level)
821+{
822+ /* DPRINTF("SCC IRQ NUM %i\n",n); */
823+ if (n) {
824+ next_irq(opaque, NEXT_SCC_DMA_I, level);
825+ } else {
826+ next_irq(opaque, NEXT_SCC_I, level);
827+ }
828+}
829+
830+static void next_escc_init(M68kCPU *cpu)
831+{
832+ qemu_irq *ser_irq = qemu_allocate_irqs(next_serial_irq, cpu, 2);
833+ DeviceState *dev;
834+ SysBusDevice *s;
835+
836+ dev = qdev_create(NULL, TYPE_ESCC);
837+ qdev_prop_set_uint32(dev, "disabled", 0);
838+ qdev_prop_set_uint32(dev, "frequency", 9600 * 384);
839+ qdev_prop_set_uint32(dev, "it_shift", 0);
840+ qdev_prop_set_bit(dev, "bit_swap", true);
841+ qdev_prop_set_chr(dev, "chrB", serial_hd(1));
842+ qdev_prop_set_chr(dev, "chrA", serial_hd(0));
843+ qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
844+ qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
845+ qdev_init_nofail(dev);
846+
847+ s = SYS_BUS_DEVICE(dev);
848+ sysbus_connect_irq(s, 0, ser_irq[0]);
849+ sysbus_connect_irq(s, 1, ser_irq[1]);
850+ sysbus_mmio_map(s, 0, 0x2118000);
851+}
852+
853+static void next_cube_init(MachineState *machine)
854+{
855+ M68kCPU *cpu;
856+ CPUM68KState *env;
857+ MemoryRegion *ram = g_new(MemoryRegion, 1);
858+ MemoryRegion *rom = g_new(MemoryRegion, 1);
859+ MemoryRegion *mmiomem = g_new(MemoryRegion, 1);
860+ MemoryRegion *scrmem = g_new(MemoryRegion, 1);
861+ MemoryRegion *dmamem = g_new(MemoryRegion, 1);
862+ MemoryRegion *bmapm1 = g_new(MemoryRegion, 1);
863+ MemoryRegion *bmapm2 = g_new(MemoryRegion, 1);
864+ MemoryRegion *sysmem = get_system_memory();
865+ NeXTState *ns = NEXT_MACHINE(machine);
866+ DeviceState *dev;
867+
868+ /* Initialize the cpu core */
869+ cpu = M68K_CPU(cpu_create(machine->cpu_type));
870+ if (!cpu) {
871+ error_report("Unable to find m68k CPU definition");
872+ exit(1);
873+ }
874+ env = &cpu->env;
875+
876+ /* Initialize CPU registers. */
877+ env->vbr = 0;
878+ env->sr = 0x2700;
879+
880+ /* Set internal registers to initial values */
881+ /* 0x0000XX00 << vital bits */
882+ ns->scr1 = 0x00011102;
883+ ns->scr2 = 0x00ff0c80;
884+
885+ /* Load RTC RAM - TODO: provide possibility to load contents from file */
886+ memcpy(ns->rtc_ram, rtc_ram2, 32);
887+
888+ /* 64MB RAM starting at 0x04000000 */
889+ memory_region_allocate_system_memory(ram, NULL, "next.ram", ram_size);
890+ memory_region_add_subregion(sysmem, 0x04000000, ram);
891+
892+ /* Framebuffer */
893+ dev = qdev_create(NULL, TYPE_NEXTFB);
894+ qdev_init_nofail(dev);
895+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0B000000);
896+
897+ /* MMIO */
898+ memory_region_init_io(mmiomem, NULL, &mmio_ops, machine, "next.mmio",
899+ 0xD0000);
900+ memory_region_add_subregion(sysmem, 0x02000000, mmiomem);
901+
902+ /* BMAP memory */
903+ memory_region_init_ram_shared_nomigrate(bmapm1, NULL, "next.bmapmem", 64,
904+ true, &error_fatal);
905+ memory_region_add_subregion(sysmem, 0x020c0000, bmapm1);
906+ /* The Rev_2.5_v66.bin firmware accesses it at 0x820c0020, too */
907+ memory_region_init_alias(bmapm2, NULL, "next.bmapmem2", bmapm1, 0x0, 64);
908+ memory_region_add_subregion(sysmem, 0x820c0000, bmapm2);
909+
910+ /* BMAP IO - acts as a catch-all for now */
911+ memory_region_init_io(scrmem, NULL, &scr_ops, machine, "next.scr",
912+ 0x20000);
913+ memory_region_add_subregion(sysmem, 0x02100000, scrmem);
914+
915+ /* KBD */
916+ dev = qdev_create(NULL, TYPE_NEXTKBD);
917+ qdev_init_nofail(dev);
918+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0200e000);
919+
920+ /* Load ROM here */
921+ if (bios_name == NULL) {
922+ bios_name = ROM_FILE;
923+ }
924+ /* still not sure if the rom should also be mapped at 0x0*/
925+ memory_region_init_rom(rom, NULL, "next.rom", 0x20000, &error_fatal);
926+ memory_region_add_subregion(sysmem, 0x01000000, rom);
927+ if (load_image_targphys(bios_name, 0x01000000, 0x20000) < 8) {
928+ if (!qtest_enabled()) {
929+ error_report("Failed to load firmware '%s'.", bios_name);
930+ }
931+ } else {
932+ uint8_t *ptr;
933+ /* Initial PC is always at offset 4 in firmware binaries */
934+ ptr = rom_ptr(0x01000004, 4);
935+ g_assert(ptr != NULL);
936+ env->pc = ldl_p(ptr);
937+ if (env->pc >= 0x01020000) {
938+ error_report("'%s' does not seem to be a valid firmware image.",
939+ bios_name);
940+ exit(1);
941+ }
942+ }
943+
944+ /* Serial */
945+ next_escc_init(cpu);
946+
947+ /* TODO: */
948+ /* Network */
949+ /* SCSI */
950+
951+ /* DMA */
952+ memory_region_init_io(dmamem, NULL, &dma_ops, machine, "next.dma", 0x5000);
953+ memory_region_add_subregion(sysmem, 0x02000000, dmamem);
954+}
955+
956+static void next_machine_class_init(ObjectClass *oc, void *data)
957+{
958+ MachineClass *mc = MACHINE_CLASS(oc);
959+
960+ mc->desc = "NeXT Cube";
961+ mc->init = next_cube_init;
962+ mc->default_ram_size = RAM_SIZE;
963+ mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
964+}
965+
966+static const TypeInfo next_typeinfo = {
967+ .name = TYPE_NEXT_MACHINE,
968+ .parent = TYPE_MACHINE,
969+ .class_init = next_machine_class_init,
970+ .instance_size = sizeof(NeXTState),
971+};
972+
973+static void next_register_type(void)
974+{
975+ type_register_static(&next_typeinfo);
976+}
977+
978+type_init(next_register_type)
--- /dev/null
+++ b/hw/m68k/next-kbd.c
@@ -0,0 +1,291 @@
1+/*
2+ * QEMU NeXT Keyboard/Mouse emulation
3+ *
4+ * Copyright (c) 2011 Bryce Lanham
5+ *
6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7+ * of this software and associated documentation files (the "Software"), to deal
8+ * in the Software without restriction, including without limitation the rights
9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+ * THE SOFTWARE.
23+ */
24+
25+/*
26+ * This is admittedly hackish, but works well enough for basic input. Mouse
27+ * support will be added once we can boot something that needs the mouse.
28+ */
29+
30+#include "qemu/osdep.h"
31+#include "qemu/log.h"
32+#include "exec/address-spaces.h"
33+#include "hw/hw.h"
34+#include "hw/sysbus.h"
35+#include "hw/m68k/next-cube.h"
36+#include "ui/console.h"
37+#include "sysemu/sysemu.h"
38+#include "migration/vmstate.h"
39+
40+#define NEXTKBD(obj) OBJECT_CHECK(NextKBDState, (obj), TYPE_NEXTKBD)
41+
42+/* following defintions from next68k netbsd */
43+#define CSR_INT 0x00800000
44+#define CSR_DATA 0x00400000
45+
46+#define KD_KEYMASK 0x007f
47+#define KD_DIRECTION 0x0080 /* pressed or released */
48+#define KD_CNTL 0x0100
49+#define KD_LSHIFT 0x0200
50+#define KD_RSHIFT 0x0400
51+#define KD_LCOMM 0x0800
52+#define KD_RCOMM 0x1000
53+#define KD_LALT 0x2000
54+#define KD_RALT 0x4000
55+#define KD_VALID 0x8000 /* only set for scancode keys ? */
56+#define KD_MODS 0x4f00
57+
58+#define KBD_QUEUE_SIZE 256
59+
60+typedef struct {
61+ uint8_t data[KBD_QUEUE_SIZE];
62+ int rptr, wptr, count;
63+} KBDQueue;
64+
65+
66+typedef struct NextKBDState {
67+ SysBusDevice sbd;
68+ MemoryRegion mr;
69+ KBDQueue queue;
70+ uint16_t shift;
71+} NextKBDState;
72+
73+static void queue_code(void *opaque, int code);
74+
75+/* lots of magic numbers here */
76+static uint32_t kbd_read_byte(void *opaque, hwaddr addr)
77+{
78+ switch (addr & 0x3) {
79+ case 0x0: /* 0xe000 */
80+ return 0x80 | 0x20;
81+
82+ case 0x1: /* 0xe001 */
83+ return 0x80 | 0x40 | 0x20 | 0x10;
84+
85+ case 0x2: /* 0xe002 */
86+ /* returning 0x40 caused mach to hang */
87+ return 0x10 | 0x2 | 0x1;
88+
89+ default:
90+ qemu_log_mask(LOG_UNIMP, "NeXT kbd read byte %"HWADDR_PRIx"\n", addr);
91+ }
92+
93+ return 0;
94+}
95+
96+static uint32_t kbd_read_word(void *opaque, hwaddr addr)
97+{
98+ qemu_log_mask(LOG_UNIMP, "NeXT kbd read word %"HWADDR_PRIx"\n", addr);
99+ return 0;
100+}
101+
102+/* even more magic numbers */
103+static uint32_t kbd_read_long(void *opaque, hwaddr addr)
104+{
105+ int key = 0;
106+ NextKBDState *s = NEXTKBD(opaque);
107+ KBDQueue *q = &s->queue;
108+
109+ switch (addr & 0xf) {
110+ case 0x0: /* 0xe000 */
111+ return 0xA0F09300;
112+
113+ case 0x8: /* 0xe008 */
114+ /* get keycode from buffer */
115+ if (q->count > 0) {
116+ key = q->data[q->rptr];
117+ if (++q->rptr == KBD_QUEUE_SIZE) {
118+ q->rptr = 0;
119+ }
120+
121+ q->count--;
122+
123+ if (s->shift) {
124+ key |= s->shift;
125+ }
126+
127+ if (key & 0x80) {
128+ return 0;
129+ } else {
130+ return 0x10000000 | KD_VALID | key;
131+ }
132+ } else {
133+ return 0;
134+ }
135+
136+ default:
137+ qemu_log_mask(LOG_UNIMP, "NeXT kbd read long %"HWADDR_PRIx"\n", addr);
138+ return 0;
139+ }
140+}
141+
142+static uint64_t kbd_readfn(void *opaque, hwaddr addr, unsigned size)
143+{
144+ switch (size) {
145+ case 1:
146+ return kbd_read_byte(opaque, addr);
147+ case 2:
148+ return kbd_read_word(opaque, addr);
149+ case 4:
150+ return kbd_read_long(opaque, addr);
151+ default:
152+ g_assert_not_reached();
153+ }
154+}
155+
156+static void kbd_writefn(void *opaque, hwaddr addr, uint64_t value,
157+ unsigned size)
158+{
159+ qemu_log_mask(LOG_UNIMP, "NeXT kbd write: size=%u addr=0x%"HWADDR_PRIx
160+ "val=0x%"PRIx64"\n", size, addr, value);
161+}
162+
163+static const MemoryRegionOps kbd_ops = {
164+ .read = kbd_readfn,
165+ .write = kbd_writefn,
166+ .valid.min_access_size = 1,
167+ .valid.max_access_size = 4,
168+ .endianness = DEVICE_NATIVE_ENDIAN,
169+};
170+
171+static void nextkbd_event(void *opaque, int ch)
172+{
173+ /*
174+ * Will want to set vars for caps/num lock
175+ * if (ch & 0x80) -> key release
176+ * there's also e0 escaped scancodes that might need to be handled
177+ */
178+ queue_code(opaque, ch);
179+}
180+
181+static const unsigned char next_keycodes[128] = {
182+ 0x00, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x50, 0x4F,
183+ 0x4E, 0x1E, 0x1F, 0x20, 0x1D, 0x1C, 0x1B, 0x00,
184+ 0x42, 0x43, 0x44, 0x45, 0x48, 0x47, 0x46, 0x06,
185+ 0x07, 0x08, 0x00, 0x00, 0x2A, 0x00, 0x39, 0x3A,
186+ 0x3B, 0x3C, 0x3D, 0x40, 0x3F, 0x3E, 0x2D, 0x2C,
187+ 0x2B, 0x26, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34,
188+ 0x35, 0x37, 0x36, 0x2e, 0x2f, 0x30, 0x00, 0x00,
189+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
191+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
192+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
193+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
194+};
195+
196+static void queue_code(void *opaque, int code)
197+{
198+ NextKBDState *s = NEXTKBD(opaque);
199+ KBDQueue *q = &s->queue;
200+ int key = code & KD_KEYMASK;
201+ int release = code & 0x80;
202+ static int ext;
203+
204+ if (code == 0xE0) {
205+ ext = 1;
206+ }
207+
208+ if (code == 0x2A || code == 0x1D || code == 0x36) {
209+ if (code == 0x2A) {
210+ s->shift = KD_LSHIFT;
211+ } else if (code == 0x36) {
212+ s->shift = KD_RSHIFT;
213+ ext = 0;
214+ } else if (code == 0x1D && !ext) {
215+ s->shift = KD_LCOMM;
216+ } else if (code == 0x1D && ext) {
217+ ext = 0;
218+ s->shift = KD_RCOMM;
219+ }
220+ return;
221+ } else if (code == (0x2A | 0x80) || code == (0x1D | 0x80) ||
222+ code == (0x36 | 0x80)) {
223+ s->shift = 0;
224+ return;
225+ }
226+
227+ if (q->count >= KBD_QUEUE_SIZE) {
228+ return;
229+ }
230+
231+ q->data[q->wptr] = next_keycodes[key] | release;
232+
233+ if (++q->wptr == KBD_QUEUE_SIZE) {
234+ q->wptr = 0;
235+ }
236+
237+ q->count++;
238+
239+ /*
240+ * might need to actually trigger the NeXT irq, but as the keyboard works
241+ * at the moment, I'll worry about it later
242+ */
243+ /* s->update_irq(s->update_arg, 1); */
244+}
245+
246+static void nextkbd_reset(DeviceState *dev)
247+{
248+ NextKBDState *nks = NEXTKBD(dev);
249+
250+ memset(&nks->queue, 0, sizeof(KBDQueue));
251+ nks->shift = 0;
252+}
253+
254+static void nextkbd_realize(DeviceState *dev, Error **errp)
255+{
256+ NextKBDState *s = NEXTKBD(dev);
257+
258+ memory_region_init_io(&s->mr, OBJECT(dev), &kbd_ops, s, "next.kbd", 0x1000);
259+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
260+
261+ qemu_add_kbd_event_handler(nextkbd_event, s);
262+}
263+
264+static const VMStateDescription nextkbd_vmstate = {
265+ .name = TYPE_NEXTKBD,
266+ .unmigratable = 1, /* TODO: Implement this when m68k CPU is migratable */
267+};
268+
269+static void nextkbd_class_init(ObjectClass *oc, void *data)
270+{
271+ DeviceClass *dc = DEVICE_CLASS(oc);
272+
273+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
274+ dc->vmsd = &nextkbd_vmstate;
275+ dc->realize = nextkbd_realize;
276+ dc->reset = nextkbd_reset;
277+}
278+
279+static const TypeInfo nextkbd_info = {
280+ .name = TYPE_NEXTKBD,
281+ .parent = TYPE_SYS_BUS_DEVICE,
282+ .instance_size = sizeof(NextKBDState),
283+ .class_init = nextkbd_class_init,
284+};
285+
286+static void nextkbd_register_types(void)
287+{
288+ type_register_static(&nextkbd_info);
289+}
290+
291+type_init(nextkbd_register_types)
--- a/include/hw/char/escc.h
+++ b/include/hw/char/escc.h
@@ -51,6 +51,7 @@ typedef struct ESCCState {
5151
5252 struct ESCCChannelState chn[2];
5353 uint32_t it_shift;
54+ bool bit_swap;
5455 MemoryRegion mmio;
5556 uint32_t disabled;
5657 uint32_t frequency;
--- /dev/null
+++ b/include/hw/m68k/next-cube.h
@@ -0,0 +1,47 @@
1+
2+#ifndef NEXT_CUBE_H
3+#define NEXT_CUBE_H
4+
5+#define TYPE_NEXTFB "next-fb"
6+
7+#define TYPE_NEXTKBD "next-kbd"
8+
9+enum next_dma_chan {
10+ NEXTDMA_FD,
11+ NEXTDMA_ENRX,
12+ NEXTDMA_ENTX,
13+ NEXTDMA_SCSI,
14+ NEXTDMA_SCC,
15+ NEXTDMA_SND
16+};
17+
18+#define DMA_ENABLE 0x01000000
19+#define DMA_SUPDATE 0x02000000
20+#define DMA_COMPLETE 0x08000000
21+
22+#define DMA_M2DEV 0x0
23+#define DMA_SETENABLE 0x00010000
24+#define DMA_SETSUPDATE 0x00020000
25+#define DMA_DEV2M 0x00040000
26+#define DMA_CLRCOMPLETE 0x00080000
27+#define DMA_RESET 0x00100000
28+
29+enum next_irqs {
30+ NEXT_FD_I,
31+ NEXT_KBD_I,
32+ NEXT_PWR_I,
33+ NEXT_ENRX_I,
34+ NEXT_ENTX_I,
35+ NEXT_SCSI_I,
36+ NEXT_CLK_I,
37+ NEXT_SCC_I,
38+ NEXT_ENTX_DMA_I,
39+ NEXT_ENRX_DMA_I,
40+ NEXT_SCSI_DMA_I,
41+ NEXT_SCC_DMA_I,
42+ NEXT_SND_I
43+};
44+
45+void next_irq(void *opaque, int number, int level);
46+
47+#endif /* NEXT_CUBE_H */
--- /dev/null
+++ b/tests/acceptance/machine_m68k_nextcube.py
@@ -0,0 +1,121 @@
1+# Functional test that boots a VM and run OCR on the framebuffer
2+#
3+# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org>
4+#
5+# This work is licensed under the terms of the GNU GPL, version 2 or
6+# later. See the COPYING file in the top-level directory.
7+
8+import os
9+import re
10+import time
11+import logging
12+import distutils.spawn
13+
14+from avocado_qemu import Test
15+from avocado import skipUnless
16+from avocado.utils import process
17+from avocado.utils.path import find_command, CmdNotFoundError
18+
19+PIL_AVAILABLE = True
20+try:
21+ from PIL import Image
22+except ImportError:
23+ PIL_AVAILABLE = False
24+
25+
26+def tesseract_available(expected_version):
27+ try:
28+ find_command('tesseract')
29+ except CmdNotFoundError:
30+ return False
31+ res = process.run('tesseract --version')
32+ try:
33+ version = res.stdout_text.split()[1]
34+ except IndexError:
35+ version = res.stderr_text.split()[1]
36+ return int(version.split('.')[0]) == expected_version
37+
38+ match = re.match(r'tesseract\s(\d)', res)
39+ if match is None:
40+ return False
41+ # now this is guaranteed to be a digit
42+ return int(match.groups()[0]) == expected_version
43+
44+
45+class NextCubeMachine(Test):
46+
47+ timeout = 15
48+
49+ def check_bootrom_framebuffer(self, screenshot_path):
50+ rom_url = ('http://www.nextcomputers.org/NeXTfiles/Software/ROM_Files/'
51+ '68040_Non-Turbo_Chipset/Rev_2.5_v66.BIN')
52+ rom_hash = 'b3534796abae238a0111299fc406a9349f7fee24'
53+ rom_path = self.fetch_asset(rom_url, asset_hash=rom_hash)
54+
55+ self.vm.set_machine('next-cube')
56+ self.vm.add_args('-bios', rom_path)
57+ self.vm.launch()
58+
59+ self.log.info('VM launched, waiting for display')
60+ # TODO: Use avocado.utils.wait.wait_for to catch the
61+ # 'displaysurface_create 1120x832' trace-event.
62+ time.sleep(2)
63+
64+ self.vm.command('human-monitor-command',
65+ command_line='screendump %s' % screenshot_path)
66+
67+ @skipUnless(PIL_AVAILABLE, 'Python PIL not installed')
68+ def test_bootrom_framebuffer_size(self):
69+ """
70+ :avocado: tags=arch:m68k
71+ :avocado: tags=machine:next_cube
72+ :avocado: tags=device:framebuffer
73+ """
74+ screenshot_path = os.path.join(self.workdir, "dump.png")
75+ self.check_bootrom_framebuffer(screenshot_path)
76+
77+ width, height = Image.open(screenshot_path).size
78+ self.assertEqual(width, 1120)
79+ self.assertEqual(height, 832)
80+
81+ @skipUnless(tesseract_available(3), 'tesseract v3 OCR tool not available')
82+ def test_bootrom_framebuffer_ocr_with_tesseract_v3(self):
83+ """
84+ :avocado: tags=arch:m68k
85+ :avocado: tags=machine:next_cube
86+ :avocado: tags=device:framebuffer
87+ """
88+ screenshot_path = os.path.join(self.workdir, "dump.png")
89+ self.check_bootrom_framebuffer(screenshot_path)
90+
91+ console_logger = logging.getLogger('console')
92+ text = process.run("tesseract %s stdout" % screenshot_path).stdout_text
93+ for line in text.split('\n'):
94+ if len(line):
95+ console_logger.debug(line)
96+ self.assertIn('Backplane', text)
97+ self.assertIn('Ethernet address', text)
98+
99+ # Tesseract 4 adds a new OCR engine based on LSTM neural networks. The
100+ # new version is faster and more accurate than version 3. The drawback is
101+ # that it is still alpha-level software.
102+ @skipUnless(tesseract_available(4), 'tesseract v4 OCR tool not available')
103+ def test_bootrom_framebuffer_ocr_with_tesseract_v4(self):
104+ """
105+ :avocado: tags=arch:m68k
106+ :avocado: tags=machine:next_cube
107+ :avocado: tags=device:framebuffer
108+ """
109+ screenshot_path = os.path.join(self.workdir, "dump.png")
110+ self.check_bootrom_framebuffer(screenshot_path)
111+
112+ console_logger = logging.getLogger('console')
113+ proc = process.run("tesseract --oem 1 %s stdout" % screenshot_path)
114+ text = proc.stdout_text
115+ for line in text.split('\n'):
116+ if len(line):
117+ console_logger.debug(line)
118+ self.assertIn('Testing the FPU, SCC', text)
119+ self.assertIn('System test failed. Error code 51', text)
120+ self.assertIn('Boot command', text)
121+ self.assertIn('Next>', text)
--- a/tests/boot-serial-test.c
+++ b/tests/boot-serial-test.c
@@ -24,6 +24,17 @@ static const uint8_t kernel_mcf5208[] = {
2424 0x60, 0xfa /* bra.s loop */
2525 };
2626
27+static const uint8_t bios_nextcube[] = {
28+ 0x06, 0x00, 0x00, 0x00, /* Initial SP */
29+ 0x01, 0x00, 0x00, 0x08, /* Initial PC */
30+ 0x41, 0xf9, 0x02, 0x11, 0x80, 0x00, /* lea 0x02118000,%a0 */
31+ 0x10, 0x3c, 0x00, 0x54, /* move.b #'T',%d0 */
32+ 0x11, 0x7c, 0x00, 0x05, 0x00, 0x01, /* move.b #5,1(%a0) Sel TXCTRL */
33+ 0x11, 0x7c, 0x00, 0x68, 0x00, 0x01, /* move.b #0x68,1(%a0) Enable TX */
34+ 0x11, 0x40, 0x00, 0x03, /* move.b %d0,3(%a0) Print 'T' */
35+ 0x60, 0xfa /* bra.s loop */
36+};
37+
2738 static const uint8_t kernel_pls3adsp1800[] = {
2839 0xb0, 0x00, 0x84, 0x00, /* imm 0x8400 */
2940 0x30, 0x60, 0x00, 0x04, /* addik r3,r0,4 */
@@ -117,6 +128,7 @@ static testdef_t tests[] = {
117128 { "sparc64", "sun4u", "", "UltraSPARC" },
118129 { "s390x", "s390-ccw-virtio", "", "device" },
119130 { "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 },
131+ { "m68k", "next-cube", "", "TT", sizeof(bios_nextcube), 0, bios_nextcube },
120132 { "microblaze", "petalogix-s3adsp1800", "", "TT",
121133 sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 },
122134 { "microblazeel", "petalogix-ml605", "", "TT",