mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/philmd/tags/renesas-20211030' into staging
Renesas SH-4 patches queue Patches from Zoltan: - Various clean up to align the code style with the rest of the code base - QOM'ify the SH_SERIAL device - Modify few memory region size to better match the hardware manual # gpg: Signature made Sat 30 Oct 2021 10:05:03 AM PDT # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] * remotes/philmd/tags/renesas-20211030: (30 commits) hw/timer/sh_timer: Remove use of hw_error hw/timer/sh_timer: Fix timer memory region size hw/timer/sh_timer: Do not wrap lines that are not too long hw/timer/sh_timer: Rename sh_timer_state to SHTimerState hw/intc/sh_intc: Remove unneeded local variable initialisers hw/intc/sh_intc: Simplify allocating sources array hw/intc/sh_intc: Avoid using continue in loops hw/intc/sh_intc: Replace abort() with g_assert_not_reached() hw/intc/sh_intc: Inline and drop sh_intc_source() function hw/intc/sh_intc: Use array index instead of pointer arithmetics hw/intc/sh_intc: Remove excessive parenthesis hw/intc/sh_intc: Move sh_intc_register() closer to its only user hw/intc/sh_intc: Drop another useless macro hw/intc/sh_intc: Rename iomem region hw/intc/sh_intc: Turn some defines into an enum hw/intc/sh_intc: Use existing macro instead of local one hw/char/sh_serial: Add device id to trace output hw/char/sh_serial: QOM-ify hw/char/sh_serial: Split off sh_serial_reset() from sh_serial_init() hw/char/sh_serial: Embed QEMUTimer in state struct ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
+133
-99
@@ -26,13 +26,17 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "hw/sh4/sh.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
//#define DEBUG_SERIAL
|
||||
#include "qemu/log.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define SH_SERIAL_FLAG_TEND (1 << 0)
|
||||
#define SH_SERIAL_FLAG_TDE (1 << 1)
|
||||
@@ -42,10 +46,10 @@
|
||||
|
||||
#define SH_RX_FIFO_LENGTH (16)
|
||||
|
||||
typedef struct {
|
||||
MemoryRegion iomem;
|
||||
MemoryRegion iomem_p4;
|
||||
MemoryRegion iomem_a7;
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(SHSerialState, SH_SERIAL)
|
||||
|
||||
struct SHSerialState {
|
||||
SysBusDevice parent;
|
||||
uint8_t smr;
|
||||
uint8_t brr;
|
||||
uint8_t scr;
|
||||
@@ -59,13 +63,12 @@ typedef struct {
|
||||
uint8_t rx_tail;
|
||||
uint8_t rx_head;
|
||||
|
||||
int freq;
|
||||
int feat;
|
||||
uint8_t feat;
|
||||
int flags;
|
||||
int rtrg;
|
||||
|
||||
CharBackend chr;
|
||||
QEMUTimer *fifo_timeout_timer;
|
||||
QEMUTimer fifo_timeout_timer;
|
||||
uint64_t etu; /* Elementary Time Unit (ns) */
|
||||
|
||||
qemu_irq eri;
|
||||
@@ -73,9 +76,13 @@ typedef struct {
|
||||
qemu_irq txi;
|
||||
qemu_irq tei;
|
||||
qemu_irq bri;
|
||||
} sh_serial_state;
|
||||
};
|
||||
|
||||
static void sh_serial_clear_fifo(sh_serial_state * s)
|
||||
typedef struct {} SHSerialStateClass;
|
||||
|
||||
OBJECT_DEFINE_TYPE(SHSerialState, sh_serial, SH_SERIAL, SYS_BUS_DEVICE)
|
||||
|
||||
static void sh_serial_clear_fifo(SHSerialState *s)
|
||||
{
|
||||
memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
|
||||
s->rx_cnt = 0;
|
||||
@@ -86,14 +93,12 @@ static void sh_serial_clear_fifo(sh_serial_state * s)
|
||||
static void sh_serial_write(void *opaque, hwaddr offs,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
sh_serial_state *s = opaque;
|
||||
SHSerialState *s = opaque;
|
||||
DeviceState *d = DEVICE(s);
|
||||
unsigned char ch;
|
||||
|
||||
#ifdef DEBUG_SERIAL
|
||||
printf("sh_serial: write offs=0x%02x val=0x%02x\n",
|
||||
offs, val);
|
||||
#endif
|
||||
switch(offs) {
|
||||
trace_sh_serial_write(d->id, size, offs, val);
|
||||
switch (offs) {
|
||||
case 0x00: /* SMR */
|
||||
s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
|
||||
return;
|
||||
@@ -103,8 +108,9 @@ static void sh_serial_write(void *opaque, hwaddr offs,
|
||||
case 0x08: /* SCR */
|
||||
/* TODO : For SH7751, SCIF mask should be 0xfb. */
|
||||
s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
|
||||
if (!(val & (1 << 5)))
|
||||
if (!(val & (1 << 5))) {
|
||||
s->flags |= SH_SERIAL_FLAG_TEND;
|
||||
}
|
||||
if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
|
||||
qemu_set_irq(s->txi, val & (1 << 7));
|
||||
}
|
||||
@@ -115,8 +121,10 @@ static void sh_serial_write(void *opaque, hwaddr offs,
|
||||
case 0x0c: /* FTDR / TDR */
|
||||
if (qemu_chr_fe_backend_connected(&s->chr)) {
|
||||
ch = val;
|
||||
/* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks */
|
||||
/*
|
||||
* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks
|
||||
*/
|
||||
qemu_chr_fe_write_all(&s->chr, &ch, 1);
|
||||
}
|
||||
s->dr = val;
|
||||
@@ -129,18 +137,23 @@ static void sh_serial_write(void *opaque, hwaddr offs,
|
||||
#endif
|
||||
}
|
||||
if (s->feat & SH_SERIAL_FEAT_SCIF) {
|
||||
switch(offs) {
|
||||
switch (offs) {
|
||||
case 0x10: /* FSR */
|
||||
if (!(val & (1 << 6)))
|
||||
if (!(val & (1 << 6))) {
|
||||
s->flags &= ~SH_SERIAL_FLAG_TEND;
|
||||
if (!(val & (1 << 5)))
|
||||
}
|
||||
if (!(val & (1 << 5))) {
|
||||
s->flags &= ~SH_SERIAL_FLAG_TDE;
|
||||
if (!(val & (1 << 4)))
|
||||
}
|
||||
if (!(val & (1 << 4))) {
|
||||
s->flags &= ~SH_SERIAL_FLAG_BRK;
|
||||
if (!(val & (1 << 1)))
|
||||
}
|
||||
if (!(val & (1 << 1))) {
|
||||
s->flags &= ~SH_SERIAL_FLAG_RDF;
|
||||
if (!(val & (1 << 0)))
|
||||
}
|
||||
if (!(val & (1 << 0))) {
|
||||
s->flags &= ~SH_SERIAL_FLAG_DR;
|
||||
}
|
||||
|
||||
if (!(val & (1 << 1)) || !(val & (1 << 0))) {
|
||||
if (s->rxi) {
|
||||
@@ -176,9 +189,8 @@ static void sh_serial_write(void *opaque, hwaddr offs,
|
||||
case 0x24: /* LSR */
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch(offs) {
|
||||
} else {
|
||||
switch (offs) {
|
||||
#if 0
|
||||
case 0x0c:
|
||||
ret = s->dr;
|
||||
@@ -192,20 +204,20 @@ static void sh_serial_write(void *opaque, hwaddr offs,
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "sh_serial: unsupported write to 0x%02"
|
||||
HWADDR_PRIx "\n", offs);
|
||||
abort();
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: unsupported write to 0x%02" HWADDR_PRIx "\n",
|
||||
__func__, offs);
|
||||
}
|
||||
|
||||
static uint64_t sh_serial_read(void *opaque, hwaddr offs,
|
||||
unsigned size)
|
||||
{
|
||||
sh_serial_state *s = opaque;
|
||||
uint32_t ret = ~0;
|
||||
SHSerialState *s = opaque;
|
||||
DeviceState *d = DEVICE(s);
|
||||
uint32_t ret = UINT32_MAX;
|
||||
|
||||
#if 0
|
||||
switch(offs) {
|
||||
switch (offs) {
|
||||
case 0x00:
|
||||
ret = s->smr;
|
||||
break;
|
||||
@@ -221,7 +233,7 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs,
|
||||
}
|
||||
#endif
|
||||
if (s->feat & SH_SERIAL_FEAT_SCIF) {
|
||||
switch(offs) {
|
||||
switch (offs) {
|
||||
case 0x00: /* SMR */
|
||||
ret = s->smr;
|
||||
break;
|
||||
@@ -230,29 +242,37 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs,
|
||||
break;
|
||||
case 0x10: /* FSR */
|
||||
ret = 0;
|
||||
if (s->flags & SH_SERIAL_FLAG_TEND)
|
||||
if (s->flags & SH_SERIAL_FLAG_TEND) {
|
||||
ret |= (1 << 6);
|
||||
if (s->flags & SH_SERIAL_FLAG_TDE)
|
||||
}
|
||||
if (s->flags & SH_SERIAL_FLAG_TDE) {
|
||||
ret |= (1 << 5);
|
||||
if (s->flags & SH_SERIAL_FLAG_BRK)
|
||||
}
|
||||
if (s->flags & SH_SERIAL_FLAG_BRK) {
|
||||
ret |= (1 << 4);
|
||||
if (s->flags & SH_SERIAL_FLAG_RDF)
|
||||
}
|
||||
if (s->flags & SH_SERIAL_FLAG_RDF) {
|
||||
ret |= (1 << 1);
|
||||
if (s->flags & SH_SERIAL_FLAG_DR)
|
||||
}
|
||||
if (s->flags & SH_SERIAL_FLAG_DR) {
|
||||
ret |= (1 << 0);
|
||||
}
|
||||
|
||||
if (s->scr & (1 << 5))
|
||||
if (s->scr & (1 << 5)) {
|
||||
s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x14:
|
||||
if (s->rx_cnt > 0) {
|
||||
ret = s->rx_fifo[s->rx_tail++];
|
||||
s->rx_cnt--;
|
||||
if (s->rx_tail == SH_RX_FIFO_LENGTH)
|
||||
if (s->rx_tail == SH_RX_FIFO_LENGTH) {
|
||||
s->rx_tail = 0;
|
||||
if (s->rx_cnt < s->rtrg)
|
||||
}
|
||||
if (s->rx_cnt < s->rtrg) {
|
||||
s->flags &= ~SH_SERIAL_FLAG_RDF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
@@ -268,9 +288,8 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs,
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch(offs) {
|
||||
} else {
|
||||
switch (offs) {
|
||||
#if 0
|
||||
case 0x0c:
|
||||
ret = s->dr;
|
||||
@@ -287,40 +306,39 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_SERIAL
|
||||
printf("sh_serial: read offs=0x%02x val=0x%x\n",
|
||||
offs, ret);
|
||||
#endif
|
||||
trace_sh_serial_read(d->id, size, offs, ret);
|
||||
|
||||
if (ret & ~((1 << 16) - 1)) {
|
||||
fprintf(stderr, "sh_serial: unsupported read from 0x%02"
|
||||
HWADDR_PRIx "\n", offs);
|
||||
abort();
|
||||
if (ret > UINT16_MAX) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: unsupported read from 0x%02" HWADDR_PRIx "\n",
|
||||
__func__, offs);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sh_serial_can_receive(sh_serial_state *s)
|
||||
static int sh_serial_can_receive(SHSerialState *s)
|
||||
{
|
||||
return s->scr & (1 << 4);
|
||||
}
|
||||
|
||||
static void sh_serial_receive_break(sh_serial_state *s)
|
||||
static void sh_serial_receive_break(SHSerialState *s)
|
||||
{
|
||||
if (s->feat & SH_SERIAL_FEAT_SCIF)
|
||||
if (s->feat & SH_SERIAL_FEAT_SCIF) {
|
||||
s->sr |= (1 << 4);
|
||||
}
|
||||
}
|
||||
|
||||
static int sh_serial_can_receive1(void *opaque)
|
||||
{
|
||||
sh_serial_state *s = opaque;
|
||||
SHSerialState *s = opaque;
|
||||
return sh_serial_can_receive(s);
|
||||
}
|
||||
|
||||
static void sh_serial_timeout_int(void *opaque)
|
||||
{
|
||||
sh_serial_state *s = opaque;
|
||||
SHSerialState *s = opaque;
|
||||
|
||||
s->flags |= SH_SERIAL_FLAG_RDF;
|
||||
if (s->scr & (1 << 6) && s->rxi) {
|
||||
@@ -330,7 +348,7 @@ static void sh_serial_timeout_int(void *opaque)
|
||||
|
||||
static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
sh_serial_state *s = opaque;
|
||||
SHSerialState *s = opaque;
|
||||
|
||||
if (s->feat & SH_SERIAL_FEAT_SCIF) {
|
||||
int i;
|
||||
@@ -344,11 +362,11 @@ static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
|
||||
if (s->rx_cnt >= s->rtrg) {
|
||||
s->flags |= SH_SERIAL_FLAG_RDF;
|
||||
if (s->scr & (1 << 6) && s->rxi) {
|
||||
timer_del(s->fifo_timeout_timer);
|
||||
timer_del(&s->fifo_timeout_timer);
|
||||
qemu_set_irq(s->rxi, 1);
|
||||
}
|
||||
} else {
|
||||
timer_mod(s->fifo_timeout_timer,
|
||||
timer_mod(&s->fifo_timeout_timer,
|
||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
|
||||
}
|
||||
}
|
||||
@@ -360,9 +378,10 @@ static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
|
||||
|
||||
static void sh_serial_event(void *opaque, QEMUChrEvent event)
|
||||
{
|
||||
sh_serial_state *s = opaque;
|
||||
if (event == CHR_EVENT_BREAK)
|
||||
SHSerialState *s = opaque;
|
||||
if (event == CHR_EVENT_BREAK) {
|
||||
sh_serial_receive_break(s);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sh_serial_ops = {
|
||||
@@ -371,20 +390,10 @@ static const MemoryRegionOps sh_serial_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
void sh_serial_init(MemoryRegion *sysmem,
|
||||
hwaddr base, int feat,
|
||||
uint32_t freq, Chardev *chr,
|
||||
qemu_irq eri_source,
|
||||
qemu_irq rxi_source,
|
||||
qemu_irq txi_source,
|
||||
qemu_irq tei_source,
|
||||
qemu_irq bri_source)
|
||||
static void sh_serial_reset(DeviceState *dev)
|
||||
{
|
||||
sh_serial_state *s;
|
||||
SHSerialState *s = SH_SERIAL(dev);
|
||||
|
||||
s = g_malloc0(sizeof(sh_serial_state));
|
||||
|
||||
s->feat = feat;
|
||||
s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
|
||||
s->rtrg = 1;
|
||||
|
||||
@@ -393,39 +402,64 @@ void sh_serial_init(MemoryRegion *sysmem,
|
||||
s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
|
||||
s->sptr = 0;
|
||||
|
||||
if (feat & SH_SERIAL_FEAT_SCIF) {
|
||||
if (s->feat & SH_SERIAL_FEAT_SCIF) {
|
||||
s->fcr = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
s->dr = 0xff;
|
||||
}
|
||||
|
||||
sh_serial_clear_fifo(s);
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &sh_serial_ops, s,
|
||||
"serial", 0x100000000ULL);
|
||||
static void sh_serial_realize(DeviceState *d, Error **errp)
|
||||
{
|
||||
SHSerialState *s = SH_SERIAL(d);
|
||||
MemoryRegion *iomem = g_malloc(sizeof(*iomem));
|
||||
|
||||
memory_region_init_alias(&s->iomem_p4, NULL, "serial-p4", &s->iomem,
|
||||
0, 0x28);
|
||||
memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
|
||||
assert(d->id);
|
||||
memory_region_init_io(iomem, OBJECT(d), &sh_serial_ops, s, d->id, 0x28);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(d), iomem);
|
||||
qdev_init_gpio_out_named(d, &s->eri, "eri", 1);
|
||||
qdev_init_gpio_out_named(d, &s->rxi, "rxi", 1);
|
||||
qdev_init_gpio_out_named(d, &s->txi, "txi", 1);
|
||||
qdev_init_gpio_out_named(d, &s->tei, "tei", 1);
|
||||
qdev_init_gpio_out_named(d, &s->bri, "bri", 1);
|
||||
|
||||
memory_region_init_alias(&s->iomem_a7, NULL, "serial-a7", &s->iomem,
|
||||
0, 0x28);
|
||||
memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
|
||||
|
||||
if (chr) {
|
||||
qemu_chr_fe_init(&s->chr, chr, &error_abort);
|
||||
if (qemu_chr_fe_backend_connected(&s->chr)) {
|
||||
qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
|
||||
sh_serial_receive1,
|
||||
sh_serial_event, NULL, s, NULL, true);
|
||||
}
|
||||
|
||||
s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
sh_serial_timeout_int, s);
|
||||
timer_init_ns(&s->fifo_timeout_timer, QEMU_CLOCK_VIRTUAL,
|
||||
sh_serial_timeout_int, s);
|
||||
s->etu = NANOSECONDS_PER_SECOND / 9600;
|
||||
s->eri = eri_source;
|
||||
s->rxi = rxi_source;
|
||||
s->txi = txi_source;
|
||||
s->tei = tei_source;
|
||||
s->bri = bri_source;
|
||||
}
|
||||
|
||||
static void sh_serial_finalize(Object *obj)
|
||||
{
|
||||
SHSerialState *s = SH_SERIAL(obj);
|
||||
|
||||
timer_del(&s->fifo_timeout_timer);
|
||||
}
|
||||
|
||||
static void sh_serial_init(Object *obj)
|
||||
{
|
||||
}
|
||||
|
||||
static Property sh_serial_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", SHSerialState, chr),
|
||||
DEFINE_PROP_UINT8("features", SHSerialState, feat, 0),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void sh_serial_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
device_class_set_props(dc, sh_serial_properties);
|
||||
dc->realize = sh_serial_realize;
|
||||
dc->reset = sh_serial_reset;
|
||||
/* Reason: part of SuperH CPU/SoC, needs to be wired up */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
@@ -101,3 +101,7 @@ exynos_uart_rx_timeout(uint32_t channel, uint32_t stat, uint32_t intsp) "UART%d:
|
||||
|
||||
# cadence_uart.c
|
||||
cadence_uart_baudrate(unsigned baudrate) "baudrate %u"
|
||||
|
||||
# sh_serial.c
|
||||
sh_serial_read(char *id, unsigned size, uint64_t offs, uint64_t val) " %s size %d offs 0x%02" PRIx64 " -> 0x%02" PRIx64
|
||||
sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %d offs 0x%02" PRIx64 " <- 0x%02" PRIx64
|
||||
|
||||
+254
-319
File diff suppressed because it is too large
Load Diff
@@ -238,3 +238,11 @@ goldfish_pic_write(void *dev, int idx, unsigned int addr, unsigned int size, uin
|
||||
goldfish_pic_reset(void *dev, int idx) "pic: %p goldfish-irq.%d"
|
||||
goldfish_pic_realize(void *dev, int idx) "pic: %p goldfish-irq.%d"
|
||||
goldfish_pic_instance_init(void *dev) "pic: %p goldfish-irq"
|
||||
|
||||
# sh_intc.c
|
||||
sh_intc_sources(int p, int a, int c, int m, unsigned short v, const char *s1, const char *s2, const char *s3) "(%d/%d/%d/%d) interrupt source 0x%x %s%s%s"
|
||||
sh_intc_pending(int p, unsigned short v) "(%d) returning interrupt source 0x%x"
|
||||
sh_intc_register(const char *s, int id, unsigned short v, int c, int m) "%s %u -> 0x%04x (%d/%d)"
|
||||
sh_intc_read(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " -> 0x%lx"
|
||||
sh_intc_write(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " <- 0x%lx"
|
||||
sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
|
||||
|
||||
@@ -49,13 +49,12 @@ struct SHPCIState {
|
||||
uint32_t iobr;
|
||||
};
|
||||
|
||||
static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
static void sh_pci_reg_write(void *p, hwaddr addr, uint64_t val, unsigned size)
|
||||
{
|
||||
SHPCIState *pcic = p;
|
||||
PCIHostState *phb = PCI_HOST_BRIDGE(pcic);
|
||||
|
||||
switch(addr) {
|
||||
switch (addr) {
|
||||
case 0 ... 0xfc:
|
||||
stl_le_p(pcic->dev->config + addr, val);
|
||||
break;
|
||||
@@ -75,13 +74,12 @@ static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val,
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t sh_pci_reg_read (void *p, hwaddr addr,
|
||||
unsigned size)
|
||||
static uint64_t sh_pci_reg_read(void *p, hwaddr addr, unsigned size)
|
||||
{
|
||||
SHPCIState *pcic = p;
|
||||
PCIHostState *phb = PCI_HOST_BRIDGE(pcic);
|
||||
|
||||
switch(addr) {
|
||||
switch (addr) {
|
||||
case 0 ... 0xfc:
|
||||
return ldl_le_p(pcic->dev->config + addr);
|
||||
case 0x1c0:
|
||||
|
||||
+38
-31
@@ -26,6 +26,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/sh4/sh.h"
|
||||
@@ -56,10 +57,10 @@
|
||||
#define LINUX_LOAD_OFFSET 0x0800000
|
||||
#define INITRD_LOAD_OFFSET 0x1800000
|
||||
|
||||
#define PA_IRLMSK 0x00
|
||||
#define PA_POWOFF 0x30
|
||||
#define PA_VERREG 0x32
|
||||
#define PA_OUTPORT 0x36
|
||||
#define PA_IRLMSK 0x00
|
||||
#define PA_POWOFF 0x30
|
||||
#define PA_VERREG 0x32
|
||||
#define PA_OUTPORT 0x36
|
||||
|
||||
typedef struct {
|
||||
uint16_t bcr;
|
||||
@@ -96,38 +97,41 @@ enum r2d_fpga_irq {
|
||||
};
|
||||
|
||||
static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = {
|
||||
[CF_IDE] = { 1, 1<<9 },
|
||||
[CF_CD] = { 2, 1<<8 },
|
||||
[PCI_INTA] = { 9, 1<<14 },
|
||||
[PCI_INTB] = { 10, 1<<13 },
|
||||
[PCI_INTC] = { 3, 1<<12 },
|
||||
[PCI_INTD] = { 0, 1<<11 },
|
||||
[SM501] = { 4, 1<<10 },
|
||||
[KEY] = { 5, 1<<6 },
|
||||
[RTC_A] = { 6, 1<<5 },
|
||||
[RTC_T] = { 7, 1<<4 },
|
||||
[SDCARD] = { 8, 1<<7 },
|
||||
[EXT] = { 11, 1<<0 },
|
||||
[TP] = { 12, 1<<15 },
|
||||
[CF_IDE] = { 1, 1 << 9 },
|
||||
[CF_CD] = { 2, 1 << 8 },
|
||||
[PCI_INTA] = { 9, 1 << 14 },
|
||||
[PCI_INTB] = { 10, 1 << 13 },
|
||||
[PCI_INTC] = { 3, 1 << 12 },
|
||||
[PCI_INTD] = { 0, 1 << 11 },
|
||||
[SM501] = { 4, 1 << 10 },
|
||||
[KEY] = { 5, 1 << 6 },
|
||||
[RTC_A] = { 6, 1 << 5 },
|
||||
[RTC_T] = { 7, 1 << 4 },
|
||||
[SDCARD] = { 8, 1 << 7 },
|
||||
[EXT] = { 11, 1 << 0 },
|
||||
[TP] = { 12, 1 << 15 },
|
||||
};
|
||||
|
||||
static void update_irl(r2d_fpga_t *fpga)
|
||||
{
|
||||
int i, irl = 15;
|
||||
for (i = 0; i < NR_IRQS; i++)
|
||||
if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk)
|
||||
if (irqtab[i].irl < irl)
|
||||
irl = irqtab[i].irl;
|
||||
for (i = 0; i < NR_IRQS; i++) {
|
||||
if ((fpga->irlmon & fpga->irlmsk & irqtab[i].msk) &&
|
||||
irqtab[i].irl < irl) {
|
||||
irl = irqtab[i].irl;
|
||||
}
|
||||
}
|
||||
qemu_set_irq(fpga->irl, irl ^ 15);
|
||||
}
|
||||
|
||||
static void r2d_fpga_irq_set(void *opaque, int n, int level)
|
||||
{
|
||||
r2d_fpga_t *fpga = opaque;
|
||||
if (level)
|
||||
if (level) {
|
||||
fpga->irlmon |= irqtab[n].msk;
|
||||
else
|
||||
} else {
|
||||
fpga->irlmon &= ~irqtab[n].msk;
|
||||
}
|
||||
update_irl(fpga);
|
||||
}
|
||||
|
||||
@@ -306,7 +310,7 @@ static void r2d_init(MachineState *machine)
|
||||
/* NIC: rtl8139 on-board, and 2 slots. */
|
||||
for (i = 0; i < nb_nics; i++)
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus,
|
||||
"rtl8139", i==0 ? "2" : NULL);
|
||||
"rtl8139", i == 0 ? "2" : NULL);
|
||||
|
||||
/* USB keyboard */
|
||||
usb_create_simple(usb_bus_find(-1), "usb-kbd");
|
||||
@@ -321,8 +325,8 @@ static void r2d_init(MachineState *machine)
|
||||
SDRAM_BASE + LINUX_LOAD_OFFSET,
|
||||
INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET);
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
|
||||
exit(1);
|
||||
error_report("qemu: could not load kernel '%s'", kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* initialization which should be done by firmware */
|
||||
@@ -330,7 +334,8 @@ static void r2d_init(MachineState *machine)
|
||||
MEMTXATTRS_UNSPECIFIED, NULL); /* cs3 SDRAM */
|
||||
address_space_stw(&address_space_memory, SH7750_BCR2, 3 << (3 * 2),
|
||||
MEMTXATTRS_UNSPECIFIED, NULL); /* cs3 32bit */
|
||||
reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */
|
||||
/* Start from P2 area */
|
||||
reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000;
|
||||
}
|
||||
|
||||
if (initrd_filename) {
|
||||
@@ -341,8 +346,8 @@ static void r2d_init(MachineState *machine)
|
||||
SDRAM_SIZE - INITRD_LOAD_OFFSET);
|
||||
|
||||
if (initrd_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename);
|
||||
exit(1);
|
||||
error_report("qemu: could not load initrd '%s'", initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* initialization which should be done by firmware */
|
||||
@@ -352,8 +357,10 @@ static void r2d_init(MachineState *machine)
|
||||
}
|
||||
|
||||
if (kernel_cmdline) {
|
||||
/* I see no evidence that this .kernel_cmdline buffer requires
|
||||
NUL-termination, so using strncpy should be ok. */
|
||||
/*
|
||||
* I see no evidence that this .kernel_cmdline buffer requires
|
||||
* NUL-termination, so using strncpy should be ok.
|
||||
*/
|
||||
strncpy(boot_params.kernel_cmdline, kernel_cmdline,
|
||||
sizeof(boot_params.kernel_cmdline));
|
||||
}
|
||||
|
||||
+332
-299
File diff suppressed because it is too large
Load Diff
+75
-73
@@ -12,85 +12,87 @@ typedef struct {
|
||||
|
||||
static regname_t regnames[] = {
|
||||
REGNAME(SH7750_PTEH_A7)
|
||||
REGNAME(SH7750_PTEL_A7)
|
||||
REGNAME(SH7750_PTEA_A7)
|
||||
REGNAME(SH7750_TTB_A7)
|
||||
REGNAME(SH7750_TEA_A7)
|
||||
REGNAME(SH7750_MMUCR_A7)
|
||||
REGNAME(SH7750_CCR_A7)
|
||||
REGNAME(SH7750_QACR0_A7)
|
||||
REGNAME(SH7750_QACR1_A7)
|
||||
REGNAME(SH7750_TRA_A7)
|
||||
REGNAME(SH7750_EXPEVT_A7)
|
||||
REGNAME(SH7750_INTEVT_A7)
|
||||
REGNAME(SH7750_STBCR_A7)
|
||||
REGNAME(SH7750_STBCR2_A7)
|
||||
REGNAME(SH7750_FRQCR_A7)
|
||||
REGNAME(SH7750_WTCNT_A7)
|
||||
REGNAME(SH7750_WTCSR_A7)
|
||||
REGNAME(SH7750_R64CNT_A7)
|
||||
REGNAME(SH7750_RSECCNT_A7)
|
||||
REGNAME(SH7750_RMINCNT_A7)
|
||||
REGNAME(SH7750_RHRCNT_A7)
|
||||
REGNAME(SH7750_RWKCNT_A7)
|
||||
REGNAME(SH7750_RDAYCNT_A7)
|
||||
REGNAME(SH7750_RMONCNT_A7)
|
||||
REGNAME(SH7750_RYRCNT_A7)
|
||||
REGNAME(SH7750_RSECAR_A7)
|
||||
REGNAME(SH7750_RMINAR_A7)
|
||||
REGNAME(SH7750_RHRAR_A7)
|
||||
REGNAME(SH7750_RWKAR_A7)
|
||||
REGNAME(SH7750_RDAYAR_A7)
|
||||
REGNAME(SH7750_RMONAR_A7)
|
||||
REGNAME(SH7750_RCR1_A7)
|
||||
REGNAME(SH7750_RCR2_A7)
|
||||
REGNAME(SH7750_BCR1_A7)
|
||||
REGNAME(SH7750_BCR2_A7)
|
||||
REGNAME(SH7750_WCR1_A7)
|
||||
REGNAME(SH7750_WCR2_A7)
|
||||
REGNAME(SH7750_WCR3_A7)
|
||||
REGNAME(SH7750_MCR_A7)
|
||||
REGNAME(SH7750_PCR_A7)
|
||||
REGNAME(SH7750_RTCSR_A7)
|
||||
REGNAME(SH7750_RTCNT_A7)
|
||||
REGNAME(SH7750_RTCOR_A7)
|
||||
REGNAME(SH7750_RFCR_A7)
|
||||
REGNAME(SH7750_SAR0_A7)
|
||||
REGNAME(SH7750_SAR1_A7)
|
||||
REGNAME(SH7750_SAR2_A7)
|
||||
REGNAME(SH7750_SAR3_A7)
|
||||
REGNAME(SH7750_DAR0_A7)
|
||||
REGNAME(SH7750_DAR1_A7)
|
||||
REGNAME(SH7750_DAR2_A7)
|
||||
REGNAME(SH7750_DAR3_A7)
|
||||
REGNAME(SH7750_DMATCR0_A7)
|
||||
REGNAME(SH7750_DMATCR1_A7)
|
||||
REGNAME(SH7750_DMATCR2_A7)
|
||||
REGNAME(SH7750_DMATCR3_A7)
|
||||
REGNAME(SH7750_CHCR0_A7)
|
||||
REGNAME(SH7750_CHCR1_A7)
|
||||
REGNAME(SH7750_CHCR2_A7)
|
||||
REGNAME(SH7750_CHCR3_A7)
|
||||
REGNAME(SH7750_DMAOR_A7)
|
||||
REGNAME(SH7750_PCTRA_A7)
|
||||
REGNAME(SH7750_PDTRA_A7)
|
||||
REGNAME(SH7750_PCTRB_A7)
|
||||
REGNAME(SH7750_PDTRB_A7)
|
||||
REGNAME(SH7750_GPIOIC_A7)
|
||||
REGNAME(SH7750_ICR_A7)
|
||||
REGNAME(SH7750_BCR3_A7)
|
||||
REGNAME(SH7750_BCR4_A7)
|
||||
REGNAME(SH7750_SDMR2_A7)
|
||||
REGNAME(SH7750_SDMR3_A7) {(uint32_t) - 1, NULL}
|
||||
REGNAME(SH7750_PTEL_A7)
|
||||
REGNAME(SH7750_PTEA_A7)
|
||||
REGNAME(SH7750_TTB_A7)
|
||||
REGNAME(SH7750_TEA_A7)
|
||||
REGNAME(SH7750_MMUCR_A7)
|
||||
REGNAME(SH7750_CCR_A7)
|
||||
REGNAME(SH7750_QACR0_A7)
|
||||
REGNAME(SH7750_QACR1_A7)
|
||||
REGNAME(SH7750_TRA_A7)
|
||||
REGNAME(SH7750_EXPEVT_A7)
|
||||
REGNAME(SH7750_INTEVT_A7)
|
||||
REGNAME(SH7750_STBCR_A7)
|
||||
REGNAME(SH7750_STBCR2_A7)
|
||||
REGNAME(SH7750_FRQCR_A7)
|
||||
REGNAME(SH7750_WTCNT_A7)
|
||||
REGNAME(SH7750_WTCSR_A7)
|
||||
REGNAME(SH7750_R64CNT_A7)
|
||||
REGNAME(SH7750_RSECCNT_A7)
|
||||
REGNAME(SH7750_RMINCNT_A7)
|
||||
REGNAME(SH7750_RHRCNT_A7)
|
||||
REGNAME(SH7750_RWKCNT_A7)
|
||||
REGNAME(SH7750_RDAYCNT_A7)
|
||||
REGNAME(SH7750_RMONCNT_A7)
|
||||
REGNAME(SH7750_RYRCNT_A7)
|
||||
REGNAME(SH7750_RSECAR_A7)
|
||||
REGNAME(SH7750_RMINAR_A7)
|
||||
REGNAME(SH7750_RHRAR_A7)
|
||||
REGNAME(SH7750_RWKAR_A7)
|
||||
REGNAME(SH7750_RDAYAR_A7)
|
||||
REGNAME(SH7750_RMONAR_A7)
|
||||
REGNAME(SH7750_RCR1_A7)
|
||||
REGNAME(SH7750_RCR2_A7)
|
||||
REGNAME(SH7750_BCR1_A7)
|
||||
REGNAME(SH7750_BCR2_A7)
|
||||
REGNAME(SH7750_WCR1_A7)
|
||||
REGNAME(SH7750_WCR2_A7)
|
||||
REGNAME(SH7750_WCR3_A7)
|
||||
REGNAME(SH7750_MCR_A7)
|
||||
REGNAME(SH7750_PCR_A7)
|
||||
REGNAME(SH7750_RTCSR_A7)
|
||||
REGNAME(SH7750_RTCNT_A7)
|
||||
REGNAME(SH7750_RTCOR_A7)
|
||||
REGNAME(SH7750_RFCR_A7)
|
||||
REGNAME(SH7750_SAR0_A7)
|
||||
REGNAME(SH7750_SAR1_A7)
|
||||
REGNAME(SH7750_SAR2_A7)
|
||||
REGNAME(SH7750_SAR3_A7)
|
||||
REGNAME(SH7750_DAR0_A7)
|
||||
REGNAME(SH7750_DAR1_A7)
|
||||
REGNAME(SH7750_DAR2_A7)
|
||||
REGNAME(SH7750_DAR3_A7)
|
||||
REGNAME(SH7750_DMATCR0_A7)
|
||||
REGNAME(SH7750_DMATCR1_A7)
|
||||
REGNAME(SH7750_DMATCR2_A7)
|
||||
REGNAME(SH7750_DMATCR3_A7)
|
||||
REGNAME(SH7750_CHCR0_A7)
|
||||
REGNAME(SH7750_CHCR1_A7)
|
||||
REGNAME(SH7750_CHCR2_A7)
|
||||
REGNAME(SH7750_CHCR3_A7)
|
||||
REGNAME(SH7750_DMAOR_A7)
|
||||
REGNAME(SH7750_PCTRA_A7)
|
||||
REGNAME(SH7750_PDTRA_A7)
|
||||
REGNAME(SH7750_PCTRB_A7)
|
||||
REGNAME(SH7750_PDTRB_A7)
|
||||
REGNAME(SH7750_GPIOIC_A7)
|
||||
REGNAME(SH7750_ICR_A7)
|
||||
REGNAME(SH7750_BCR3_A7)
|
||||
REGNAME(SH7750_BCR4_A7)
|
||||
REGNAME(SH7750_SDMR2_A7)
|
||||
REGNAME(SH7750_SDMR3_A7)
|
||||
{ (uint32_t)-1, NULL }
|
||||
};
|
||||
|
||||
const char *regname(uint32_t addr)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; regnames[i].regaddr != (uint32_t) - 1; i++) {
|
||||
if (regnames[i].regaddr == addr)
|
||||
return regnames[i].regname;
|
||||
for (i = 0; regnames[i].regaddr != (uint32_t)-1; i++) {
|
||||
if (regnames[i].regaddr == addr) {
|
||||
return regnames[i].regname;
|
||||
}
|
||||
}
|
||||
|
||||
return "<unknown reg>";
|
||||
|
||||
+764
-764
File diff suppressed because it is too large
Load Diff
+6
-6
@@ -22,11 +22,11 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
Shix 2.0 board by Alexis Polti, described at
|
||||
https://web.archive.org/web/20070917001736/perso.enst.fr/~polti/realisations/shix20
|
||||
|
||||
More information in target/sh4/README.sh4
|
||||
*/
|
||||
* Shix 2.0 board by Alexis Polti, described at
|
||||
* https://web.archive.org/web/20070917001736/perso.enst.fr/~polti/realisations/shix20
|
||||
*
|
||||
* More information in target/sh4/README.sh4
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "cpu.h"
|
||||
@@ -48,7 +48,7 @@ static void shix_init(MachineState *machine)
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *sdram = g_new(MemoryRegion, 2);
|
||||
const char *bios_name = machine->firmware ?: BIOS_FILENAME;
|
||||
|
||||
|
||||
cpu = SUPERH_CPU(cpu_create(machine->cpu_type));
|
||||
|
||||
/* Allocate memory space */
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# sh7750.c
|
||||
sh7750_porta(uint16_t prev, uint16_t cur, uint16_t pdtr, uint16_t pctr) "porta changed from 0x%04x to 0x%04x\npdtra=0x%04x, pctra=0x%08x"
|
||||
sh7750_portb(uint16_t prev, uint16_t cur, uint16_t pdtr, uint16_t pctr) "portb changed from 0x%04x to 0x%04x\npdtrb=0x%04x, pctrb=0x%08x"
|
||||
@@ -0,0 +1 @@
|
||||
#include "trace/trace-hw_sh4.h"
|
||||
+78
-73
@@ -10,13 +10,12 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "exec/memory.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sh4/sh.h"
|
||||
#include "hw/timer/tmu012.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
//#define DEBUG_TIMER
|
||||
#include "trace.h"
|
||||
|
||||
#define TIMER_TCR_TPSC (7 << 0)
|
||||
#define TIMER_TCR_CKEG (3 << 3)
|
||||
@@ -46,24 +45,24 @@ typedef struct {
|
||||
int feat;
|
||||
int enabled;
|
||||
qemu_irq irq;
|
||||
} sh_timer_state;
|
||||
} SHTimerState;
|
||||
|
||||
/* Check all active timers, and schedule the next timer interrupt. */
|
||||
|
||||
static void sh_timer_update(sh_timer_state *s)
|
||||
static void sh_timer_update(SHTimerState *s)
|
||||
{
|
||||
int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE);
|
||||
|
||||
if (new_level != s->old_level)
|
||||
qemu_set_irq (s->irq, new_level);
|
||||
|
||||
if (new_level != s->old_level) {
|
||||
qemu_set_irq(s->irq, new_level);
|
||||
}
|
||||
s->old_level = s->int_level;
|
||||
s->int_level = new_level;
|
||||
}
|
||||
|
||||
static uint32_t sh_timer_read(void *opaque, hwaddr offset)
|
||||
{
|
||||
sh_timer_state *s = (sh_timer_state *)opaque;
|
||||
SHTimerState *s = opaque;
|
||||
|
||||
switch (offset >> 2) {
|
||||
case OFFSET_TCOR:
|
||||
@@ -73,19 +72,18 @@ static uint32_t sh_timer_read(void *opaque, hwaddr offset)
|
||||
case OFFSET_TCR:
|
||||
return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0);
|
||||
case OFFSET_TCPR:
|
||||
if (s->feat & TIMER_FEAT_CAPT)
|
||||
if (s->feat & TIMER_FEAT_CAPT) {
|
||||
return s->tcpr;
|
||||
/* fall through */
|
||||
default:
|
||||
hw_error("sh_timer_read: Bad offset %x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sh_timer_write(void *opaque, hwaddr offset,
|
||||
uint32_t value)
|
||||
static void sh_timer_write(void *opaque, hwaddr offset, uint32_t value)
|
||||
{
|
||||
sh_timer_state *s = (sh_timer_state *)opaque;
|
||||
SHTimerState *s = opaque;
|
||||
int freq;
|
||||
|
||||
switch (offset >> 2) {
|
||||
@@ -104,19 +102,30 @@ static void sh_timer_write(void *opaque, hwaddr offset,
|
||||
case OFFSET_TCR:
|
||||
ptimer_transaction_begin(s->timer);
|
||||
if (s->enabled) {
|
||||
/* Pause the timer if it is running. This may cause some
|
||||
inaccuracy dure to rounding, but avoids a whole lot of other
|
||||
messyness. */
|
||||
/*
|
||||
* Pause the timer if it is running. This may cause some inaccuracy
|
||||
* due to rounding, but avoids a whole lot of other messiness
|
||||
*/
|
||||
ptimer_stop(s->timer);
|
||||
}
|
||||
freq = s->freq;
|
||||
/* ??? Need to recalculate expiry time after changing divisor. */
|
||||
switch (value & TIMER_TCR_TPSC) {
|
||||
case 0: freq >>= 2; break;
|
||||
case 1: freq >>= 4; break;
|
||||
case 2: freq >>= 6; break;
|
||||
case 3: freq >>= 8; break;
|
||||
case 4: freq >>= 10; break;
|
||||
case 0:
|
||||
freq >>= 2;
|
||||
break;
|
||||
case 1:
|
||||
freq >>= 4;
|
||||
break;
|
||||
case 2:
|
||||
freq >>= 6;
|
||||
break;
|
||||
case 3:
|
||||
freq >>= 8;
|
||||
break;
|
||||
case 4:
|
||||
freq >>= 10;
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
if (s->feat & TIMER_FEAT_EXTCLK) {
|
||||
@@ -124,7 +133,8 @@ static void sh_timer_write(void *opaque, hwaddr offset,
|
||||
}
|
||||
/* fallthrough */
|
||||
default:
|
||||
hw_error("sh_timer_write: Reserved TPSC value\n");
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Reserved TPSC value\n", __func__);
|
||||
}
|
||||
switch ((value & TIMER_TCR_CKEG) >> 3) {
|
||||
case 0:
|
||||
@@ -137,7 +147,8 @@ static void sh_timer_write(void *opaque, hwaddr offset,
|
||||
}
|
||||
/* fallthrough */
|
||||
default:
|
||||
hw_error("sh_timer_write: Reserved CKEG value\n");
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Reserved CKEG value\n", __func__);
|
||||
}
|
||||
switch ((value & TIMER_TCR_ICPE) >> 6) {
|
||||
case 0:
|
||||
@@ -149,7 +160,8 @@ static void sh_timer_write(void *opaque, hwaddr offset,
|
||||
}
|
||||
/* fallthrough */
|
||||
default:
|
||||
hw_error("sh_timer_write: Reserved ICPE value\n");
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Reserved ICPE value\n", __func__);
|
||||
}
|
||||
if ((value & TIMER_TCR_UNF) == 0) {
|
||||
s->int_level = 0;
|
||||
@@ -158,13 +170,15 @@ static void sh_timer_write(void *opaque, hwaddr offset,
|
||||
value &= ~TIMER_TCR_UNF;
|
||||
|
||||
if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT))) {
|
||||
hw_error("sh_timer_write: Reserved ICPF value\n");
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Reserved ICPF value\n", __func__);
|
||||
}
|
||||
|
||||
value &= ~TIMER_TCR_ICPF; /* capture not supported */
|
||||
|
||||
if (value & TIMER_TCR_RESERVED) {
|
||||
hw_error("sh_timer_write: Reserved TCR bits set\n");
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Reserved TCR bits set\n", __func__);
|
||||
}
|
||||
s->tcr = value;
|
||||
ptimer_set_limit(s->timer, s->tcor, 0);
|
||||
@@ -182,19 +196,17 @@ static void sh_timer_write(void *opaque, hwaddr offset,
|
||||
}
|
||||
/* fallthrough */
|
||||
default:
|
||||
hw_error("sh_timer_write: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
|
||||
}
|
||||
sh_timer_update(s);
|
||||
}
|
||||
|
||||
static void sh_timer_start_stop(void *opaque, int enable)
|
||||
{
|
||||
sh_timer_state *s = (sh_timer_state *)opaque;
|
||||
|
||||
#ifdef DEBUG_TIMER
|
||||
printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled);
|
||||
#endif
|
||||
SHTimerState *s = opaque;
|
||||
|
||||
trace_sh_timer_start_stop(enable, s->enabled);
|
||||
ptimer_transaction_begin(s->timer);
|
||||
if (s->enabled && !enable) {
|
||||
ptimer_stop(s->timer);
|
||||
@@ -204,24 +216,20 @@ static void sh_timer_start_stop(void *opaque, int enable)
|
||||
}
|
||||
ptimer_transaction_commit(s->timer);
|
||||
s->enabled = !!enable;
|
||||
|
||||
#ifdef DEBUG_TIMER
|
||||
printf("sh_timer_start_stop done %d\n", s->enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void sh_timer_tick(void *opaque)
|
||||
{
|
||||
sh_timer_state *s = (sh_timer_state *)opaque;
|
||||
SHTimerState *s = opaque;
|
||||
s->int_level = s->enabled;
|
||||
sh_timer_update(s);
|
||||
}
|
||||
|
||||
static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq)
|
||||
{
|
||||
sh_timer_state *s;
|
||||
SHTimerState *s;
|
||||
|
||||
s = (sh_timer_state *)g_malloc0(sizeof(sh_timer_state));
|
||||
s = g_malloc0(sizeof(*s));
|
||||
s->freq = freq;
|
||||
s->feat = feat;
|
||||
s->tcor = 0xffffffff;
|
||||
@@ -252,50 +260,49 @@ typedef struct {
|
||||
int feat;
|
||||
} tmu012_state;
|
||||
|
||||
static uint64_t tmu012_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
static uint64_t tmu012_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
tmu012_state *s = (tmu012_state *)opaque;
|
||||
|
||||
#ifdef DEBUG_TIMER
|
||||
printf("tmu012_read 0x%lx\n", (unsigned long) offset);
|
||||
#endif
|
||||
tmu012_state *s = opaque;
|
||||
|
||||
trace_sh_timer_read(offset);
|
||||
if (offset >= 0x20) {
|
||||
if (!(s->feat & TMU012_FEAT_3CHAN)) {
|
||||
hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad channel offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
return sh_timer_read(s->timer[2], offset - 0x20);
|
||||
}
|
||||
|
||||
if (offset >= 0x14)
|
||||
if (offset >= 0x14) {
|
||||
return sh_timer_read(s->timer[1], offset - 0x14);
|
||||
|
||||
if (offset >= 0x08)
|
||||
}
|
||||
if (offset >= 0x08) {
|
||||
return sh_timer_read(s->timer[0], offset - 0x08);
|
||||
|
||||
if (offset == 4)
|
||||
}
|
||||
if (offset == 4) {
|
||||
return s->tstr;
|
||||
|
||||
if ((s->feat & TMU012_FEAT_TOCR) && offset == 0)
|
||||
}
|
||||
if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) {
|
||||
return s->tocr;
|
||||
}
|
||||
|
||||
hw_error("tmu012_write: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tmu012_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
tmu012_state *s = (tmu012_state *)opaque;
|
||||
|
||||
#ifdef DEBUG_TIMER
|
||||
printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
|
||||
#endif
|
||||
tmu012_state *s = opaque;
|
||||
|
||||
trace_sh_timer_write(offset, value);
|
||||
if (offset >= 0x20) {
|
||||
if (!(s->feat & TMU012_FEAT_3CHAN)) {
|
||||
hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad channel offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
sh_timer_write(s->timer[2], offset - 0x20, value);
|
||||
return;
|
||||
@@ -318,7 +325,7 @@ static void tmu012_write(void *opaque, hwaddr offset,
|
||||
sh_timer_start_stop(s->timer[2], value & (1 << 2));
|
||||
} else {
|
||||
if (value & (1 << 2)) {
|
||||
hw_error("tmu012_write: Bad channel\n");
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad channel\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,15 +344,14 @@ static const MemoryRegionOps tmu012_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
void tmu012_init(MemoryRegion *sysmem, hwaddr base,
|
||||
int feat, uint32_t freq,
|
||||
void tmu012_init(MemoryRegion *sysmem, hwaddr base, int feat, uint32_t freq,
|
||||
qemu_irq ch0_irq, qemu_irq ch1_irq,
|
||||
qemu_irq ch2_irq0, qemu_irq ch2_irq1)
|
||||
{
|
||||
tmu012_state *s;
|
||||
int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0;
|
||||
|
||||
s = (tmu012_state *)g_malloc0(sizeof(tmu012_state));
|
||||
s = g_malloc0(sizeof(*s));
|
||||
s->feat = feat;
|
||||
s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq);
|
||||
s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq);
|
||||
@@ -354,15 +360,14 @@ void tmu012_init(MemoryRegion *sysmem, hwaddr base,
|
||||
ch2_irq0); /* ch2_irq1 not supported */
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &tmu012_ops, s,
|
||||
"timer", 0x100000000ULL);
|
||||
memory_region_init_io(&s->iomem, NULL, &tmu012_ops, s, "timer", 0x30);
|
||||
|
||||
memory_region_init_alias(&s->iomem_p4, NULL, "timer-p4",
|
||||
&s->iomem, 0, 0x1000);
|
||||
&s->iomem, 0, memory_region_size(&s->iomem));
|
||||
memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
|
||||
|
||||
memory_region_init_alias(&s->iomem_a7, NULL, "timer-a7",
|
||||
&s->iomem, 0, 0x1000);
|
||||
&s->iomem, 0, memory_region_size(&s->iomem));
|
||||
memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
|
||||
/* ??? Save/restore. */
|
||||
}
|
||||
|
||||
@@ -94,3 +94,8 @@ sifive_pwm_set_alarm(uint64_t alarm, uint64_t now) "Setting alarm to: 0x%" PRIx6
|
||||
sifive_pwm_interrupt(int num) "Interrupt %d"
|
||||
sifive_pwm_read(uint64_t offset) "Read at address: 0x%" PRIx64
|
||||
sifive_pwm_write(uint64_t data, uint64_t offset) "Write 0x%" PRIx64 " at address: 0x%" PRIx64
|
||||
|
||||
# sh_timer.c
|
||||
sh_timer_start_stop(int enable, int current) "%d (%d)"
|
||||
sh_timer_read(uint64_t offset) "tmu012_read 0x%" PRIx64
|
||||
sh_timer_write(uint64_t offset, uint64_t value) "tmu012_write 0x%" PRIx64 " 0x%08" PRIx64
|
||||
|
||||
+6
-13
@@ -44,25 +44,18 @@ typedef struct {
|
||||
uint16_t portbmask_trigger;
|
||||
/* Return 0 if no action was taken */
|
||||
int (*port_change_cb) (uint16_t porta, uint16_t portb,
|
||||
uint16_t * periph_pdtra,
|
||||
uint16_t * periph_portdira,
|
||||
uint16_t * periph_pdtrb,
|
||||
uint16_t * periph_portdirb);
|
||||
uint16_t *periph_pdtra,
|
||||
uint16_t *periph_portdira,
|
||||
uint16_t *periph_pdtrb,
|
||||
uint16_t *periph_portdirb);
|
||||
} sh7750_io_device;
|
||||
|
||||
int sh7750_register_io_device(struct SH7750State *s,
|
||||
sh7750_io_device * device);
|
||||
sh7750_io_device *device);
|
||||
|
||||
/* sh_serial.c */
|
||||
#define TYPE_SH_SERIAL "sh-serial"
|
||||
#define SH_SERIAL_FEAT_SCIF (1 << 0)
|
||||
void sh_serial_init(MemoryRegion *sysmem,
|
||||
hwaddr base, int feat,
|
||||
uint32_t freq, Chardev *chr,
|
||||
qemu_irq eri_source,
|
||||
qemu_irq rxi_source,
|
||||
qemu_irq txi_source,
|
||||
qemu_irq tei_source,
|
||||
qemu_irq bri_source);
|
||||
|
||||
/* sh7750.c */
|
||||
qemu_irq sh7750_irl(struct SH7750State *s);
|
||||
|
||||
@@ -58,7 +58,7 @@ struct intc_desc {
|
||||
};
|
||||
|
||||
int sh_intc_get_pending_vector(struct intc_desc *desc, int imask);
|
||||
struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id);
|
||||
|
||||
void sh_intc_toggle_source(struct intc_source *source,
|
||||
int enable_adj, int assert_adj);
|
||||
|
||||
|
||||
@@ -2459,6 +2459,7 @@ if have_system
|
||||
'hw/s390x',
|
||||
'hw/scsi',
|
||||
'hw/sd',
|
||||
'hw/sh4',
|
||||
'hw/sparc',
|
||||
'hw/sparc64',
|
||||
'hw/ssi',
|
||||
|
||||
Reference in New Issue
Block a user