This file implements a platform for Microchip PIC32MX7 microcontroller, with three boards (machine types) supported:
pic32mx7-explorer16 PIC32MX7 microcontroller on Microchip Explorer-16 board pic32mx7-max32 PIC32MX7 microcontroller on chipKIT Max32 board pic32mx7-maximite PIC32MX7 microcontroller on Geoff's Maximite computer Signed-off-by: Serge Vakulenko <serge.vakule...@gmail.com> --- hw/mips/mips_pic32mx7.c | 1641 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1641 insertions(+) create mode 100644 hw/mips/mips_pic32mx7.c diff --git a/hw/mips/mips_pic32mx7.c b/hw/mips/mips_pic32mx7.c new file mode 100644 index 0000000..21dd115 --- /dev/null +++ b/hw/mips/mips_pic32mx7.c @@ -0,0 +1,1641 @@ +/* + * QEMU support for Microchip PIC32MX7 microcontroller. + * + * Copyright (c) 2015 Serge Vakulenko + * + * 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 "hw/i386/pc.h" +#include "hw/char/serial.h" +#include "hw/mips/cpudevs.h" +#include "sysemu/char.h" +#include "hw/loader.h" +#include "qemu/error-report.h" +#include "hw/empty_slot.h" +#include <termios.h> + +#define PIC32MX7 +#include "pic32mx.h" +#include "pic32_peripherals.h" + +/* Hardware addresses */ +#define PROGRAM_FLASH_START 0x1d000000 +#define BOOT_FLASH_START 0x1fc00000 +#define DATA_MEM_START 0x00000000 +#define IO_MEM_START 0x1f800000 + +#define PROGRAM_FLASH_SIZE (512*1024) /* 512 kbytes */ +#define BOOT_FLASH_SIZE (12*1024) /* 12 kbytes */ +#define DATA_MEM_SIZE (128*1024) /* 128 kbytes */ +#define USER_MEM_START 0xbf000000 + +#define TYPE_MIPS_PIC32 "mips-pic32mx7" + +/* + * Board variants. + */ +enum { + BOARD_MAX32, /* chipKIT Max32 board */ + BOARD_MAXIMITE, /* Geoff's Maximite board */ + BOARD_EXPLORER16, /* Microchip Explorer-16 board */ +}; + +static const char *board_name[] = { + "chipKIT Max32", + "Geoff's Maximite Computer", + "Microchip Explorer16", +}; + +/* + * Pointers to Flash memory contents. + */ +static char *prog_ptr; +static char *boot_ptr; + +#define BOOTMEM(addr) ((uint32_t *) boot_ptr)[(addr & 0xffff) >> 2] + +/* + * TODO: add option to enable tracing. + */ +#define TRACE 0 + +/* + * PIC32MX7 specific table: + * translate IRQ number to interrupt vector. + */ +static const int irq_to_vector[] = { + PIC32_VECT_CT, /* 0 - Core Timer Interrupt */ + PIC32_VECT_CS0, /* 1 - Core Software Interrupt 0 */ + PIC32_VECT_CS1, /* 2 - Core Software Interrupt 1 */ + PIC32_VECT_INT0, /* 3 - External Interrupt 0 */ + PIC32_VECT_T1, /* 4 - Timer1 */ + PIC32_VECT_IC1, /* 5 - Input Capture 1 */ + PIC32_VECT_OC1, /* 6 - Output Compare 1 */ + PIC32_VECT_INT1, /* 7 - External Interrupt 1 */ + PIC32_VECT_T2, /* 8 - Timer2 */ + PIC32_VECT_IC2, /* 9 - Input Capture 2 */ + PIC32_VECT_OC2, /* 10 - Output Compare 2 */ + PIC32_VECT_INT2, /* 11 - External Interrupt 2 */ + PIC32_VECT_T3, /* 12 - Timer3 */ + PIC32_VECT_IC3, /* 13 - Input Capture 3 */ + PIC32_VECT_OC3, /* 14 - Output Compare 3 */ + PIC32_VECT_INT3, /* 15 - External Interrupt 3 */ + PIC32_VECT_T4, /* 16 - Timer4 */ + PIC32_VECT_IC4, /* 17 - Input Capture 4 */ + PIC32_VECT_OC4, /* 18 - Output Compare 4 */ + PIC32_VECT_INT4, /* 19 - External Interrupt 4 */ + PIC32_VECT_T5, /* 20 - Timer5 */ + PIC32_VECT_IC5, /* 21 - Input Capture 5 */ + PIC32_VECT_OC5, /* 22 - Output Compare 5 */ + PIC32_VECT_SPI1, /* 23 - SPI1 Fault */ + PIC32_VECT_SPI1, /* 24 - SPI1 Transfer Done */ + PIC32_VECT_SPI1, /* 25 - SPI1 Receive Done */ + + PIC32_VECT_U1 | /* 26 - UART1 Error */ + PIC32_VECT_SPI3 | /* 26 - SPI3 Fault */ + PIC32_VECT_I2C3, /* 26 - I2C3 Bus Collision Event */ + + PIC32_VECT_U1 | /* 27 - UART1 Receiver */ + PIC32_VECT_SPI3 | /* 27 - SPI3 Transfer Done */ + PIC32_VECT_I2C3, /* 27 - I2C3 Slave Event */ + + PIC32_VECT_U1 | /* 28 - UART1 Transmitter */ + PIC32_VECT_SPI3 | /* 28 - SPI3 Receive Done */ + PIC32_VECT_I2C3, /* 28 - I2C3 Master Event */ + + PIC32_VECT_I2C1, /* 29 - I2C1 Bus Collision Event */ + PIC32_VECT_I2C1, /* 30 - I2C1 Slave Event */ + PIC32_VECT_I2C1, /* 31 - I2C1 Master Event */ + PIC32_VECT_CN, /* 32 - Input Change Interrupt */ + PIC32_VECT_AD1, /* 33 - ADC1 Convert Done */ + PIC32_VECT_PMP, /* 34 - Parallel Master Port */ + PIC32_VECT_CMP1, /* 35 - Comparator Interrupt */ + PIC32_VECT_CMP2, /* 36 - Comparator Interrupt */ + + PIC32_VECT_U3 | /* 37 - UART3 Error */ + PIC32_VECT_SPI2 | /* 37 - SPI2 Fault */ + PIC32_VECT_I2C4, /* 37 - I2C4 Bus Collision Event */ + + PIC32_VECT_U3 | /* 38 - UART3 Receiver */ + PIC32_VECT_SPI2 | /* 38 - SPI2 Transfer Done */ + PIC32_VECT_I2C4, /* 38 - I2C4 Slave Event */ + + PIC32_VECT_U3 | /* 39 - UART3 Transmitter */ + PIC32_VECT_SPI2 | /* 39 - SPI2 Receive Done */ + PIC32_VECT_I2C4, /* 39 - I2C4 Master Event */ + + PIC32_VECT_U2 | /* 40 - UART2 Error */ + PIC32_VECT_SPI4 | /* 40 - SPI4 Fault */ + PIC32_VECT_I2C5, /* 40 - I2C5 Bus Collision Event */ + + PIC32_VECT_U2 | /* 41 - UART2 Receiver */ + PIC32_VECT_SPI4 | /* 41 - SPI4 Transfer Done */ + PIC32_VECT_I2C5, /* 41 - I2C5 Slave Event */ + + PIC32_VECT_U2 | /* 42 - UART2 Transmitter */ + PIC32_VECT_SPI4 | /* 42 - SPI4 Receive Done */ + PIC32_VECT_I2C5, /* 42 - I2C5 Master Event */ + + PIC32_VECT_I2C2, /* 43 - I2C2 Bus Collision Event */ + PIC32_VECT_I2C2, /* 44 - I2C2 Slave Event */ + PIC32_VECT_I2C2, /* 45 - I2C2 Master Event */ + PIC32_VECT_FSCM, /* 46 - Fail-Safe Clock Monitor */ + PIC32_VECT_RTCC, /* 47 - Real-Time Clock and Calendar */ + PIC32_VECT_DMA0, /* 48 - DMA Channel 0 */ + PIC32_VECT_DMA1, /* 49 - DMA Channel 1 */ + PIC32_VECT_DMA2, /* 50 - DMA Channel 2 */ + PIC32_VECT_DMA3, /* 51 - DMA Channel 3 */ + PIC32_VECT_DMA4, /* 52 - DMA Channel 4 */ + PIC32_VECT_DMA5, /* 53 - DMA Channel 5 */ + PIC32_VECT_DMA6, /* 54 - DMA Channel 6 */ + PIC32_VECT_DMA7, /* 55 - DMA Channel 7 */ + PIC32_VECT_FCE, /* 56 - Flash Control Event */ + PIC32_VECT_USB, /* 57 - USB */ + PIC32_VECT_CAN1, /* 58 - Control Area Network 1 */ + PIC32_VECT_CAN2, /* 59 - Control Area Network 2 */ + PIC32_VECT_ETH, /* 60 - Ethernet Interrupt */ + PIC32_VECT_IC1, /* 61 - Input Capture 1 Error */ + PIC32_VECT_IC2, /* 62 - Input Capture 2 Error */ + PIC32_VECT_IC3, /* 63 - Input Capture 3 Error */ + PIC32_VECT_IC4, /* 64 - Input Capture 4 Error */ + PIC32_VECT_IC5, /* 65 - Input Capture 5 Error */ + PIC32_VECT_PMP, /* 66 - Parallel Master Port Error */ + PIC32_VECT_U4, /* 67 - UART4 Error */ + PIC32_VECT_U4, /* 68 - UART4 Receiver */ + PIC32_VECT_U4, /* 69 - UART4 Transmitter */ + PIC32_VECT_U6, /* 70 - UART6 Error */ + PIC32_VECT_U6, /* 71 - UART6 Receiver */ + PIC32_VECT_U6, /* 72 - UART6 Transmitter */ + PIC32_VECT_U5, /* 73 - UART5 Error */ + PIC32_VECT_U5, /* 74 - UART5 Receiver */ + PIC32_VECT_U5, /* 75 - UART5 Transmitter */ +}; + +static void update_irq_status(pic32_t *s) +{ + /* Assume no interrupts pending. */ + int cause_ripl = 0; + int vector = 0; + CPUMIPSState *env = &s->cpu->env; + int current_ripl = (env->CP0_Cause >> (CP0Ca_IP + 2)) & 0x3f; + + VALUE(INTSTAT) = 0; + + if ((VALUE(IFS0) & VALUE(IEC0)) || + (VALUE(IFS1) & VALUE(IEC1)) || + (VALUE(IFS2) & VALUE(IEC2))) + { + /* Find the most prioritive pending interrupt, + * it's vector and level. */ + int irq; + for (irq = 0; irq < sizeof(irq_to_vector)/sizeof(int); irq++) { + int n = irq >> 5; + + if (((VALUE(IFS(n)) & VALUE(IEC(n))) >> (irq & 31)) & 1) { + /* Interrupt is pending. */ + int v = irq_to_vector[irq]; + if (v < 0) { + continue; + } + + int level = VALUE(IPC(v >> 2)); + level >>= 2 + (v & 3) * 8; + level &= 7; + if (level > cause_ripl) { + vector = v; + cause_ripl = level; + } + } + } + VALUE(INTSTAT) = vector | (cause_ripl << 8); + } + + if (cause_ripl == current_ripl) { + return; + } + + if (TRACE) { + fprintf(qemu_logfile, "--- Priority level Cause.RIPL = %u\n", + cause_ripl); + } + + /* + * Modify Cause.RIPL field and take EIC interrupt. + */ + env->CP0_Cause &= ~(0x3f << (CP0Ca_IP + 2)); + env->CP0_Cause |= cause_ripl << (CP0Ca_IP + 2); + cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD); +} + +/* + * Set interrupt flag status + */ +static void irq_raise(pic32_t *s, int irq) +{ + if (VALUE(IFS(irq >> 5)) & (1 << (irq & 31))) { + return; + } + + VALUE(IFS(irq >> 5)) |= 1 << (irq & 31); + update_irq_status(s); +} + +/* + * Clear interrupt flag status + */ +static void irq_clear(pic32_t *s, int irq) +{ + if (!(VALUE(IFS(irq >> 5)) & (1 << (irq & 31)))) { + return; + } + + VALUE(IFS(irq >> 5)) &= ~(1 << (irq & 31)); + update_irq_status(s); +} + +/* + * Timer interrupt or soft interrupt. + */ +static void pic32_irq_request(void *opaque, int num, int raise) +{ + pic32_t *s = opaque; + CPUMIPSState *env = &s->cpu->env; + + if (raise) { + if (TRACE) { + if (num == 0) + fprintf(qemu_logfile, "--- %08x: Timer interrupt\n", + env->active_tc.PC); + else + fprintf(qemu_logfile, "--- %08x: Soft interrupt %u\n", + env->active_tc.PC, num-1); + } + irq_raise(s, num); + } else { + if (TRACE) { + if (num == 0) + fprintf(qemu_logfile, "--- %08x: Clear timer interrupt\n", + env->active_tc.PC); + else + fprintf(qemu_logfile, "--- %08x: Clear soft interrupt %u\n", + env->active_tc.PC, num-1); + } + irq_clear(s, num); + } +} + +/* + * Perform an assign/clear/set/invert operation. + */ +static inline unsigned write_op(int a, int b, int op) +{ + switch (op & 0xc) { + case 0x0: /* Assign */ + a = b; + break; + case 0x4: /* Clear */ + a &= ~b; + break; + case 0x8: /* Set */ + a |= b; + break; + case 0xc: /* Invert */ + a ^= b; + break; + } + return a; +} + +static void io_reset(pic32_t *s) +{ + int i; + + /* + * Bus matrix control registers. + */ + VALUE(BMXCON) = 0x001f0041; /* Bus Matrix Control */ + VALUE(BMXDKPBA) = 0; /* Data RAM kernel program base */ + VALUE(BMXDUDBA) = 0; /* Data RAM user data base address */ + VALUE(BMXDUPBA) = 0; /* Data RAM user program base */ + VALUE(BMXPUPBA) = 0; /* Program Flash user program base */ + VALUE(BMXDRMSZ) = 128 * 1024; /* Data RAM memory size */ + VALUE(BMXPFMSZ) = 512 * 1024; /* Program Flash memory size */ + VALUE(BMXBOOTSZ) = 12 * 1024; /* Boot Flash size */ + + /* + * Prefetch controller. + */ + VALUE(CHECON) = 0x00000007; + + /* + * System controller. + */ + VALUE(OSCTUN) = 0; + VALUE(DDPCON) = 0; + VALUE(SYSKEY) = 0; + VALUE(RCON) = 0; + VALUE(RSWRST) = 0; + s->syskey_unlock = 0; + + /* + * Analog to digital converter. + */ + VALUE(AD1CON1) = 0; /* Control register 1 */ + VALUE(AD1CON2) = 0; /* Control register 2 */ + VALUE(AD1CON3) = 0; /* Control register 3 */ + VALUE(AD1CHS) = 0; /* Channel select */ + VALUE(AD1CSSL) = 0; /* Input scan selection */ + VALUE(AD1PCFG) = 0; /* Port configuration */ + + /* + * General purpose IO signals. + * All pins are inputs, high, open drains and pullups disabled. + * No interrupts on change. + */ + VALUE(TRISA) = 0xFFFF; /* Port A: mask of inputs */ + VALUE(PORTA) = 0xFFFF; /* Port A: read inputs, write outputs */ + VALUE(LATA) = 0xFFFF; /* Port A: read/write outputs */ + VALUE(ODCA) = 0; /* Port A: open drain configuration */ + VALUE(TRISB) = 0xFFFF; /* Port B: mask of inputs */ + VALUE(PORTB) = 0xFFFF; /* Port B: read inputs, write outputs */ + VALUE(LATB) = 0xFFFF; /* Port B: read/write outputs */ + VALUE(ODCB) = 0; /* Port B: open drain configuration */ + VALUE(TRISC) = 0xFFFF; /* Port C: mask of inputs */ + VALUE(PORTC) = 0xFFFF; /* Port C: read inputs, write outputs */ + VALUE(LATC) = 0xFFFF; /* Port C: read/write outputs */ + VALUE(ODCC) = 0; /* Port C: open drain configuration */ + VALUE(TRISD) = 0xFFFF; /* Port D: mask of inputs */ + VALUE(PORTD) = 0xFFFF; /* Port D: read inputs, write outputs */ + VALUE(LATD) = 0xFFFF; /* Port D: read/write outputs */ + VALUE(ODCD) = 0; /* Port D: open drain configuration */ + VALUE(TRISE) = 0xFFFF; /* Port E: mask of inputs */ + VALUE(PORTE) = 0xFFFF; /* Port D: read inputs, write outputs */ + VALUE(LATE) = 0xFFFF; /* Port E: read/write outputs */ + VALUE(ODCE) = 0; /* Port E: open drain configuration */ + VALUE(TRISF) = 0xFFFF; /* Port F: mask of inputs */ + VALUE(PORTF) = 0xFFFF; /* Port F: read inputs, write outputs */ + VALUE(LATF) = 0xFFFF; /* Port F: read/write outputs */ + VALUE(ODCF) = 0; /* Port F: open drain configuration */ + VALUE(TRISG) = 0xFFFF; /* Port G: mask of inputs */ + VALUE(PORTG) = 0xFFFF; /* Port G: read inputs, write outputs */ + VALUE(LATG) = 0xFFFF; /* Port G: read/write outputs */ + VALUE(ODCG) = 0; /* Port G: open drain configuration */ + VALUE(CNCON) = 0; /* Interrupt-on-change control */ + VALUE(CNEN) = 0; /* Input change interrupt enable */ + VALUE(CNPUE) = 0; /* Input pin pull-up enable */ + + /* + * Reset UARTs. + */ + VALUE(U1MODE) = 0; + VALUE(U1STA) = PIC32_USTA_RIDLE | PIC32_USTA_TRMT; + VALUE(U1TXREG) = 0; + VALUE(U1RXREG) = 0; + VALUE(U1BRG) = 0; + VALUE(U2MODE) = 0; + VALUE(U2STA) = PIC32_USTA_RIDLE | PIC32_USTA_TRMT; + VALUE(U2TXREG) = 0; + VALUE(U2RXREG) = 0; + VALUE(U2BRG) = 0; + VALUE(U3MODE) = 0; + VALUE(U3STA) = PIC32_USTA_RIDLE | PIC32_USTA_TRMT; + VALUE(U3TXREG) = 0; + VALUE(U3RXREG) = 0; + VALUE(U3BRG) = 0; + VALUE(U4MODE) = 0; + VALUE(U4STA) = PIC32_USTA_RIDLE | PIC32_USTA_TRMT; + VALUE(U4TXREG) = 0; + VALUE(U4RXREG) = 0; + VALUE(U4BRG) = 0; + VALUE(U5MODE) = 0; + VALUE(U5STA) = PIC32_USTA_RIDLE | PIC32_USTA_TRMT; + VALUE(U5TXREG) = 0; + VALUE(U5RXREG) = 0; + VALUE(U5BRG) = 0; + VALUE(U6MODE) = 0; + VALUE(U6STA) = PIC32_USTA_RIDLE | PIC32_USTA_TRMT; + VALUE(U6TXREG) = 0; + VALUE(U6RXREG) = 0; + VALUE(U6BRG) = 0; + + /* + * Reset SPI. + */ + VALUE(SPI1CON) = 0; + VALUE(SPI1STAT) = PIC32_SPISTAT_SPITBE; /* Transmit buffer is empty */ + VALUE(SPI1BRG) = 0; + + VALUE(SPI2CON) = 0; + VALUE(SPI2STAT) = PIC32_SPISTAT_SPITBE; /* Transmit buffer is empty */ + VALUE(SPI2BRG) = 0; + + VALUE(SPI3CON) = 0; + VALUE(SPI3STAT) = PIC32_SPISTAT_SPITBE; /* Transmit buffer is empty */ + VALUE(SPI3BRG) = 0; + + VALUE(SPI4CON) = 0; + VALUE(SPI4STAT) = PIC32_SPISTAT_SPITBE; /* Transmit buffer is empty */ + VALUE(SPI4BRG) = 0; + + for (i = 0; i < NUM_SPI; i++) { + s->spi[i].rfifo = 0; + s->spi[i].wfifo = 0; + } +} + +static unsigned io_read32(pic32_t *s, unsigned offset, const char **namep) +{ + unsigned *bufp = &VALUE(offset); + + switch (offset) { + /*------------------------------------------------------------------------- + * Bus matrix control registers. + */ + STORAGE(BMXCON); break; /* Bus Mmatrix Control */ + STORAGE(BMXDKPBA); break; /* Data RAM kernel program base address */ + STORAGE(BMXDUDBA); break; /* Data RAM user data base address */ + STORAGE(BMXDUPBA); break; /* Data RAM user program base address */ + STORAGE(BMXPUPBA); break; /* Program Flash user program base address */ + STORAGE(BMXDRMSZ); break; /* Data RAM memory size */ + STORAGE(BMXPFMSZ); break; /* Program Flash memory size */ + STORAGE(BMXBOOTSZ); break; /* Boot Flash size */ + + /*------------------------------------------------------------------------- + * Interrupt controller registers. + */ + STORAGE(INTCON); break; /* Interrupt Control */ + STORAGE(INTSTAT); break; /* Interrupt Status */ + STORAGE(IFS0); break; /* IFS(0..2) - Interrupt Flag Status */ + STORAGE(IFS1); break; + STORAGE(IFS2); break; + STORAGE(IEC0); break; /* IEC(0..2) - Interrupt Enable Control */ + STORAGE(IEC1); break; + STORAGE(IEC2); break; + STORAGE(IPC0); break; /* IPC(0..11) - Interrupt Priority Control */ + STORAGE(IPC1); break; + STORAGE(IPC2); break; + STORAGE(IPC3); break; + STORAGE(IPC4); break; + STORAGE(IPC5); break; + STORAGE(IPC6); break; + STORAGE(IPC7); break; + STORAGE(IPC8); break; + STORAGE(IPC9); break; + STORAGE(IPC10); break; + STORAGE(IPC11); break; + STORAGE(IPC12); break; + + /*------------------------------------------------------------------------- + * Prefetch controller. + */ + STORAGE(CHECON); break; /* Prefetch Control */ + + /*------------------------------------------------------------------------- + * System controller. + */ + STORAGE(OSCCON); break; /* Oscillator Control */ + STORAGE(OSCTUN); break; /* Oscillator Tuning */ + STORAGE(DDPCON); break; /* Debug Data Port Control */ + STORAGE(DEVID); break; /* Device Identifier */ + STORAGE(SYSKEY); break; /* System Key */ + STORAGE(RCON); break; /* Reset Control */ + STORAGE(RSWRST); /* Software Reset */ + if ((VALUE(RSWRST) & 1) && s->stop_on_reset) { + exit(0); + } + break; + + /*------------------------------------------------------------------------- + * DMA controller. + */ + STORAGE(DMACON); break; /* DMA Control */ + STORAGE(DMASTAT); break; /* DMA Status */ + STORAGE(DMAADDR); break; /* DMA Address */ + + /*------------------------------------------------------------------------- + * Analog to digital converter. + */ + STORAGE(AD1CON1); break; /* Control register 1 */ + STORAGE(AD1CON2); break; /* Control register 2 */ + STORAGE(AD1CON3); break; /* Control register 3 */ + STORAGE(AD1CHS); break; /* Channel select */ + STORAGE(AD1CSSL); break; /* Input scan selection */ + STORAGE(AD1PCFG); break; /* Port configuration */ + STORAGE(ADC1BUF0); break; /* Result words */ + STORAGE(ADC1BUF1); break; + STORAGE(ADC1BUF2); break; + STORAGE(ADC1BUF3); break; + STORAGE(ADC1BUF4); break; + STORAGE(ADC1BUF5); break; + STORAGE(ADC1BUF6); break; + STORAGE(ADC1BUF7); break; + STORAGE(ADC1BUF8); break; + STORAGE(ADC1BUF9); break; + STORAGE(ADC1BUFA); break; + STORAGE(ADC1BUFB); break; + STORAGE(ADC1BUFC); break; + STORAGE(ADC1BUFD); break; + STORAGE(ADC1BUFE); break; + STORAGE(ADC1BUFF); break; + + /*-------------------------------------- + * USB registers. + */ + STORAGE(U1OTGIR); break; /* OTG interrupt flags */ + STORAGE(U1OTGIE); break; /* OTG interrupt enable */ + STORAGE(U1OTGSTAT); break; /* Comparator and pin status */ + STORAGE(U1OTGCON); break; /* Resistor and pin control */ + STORAGE(U1PWRC); break; /* Power control */ + STORAGE(U1IR); break; /* Pending interrupt */ + STORAGE(U1IE); break; /* Interrupt enable */ + STORAGE(U1EIR); break; /* Pending error interrupt */ + STORAGE(U1EIE); break; /* Error interrupt enable */ + STORAGE(U1STAT); break; /* Status FIFO */ + STORAGE(U1CON); break; /* Control */ + STORAGE(U1ADDR); break; /* Address */ + STORAGE(U1BDTP1); break; /* Buffer descriptor table pointer 1 */ + STORAGE(U1FRML); break; /* Frame counter low */ + STORAGE(U1FRMH); break; /* Frame counter high */ + STORAGE(U1TOK); break; /* Host control */ + STORAGE(U1SOF); break; /* SOF counter */ + STORAGE(U1BDTP2); break; /* Buffer descriptor table pointer 2 */ + STORAGE(U1BDTP3); break; /* Buffer descriptor table pointer 3 */ + STORAGE(U1CNFG1); break; /* Debug and idle */ + STORAGE(U1EP(0)); break; /* Endpoint control */ + STORAGE(U1EP(1)); break; + STORAGE(U1EP(2)); break; + STORAGE(U1EP(3)); break; + STORAGE(U1EP(4)); break; + STORAGE(U1EP(5)); break; + STORAGE(U1EP(6)); break; + STORAGE(U1EP(7)); break; + STORAGE(U1EP(8)); break; + STORAGE(U1EP(9)); break; + STORAGE(U1EP(10)); break; + STORAGE(U1EP(11)); break; + STORAGE(U1EP(12)); break; + STORAGE(U1EP(13)); break; + STORAGE(U1EP(14)); break; + STORAGE(U1EP(15)); break; + + /*------------------------------------------------------------------------- + * General purpose IO signals. + */ + STORAGE(TRISA); break; /* Port A: mask of inputs */ + STORAGE(PORTA); break; /* Port A: read inputs */ + STORAGE(LATA); break; /* Port A: read outputs */ + STORAGE(ODCA); break; /* Port A: open drain configuration */ + STORAGE(TRISB); break; /* Port B: mask of inputs */ + STORAGE(PORTB); break; /* Port B: read inputs */ + STORAGE(LATB); break; /* Port B: read outputs */ + STORAGE(ODCB); break; /* Port B: open drain configuration */ + STORAGE(TRISC); break; /* Port C: mask of inputs */ + STORAGE(PORTC); break; /* Port C: read inputs */ + STORAGE(LATC); break; /* Port C: read outputs */ + STORAGE(ODCC); break; /* Port C: open drain configuration */ + STORAGE(TRISD); break; /* Port D: mask of inputs */ + STORAGE(PORTD); break; /* Port D: read inputs */ + STORAGE(LATD); break; /* Port D: read outputs */ + STORAGE(ODCD); break; /* Port D: open drain configuration */ + STORAGE(TRISE); break; /* Port E: mask of inputs */ + STORAGE(PORTE); break; /* Port E: read inputs */ + STORAGE(LATE); break; /* Port E: read outputs */ + STORAGE(ODCE); break; /* Port E: open drain configuration */ + STORAGE(TRISF); break; /* Port F: mask of inputs */ + STORAGE(PORTF); break; /* Port F: read inputs */ + STORAGE(LATF); break; /* Port F: read outputs */ + STORAGE(ODCF); break; /* Port F: open drain configuration */ + STORAGE(TRISG); break; /* Port G: mask of inputs */ + STORAGE(PORTG); break; /* Port G: read inputs */ + STORAGE(LATG); break; /* Port G: read outputs */ + STORAGE(ODCG); break; /* Port G: open drain configuration */ + STORAGE(CNCON); break; /* Interrupt-on-change control */ + STORAGE(CNEN); break; /* Input change interrupt enable */ + STORAGE(CNPUE); break; /* Input pin pull-up enable */ + + /*------------------------------------------------------------------------- + * UART 1. + */ + STORAGE(U1RXREG); /* Receive data */ + *bufp = pic32_uart_get_char(s, 0); + break; + STORAGE(U1BRG); break; /* Baud rate */ + STORAGE(U1MODE); break; /* Mode */ + STORAGE(U1STA); /* Status and control */ + pic32_uart_poll_status(s, 0); + break; + STORAGE(U1TXREG); *bufp = 0; break; /* Transmit */ + STORAGE(U1MODECLR); *bufp = 0; break; + STORAGE(U1MODESET); *bufp = 0; break; + STORAGE(U1MODEINV); *bufp = 0; break; + STORAGE(U1STACLR); *bufp = 0; break; + STORAGE(U1STASET); *bufp = 0; break; + STORAGE(U1STAINV); *bufp = 0; break; + STORAGE(U1BRGCLR); *bufp = 0; break; + STORAGE(U1BRGSET); *bufp = 0; break; + STORAGE(U1BRGINV); *bufp = 0; break; + + /*------------------------------------------------------------------------- + * UART 2. + */ + STORAGE(U2RXREG); /* Receive data */ + *bufp = pic32_uart_get_char(s, 1); + break; + STORAGE(U2BRG); break; /* Baud rate */ + STORAGE(U2MODE); break; /* Mode */ + STORAGE(U2STA); /* Status and control */ + pic32_uart_poll_status(s, 1); + break; + STORAGE(U2TXREG); *bufp = 0; break; /* Transmit */ + STORAGE(U2MODECLR); *bufp = 0; break; + STORAGE(U2MODESET); *bufp = 0; break; + STORAGE(U2MODEINV); *bufp = 0; break; + STORAGE(U2STACLR); *bufp = 0; break; + STORAGE(U2STASET); *bufp = 0; break; + STORAGE(U2STAINV); *bufp = 0; break; + STORAGE(U2BRGCLR); *bufp = 0; break; + STORAGE(U2BRGSET); *bufp = 0; break; + STORAGE(U2BRGINV); *bufp = 0; break; + + /*------------------------------------------------------------------------- + * UART 3. + */ + STORAGE(U3RXREG); /* Receive data */ + *bufp = pic32_uart_get_char(s, 2); + break; + STORAGE(U3BRG); break; /* Baud rate */ + STORAGE(U3MODE); break; /* Mode */ + STORAGE(U3STA); /* Status and control */ + pic32_uart_poll_status(s, 2); + break; + STORAGE(U3TXREG); *bufp = 0; break; /* Transmit */ + STORAGE(U3MODECLR); *bufp = 0; break; + STORAGE(U3MODESET); *bufp = 0; break; + STORAGE(U3MODEINV); *bufp = 0; break; + STORAGE(U3STACLR); *bufp = 0; break; + STORAGE(U3STASET); *bufp = 0; break; + STORAGE(U3STAINV); *bufp = 0; break; + STORAGE(U3BRGCLR); *bufp = 0; break; + STORAGE(U3BRGSET); *bufp = 0; break; + STORAGE(U3BRGINV); *bufp = 0; break; + + /*------------------------------------------------------------------------- + * UART 4. + */ + STORAGE(U4RXREG); /* Receive data */ + *bufp = pic32_uart_get_char(s, 3); + break; + STORAGE(U4BRG); break; /* Baud rate */ + STORAGE(U4MODE); break; /* Mode */ + STORAGE(U4STA); /* Status and control */ + pic32_uart_poll_status(s, 3); + break; + STORAGE(U4TXREG); *bufp = 0; break; /* Transmit */ + STORAGE(U4MODECLR); *bufp = 0; break; + STORAGE(U4MODESET); *bufp = 0; break; + STORAGE(U4MODEINV); *bufp = 0; break; + STORAGE(U4STACLR); *bufp = 0; break; + STORAGE(U4STASET); *bufp = 0; break; + STORAGE(U4STAINV); *bufp = 0; break; + STORAGE(U4BRGCLR); *bufp = 0; break; + STORAGE(U4BRGSET); *bufp = 0; break; + STORAGE(U4BRGINV); *bufp = 0; break; + + /*------------------------------------------------------------------------- + * UART 5. + */ + STORAGE(U5RXREG); /* Receive data */ + *bufp = pic32_uart_get_char(s, 4); + break; + STORAGE(U5BRG); break; /* Baud rate */ + STORAGE(U5MODE); break; /* Mode */ + STORAGE(U5STA); /* Status and control */ + pic32_uart_poll_status(s, 4); + break; + STORAGE(U5TXREG); *bufp = 0; break; /* Transmit */ + STORAGE(U5MODECLR); *bufp = 0; break; + STORAGE(U5MODESET); *bufp = 0; break; + STORAGE(U5MODEINV); *bufp = 0; break; + STORAGE(U5STACLR); *bufp = 0; break; + STORAGE(U5STASET); *bufp = 0; break; + STORAGE(U5STAINV); *bufp = 0; break; + STORAGE(U5BRGCLR); *bufp = 0; break; + STORAGE(U5BRGSET); *bufp = 0; break; + STORAGE(U5BRGINV); *bufp = 0; break; + + /*------------------------------------------------------------------------- + * UART 6. + */ + STORAGE(U6RXREG); /* Receive data */ + *bufp = pic32_uart_get_char(s, 5); + break; + STORAGE(U6BRG); break; /* Baud rate */ + STORAGE(U6MODE); break; /* Mode */ + STORAGE(U6STA); /* Status and control */ + pic32_uart_poll_status(s, 5); + break; + STORAGE(U6TXREG); *bufp = 0; break; /* Transmit */ + STORAGE(U6MODECLR); *bufp = 0; break; + STORAGE(U6MODESET); *bufp = 0; break; + STORAGE(U6MODEINV); *bufp = 0; break; + STORAGE(U6STACLR); *bufp = 0; break; + STORAGE(U6STASET); *bufp = 0; break; + STORAGE(U6STAINV); *bufp = 0; break; + STORAGE(U6BRGCLR); *bufp = 0; break; + STORAGE(U6BRGSET); *bufp = 0; break; + STORAGE(U6BRGINV); *bufp = 0; break; + + /*------------------------------------------------------------------------- + * SPI 1. + */ + STORAGE(SPI1CON); break; /* Control */ + STORAGE(SPI1CONCLR); *bufp = 0; break; + STORAGE(SPI1CONSET); *bufp = 0; break; + STORAGE(SPI1CONINV); *bufp = 0; break; + STORAGE(SPI1STAT); break; /* Status */ + STORAGE(SPI1STATCLR); *bufp = 0; break; + STORAGE(SPI1STATSET); *bufp = 0; break; + STORAGE(SPI1STATINV); *bufp = 0; break; + STORAGE(SPI1BUF); /* Buffer */ + *bufp = pic32_spi_readbuf(s, 0); + break; + STORAGE(SPI1BRG); break; /* Baud rate */ + STORAGE(SPI1BRGCLR); *bufp = 0; break; + STORAGE(SPI1BRGSET); *bufp = 0; break; + STORAGE(SPI1BRGINV); *bufp = 0; break; + + /*------------------------------------------------------------------------- + * SPI 2. + */ + STORAGE(SPI2CON); break; /* Control */ + STORAGE(SPI2CONCLR); *bufp = 0; break; + STORAGE(SPI2CONSET); *bufp = 0; break; + STORAGE(SPI2CONINV); *bufp = 0; break; + STORAGE(SPI2STAT); break; /* Status */ + STORAGE(SPI2STATCLR); *bufp = 0; break; + STORAGE(SPI2STATSET); *bufp = 0; break; + STORAGE(SPI2STATINV); *bufp = 0; break; + STORAGE(SPI2BUF); /* Buffer */ + *bufp = pic32_spi_readbuf(s, 1); + break; + STORAGE(SPI2BRG); break; /* Baud rate */ + STORAGE(SPI2BRGCLR); *bufp = 0; break; + STORAGE(SPI2BRGSET); *bufp = 0; break; + STORAGE(SPI2BRGINV); *bufp = 0; break; + + /*------------------------------------------------------------------------- + * SPI 3. + */ + STORAGE(SPI3CON); break; /* Control */ + STORAGE(SPI3CONCLR); *bufp = 0; break; + STORAGE(SPI3CONSET); *bufp = 0; break; + STORAGE(SPI3CONINV); *bufp = 0; break; + STORAGE(SPI3STAT); break; /* Status */ + STORAGE(SPI3STATCLR); *bufp = 0; break; + STORAGE(SPI3STATSET); *bufp = 0; break; + STORAGE(SPI3STATINV); *bufp = 0; break; + STORAGE(SPI3BUF); /* SPIx Buffer */ + *bufp = pic32_spi_readbuf(s, 2); + break; + STORAGE(SPI3BRG); break; /* Baud rate */ + STORAGE(SPI3BRGCLR); *bufp = 0; break; + STORAGE(SPI3BRGSET); *bufp = 0; break; + STORAGE(SPI3BRGINV); *bufp = 0; break; + + /*------------------------------------------------------------------------- + * SPI 4. + */ + STORAGE(SPI4CON); break; /* Control */ + STORAGE(SPI4CONCLR); *bufp = 0; break; + STORAGE(SPI4CONSET); *bufp = 0; break; + STORAGE(SPI4CONINV); *bufp = 0; break; + STORAGE(SPI4STAT); break; /* Status */ + STORAGE(SPI4STATCLR); *bufp = 0; break; + STORAGE(SPI4STATSET); *bufp = 0; break; + STORAGE(SPI4STATINV); *bufp = 0; break; + STORAGE(SPI4BUF); /* Buffer */ + *bufp = pic32_spi_readbuf(s, 3); + break; + STORAGE(SPI4BRG); break; /* Baud rate */ + STORAGE(SPI4BRGCLR); *bufp = 0; break; + STORAGE(SPI4BRGSET); *bufp = 0; break; + STORAGE(SPI4BRGINV); *bufp = 0; break; + + default: + printf("--- Read 1f8%05x: peripheral register not supported\n", + offset); + if (TRACE) { + fprintf(qemu_logfile, + "--- Read 1f8%05x: peripheral register not supported\n", + offset); + } + exit(1); + } + return *bufp; +} + +static void io_write32(pic32_t *s, unsigned offset, unsigned data, + const char **namep) +{ + unsigned *bufp = &VALUE(offset); + + switch (offset) { + /*------------------------------------------------------------------------- + * Bus matrix control registers. + */ + WRITEOP(BMXCON); return; /* Bus Matrix Control */ + STORAGE(BMXDKPBA); break; /* Data RAM kernel program base address */ + STORAGE(BMXDUDBA); break; /* Data RAM user data base address */ + STORAGE(BMXDUPBA); break; /* Data RAM user program base address */ + STORAGE(BMXPUPBA); break; /* Program Flash user program base address */ + READONLY(BMXDRMSZ); /* Data RAM memory size */ + READONLY(BMXPFMSZ); /* Program Flash memory size */ + READONLY(BMXBOOTSZ); /* Boot Flash size */ + + /*------------------------------------------------------------------------- + * Interrupt controller registers. + */ + WRITEOP(INTCON); return; /* Interrupt Control */ + READONLY(INTSTAT); /* Interrupt Status */ + WRITEOP(IPTMR); return; /* Temporal Proximity Timer */ + WRITEOP(IFS0); goto irq; /* IFS(0..2) - Interrupt Flag Status */ + WRITEOP(IFS1); goto irq; + WRITEOP(IFS2); goto irq; + WRITEOP(IEC0); goto irq; /* IEC(0..2) - Interrupt Enable Control */ + WRITEOP(IEC1); goto irq; + WRITEOP(IEC2); goto irq; + WRITEOP(IPC0); goto irq; /* IPC(0..11) - Interrupt Priority Control */ + WRITEOP(IPC1); goto irq; + WRITEOP(IPC2); goto irq; + WRITEOP(IPC3); goto irq; + WRITEOP(IPC4); goto irq; + WRITEOP(IPC5); goto irq; + WRITEOP(IPC6); goto irq; + WRITEOP(IPC7); goto irq; + WRITEOP(IPC8); goto irq; + WRITEOP(IPC9); goto irq; + WRITEOP(IPC10); goto irq; + WRITEOP(IPC11); goto irq; + WRITEOP(IPC12); +irq: update_irq_status(s); + return; + + /*------------------------------------------------------------------------- + * Prefetch controller. + */ + WRITEOP(CHECON); /* Prefetch Control */ + return; + + /*------------------------------------------------------------------------- + * System controller. + */ + WRITEOPR(OSCCON, PIC32_OSCCON_UNUSED); /* Oscillator Control */ + break; + WRITEOPR(OSCTUN, PIC32_OSCTUN_UNUSED); /* Oscillator Tuning */ + break; + STORAGE(DDPCON); /* Debug Data Port Control */ + break; + READONLY(DEVID); /* Device Identifier */ + + STORAGE(SYSKEY); /* System Key */ + /* Unlock state machine. */ + if (s->syskey_unlock == 0 && VALUE(SYSKEY) == 0xaa996655) { + s->syskey_unlock = 1; + } + if (s->syskey_unlock == 1 && VALUE(SYSKEY) == 0x556699aa) { + s->syskey_unlock = 2; + } else { + s->syskey_unlock = 0; + } + break; + WRITEOPR(RCON, PIC32_RCON_UNUSED); /* Reset Control */ + break; + WRITEOP(RSWRST); /* Software Reset */ + if (s->syskey_unlock == 2 && (VALUE(RSWRST) & 1)) { + /* Reset CPU. */ + qemu_system_reset_request(); + + /* Reset all devices */ + io_reset(s); + pic32_sdcard_reset(s); + } + break; + + /*------------------------------------------------------------------------- + * DMA controller. + */ + WRITEOP(DMACON); return; /* DMA Control */ + STORAGE(DMASTAT); break; /* DMA Status */ + STORAGE(DMAADDR); break; /* DMA Address */ + + /*------------------------------------------------------------------------- + * Analog to digital converter. + */ + WRITEOP(AD1CON1); return; /* Control register 1 */ + WRITEOP(AD1CON2); return; /* Control register 2 */ + WRITEOP(AD1CON3); return; /* Control register 3 */ + WRITEOP(AD1CHS); return; /* Channel select */ + WRITEOP(AD1CSSL); return; /* Input scan selection */ + WRITEOP(AD1PCFG); return; /* Port configuration */ + READONLY(ADC1BUF0); /* Result words */ + READONLY(ADC1BUF1); + READONLY(ADC1BUF2); + READONLY(ADC1BUF3); + READONLY(ADC1BUF4); + READONLY(ADC1BUF5); + READONLY(ADC1BUF6); + READONLY(ADC1BUF7); + READONLY(ADC1BUF8); + READONLY(ADC1BUF9); + READONLY(ADC1BUFA); + READONLY(ADC1BUFB); + READONLY(ADC1BUFC); + READONLY(ADC1BUFD); + READONLY(ADC1BUFE); + READONLY(ADC1BUFF); + + /*-------------------------------------- + * USB registers. + */ + STORAGE(U1OTGIR); /* OTG interrupt flags */ + VALUE(U1OTGIR) = 0; + return; + STORAGE(U1OTGIE); break; /* OTG interrupt enable */ + READONLY(U1OTGSTAT); /* Comparator and pin status */ + STORAGE(U1OTGCON); break; /* Resistor and pin control */ + STORAGE(U1PWRC); break; /* Power control */ + STORAGE(U1IR); /* Pending interrupt */ + VALUE(U1IR) = 0; + return; + STORAGE(U1IE); break; /* Interrupt enable */ + STORAGE(U1EIR); /* Pending error interrupt */ + VALUE(U1EIR) = 0; + return; + STORAGE(U1EIE); break; /* Error interrupt enable */ + READONLY(U1STAT); /* Status FIFO */ + STORAGE(U1CON); break; /* Control */ + STORAGE(U1ADDR); break; /* Address */ + STORAGE(U1BDTP1); break; /* Buffer descriptor table pointer 1 */ + READONLY(U1FRML); /* Frame counter low */ + READONLY(U1FRMH); /* Frame counter high */ + STORAGE(U1TOK); break; /* Host control */ + STORAGE(U1SOF); break; /* SOF counter */ + STORAGE(U1BDTP2); break; /* Buffer descriptor table pointer 2 */ + STORAGE(U1BDTP3); break; /* Buffer descriptor table pointer 3 */ + STORAGE(U1CNFG1); break; /* Debug and idle */ + STORAGE(U1EP(0)); break; /* Endpoint control */ + STORAGE(U1EP(1)); break; + STORAGE(U1EP(2)); break; + STORAGE(U1EP(3)); break; + STORAGE(U1EP(4)); break; + STORAGE(U1EP(5)); break; + STORAGE(U1EP(6)); break; + STORAGE(U1EP(7)); break; + STORAGE(U1EP(8)); break; + STORAGE(U1EP(9)); break; + STORAGE(U1EP(10)); break; + STORAGE(U1EP(11)); break; + STORAGE(U1EP(12)); break; + STORAGE(U1EP(13)); break; + STORAGE(U1EP(14)); break; + STORAGE(U1EP(15)); break; + + /*------------------------------------------------------------------------- + * General purpose IO signals. + */ + WRITEOP(TRISA); return; /* Port A: mask of inputs */ + WRITEOPX(PORTA, LATA); /* Port A: write outputs */ + WRITEOP(LATA); /* Port A: write outputs */ + pic32_gpio_write(s, 0, VALUE(LATA)); + return; + WRITEOP(ODCA); return; /* Port A: open drain configuration */ + WRITEOP(TRISB); return; /* Port B: mask of inputs */ + WRITEOPX(PORTB, LATB); /* Port B: write outputs */ + WRITEOP(LATB); /* Port B: write outputs */ + pic32_gpio_write(s, 1, VALUE(LATB)); + return; + WRITEOP(ODCB); return; /* Port B: open drain configuration */ + WRITEOP(TRISC); return; /* Port C: mask of inputs */ + WRITEOPX(PORTC, LATC); /* Port C: write outputs */ + WRITEOP(LATC); /* Port C: write outputs */ + pic32_gpio_write(s, 2, VALUE(LATC)); + return; + WRITEOP(ODCC); return; /* Port C: open drain configuration */ + WRITEOP(TRISD); return; /* Port D: mask of inputs */ + WRITEOPX(PORTD, LATD); /* Port D: write outputs */ + WRITEOP(LATD); /* Port D: write outputs */ + pic32_gpio_write(s, 3, VALUE(LATD)); + return; + WRITEOP(ODCD); return; /* Port D: open drain configuration */ + WRITEOP(TRISE); return; /* Port E: mask of inputs */ + WRITEOPX(PORTE, LATE); /* Port E: write outputs */ + WRITEOP(LATE); /* Port E: write outputs */ + pic32_gpio_write(s, 4, VALUE(LATE)); + return; + WRITEOP(ODCE); return; /* Port E: open drain configuration */ + WRITEOP(TRISF); return; /* Port F: mask of inputs */ + WRITEOPX(PORTF, LATF); /* Port F: write outputs */ + WRITEOP(LATF); /* Port F: write outputs */ + pic32_gpio_write(s, 5, VALUE(LATF)); + return; + WRITEOP(ODCF); return; /* Port F: open drain configuration */ + WRITEOP(TRISG); return; /* Port G: mask of inputs */ + WRITEOPX(PORTG, LATG); /* Port G: write outputs */ + WRITEOP(LATG); /* Port G: write outputs */ + pic32_gpio_write(s, 6, VALUE(LATG)); + return; + WRITEOP(ODCG); return; /* Port G: open drain configuration */ + WRITEOP(CNCON); return; /* Interrupt-on-change control */ + WRITEOP(CNEN); return; /* Input change interrupt enable */ + WRITEOP(CNPUE); return; /* Input pin pull-up enable */ + + /*------------------------------------------------------------------------- + * UART 1. + */ + STORAGE(U1TXREG); /* Transmit */ + pic32_uart_put_char(s, 0, data); + break; + WRITEOP(U1MODE); /* Mode */ + pic32_uart_update_mode(s, 0); + return; + WRITEOPR(U1STA, /* Status and control */ + PIC32_USTA_URXDA | PIC32_USTA_FERR | PIC32_USTA_PERR | + PIC32_USTA_RIDLE | PIC32_USTA_TRMT | PIC32_USTA_UTXBF); + pic32_uart_update_status(s, 0); + return; + WRITEOP(U1BRG); return; /* Baud rate */ + READONLY(U1RXREG); /* Receive */ + + /*------------------------------------------------------------------------- + * UART 2. + */ + STORAGE(U2TXREG); /* Transmit */ + pic32_uart_put_char(s, 1, data); + break; + WRITEOP(U2MODE); /* Mode */ + pic32_uart_update_mode(s, 1); + return; + WRITEOPR(U2STA, /* Status and control */ + PIC32_USTA_URXDA | PIC32_USTA_FERR | PIC32_USTA_PERR | + PIC32_USTA_RIDLE | PIC32_USTA_TRMT | PIC32_USTA_UTXBF); + pic32_uart_update_status(s, 1); + return; + WRITEOP(U2BRG); return; /* Baud rate */ + READONLY(U2RXREG); /* Receive */ + + /*------------------------------------------------------------------------- + * UART 3. + */ + STORAGE(U3TXREG); /* Transmit */ + pic32_uart_put_char(s, 2, data); + break; + WRITEOP(U3MODE); /* Mode */ + pic32_uart_update_mode(s, 2); + return; + WRITEOPR(U3STA, /* Status and control */ + PIC32_USTA_URXDA | PIC32_USTA_FERR | PIC32_USTA_PERR | + PIC32_USTA_RIDLE | PIC32_USTA_TRMT | PIC32_USTA_UTXBF); + pic32_uart_update_status(s, 2); + return; + WRITEOP(U3BRG); return; /* Baud rate */ + READONLY(U3RXREG); /* Receive */ + + /*------------------------------------------------------------------------- + * UART 4. + */ + STORAGE(U4TXREG); /* Transmit */ + pic32_uart_put_char(s, 3, data); + break; + WRITEOP(U4MODE); /* Mode */ + pic32_uart_update_mode(s, 3); + return; + WRITEOPR(U4STA, /* Status and control */ + PIC32_USTA_URXDA | PIC32_USTA_FERR | PIC32_USTA_PERR | + PIC32_USTA_RIDLE | PIC32_USTA_TRMT | PIC32_USTA_UTXBF); + pic32_uart_update_status(s, 3); + return; + WRITEOP(U4BRG); return; /* Baud rate */ + READONLY(U4RXREG); /* Receive */ + + /*------------------------------------------------------------------------- + * UART 5. + */ + STORAGE(U5TXREG); /* Transmit */ + pic32_uart_put_char(s, 4, data); + break; + WRITEOP(U5MODE); /* Mode */ + pic32_uart_update_mode(s, 4); + return; + WRITEOPR(U5STA, /* Status and control */ + PIC32_USTA_URXDA | PIC32_USTA_FERR | PIC32_USTA_PERR | + PIC32_USTA_RIDLE | PIC32_USTA_TRMT | PIC32_USTA_UTXBF); + pic32_uart_update_status(s, 4); + return; + WRITEOP(U5BRG); return; /* Baud rate */ + READONLY(U5RXREG); /* Receive */ + + /*------------------------------------------------------------------------- + * UART 6. + */ + STORAGE(U6TXREG); /* Transmit */ + pic32_uart_put_char(s, 5, data); + break; + WRITEOP(U6MODE); /* Mode */ + pic32_uart_update_mode(s, 5); + return; + WRITEOPR(U6STA, /* Status and control */ + PIC32_USTA_URXDA | PIC32_USTA_FERR | PIC32_USTA_PERR | + PIC32_USTA_RIDLE | PIC32_USTA_TRMT | PIC32_USTA_UTXBF); + pic32_uart_update_status(s, 5); + return; + WRITEOP(U6BRG); return; /* Baud rate */ + READONLY(U6RXREG); /* Receive */ + + /*------------------------------------------------------------------------- + * SPI. + */ + WRITEOP(SPI1CON); /* Control */ + pic32_spi_control(s, 0); + return; + WRITEOPR(SPI1STAT, ~PIC32_SPISTAT_SPIROV); /* Status */ + return; /* Only ROV bit writable */ + STORAGE(SPI1BUF); /* Buffer */ + pic32_spi_writebuf(s, 0, data); + return; + WRITEOP(SPI1BRG); return; /* Baud rate */ + WRITEOP(SPI2CON); /* Control */ + pic32_spi_control(s, 1); + return; + WRITEOPR(SPI2STAT, ~PIC32_SPISTAT_SPIROV); /* Status */ + return; /* Only ROV bit writable */ + STORAGE(SPI2BUF); /* Buffer */ + pic32_spi_writebuf(s, 1, data); + return; + WRITEOP(SPI2BRG); return; /* Baud rate */ + WRITEOP(SPI3CON); /* Control */ + pic32_spi_control(s, 2); + return; + WRITEOPR(SPI3STAT, ~PIC32_SPISTAT_SPIROV); /* Status */ + return; /* Only ROV bit writable */ + STORAGE(SPI3BUF); /* Buffer */ + pic32_spi_writebuf(s, 2, data); + return; + WRITEOP(SPI3BRG); return; /* Baud rate */ + WRITEOP(SPI4CON); /* Control */ + pic32_spi_control(s, 3); + return; + WRITEOPR(SPI4STAT, ~PIC32_SPISTAT_SPIROV); /* Status */ + return; /* Only ROV bit writable */ + STORAGE(SPI4BUF); /* Buffer */ + pic32_spi_writebuf(s, 3, data); + return; + WRITEOP(SPI4BRG); return; /* Baud rate */ + + default: + printf("--- Write %08x to 1f8%05x: peripheral register not supported\n", + data, offset); + if (TRACE) { + fprintf(qemu_logfile, + "--- Write %08x to 1f8%05x: peripheral register not supported\n", + data, offset); + } + exit(1); +readonly: + printf("--- Write %08x to %s: readonly register\n", + data, *namep); + if (TRACE) { + fprintf(qemu_logfile, "--- Write %08x to %s: readonly register\n", + data, *namep); + } + *namep = 0; + return; + } + *bufp = data; +} + +static uint64_t pic32_io_read(void *opaque, hwaddr addr, unsigned bytes) +{ + pic32_t *s = opaque; + uint32_t offset = addr & 0xfffff; + const char *name = "???"; + uint32_t data = 0; + + data = io_read32(s, offset & ~3, &name); + switch (bytes) { + case 1: + offset &= 3; + if (offset != 0) { + /* Unaligned read. */ + data >>= offset * 8; + } + data = (uint8_t) data; + if (TRACE) { + fprintf(qemu_logfile, "--- I/O Read %02x from %s\n", data, name); + } + break; + case 2: + if (offset & 2) { + /* Unaligned read. */ + data >>= 16; + } + data = (uint16_t) data; + if (TRACE) { + fprintf(qemu_logfile, "--- I/O Read %04x from %s\n", data, name); + } + break; + default: + if (TRACE) { + fprintf(qemu_logfile, "--- I/O Read %08x from %s\n", data, name); + } + break; + } + return data; +} + +static void pic32_io_write(void *opaque, hwaddr addr, uint64_t data, + unsigned bytes) +{ + pic32_t *s = opaque; + uint32_t offset = addr & 0xfffff; + const char *name = "???"; + + /* Fetch data and align to word format. */ + switch (bytes) { + case 1: + data = (uint8_t) data; + data <<= (offset & 3) * 8; + break; + case 2: + data = (uint16_t) data; + data <<= (offset & 2) * 8; + break; + } + io_write32(s, offset & ~3, data, &name); + + if (TRACE && name != 0) { + fprintf(qemu_logfile, "--- I/O Write %08x to %s\n", + (uint32_t) data, name); + } +} + +/* + * This function is called when the processor is stopped + * on WAIT instruction, waiting for external interrupt. + */ +static void pic32_exec_exit(CPUState *cs) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + + if (cs->halted && !(env->CP0_Status & (1 << CP0St_IE))) { + /* WAIT instruction with interrupts disabled - halt the simulation. */ + qemu_system_shutdown_request(); + } +} + +static const MemoryRegionOps pic32_io_ops = { + .read = pic32_io_read, + .write = pic32_io_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void main_cpu_reset(void *opaque) +{ + MIPSCPU *cpu = opaque; + CPUMIPSState *env = &cpu->env; + int i; + + cpu_reset(CPU(cpu)); + + /* Adjust the initial configuration for M4K core. */ + env->CP0_IntCtl = 0; + env->CP0_Debug = (1 << CP0DB_CNT) | (3 << CP0DB_VER); + for (i = 0; i < 7; i++) { + env->CP0_WatchHi[i] = 0; + } +} + +static void store_byte(unsigned address, unsigned char byte) +{ + if (address >= PROGRAM_FLASH_START && + address < PROGRAM_FLASH_START + PROGRAM_FLASH_SIZE) { + /*printf("Store %02x to program memory %08x\n", byte, address);*/ + prog_ptr[address & 0xfffff] = byte; + return; + } + + if (address >= BOOT_FLASH_START && + address < BOOT_FLASH_START + BOOT_FLASH_SIZE) { + /*printf("Store %02x to boot memory %08x\n", byte, address);*/ + boot_ptr[address & 0xffff] = byte; + return; + } + + printf("Bad hex file: " + "incorrect address %08X, must be %08X-%08X or %08X-%08X\n", + address, PROGRAM_FLASH_START, + PROGRAM_FLASH_START + PROGRAM_FLASH_SIZE - 1, + BOOT_FLASH_START, BOOT_FLASH_START + BOOT_FLASH_SIZE - 1); + exit(1); +} + +/* + * Ignore ^C and ^\ signals and pass these characters to the target. + */ +static void pic32_pass_signal_chars(void) +{ + struct termios tty; + + tcgetattr(0, &tty); + tty.c_lflag &= ~ISIG; + tcsetattr(0, TCSANOW, &tty); +} + +static void pic32_init(MachineState *machine, int board_type) +{ + const char *cpu_model = machine->cpu_model; + unsigned ram_size = DATA_MEM_SIZE; + MemoryRegion *system_memory = get_system_memory(); + MemoryRegion *ram_main = g_new(MemoryRegion, 1); + MemoryRegion *prog_mem = g_new(MemoryRegion, 1); + MemoryRegion *boot_mem = g_new(MemoryRegion, 1); + MemoryRegion *io_mem = g_new(MemoryRegion, 1); + MIPSCPU *cpu; + CPUMIPSState *env; + + DeviceState *dev = qdev_create(NULL, TYPE_MIPS_PIC32); + pic32_t *s = OBJECT_CHECK(pic32_t, dev, TYPE_MIPS_PIC32); + s->board_type = board_type; + s->stop_on_reset = 1; /* halt simulation on soft reset */ + s->iomem = g_malloc0(IO_MEM_SIZE); /* backing storage for I/O area */ + + qdev_init_nofail(dev); + + /* Init CPU. */ + if (!cpu_model) { + cpu_model = "M4K"; + } + printf("Board: %s\n", board_name[board_type]); + if (qemu_logfile) { + fprintf(qemu_logfile, "Board: %s\n", board_name[board_type]); + } + + printf("Processor: %s\n", cpu_model); + if (qemu_logfile) { + fprintf(qemu_logfile, "Processor: %s\n", cpu_model); + } + + cpu = cpu_mips_init(cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + s->cpu = cpu; + env = &cpu->env; + + /* Register RAM */ + printf("RAM size: %u kbytes\n", ram_size / 1024); + if (qemu_logfile) { + fprintf(qemu_logfile, "RAM size: %u kbytes\n", ram_size / 1024); + } + + memory_region_init_ram(ram_main, NULL, "kernel.ram", + ram_size, &error_abort); + vmstate_register_ram_global(ram_main); + memory_region_add_subregion(system_memory, DATA_MEM_START, ram_main); + + /* Alias for user space 96 kbytes. + * For MX family only. */ + MemoryRegion *ram_user = g_new(MemoryRegion, 1); + memory_region_init_alias(ram_user, NULL, "user.ram", + ram_main, 0x8000, ram_size - 0x8000); + memory_region_add_subregion(system_memory, + USER_MEM_START + 0x8000, ram_user); + + /* Special function registers. */ + memory_region_init_io(io_mem, NULL, &pic32_io_ops, s, + "io", IO_MEM_SIZE); + memory_region_add_subregion(system_memory, IO_MEM_START, io_mem); + + /* + * Map the flash memory. + */ + memory_region_init_ram(boot_mem, NULL, "boot.flash", + BOOT_FLASH_SIZE, &error_abort); + memory_region_init_ram(prog_mem, NULL, "prog.flash", + PROGRAM_FLASH_SIZE, &error_abort); + + /* Load a Flash memory image. */ + if (!machine->kernel_filename) { + error_report("No -kernel argument was specified."); + exit(1); + } + prog_ptr = memory_region_get_ram_ptr(prog_mem); + boot_ptr = memory_region_get_ram_ptr(boot_mem); + if (bios_name) { + pic32_load_hex_file(bios_name, store_byte); + } + pic32_load_hex_file(machine->kernel_filename, store_byte); + + memory_region_set_readonly(boot_mem, true); + memory_region_set_readonly(prog_mem, true); + memory_region_add_subregion(system_memory, BOOT_FLASH_START, boot_mem); + memory_region_add_subregion(system_memory, PROGRAM_FLASH_START, prog_mem); + + /* Init internal devices */ + s->irq_raise = irq_raise; + s->irq_clear = irq_clear; + qemu_register_reset(main_cpu_reset, cpu); + + /* Setup interrupt controller in EIC mode. */ + qemu_irq *qi = qemu_allocate_irqs(pic32_irq_request, s, 3); + env->eic_timer_irq = qi[0]; + env->eic_soft_irq[0] = qi[1]; + env->eic_soft_irq[1] = qi[2]; + env->CP0_Config3 |= 1 << CP0C3_VEIC; + + /* CPU runs at 80MHz. + * Count register increases at half this rate. */ + cpu_mips_clock_init(env, 40*1000*1000); + + /* Setup callback for CPU halt. */ + MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu); + CPUClass *cc = CPU_CLASS(mcc); + cc->cpu_exec_exit = pic32_exec_exit; + + /* + * Initialize board-specific parameters. + */ + int cs0_port, cs0_pin, cs1_port, cs1_pin; + switch (board_type) { + default: + case BOARD_MAX32: + BOOTMEM(DEVCFG0) = 0xffffff7f; /* Max32 board */ + BOOTMEM(DEVCFG1) = 0x5bfd6aff; /* console on UART1 */ + BOOTMEM(DEVCFG2) = 0xd979f8f9; + BOOTMEM(DEVCFG3) = 0xffff0722; + VALUE(DEVID) = 0x04307053; /* MX795F512L */ + VALUE(OSCCON) = 0x01453320; /* external oscillator 8MHz */ + s->sdcard_spi_port = 1; /* SD card at SPI2, */ + cs0_port = 2; cs0_pin = 14; /* select0 at C14, */ + cs1_port = 3; cs1_pin = 1; /* select1 at D1 */ + break; + case BOARD_MAXIMITE: + /* TODO: get real data from Maximite board */ + BOOTMEM(DEVCFG0) = 0xffffff7f; + BOOTMEM(DEVCFG1) = 0x5bfd6aff; /* console on UART1 */ + BOOTMEM(DEVCFG2) = 0xd979f8f9; + BOOTMEM(DEVCFG3) = 0xffff0722; + VALUE(DEVID) = 0x04307053; /* MX795F512L */ + VALUE(OSCCON) = 0x01453320; /* external oscillator 8MHz */ + s->sdcard_spi_port = 3; /* SD card at SPI4, */ + cs0_port = 4; cs0_pin = 0; /* select0 at E0, */ + cs1_port = -1; cs1_pin = -1; /* select1 not available */ + break; + case BOARD_EXPLORER16: + /* TODO: get real data from Explorer16 board */ + BOOTMEM(DEVCFG0) = 0xffffff7f; + BOOTMEM(DEVCFG1) = 0x5bfd6aff; /* console on UART2 */ + BOOTMEM(DEVCFG2) = 0xd979f8f9; + BOOTMEM(DEVCFG3) = 0xffff0722; + VALUE(DEVID) = 0x04307053; /* MX795F512L */ + VALUE(OSCCON) = 0x01453320; /* external oscillator 8MHz */ + s->sdcard_spi_port = 0; /* SD card at SPI1, */ + cs0_port = 1; cs0_pin = 1; /* select0 at B1, */ + cs1_port = 1; cs1_pin = 2; /* select1 at B2 */ + break; + } + + /* UARTs */ + pic32_uart_init(s, 0, PIC32_IRQ_U1E, U1STA, U1MODE); + pic32_uart_init(s, 1, PIC32_IRQ_U2E, U2STA, U2MODE); + pic32_uart_init(s, 2, PIC32_IRQ_U3E, U3STA, U3MODE); + pic32_uart_init(s, 3, PIC32_IRQ_U4E, U4STA, U4MODE); + pic32_uart_init(s, 4, PIC32_IRQ_U5E, U5STA, U5MODE); + pic32_uart_init(s, 5, PIC32_IRQ_U6E, U6STA, U6MODE); + + /* SPIs */ + pic32_spi_init(s, 0, PIC32_IRQ_SPI1E, SPI1CON, SPI1STAT); + pic32_spi_init(s, 1, PIC32_IRQ_SPI2E, SPI2CON, SPI2STAT); + pic32_spi_init(s, 2, PIC32_IRQ_SPI3E, SPI3CON, SPI3STAT); + pic32_spi_init(s, 3, PIC32_IRQ_SPI4E, SPI4CON, SPI4STAT); + + /* + * Load SD card images. + * Use options: + * -sd filename + * or -hda filename + * and -hdb filename + */ + const char *sd0_file = 0, *sd1_file = 0; + DriveInfo *dinfo = drive_get(IF_IDE, 0, 0); + if (dinfo) { + sd0_file = qemu_opt_get(dinfo->opts, "file"); + dinfo->is_default = 1; + + dinfo = drive_get(IF_IDE, 0, 1); + if (dinfo) { + sd1_file = qemu_opt_get(dinfo->opts, "file"); + dinfo->is_default = 1; + } + } + if (!sd0_file) { + dinfo = drive_get(IF_SD, 0, 0); + if (dinfo) { + sd0_file = qemu_opt_get(dinfo->opts, "file"); + dinfo->is_default = 1; + } + } + pic32_sdcard_init(s, 0, "sd0", sd0_file, cs0_port, cs0_pin); + pic32_sdcard_init(s, 1, "sd1", sd1_file, cs1_port, cs1_pin); + + io_reset(s); + pic32_sdcard_reset(s); + pic32_pass_signal_chars(); +} + +static void pic32_init_max32(MachineState *machine) +{ + pic32_init(machine, BOARD_MAX32); +} + +static void pic32_init_maximite(MachineState *machine) +{ + pic32_init(machine, BOARD_MAXIMITE); +} + +static void pic32_init_explorer16(MachineState *machine) +{ + pic32_init(machine, BOARD_EXPLORER16); +} + +static int pic32_sysbus_device_init(SysBusDevice *sysbusdev) +{ + return 0; +} + +static void pic32_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pic32_sysbus_device_init; +} + +static const TypeInfo pic32_device = { + .name = TYPE_MIPS_PIC32, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pic32_t), + .class_init = pic32_class_init, +}; + +static void pic32_register_types(void) +{ + type_register_static(&pic32_device); +} + +static QEMUMachine pic32_board[3] = { + { + .name = "pic32mx7-max32", + .desc = "PIC32MX7 microcontroller on chipKIT Max32 board", + .init = pic32_init_max32, + .max_cpus = 1, + }, + { + .name = "pic32mx7-maximite", + .desc = "PIC32MX7 microcontroller on Geoff's Maximite board", + .init = pic32_init_maximite, + .max_cpus = 1, + }, + { + .name = "pic32mx7-explorer16", + .desc = "PIC32MX7 microcontroller on Microchip Explorer-16 board", + .init = pic32_init_explorer16, + .max_cpus = 1, + }, +}; + +static void pic32_machine_init(void) +{ + qemu_register_machine(&pic32_board[0]); + qemu_register_machine(&pic32_board[1]); + qemu_register_machine(&pic32_board[2]); +} + +type_init(pic32_register_types) +machine_init(pic32_machine_init); -- 2.2.2