sim: example-synacor: a simple implementation for reference

Provide a simple example simulator for people porting to new targets
to use as a reference.  This one has the advantage of being used by
people and having a fun program available for it.

It doesn't require a special target -- the example simulators can be
built for any existing port.
This commit is contained in:
Mike Frysinger 2020-12-09 22:26:30 -05:00
parent a389375f5b
commit 26da232cbd
34 changed files with 16037 additions and 1 deletions

View File

@ -1,3 +1,8 @@
2021-04-03 Mike Frysinger <vapier@gentoo.org>
* configure.ac: Add --example-sims option.
* configure: Regenerate.
2021-04-03 Mike Frysinger <vapier@gentoo.org>
* Makefile.am (check_PROGRAMS, CLEANFILES, DISTCLEANFILES): Define.

16
sim/configure vendored
View File

@ -744,6 +744,7 @@ enable_maintainer_mode
enable_dependency_tracking
enable_silent_rules
enable_sim
enable_example_sims
enable_targets
'
ac_precious_vars='build_alias
@ -785,7 +786,8 @@ sh
erc32
ppc
ft32
v850'
v850
example-synacor'
# Initialize some variables set by options.
ac_init_help=
@ -1414,6 +1416,7 @@ Optional Features:
--enable-silent-rules less verbose build output (undo: "make V=1")
--disable-silent-rules verbose build output (undo: "make V=0")
--enable-sim Enable the GNU simulator
--enable-example-sims enable example GNU simulators
--enable-targets alternative target configurations
Some influential environment variables:
@ -4832,6 +4835,12 @@ esac
fi
# Check whether --enable-example-sims was given.
if test "${enable_example_sims+set}" = set; then :
enableval=$enable_example_sims;
fi
# Check whether --enable-targets was given.
if test "${enable_targets+set}" = set; then :
enableval=$enable_targets; case "${enableval}" in
@ -5227,6 +5236,11 @@ subdirs="$subdirs aarch64"
esac
done
if test "x${enable_example_sims}" = xyes; then
subdirs="$subdirs example-synacor"
fi
fi
if test "$sim_igen" = "yes"; then
SIM_ENABLE_IGEN_TRUE=

View File

@ -19,6 +19,10 @@ yes | no) ;;
*) AC_MSG_ERROR(bad value ${enableval} given for --enable-sim option) ;;
esac])
AC_ARG_ENABLE([example-sims],
[AC_HELP_STRING([--enable-example-sims],
[enable example GNU simulators])])
AC_ARG_ENABLE(targets,
[ --enable-targets alternative target configurations],
[case "${enableval}" in
@ -85,6 +89,10 @@ if test "${enable_sim}" != no; then
SIM_TARGET([ft32-*-*], [ft32])
SIM_TARGET([v850*-*-*], [v850], [sim_igen=yes])
done
if test "x${enable_example_sims}" = xyes; then
AC_CONFIG_SUBDIRS(example-synacor)
fi
fi
AM_CONDITIONAL([SIM_ENABLE_IGEN], [test "$sim_igen" = "yes"])

View File

@ -0,0 +1,5 @@
2021-04-03 Mike Frysinger <vapier@gentoo.org>
* configure.ac, interp.c, Makefile.in, README, README.arch-spec,
sim-main.c, sim-main.h: New files for example simulator.
* aclocal.m4, config.in, configure: Regenerated.

View File

@ -0,0 +1,26 @@
# Makefile template for Configure for the example synacor simulator.
# Copyright (C) 2005-2021 Free Software Foundation, Inc.
# Written by Mike Frysinger <vapier@gentoo.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
## COMMON_PRE_CONFIG_FRAG
SIM_OBJS = \
$(SIM_NEW_COMMON_OBJS) \
sim-resume.o \
interp.o \
sim-main.o
## COMMON_POST_CONFIG_FRAG

View File

@ -0,0 +1,15 @@
= OVERVIEW =
The Synacor Challenge is a fun programming exercise with a number of puzzles
built into it. You can find more details about it here:
https://challenge.synacor.com/
The first puzzle is writing an interpreter for their custom ISA. This is a
simulator for that custom CPU. The CPU is quite basic: it's 16-bit with only
8 registers and a limited set of instructions. This means the port will never
grow new features. See README.arch-spec for more details.
Implementing it here ends up being quite useful: it acts as a simple constrained
"real world" example for people who want to implement a new simulator for their
own architecture. We demonstrate all the basic fundamentals (registers, memory,
branches, and tracing) that all ports should have.

View File

@ -0,0 +1,73 @@
== architecture ==
- three storage regions
- memory with 15-bit address space storing 16-bit values
- eight registers
- an unbounded stack which holds individual 16-bit values
- all numbers are unsigned integers 0..32767 (15-bit)
- all math is modulo 32768; 32758 + 15 => 5
== binary format ==
- each number is stored as a 16-bit little-endian pair (low byte, high byte)
- numbers 0..32767 mean a literal value
- numbers 32768..32775 instead mean registers 0..7
- numbers 32776..65535 are invalid
- programs are loaded into memory starting at address 0
- address 0 is the first 16-bit value, address 1 is the second 16-bit value, etc
== execution ==
- After an operation is executed, the next instruction to read is immediately after the last argument of the current operation.
If a jump was performed, the next operation is instead the exact destination of the jump.
- Encountering a register as an operation argument should be taken as reading from the register or setting into the register as appropriate.
== hints ==
- Start with operations 0, 19, and 21.
- Here's a code for the challenge website: jTTockJlJiOC
- The program "9,32768,32769,4,19,32768" occupies six memory addresses and should:
- Store into register 0 the sum of 4 and the value contained in register 1.
- Output to the terminal the character with the ascii code contained in register 0.
== opcode listing ==
halt: 0
stop execution and terminate the program
set: 1 a b
set register <a> to the value of <b>
push: 2 a
push <a> onto the stack
pop: 3 a
remove the top element from the stack and write it into <a>; empty stack = error
eq: 4 a b c
set <a> to 1 if <b> is equal to <c>; set it to 0 otherwise
gt: 5 a b c
set <a> to 1 if <b> is greater than <c>; set it to 0 otherwise
jmp: 6 a
jump to <a>
jt: 7 a b
if <a> is nonzero, jump to <b>
jf: 8 a b
if <a> is zero, jump to <b>
add: 9 a b c
assign into <a> the sum of <b> and <c> (modulo 32768)
mult: 10 a b c
store into <a> the product of <b> and <c> (modulo 32768)
mod: 11 a b c
store into <a> the remainder of <b> divided by <c>
and: 12 a b c
stores into <a> the bitwise and of <b> and <c>
or: 13 a b c
stores into <a> the bitwise or of <b> and <c>
not: 14 a b
stores 15-bit bitwise inverse of <b> in <a>
rmem: 15 a b
read memory at address <b> and write it to <a>
wmem: 16 a b
write the value from <b> into memory at address <a>
call: 17 a
write the address of the next instruction to the stack and jump to <a>
ret: 18
remove the top element from the stack and jump to it; empty stack = halt
out: 19 a
write the character represented by ascii code <a> to the terminal
in: 20 a
read a character from the terminal and write its ascii code to <a>; it can be assumed that once input starts, it will continue until a newline is encountered; this means that you can safely read whole lines from the keyboard and trust that they will be fully read
noop: 21
no operation

121
sim/example-synacor/aclocal.m4 vendored Normal file
View File

@ -0,0 +1,121 @@
# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
# AM_CONDITIONAL -*- Autoconf -*-
# Copyright (C) 1997-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
# -------------------------------------
# Define a conditional.
AC_DEFUN([AM_CONDITIONAL],
[AC_PREREQ([2.52])dnl
m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
AC_SUBST([$1_TRUE])dnl
AC_SUBST([$1_FALSE])dnl
_AM_SUBST_NOTMAKE([$1_TRUE])dnl
_AM_SUBST_NOTMAKE([$1_FALSE])dnl
m4_define([_AM_COND_VALUE_$1], [$2])dnl
if $2; then
$1_TRUE=
$1_FALSE='#'
else
$1_TRUE='#'
$1_FALSE=
fi
AC_CONFIG_COMMANDS_PRE(
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
AC_MSG_ERROR([[conditional "$1" was never defined.
Usually this means the macro was only invoked conditionally.]])
fi])])
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
# From Jim Meyering
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_MAINTAINER_MODE([DEFAULT-MODE])
# ----------------------------------
# Control maintainer-specific portions of Makefiles.
# Default is to disable them, unless 'enable' is passed literally.
# For symmetry, 'disable' may be passed as well. Anyway, the user
# can override the default with the --enable/--disable switch.
AC_DEFUN([AM_MAINTAINER_MODE],
[m4_case(m4_default([$1], [disable]),
[enable], [m4_define([am_maintainer_other], [disable])],
[disable], [m4_define([am_maintainer_other], [enable])],
[m4_define([am_maintainer_other], [enable])
m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
dnl maintainer-mode's default is 'disable' unless 'enable' is passed
AC_ARG_ENABLE([maintainer-mode],
[AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
am_maintainer_other[ make rules and dependencies not useful
(and sometimes confusing) to the casual installer])],
[USE_MAINTAINER_MODE=$enableval],
[USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
AC_MSG_RESULT([$USE_MAINTAINER_MODE])
AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
MAINT=$MAINTAINER_MODE_TRUE
AC_SUBST([MAINT])dnl
]
)
# Copyright (C) 2006-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# _AM_SUBST_NOTMAKE(VARIABLE)
# ---------------------------
# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
# This macro is traced by Automake.
AC_DEFUN([_AM_SUBST_NOTMAKE])
# AM_SUBST_NOTMAKE(VARIABLE)
# --------------------------
# Public sister of _AM_SUBST_NOTMAKE.
AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
m4_include([../m4/sim_ac_common.m4])
m4_include([../m4/sim_ac_option_alignment.m4])
m4_include([../m4/sim_ac_option_assert.m4])
m4_include([../m4/sim_ac_option_endian.m4])
m4_include([../m4/sim_ac_option_environment.m4])
m4_include([../m4/sim_ac_option_inline.m4])
m4_include([../m4/sim_ac_option_warnings.m4])
m4_include([../m4/sim_ac_output.m4])
m4_include([../m4/sim_ac_toolchain.m4])
m4_include([../../config/acx.m4])
m4_include([../../config/depstand.m4])
m4_include([../../config/gettext-sister.m4])
m4_include([../../config/lead-dot.m4])
m4_include([../../config/override.m4])
m4_include([../../config/plugins.m4])
m4_include([../../config/zlib.m4])
m4_include([../../libtool.m4])
m4_include([../../ltoptions.m4])
m4_include([../../ltsugar.m4])
m4_include([../../ltversion.m4])
m4_include([../../lt~obsolete.m4])

View File

@ -0,0 +1,242 @@
/* config.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
/* Sim debug setting */
#undef DEBUG
/* Define to 1 if translation of program messages to the user's native
language is requested. */
#undef ENABLE_NLS
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the <fpu_control.h> header file. */
#undef HAVE_FPU_CONTROL_H
/* Define to 1 if you have the `ftruncate' function. */
#undef HAVE_FTRUNCATE
/* Define to 1 if you have the `getrusage' function. */
#undef HAVE_GETRUSAGE
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `nsl' library (-lnsl). */
#undef HAVE_LIBNSL
/* Define to 1 if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET
/* Define to 1 if you have the `lstat' function. */
#undef HAVE_LSTAT
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mmap' function. */
#undef HAVE_MMAP
/* Define to 1 if you have the `munmap' function. */
#undef HAVE_MUNMAP
/* Define to 1 if you have the `posix_fallocate' function. */
#undef HAVE_POSIX_FALLOCATE
/* Define to 1 if you have the `sigaction' function. */
#undef HAVE_SIGACTION
/* Define to 1 if the system has the type `socklen_t'. */
#undef HAVE_SOCKLEN_T
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if `st_atime' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_ATIME
/* Define to 1 if `st_blksize' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_BLKSIZE
/* Define to 1 if `st_blocks' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_BLOCKS
/* Define to 1 if `st_ctime' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_CTIME
/* Define to 1 if `st_dev' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_DEV
/* Define to 1 if `st_gid' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_GID
/* Define to 1 if `st_ino' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_INO
/* Define to 1 if `st_mode' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MODE
/* Define to 1 if `st_mtime' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIME
/* Define to 1 if `st_nlink' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_NLINK
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_RDEV
/* Define to 1 if `st_size' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_SIZE
/* Define to 1 if `st_uid' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_UID
/* Define to 1 if you have the <sys/mman.h> header file. */
#undef HAVE_SYS_MMAN_H
/* Define to 1 if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/times.h> header file. */
#undef HAVE_SYS_TIMES_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the `time' function. */
#undef HAVE_TIME
/* Define to 1 if you have the `truncate' function. */
#undef HAVE_TRUNCATE
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the <windows.h> header file. */
#undef HAVE_WINDOWS_H
/* Define to 1 if you have the `__setfpucw' function. */
#undef HAVE___SETFPUCW
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Name of this package. */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Additional package description */
#undef PKGVERSION
/* Sim profile settings */
#undef PROFILE
/* Bug reporting address */
#undef REPORT_BUGS_TO
/* Define as the return type of signal handlers (`int' or `void'). */
#undef RETSIGTYPE
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Sim assert settings */
#undef WITH_ASSERT
/* Sim debug setting */
#undef WITH_DEBUG
/* Sim default environment */
#undef WITH_ENVIRONMENT
/* Sim profile settings */
#undef WITH_PROFILE
/* How to route I/O */
#undef WITH_STDIO
/* Sim trace settings */
#undef WITH_TRACE
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif
/* Define to 1 if on MINIX. */
#undef _MINIX
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
#undef _POSIX_1_SOURCE
/* Define to 1 if you need to in order for `stat' and other things to work. */
#undef _POSIX_SOURCE

14333
sim/example-synacor/configure vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(Makefile.in)
AC_CONFIG_MACRO_DIRS([../m4 ../.. ../../config])
SIM_AC_COMMON
SIM_AC_OPTION_ENDIAN(LITTLE)
SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT,STRICT_ALIGNMENT)
SIM_AC_OUTPUT

View File

@ -0,0 +1,176 @@
/* Example synacor simulator.
Copyright (C) 2005-2021 Free Software Foundation, Inc.
Contributed by Mike Frysinger.
This file is part of simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* This file contains the main glue logic between the sim core and the target
specific simulator. Normally this file will be kept small and the target
details will live in other files.
For more specific details on these functions, see the gdb/remote-sim.h
header file. */
#include "config.h"
#include "sim-main.h"
#include "sim-options.h"
/* This function is the main loop. It should process ticks and decode+execute
a single instruction.
Usually you do not need to change things here. */
void
sim_engine_run (SIM_DESC sd,
int next_cpu_nr, /* ignore */
int nr_cpus, /* ignore */
int siggnal) /* ignore */
{
SIM_CPU *cpu;
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
cpu = STATE_CPU (sd, 0);
while (1)
{
step_once (cpu);
if (sim_events_tick (sd))
sim_events_process (sd);
}
}
/* Initialize the simulator from scratch. This is called once per lifetime of
the simulation. Think of it as a processor reset.
Usually all cpu-specific setup is handled in the initialize_cpu callback.
If you want to do cpu-independent stuff, then it should go at the end (see
where memory is initialized). */
#define DEFAULT_MEM_SIZE (16 * 1024 * 1024)
static void
free_state (SIM_DESC sd)
{
if (STATE_MODULES (sd) != NULL)
sim_module_uninstall (sd);
sim_cpu_free_all (sd);
sim_state_free (sd);
}
SIM_DESC
sim_open (SIM_OPEN_KIND kind, host_callback *callback,
struct bfd *abfd, char * const *argv)
{
char c;
int i;
SIM_DESC sd = sim_state_alloc (kind, callback);
/* The cpu data is kept in a separately allocated chunk of memory. */
if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* XXX: Default to the Virtual environment. */
if (STATE_ENVIRONMENT (sd) == ALL_ENVIRONMENT)
STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT;
/* The parser will print an error message for us, so we silently return. */
if (sim_parse_args (sd, argv) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* Check for/establish the a reference program image. */
if (sim_analyze_program (sd,
(STATE_PROG_ARGV (sd) != NULL
? *STATE_PROG_ARGV (sd)
: NULL), abfd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* Establish any remaining configuration options. */
if (sim_config (sd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
if (sim_post_argv_init (sd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* CPU specific initialization. */
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
{
SIM_CPU *cpu = STATE_CPU (sd, i);
initialize_cpu (sd, cpu);
}
/* Allocate external memory if none specified by user.
Use address 4 here in case the user wanted address 0 unmapped. */
if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
sim_do_commandf (sd, "memory-size %#x", DEFAULT_MEM_SIZE);
return sd;
}
/* Prepare to run a program that has already been loaded into memory.
Usually you do not need to change things here. */
SIM_RC
sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
char * const *argv, char * const *env)
{
SIM_CPU *cpu = STATE_CPU (sd, 0);
sim_cia addr;
/* Set the PC. */
if (abfd != NULL)
addr = bfd_get_start_address (abfd);
else
addr = 0;
sim_pc_set (cpu, addr);
/* Standalone mode (i.e. `run`) will take care of the argv for us in
sim_open() -> sim_parse_args(). But in debug mode (i.e. 'target sim'
with `gdb`), we need to handle it because the user can change the
argv on the fly via gdb's 'run'. */
if (STATE_PROG_ARGV (sd) != argv)
{
freeargv (STATE_PROG_ARGV (sd));
STATE_PROG_ARGV (sd) = dupargv (argv);
}
return SIM_RC_OK;
}

View File

@ -0,0 +1,530 @@
/* Example synacor simulator.
Copyright (C) 2005-2021 Free Software Foundation, Inc.
Contributed by Mike Frysinger.
This file is part of simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* This file contains the main simulator decoding logic. i.e. everything that
is architecture specific. */
#include "config.h"
#include "sim-main.h"
/* Get the register number from the number. */
static unsigned16
register_num (SIM_CPU *cpu, unsigned16 num)
{
SIM_DESC sd = CPU_STATE (cpu);
if (num < 0x8000 || num >= 0x8008)
sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
return num & 0xf;
}
/* Helper to process immediates according to the ISA. */
static unsigned16
interp_num (SIM_CPU *cpu, unsigned16 num)
{
SIM_DESC sd = CPU_STATE (cpu);
if (num < 0x8000)
{
/* Numbers 0..32767 mean a literal value. */
TRACE_DECODE (cpu, "%#x is a literal", num);
return num;
}
else if (num < 0x8008)
{
/* Numbers 32768..32775 instead mean registers 0..7. */
TRACE_DECODE (cpu, "%#x is register R%i", num, num & 0xf);
return cpu->regs[num & 0xf];
}
else
{
/* Numbers 32776..65535 are invalid. */
TRACE_DECODE (cpu, "%#x is an invalid number", num);
sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
}
}
/* Decode & execute a single instruction. */
void step_once (SIM_CPU *cpu)
{
SIM_DESC sd = CPU_STATE (cpu);
unsigned16 iw1, num1;
sim_cia pc = sim_pc_get (cpu);
iw1 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc);
TRACE_EXTRACT (cpu, "%04x: iw1: %#x", pc, iw1);
/* This never happens, but technically is possible in the ISA. */
num1 = interp_num (cpu, iw1);
if (num1 == 0)
{
/* halt: 0: Stop execution and terminate the program. */
TRACE_INSN (cpu, "HALT");
sim_engine_halt (sd, cpu, NULL, pc, sim_exited, 0);
}
else if (num1 == 1)
{
/* set: 1 a b: Set register <a> to the value of <b>. */
unsigned16 iw2, iw3, num2, num3;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
TRACE_EXTRACT (cpu, "SET %#x %#x", iw2, iw3);
TRACE_INSN (cpu, "SET R%i %#x", num2, num3);
TRACE_REGISTER (cpu, "R%i = %#x", num2, num3);
cpu->regs[num2] = num3;
pc += 6;
}
else if (num1 == 2)
{
/* push: 2 a: Push <a> onto the stack. */
unsigned16 iw2, num2;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = interp_num (cpu, iw2);
TRACE_EXTRACT (cpu, "PUSH %#x", iw2);
TRACE_INSN (cpu, "PUSH %#x", num2);
sim_core_write_aligned_2 (cpu, pc, write_map, cpu->sp, num2);
cpu->sp -= 2;
TRACE_REGISTER (cpu, "SP = %#x", cpu->sp);
pc += 4;
}
else if (num1 == 3)
{
/* pop: 3 a: Remove the top element from the stack and write it into <a>.
Empty stack = error. */
unsigned16 iw2, num2, result;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
TRACE_EXTRACT (cpu, "POP %#x", iw2);
TRACE_INSN (cpu, "POP R%i", num2);
cpu->sp += 2;
TRACE_REGISTER (cpu, "SP = %#x", cpu->sp);
result = sim_core_read_aligned_2 (cpu, pc, read_map, cpu->sp);
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
cpu->regs[num2] = result;
pc += 4;
}
else if (num1 == 4)
{
/* eq: 4 a b c: Set <a> to 1 if <b> is equal to <c>; set it to 0
otherwise. */
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
num4 = interp_num (cpu, iw4);
result = (num3 == num4);
TRACE_EXTRACT (cpu, "EQ %#x %#x %#x", iw2, iw3, iw4);
TRACE_INSN (cpu, "EQ R%i %#x %#x", num2, num3, num4);
TRACE_DECODE (cpu, "R%i = (%#x == %#x) = %i", num2, num3, num4, result);
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
cpu->regs[num2] = result;
pc += 8;
}
else if (num1 == 5)
{
/* gt: 5 a b c: Set <a> to 1 if <b> is greater than <c>; set it to 0
otherwise. */
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
num4 = interp_num (cpu, iw4);
result = (num3 > num4);
TRACE_EXTRACT (cpu, "GT %#x %#x %#x", iw2, iw3, iw4);
TRACE_INSN (cpu, "GT R%i %#x %#x", num2, num3, num4);
TRACE_DECODE (cpu, "R%i = (%#x > %#x) = %i", num2, num3, num4, result);
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
cpu->regs[num2] = result;
pc += 8;
}
else if (num1 == 6)
{
/* jmp: 6 a: Jump to <a>. */
unsigned16 iw2, num2;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = interp_num (cpu, iw2);
/* Addresses are 16-bit aligned. */
num2 <<= 1;
TRACE_EXTRACT (cpu, "JMP %#x", iw2);
TRACE_INSN (cpu, "JMP %#x", num2);
pc = num2;
TRACE_BRANCH (cpu, "JMP %#x", pc);
}
else if (num1 == 7)
{
/* jt: 7 a b: If <a> is nonzero, jump to <b>. */
unsigned16 iw2, iw3, num2, num3;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = interp_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
/* Addresses are 16-bit aligned. */
num3 <<= 1;
TRACE_EXTRACT (cpu, "JT %#x %#x", iw2, iw3);
TRACE_INSN (cpu, "JT %#x %#x", num2, num3);
TRACE_DECODE (cpu, "JT %#x != 0 -> %s", num2, num2 ? "taken" : "nop");
if (num2)
{
pc = num3;
TRACE_BRANCH (cpu, "JT %#x", pc);
}
else
pc += 6;
}
else if (num1 == 8)
{
/* jf: 8 a b: If <a> is zero, jump to <b>. */
unsigned16 iw2, iw3, num2, num3;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = interp_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
/* Addresses are 16-bit aligned. */
num3 <<= 1;
TRACE_EXTRACT (cpu, "JF %#x %#x", iw2, iw3);
TRACE_INSN (cpu, "JF %#x %#x", num2, num3);
TRACE_DECODE (cpu, "JF %#x == 0 -> %s", num2, num2 ? "nop" : "taken");
if (!num2)
{
pc = num3;
TRACE_BRANCH (cpu, "JF %#x", pc);
}
else
pc += 6;
}
else if (num1 == 9)
{
/* add: 9 a b c: Assign <a> the sum of <b> and <c> (modulo 32768). */
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
num4 = interp_num (cpu, iw4);
result = (num3 + num4) % 32768;
TRACE_EXTRACT (cpu, "ADD %#x %#x %#x", iw2, iw3, iw4);
TRACE_INSN (cpu, "ADD R%i %#x %#x", num2, num3, num4);
TRACE_DECODE (cpu, "R%i = (%#x + %#x) %% %i = %#x", num2, num3, num4,
32768, result);
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
cpu->regs[num2] = result;
pc += 8;
}
else if (num1 == 10)
{
/* mult: 10 a b c: Store into <a> the product of <b> and <c> (modulo
32768). */
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
num4 = interp_num (cpu, iw4);
result = (num3 * num4) % 32768;
TRACE_EXTRACT (cpu, "MULT %#x %#x %#x", iw2, iw3, iw4);
TRACE_INSN (cpu, "MULT R%i %#x %#x", num2, num3, num4);
TRACE_DECODE (cpu, "R%i = (%#x * %#x) %% %i = %#x", num2, num3, num4,
32768, result);
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
cpu->regs[num2] = result;
pc += 8;
}
else if (num1 == 11)
{
/* mod: 11 a b c: Store into <a> the remainder of <b> divided by <c>. */
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
num4 = interp_num (cpu, iw4);
result = num3 % num4;
TRACE_EXTRACT (cpu, "MOD %#x %#x %#x", iw2, iw3, iw4);
TRACE_INSN (cpu, "MOD R%i %#x %#x", num2, num3, num4);
TRACE_DECODE (cpu, "R%i = %#x %% %#x = %#x", num2, num3, num4, result);
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
cpu->regs[num2] = result;
pc += 8;
}
else if (num1 == 12)
{
/* and: 12 a b c: Stores into <a> the bitwise and of <b> and <c>. */
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
num4 = interp_num (cpu, iw4);
result = (num3 & num4);
TRACE_EXTRACT (cpu, "AND %#x %#x %#x", iw2, iw3, iw4);
TRACE_INSN (cpu, "AND R%i %#x %#x", num2, num3, num4);
TRACE_DECODE (cpu, "R%i = %#x & %#x = %#x", num2, num3, num4, result);
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
cpu->regs[num2] = result;
pc += 8;
}
else if (num1 == 13)
{
/* or: 13 a b c: Stores into <a> the bitwise or of <b> and <c>. */
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
num4 = interp_num (cpu, iw4);
result = (num3 | num4);
TRACE_EXTRACT (cpu, "OR %#x %#x %#x", iw2, iw3, iw4);
TRACE_INSN (cpu, "OR R%i %#x %#x", num2, num3, num4);
TRACE_DECODE (cpu, "R%i = %#x | %#x = %#x", num2, num3, num4, result);
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
cpu->regs[num2] = result;
pc += 8;
}
else if (num1 == 14)
{
/* not: 14 a b: Stores 15-bit bitwise inverse of <b> in <a>. */
unsigned16 iw2, iw3, num2, num3, result;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
result = (~num3) & 0x7fff;
TRACE_EXTRACT (cpu, "NOT %#x %#x", iw2, iw3);
TRACE_INSN (cpu, "NOT R%i %#x", num2, num3);
TRACE_DECODE (cpu, "R%i = (~%#x) & 0x7fff = %#x", num2, num3, result);
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
cpu->regs[num2] = result;
pc += 6;
}
else if (num1 == 15)
{
/* rmem: 15 a b: Read memory at address <b> and write it to <a>. */
unsigned16 iw2, iw3, num2, num3, result;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
/* Addresses are 16-bit aligned. */
num3 <<= 1;
TRACE_EXTRACT (cpu, "RMEM %#x %#x", iw2, iw3);
TRACE_INSN (cpu, "RMEM R%i %#x", num2, num3);
TRACE_MEMORY (cpu, "reading %#x", num3);
result = sim_core_read_aligned_2 (cpu, pc, read_map, num3);
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
cpu->regs[num2] = result;
pc += 6;
}
else if (num1 == 16)
{
/* wmem: 16 a b: Write the value from <b> into memory at address <a>. */
unsigned16 iw2, iw3, num2, num3;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = interp_num (cpu, iw2);
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
num3 = interp_num (cpu, iw3);
/* Addresses are 16-bit aligned. */
num2 <<= 1;
TRACE_EXTRACT (cpu, "WMEM %#x %#x", iw2, iw3);
TRACE_INSN (cpu, "WMEM %#x %#x", num2, num3);
TRACE_MEMORY (cpu, "writing %#x to %#x", num3, num2);
sim_core_write_aligned_2 (cpu, pc, write_map, num2, num3);
pc += 6;
}
else if (num1 == 17)
{
/* call: 17 a: Write the address of the next instruction to the stack and
jump to <a>. */
unsigned16 iw2, num2;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = interp_num (cpu, iw2);
/* Addresses are 16-bit aligned. */
num2 <<= 1;
TRACE_EXTRACT (cpu, "CALL %#x", iw2);
TRACE_INSN (cpu, "CALL %#x", num2);
TRACE_MEMORY (cpu, "pushing %#x onto stack", (pc + 4) >> 1);
sim_core_write_aligned_2 (cpu, pc, write_map, cpu->sp, (pc + 4) >> 1);
cpu->sp -= 2;
TRACE_REGISTER (cpu, "SP = %#x", cpu->sp);
pc = num2;
TRACE_BRANCH (cpu, "CALL %#x", pc);
}
else if (num1 == 18)
{
/* ret: 18: Remove the top element from the stack and jump to it; empty
stack = halt. */
unsigned16 result;
TRACE_INSN (cpu, "RET");
cpu->sp += 2;
TRACE_REGISTER (cpu, "SP = %#x", cpu->sp);
result = sim_core_read_aligned_2 (cpu, pc, read_map, cpu->sp);
TRACE_MEMORY (cpu, "popping %#x off of stack", result << 1);
pc = result << 1;
TRACE_BRANCH (cpu, "RET -> %#x", pc);
}
else if (num1 == 19)
{
/* out: 19 a: Write the character <a> to the terminal. */
unsigned16 iw2, num2;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = interp_num (cpu, iw2);
TRACE_EXTRACT (cpu, "OUT %#x", iw2);
TRACE_INSN (cpu, "OUT %#x", num2);
TRACE_EVENTS (cpu, "write to stdout: %#x (%c)", num2, num2);
sim_io_printf (sd, "%c", num2);
pc += 4;
}
else if (num1 == 20)
{
/* in: 20 a: read a character from the terminal and write its ascii code
to <a>. It can be assumed that once input starts, it will continue
until a newline is encountered. This means that you can safely read
lines from the keyboard and trust that they will be fully read. */
unsigned16 iw2, num2;
char c;
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
num2 = register_num (cpu, iw2);
TRACE_EXTRACT (cpu, "IN %#x", iw2);
TRACE_INSN (cpu, "IN %#x", num2);
sim_io_read_stdin (sd, &c, 1);
TRACE_EVENTS (cpu, "read from stdin: %#x (%c)", c, c);
/* The challenge uses lowercase for all inputs, so insert some low level
helpers of our own to make it a bit nicer. */
switch (c)
{
case 'Q':
sim_engine_halt (sd, cpu, NULL, pc, sim_exited, 0);
break;
}
TRACE_REGISTER (cpu, "R%i = %#x", iw2 & 0xf, c);
cpu->regs[iw2 & 0xf] = c;
pc += 4;
}
else if (num1 == 21)
{
/* noop: 21: no operation */
TRACE_INSN (cpu, "NOOP");
pc += 2;
}
else
sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL);
TRACE_REGISTER (cpu, "PC = %#x", pc);
sim_pc_set (cpu, pc);
}
/* Return the program counter for this cpu. */
static sim_cia
pc_get (sim_cpu *cpu)
{
return cpu->pc;
}
/* Set the program counter for this cpu to the new pc value. */
static void
pc_set (sim_cpu *cpu, sim_cia pc)
{
cpu->pc = pc;
}
/* Initialize the state for a single cpu. Usuaully this involves clearing all
registers back to their reset state. Should also hook up the fetch/store
helper functions too. */
void initialize_cpu (SIM_DESC sd, SIM_CPU *cpu)
{
memset (cpu->regs, 0, sizeof (cpu->regs));
cpu->pc = 0;
/* Make sure it's initialized outside of the 16-bit address space. */
cpu->sp = 0x80000;
CPU_PC_FETCH (cpu) = pc_get;
CPU_PC_STORE (cpu) = pc_set;
}

View File

@ -0,0 +1,49 @@
/* Example synacor simulator.
Copyright (C) 2005-2021 Free Software Foundation, Inc.
Contributed by Mike Frysinger.
This file is part of simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef SIM_MAIN_H
#define SIM_MAIN_H
#include "sim-basics.h"
#include "sim-base.h"
struct _sim_cpu {
/* ... simulator specific members ... */
unsigned16 regs[8];
sim_cia pc;
/* This isn't a real register, and the stack is not directly addressable,
so use memory outside of the 16-bit address space. */
unsigned32 sp;
sim_cpu_base base;
};
struct sim_state {
sim_cpu *cpu[MAX_NR_PROCESSORS];
/* ... simulator specific members ... */
sim_state_base base;
};
extern void step_once (SIM_CPU *);
extern void initialize_cpu (SIM_DESC, SIM_CPU *);
#endif

View File

@ -1,3 +1,7 @@
2021-04-03 Mike Frysinger <vapier@gentoo.org>
* lib/sim-defs.exp (run_sim_test): Convert examples to binaries.
2021-04-03 Mike Frysinger <vapier@gentoo.org>
* local.mk: Include %D%/common/local.mk.

View File

@ -0,0 +1,5 @@
2021-04-03 Mike Frysinger <vapier@gentoo.org>
* add.s, allinsn.exp, and.s, call.s, exit-0.s, gt.s, isa.inc, jmp.s,
mem.s, mod.s, mult.s, not.s, or.s, push-pop.s, ret.s, set.s,
testutils.inc: New files.

View File

@ -0,0 +1,24 @@
# check the ADD insn.
# mach: example
.include "testutils.inc"
start
JMP 3
HALT
SET r2, 2
ADD r2, r2, r2
EQ r3, r2, 4
JF r3, 2
ADD r1, 100, r2
EQ r4, r1, 104
JF r4, 2
# 0x7ffe == -2
ADD r0, r1, 0x7ffe
EQ r4, r0, 102
JF r4, 2
pass

View File

@ -0,0 +1,19 @@
# Example synacor simulator testsuite.
if [istarget *] {
# Used to locate the `run` program.
global arch
set arch "example-synacor"
# All machines.
set all_machs "example"
foreach src [lsort [glob -nocomplain $srcdir/$subdir/*.s]] {
# If we're only testing specific files and this isn't one of them,
# skip it.
if ![runtest_file_p $runtests $src] {
continue
}
run_sim_test $src $all_machs
}
}

View File

@ -0,0 +1,18 @@
# check the AND insn.
# mach: example
.include "testutils.inc"
start
JMP 3
HALT
AND r2, 0xfff, 0x7f0c
EQ r3, r2, 0xf0c
JF r3, 2
AND r2, r2, 0xf
EQ r3, r2, 0xc
JF r3, 2
pass

View File

@ -0,0 +1,14 @@
# check the CALL insn.
# mach: example
.include "testutils.inc"
start
CALL 3
HALT
POP r0
EQ r1, r0, 2
JF r1, 2
pass

View File

@ -0,0 +1,10 @@
# check that the sim doesn't die immediately.
# mach: example
.include "testutils.inc"
start
NOOP
NOOP
NOOP
pass

View File

@ -0,0 +1,31 @@
# check the GT insn.
# mach: example
.include "testutils.inc"
start
JMP 3
HALT
GT r0, 3, 2
EQ r1, r0, 1
JF r1, 2
GT r0, 2, 2
EQ r1, r0, 0
JF r1, 2
GT r0, 1, 2
EQ r1, r0, 0
JF r1, 2
SET r2, 3
SET r3, 4
GT r0, r2, r3
EQ r1, r0, 0
JF r1, 2
GT r0, r3, r2
EQ r1, r0, 1
JF r1, 2
pass

View File

@ -0,0 +1,108 @@
# Macros for the fake ISA. Keep in sync with example-synacor/README.arch-spec.
# These .set macros will generate symbols in the output ELF, but it also allows
# use to use them as arguments to the insns below. Oh well.
.set r0, 32768
.set r1, r0+1
.set r2, r0+2
.set r3, r0+3
.set r4, r0+4
.set r5, r0+5
.set r6, r0+6
.set r7, r0+7
# The target is little endian, so make sure we output the 16-bit words as such.
.macro _op op:req, more:vararg
.byte \op & 0xff, (\op >> 8) & 0xff
.ifnb \more
_op \more
.endif
.endm
.macro HALT
_op 0
.endm
.macro SET a:req, b:req
_op 1, \a, \b
.endm
.macro PUSH a:req
_op 2, \a
.endm
.macro POP a:req
_op 3, \a
.endm
.macro EQ a:req, b:req, c:req
_op 4, \a, \b, \c
.endm
.macro GT a:req, b:req, c:req
_op 5, \a, \b, \c
.endm
.macro JMP a:req
_op 6, \a
.endm
.macro JT a:req, b:req
_op 7, \a, \b
.endm
.macro JF a:req, b:req
_op 8, \a, \b
.endm
.macro ADD a:req, b:req, c:req
_op 9, \a, \b, \c
.endm
.macro MULT a:req, b:req, c:req
_op 10, \a, \b, \c
.endm
.macro MOD a:req, b:req, c:req
_op 11, \a, \b, \c
.endm
.macro AND a:req, b:req, c:req
_op 12, \a, \b, \c
.endm
.macro OR a:req, b:req, c:req
_op 13, \a, \b, \c
.endm
.macro NOT a:req, b:req
_op 14, \a, \b
.endm
.macro RMEM a:req, b:req
_op 15, \a, \b
.endm
.macro WMEM a:req, b:req
_op 16, \a, \b
.endm
.macro CALL a:req
_op 17, \a
.endm
.macro RET
_op 18
.endm
.macro OUT a:req
_op 19, \a
.endm
.macro IN a:req
_op 20, \a
.endm
.macro NOOP
_op 21
.endm

View File

@ -0,0 +1,9 @@
# check the JMP insn.
# mach: example
.include "testutils.inc"
start
JMP 3
HALT
pass

View File

@ -0,0 +1,25 @@
# check the RMEM & WMEM insns.
# mach: example
.include "testutils.inc"
start
JMP 14
HALT
pass
# Read a constant address.
RMEM r0, 1
EQ r1, r0, 14
JF r1, 2
# Change the first JMP to skip HALT and hit the pass.
WMEM 1, 3
# Read an address in a register.
SET r2, 1
RMEM r0, r2
EQ r1, r0, 3
JF r1, 2
JMP 0

View File

@ -0,0 +1,18 @@
# check the MOD insn.
# mach: example
.include "testutils.inc"
start
JMP 3
HALT
MOD r0, 8, 3
EQ r1, r0, 2
JF r1, 2
MOD r0, r0, 2
EQ r1, r0, 0
JF r1, 2
pass

View File

@ -0,0 +1,18 @@
# check the MULT insn.
# mach: example
.include "testutils.inc"
start
JMP 3
HALT
MULT r0, 3, 2
EQ r1, r0, 6
JF r1, 2
MULT r0, r0, 8
EQ r1, r0, 48
JF r1, 2
pass

View File

@ -0,0 +1,15 @@
# check the NOT insn.
# mach: example
.include "testutils.inc"
start
JMP 3
HALT
SET r2, 0xc
NOT r0, r2
EQ r3, r0, 0x7ff3
JF r3, 2
pass

View File

@ -0,0 +1,18 @@
# check the OR insn.
# mach: example
.include "testutils.inc"
start
JMP 3
HALT
OR r2, 0xf, 0x80
EQ r3, r2, 0x8f
JF r3, 2
OR r2, r2, 0xff
EQ r3, r2, 0xff
JF r3, 2
pass

View File

@ -0,0 +1,22 @@
# check the PUSH & POP insns.
# mach: example
.include "testutils.inc"
start
JMP 3
HALT
PUSH 1
SET r0, 3
PUSH r0
POP r1
POP r2
EQ r7, r0, 3
JF r7, 2
EQ r7, r1, 3
JF r7, 2
EQ r7, r2, 1
JF r7, 2
pass

View File

@ -0,0 +1,13 @@
# check the RET insn.
# mach: example
.include "testutils.inc"
start
JMP 13
pass
SET r5, 2
PUSH r5
RET
HALT

View File

@ -0,0 +1,20 @@
# check the SET insn.
# mach: example
.include "testutils.inc"
start
JMP 3
HALT
SET r2, 2
EQ r3, r2, 2
JF r3, 2
SET r1, 1
EQ r3, r1, 1
JF r3, 2
SET r0, r2
EQ r3, r0, 2
JF r3, 2
pass

View File

@ -0,0 +1,31 @@
.include "isa.inc"
# MACRO: pass
# Write 'pass' to stdout and quit
.macro pass
OUT 'p'
OUT 'a'
OUT 's'
OUT 's'
OUT '\n'
HALT
.endm
# MACRO: fail
# Write 'fail' to stdout and quit
.macro fail
OUT 'f'
OUT 'a'
OUT 'i'
OUT 'l'
OUT '\n'
HALT
.endm
# MACRO: start
# All assembler tests should start with a call to "start"
.macro start
.text
.global _start
_start:
.endm

View File

@ -378,6 +378,13 @@ proc run_sim_test { name requested_machs } {
set options "$options timeout=$opts(timeout)"
}
if [string match "example" "$mach"] {
set objcopy [find_binutils_prog objcopy]
set comp_output [remote_exec host $objcopy "-O binary -j .text ${name}.x ${name}.bin"]
file rename -force "${name}.bin" "${name}.x"
append opts(sim,$mach) " --target binary"
}
set result [sim_run ${name}.x "$opts(sim,$mach) $global_sim_options" "$opts(progopts)" "" "$options"]
set return_code [lindex $result 0]
set output [lindex $result 1]