From 83fa1010ae342c5ad0392182fcdcce438c71b163 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 13:26:33 +0000 Subject: [PATCH] EtraxFS board support, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3364 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/etraxfs.c | 178 ++++++++++++++++++++++++++++++ hw/etraxfs_ser.c | 122 +++++++++++++++++++++ hw/etraxfs_timer.c | 268 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 568 insertions(+) create mode 100644 hw/etraxfs.c create mode 100644 hw/etraxfs_ser.c create mode 100644 hw/etraxfs_timer.c diff --git a/hw/etraxfs.c b/hw/etraxfs.c new file mode 100644 index 0000000000..cf0f38493c --- /dev/null +++ b/hw/etraxfs.c @@ -0,0 +1,178 @@ +/* + * QEMU ETRAX System Emulator + * + * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. + * + * 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 +#include +#include "vl.h" + +extern FILE *logfile; + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); +} + +static uint32_t fs_mmio_readb (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} +static uint32_t fs_mmio_readw (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} + +static uint32_t fs_mmio_readl (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x p=%x\n", __func__, addr, env->pc); + return r; +} + +static void +fs_mmio_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} +static void +fs_mmio_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} +static void +fs_mmio_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} + +static CPUReadMemoryFunc *fs_mmio_read[] = { + &fs_mmio_readb, + &fs_mmio_readw, + &fs_mmio_readl, +}; + +static CPUWriteMemoryFunc *fs_mmio_write[] = { + &fs_mmio_writeb, + &fs_mmio_writew, + &fs_mmio_writel, +}; + + +/* Init functions for different blocks. */ +extern void etraxfs_timer_init(CPUState *env, qemu_irq *irqs); +extern void etraxfs_ser_init(CPUState *env, qemu_irq *irqs); + +void etrax_ack_irq(CPUState *env, uint32_t mask) +{ + env->pending_interrupts &= ~mask; +} + +static void dummy_cpu_set_irq(void *opaque, int irq, int level) +{ + CPUState *env = opaque; + + /* Hmm, should this really be done here? */ + env->pending_interrupts |= 1 << irq; + cpu_interrupt(env, CPU_INTERRUPT_HARD); +} + +static +void bareetraxfs_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env; + qemu_irq *irqs; + int kernel_size; + int internal_regs; + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "crisv32"; + } + env = cpu_init(); +/* register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); */ + qemu_register_reset(main_cpu_reset, env); + irqs = qemu_allocate_irqs(dummy_cpu_set_irq, env, 32); + + internal_regs = cpu_register_io_memory(0, + fs_mmio_read, fs_mmio_write, env); + /* 0xb0050000 is the last reg. */ + cpu_register_physical_memory (0xac000000, 0x4010000, internal_regs); + /* allocate RAM */ + cpu_register_physical_memory(0x40000000, ram_size, IO_MEM_RAM); + + etraxfs_timer_init(env, irqs); + etraxfs_ser_init(env, irqs); + + kernel_size = load_image(kernel_filename, phys_ram_base + 0x4000); + /* magic for boot. */ + env->regs[8] = 0x56902387; + env->regs[9] = 0x40004000 + kernel_size; + env->pc = 0x40004000; + + { + unsigned char *ptr = phys_ram_base + 0x4000; + int i; + for (i = 0; i < 8; i++) + { + printf ("%2.2x ", ptr[i]); + } + printf("\n"); + } + + printf ("pc =%x\n", env->pc); + printf ("ram size =%d\n", ram_size); + printf ("kernel name =%s\n", kernel_filename); + printf ("kernel size =%d\n", kernel_size); + printf ("cpu haltd =%d\n", env->halted); +} + +void DMA_run(void) +{ +} + +void pic_info() +{ +} + +void irq_info() +{ +} + +QEMUMachine bareetraxfs_machine = { + "bareetraxfs", + "Bare ETRAX FS board", + bareetraxfs_init, +}; diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c new file mode 100644 index 0000000000..3ff6ff77ce --- /dev/null +++ b/hw/etraxfs_ser.c @@ -0,0 +1,122 @@ +/* + * QEMU ETRAX System Emulator + * + * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. + * + * 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 +#include +#include "vl.h" + +#define RW_TR_DMA_EN 0xb0026004 +#define RW_DOUT 0xb002601c +#define RW_STAT_DIN 0xb0026020 +#define R_STAT_DIN 0xb0026024 + +static uint32_t ser_readb (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} +static uint32_t ser_readw (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} + +static uint32_t ser_readl (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + + switch (addr) + { + case RW_TR_DMA_EN: + break; + case R_STAT_DIN: + r |= 1 << 24; /* set tr_rdy. */ + r |= 1 << 22; /* set tr_idle. */ + break; + + default: + printf ("%s %x p=%x\n", __func__, addr, env->pc); + break; + } + return r; +} + +static void +ser_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} +static void +ser_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} +static void +ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + + switch (addr) + { + case RW_TR_DMA_EN: + break; + case RW_DOUT: + if (isprint(value) || isspace(value)) + putchar(value); + else + putchar('.'); + break; + default: + printf ("%s %x %x pc=%x\n", + __func__, addr, value, env->pc); + break; + } +} + +static CPUReadMemoryFunc *ser_read[] = { + &ser_readb, + &ser_readw, + &ser_readl, +}; + +static CPUWriteMemoryFunc *ser_write[] = { + &ser_writeb, + &ser_writew, + &ser_writel, +}; + +void etraxfs_ser_init(CPUState *env, qemu_irq *irqs) +{ + int ser_regs; + + ser_regs = cpu_register_io_memory(0, ser_read, ser_write, env); + cpu_register_physical_memory (0xb0026000, 0x3c, ser_regs); +} diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c new file mode 100644 index 0000000000..1c2e4035f0 --- /dev/null +++ b/hw/etraxfs_timer.c @@ -0,0 +1,268 @@ +/* + * QEMU ETRAX System Emulator + * + * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. + * + * 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 +#include +#include "vl.h" + +void etrax_ack_irq(CPUState *env, uint32_t mask); + +#define R_TIME 0xb001e038 +#define RW_TMR0_DIV 0xb001e000 +#define R_TMR0_DATA 0xb001e004 +#define RW_TMR0_CTRL 0xb001e008 +#define RW_TMR1_DIV 0xb001e010 +#define R_TMR1_DATA 0xb001e014 +#define RW_TMR1_CTRL 0xb001e018 + +#define RW_INTR_MASK 0xb001e048 +#define RW_ACK_INTR 0xb001e04c +#define R_INTR 0xb001e050 +#define R_MASKED_INTR 0xb001e054 + + +uint32_t rw_intr_mask; +uint32_t rw_ack_intr; +uint32_t r_intr; + +struct fs_timer_t { + QEMUBH *bh; + unsigned int limit; + int scale; + ptimer_state *ptimer; + CPUState *env; + qemu_irq *irq; + uint32_t mask; +}; + +static struct fs_timer_t timer0; + +/* diff two timevals. Return a single int in us. */ +int diff_timeval_us(struct timeval *a, struct timeval *b) +{ + int diff; + + /* assume these values are signed. */ + diff = (a->tv_sec - b->tv_sec) * 1000 * 1000; + diff += (a->tv_usec - b->tv_usec); + return diff; +} + +static uint32_t timer_readb (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} +static uint32_t timer_readw (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} + +static uint32_t timer_readl (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + + switch (addr) { + case R_TMR0_DATA: + break; + case R_TMR1_DATA: + printf ("R_TMR1_DATA\n"); + break; + case R_TIME: + { + static struct timeval last; + struct timeval now; + gettimeofday(&now, NULL); + if (!(last.tv_sec == 0 && last.tv_usec == 0)) { + r = diff_timeval_us(&now, &last); + r *= 1000; /* convert to ns. */ + r++; /* make sure we increase for each call. */ + } + last = now; + break; + } + + case RW_INTR_MASK: + r = rw_intr_mask; + break; + case R_MASKED_INTR: + r = r_intr & rw_intr_mask; + break; + default: + printf ("%s %x p=%x\n", __func__, addr, env->pc); + break; + } + return r; +} + +static void +timer_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} +static void +timer_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} + +static void write_ctrl(struct fs_timer_t *t, uint32_t v) +{ + int op; + int freq; + int freq_hz; + + op = v & 3; + freq = v >> 2; + freq_hz = 32000000; + + switch (freq) + { + case 0: + case 1: + printf ("extern or disabled timer clock?\n"); + break; + case 4: freq_hz = 29493000; break; + case 5: freq_hz = 32000000; break; + case 6: freq_hz = 32768000; break; + case 7: freq_hz = 100000000; break; + default: + abort(); + break; + } + + printf ("freq_hz=%d limit=%d\n", freq_hz, t->limit); + t->scale = 0; + if (t->limit > 2048) + { + t->scale = 2048; + ptimer_set_period(timer0.ptimer, freq_hz / t->scale); + } + + printf ("op=%d\n", op); + switch (op) + { + case 0: + printf ("limit=%d %d\n", t->limit, t->limit/t->scale); + ptimer_set_limit(t->ptimer, t->limit / t->scale, 1); + break; + case 1: + ptimer_stop(t->ptimer); + break; + case 2: + ptimer_run(t->ptimer, 0); + break; + default: + abort(); + break; + } +} + +static void timer_ack_irq(void) +{ + if (!(r_intr & timer0.mask & rw_intr_mask)) { + qemu_irq_lower(timer0.irq[0]); + etrax_ack_irq(timer0.env, 1 << 0x1b); + } +} + +static void +timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", + __func__, addr, value, env->pc); + switch (addr) + { + case RW_TMR0_DIV: + printf ("RW_TMR0_DIV=%x\n", value); + timer0.limit = value; + break; + case RW_TMR0_CTRL: + printf ("RW_TMR0_CTRL=%x\n", value); + write_ctrl(&timer0, value); + break; + case RW_TMR1_DIV: + printf ("RW_TMR1_DIV=%x\n", value); + break; + case RW_TMR1_CTRL: + printf ("RW_TMR1_CTRL=%x\n", value); + break; + case RW_INTR_MASK: + printf ("RW_INTR_MASK=%x\n", value); + rw_intr_mask = value; + break; + case RW_ACK_INTR: + r_intr &= ~value; + timer_ack_irq(); + break; + default: + printf ("%s %x %x pc=%x\n", + __func__, addr, value, env->pc); + break; + } +} + +static CPUReadMemoryFunc *timer_read[] = { + &timer_readb, + &timer_readw, + &timer_readl, +}; + +static CPUWriteMemoryFunc *timer_write[] = { + &timer_writeb, + &timer_writew, + &timer_writel, +}; + +static void timer_irq(void *opaque) +{ + struct fs_timer_t *t = opaque; + + r_intr |= t->mask; + if (t->mask & rw_intr_mask) { + qemu_irq_raise(t->irq[0]); + } +} + +void etraxfs_timer_init(CPUState *env, qemu_irq *irqs) +{ + int timer_regs; + + timer0.bh = qemu_bh_new(timer_irq, &timer0); + timer0.ptimer = ptimer_init(timer0.bh); + timer0.irq = irqs + 0x1b; + timer0.mask = 1; + timer0.env = env; + + timer_regs = cpu_register_io_memory(0, timer_read, timer_write, env); + cpu_register_physical_memory (0xb001e000, 0x5c, timer_regs); +} -- 2.34.1