mirror of https://github.com/xemu-project/xemu.git
let lpc47m157 control its own serial devices
This commit is contained in:
parent
4a23de0a88
commit
5cc6ebf9bd
|
@ -18,16 +18,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hw/isa/isa.h"
|
#include "hw/isa/isa.h"
|
||||||
|
#include "hw/char/serial.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
#include "qapi/qmp/qerror.h"
|
||||||
|
|
||||||
|
#define MAX_DEVICE 0xC
|
||||||
#define ENTER_CONFIG_KEY 0x55
|
|
||||||
#define EXIT_CONFIG_KEY 0xAA
|
|
||||||
|
|
||||||
#define MAX_CONFIG_REG 0x30
|
|
||||||
#define CONFIG_DEVICE_NUMBER 0x07
|
|
||||||
#define CONFIG_PORT_LOW 0x26
|
|
||||||
#define CONFIG_PORT_HIGH 0x27
|
|
||||||
|
|
||||||
#define DEVICE_FDD 0x0
|
#define DEVICE_FDD 0x0
|
||||||
#define DEVICE_PARALLEL_PORT 0x3
|
#define DEVICE_PARALLEL_PORT 0x3
|
||||||
#define DEVICE_SERIAL_PORT_1 0x4
|
#define DEVICE_SERIAL_PORT_1 0x4
|
||||||
|
@ -37,8 +33,20 @@
|
||||||
#define DEVICE_PME 0xA
|
#define DEVICE_PME 0xA
|
||||||
#define DEVICE_MPU_401 0xB
|
#define DEVICE_MPU_401 0xB
|
||||||
|
|
||||||
|
#define ENTER_CONFIG_KEY 0x55
|
||||||
|
#define EXIT_CONFIG_KEY 0xAA
|
||||||
|
|
||||||
|
#define MAX_CONFIG_REG 0x30
|
||||||
|
#define MAX_DEVICE_REGS 0xFF
|
||||||
|
|
||||||
|
#define CONFIG_DEVICE_NUMBER 0x07
|
||||||
|
#define CONFIG_PORT_LOW 0x26
|
||||||
|
#define CONFIG_PORT_HIGH 0x27
|
||||||
|
|
||||||
|
#define CONFIG_DEVICE_ACTIVATE 0x30
|
||||||
#define CONFIG_DEVICE_BASE_ADDRESS_HIGH 0x60
|
#define CONFIG_DEVICE_BASE_ADDRESS_HIGH 0x60
|
||||||
#define CONFIG_DEVICE_BASE_ADDRESS_LOW 0x61
|
#define CONFIG_DEVICE_BASE_ADDRESS_LOW 0x61
|
||||||
|
#define CONFIG_DEVICE_INETRRUPT 0x70
|
||||||
|
|
||||||
#define DEBUG_LPC47M157
|
#define DEBUG_LPC47M157
|
||||||
|
|
||||||
|
@ -51,11 +59,41 @@ typedef struct LPC47M157State {
|
||||||
uint32_t selected_reg;
|
uint32_t selected_reg;
|
||||||
|
|
||||||
uint8_t config_regs[MAX_CONFIG_REG];
|
uint8_t config_regs[MAX_CONFIG_REG];
|
||||||
|
uint8_t device_regs[MAX_DEVICE][MAX_DEVICE_REGS];
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool active;
|
||||||
|
SerialState state;
|
||||||
|
} serial[2];
|
||||||
} LPC47M157State;
|
} LPC47M157State;
|
||||||
|
|
||||||
#define LPC47M157_DEVICE(obj) \
|
#define LPC47M157_DEVICE(obj) \
|
||||||
OBJECT_CHECK(LPC47M157State, (obj), "lpc47m157")
|
OBJECT_CHECK(LPC47M157State, (obj), "lpc47m157")
|
||||||
|
|
||||||
|
static void update_devices(LPC47M157State *s)
|
||||||
|
{
|
||||||
|
ISADevice *isadev = ISA_DEVICE(s);
|
||||||
|
|
||||||
|
/* init serial devices */
|
||||||
|
for (int i=0; i<2; i++) {
|
||||||
|
uint8_t *dev = s->device_regs[DEVICE_SERIAL_PORT_1 + i];
|
||||||
|
if (dev[CONFIG_DEVICE_ACTIVATE] && !s->serial[i].active) {
|
||||||
|
|
||||||
|
uint32_t iobase = (dev[CONFIG_DEVICE_BASE_ADDRESS_HIGH] << 8)
|
||||||
|
| dev[CONFIG_DEVICE_BASE_ADDRESS_LOW];
|
||||||
|
uint32_t irq = dev[CONFIG_DEVICE_INETRRUPT];
|
||||||
|
|
||||||
|
SerialState *ss = &s->serial[i].state;
|
||||||
|
if (irq != 0) {
|
||||||
|
isa_init_irq(isadev, &ss->irq, irq);
|
||||||
|
}
|
||||||
|
isa_register_ioport(isadev, &ss->io, iobase);
|
||||||
|
|
||||||
|
s->serial[i].active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void lpc47m157_io_write(void *opaque, hwaddr addr, uint64_t val,
|
static void lpc47m157_io_write(void *opaque, hwaddr addr, uint64_t val,
|
||||||
unsigned int size)
|
unsigned int size)
|
||||||
{
|
{
|
||||||
|
@ -72,19 +110,23 @@ static void lpc47m157_io_write(void *opaque, hwaddr addr, uint64_t val,
|
||||||
} else if (val == EXIT_CONFIG_KEY) {
|
} else if (val == EXIT_CONFIG_KEY) {
|
||||||
assert(s->configuration_mode);
|
assert(s->configuration_mode);
|
||||||
s->configuration_mode = false;
|
s->configuration_mode = false;
|
||||||
|
|
||||||
|
update_devices(s);
|
||||||
} else {
|
} else {
|
||||||
s->selected_reg = val;
|
s->selected_reg = val;
|
||||||
}
|
}
|
||||||
} else if (addr == 1) { //DATA_PORT
|
} else if (addr == 1) { //DATA_PORT
|
||||||
if (s->selected_reg < MAX_CONFIG_REG) {
|
if (s->selected_reg < MAX_CONFIG_REG) {
|
||||||
//global configuration register
|
/* global configuration register */
|
||||||
s->config_regs[s->selected_reg] = val;
|
s->config_regs[s->selected_reg] = val;
|
||||||
} else {
|
} else {
|
||||||
if (s->config_regs[CONFIG_DEVICE_NUMBER] == DEVICE_SERIAL_PORT_1) {
|
/* device register */
|
||||||
|
assert(s->config_regs[CONFIG_DEVICE_NUMBER] < MAX_DEVICE);
|
||||||
} else {
|
uint8_t* dev = s->device_regs[s->config_regs[CONFIG_DEVICE_NUMBER]];
|
||||||
assert(false);
|
dev[s->selected_reg] = val;
|
||||||
}
|
#ifdef DEBUG_LPC47M157
|
||||||
|
printf("lpc47m157 dev %x . %x = %llx\n", s->config_regs[CONFIG_DEVICE_NUMBER], s->selected_reg, val);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(false);
|
assert(false);
|
||||||
|
@ -102,7 +144,9 @@ static uint64_t lpc47m157_io_read(void *opaque, hwaddr addr, unsigned int size)
|
||||||
if (s->selected_reg < MAX_CONFIG_REG) {
|
if (s->selected_reg < MAX_CONFIG_REG) {
|
||||||
val = s->config_regs[s->selected_reg];
|
val = s->config_regs[s->selected_reg];
|
||||||
} else {
|
} else {
|
||||||
|
assert(s->config_regs[CONFIG_DEVICE_NUMBER] < MAX_DEVICE);
|
||||||
|
uint8_t* dev = s->device_regs[s->config_regs[CONFIG_DEVICE_NUMBER]];
|
||||||
|
val = dev[s->selected_reg];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(false);
|
assert(false);
|
||||||
|
@ -136,15 +180,53 @@ static void lpc47m157_realize(DeviceState *dev, Error **errp)
|
||||||
memory_region_init_io(&s->io, OBJECT(s),
|
memory_region_init_io(&s->io, OBJECT(s),
|
||||||
&lpc47m157_io_ops, s, "lpc47m157", 2);
|
&lpc47m157_io_ops, s, "lpc47m157", 2);
|
||||||
isa_register_ioport(isa, &s->io, iobase);
|
isa_register_ioport(isa, &s->io, iobase);
|
||||||
|
|
||||||
|
/* init serial cores */
|
||||||
|
for (int i=0; i<2; i++) {
|
||||||
|
CharDriverState *chr = serial_hds[i];
|
||||||
|
if (chr == NULL) {
|
||||||
|
char name[5];
|
||||||
|
snprintf(name, sizeof(name), "ser%d", i);
|
||||||
|
chr = qemu_chr_new(name, "null", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialState *ss = &s->serial[i].state;
|
||||||
|
ss->chr = chr;
|
||||||
|
ss->baudbase = 115200;
|
||||||
|
|
||||||
|
Error *err = NULL;
|
||||||
|
serial_realize_core(ss, &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
qerror_report_err(err);
|
||||||
|
error_free(err);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_init_io(&ss->io, OBJECT(s),
|
||||||
|
&serial_io_ops, ss, "serial", 8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_lpc47m157= {
|
||||||
|
.name = "lpc47m157",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_STRUCT(serial[0].state, LPC47M157State, 0,
|
||||||
|
vmstate_serial, SerialState),
|
||||||
|
VMSTATE_STRUCT(serial[1].state, LPC47M157State, 0,
|
||||||
|
vmstate_serial, SerialState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void lpc47m157_class_init(ObjectClass *klass, void *data)
|
static void lpc47m157_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
dc->realize = lpc47m157_realize;
|
dc->realize = lpc47m157_realize;
|
||||||
|
dc->vmsd = &vmstate_lpc47m157;
|
||||||
//dc->reset = pc87312_reset;
|
//dc->reset = pc87312_reset;
|
||||||
//dc->vmsd = &vmstate_pc87312;
|
|
||||||
//dc->props = pc87312_properties;
|
//dc->props = pc87312_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue