forked from Imagelibrary/binutils-gdb
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:
5
sim/example-synacor/ChangeLog
Normal file
5
sim/example-synacor/ChangeLog
Normal 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.
|
||||
26
sim/example-synacor/Makefile.in
Normal file
26
sim/example-synacor/Makefile.in
Normal 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
|
||||
15
sim/example-synacor/README
Normal file
15
sim/example-synacor/README
Normal 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.
|
||||
73
sim/example-synacor/README.arch-spec
Normal file
73
sim/example-synacor/README.arch-spec
Normal 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
121
sim/example-synacor/aclocal.m4
vendored
Normal 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])
|
||||
242
sim/example-synacor/config.in
Normal file
242
sim/example-synacor/config.in
Normal 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
14333
sim/example-synacor/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
10
sim/example-synacor/configure.ac
Normal file
10
sim/example-synacor/configure.ac
Normal 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
|
||||
176
sim/example-synacor/interp.c
Normal file
176
sim/example-synacor/interp.c
Normal 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;
|
||||
}
|
||||
530
sim/example-synacor/sim-main.c
Normal file
530
sim/example-synacor/sim-main.c
Normal 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;
|
||||
}
|
||||
49
sim/example-synacor/sim-main.h
Normal file
49
sim/example-synacor/sim-main.h
Normal 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
|
||||
Reference in New Issue
Block a user