* [Qemu-devel] Patch that adds machine "Altera Excalibur"
@ 2006-04-10 11:26 Schwarz, Konrad
2006-04-16 16:24 ` Paul Brook
0 siblings, 1 reply; 3+ messages in thread
From: Schwarz, Konrad @ 2006-04-10 11:26 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 143 bytes --]
Hello,
this patch adds support for the Altera Excalibur device (an FPGA that
supports the ARM922T core).
Regards,
Konrad Schwarz
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Konrad Schwarz.vcf --]
[-- Type: text/x-vcard; name="Konrad Schwarz.vcf", Size: 650 bytes --]
BEGIN:VCARD
VERSION:2.1
N:Schwarz;Konrad
FN:Konrad Schwarz
ORG:Siemens AG;CT SE 2
TITLE:Principal Engineer
TEL;WORK;VOICE:+49 (89) 636-53579
TEL;WORK;FAX:+49 (89) 636-45450
ADR;WORK;ENCODING=QUOTED-PRINTABLE:;53 518;Siemens AG=0D=0ACT SE 2;M=FCnchen;;81730;Germany
LABEL;WORK;ENCODING=QUOTED-PRINTABLE:53 518=0D=0ASiemens AG=0D=0ACT SE 2=0D=0AM=FCnchen 81730=0D=0AGermany
ADR;POSTAL;ENCODING=QUOTED-PRINTABLE:;;Siemens AG=0D=0ACT SE 2;M=FCnchen;;81730;Germany
LABEL;POSTAL;ENCODING=QUOTED-PRINTABLE:Siemens AG=0D=0ACT SE 2=0D=0AM=FCnchen 81730=0D=0AGermany
EMAIL;PREF;INTERNET:konrad.schwarz@siemens.com
REV:20060130T101011Z
END:VCARD
[-- Attachment #3: diffs-altera-excalibur --]
[-- Type: application/octet-stream, Size: 51756 bytes --]
Index: qemu-doc.texi
===================================================================
--- qemu-doc.texi (.../vendor/0.8.0) (revision 67)
+++ qemu-doc.texi (.../tags/altera-excalibur) (revision 67)
@@ -48,6 +48,8 @@
@item Sun4u (64-bit Sparc processor, in progress)
@item Malta board (32-bit MIPS processor)
@item ARM Integrator/CP (ARM1026E processor)
+@item Altera Excalibur FPGA (also ARM1026E processor,
+in real-life it is a ARM922T)
@end itemize
For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported.
@@ -432,6 +434,7 @@
[Linux only, parallel port only] Use host parallel port
@var{N}. Currently only SPP parallel port features can be used.
@item file:filename
+[Unix only]
Write output to filename. No character can be read.
@item stdio
[Unix only] standard input/output
@@ -1390,6 +1393,30 @@
A Linux 2.6 test image is available on the QEMU web site. More
information is available in the QEMU mailing-list archive.
+The Altera Excalibur board is emulated with the following devices:
+
+@itemize @minus
+@item
+ARM1026E CPU---in reality, the Altera Excalibur uses an ARM922T core, which
+implements ARM architecture v4T, but
+the ARM1026E, which implements (at least) ARM architecture v5,
+should be downwards compatible.
+@item
+All Excalibur registers (with limited functionality in many cases)
+@item
+Embedded Peripherals Memory Map
+@item
+The Excalibur UART
+@item
+The Excalibur Timers
+@item
+The Excalibur Watchdog Timer
+@item
+The Excalibur Interrupt Controller
+@item
+The Excalibur Clocks
+@end itemize
+
@chapter QEMU Linux User space emulator
@section Quick Start
Index: Makefile.target
===================================================================
--- Makefile.target (.../vendor/0.8.0) (revision 67)
+++ Makefile.target (.../tags/altera-excalibur) (revision 67)
@@ -334,6 +334,8 @@
endif
ifeq ($(TARGET_BASE_ARCH), arm)
VL_OBJS+= integratorcp.o ps2.o smc91c111.o
+VL_OBJS+= altera-excalibur.o magic-load.o
+altera-excalibur.o: CFLAGS += -Wno-parentheses -O0 -fno-omit-frame-pointer
endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
@@ -437,9 +439,10 @@
ifeq ($(TARGET_BASE_ARCH), sparc)
op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h
-magic_load.o: elf_op.h
endif
+magic-load.o: elf_ops.h
+
ifeq ($(TARGET_BASE_ARCH), ppc)
op.o: op.c op_template.h op_mem.h
op_helper.o: op_helper_mem.h
Index: hw/altera-excalibur.c
===================================================================
--- hw/altera-excalibur.c (.../vendor/0.8.0) (revision 0)
+++ hw/altera-excalibur.c (.../tags/altera-excalibur) (revision 67)
@@ -0,0 +1,1599 @@
+/*
+ * Altera Excalibur System emulation.
+ *
+ * Copyright (c) 2006 Siemens AG
+ * Written by Konrad Schwarz
+ *
+ * This code is licenced under the GPL
+ */
+
+# if 0
+# include <cpu_all.h>
+# endif
+# include <vl.h>
+
+enum altera_excalibur_interrupt_source {
+ altera_excalibur_interrupt_source_PLD0,
+ altera_excalibur_interrupt_source_PLD1,
+ altera_excalibur_interrupt_source_PLD2,
+ altera_excalibur_interrupt_source_PLD3,
+ altera_excalibur_interrupt_source_PLD4,
+ altera_excalibur_interrupt_source_PLD5,
+ altera_excalibur_interrupt_source_EXTPIN,
+ altera_excalibur_interrupt_source_UART,
+ altera_excalibur_interrupt_source_TIMER0,
+ altera_excalibur_interrupt_source_TIMER1,
+ altera_excalibur_interrupt_source_PLL,
+ altera_excalibur_interrupt_source_EBI,
+ altera_excalibur_interrupt_source_STRIPE_PLD,
+ altera_excalibur_interrupt_source_AHB1_2,
+ altera_excalibur_interrupt_source_TX,
+ altera_excalibur_interrupt_source_RX,
+ altera_excalibur_interrupt_source_FASTCOMMS,
+ altera_excalibur_interrupt_source_last
+};
+
+struct altera_excalibur_state {
+ uint64_t wd_start_time;
+ CPUState *s;
+ CharDriverState *chr;
+ QEMUTimer *wd;
+ struct altera_excalibur_timer {
+ uint64_t start_time, end_time;
+ int unsigned long sr, pre, limit, read, interrupt;
+ QEMUTimer *ts;
+ struct altera_excalibur_state *e_;
+ } TIMER [2];
+ int long unsigned
+ CLK_REF,
+ AHB1_FREQ,
+ INT_MASK_SET,
+ INT_SOURCE_STATUS,
+ INT_PLD_PRIORITY,
+ INT_MODE,
+ INT_PRIORITY [altera_excalibur_interrupt_source_last],
+ GP_IO,
+ IDCODE,
+ SRAM0_SR,
+ SRAM1_SR,
+ DPSRAM0_SR,
+ DPSRAM1_SR,
+ BOOT_CR,
+ RESET_SR,
+ WDOG_CR,
+ WDOG_RELOAD,
+ UART_RSR,
+ UART_TSR,
+ UART_FCR,
+ UART_IES,
+ UART_ISR,
+ UART_MC,
+ UART_MCR,
+ UART_MSR,
+ UART_DIV_HI,
+ UART_DIV_LO,
+ IOCR_SDRAM,
+ IOCR_EBI,
+ IOCR_UART,
+ IOCR_TRACE,
+ SDRAM_WIDTH,
+ MMAP_REGISTERS,
+ MMAP_SRAM0,
+ MMAP_SRAM1,
+ MMAP_DPSRAM0,
+ MMAP_DPSRAM1,
+ MMAP_SDRAM0,
+ MMAP_SDRAM1,
+ MMAP_EBI0,
+ MMAP_EBI1,
+ MMAP_EBI2,
+ MMAP_EBI3,
+ MMAP_PLD0,
+ MMAP_PLD1,
+ MMAP_PLD2,
+ MMAP_PLD3,
+ AHB12B_CR,
+ AHB12B_ADDRSR,
+ PLDSB_CR,
+ PLDSB_SR,
+ PLDMB_CR,
+ CONFIG_CONTROL,
+ CONFIG_CLOCK,
+ CONFIG_DATA,
+ CLK_PLL1_MCNT,
+ CLK_PLL1_NCNT,
+ CLK_PLL1_KCNT,
+ CLK_PLL1_CTRL,
+ CLK_PLL2_MCNT,
+ CLK_PLL2_NCNT,
+ CLK_PLL2_KCNT,
+ CLK_PLL2_CTRL,
+ CLK_STATUS,
+ CLK_DERIVE,
+ EBI_SR,
+ EBI_BLOCK0,
+ EBI_BLOCK1,
+ EBI_BLOCK2,
+ EBI_BLOCK3,
+ EBI_INT_SR,
+ EBI_INT_ADDRSR,
+ SDRAM_TIMING1,
+ SDRAM_TIMING2,
+ SDRAM_CONFIG,
+ SDRAM_REFRESH,
+ SDRAM_ADDR,
+ SDRAM_INIT,
+ SDRAM_MODE0,
+ SDRAM_MODE1,
+ AHB12B_SR,
+ PLDSB_ADDRSR;
+ struct altera_excalibur_uart_rx_buf {
+ char rx_data, status;
+ } *uart_rx_buf_read, *uart_rx_buf_write, uart_rx_buf [17];
+ int iomemtype;
+};
+
+static void
+altera_excalibur_calc_interrupt (struct altera_excalibur_state *const e)
+{
+ int unsigned long unmasked = e->INT_SOURCE_STATUS & e->INT_MASK_SET,
+ *prio_reg = e->INT_PRIORITY, i = 1;
+ int unsigned have_IRQ = 0, have_FIQ = 0;
+ switch (e->INT_MODE) {
+ int long unsigned priority;
+ case 0:
+ if (0x3f == (priority = e->INT_PLD_PRIORITY))
+ have_FIQ = 1;
+ else
+ have_IRQ = !!priority;
+ goto skip_PLD_priorities;
+ case 1:
+ have_IRQ == !!(priority = ~0u << 1 & e->INT_PLD_PRIORITY);
+ if (1 & unmasked) {
+ int unsigned long new_priority;
+ new_priority = (1u << 6) - 1 & *prio_reg;
+ if (1u << 6 & new_priority || 0x3f == new_priority)
+ have_FIQ = 1;
+ else
+ have_IRQ |= !!new_priority;
+ if (have_FIQ & have_IRQ)
+ goto end;
+ }
+skip_PLD_priorities:
+ i <<= 6;
+ prio_reg += 6;
+ break;
+ case 2:
+ cpu_abort (e->s, "2 is a reserved value for MODE field "
+ "in the interrupt controller operating "
+ "mode register"
+ "(Altera Excalibur INT_MODE)\n");
+ }
+ for (; unmasked; i <<= 1, ++prio_reg)
+ if (unmasked & i) {
+ int unsigned long new_priority;
+ unmasked &= ~i;
+ new_priority = (1u << 6) - 1 & *prio_reg;
+ if (1u << 6 & new_priority || 0x3f == new_priority)
+ have_FIQ = 1;
+ else
+ have_IRQ |= !!new_priority;
+ if (have_FIQ & have_IRQ)
+ break;
+ }
+end:
+ (have_FIQ? cpu_interrupt: cpu_reset_interrupt) (
+ e->s, CPU_INTERRUPT_FIQ);
+ (have_IRQ? cpu_interrupt: cpu_reset_interrupt) (
+ e->s, CPU_INTERRUPT_HARD);
+}
+
+static void
+altera_excalibur_set_interrupt (struct altera_excalibur_state *const e,
+ int long unsigned source)
+{
+ e->INT_SOURCE_STATUS |= source;
+ altera_excalibur_calc_interrupt (e);
+}
+
+static void
+altera_excalibur_clear_interrupt (struct altera_excalibur_state *const e,
+ int long unsigned source)
+{
+ e->INT_SOURCE_STATUS &= ~source;
+ altera_excalibur_calc_interrupt (e);
+}
+
+static void
+altera_excalibur_wd_callback (void *const opaque)
+{
+# define e ((struct altera_excalibur_state *) opaque)
+ e->RESET_SR |= 1lu << 0;
+# if 0
+ cpu_abort (e->s, "Watchdog Reset: software trigger\n");
+# else
+ cpu_reset (e->s);
+# endif
+# undef e
+}
+
+# define ALTERA_EXCALIBUR_QEMU_RT_COCK_FREQ 1000
+
+static void
+altera_excalibur_timer_callback (void *const opaque)
+{
+# define t ((struct altera_excalibur_timer *) opaque)
+ int unsigned long const sr = t->sr;
+ switch ((1u << 2) - 1 & sr) {
+ case 3: /* reserved */
+ cpu_abort (t->e_->s,
+ "3 is a reserved value for MODE field in timer "
+ "control register "
+ "(Altera Excalibur TIMERx_CR)\n");
+ case 0: /* free running heartbeat mode */ {
+ int long long unsigned pre;
+ qemu_mod_timer (t->ts, t->end_time
+ = (t->start_time = t->end_time)
+ + muldiv64 (((pre = t->pre)?
+ t->limit * (pre + 1): t->limit + 1) - t->read,
+ ALTERA_EXCALIBUR_QEMU_RT_COCK_FREQ,
+ t->e_->AHB1_FREQ >> 1));
+ }
+ break;
+ case 1: /* one shot delay */
+ t->read = 0;
+ t->sr = ~(1u << 4) & sr;
+ break;
+ case 2: /* software interval timer */
+ qemu_mod_timer (t->ts, t->end_time +=
+ muldiv64 (1llu << 32,
+ ALTERA_EXCALIBUR_QEMU_RT_COCK_FREQ,
+ t->e_->AHB1_FREQ >> 1));
+ }
+ t->sr |= 1u << 3;
+ if (1u << 2 & sr & ~sr >> 1)
+ altera_excalibur_set_interrupt (t->e_, t->interrupt);
+# undef t
+}
+
+static int
+altera_excalibur_timer_initialize (struct altera_excalibur_timer *const t,
+ int long unsigned const interrupt,
+ struct altera_excalibur_state *const e)
+{
+
+ if (!(t->ts = qemu_new_timer (rt_clock, altera_excalibur_timer_callback,
+ t)))
+ return 1;
+ t->sr = t->pre = t->limit = t->read = 0;
+ t->interrupt = interrupt;
+ t->e_ = e;
+ return 0;
+}
+
+static void
+altera_excalibur_recalc_uart_interrupts (struct altera_excalibur_state *const e)
+{
+ (e->UART_IES & e->UART_ISR?
+ altera_excalibur_set_interrupt:
+ altera_excalibur_clear_interrupt) (e,
+ 1lu << altera_excalibur_interrupt_source_UART);
+}
+
+# if -1 == -3 / 2
+# define ALTERA_EXCALIBUR_MOD_EXTRA(X) (X) +
+# else
+# define ALTERA_EXCALIBUR_MOD_EXTRA(X)
+# endif
+# define ALTERA_EXCALIBUR_UART_USED(e)\
+ (ALTERA_EXCALIBUR_MOD_EXTRA (sizeof e->uart_rx_buf\
+ / sizeof *e->uart_rx_buf)\
+ e->uart_rx_buf_read - e->uart_rx_buf_write)\
+ % (sizeof e->uart_rx_buf / sizeof *e->uart_rx_buf)
+
+static int
+altera_excalibur_uart_can_read (void *const opaque)
+{
+# define e ((struct altera_excalibur_state *) opaque)
+ return 1lu << 4 & e->UART_MCR? 0:
+ sizeof e->uart_rx_buf / sizeof *e->uart_rx_buf - 1
+ - ALTERA_EXCALIBUR_UART_USED (e);
+# undef e
+}
+
+static int unsigned const altera_excalibur_uart_rx_thresholds [] = {
+ 1, 2, 4, 6, 8, 10, 12, 14
+};
+
+static void
+altera_excalibur_uart_read (void *const opaque, const uint8_t *buf, int size)
+{
+# define e ((struct altera_excalibur_state *) opaque)
+ while (size--) {
+ e->uart_rx_buf_write->rx_data = *buf++;
+ e->uart_rx_buf_write++->status = 0;
+ if (sizeof e->uart_rx_buf / sizeof *e->uart_rx_buf
+ <= e->uart_rx_buf_write - e->uart_rx_buf)
+ e->uart_rx_buf_write = e->uart_rx_buf;
+ }
+ if (1 /* received-character timeout */
+ || altera_excalibur_uart_rx_thresholds [e->UART_FCR >> 5]
+ <= ALTERA_EXCALIBUR_UART_USED (e)) {
+ e->UART_ISR |= 1lu << 0;
+ altera_excalibur_recalc_uart_interrupts (e);
+ }
+# undef e
+}
+
+static void
+altera_excalibur_uart_event_handler (void *opaque, int event)
+{
+# define e ((struct altera_excalibur_state *) opaque)
+ switch (event) {
+ struct altera_excalibur_uart_rx_buf *write;
+ case CHR_EVENT_BREAK:
+ write = e->uart_rx_buf_write;
+ write->rx_data = 0;
+ write++->status = 1lu << 3;
+ if (sizeof e->uart_rx_buf / sizeof *e->uart_rx_buf
+ <= write - e->uart_rx_buf)
+ write = e->uart_rx_buf;
+ if (write == e->uart_rx_buf_read)
+ e->uart_rx_buf_write->status |= 1lu << 0;
+ else
+ e->uart_rx_buf_write = write;
+ break;
+ }
+# undef e
+}
+
+static void
+altera_excalibur_write8 (void *const opaque, target_phys_addr_t const offset,
+ uint32_t const value)
+{
+# define e ((struct altera_excalibur_state *) opaque)
+ cpu_abort (e->s, "Attempt to write 8-bit value %02x to "
+ "Excalibur address map at addresss %08x\n",
+ value, offset);
+}
+
+static void
+altera_excalibur_write16 (void *const opaque, target_phys_addr_t const offset,
+ uint32_t const value)
+{
+# define e ((struct altera_excalibur_state *) opaque)
+ cpu_abort (e->s, "Attempt to write 16-bit value %04x to "
+ "Excalibur address map at addresss %08x\n",
+ value, offset);
+}
+
+static void
+altera_excalibur_write32 (void *const opaque, target_phys_addr_t const offset,
+ uint32_t const value)
+{
+ if (!(1 & e->MMAP_REGISTERS))
+ goto bus_error;
+
+# define e ((struct altera_excalibur_state *) opaque)
+ switch (offset - (~0lu << 14 & e->MMAP_REGISTERS)) {
+ default:
+bus_error:
+ cpu_abort (e->s, "Attempt to write 32-bit value %08x to "
+ "Excalibur address map at addresss %08x\n",
+ value, offset);
+ case 0x0:
+ e->BOOT_CR &= ~((1lu << 3) - 1 & value);
+ break;
+ case 0x4:
+ e->RESET_SR &= ~((1lu << 4) - 1 & value);
+ break;
+# if 0
+ case 0x8:
+ e->IDCODE;
+ case 0x20:
+ e->SRAM0_SR;
+ case 0x24:
+ e->SRAM1_SR;
+ case 0x30:
+ e->DPSRAM0_SR;
+ case 0x38:
+ e->DPSRAM1_SR;
+# endif
+
+ case 0x40:
+ if (1lu << 0 & e->IOCR_SDRAM)
+ goto bus_error;
+ e->IOCR_SDRAM = (1lu << 7) - 1 & value;
+ break;
+ case 0x44:
+ if (1lu << 0 & e->IOCR_EBI)
+ goto bus_error;
+ e->IOCR_EBI = (1lu << 7) - 1 & value;
+ break;
+ case 0x48:
+ if (1lu << 0 & e->IOCR_UART)
+ goto bus_error;
+ e->IOCR_UART = (1lu << 7) - 1 & value;
+ break;
+ case 0x4c:
+ if (1lu << 0 & e->IOCR_TRACE)
+ goto bus_error;
+ e->IOCR_TRACE = (1lu << 5) - 1 & value;
+ break;
+
+ case 0x7c:
+ if (1lu << 0 & e->SDRAM_WIDTH)
+ goto bus_error;
+ e->SDRAM_WIDTH = (1lu << 2) - 1 & value;
+
+ case 0x80:
+ e->MMAP_REGISTERS = (~0lu << 14 | (1lu << 1) - 1) & value;
+ cpu_register_physical_memory (~0lu << 14 & value, 1lu << 13,
+ e->iomemtype);
+ break;
+ case 0x90:
+ e->MMAP_SRAM0 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 1) - 1) & value;
+ break;
+ case 0x94:
+ e->MMAP_SRAM1 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 1) - 1) & value;
+ break;
+ case 0xa0:
+ e->MMAP_DPSRAM0 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 1) - 1) & value;
+ break;
+ case 0xa4:
+ e->MMAP_DPSRAM1 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 1) - 1) & value;
+ break;
+ case 0xb0:
+ e->MMAP_SDRAM0 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 1) - 1) & value;
+ break;
+ case 0xb4:
+ e->MMAP_SDRAM1 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 1) - 1) & value;
+ break;
+ case 0xc0:
+ e->MMAP_EBI0 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 2) - 1) & value;
+ break;
+ case 0xc4:
+ e->MMAP_EBI1 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 2) - 1) & value;
+ break;
+ case 0xc8:
+ e->MMAP_EBI2 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 2) - 1) & value;
+ break;
+ case 0xcc:
+ e->MMAP_EBI3 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 2) - 1) & value;
+ break;
+ case 0xd0:
+ e->MMAP_PLD0 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 2) - 1) & value;
+ break;
+ case 0xd4:
+ e->MMAP_PLD1 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 2) - 1) & value;
+ break;
+ case 0xd8:
+ e->MMAP_PLD2 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 2) - 1) & value;
+ break;
+ case 0xdc:
+ e->MMAP_PLD3 = (~0lu << 14
+ | (1lu << 12 - 7) - 1 << 7 | (1lu << 2) - 1) & value;
+ break;
+
+ case 0x100:
+ e->AHB12B_CR = (1lu << 2) - 1 & value;
+ break;
+ case 0x110:
+ e->PLDSB_CR = (1lu << 2) - 1 & value;
+ break;
+# if 0
+ case 0x114:
+ return e->PLDSB_ADDRSR;
+# endif
+ case 0x118:
+ e->PLDSB_SR = ~0lu << 1 & e->PLDSB_SR
+ | (1u << 1) - 1 & e->PLDSB_SR
+ & ~value;
+ break;
+ case 0x120:
+ e->PLDMB_CR = (1u << 2) - 1 & value;
+ break;
+
+ case 0x140:
+ e->CONFIG_CONTROL = ~0lu << 2 & e->CONFIG_CONTROL
+ | (1u << 2) - 1 & value;
+ break;
+ case 0x144:
+ e->CONFIG_CLOCK = (1lu << 16) - 1 & value;
+ break;
+ case 0x148:
+ e->CONFIG_DATA = value;
+ break;
+ case 0x14c:
+ e->CONFIG_CONTROL |= 0x554e4c4b == value;
+ break;
+
+ case 0x150:
+ e->GP_IO = (~0u << 8) & e->GP_IO
+ | (1u << 8) - 1 & value;
+ break;
+
+ {
+ struct altera_excalibur_timer *timer;
+# define TIMER_CASE(ADDRESS, LABEL)\
+ case ADDRESS:\
+ timer = e->TIMER;\
+ goto LABEL;\
+ case 0x40 + ADDRESS:\
+ timer = 1 + e->TIMER;\
+LABEL:
+
+ TIMER_CASE (0x200, timer_write_cr)
+ {
+ int long unsigned sr, old_sr, pre;
+ timer->sr = sr = (1 << 4 | (1 << 3) - 1) & value
+ | 1u << 3 & ~value & (old_sr = timer->sr);
+ (1u << 2 & sr >> 1 & sr? altera_excalibur_set_interrupt:
+ altera_excalibur_clear_interrupt) (
+ timer->e_, timer->interrupt);
+ if (!(1u << 4 & old_sr)) {
+ if (1u << 4 & sr) {
+ /* cause timer to start */
+ qemu_mod_timer (timer->ts, timer->end_time
+ = (timer->start_time
+ = qemu_get_clock (rt_clock))
+ + muldiv64 (((pre = timer->pre)?
+ timer->limit * (pre + 1):
+ timer->limit + 1) - timer->read,
+ ALTERA_EXCALIBUR_QEMU_\
+RT_COCK_FREQ,
+ timer->e_->AHB1_FREQ >> 1));
+ }
+ } else if (!(1u << 4 & sr)) {
+ /* cause timer to stop */
+ qemu_del_timer (timer->ts);
+ timer->read = muldiv64 (qemu_get_clock (rt_clock)
+ - timer->start_time,
+ timer->e_->AHB1_FREQ >> 1,
+ ALTERA_EXCALIBUR_QEMU_RT_COCK_FREQ
+ * (1 + timer->pre));
+ }
+ break;
+ }
+ TIMER_CASE (0x210, timer_write_pre)
+ if (!(1u << 4 & timer->sr))
+ timer->pre = value;
+ break;
+ TIMER_CASE (0x220, timer_write_limit)
+ timer->limit = value;
+ break;
+# if 0
+ TIMER_CASE (0x230, timer_write_read)
+ return e->TIMER0_READ;
+ break;
+# endif
+ }
+
+# if 0
+ case 0x280:
+ return e->UART_RSR;
+ case 0x284:
+ return e->UART_RDR;
+ case 0x288:
+ return e->UART_RD;
+ case 0x28c:
+ return e->UART_TSR;
+# endif
+ case 0x290:
+ if (1lu << 4 & e->UART_MCR) {
+ struct altera_excalibur_uart_rx_buf *write;
+ write = e->uart_rx_buf_write;
+ write->rx_data = value;
+ write++->status = 0;
+ if (sizeof e->uart_rx_buf / sizeof *e->uart_rx_buf
+ <= write - e->uart_rx_buf)
+ write = e->uart_rx_buf;
+ if (write == e->uart_rx_buf_read)
+ e->uart_rx_buf_write->status |= 1lu << 0;
+ else
+ e->uart_rx_buf_write = write;
+ if (altera_excalibur_uart_rx_thresholds [
+ e->UART_FCR >> 5]
+ <= ALTERA_EXCALIBUR_UART_USED (e)) {
+ e->UART_ISR |= 1lu << 0;
+ }
+ } else {
+ uint8_t const buf = value;
+ /* dropping return value, seems the norm in QEMU */
+ qemu_chr_write (e->chr, &buf, 1);
+ }
+ e->UART_ISR |= 1lu << 2; /* TII interrupt */
+ goto uart_recalc_interrupts;
+ case 0x294:
+ if (1lu << 1 & value)
+ e->uart_rx_buf_read = e->uart_rx_buf_write;
+ e->UART_FCR = (1lu << 8) - (1lu << 2) & value;
+# if 0
+ if (altera_excalibur_uart_rx_thresholds [e->UART_FCR >> 5]
+ <= ALTERA_EXCALIBUR_UART_USED (e)) {
+ e->UART_ISR |= 1lu << 0;
+ goto uart_recalc_interrupts;
+ }
+# endif
+ if (1lu << 0 & value) {
+ e->UART_ISR |= 1lu << 2;
+ goto uart_recalc_interrupts;
+ }
+ break;
+ case 0x298:
+ e->UART_IES |= (1lu << 4) - 1 & value;
+ goto uart_recalc_interrupts;
+ case 0x29c:
+ e->UART_IES &= ~((1lu << 4) - 1 & value);
+uart_recalc_interrupts:
+ altera_excalibur_recalc_uart_interrupts (e);
+ break;
+# if 0
+ case 0x2a0:
+ return e->UART_ISR;
+ case 0x2a4:
+ return e->UART_IID;
+# endif
+ case 0x2a8:
+ e->UART_MC = (1lu << 7) - 1 & value;
+ goto recalc_uart_settings;
+ case 0x2ac:
+ e->UART_MCR = (1lu << 8) - 1 & value;
+ /* should output status pins here */
+ {
+ int result;
+ if (1lu << 5 & value && (result = qemu_chr_ioctl (e->chr,
+ CHR_IOCTL_SERIAL_SET_BREAK, 0)))
+ cpu_abort (e->s, "UART break unsupported , error: %d\n",
+ result);
+ }
+ break;
+# if 0
+ case 0x2b0:
+ return e->UART_MSR;
+# endif
+ case 0x2b4:
+ e->UART_DIV_LO = (1lu << 8) - 1 & value;
+ break;
+ case 0x2b8:
+ e->UART_DIV_HI = (1lu << 8) - 1 & value;
+recalc_uart_settings:
+ {
+ QEMUSerialSetParams sp;
+ int long unsigned const mc = e->UART_MC;
+ int long unsigned divisor;
+ int result;
+ sp.parity = !(1lu << 3 & mc)? 'N':
+ !(1lu << 5 & mc)? 1lu << 4 & mc? 'E': 'O':
+ 1lu << 4 & mc? 'M' /* mark */: 'S' /* space */;
+ sp.data_bits = 5 + ((1lu << 2) - 1 & mc);
+ sp.stop_bits = 1 + (1lu & mc >> 2);
+ if (2 > (divisor = e->UART_DIV_HI << 8 | e->UART_DIV_LO))
+ divisor = 2;
+ sp.speed = ((25 >> 1) + (e->AHB1_FREQ >> 5) / divisor)
+ / 25 * 25;
+ if (result = qemu_chr_ioctl (e->chr,
+ CHR_IOCTL_SERIAL_SET_PARAMS, &sp))
+ fprintf (stderr, "Unsupported UART mode, error: %d\n",
+ result);
+ }
+ break;
+
+# if 1 /* EPXA1, EPPXA4 */
+# define PLL_MN_HIGH 16
+# define PLL_MN_LOW 7
+# define PLL_K_HIGH 16
+# define PLL_K_LOW 7
+# else
+# define PLL_MN_HIGH 12
+# define PLL_MN_LOW 3
+# define PLL_K_HIGH 11
+# define PLL_K_LOW 2
+# endif
+ case 0x300:
+ e->CLK_PLL1_NCNT
+ = ((1lu << 19) - (1lu << 16)
+ | ((1lu << PLL_MN_HIGH) - (1lu << 8))
+ | (1lu << PLL_MN_LOW) - (1lu << 0)) & value;
+ goto recalc_pll;
+ case 0x304:
+ e->CLK_PLL1_MCNT
+ = ((1lu << 19) - (1lu << 16)
+ | ((1lu << PLL_MN_HIGH) - (1lu << 8))
+ | (1lu << PLL_MN_LOW) - (1lu << 0)) & value;
+ goto recalc_pll;
+ case 0x308:
+ e->CLK_PLL1_KCNT
+ = ((1lu << 19) - (1lu << 16)
+ | ((1lu << PLL_K_HIGH) - (1lu << 8))
+ | (1lu << PLL_K_LOW) - (1lu << 0)) & value;
+ goto recalc_pll;
+ case 0x30c:
+ e->CLK_PLL1_CTRL
+ = 1lu << 12 | 1lu << 2 | (
+# if 0 /* EPXA 1 only */
+ (1lu << 15) |
+# endif
+ ((1lu << 7) - (1lu << 4))
+ | ((1lu << 1) - (1lu << 0))) & value;
+ goto recalc_pll;
+
+ case 0x310:
+ e->CLK_PLL2_NCNT
+ = ((1lu << 19) - (1lu << 16)
+ | ((1lu << PLL_MN_HIGH) - (1lu << 8))
+ | (1lu << PLL_MN_LOW) - (1lu << 0)) & value;
+ goto recalc_pll;
+ case 0x314:
+ e->CLK_PLL2_MCNT
+ = ((1lu << 19) - (1lu << 16)
+ | ((1lu << PLL_MN_HIGH) - (1lu << 8))
+ | (1lu << PLL_MN_LOW) - (1lu << 0)) & value;
+ goto recalc_pll;
+ case 0x318:
+ e->CLK_PLL2_KCNT
+ = ((1lu << 19) - (1lu << 16)
+ | ((1lu << PLL_K_HIGH) - (1lu << 8))
+ | (1lu << PLL_K_LOW) - (1lu << 0)) & value;
+ goto recalc_pll;
+ case 0x31c:
+ e->CLK_PLL2_CTRL
+ = 1lu << 12 | 1lu << 2 | (
+# if 0 /* EPXA 1 only */
+ (1lu << 15) |
+# endif
+ ((1lu << 7) - (1lu << 4))
+ | ((1lu << 1) - (1lu << 0))) & value;
+ goto recalc_pll;
+
+ case 0x320:
+ e->CLK_STATUS = ~((1lu << 6) - (1lu << 4)) & e->CLK_STATUS
+ | ((1lu << 6) - (1lu << 4)) &
+ (e->CLK_DERIVE = (
+ ((1lu << 14) - (1lu << 12)) & value | 1lu << 4))
+ >> 12 - 4;
+recalc_pll:
+
+ if ((1lu << 4) & e->CLK_STATUS) {
+ e->AHB1_FREQ = e->CLK_REF;
+ break;
+ }
+ e->AHB1_FREQ = ((((1lu << 6) - (1lu << 0)) & e->CLK_PLL1_MCNT)
+ << 1 | 1 & e->CLK_PLL1_MCNT >> 16) * e->CLK_REF
+ / ((((1lu << 6) - (1lu << 0))
+ & e->CLK_PLL1_NCNT)
+ << 1 | 1 & e->CLK_PLL1_NCNT >> 16);
+ e->AHB1_FREQ = e->AHB1_FREQ
+ / ((((1lu << 6) - (1lu << 0))
+ & e->CLK_PLL1_KCNT)
+ << 1 | 1 & e->CLK_PLL1_KCNT >> 16) >> 1;
+ break;
+ case 0x324:
+ if (!((1lu << 4) - (1lu << 2) & (e->CLK_STATUS
+ &= ~((1lu << 4) - (1lu << 2) & value))))
+ altera_excalibur_clear_interrupt (e,
+ 1lu <<
+ altera_excalibur_interrupt_source_PLL);
+ break;
+
+# if 0
+ case 0x328:
+ return muldiv64 (qemu_get_clock (vm_clock),
+ e->AHB1_FREQ, ticks_per_sec);
+# endif
+
+ case 0x380:
+ e->EBI_SR = (0
+ | (1lu << 5) - (1lu << 0)
+ | (1lu << 20) - (1lu << 6)
+ ) & value;
+ break;
+ case 0x390:
+ e->EBI_BLOCK0 = (0
+ | (1lu << 8) - (1lu << 0)
+ ) & value;
+ break;
+ case 0x394:
+ e->EBI_BLOCK1 = (0
+ | (1lu << 8) - (1lu << 0)
+ ) & value;
+ break;
+ case 0x398:
+ e->EBI_BLOCK2 = (0
+ | (1lu << 8) - (1lu << 0)
+ ) & value;
+ break;
+ case 0x39c:
+ e->EBI_BLOCK3 = (0
+ | (1lu << 8) - (1lu << 0)
+ ) & value;
+ break;
+ case 0x3a0:
+ e->EBI_INT_SR &= ~(1lu & value);
+ altera_excalibur_clear_interrupt (e,
+ 1lu <<
+ altera_excalibur_interrupt_source_EBI);
+ break;
+# if 0
+ case 0x3a4:
+ return e->EBI_INT_ADDRSR;
+# endif
+
+ case 0x400:
+ e->SDRAM_TIMING1 = (0
+ | (1lu << 16) - (1lu << 0)
+ ) & value;
+ break;
+ case 0x404:
+ e->SDRAM_TIMING2 = (0
+ | (1lu << 16) - (1lu << 3)
+ ) & value;
+ break;
+ case 0x408:
+ e->SDRAM_CONFIG = (0
+ | (1lu << 16) - (1lu << 15)
+ ) & value;
+ break;
+ case 0x40c:
+ e->SDRAM_REFRESH = (0
+ | (1lu << 16) - (1lu << 0)
+ ) & value;
+ break;
+ case 0x410:
+ e->SDRAM_ADDR = (0
+ | (1lu << 16) - (1lu << 8)
+ ) & value;
+ break;
+ case 0x41c:
+ e->SDRAM_INIT = (0
+ | (1lu << 16) - (1lu << 15)
+ ) & value;
+ break;
+ case 0x420:
+ e->SDRAM_MODE0 = (0
+ | (1lu << 12) - (1lu << 0)
+ ) & value;
+ break;
+ case 0x424:
+ e->SDRAM_MODE1 = (0
+ | (1lu << 12) - (1lu << 0)
+ ) & value;
+ break;
+
+ case 0x800:
+ e->AHB12B_SR = ~0lu << 1 & e->AHB12B_SR
+ | (1lu << 1) - 1 & e->AHB12B_SR
+ & ~value;
+ break;
+# if 0
+ case 0x804:
+ return e->AHB12B_ADDRSR;
+# endif
+
+ case 0xa00:
+ if (1u & e->WDOG_CR)
+# if 0
+ cause abort memory exception
+# else
+ cpu_abort (e->s, "Memory abort: "
+ "Watchdog condition register is "
+ "already locked\n");
+# endif
+ else
+ e->WDOG_RELOAD = 0xa5a5a5a5;
+ {
+ int unsigned long const trigger = ((1lu << 30) - 1
+ ^ (1lu << 4) - 1) & value;
+ if (!e->WDOG_CR && trigger)
+ qemu_mod_timer (e->wd, (e->wd_start_time
+ = qemu_get_clock (rt_clock)) +
+ muldiv64 (ALTERA_EXCALIBUR_QEMU_RT_COCK_FREQ,
+ trigger, e->CLK_REF));
+ }
+ e->WDOG_CR = ((1lu << 30) - (1lu << 4) | 1lu << 0)
+ & value;
+ break;
+
+# if 0
+ case 0xa04:
+ return e->WDOG_COUNT;
+# endif
+ case 0xa08:
+ if (e->WDOG_RELOAD != value) {
+ e->RESET_SR |= 1lu << 0;
+# if 0
+ cpu_abort (e->s, "Watchdog Reset: "
+ "incorrect value %#08x written to "
+ "watchdog reload value, expecting "
+ "%#08x\n", value, e->WDOG_RELOAD);
+# else
+ cpu_reset (e->s);
+# endif
+ }
+ if (!(1u << 1 & (e->WDOG_RELOAD = value << 1 | value >> 1))
+ && ~1lu & e->WDOG_CR)
+ qemu_mod_timer (e->wd, (e->wd_start_time
+ = qemu_get_clock (rt_clock))
+ + muldiv64 (
+ ALTERA_EXCALIBUR_QEMU_RT_COCK_FREQ,
+ ~(1lu << 0) & e->WDOG_CR,
+ e->CLK_REF));
+ break;
+
+ case 0xc00:
+ e->INT_MASK_SET |= value;
+ goto recalc_interrupts;
+ case 0xc04:
+ e->INT_MASK_SET &= ~value;
+ goto recalc_interrupts;
+# if 0
+ case 0xc08:
+ return e->INT_SOURCE_STATUS;
+ case 0xc0c:
+ return e->INT_REQUEST_STATUS;
+ case 0xc10:
+ return e->INT_ID;
+ case 0xc14:
+ return e->INT_PLD_PRIORITY;
+# endif
+ case 0xc18:
+ e->INT_MODE = (1u << 2) - 1 & value;
+ goto recalc_interrupts;
+
+# define INTERRUPT_PRIORITY_WRITE(ADDRESS, SOURCE)\
+ case ADDRESS:\
+ e->INT_PRIORITY [\
+ altera_excalibur_interrupt_source_ ## SOURCE]\
+ = (1u << 6) - 1 & value;\
+ goto recalc_interrupts;
+
+ INTERRUPT_PRIORITY_WRITE (0xc80, PLD0)
+ INTERRUPT_PRIORITY_WRITE (0xc84, PLD1)
+ INTERRUPT_PRIORITY_WRITE (0xc88, PLD2)
+ INTERRUPT_PRIORITY_WRITE (0xc8c, PLD3)
+ INTERRUPT_PRIORITY_WRITE (0xc90, PLD4)
+ INTERRUPT_PRIORITY_WRITE (0xc94, PLD5)
+ INTERRUPT_PRIORITY_WRITE (0xc98, EXTPIN)
+ INTERRUPT_PRIORITY_WRITE (0xc9c, UART)
+ INTERRUPT_PRIORITY_WRITE (0xca0, TIMER0)
+ INTERRUPT_PRIORITY_WRITE (0xca4, TIMER1)
+ INTERRUPT_PRIORITY_WRITE (0xca8, PLL)
+ INTERRUPT_PRIORITY_WRITE (0xcac, EBI)
+ INTERRUPT_PRIORITY_WRITE (0xcb0, STRIPE_PLD)
+ INTERRUPT_PRIORITY_WRITE (0xcb4, AHB1_2)
+ INTERRUPT_PRIORITY_WRITE (0xcb8, TX)
+ INTERRUPT_PRIORITY_WRITE (0xcbc, RX)
+ INTERRUPT_PRIORITY_WRITE (0xcc0, FASTCOMMS)
+recalc_interrupts:
+ altera_excalibur_calc_interrupt (e);
+ }
+}
+
+static CPUWriteMemoryFunc *altera_excalibur_write_funcs [] = {
+ altera_excalibur_write8,
+ altera_excalibur_write16,
+ altera_excalibur_write32
+};
+
+
+static uint32_t
+altera_excalibur_read8 (void *const opaque, target_phys_addr_t const offset)
+{
+ cpu_abort (e->s, "Attempt to read 8-bit value from Excalibur address "
+ "map at addresss %08x\n", offset);
+}
+
+static uint32_t
+altera_excalibur_read16 (void *const opaque, target_phys_addr_t const offset)
+{
+ cpu_abort (e->s, "Attempt to read 16-bit value from Excalibur address "
+ "map at addresss %08x\n", offset);
+}
+
+static uint32_t
+altera_excalibur_read32 (void *const opaque, target_phys_addr_t const offset)
+{
+ if (!(1 & e->MMAP_REGISTERS))
+ goto bus_error;
+ switch (offset - (~0lu << 14 & e->MMAP_REGISTERS)) {
+ default:
+bus_error:
+ cpu_abort (e->s, "Attempt to read 32-bit value from "
+ "Excalibur address map at addresss %08x\n", offset);
+ case 0x0:
+ return e->BOOT_CR;
+ case 0x4:
+ return e->RESET_SR;
+ case 0x8:
+ return e->IDCODE;
+ case 0x20:
+ return e->SRAM0_SR;
+ case 0x24:
+ return e->SRAM1_SR;
+ case 0x30:
+ return e->DPSRAM0_SR;
+ case 0x38:
+ return e->DPSRAM1_SR;
+
+ case 0x40:
+ return e->IOCR_SDRAM;
+ case 0x44:
+ return e->IOCR_EBI;
+ case 0x48:
+ return e->IOCR_UART;
+ case 0x4c:
+ return e->IOCR_TRACE;
+
+ case 0x7c:
+ return e->SDRAM_WIDTH;
+
+ case 0x80:
+ return e->MMAP_REGISTERS;
+ case 0x90:
+ return e->MMAP_SRAM0;
+ case 0x94:
+ return e->MMAP_SRAM1;
+ case 0xa0:
+ return e->MMAP_DPSRAM0;
+ case 0xa4:
+ return e->MMAP_DPSRAM1;
+ case 0xb0:
+ return e->MMAP_SDRAM0;
+ case 0xb4:
+ return e->MMAP_SDRAM1;
+ case 0xc0:
+ return e->MMAP_EBI0;
+ case 0xc4:
+ return e->MMAP_EBI1;
+ case 0xc8:
+ return e->MMAP_EBI2;
+ case 0xcc:
+ return e->MMAP_PLD3;
+ case 0xd0:
+ return e->MMAP_PLD0;
+ case 0xd4:
+ return e->MMAP_PLD1;
+ case 0xd8:
+ return e->MMAP_PLD2;
+ case 0xdc:
+ return e->MMAP_PLD3;
+
+ case 0x100:
+ return e->AHB12B_CR;
+ case 0x110:
+ return e->PLDSB_CR;
+ case 0x114:
+ return e->PLDSB_ADDRSR;
+ case 0x118:
+ return e->PLDSB_SR;
+ case 0x120:
+ return e->PLDMB_CR;
+
+ case 0x140:
+ return e->CONFIG_CONTROL;
+ case 0x144:
+ return e->CONFIG_CLOCK;
+# if 0
+ case 0x148:
+ return e->CONFIG_DATA;
+ case 0x14c:
+ return e->CONFIG_UNLOCK;
+# endif
+
+ case 0x150:
+ return e->GP_IO;
+
+ {
+ struct altera_excalibur_timer *timer;
+ TIMER_CASE (0x200, timer_read_sr)
+ return timer->sr;
+ TIMER_CASE (0x210, timer_read_pre)
+ return timer->pre;
+ TIMER_CASE (0x220, timer_read_limit)
+ return timer->limit;
+ TIMER_CASE (0x230, timer_read_read)
+ return 1u << 4 & timer->sr?
+ muldiv64 (qemu_get_clock (rt_clock)
+ - timer->start_time, e->AHB1_FREQ >> 1,
+ ALTERA_EXCALIBUR_QEMU_RT_COCK_FREQ
+ * (1 + timer->pre)): timer->read;
+ }
+
+ case 0x280:
+ e->UART_ISR &= ~(1lu << 0);
+ altera_excalibur_recalc_uart_interrupts (e);
+ {
+ struct altera_excalibur_uart_rx_buf *b;
+ int long unsigned i = 0;
+ for (b = e->uart_rx_buf_read; b != e->uart_rx_buf_write; ++i) {
+ i |= !!b->status << 7;
+ if (sizeof e->uart_rx_buf / sizeof *e->uart_rx_buf
+ + e->uart_rx_buf <= ++b)
+ b = e->uart_rx_buf;
+ }
+ return i;
+ }
+ case 0x284:
+ return e->uart_rx_buf_read->status;
+ case 0x288: {
+ int long unsigned value = e->uart_rx_buf_read->rx_data;
+ if (e->uart_rx_buf_write != e->uart_rx_buf_read)
+ if (sizeof e->uart_rx_buf / sizeof *e->uart_rx_buf
+ + e->uart_rx_buf
+ <= ++e->uart_rx_buf_read)
+ e->uart_rx_buf_read = e->uart_rx_buf;
+ return value;
+ }
+ case 0x28c:
+ e->UART_ISR &= ~(1lu << 2 | 1lu << 1);
+ altera_excalibur_recalc_uart_interrupts (e);
+ return e->UART_TSR;
+ case 0x290:
+ return 0;
+ case 0x294:
+ return e->UART_FCR;
+ case 0x298:
+ case 0x29c:
+ return e->UART_IES;
+ case 0x2a0:
+ return e->UART_ISR;
+ case 0x2a4:
+ {
+ int long unsigned const enabled_interrupts
+ = e->UART_IES & e->UART_ISR;
+ return 1lu << 0 & enabled_interrupts? 1:
+ 1lu << 1 & enabled_interrupts? 2:
+ 1lu << 2 & enabled_interrupts? 3:
+ 1lu << 3 & enabled_interrupts? 4:
+ 0;
+ }
+ case 0x2a8:
+ return e->UART_MC;
+ case 0x2ac:
+ return e->UART_MCR;
+ case 0x2b0: {
+ int long unsigned value;
+ e->UART_ISR &= ~(1lu << 3);
+ altera_excalibur_recalc_uart_interrupts (e);
+ value = e->UART_MSR;
+ e->UART_MSR &= ~((1lu << 4) - 1);
+ return value;
+ }
+ case 0x2b4:
+ return e->UART_DIV_LO;
+ case 0x2b8:
+ return e->UART_DIV_HI;
+
+ case 0x300:
+ return e->CLK_PLL1_NCNT;
+ case 0x304:
+ return e->CLK_PLL1_MCNT;
+ case 0x308:
+ return e->CLK_PLL1_KCNT;
+ case 0x30c:
+ return e->CLK_PLL1_CTRL;
+ case 0x310:
+ return e->CLK_PLL2_NCNT;
+ case 0x314:
+ return e->CLK_PLL2_MCNT;
+ case 0x318:
+ return e->CLK_PLL2_KCNT;
+ case 0x31c:
+ return e->CLK_PLL2_CTRL;
+ case 0x320:
+ return e->CLK_DERIVE;
+ case 0x324:
+ return e->CLK_STATUS;
+ case 0x328:
+ return muldiv64 (qemu_get_clock (vm_clock),
+ e->AHB1_FREQ, ticks_per_sec);
+
+ case 0x380:
+ return e->EBI_SR;
+ case 0x390:
+ return e->EBI_BLOCK0;
+ case 0x394:
+ return e->EBI_BLOCK1;
+ case 0x398:
+ return e->EBI_BLOCK2;
+ case 0x39c:
+ return e->EBI_BLOCK3;
+ case 0x3a0:
+ return e->EBI_INT_SR;
+ case 0x3a4:
+ return e->EBI_INT_ADDRSR;
+
+ case 0x400:
+ return e->SDRAM_TIMING1;
+ case 0x404:
+ return e->SDRAM_TIMING2;
+ case 0x408:
+ return e->SDRAM_CONFIG;
+ case 0x40c:
+ return e->SDRAM_REFRESH;
+ case 0x410:
+ return e->SDRAM_ADDR;
+ case 0x41c:
+ return e->SDRAM_INIT;
+ case 0x420:
+ return e->SDRAM_MODE0;
+ case 0x424:
+ return e->SDRAM_MODE1;
+
+ case 0x800:
+ return e->AHB12B_SR;
+ case 0x804:
+ return e->AHB12B_ADDRSR;
+
+ case 0xa00:
+ return e->WDOG_CR;
+ case 0xa04:
+ return muldiv64 (qemu_get_clock (rt_clock) - e->wd_start_time,
+ e->CLK_REF, ALTERA_EXCALIBUR_QEMU_RT_COCK_FREQ);
+# if 0
+ case 0xa08:
+ return e->WDOG_RELOAD;
+# endif
+
+ case 0xc00:
+ case 0xc04:
+ return e->INT_MASK_SET;
+ case 0xc08:
+ return e->INT_SOURCE_STATUS;
+ case 0xc0c:
+ return e->INT_SOURCE_STATUS & e->INT_MASK_SET;
+ case 0xc10: {
+ int unsigned long unmasked = e->INT_SOURCE_STATUS
+ & e->INT_MASK_SET,
+ priority = 0, *prio_reg = e->INT_PRIORITY,
+ i = 1;
+ switch (e->INT_MODE) {
+ case 0:
+ priority = e->INT_PLD_PRIORITY;
+ goto skip_PLD_priorities;
+ case 1:
+ priority = ~0u << 1 & e->INT_PLD_PRIORITY;
+ if (1 & unmasked) {
+ int unsigned long new_priority;
+ if (priority < (new_priority = (1u << 6) - 1
+ & *prio_reg))
+ priority = new_priority;
+ }
+skip_PLD_priorities:
+ i <<= 6;
+ prio_reg += 6;
+ break;
+ case 2:
+ cpu_abort (e->s, "2 is a reserved value for MODE field "
+ "in the interrupt controller operating "
+ "mode register"
+ "(Altera Excalibur INT_MODE)\n");
+ }
+ for (; unmasked; i <<= 1, ++prio_reg)
+ if (unmasked & i) {
+ int unsigned long new_priority;
+ unmasked &= ~i;
+ if (priority < (new_priority = (1u << 6) - 1
+ & *prio_reg))
+ priority = new_priority;
+ }
+ return priority;
+ }
+ case 0xc14:
+ return e->INT_PLD_PRIORITY;
+ case 0xc18:
+ return e->INT_MODE;
+# define INTERRUPT_PRIORITY_READ(ADDRESS, SOURCE)\
+ case ADDRESS:\
+ return e->INT_PRIORITY [\
+ altera_excalibur_interrupt_source_ ## SOURCE];
+
+ INTERRUPT_PRIORITY_READ (0xc80, PLD0)
+ INTERRUPT_PRIORITY_READ (0xc84, PLD1)
+ INTERRUPT_PRIORITY_READ (0xc88, PLD2)
+ INTERRUPT_PRIORITY_READ (0xc8c, PLD3)
+ INTERRUPT_PRIORITY_READ (0xc90, PLD4)
+ INTERRUPT_PRIORITY_READ (0xc94, PLD5)
+ INTERRUPT_PRIORITY_READ (0xc98, EXTPIN)
+ INTERRUPT_PRIORITY_READ (0xc9c, UART)
+ INTERRUPT_PRIORITY_READ (0xca0, TIMER0)
+ INTERRUPT_PRIORITY_READ (0xca4, TIMER1)
+ INTERRUPT_PRIORITY_READ (0xca8, PLL)
+ INTERRUPT_PRIORITY_READ (0xcac, EBI)
+ INTERRUPT_PRIORITY_READ (0xcb0, STRIPE_PLD)
+ INTERRUPT_PRIORITY_READ (0xcb4, AHB1_2)
+ INTERRUPT_PRIORITY_READ (0xcb8, TX)
+ INTERRUPT_PRIORITY_READ (0xcbc, RX)
+ INTERRUPT_PRIORITY_READ (0xcc0, FASTCOMMS)
+ }
+
+# undef e
+}
+
+static CPUReadMemoryFunc *altera_excalibur_read_funcs [] = {
+ altera_excalibur_read8,
+ altera_excalibur_read16,
+ altera_excalibur_read32
+};
+
+static struct altera_excalibur_state
+*altera_excalibur_device_init (CPUState *const s, CharDriverState *const chr)
+{
+ struct altera_excalibur_state *e;
+ if (!(e = qemu_malloc (sizeof *e)))
+ goto state_allocation;
+ e->s = s;
+ if (!(e->wd = qemu_new_timer (rt_clock, altera_excalibur_wd_callback,
+ e)))
+ goto wd_allocation;
+ if (altera_excalibur_timer_initialize (0 + e->TIMER,
+ 1lu << altera_excalibur_interrupt_source_TIMER0, e))
+ goto timer0_allocation;
+ if (altera_excalibur_timer_initialize (1 + e->TIMER,
+ 1lu << altera_excalibur_interrupt_source_TIMER1, e))
+ goto timer1_allocation;
+
+ e->INT_MASK_SET = 0
+ | 1lu << altera_excalibur_interrupt_source_PLD0
+ | 1lu << altera_excalibur_interrupt_source_PLD1
+ | 1lu << altera_excalibur_interrupt_source_PLD2
+ | 1lu << altera_excalibur_interrupt_source_PLD3
+ | 1lu << altera_excalibur_interrupt_source_PLD4
+ | 1lu << altera_excalibur_interrupt_source_PLD5
+ ;
+ e->INT_SOURCE_STATUS = 0;
+ e->INT_PLD_PRIORITY = 0;
+ e->INT_MODE = 0x3;
+ memset (1 + e->INT_PRIORITY, 0, sizeof e->INT_PRIORITY
+ - 1 * sizeof *e->INT_PRIORITY);
+ {
+ typedef int assert_PLD0_at_beginning [
+ !altera_excalibur_interrupt_source_PLD0? 1: -1];
+ }
+ e->INT_PRIORITY [altera_excalibur_interrupt_source_PLD0] = 0x40;
+
+ e->CLK_REF = 20000000; /* node arm */
+
+ {
+ enum {
+ pll1_m = 8,
+ pll1_n = 1,
+ pll1_k = 1,
+ pll2_m = 80,
+ pll2_n = 3,
+ pll2_k = 4
+ };
+# define ASSIGN_PLL_CNT(x) (0\
+ | (x) >> 1 << 0\
+ | ((x) >> 1) + (1lu << 0 & (x)) << 8\
+ | (1lu == (x)) << 18\
+ | !(1lu << 0 & (x)) << 17\
+ | (1lu << 0 & (x)) << 16\
+ )
+
+ e->CLK_PLL1_MCNT = ASSIGN_PLL_CNT (pll1_m);
+ e->CLK_PLL1_NCNT = ASSIGN_PLL_CNT (pll1_n);
+ e->CLK_PLL1_KCNT = ASSIGN_PLL_CNT (pll1_k);
+ e->CLK_PLL1_CTRL = 0
+ | 1lu << 0
+ | 1lu << 2
+ | 6lu << 4
+ | 1lu << 12
+ | 0lu << 15
+ ;
+ e->CLK_PLL2_MCNT = ASSIGN_PLL_CNT (pll2_m);
+ e->CLK_PLL2_NCNT = ASSIGN_PLL_CNT (pll2_n);
+ e->CLK_PLL2_KCNT = ASSIGN_PLL_CNT (pll2_k);
+ e->CLK_PLL2_CTRL = 0
+ | 1lu << 0
+ | 1lu << 2
+ | 6lu << 4
+ | 1lu << 12
+ | 0lu << 15
+ ;
+ e->CLK_DERIVE = 0
+ | 1lu << 4
+ ;
+ e->CLK_STATUS = 0
+ | 1lu << 0
+ | 1lu << 1
+ | 0lu << 2
+ | 0lu << 3
+ | 1lu << 4
+ | 1lu << 5
+ ;
+ }
+
+ e->AHB1_FREQ = 160000000;
+
+# if 0
+ e->SDRAMx2 = 133000000;
+# endif
+ e->GP_IO = 0;
+ e->IDCODE = 0x84010dd; /* EPXA4 device */
+ e->SRAM0_SR = 1 << 16; /* EPXA4 device */
+ e->SRAM1_SR = 1 << 16; /* EPXA4 device */
+ e->DPSRAM0_SR = 1 << 15; /* EPXA4 device */
+ e->DPSRAM1_SR = 1 << 15; /* EPXA4 device */
+ e->BOOT_CR = 0x4;
+ e->RESET_SR = 0;
+ e->IOCR_SDRAM = 0;
+ e->IOCR_EBI = 0;
+ e->IOCR_UART = 0;
+ e->IOCR_TRACE = 0;
+ e->WDOG_RELOAD = 0xa5a5a5a5;
+ e->WDOG_CR = 0;
+
+ e->chr = chr;
+ e->uart_rx_buf_read = e->uart_rx_buf_write = e->uart_rx_buf;
+ e->UART_RSR = 0;
+ e->UART_TSR = 1lu << 7;
+ e->UART_FCR = 0;
+ e->UART_IES = 0;
+ e->UART_ISR = 1lu << 2;
+ e->UART_MC = 0;
+ e->UART_MCR = 0;
+ e->UART_MSR = 0;
+ e->UART_DIV_HI = 0;
+ e->UART_DIV_LO = 0;
+ qemu_chr_add_read_handler (chr, altera_excalibur_uart_can_read,
+ altera_excalibur_uart_read, e);
+ qemu_chr_add_event_handler (chr, altera_excalibur_uart_event_handler);
+
+ e->IOCR_SDRAM = 0;
+ e->IOCR_EBI = 0;
+ e->IOCR_UART = 0;
+ e->IOCR_TRACE = 0;
+ e->SDRAM_WIDTH = 1lu << 2;
+ e->AHB12B_CR = 0;
+ e->AHB12B_ADDRSR = 0;
+ e->PLDSB_CR = 0;
+ e->PLDSB_SR = 0;
+ e->PLDMB_CR = 0;
+ e->CONFIG_CONTROL = 0;
+ e->CONFIG_CLOCK = 0;
+
+ e->EBI_SR = 0
+ | 0lu << 0
+ | 0lu << 1
+ | 0lu << 2
+ | 1lu << 3
+ | 1lu << 4
+ | 5lu << 6
+ | 127lu << 10
+ | 1lu << 18
+ | 1lu << 19
+ | 1lu << 27
+ | 0lu << 28
+ | 1lu << 29
+ | 0lu << 30
+ | 0lu << 31
+ ;
+ e->EBI_INT_SR = 0;
+ e->EBI_INT_ADDRSR = 0;
+ e->EBI_BLOCK0 = 0;
+ e->EBI_BLOCK1 = 0;
+ e->EBI_BLOCK2 = 0;
+ e->EBI_BLOCK3 = 0;
+ e->SDRAM_TIMING1 = 0;
+ e->SDRAM_TIMING2 = 0;
+ e->SDRAM_CONFIG = 0;
+ e->SDRAM_REFRESH = 0;
+ e->SDRAM_ADDR = 1lu << 7;
+ e->SDRAM_INIT = 0;
+ e->SDRAM_MODE0 = 0;
+ e->SDRAM_MODE1 = 0;
+ e->AHB12B_SR = 0;
+ e->PLDSB_ADDRSR = 0;
+
+
+ if (-1 == (e->iomemtype = cpu_register_io_memory (0,
+ altera_excalibur_read_funcs,
+ altera_excalibur_write_funcs, e)))
+ goto register_io_memory;
+
+# define ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP(MMAP,\
+ ADDRESS, SIZE, NP, EN, TYPE)\
+ e->MMAP_ ## MMAP = (ADDRESS) | (SIZE) << 7 | (NP) << 1 | (EN) << 0;\
+ if (EN)\
+ cpu_register_physical_memory (ADDRESS, 1lu << (SIZE), TYPE);
+
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (REGISTERS,
+ 0x7fffc000, 13u, 1u, 1u, e->iomemtype)
+# if 0
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (SDRAM0,
+ 0, 26u, 0u, 1u, IO_MEM_RAM)
+# endif
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (SDRAM1,
+ 0, 0, 0u, 0u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (SRAM0,
+ 0x20000000, 16u, 0u, 1u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (SRAM1,
+ 0x20020000, 16u, 0u, 1u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (DPSRAM0,
+ 0x20040000, 15u, 0u, 1u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (DPSRAM1,
+ 0x0, 0, 0u, 0u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (EBI0,
+ 0x0, 0, 0u, 0u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (EBI1,
+ 0x0, 0, 0u, 0u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (EBI2,
+ 0x0, 0, 0u, 0u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (EBI3,
+ 0x0, 0, 0u, 0u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (PLD0,
+ 0x0, 0, 0u, 0u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (PLD1,
+ 0x0, 0, 0u, 0u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (PLD2,
+ 0x0, 0, 0u, 0u, IO_MEM_RAM)
+ ALTERA_EXCALIBUR_REGISTER_PHYSICAL_AND_MMAP (PLD3,
+ 0x0, 0, 0u, 0u, IO_MEM_RAM)
+
+ return e;
+
+register_io_memory:
+ qemu_free_timer (e->TIMER [1].ts);
+timer1_allocation:
+ qemu_free_timer (e->TIMER [0].ts);
+timer0_allocation:
+ qemu_free_timer (e->wd);
+wd_allocation:
+ qemu_free (e);
+state_allocation:
+ return 0;
+}
+
+/* Board init. */
+
+static void
+altera_excalibur_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)
+{
+ CPUState *s;
+ int entry;
+
+ s = cpu_init();
+ cpu_register_physical_memory (0, ram_size, IO_MEM_RAM);
+
+ if (!altera_excalibur_device_init (s, serial_hds [0])) {
+ perror ("memory allocation");
+ exit (1);
+ }
+
+ /* Load the kernel. */
+ if (!kernel_filename) {
+ fprintf (stderr, "Kernel image must be specified\n");
+ exit (1);
+ }
+ entry = load_elf (kernel_filename, phys_ram_base);
+ if (-1 == entry) {
+ fprintf (stderr, "qemu: could not load image '%s'\n",
+ kernel_filename);
+ exit (1);
+ }
+ s->regs [15] = entry;
+}
+
+QEMUMachine altera_excalibur_machine = {
+ "altera_excalibur",
+ "Altera Excalibur",
+ altera_excalibur_init
+};
Index: hw/elf_ops.h
===================================================================
--- hw/elf_ops.h (.../vendor/0.8.0) (revision 67)
+++ hw/elf_ops.h (.../tags/altera-excalibur) (revision 67)
@@ -1,4 +1,3 @@
-#ifdef BSWAP_NEEDED
static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
{
bswap16s(&ehdr->e_type); /* Object file type */
@@ -16,6 +15,7 @@
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
+# ifdef BSWAP_NEEDED
static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
{
bswap32s(&phdr->p_type); /* Segment type */
@@ -49,9 +49,10 @@
bswapSZs(&sym->st_size);
bswap16s(&sym->st_shndx);
}
-#endif
+# endif
-static int glue(find_phdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, elf_word type)
+static int glue(find_phdr, SZ)(struct elfhdr *ehdr, int fd,
+ struct elf_phdr *phdr, elf_word type)
{
int i, retval;
@@ -70,7 +71,8 @@
return -1;
}
-static void * glue(find_shdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
+static void * glue(find_shdr, SZ)(struct elfhdr *ehdr, int fd,
+ struct elf_shdr *shdr, elf_word type)
{
int i, retval;
@@ -89,11 +91,13 @@
return NULL;
}
-static void * glue(find_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
+static void * glue(find_strtab, SZ)(struct elfhdr *ehdr, int fd,
+ struct elf_shdr *shdr, struct elf_shdr *symtab)
{
int retval;
- retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
+ retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr)
+ * symtab->sh_link, SEEK_SET);
if (retval < 0)
return NULL;
@@ -106,7 +110,8 @@
return NULL;
}
-static int glue(read_program, SZ)(int fd, struct elf_phdr *phdr, void *dst, elf_word entry)
+static int glue(read_program, SZ)(int fd, struct elf_phdr *phdr, void *dst,
+ elf_word entry)
{
int retval;
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
@@ -115,6 +120,47 @@
return read(fd, dst, phdr->p_filesz);
}
+static int
+glue (read_program_physical_all, SZ) (struct elfhdr const *const ehdr,
+ int const fd, void *const dst)
+{
+ struct elf_phdr *phdr, *phdr_end, *phdr_start;
+ ptrdiff_t diff;
+ size_t size;
+ if (sizeof *phdr > ehdr->e_phentsize)
+ goto size_check_failed;
+ if (!(phdr_start = phdr
+ = qemu_malloc (size = ehdr->e_phentsize * ehdr->e_phnum)))
+ goto malloc_failed;
+ if (-1 == lseek (fd, ehdr->e_phoff, SEEK_SET)
+ || size != read (fd, phdr, size))
+ goto lseek_phdr_failed;
+ for (phdr_end = (void *) (size + (char *) phdr); phdr_end > phdr;
+ phdr = (void *) (ehdr->e_phentsize + (char *) phdr)) {
+ /* assuming any extensions to the Program Header will be done
+ so as not to disturb alignment (guaranteed by ELF) */
+ if (PT_LOAD != phdr->p_type)
+ continue;
+ if (-1 == lseek (fd, phdr->p_offset, SEEK_SET))
+ goto lseek_phdr_failed;
+ if (phdr->p_filesz != read (fd, phdr->p_vaddr + (char *) dst,
+ phdr->p_filesz))
+ goto lseek_phdr_failed;
+ if (0 < (diff = phdr->p_memsz - phdr->p_filesz))
+ memset (phdr->p_filesz + phdr->p_vaddr + (char *) dst, 0, diff);
+ else if (0 > diff)
+ goto lseek_phdr_failed;
+ }
+ qemu_free (phdr_start);
+ return 0;
+
+lseek_phdr_failed:
+ qemu_free (phdr);
+malloc_failed:
+size_check_failed:
+ return -1;
+}
+
static int glue(read_section, SZ)(int fd, struct elf_shdr *s, void *dst)
{
int retval;
@@ -128,7 +174,8 @@
return 0;
}
-static void * glue(process_section, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
+static void * glue(process_section, SZ)(struct elfhdr *ehdr, int fd,
+ struct elf_shdr *shdr, elf_word type)
{
void *dst;
@@ -144,7 +191,8 @@
return NULL;
}
-static void * glue(process_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
+static void * glue(process_strtab, SZ)(struct elfhdr *ehdr, int fd,
+ struct elf_shdr *shdr, struct elf_shdr *symtab)
{
void *dst;
Index: hw/magic-load.c
===================================================================
--- hw/magic-load.c (.../vendor/0.8.0) (revision 67)
+++ hw/magic-load.c (.../tags/altera-excalibur) (revision 67)
@@ -1,3 +1,5 @@
+# include <stddef.h>
+
#include "vl.h"
#include "disas.h"
#include "exec-all.h"
@@ -57,24 +59,19 @@
#include "elf.h"
#ifndef BSWAP_NEEDED
-#define bswap_ehdr32(e) do { } while (0)
#define bswap_phdr32(e) do { } while (0)
#define bswap_shdr32(e) do { } while (0)
#define bswap_sym32(e) do { } while (0)
-#ifdef TARGET_SPARC64
-#define bswap_ehdr64(e) do { } while (0)
#define bswap_phdr64(e) do { } while (0)
#define bswap_shdr64(e) do { } while (0)
#define bswap_sym64(e) do { } while (0)
#endif
-#endif
#define SZ 32
#define elf_word uint32_t
#define bswapSZs bswap32s
#include "elf_ops.h"
-#ifdef TARGET_SPARC64
#undef elfhdr
#undef elf_phdr
#undef elf_shdr
@@ -92,64 +89,138 @@
#define bswapSZs bswap64s
#define SZ 64
#include "elf_ops.h"
-#endif
int load_elf(const char *filename, uint8_t *addr)
{
struct elf32_hdr ehdr;
int retval, fd;
- Elf32_Half machine;
+ int need_to_swap;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
- goto error;
+ goto return_minus_one;
retval = read(fd, &ehdr, sizeof(ehdr));
- if (retval < 0)
+ if (retval < sizeof ehdr)
goto error;
- if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
- || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F')
+ if (ELFMAG0 != ehdr.e_ident [EI_MAG0]
+ || ELFMAG1 != ehdr.e_ident [EI_MAG1]
+ || ELFMAG2 != ehdr.e_ident [EI_MAG2]
+ || ELFMAG3 != ehdr.e_ident [EI_MAG3])
goto error;
- machine = tswap16(ehdr.e_machine);
- if (machine == EM_SPARC || machine == EM_SPARC32PLUS) {
+
+ if (EV_CURRENT != ehdr.e_ident [EI_VERSION])
+ goto error;
+
+ need_to_swap =
+# ifdef WORDS_BIGENDIAN
+ ELFDATA2LSB
+# else
+ ELFDATA2MSB
+# endif
+ == ehdr.e_ident [EI_DATA];
+
+# ifdef TARGET_ARM
+ if (ELFDATA2LSB != ehdr.e_ident [EI_DATA])
+ goto error; /* big-endian image */
+
+ if (!(EF_ARM_HASENTRY & ehdr.e_flags))
+ goto error; /* no entry point */
+# endif
+
+ if (ELFCLASS32 == ehdr.e_ident [EI_CLASS]) {
+# ifdef TARGET_SPARC
struct elf32_phdr phdr;
+# endif
- bswap_ehdr32(&ehdr);
+ if (need_to_swap)
+ bswap_ehdr32 (&ehdr);
+ if (ET_EXEC != ehdr.e_type)
+ goto error;
+
+ if (
+# ifdef TARGET_SPARC
+ EM_SPARC32PLUS != ehdr.e_machine &&
+ EM_SPARC
+# elif defined TARGET_I386
+ EM_386
+# elif defined TARGET_MIPS
+ EM_MIPS
+# elif defined TARGET_PPC
+ EM_PPC
+# elif defined TARGET_ARM
+ EM_ARM
+# else
+ EM_NONE
+# endif
+ != ehdr.e_machine)
+ goto error;
+
+ if (sizeof ehdr > ehdr.e_ehsize)
+ goto error;
+
+ if (!ehdr.e_phoff)
+ goto error;
+
+
+# ifdef TARGET_SPARC
if (find_phdr32(&ehdr, fd, &phdr, PT_LOAD))
goto error;
retval = read_program32(fd, &phdr, addr, ehdr.e_entry);
+# else
+ retval = read_program_physical_all32 (&ehdr, fd, addr);
+# endif
if (retval < 0)
goto error;
load_symbols32(&ehdr, fd);
- }
-#ifdef TARGET_SPARC64
- else if (machine == EM_SPARCV9) {
+ close (fd);
+ return ehdr.e_entry;
+ } else if (ELFCLASS64 == ehdr.e_ident [EI_CLASS]) {
struct elf64_hdr ehdr64;
struct elf64_phdr phdr;
- lseek(fd, 0, SEEK_SET);
+ if (-1 == lseek(fd, 0, SEEK_SET))
+ goto error;
retval = read(fd, &ehdr64, sizeof(ehdr64));
- if (retval < 0)
+ if (retval < sizeof ehdr64)
goto error;
- bswap_ehdr64(&ehdr64);
+ if (need_to_swap)
+ bswap_ehdr64(&ehdr64);
+
+ if (ET_EXEC != ehdr64.e_type)
+ goto error;
+ if (
+# ifdef TARGET_SPARC64
+ EM_SPARCV9
+# else
+ EM_NONE
+# endif
+ != ehdr64.e_machine)
+ goto error;
+
+ if (sizeof ehdr64 > ehdr64.e_ehsize)
+ goto error;
+
if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD))
goto error;
- retval = read_program64(fd, &phdr, phys_ram_base + ehdr64.e_entry, ehdr64.e_entry);
+ retval = read_program64(fd, &phdr,
+ phys_ram_base + ehdr64.e_entry, ehdr64.e_entry);
if (retval < 0)
goto error;
load_symbols64(&ehdr64, fd);
- }
-#endif
+ } else
+ goto error;
close(fd);
return retval;
error:
close(fd);
+return_minus_one:
return -1;
}
Index: vl.c
===================================================================
--- vl.c (.../vendor/0.8.0) (revision 67)
+++ vl.c (.../tags/altera-excalibur) (revision 67)
@@ -4265,6 +4265,7 @@
#endif
#elif defined(TARGET_ARM)
qemu_register_machine(&integratorcp_machine);
+ qemu_register_machine(&altera_excalibur_machine);
#else
#error unsupported CPU
#endif
Index: vl.h
===================================================================
--- vl.h (.../vendor/0.8.0) (revision 67)
+++ vl.h (.../tags/altera-excalibur) (revision 67)
@@ -942,7 +942,7 @@
void usb_info(void);
/* integratorcp.c */
-extern QEMUMachine integratorcp_machine;
+extern QEMUMachine integratorcp_machine, altera_excalibur_machine;
/* ps2.c */
void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] Patch that adds machine "Altera Excalibur"
2006-04-10 11:26 [Qemu-devel] Patch that adds machine "Altera Excalibur" Schwarz, Konrad
@ 2006-04-16 16:24 ` Paul Brook
0 siblings, 0 replies; 3+ messages in thread
From: Paul Brook @ 2006-04-16 16:24 UTC (permalink / raw)
To: qemu-devel; +Cc: Schwarz, Konrad
On Monday 10 April 2006 12:26, Schwarz, Konrad wrote:
> Hello,
> this patch adds support for the Altera Excalibur device (an FPGA that
> supports the ARM922T core).
Are there any plans to update the linux kernel support for this board?
It doesn't seem to be supported in linux 2.6.
What are you using the emulation for? I'm worried that if there's no way for
other people (eg. Me and Fabrice) to test the code then it's just going to
bitrot.
A few points on the patch itself. Some of them are cosmetic, but I'd still
like to get them resolved before applying the patch.
+static uint32_t
+altera_excalibur_read32 (void *const opaque, target_phys_addr_t const offset)
+{
+ if (!(1 & e->MMAP_REGISTERS))
Shouldn't this be &3?
- Changing the memory map registers appears to be only half-implemented.
- Qemu can now support different ARM CPU cores relatively easily, , so you
should be able to get it to report the correct ID. Enforcing v4t only is
harder, but less important.
- Please use 4 spaces for code indent, not tabs.
- This is just ugly:
+# define e ((struct altera_excalibur_state *) opaque)
Use a local variable like the existing code.
- There appears to be support for different board variants, scattered in
several different places and #if 0'ed out. This should at least be controlled
by a single #define, preferably a runtime option.
- There are several chunks of code surrounded by #if 0 for no apparent reason.
- Token names in ALL_CAPS should only be used for preprocessor macros and
constants, not field names.
- Mangling CFLAGS for one object file is not acceptable.
+altera-excalibur.o: CFLAGS += -Wno-parentheses -O0 -fno-omit-frame-pointer
The warnings produced by -Wparentheses should IMHO be fixed, not ignored. Some
of the C operator precedence rules are non-obvious so it's best to be
explicit.
I'm guessing the -O0 and -fno-omit-frame-pointer are for debugging, so should
be removed before submission.
Paul
^ permalink raw reply [flat|nested] 3+ messages in thread
* [Qemu-devel] Patch that adds machine "Altera Excalibur"
@ 2006-04-18 8:53 Schwarz, Konrad
0 siblings, 0 replies; 3+ messages in thread
From: Schwarz, Konrad @ 2006-04-18 8:53 UTC (permalink / raw)
To: qemu-devel
> -----Original Message-----
> From: Paul Brook [mailto:paul@codesourcery.com]
> On Monday 10 April 2006 12:26, Schwarz, Konrad wrote:
> > Hello,
> > this patch adds support for the Altera Excalibur device (an
> FPGA that
> > supports the ARM922T core).
>
> Are there any plans to update the linux kernel support for this board?
> It doesn't seem to be supported in linux 2.6.
My target operating system is not Linux, see below. Note that the
Altera Excalibur device is actually just a chip, not a whole board;
Altera wedded an ARM core (hard macro) to its FPGA technology in this
product. (The code of course doesn't emulate the FPGA, however, it is
straightforward to emulate peripherals that have been implemented in the
FPGA within the QEMU framework.)
But I think the QEMU "machine" abstraction and the split between
X_init() and X_device_init() still works well in this case: all I need
to do is to remove the "static" storage class specifier of the routine
altera_excalibur_device_init() to make the device available as the heart
of a different board.
>
> What are you using the emulation for? I'm worried that if there's no
> way for other people (eg. Me and Fabrice) to test the code then it's
> just going to bitrot.
I am using an operating system that implements the "OSEK/VDX" OS
standard (http://www.osek-vdx.org). At some point, I may be able to
open source my implementation. Our use case is simulation of
(relatively) small electronic control units for the automotive industry.
I understand your concerns about bitrot, but see no perfect answer. I
could provide you with bootable images that use OSEK OS. Come to think
of it, I *do* have a Linux 2.4 kernel that runs on the hardware that
this patch is emulating, that should work, but I haven't tested it.
(Also, the U-Boot loader from Denx http://www.denx.de runs on the real
hardware). Would that be acceptable to you? However, that would
probably be at odds with the loading strategy I've used.
I would prefer to keep things the way they are; perhaps I could provide
you with a TCL or DejaGNU regression test that utilizes OSEK (you name
it). If someone else picks up the ball and wants Linux on this machine,
we could find a better answer then---currently, I see no way to find
time to port Linux to this machine.
>
> A few points on the patch itself. Some of them are cosmetic, but I'd
> still like to get them resolved before applying the patch.
>
> +static uint32_t
> +altera_excalibur_read32 (void *const opaque,
> target_phys_addr_t const
> +offset) {
> + if (!(1 & e->MMAP_REGISTERS))
>
> Shouldn't this be &3?
Excalibur Devices Hardware Reference Manual, v3.1, November 2002, pg 100
Bit 0 (LSb) is the EN bit:
"EN R/W Enable. Setting this bit enables decoding of this
memory range."
If you suggested "3 & ..." as an alignedness check of the address, I
have to admit to not knowing off hand what exactly the HW does in this
case.
>
> - Changing the memory map registers appears to be only
> half-implemented.
The reason for this is because I was not able to find a prototype in
QEMU 0.8.0 cpu-all.h that allows one to change or to unregister physical
memory.
>
> - Qemu can now support different ARM CPU cores relatively easily, , so
> you should be able to get it to report the correct ID. Enforcing v4t
> only is harder, but less important.
Do you mean CP15 register 0 for reporting the ID or what?
>
> - Please use 4 spaces for code indent, not tabs.
>
> - This is just ugly:
> +# define e ((struct altera_excalibur_state *) opaque)
> Use a local variable like the existing code.
>
> - There appears to be support for different board variants, scattered
> in several different places and #if 0'ed out. This should at least be
> controlled by a single #define, preferably a runtime option.
>
The board variants are actually device variants. There are 1 and a half
locations where the device variants actually come into play, but as you
suggest, a symbolic name would be better.
> - There are several chunks of code surrounded by #if 0 for no apparent
> reason.
The reason was documentation, some registers are read-only and I wanted
to make sure that I hadn't forgotten any. The way it is now allows one
to find each register quickly, in both the read and write paths and see
that a conscious decision regarding its use was made. I can present and
document this better.
>
> - Token names in ALL_CAPS should only be used for preprocessor macros
> and constants, not field names.
Structure members that model hardware registers use the exact spelling
of the defining Altera Excalibur manual. I would like to keep that. I
could prefix each such structure member with a lower case prefix, to
avoid name clashes with macros, if you like.
>
> - Mangling CFLAGS for one object file is not acceptable.
> +altera-excalibur.o: CFLAGS += -Wno-parentheses -O0
> +-fno-omit-frame-pointer
> The warnings produced by -Wparentheses should IMHO be fixed, not
> ignored. Some of the C operator precedence rules are non-obvious so
> it's best to be explicit.
This is part of my "improvement plan for the universe" :-).
> I'm guessing the -O0 and -fno-omit-frame-pointer are for debugging, so
> should be removed before submission.
I haven't tested without those flags yet.
> Paul
Since other things have higher priority for me now, would it be ok if I
resubmitted in a few weeks time?
Regards,
Konrad
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2006-04-18 8:54 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-10 11:26 [Qemu-devel] Patch that adds machine "Altera Excalibur" Schwarz, Konrad
2006-04-16 16:24 ` Paul Brook
-- strict thread matches above, loose matches on Subject: below --
2006-04-18 8:53 Schwarz, Konrad
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).