VirtualMIPS simulator: create a platform for generic M4K core.

This commit is contained in:
Serge Vakulenko
2015-10-26 22:44:38 -07:00
parent d4dbb43d44
commit ade0fff092
11 changed files with 543 additions and 12 deletions

View File

@@ -2,7 +2,7 @@ TOPSRC = $(shell cd ../../..; pwd)
include $(TOPSRC)/target.mk
#include $(TOPSRC)/cross.mk
CFLAGS = -Os
CFLAGS += -Os
LIBS = -lc
ARCH = mips

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

378
tools/virtualmips/m4k.c Normal file
View File

@@ -0,0 +1,378 @@
/*
* Simulation of generic M4K core.
*
* Copyright (C) 2015 Serge Vakulenko <serge@vak.ru>
*
* This file is part of the virtualmips distribution.
* See LICENSE file for terms of the license.
*/
#define _GNU_SOURCE
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#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);
}

66
tools/virtualmips/m4k.h Normal file
View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2015 Serge Vakulenko <serge@vak.ru>
*
* 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

View File

@@ -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 */

View File

@@ -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; i<NVTTY; i++)
vm->vtty_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
*/