From ade0fff0922a617e8d8dc19a735372d5c1133dfb Mon Sep 17 00:00:00 2001 From: Serge Vakulenko Date: Mon, 26 Oct 2015 22:44:38 -0700 Subject: [PATCH] VirtualMIPS simulator: create a platform for generic M4K core. --- src/cmd/smallc/Makefile | 2 +- src/libc/mips/Makefile | 4 +- tools/virtualmips/Makefile | 2 +- tools/virtualmips/Makefile-m4k | 86 ++++++++ tools/virtualmips/dev_ram.c | 2 +- tools/virtualmips/device.c | 1 + tools/virtualmips/device.h | 1 + tools/virtualmips/m4k.c | 378 +++++++++++++++++++++++++++++++++ tools/virtualmips/m4k.h | 66 ++++++ tools/virtualmips/main.c | 2 +- tools/virtualmips/vm.c | 11 +- 11 files changed, 543 insertions(+), 12 deletions(-) create mode 100644 tools/virtualmips/Makefile-m4k create mode 100644 tools/virtualmips/m4k.c create mode 100644 tools/virtualmips/m4k.h diff --git a/src/cmd/smallc/Makefile b/src/cmd/smallc/Makefile index acd932a..72841a0 100644 --- a/src/cmd/smallc/Makefile +++ b/src/cmd/smallc/Makefile @@ -2,7 +2,7 @@ TOPSRC = $(shell cd ../../..; pwd) include $(TOPSRC)/target.mk #include $(TOPSRC)/cross.mk -CFLAGS = -Os +CFLAGS += -Os LIBS = -lc ARCH = mips diff --git a/src/libc/mips/Makefile b/src/libc/mips/Makefile index a62fcda..96fd578 100644 --- a/src/libc/mips/Makefile +++ b/src/libc/mips/Makefile @@ -17,7 +17,7 @@ mips.a: ${ALL} rm -rf tmp ${ALL}: FRC - cd $@; ${MAKE} ${MFLAGS} DEFS=${DEFS} + cd $@; ${MAKE} ${MFLAGS} DEFS="${DEFS}" FRC: @@ -32,4 +32,4 @@ clean: depend: for i in ${ALL}; do \ - (cd $$i; ${MAKE} ${MFLAGS} DEFS=${DEFS} depend); done + (cd $$i; ${MAKE} ${MFLAGS} DEFS="${DEFS}" depend); done diff --git a/tools/virtualmips/Makefile b/tools/virtualmips/Makefile index 46ae104..bd41135 100644 --- a/tools/virtualmips/Makefile +++ b/tools/virtualmips/Makefile @@ -74,7 +74,7 @@ $(PROG): $(OBJS) @mkdir .deps clean: - rm -rf *.o *~ *_log.txt .deps pavo pic32 pic32-log.txt + rm -rf *.o *~ *_log.txt .deps pavo pic32 m4k ifeq (.deps, $(wildcard .deps)) -include .deps/*.dep diff --git a/tools/virtualmips/Makefile-m4k b/tools/virtualmips/Makefile-m4k new file mode 100644 index 0000000..0a6e784 --- /dev/null +++ b/tools/virtualmips/Makefile-m4k @@ -0,0 +1,86 @@ +# +# Build VirtualMIPS simulator. +# + +# Select target board: +# chipKIT Max32 +CFLAGS = -DSIM_PIC32 -DPIC32MX7 -DMAX32 + +# Maximite +#CFLAGS = -DSIM_PIC32 -DPIC32MX7 -DMAXIMITE + +# Microchip Explorer 16 +#CFLAGS = -DSIM_PIC32 -DPIC32MX7 -DEXPLORER16 + +# UBW32 with UART console +#CFLAGS = -DSIM_PIC32 -DPIC32MX7 -DUBW32 + +CC = gcc -g +CFLAGS += -Wall -MT $@ -MD -MP -MF .deps/$*.dep -I/opt/local/include -I/opt/local/include/libelf +LIBS = -lpthread -lelf + +ifneq ($(wildcard /usr/lib/librt.a),) +LIBS += -lrt # Linux +endif +ifneq ($(wildcard /usr/lib/i386-linux-gnu/librt.a),) +LIBS += -lrt # Linux +endif +ifneq ($(wildcard /opt/local/lib/libintl.a),) +LIBS += -L/opt/local/lib -lintl # Mac OS X +endif + +# Optimization. +CFLAGS += -O +#CFLAGS += -O3 -fomit-frame-pointer + +# Microchip PIC32MX +#PROG = pic32 +#OBJS = pic32.o pic32_dev_flash.o pic32_dev_uart.o pic32_dev_intcon.o \ +# pic32_dev_spi.o pic32_dev_gpio.o dev_sdcard.o dev_swap.o \ +# pic32_dev_bmxcon.o pic32_dev_dmacon.o pic32_dev_syscon.o \ +# pic32_dev_prefetch.o pic32_dev_adc.o pic32_dev_devcfg.o \ +# pic32_dev_rtcc.o pic32_dev_timer.o + +# Generic M4K core +PROG = m4k +OBJS = m4k.o + +# Ingenic JZ4740. +#CFLAGS += -DSIM_PAVO -D_USE_FDD_ +#PROG = pavo +#OBJS = pavo.o jz4740.o jz4740_dev_cpm.o jz4740_dev_dma.o \ +# jz4740_dev_emc.o jz4740_dev_gpio.o jz4740_dev_int.o \ +# jz4740_dev_rtc.o jz4740_dev_ts.o \ +# jz4740_dev_uart.o jz4740_dev_wdt_tcu.o + +# Implement LCD. +#CFLAGS += -DSIM_LCD +#LIBS += -lSDL +#OBJS += jz4740_dev_lcd.o vp_sdl.o + +# Use JIT compiler. +#CFLAGS += -D_USE_JIT_ +#OBJS += mips_jit.o x86_trans.o + +# Common files. +OBJS += dev_cs8900.o dev_nand_flash_1g.o dev_ram.o \ + dev_vtty.o device.o vm.o cpu.o mips.o mips_cp0.o \ + mips_exec.o mips_fdd.o crc.o mips_hostalarm.o \ + mempool.o sbox.o utils.o vp_clock.o vp_timer.o net_io.o \ + mips_memory.o debug.o gdb_interface.o main.o \ + mips-dis.o config.o + +all: .deps $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +.deps: + @mkdir .deps + +clean: + rm -rf *.o *~ *_log.txt .deps pavo m4k pic32 pic32-log.txt + +ifeq (.deps, $(wildcard .deps)) +-include .deps/*.dep +endif diff --git a/tools/virtualmips/dev_ram.c b/tools/virtualmips/dev_ram.c index c2aa6a4..99c5f68 100644 --- a/tools/virtualmips/dev_ram.c +++ b/tools/virtualmips/dev_ram.c @@ -27,7 +27,7 @@ void dev_ram_reset (cpu_mips_t * cpu, struct vdevice *dev) { assert (dev->host_addr != 0); /*reset ram */ - memset ((unsigned char *) dev->host_addr, 0x0, dev->phys_len); + //memset ((unsigned char *) dev->host_addr, 0x0, dev->phys_len); } diff --git a/tools/virtualmips/device.c b/tools/virtualmips/device.c index 4f7399b..f8e3f3d 100644 --- a/tools/virtualmips/device.c +++ b/tools/virtualmips/device.c @@ -226,6 +226,7 @@ struct vdevice *dev_create_ram (vm_instance_t * vm, char *name, m_pa_t paddr, dev->phys_len = len; //dev->flags = VDEVICE_FLAG_CACHING; dev->host_addr = (m_iptr_t) m_memalign (4096, dev->phys_len); + memset ((void*) dev->host_addr, 0, dev->phys_len); if (!dev->host_addr) { free (dev); diff --git a/tools/virtualmips/device.h b/tools/virtualmips/device.h index 4fe58b6..e72bc24 100644 --- a/tools/virtualmips/device.h +++ b/tools/virtualmips/device.h @@ -68,6 +68,7 @@ static forced_inline struct vdevice *dev_lookup (vm_instance_t * vm, m_pa_t phys_addr); void dev_init (struct vdevice *dev); +int dev_ram_init (vm_instance_t * vm, char *name, m_pa_t paddr, m_uint32_t len); struct vdevice *dev_create (char *name); struct vdevice *dev_create_ram (vm_instance_t * vm, char *name, m_pa_t paddr, m_uint32_t len); diff --git a/tools/virtualmips/m4k.c b/tools/virtualmips/m4k.c new file mode 100644 index 0000000..38cf35a --- /dev/null +++ b/tools/virtualmips/m4k.c @@ -0,0 +1,378 @@ +/* + * Simulation of generic M4K core. + * + * Copyright (C) 2015 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include + +#include "vp_lock.h" +#include "utils.h" +#include "mips.h" +#include "vm.h" +#include "cpu.h" +#include "mips_exec.h" +#include "debug.h" + +#include "m4k.h" +#include "device.h" +#include "mips_jit.h" + +#define BOOT_RAM_KBYTES 64 /* Size of boot RAM area */ + +/* + * Store a word to the physical memory. + */ +int store_word (vm_instance_t *vm, m_pa_t paddr, unsigned data) +{ + struct vdevice *dev = dev_lookup (vm, paddr); + char *ptr; + + if (! dev) + return -1; + + /* Only for RAM */ + ptr = (char *) dev->host_addr + (paddr - dev->phys_addr); + *(m_uint32_t*) ptr = data; + return 0; +} + +/* + * Load MIPS hex file into memory. + */ +static void load_hex_file (struct vm_instance *vm, const char *filename) +{ + FILE *fp; + char buf [64], *p, *ep; + unsigned address, end_address, data, big_endian = 0; + + fp = fopen (filename, "r"); + if (! fp) { + fprintf (stderr, "%s: Cannot open\n", filename); + exit (-1); + } + while (fgets (buf, sizeof(buf), fp) != 0) { + /* Check header for endian */ + if (buf[0] == '#') { + if (strncmp (buf, "# Endian Big", 12) == 0) { + big_endian = 1; + } + continue; + } + address = strtoul (buf, &ep, 16); + if (ep == buf || *ep == 0) { + continue; + } + if (*ep == '-') { + p = ep+1; + end_address = strtoul (p, &ep, 16); + if (ep == p || *ep != ' ') { + continue; + } + } else + end_address = address; + p = ep; + data = strtoul (p, &ep, 16); + if (ep == p) { + continue; + } + + /* Byte swap. */ + if (big_endian) { + data = (data & 0x000000ff) << 24 | + (data & 0x0000ff00) << 8 | + (data & 0x00ff0000) >> 8 | + (data & 0xff000000) >> 24 ; + } + + do { + if (store_word (vm, address << 2, data) < 0) { + fprintf (stderr, "%s: No memory at physical address %08x\n", + filename, address << 2); + exit (-1); + } + //printf (" %08x <= %08x\n", address << 2, data); + } while (address++ < end_address); + } + fclose (fp); +} + +/* + * Initialize the M4K platform. + */ +static int m4k_init_platform (m4k_t *m4k) +{ + struct vm_instance *vm = m4k->vm; + cpu_mips_t *cpu0; + void *(*cpu_run_fn) (void *); + + //vm_init_vtty (vm); + + /* Create a CPU group */ + vm->cpu_group = cpu_group_create ("System CPU"); + + /* Initialize the virtual MIPS processor */ + cpu0 = cpu_create (vm, CPU_TYPE_MIPS32, 0); + if (! cpu0) { + vm_error (vm, "unable to create CPU0!\n"); + return (-1); + } + /* Add this CPU to the system CPU group */ + cpu_group_add (vm->cpu_group, cpu0); + vm->boot_cpu = cpu0; + + /* create the CPU thread execution */ + cpu_run_fn = (void *) mips_exec_run_cpu; + if (pthread_create (&cpu0->cpu_thread, NULL, cpu_run_fn, cpu0) != 0) { + fprintf (stderr, "cpu_create: unable to create thread for CPU%u\n", + 0); + free (cpu0); + return (-1); + } + /* 32-bit address */ + cpu0->addr_bus_mask = 0xffffffff; + + /* Initialize main RAM */ + vm_ram_init (vm, 0x00000000ULL); + + /* Initialize boot RAM area */ + dev_ram_init (vm, "boot", 0x1fc00000, BOOT_RAM_KBYTES*1024); + + load_hex_file (vm, m4k->boot_file_name); + return (0); +} + +/* + * Find pending interrupt with the biggest priority. + * Setup INTSTAT and cause registers. + * Update irq_pending flag for CPU. + */ +void m4k_update_irq_flag (m4k_t *m4k) +{ + cpu_mips_t *cpu = m4k->vm->boot_cpu; + + /* Assume no interrupts pending. */ + cpu->irq_cause = 0; + cpu->irq_pending = 0; + + //TODO + cpu->irq_cause = 0; +/*printf ("-- vector = %d, level = %d\n", vector, level);*/ + + mips_update_irq_flag (cpu); +} + +void m4k_clear_irq (vm_instance_t *vm, u_int irq) +{ + m4k_t *m4k = (m4k_t*) vm->hw_data; + + /* Clear interrupt flag status */ + //TODO + + m4k_update_irq_flag (m4k); +} + +void m4k_set_irq (vm_instance_t *vm, u_int irq) +{ + m4k_t *m4k = (m4k_t*) vm->hw_data; + + /* Set interrupt flag status */ + //TODO + + m4k_update_irq_flag (m4k); +} + +/* + * Activate core timer interrupt + */ +void set_timer_irq (cpu_mips_t *cpu) +{ + //TODO +} + +/* + * Clear core timer interrupt + */ +void clear_timer_irq (cpu_mips_t *cpu) +{ + //TODO +} + +/* + * Increment timers. + */ +void host_alarm (cpu_mips_t *cpu, int nclocks) +{ + //m4k_t *m4k = (m4k_t*) cpu->vm->hw_data; + //TODO +} + +/* + * Configuration information. + */ +static char *start_address = "0xbfc00000"; + +static void configure_parameter (void *arg, char *section, char *param, char *value) +{ + m4k_t *m4k = arg; + vm_instance_t *vm = m4k->vm; + + if (strcmp (param, "ram_size") == 0) + vm->ram_size = strtoul (value, 0, 0); + else if (strcmp (param, "gdb_debug") == 0) + vm->gdb_debug = strtoul (value, 0, 0); + else if (strcmp (param, "gdb_port") == 0) + vm->gdb_port = strtoul (value, 0, 0); + else if (strcmp (param, "jit_use") == 0) + vm->jit_use = strtoul (value, 0, 0); + else if (strcmp (param, "debug_level") == 0) + vm->debug_level = strtoul (value, 0, 0); + else if (strcmp (param, "hex_file_name") == 0) + m4k->boot_file_name = strdup (value); + else if (strcmp (param, "start_address") == 0) + start_address = strdup (value); + else { + fprintf (stderr, "%s: unknown parameter `%s'\n", vm->configure_filename, param); + exit (-1); + } + //printf ("Configure: %s = '%s'\n", param, value); +} + +static void m4k_parse_configure (m4k_t *m4k) +{ + vm_instance_t *vm = m4k->vm; + + conf_parse (vm->configure_filename, configure_parameter, m4k); + if (start_address) + m4k->start_address = strtoul (start_address, 0, 0); + + ASSERT(vm->ram_size != 0, "ram_size can not be 0\n"); + + /* Add other configure information validation here */ + if (vm->jit_use) { + ASSERT (JIT_SUPPORT == 1, + "You must compile with JIT Support to use jit.\n"); + } + + const char *output_file_name = "m4k.trace"; + printf ("Redirect output to %s\n", output_file_name); + if (freopen(output_file_name, "w", stdout) != stdout) { + fprintf (stderr, "M4K: Unable to redirect output!\n"); + exit(-1); + } + + /* Print the configure information */ + printf("Using configure file: %s\n", vm->configure_filename); + printf("ram_size: %dk bytes \n", vm->ram_size); + + if (vm->gdb_debug != 0) { + printf("GDB debug enable\n"); + printf("GDB port: %d \n",vm->gdb_port); + } + + /* print other configure information here */ + printf ("start_address: 0x%x\n", m4k->start_address); +} + +/* + * Create an instance of virtual machine. + */ +vm_instance_t *create_instance (char *configure_filename) +{ + vm_instance_t *vm; + m4k_t *m4k; + const char *name = "m4k"; + + m4k = malloc (sizeof (*m4k)); + if (! m4k) { + fprintf (stderr, "M4K: unable to create new instance!\n"); + return NULL; + } + memset (m4k, 0, sizeof (*m4k)); + + vm = vm_create (name, VM_TYPE_PIC32); + if (! vm) { + fprintf (stderr, "M4K: unable to create VM instance!\n"); + free (m4k); + return NULL; + } + vm->hw_data = m4k; + m4k->vm = vm; + + /* Initialize default parameters for m4k */ + if (configure_filename == NULL) + configure_filename = "m4k.conf"; + vm->configure_filename = strdup (configure_filename); + vm->ram_size = 4*1024; /* kilobytes */ + + m4k_parse_configure (m4k); + + /* init gdb debug */ + vm_debug_init (m4k->vm); + + return m4k->vm; +} + +int init_instance (vm_instance_t * vm) +{ + m4k_t *m4k = (m4k_t *) vm->hw_data; + cpu_mips_t *cpu; + + if (m4k_init_platform (m4k) == -1) { + vm_error (vm, "unable to initialize the platform hardware.\n"); + return (-1); + } + if (! vm->boot_cpu) { + vm_error (vm, "unable to boot cpu.\n"); + return (-1); + } + + /* IRQ routing */ + vm->set_irq = m4k_set_irq; + vm->clear_irq = m4k_clear_irq; + + vm_suspend (vm); + + /* Check that CPU activity is really suspended */ + if (cpu_group_sync_state (vm->cpu_group) == -1) { + vm_error (vm, "unable to sync with system CPUs.\n"); + return (-1); + } + + /* Reset the boot CPU */ + cpu = vm->boot_cpu; + mips_reset (cpu); + + /* Set config0-config3 registers. */ + cpu->cp0.config_usable = 0x0f; + cpu->cp0.config_reg[0] = 0xa4000582; + cpu->cp0.config_reg[1] = 0x80000006; + cpu->cp0.config_reg[2] = 0x80000000; + cpu->cp0.config_reg[3] = 0x00000020; + + /* set PC and PRID */ + cpu->cp0.reg[MIPS_CP0_PRID] = 0x00018700; + cpu->cp0.tlb_entries = 0; + cpu->pc = m4k->start_address; + + /* reset all devices */ + dev_reset_all (vm); + +#ifdef _USE_JIT_ + /* if jit is used. flush all jit buffer */ + if (vm->jit_use) + mips_jit_flush (cpu, 0); +#endif + + /* Launch the simulation */ + printf ("--- Start simulation: PC=0x%" LL "x, JIT %sabled\n", + cpu->pc, vm->jit_use ? "en" : "dis"); + vm->status = VM_STATUS_RUNNING; + cpu_start (vm->boot_cpu); + return (0); +} diff --git a/tools/virtualmips/m4k.h b/tools/virtualmips/m4k.h new file mode 100644 index 0000000..3d8cab1 --- /dev/null +++ b/tools/virtualmips/m4k.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#ifndef __M4K_H__ +#define __M4K_H__ + +#include "types.h" + +#define DATA_WIDTH 32 /* MIPS32 architecture */ +#define LL /* empty - printf format for machine word */ + +/* + * Data types + */ +typedef m_uint32_t m_va_t; +typedef m_uint32_t m_pa_t; +typedef m_uint32_t m_reg_t; +typedef m_int32_t m_ireg_t; +typedef m_uint32_t m_cp0_reg_t; + +/*Guest endian*/ +#define GUEST_BYTE_ORDER ARCH_LITTLE_ENDIAN + +/* Host to VM conversion functions */ +#if HOST_BYTE_ORDER == GUEST_BYTE_ORDER +#define htovm16(x) (x) +#define htovm32(x) (x) +#define htovm64(x) (x) + +#define vmtoh16(x) (x) +#define vmtoh32(x) (x) +#define vmtoh64(x) (x) +#else //host:big guest:little + +#define htovm16(x) (ntohs(x)) +#define htovm32(x) (ntohl(x)) +#define htovm64(x) (swap64(x)) + +#define vmtoh16(x) (htons(x)) +#define vmtoh32(x) (htonl(x)) +#define vmtoh64(x) (swap64(x)) +#endif + +struct m4k_system { + /* Associated VM instance */ + vm_instance_t *vm; + + unsigned start_address; /* jump here on reset */ + char *boot_file_name; /* image of boot flash */ +}; + +typedef struct m4k_system m4k_t; +struct virtual_tty; + +vm_instance_t *create_instance (char *conf); +int init_instance (vm_instance_t *vm); +int m4k_reset (vm_instance_t *vm); +void m4k_update_irq_flag (m4k_t *m4k); +void m4k_set_irq (vm_instance_t *vm, unsigned irq); +void m4k_clear_irq (vm_instance_t *vm, unsigned irq); +void dumpregs (cpu_mips_t *cpu); + +#endif diff --git a/tools/virtualmips/main.c b/tools/virtualmips/main.c index ce0648d..7d44f0f 100644 --- a/tools/virtualmips/main.c +++ b/tools/virtualmips/main.c @@ -63,7 +63,7 @@ int main (int argc, char *argv[]) char *configure_filename = NULL; printf ("VirtualMIPS (version %s)\n", VERSION); - printf ("Copyright (c) 2008 yajin, 2011 vak.\n"); + printf ("Copyright (c) 2008 yajin, 2011-2015 vak.\n"); printf ("Build date: %s %s\n\n", __DATE__, __TIME__); /* Initialize CRC functions */ diff --git a/tools/virtualmips/vm.c b/tools/virtualmips/vm.c index aa96f35..4688b4e 100644 --- a/tools/virtualmips/vm.c +++ b/tools/virtualmips/vm.c @@ -125,10 +125,12 @@ int vm_create_log (vm_instance_t * vm) if (vm->log_file_enabled) { vm_close_log (vm); - if (!(vm->log_file = vm_build_filename (vm, "log.txt"))) + vm->log_file = vm_build_filename (vm, "log.txt"); + if (! vm->log_file) return (-1); - if (!(vm->log_fd = fopen (vm->log_file, "w"))) { + vm->log_fd = fopen (vm->log_file, "w"); + if (! vm->log_fd) { fprintf (stderr, "VM %s: unable to create log file '%s'\n", vm->name, vm->log_file); free (vm->log_file); @@ -174,7 +176,7 @@ vm_instance_t *vm_create (const char *name, int machine_type) for (i=1; ivtty_type[i] = VTTY_TYPE_NONE; //vm->timer_irq_check_itv = VM_TIMER_IRQ_CHECK_ITV; - vm->log_file_enabled = TRUE; + //vm->log_file_enabled = TRUE; vm->name = strdup (name); if (!name) { @@ -277,9 +279,6 @@ void vm_free (vm_instance_t * vm) } } -int dev_ram_init (vm_instance_t * vm, char *name, m_pa_t paddr, - m_uint32_t len); - /* * Initialize RAM */