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/char/serial.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
|
||||
|
||||
#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 MAX_DEVICE 0xC
|
||||
#define DEVICE_FDD 0x0
|
||||
#define DEVICE_PARALLEL_PORT 0x3
|
||||
#define DEVICE_SERIAL_PORT_1 0x4
|
||||
|
@ -37,8 +33,20 @@
|
|||
#define DEVICE_PME 0xA
|
||||
#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_LOW 0x61
|
||||
#define CONFIG_DEVICE_INETRRUPT 0x70
|
||||
|
||||
#define DEBUG_LPC47M157
|
||||
|
||||
|
@ -51,11 +59,41 @@ typedef struct LPC47M157State {
|
|||
uint32_t selected_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;
|
||||
|
||||
#define LPC47M157_DEVICE(obj) \
|
||||
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,
|
||||
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) {
|
||||
assert(s->configuration_mode);
|
||||
s->configuration_mode = false;
|
||||
|
||||
update_devices(s);
|
||||
} else {
|
||||
s->selected_reg = val;
|
||||
}
|
||||
} else if (addr == 1) { //DATA_PORT
|
||||
if (s->selected_reg < MAX_CONFIG_REG) {
|
||||
//global configuration register
|
||||
/* global configuration register */
|
||||
s->config_regs[s->selected_reg] = val;
|
||||
} else {
|
||||
if (s->config_regs[CONFIG_DEVICE_NUMBER] == DEVICE_SERIAL_PORT_1) {
|
||||
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
/* device register */
|
||||
assert(s->config_regs[CONFIG_DEVICE_NUMBER] < MAX_DEVICE);
|
||||
uint8_t* dev = s->device_regs[s->config_regs[CONFIG_DEVICE_NUMBER]];
|
||||
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 {
|
||||
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) {
|
||||
val = s->config_regs[s->selected_reg];
|
||||
} 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 {
|
||||
assert(false);
|
||||
|
@ -136,15 +180,53 @@ static void lpc47m157_realize(DeviceState *dev, Error **errp)
|
|||
memory_region_init_io(&s->io, OBJECT(s),
|
||||
&lpc47m157_io_ops, s, "lpc47m157", 2);
|
||||
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)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = lpc47m157_realize;
|
||||
dc->vmsd = &vmstate_lpc47m157;
|
||||
//dc->reset = pc87312_reset;
|
||||
//dc->vmsd = &vmstate_pc87312;
|
||||
//dc->props = pc87312_properties;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue