From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp.gentoo.org (dev.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) by sourceware.org (Postfix) with ESMTP id 76F3D388A425 for ; Tue, 19 Jan 2021 04:05:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 76F3D388A425 Received: from vapier.lan (localhost [127.0.0.1]) by smtp.gentoo.org (Postfix) with ESMTP id 2BB67340C76 for ; Tue, 19 Jan 2021 04:05:57 +0000 (UTC) From: Mike Frysinger To: gdb-patches@sourceware.org Subject: [PATCH v2] sim: example-synacor: a simple implementation for reference Date: Mon, 18 Jan 2021 23:05:55 -0500 Message-Id: <20210119040555.7487-1-vapier@gentoo.org> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20210103072446.10840-1-vapier@gentoo.org> References: <20210103072446.10840-1-vapier@gentoo.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-10.7 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, RCVD_IN_DNSWL_NONE, SCC_10_SHORT_WORD_LINES, SCC_5_SHORT_WORD_LINES, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 19 Jan 2021 04:06:03 -0000 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. --- sim/ChangeLog | 5 + sim/configure | 15 +- sim/configure.ac | 7 + sim/example-synacor/ChangeLog | 5 + sim/example-synacor/Makefile.in | 26 + sim/example-synacor/README | 15 + sim/example-synacor/README.arch-spec | 73 + sim/example-synacor/aclocal.m4 | 119 + sim/example-synacor/config.in | 242 + sim/example-synacor/configure | 16029 ++++++++++++++++++ sim/example-synacor/configure.ac | 10 + sim/example-synacor/interp.c | 178 + sim/example-synacor/sim-main.c | 530 + sim/example-synacor/sim-main.h | 49 + sim/testsuite/example-synacor/ChangeLog | 5 + sim/testsuite/example-synacor/add.s | 24 + sim/testsuite/example-synacor/allinsn.exp | 15 + sim/testsuite/example-synacor/and.s | 18 + sim/testsuite/example-synacor/call.s | 14 + sim/testsuite/example-synacor/exit-0.s | 10 + sim/testsuite/example-synacor/gt.s | 31 + sim/testsuite/example-synacor/isa.inc | 108 + sim/testsuite/example-synacor/jmp.s | 9 + sim/testsuite/example-synacor/mem.s | 25 + sim/testsuite/example-synacor/mod.s | 18 + sim/testsuite/example-synacor/mult.s | 18 + sim/testsuite/example-synacor/not.s | 15 + sim/testsuite/example-synacor/or.s | 18 + sim/testsuite/example-synacor/push-pop.s | 22 + sim/testsuite/example-synacor/ret.s | 13 + sim/testsuite/example-synacor/set.s | 20 + sim/testsuite/example-synacor/testutils.inc | 31 + sim/testsuite/lib/sim-defs.exp | 7 + 33 files changed, 17723 insertions(+), 1 deletion(-) create mode 100644 sim/example-synacor/ChangeLog create mode 100644 sim/example-synacor/Makefile.in create mode 100644 sim/example-synacor/README create mode 100644 sim/example-synacor/README.arch-spec create mode 100644 sim/example-synacor/aclocal.m4 create mode 100644 sim/example-synacor/config.in create mode 100755 sim/example-synacor/configure create mode 100644 sim/example-synacor/configure.ac create mode 100644 sim/example-synacor/interp.c create mode 100644 sim/example-synacor/sim-main.c create mode 100644 sim/example-synacor/sim-main.h create mode 100644 sim/testsuite/example-synacor/ChangeLog create mode 100644 sim/testsuite/example-synacor/add.s create mode 100644 sim/testsuite/example-synacor/allinsn.exp create mode 100644 sim/testsuite/example-synacor/and.s create mode 100644 sim/testsuite/example-synacor/call.s create mode 100644 sim/testsuite/example-synacor/exit-0.s create mode 100644 sim/testsuite/example-synacor/gt.s create mode 100644 sim/testsuite/example-synacor/isa.inc create mode 100644 sim/testsuite/example-synacor/jmp.s create mode 100644 sim/testsuite/example-synacor/mem.s create mode 100644 sim/testsuite/example-synacor/mod.s create mode 100644 sim/testsuite/example-synacor/mult.s create mode 100644 sim/testsuite/example-synacor/not.s create mode 100644 sim/testsuite/example-synacor/or.s create mode 100644 sim/testsuite/example-synacor/push-pop.s create mode 100644 sim/testsuite/example-synacor/ret.s create mode 100644 sim/testsuite/example-synacor/set.s create mode 100644 sim/testsuite/example-synacor/testutils.inc diff --git a/sim/ChangeLog b/sim/ChangeLog index 7b83115d9c5c..bd85fc1c2a64 100644 --- a/sim/ChangeLog +++ b/sim/ChangeLog @@ -1,3 +1,8 @@ +2021-01-03 Mike Frysinger + + * configure.ac: Add --example-sims option. + * configure: Regenerate. + 2021-01-18 Mike Frysinger * configure.ac: Call AC_PROG_CPP. diff --git a/sim/configure.ac b/sim/configure.ac index 99364cac7f4e..cb9c1c9f69ab 100644 --- a/sim/configure.ac +++ b/sim/configure.ac @@ -49,5 +49,12 @@ if test "${enable_sim}" != no; then fi fi +AC_ARG_ENABLE([example-sims], + [AC_HELP_STRING([--enable-example-sims], + [enable example GNU simulators])]) +if test "x${enable_example_sims}" = xyes; then + AC_CONFIG_SUBDIRS(example-synacor) +fi + AC_CONFIG_FILES([Makefile testsuite/Makefile]) AC_OUTPUT diff --git a/sim/example-synacor/ChangeLog b/sim/example-synacor/ChangeLog new file mode 100644 index 000000000000..f4eb00116888 --- /dev/null +++ b/sim/example-synacor/ChangeLog @@ -0,0 +1,5 @@ +2021-01-03 Mike Frysinger + + * 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. diff --git a/sim/example-synacor/Makefile.in b/sim/example-synacor/Makefile.in new file mode 100644 index 000000000000..edd77ac801e8 diff --git a/sim/example-synacor/README b/sim/example-synacor/README new file mode 100644 index 000000000000..93ffd53d5a49 --- /dev/null +++ b/sim/example-synacor/README @@ -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. diff --git a/sim/example-synacor/README.arch-spec b/sim/example-synacor/README.arch-spec new file mode 100644 index 000000000000..da2d9d003670 --- /dev/null +++ b/sim/example-synacor/README.arch-spec @@ -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 to the value of +push: 2 a + push onto the stack +pop: 3 a + remove the top element from the stack and write it into ; empty stack = error +eq: 4 a b c + set to 1 if is equal to ; set it to 0 otherwise +gt: 5 a b c + set to 1 if is greater than ; set it to 0 otherwise +jmp: 6 a + jump to +jt: 7 a b + if is nonzero, jump to +jf: 8 a b + if is zero, jump to +add: 9 a b c + assign into the sum of and (modulo 32768) +mult: 10 a b c + store into the product of and (modulo 32768) +mod: 11 a b c + store into the remainder of divided by +and: 12 a b c + stores into the bitwise and of and +or: 13 a b c + stores into the bitwise or of and +not: 14 a b + stores 15-bit bitwise inverse of in +rmem: 15 a b + read memory at address and write it to +wmem: 16 a b + write the value from into memory at address +call: 17 a + write the address of the next instruction to the stack and jump to +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 to the terminal +in: 20 a + read a character from the terminal and write its ascii code to ; 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 diff --git a/sim/example-synacor/aclocal.m4 b/sim/example-synacor/aclocal.m4 new file mode 100644 index 000000000000..e9f11c775c31 diff --git a/sim/example-synacor/config.in b/sim/example-synacor/config.in new file mode 100644 index 000000000000..cb5ea1b01c95 diff --git a/sim/example-synacor/configure b/sim/example-synacor/configure new file mode 100755 index 000000000000..b8b0b4fa349b diff --git a/sim/example-synacor/configure.ac b/sim/example-synacor/configure.ac new file mode 100644 index 000000000000..ccb2ba8d7308 --- /dev/null +++ b/sim/example-synacor/configure.ac @@ -0,0 +1,10 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(Makefile.in) +sinclude(../common/acinclude.m4) + +SIM_AC_COMMON + +SIM_AC_OPTION_ENDIAN(LITTLE) +SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT,STRICT_ALIGNMENT) + +SIM_AC_OUTPUT diff --git a/sim/example-synacor/interp.c b/sim/example-synacor/interp.c new file mode 100644 index 000000000000..7b831101f809 --- /dev/null +++ b/sim/example-synacor/interp.c @@ -0,0 +1,178 @@ +/* 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 . */ + +/* 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; + + /* getopt will print the error message so we just have to exit if this fails. + FIXME: Hmmm... in the case of gdb we need getopt to call + print_filtered. */ + 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; +} diff --git a/sim/example-synacor/sim-main.c b/sim/example-synacor/sim-main.c new file mode 100644 index 000000000000..a7d748f3022c --- /dev/null +++ b/sim/example-synacor/sim-main.c @@ -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 . */ + +/* 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 to the value of . */ + 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 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 . + 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 to 1 if is equal to ; 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 to 1 if is greater than ; 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 . */ + 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 is nonzero, jump to . */ + 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 is zero, jump to . */ + 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 the sum of and (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 the product of and (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 the remainder of divided by . */ + 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 the bitwise and of and . */ + 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 the bitwise or of and . */ + 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 in . */ + 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 and write it to . */ + 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 into memory at address . */ + 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 . */ + 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 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 . 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; +} diff --git a/sim/example-synacor/sim-main.h b/sim/example-synacor/sim-main.h new file mode 100644 index 000000000000..ba0e4efa12a9 --- /dev/null +++ b/sim/example-synacor/sim-main.h @@ -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 . */ + +#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 diff --git a/sim/testsuite/example-synacor/ChangeLog b/sim/testsuite/example-synacor/ChangeLog new file mode 100644 index 000000000000..58295bb38fa0 --- /dev/null +++ b/sim/testsuite/example-synacor/ChangeLog @@ -0,0 +1,5 @@ +2021-01-13 Mike Frysinger + + * 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. diff --git a/sim/testsuite/example-synacor/add.s b/sim/testsuite/example-synacor/add.s new file mode 100644 index 000000000000..64a8c20d8edc --- /dev/null +++ b/sim/testsuite/example-synacor/add.s @@ -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 diff --git a/sim/testsuite/example-synacor/allinsn.exp b/sim/testsuite/example-synacor/allinsn.exp new file mode 100644 index 000000000000..a73312b8adfb --- /dev/null +++ b/sim/testsuite/example-synacor/allinsn.exp @@ -0,0 +1,15 @@ +# Example synacor simulator testsuite. + +if [istarget *] { + # 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 + } +} diff --git a/sim/testsuite/example-synacor/and.s b/sim/testsuite/example-synacor/and.s new file mode 100644 index 000000000000..1d1885985590 --- /dev/null +++ b/sim/testsuite/example-synacor/and.s @@ -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 diff --git a/sim/testsuite/example-synacor/call.s b/sim/testsuite/example-synacor/call.s new file mode 100644 index 000000000000..6d7b545a14bc --- /dev/null +++ b/sim/testsuite/example-synacor/call.s @@ -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 diff --git a/sim/testsuite/example-synacor/exit-0.s b/sim/testsuite/example-synacor/exit-0.s new file mode 100644 index 000000000000..2c1fb72f5d7c --- /dev/null +++ b/sim/testsuite/example-synacor/exit-0.s @@ -0,0 +1,10 @@ +# check that the sim doesn't die immediately. +# mach: example + +.include "testutils.inc" + + start + NOOP + NOOP + NOOP + pass diff --git a/sim/testsuite/example-synacor/gt.s b/sim/testsuite/example-synacor/gt.s new file mode 100644 index 000000000000..aef28e34404c --- /dev/null +++ b/sim/testsuite/example-synacor/gt.s @@ -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 diff --git a/sim/testsuite/example-synacor/isa.inc b/sim/testsuite/example-synacor/isa.inc new file mode 100644 index 000000000000..e2e1136ecfb7 --- /dev/null +++ b/sim/testsuite/example-synacor/isa.inc @@ -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 diff --git a/sim/testsuite/example-synacor/jmp.s b/sim/testsuite/example-synacor/jmp.s new file mode 100644 index 000000000000..dcacf668adc4 --- /dev/null +++ b/sim/testsuite/example-synacor/jmp.s @@ -0,0 +1,9 @@ +# check the JMP insn. +# mach: example + +.include "testutils.inc" + + start + JMP 3 + HALT + pass diff --git a/sim/testsuite/example-synacor/mem.s b/sim/testsuite/example-synacor/mem.s new file mode 100644 index 000000000000..24aa0a9e6fc6 --- /dev/null +++ b/sim/testsuite/example-synacor/mem.s @@ -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 diff --git a/sim/testsuite/example-synacor/mod.s b/sim/testsuite/example-synacor/mod.s new file mode 100644 index 000000000000..f0b4217574c5 --- /dev/null +++ b/sim/testsuite/example-synacor/mod.s @@ -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 diff --git a/sim/testsuite/example-synacor/mult.s b/sim/testsuite/example-synacor/mult.s new file mode 100644 index 000000000000..d323cf53aa77 --- /dev/null +++ b/sim/testsuite/example-synacor/mult.s @@ -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 diff --git a/sim/testsuite/example-synacor/not.s b/sim/testsuite/example-synacor/not.s new file mode 100644 index 000000000000..8a4a570ce6e0 --- /dev/null +++ b/sim/testsuite/example-synacor/not.s @@ -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 diff --git a/sim/testsuite/example-synacor/or.s b/sim/testsuite/example-synacor/or.s new file mode 100644 index 000000000000..f8f2ae3a1539 --- /dev/null +++ b/sim/testsuite/example-synacor/or.s @@ -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 diff --git a/sim/testsuite/example-synacor/push-pop.s b/sim/testsuite/example-synacor/push-pop.s new file mode 100644 index 000000000000..b8199c5d34e4 --- /dev/null +++ b/sim/testsuite/example-synacor/push-pop.s @@ -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 diff --git a/sim/testsuite/example-synacor/ret.s b/sim/testsuite/example-synacor/ret.s new file mode 100644 index 000000000000..63bfa7132cbe --- /dev/null +++ b/sim/testsuite/example-synacor/ret.s @@ -0,0 +1,13 @@ +# check the RET insn. +# mach: example + +.include "testutils.inc" + + start + JMP 13 + pass + + SET r5, 2 + PUSH r5 + RET + HALT diff --git a/sim/testsuite/example-synacor/set.s b/sim/testsuite/example-synacor/set.s new file mode 100644 index 000000000000..8b441c762eaa --- /dev/null +++ b/sim/testsuite/example-synacor/set.s @@ -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 diff --git a/sim/testsuite/example-synacor/testutils.inc b/sim/testsuite/example-synacor/testutils.inc new file mode 100644 index 000000000000..0f286c6036ca --- /dev/null +++ b/sim/testsuite/example-synacor/testutils.inc @@ -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 diff --git a/sim/testsuite/lib/sim-defs.exp b/sim/testsuite/lib/sim-defs.exp index 43a07050f508..04ab4685612b 100644 --- a/sim/testsuite/lib/sim-defs.exp +++ b/sim/testsuite/lib/sim-defs.exp @@ -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] -- 2.28.0