mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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>
This commit is contained in:
+6
-1
@@ -232,15 +232,20 @@ matrix:
|
||||
|
||||
# Acceptance (Functional) tests
|
||||
- env:
|
||||
- CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu,ppc64-softmmu"
|
||||
- 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"
|
||||
- TEST_CMD="make check-acceptance"
|
||||
after_failure:
|
||||
- cat tests/results/latest/job.log
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3-pil
|
||||
- python3-pip
|
||||
- python3.5-venv
|
||||
- tesseract-ocr
|
||||
- tesseract-ocr-eng
|
||||
|
||||
|
||||
# Using newer GCC with sanitizers
|
||||
- addons:
|
||||
apt:
|
||||
|
||||
@@ -910,6 +910,13 @@ F: hw/char/mcf_uart.c
|
||||
F: hw/net/mcf_fec.c
|
||||
F: include/hw/m68k/mcf*.h
|
||||
|
||||
NeXTcube
|
||||
M: Thomas Huth <huth@tuxfamily.org>
|
||||
S: Odd Fixes
|
||||
F: hw/m68k/next-*.c
|
||||
F: hw/display/next-fb.c
|
||||
F: include/hw/m68k/next-cube.h
|
||||
|
||||
MicroBlaze Machines
|
||||
-------------------
|
||||
petalogix_s3adsp1800
|
||||
|
||||
@@ -6,3 +6,4 @@ CONFIG_SEMIHOSTING=y
|
||||
#
|
||||
CONFIG_AN5206=y
|
||||
CONFIG_MCF5208=y
|
||||
CONFIG_NEXTCUBE=y
|
||||
|
||||
+24
-6
@@ -45,14 +45,21 @@
|
||||
* mouse and keyboard ports don't implement all functions and they are
|
||||
* only asynchronous. There is no DMA.
|
||||
*
|
||||
* Z85C30 is also used on PowerMacs. There are some small differences
|
||||
* between Sparc version (sunzilog) and PowerMac (pmac):
|
||||
* Z85C30 is also used on PowerMacs and m68k Macs.
|
||||
*
|
||||
* There are some small differences between Sparc version (sunzilog)
|
||||
* and PowerMac (pmac):
|
||||
* Offset between control and data registers
|
||||
* There is some kind of lockup bug, but we can ignore it
|
||||
* CTS is inverted
|
||||
* DMA on pmac using DBDMA chip
|
||||
* pmac can do IRDA and faster rates, sunzilog can only do 38400
|
||||
* pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz
|
||||
*
|
||||
* Linux driver for m68k Macs is the same as for PowerMac (pmac_zilog),
|
||||
* but registers are grouped by type and not by channel:
|
||||
* channel is selected by bit 0 of the address (instead of bit 1)
|
||||
* and register is selected by bit 1 of the address (instead of bit 0).
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -172,6 +179,16 @@ static void handle_kbd_command(ESCCChannelState *s, int val);
|
||||
static int serial_can_receive(void *opaque);
|
||||
static void serial_receive_byte(ESCCChannelState *s, int ch);
|
||||
|
||||
static int reg_shift(ESCCState *s)
|
||||
{
|
||||
return s->bit_swap ? s->it_shift + 1 : s->it_shift;
|
||||
}
|
||||
|
||||
static int chn_shift(ESCCState *s)
|
||||
{
|
||||
return s->bit_swap ? s->it_shift : s->it_shift + 1;
|
||||
}
|
||||
|
||||
static void clear_queue(void *opaque)
|
||||
{
|
||||
ESCCChannelState *s = opaque;
|
||||
@@ -436,8 +453,8 @@ static void escc_mem_write(void *opaque, hwaddr addr,
|
||||
int newreg, channel;
|
||||
|
||||
val &= 0xff;
|
||||
saddr = (addr >> serial->it_shift) & 1;
|
||||
channel = (addr >> (serial->it_shift + 1)) & 1;
|
||||
saddr = (addr >> reg_shift(serial)) & 1;
|
||||
channel = (addr >> chn_shift(serial)) & 1;
|
||||
s = &serial->chn[channel];
|
||||
switch (saddr) {
|
||||
case SERIAL_CTRL:
|
||||
@@ -547,8 +564,8 @@ static uint64_t escc_mem_read(void *opaque, hwaddr addr,
|
||||
uint32_t ret;
|
||||
int channel;
|
||||
|
||||
saddr = (addr >> serial->it_shift) & 1;
|
||||
channel = (addr >> (serial->it_shift + 1)) & 1;
|
||||
saddr = (addr >> reg_shift(serial)) & 1;
|
||||
channel = (addr >> chn_shift(serial)) & 1;
|
||||
s = &serial->chn[channel];
|
||||
switch (saddr) {
|
||||
case SERIAL_CTRL:
|
||||
@@ -832,6 +849,7 @@ static void escc_realize(DeviceState *dev, Error **errp)
|
||||
static Property escc_properties[] = {
|
||||
DEFINE_PROP_UINT32("frequency", ESCCState, frequency, 0),
|
||||
DEFINE_PROP_UINT32("it_shift", ESCCState, it_shift, 0),
|
||||
DEFINE_PROP_BOOL("bit_swap", ESCCState, bit_swap, false),
|
||||
DEFINE_PROP_UINT32("disabled", ESCCState, disabled, 0),
|
||||
DEFINE_PROP_UINT32("chnBtype", ESCCState, chn[0].type, 0),
|
||||
DEFINE_PROP_UINT32("chnAtype", ESCCState, chn[1].type, 0),
|
||||
|
||||
@@ -38,6 +38,7 @@ common-obj-$(CONFIG_RASPI) += bcm2835_fb.o
|
||||
common-obj-$(CONFIG_SM501) += sm501.o
|
||||
common-obj-$(CONFIG_TCX) += tcx.o
|
||||
common-obj-$(CONFIG_CG3) += cg3.o
|
||||
common-obj-$(CONFIG_NEXTCUBE) += next-fb.o
|
||||
|
||||
obj-$(CONFIG_VGA) += vga.o
|
||||
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 "qapi/error.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/display/framebuffer.h"
|
||||
#include "ui/pixel_ops.h"
|
||||
#include "hw/m68k/next-cube.h"
|
||||
|
||||
#define NEXTFB(obj) OBJECT_CHECK(NeXTFbState, (obj), TYPE_NEXTFB)
|
||||
|
||||
struct NeXTFbState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion fb_mr;
|
||||
MemoryRegionSection fbsection;
|
||||
QemuConsole *con;
|
||||
|
||||
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);
|
||||
static const 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, s->cols, s->rows,
|
||||
src_width, dest_width, 0, 1, nextfb_draw_line,
|
||||
s, &first, &last);
|
||||
|
||||
dpy_gfx_update(s->con, 0, 0, s->cols, s->rows);
|
||||
}
|
||||
|
||||
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_init_ram(&s->fb_mr, OBJECT(dev), "next-video", 0x1CB100,
|
||||
&error_fatal);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &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;
|
||||
|
||||
/* Note: This device does not any state that we have to reset or migrate */
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -7,3 +7,8 @@ config MCF5208
|
||||
bool
|
||||
select COLDFIRE
|
||||
select PTIMER
|
||||
|
||||
config NEXTCUBE
|
||||
bool
|
||||
select FRAMEBUFFER
|
||||
select ESCC
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
obj-$(CONFIG_AN5206) += an5206.o mcf5206.o
|
||||
obj-$(CONFIG_MCF5208) += mcf5208.o mcf_intc.o
|
||||
obj-$(CONFIG_NEXTCUBE) += next-kbd.o next-cube.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* QEMU NeXT Keyboard/Mouse 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is admittedly hackish, but works well enough for basic input. Mouse
|
||||
* support will be added once we can boot something that needs the mouse.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/m68k/next-cube.h"
|
||||
#include "ui/console.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
#define NEXTKBD(obj) OBJECT_CHECK(NextKBDState, (obj), TYPE_NEXTKBD)
|
||||
|
||||
/* following defintions from next68k netbsd */
|
||||
#define CSR_INT 0x00800000
|
||||
#define CSR_DATA 0x00400000
|
||||
|
||||
#define KD_KEYMASK 0x007f
|
||||
#define KD_DIRECTION 0x0080 /* pressed or released */
|
||||
#define KD_CNTL 0x0100
|
||||
#define KD_LSHIFT 0x0200
|
||||
#define KD_RSHIFT 0x0400
|
||||
#define KD_LCOMM 0x0800
|
||||
#define KD_RCOMM 0x1000
|
||||
#define KD_LALT 0x2000
|
||||
#define KD_RALT 0x4000
|
||||
#define KD_VALID 0x8000 /* only set for scancode keys ? */
|
||||
#define KD_MODS 0x4f00
|
||||
|
||||
#define KBD_QUEUE_SIZE 256
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[KBD_QUEUE_SIZE];
|
||||
int rptr, wptr, count;
|
||||
} KBDQueue;
|
||||
|
||||
|
||||
typedef struct NextKBDState {
|
||||
SysBusDevice sbd;
|
||||
MemoryRegion mr;
|
||||
KBDQueue queue;
|
||||
uint16_t shift;
|
||||
} NextKBDState;
|
||||
|
||||
static void queue_code(void *opaque, int code);
|
||||
|
||||
/* lots of magic numbers here */
|
||||
static uint32_t kbd_read_byte(void *opaque, hwaddr addr)
|
||||
{
|
||||
switch (addr & 0x3) {
|
||||
case 0x0: /* 0xe000 */
|
||||
return 0x80 | 0x20;
|
||||
|
||||
case 0x1: /* 0xe001 */
|
||||
return 0x80 | 0x40 | 0x20 | 0x10;
|
||||
|
||||
case 0x2: /* 0xe002 */
|
||||
/* returning 0x40 caused mach to hang */
|
||||
return 0x10 | 0x2 | 0x1;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "NeXT kbd read byte %"HWADDR_PRIx"\n", addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t kbd_read_word(void *opaque, hwaddr addr)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "NeXT kbd read word %"HWADDR_PRIx"\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* even more magic numbers */
|
||||
static uint32_t kbd_read_long(void *opaque, hwaddr addr)
|
||||
{
|
||||
int key = 0;
|
||||
NextKBDState *s = NEXTKBD(opaque);
|
||||
KBDQueue *q = &s->queue;
|
||||
|
||||
switch (addr & 0xf) {
|
||||
case 0x0: /* 0xe000 */
|
||||
return 0xA0F09300;
|
||||
|
||||
case 0x8: /* 0xe008 */
|
||||
/* get keycode from buffer */
|
||||
if (q->count > 0) {
|
||||
key = q->data[q->rptr];
|
||||
if (++q->rptr == KBD_QUEUE_SIZE) {
|
||||
q->rptr = 0;
|
||||
}
|
||||
|
||||
q->count--;
|
||||
|
||||
if (s->shift) {
|
||||
key |= s->shift;
|
||||
}
|
||||
|
||||
if (key & 0x80) {
|
||||
return 0;
|
||||
} else {
|
||||
return 0x10000000 | KD_VALID | key;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "NeXT kbd read long %"HWADDR_PRIx"\n", addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t kbd_readfn(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return kbd_read_byte(opaque, addr);
|
||||
case 2:
|
||||
return kbd_read_word(opaque, addr);
|
||||
case 4:
|
||||
return kbd_read_long(opaque, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void kbd_writefn(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "NeXT kbd write: size=%u addr=0x%"HWADDR_PRIx
|
||||
"val=0x%"PRIx64"\n", size, addr, value);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps kbd_ops = {
|
||||
.read = kbd_readfn,
|
||||
.write = kbd_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void nextkbd_event(void *opaque, int ch)
|
||||
{
|
||||
/*
|
||||
* Will want to set vars for caps/num lock
|
||||
* if (ch & 0x80) -> key release
|
||||
* there's also e0 escaped scancodes that might need to be handled
|
||||
*/
|
||||
queue_code(opaque, ch);
|
||||
}
|
||||
|
||||
static const unsigned char next_keycodes[128] = {
|
||||
0x00, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x50, 0x4F,
|
||||
0x4E, 0x1E, 0x1F, 0x20, 0x1D, 0x1C, 0x1B, 0x00,
|
||||
0x42, 0x43, 0x44, 0x45, 0x48, 0x47, 0x46, 0x06,
|
||||
0x07, 0x08, 0x00, 0x00, 0x2A, 0x00, 0x39, 0x3A,
|
||||
0x3B, 0x3C, 0x3D, 0x40, 0x3F, 0x3E, 0x2D, 0x2C,
|
||||
0x2B, 0x26, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34,
|
||||
0x35, 0x37, 0x36, 0x2e, 0x2f, 0x30, 0x00, 0x00,
|
||||
0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static void queue_code(void *opaque, int code)
|
||||
{
|
||||
NextKBDState *s = NEXTKBD(opaque);
|
||||
KBDQueue *q = &s->queue;
|
||||
int key = code & KD_KEYMASK;
|
||||
int release = code & 0x80;
|
||||
static int ext;
|
||||
|
||||
if (code == 0xE0) {
|
||||
ext = 1;
|
||||
}
|
||||
|
||||
if (code == 0x2A || code == 0x1D || code == 0x36) {
|
||||
if (code == 0x2A) {
|
||||
s->shift = KD_LSHIFT;
|
||||
} else if (code == 0x36) {
|
||||
s->shift = KD_RSHIFT;
|
||||
ext = 0;
|
||||
} else if (code == 0x1D && !ext) {
|
||||
s->shift = KD_LCOMM;
|
||||
} else if (code == 0x1D && ext) {
|
||||
ext = 0;
|
||||
s->shift = KD_RCOMM;
|
||||
}
|
||||
return;
|
||||
} else if (code == (0x2A | 0x80) || code == (0x1D | 0x80) ||
|
||||
code == (0x36 | 0x80)) {
|
||||
s->shift = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (q->count >= KBD_QUEUE_SIZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
q->data[q->wptr] = next_keycodes[key] | release;
|
||||
|
||||
if (++q->wptr == KBD_QUEUE_SIZE) {
|
||||
q->wptr = 0;
|
||||
}
|
||||
|
||||
q->count++;
|
||||
|
||||
/*
|
||||
* might need to actually trigger the NeXT irq, but as the keyboard works
|
||||
* at the moment, I'll worry about it later
|
||||
*/
|
||||
/* s->update_irq(s->update_arg, 1); */
|
||||
}
|
||||
|
||||
static void nextkbd_reset(DeviceState *dev)
|
||||
{
|
||||
NextKBDState *nks = NEXTKBD(dev);
|
||||
|
||||
memset(&nks->queue, 0, sizeof(KBDQueue));
|
||||
nks->shift = 0;
|
||||
}
|
||||
|
||||
static void nextkbd_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
NextKBDState *s = NEXTKBD(dev);
|
||||
|
||||
memory_region_init_io(&s->mr, OBJECT(dev), &kbd_ops, s, "next.kbd", 0x1000);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
|
||||
|
||||
qemu_add_kbd_event_handler(nextkbd_event, s);
|
||||
}
|
||||
|
||||
static const VMStateDescription nextkbd_vmstate = {
|
||||
.name = TYPE_NEXTKBD,
|
||||
.unmigratable = 1, /* TODO: Implement this when m68k CPU is migratable */
|
||||
};
|
||||
|
||||
static void nextkbd_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
dc->vmsd = &nextkbd_vmstate;
|
||||
dc->realize = nextkbd_realize;
|
||||
dc->reset = nextkbd_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo nextkbd_info = {
|
||||
.name = TYPE_NEXTKBD,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(NextKBDState),
|
||||
.class_init = nextkbd_class_init,
|
||||
};
|
||||
|
||||
static void nextkbd_register_types(void)
|
||||
{
|
||||
type_register_static(&nextkbd_info);
|
||||
}
|
||||
|
||||
type_init(nextkbd_register_types)
|
||||
@@ -51,6 +51,7 @@ typedef struct ESCCState {
|
||||
|
||||
struct ESCCChannelState chn[2];
|
||||
uint32_t it_shift;
|
||||
bool bit_swap;
|
||||
MemoryRegion mmio;
|
||||
uint32_t disabled;
|
||||
uint32_t frequency;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
#ifndef NEXT_CUBE_H
|
||||
#define NEXT_CUBE_H
|
||||
|
||||
#define TYPE_NEXTFB "next-fb"
|
||||
|
||||
#define TYPE_NEXTKBD "next-kbd"
|
||||
|
||||
enum next_dma_chan {
|
||||
NEXTDMA_FD,
|
||||
NEXTDMA_ENRX,
|
||||
NEXTDMA_ENTX,
|
||||
NEXTDMA_SCSI,
|
||||
NEXTDMA_SCC,
|
||||
NEXTDMA_SND
|
||||
};
|
||||
|
||||
#define DMA_ENABLE 0x01000000
|
||||
#define DMA_SUPDATE 0x02000000
|
||||
#define DMA_COMPLETE 0x08000000
|
||||
|
||||
#define DMA_M2DEV 0x0
|
||||
#define DMA_SETENABLE 0x00010000
|
||||
#define DMA_SETSUPDATE 0x00020000
|
||||
#define DMA_DEV2M 0x00040000
|
||||
#define DMA_CLRCOMPLETE 0x00080000
|
||||
#define DMA_RESET 0x00100000
|
||||
|
||||
enum next_irqs {
|
||||
NEXT_FD_I,
|
||||
NEXT_KBD_I,
|
||||
NEXT_PWR_I,
|
||||
NEXT_ENRX_I,
|
||||
NEXT_ENTX_I,
|
||||
NEXT_SCSI_I,
|
||||
NEXT_CLK_I,
|
||||
NEXT_SCC_I,
|
||||
NEXT_ENTX_DMA_I,
|
||||
NEXT_ENRX_DMA_I,
|
||||
NEXT_SCSI_DMA_I,
|
||||
NEXT_SCC_DMA_I,
|
||||
NEXT_SND_I
|
||||
};
|
||||
|
||||
void next_irq(void *opaque, int number, int level);
|
||||
|
||||
#endif /* NEXT_CUBE_H */
|
||||
@@ -0,0 +1,121 @@
|
||||
# Functional test that boots a VM and run OCR on the framebuffer
|
||||
#
|
||||
# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
# later. See the COPYING file in the top-level directory.
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import logging
|
||||
import distutils.spawn
|
||||
|
||||
from avocado_qemu import Test
|
||||
from avocado import skipUnless
|
||||
from avocado.utils import process
|
||||
from avocado.utils.path import find_command, CmdNotFoundError
|
||||
|
||||
PIL_AVAILABLE = True
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
PIL_AVAILABLE = False
|
||||
|
||||
|
||||
def tesseract_available(expected_version):
|
||||
try:
|
||||
find_command('tesseract')
|
||||
except CmdNotFoundError:
|
||||
return False
|
||||
res = process.run('tesseract --version')
|
||||
try:
|
||||
version = res.stdout_text.split()[1]
|
||||
except IndexError:
|
||||
version = res.stderr_text.split()[1]
|
||||
return int(version.split('.')[0]) == expected_version
|
||||
|
||||
match = re.match(r'tesseract\s(\d)', res)
|
||||
if match is None:
|
||||
return False
|
||||
# now this is guaranteed to be a digit
|
||||
return int(match.groups()[0]) == expected_version
|
||||
|
||||
|
||||
class NextCubeMachine(Test):
|
||||
|
||||
timeout = 15
|
||||
|
||||
def check_bootrom_framebuffer(self, screenshot_path):
|
||||
rom_url = ('http://www.nextcomputers.org/NeXTfiles/Software/ROM_Files/'
|
||||
'68040_Non-Turbo_Chipset/Rev_2.5_v66.BIN')
|
||||
rom_hash = 'b3534796abae238a0111299fc406a9349f7fee24'
|
||||
rom_path = self.fetch_asset(rom_url, asset_hash=rom_hash)
|
||||
|
||||
self.vm.set_machine('next-cube')
|
||||
self.vm.add_args('-bios', rom_path)
|
||||
self.vm.launch()
|
||||
|
||||
self.log.info('VM launched, waiting for display')
|
||||
# TODO: Use avocado.utils.wait.wait_for to catch the
|
||||
# 'displaysurface_create 1120x832' trace-event.
|
||||
time.sleep(2)
|
||||
|
||||
self.vm.command('human-monitor-command',
|
||||
command_line='screendump %s' % screenshot_path)
|
||||
|
||||
@skipUnless(PIL_AVAILABLE, 'Python PIL not installed')
|
||||
def test_bootrom_framebuffer_size(self):
|
||||
"""
|
||||
:avocado: tags=arch:m68k
|
||||
:avocado: tags=machine:next_cube
|
||||
:avocado: tags=device:framebuffer
|
||||
"""
|
||||
screenshot_path = os.path.join(self.workdir, "dump.png")
|
||||
self.check_bootrom_framebuffer(screenshot_path)
|
||||
|
||||
width, height = Image.open(screenshot_path).size
|
||||
self.assertEqual(width, 1120)
|
||||
self.assertEqual(height, 832)
|
||||
|
||||
@skipUnless(tesseract_available(3), 'tesseract v3 OCR tool not available')
|
||||
def test_bootrom_framebuffer_ocr_with_tesseract_v3(self):
|
||||
"""
|
||||
:avocado: tags=arch:m68k
|
||||
:avocado: tags=machine:next_cube
|
||||
:avocado: tags=device:framebuffer
|
||||
"""
|
||||
screenshot_path = os.path.join(self.workdir, "dump.png")
|
||||
self.check_bootrom_framebuffer(screenshot_path)
|
||||
|
||||
console_logger = logging.getLogger('console')
|
||||
text = process.run("tesseract %s stdout" % screenshot_path).stdout_text
|
||||
for line in text.split('\n'):
|
||||
if len(line):
|
||||
console_logger.debug(line)
|
||||
self.assertIn('Backplane', text)
|
||||
self.assertIn('Ethernet address', text)
|
||||
|
||||
# Tesseract 4 adds a new OCR engine based on LSTM neural networks. The
|
||||
# new version is faster and more accurate than version 3. The drawback is
|
||||
# that it is still alpha-level software.
|
||||
@skipUnless(tesseract_available(4), 'tesseract v4 OCR tool not available')
|
||||
def test_bootrom_framebuffer_ocr_with_tesseract_v4(self):
|
||||
"""
|
||||
:avocado: tags=arch:m68k
|
||||
:avocado: tags=machine:next_cube
|
||||
:avocado: tags=device:framebuffer
|
||||
"""
|
||||
screenshot_path = os.path.join(self.workdir, "dump.png")
|
||||
self.check_bootrom_framebuffer(screenshot_path)
|
||||
|
||||
console_logger = logging.getLogger('console')
|
||||
proc = process.run("tesseract --oem 1 %s stdout" % screenshot_path)
|
||||
text = proc.stdout_text
|
||||
for line in text.split('\n'):
|
||||
if len(line):
|
||||
console_logger.debug(line)
|
||||
self.assertIn('Testing the FPU, SCC', text)
|
||||
self.assertIn('System test failed. Error code 51', text)
|
||||
self.assertIn('Boot command', text)
|
||||
self.assertIn('Next>', text)
|
||||
@@ -24,6 +24,17 @@ static const uint8_t kernel_mcf5208[] = {
|
||||
0x60, 0xfa /* bra.s loop */
|
||||
};
|
||||
|
||||
static const uint8_t bios_nextcube[] = {
|
||||
0x06, 0x00, 0x00, 0x00, /* Initial SP */
|
||||
0x01, 0x00, 0x00, 0x08, /* Initial PC */
|
||||
0x41, 0xf9, 0x02, 0x11, 0x80, 0x00, /* lea 0x02118000,%a0 */
|
||||
0x10, 0x3c, 0x00, 0x54, /* move.b #'T',%d0 */
|
||||
0x11, 0x7c, 0x00, 0x05, 0x00, 0x01, /* move.b #5,1(%a0) Sel TXCTRL */
|
||||
0x11, 0x7c, 0x00, 0x68, 0x00, 0x01, /* move.b #0x68,1(%a0) Enable TX */
|
||||
0x11, 0x40, 0x00, 0x03, /* move.b %d0,3(%a0) Print 'T' */
|
||||
0x60, 0xfa /* bra.s loop */
|
||||
};
|
||||
|
||||
static const uint8_t kernel_pls3adsp1800[] = {
|
||||
0xb0, 0x00, 0x84, 0x00, /* imm 0x8400 */
|
||||
0x30, 0x60, 0x00, 0x04, /* addik r3,r0,4 */
|
||||
@@ -117,6 +128,7 @@ static testdef_t tests[] = {
|
||||
{ "sparc64", "sun4u", "", "UltraSPARC" },
|
||||
{ "s390x", "s390-ccw-virtio", "", "device" },
|
||||
{ "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 },
|
||||
{ "m68k", "next-cube", "", "TT", sizeof(bios_nextcube), 0, bios_nextcube },
|
||||
{ "microblaze", "petalogix-s3adsp1800", "", "TT",
|
||||
sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 },
|
||||
{ "microblazeel", "petalogix-ml605", "", "TT",
|
||||
|
||||
Reference in New Issue
Block a user