Skip to content
Browse files

Merge branch 'develop'

  • Loading branch information...
2 parents ab2a0b3 + d5ea1da commit e0eb8cfe6e0e7126330606b39611775eba643b55 @kulp committed Sep 8, 2012
View
14 Makefile
@@ -30,6 +30,7 @@ ifeq ($(DEBUG),)
CFLAGS += -O3
else
CPPFLAGS += -DDEBUG=$(DEBUG)
+ CFLAGS += -fstack-protector -Wstack-protector
endif
PEDANTIC ?= -Werror -pedantic-errors
@@ -50,7 +51,7 @@ CPPFLAGS += $(patsubst %,-D%,$(DEFINES)) \
DEVICES = ram sparseram debugwrap serial spi
DEVOBJS = $(DEVICES:%=%.o)
# plugin devices
-PDEVICES = spidummy spisd
+PDEVICES = spidummy spisd spi
PDEVOBJS = $(PDEVICES:%=%,dy.o)
PDEVLIBS = $(PDEVOBJS:%,dy.o=lib%$(DYLIB_SUFFIX))
@@ -68,7 +69,7 @@ tas$(EXE_SUFFIX) tsim$(EXE_SUFFIX): asm.o obj.o
tsim$(EXE_SUFFIX): asm.o obj.o ffi.o plugin.o \
$(GENDIR)/debugger_parser.o \
$(GENDIR)/debugger_lexer.o
-tsim$(EXE_SUFFIX): $(DEVOBJS) sim.o
+tsim$(EXE_SUFFIX): $(DEVOBJS) sim.o param.o
tld$(EXE_SUFFIX): obj.o
asm.o: CFLAGS += -Wno-override-init
@@ -82,6 +83,9 @@ tas$(EXE_SUFFIX) tsim$(EXE_SUFFIX) tld$(EXE_SUFFIX): DEFINES += BUILD_NAME='$(BU
tas.o asm.o tsim.o sim.o ffi.o $(DEVOBJS) $(PDEVOBJS): CFLAGS += -Wno-unused-value
# don't complain about unused state
ffi.o asm.o $(DEVOBJS) $(PDEVOBJS): CFLAGS += -Wno-unused-parameter
+# link plugin-common data and functions into every plugin
+$(PDEVLIBS): pluginimpl,dy.o
+libspi$(DYLIB_SUFFIX): plugin,dy.o
# flex-generated code we can't control warnings of as easily
$(GENDIR)/debugger_parser.o $(GENDIR)/debugger_lexer.o \
@@ -170,7 +174,7 @@ else
@$(BISON) --defines=$(GENDIR)/$*.h -o $(GENDIR)/$*.c $<
endif
-$(PDEVOBJS): %,dy.o: %.c
+plugin,dy.o pluginimpl,dy.o $(PDEVOBJS): %,dy.o: %.c
ifneq ($(MAKE_VERBOSE),)
$(COMPILE.c) -o $@ $<
else
@@ -180,9 +184,9 @@ endif
$(PDEVLIBS): lib%$(DYLIB_SUFFIX): %,dy.o
ifneq ($(MAKE_VERBOSE),)
- $(LINK.c) -shared -o $@ $< $(LDLIBS)
+ $(LINK.c) -shared -o $@ $^ $(LDLIBS)
else
@echo "[ DYLD ] $@"
- @$(LINK.c) -shared -o $@ $< $(LDLIBS)
+ @$(LINK.c) -shared -o $@ $^ $(LDLIBS)
endif
View
1 ex/Makefile
@@ -17,6 +17,7 @@ all: $(TARGETS)
hello.texe: puts.to
compare.texe: strcmp.to puts.to
maths.texe: isqrt.to umod.to udiv.to dword/add.to dword/mul.to
+totient.texe: gcd.to
%.tas: %.tas.cpp
mkdir -p $(*D)
View
75 ex/totient.tas → ex/totient.tas.cpp
@@ -1,40 +1,35 @@
-#include "common.th"
-
-_start:
- prologue
-
- c <- 67
- call(totient)
-
- illegal
-
-// Computes the number of values less than C that are relatively prime to C.
-// Stores the result in B.
-totient:
- b <- 0
- d <- c
-
-loop:
- k <- d == a
- jnzrel(k, done)
-
- push(b)
- push(c)
- push(d)
-
- call(gcd)
-
- k <- b <> 1
- k <- k + 1
-
- pop(d)
- pop(c)
- pop(b)
-
- b <- b + k
-
- d <- d - 1
- goto(loop)
-
-done:
- ret
+#include "common.th"
+
+_start:
+ prologue
+
+ c <- 67
+ call(totient)
+
+ illegal
+
+// Computes the number of values less than C that are relatively prime to C.
+// Stores the result in B.
+totient:
+ b <- 0
+ d <- c
+
+loop:
+ k <- d == a
+ jnzrel(k, done)
+
+ pushall(b,c,d)
+
+ call(gcd)
+
+ k <- b <> 1
+
+ popall(b,c,d)
+
+ b <- b + k + 1
+
+ d <- d - 1
+ goto(loop)
+
+done:
+ ret
View
61 lib/common.th
@@ -6,16 +6,65 @@
// written, so the stack will start at -1 (0xffffffff).
#define prologue o <- o - 1
-#define rel(Label) p + (@Label - . - 1)
-#define reloff(Label,Off) p + (@Label - . - 1 + (Off))
+#define rel(Label) reloff(Label,0)
+#define reloff(Label,Off) (@Label - (. + 1 - (Off))) + p
#define goto(Label) p <- rel(Label)
-#define call(Target) [o] <- p + 2 ; o <- o - 1 ; goto(Target)
+#define call(Target) push(p + 2); goto(Target)
// XXX jnzrel requires Cond to be either 0 or -1, so it's not properly "nz"
-#define jnzrel(Cond,Label) p <- Cond & (@Label - . - 1) + p
-#define jzrel(Cond,Label) p <- Cond &~ (@Label - . - 1) + p
-#define push(Reg) Reg -> [o] ; o <- o - 1
+#define jnzrel(Cond,Label) p <- Cond & rel(Label)
+#define jzrel(Cond,Label) p <- Cond & 1 + p ; goto(Label)
+#define push(Expr) [o] <- Expr ; o <- o - 1
#define pop(Reg) o <- o + 1 ; Reg <- [o]
#define ret pop(p)
+// arguments pushed in the order specified
+#define pushall(...) o <- o - (_narg(__VA_ARGS__)) ; _paste(_push_,_narg(__VA_ARGS__))(_narg(__VA_ARGS__),__VA_ARGS__)
+// arguments popped in the reverse of the order specified
+#define popall(...) _paste(_pop_,_narg(__VA_ARGS__))(_narg(__VA_ARGS__),__VA_ARGS__) ; o <- o + (_narg(__VA_ARGS__))
+
+// ---
+
+#define _paste(X,Y) _paste_(X,Y)
+#define _paste_(X,Y) X ## Y
+
+#define _push_op(Off,Reg) Reg -> [o + (Off)]
+#define _push_0(...) /* no-op */
+#define _push_1(Off,Reg,...) _push_op(Off,Reg) ; _push_0( (Off) - 1,__VA_ARGS__)
+#define _push_2(Off,Reg,...) _push_op(Off,Reg) ; _push_1( (Off) - 1,__VA_ARGS__)
+#define _push_3(Off,Reg,...) _push_op(Off,Reg) ; _push_2( (Off) - 1,__VA_ARGS__)
+#define _push_4(Off,Reg,...) _push_op(Off,Reg) ; _push_3( (Off) - 1,__VA_ARGS__)
+#define _push_5(Off,Reg,...) _push_op(Off,Reg) ; _push_4( (Off) - 1,__VA_ARGS__)
+#define _push_6(Off,Reg,...) _push_op(Off,Reg) ; _push_5( (Off) - 1,__VA_ARGS__)
+#define _push_7(Off,Reg,...) _push_op(Off,Reg) ; _push_6( (Off) - 1,__VA_ARGS__)
+#define _push_8(Off,Reg,...) _push_op(Off,Reg) ; _push_7( (Off) - 1,__VA_ARGS__)
+#define _push_9(Off,Reg,...) _push_op(Off,Reg) ; _push_8( (Off) - 1,__VA_ARGS__)
+#define _push_10(Off,Reg,...) _push_op(Off,Reg) ; _push_9( (Off) - 1,__VA_ARGS__)
+#define _push_11(Off,Reg,...) _push_op(Off,Reg) ; _push_10((Off) - 1,__VA_ARGS__)
+#define _push_12(Off,Reg,...) _push_op(Off,Reg) ; _push_11((Off) - 1,__VA_ARGS__)
+#define _push_13(Off,Reg,...) _push_op(Off,Reg) ; _push_12((Off) - 1,__VA_ARGS__)
+#define _push_14(Off,Reg,...) _push_op(Off,Reg) ; _push_13((Off) - 1,__VA_ARGS__)
+#define _push_15(Off,Reg,...) _push_op(Off,Reg) ; _push_14((Off) - 1,__VA_ARGS__)
+
+#define _pop_op(Off,Reg) Reg <- [o + (Off)]
+#define _pop_0(...) /* no-op */
+#define _pop_1(Off,Reg,...) _pop_0( (Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_2(Off,Reg,...) _pop_1( (Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_3(Off,Reg,...) _pop_2( (Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_4(Off,Reg,...) _pop_3( (Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_5(Off,Reg,...) _pop_4( (Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_6(Off,Reg,...) _pop_5( (Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_7(Off,Reg,...) _pop_6( (Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_8(Off,Reg,...) _pop_7( (Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_9(Off,Reg,...) _pop_8( (Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_10(Off,Reg,...) _pop_9( (Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_11(Off,Reg,...) _pop_10((Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_12(Off,Reg,...) _pop_11((Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_13(Off,Reg,...) _pop_12((Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_14(Off,Reg,...) _pop_13((Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+#define _pop_15(Off,Reg,...) _pop_14((Off) - 1,__VA_ARGS__) ; _pop_op(Off,Reg)
+
+#define _narg(...) _narg_impl(__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
+#define _narg_impl(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,...) _15
+
#endif
View
6 lib/gcd.tas → lib/gcd.tas.cpp
@@ -10,16 +10,16 @@
b <- d
k <- c == 0
jnzrel(k, done)
-
+
b <- c
loop:
k <- d == 0
jnzrel(k, done)
-
+
k <- b > d
jnzrel(k, else)
-
+
d <- d - b
goto(loop)
View
2 lib/strcmp.tas.cpp
@@ -5,7 +5,7 @@
// TODO permit compared strings to differ after the terminating \0
- .global strcmp
+ .global strcmp
strcmp:
b <- 0 // start with matching
_loop:
View
2 plugins/spi.rcp
@@ -0,0 +1,2 @@
+--param=plugin.impl[0]=spi
+--param=spi.impl=spisd
View
27 src/asm.c
@@ -130,6 +130,17 @@ int print_disassembly(FILE *out, struct instruction *i, int flags)
} else if (g->op == OP_SUBTRACT && g->x == 0) {
f5 = ' '; // don't print X
}
+
+ // sugar for P update idiom ; prefer signed decimal operand
+ if (g->y == 15
+ && ( (g->op == OP_BITWISE_AND)
+ || (g->op == OP_BITWISE_OR && g->x == 0)
+ || (g->op == OP_ADD)
+ || (g->op == OP_SUBTRACT)
+ )
+ ) {
+ hex = 0;
+ }
}
#define C_(E,D,C,B,A) (((E) << 4) | ((D) << 3) | ((C) << 2) | ((B) << 1) | (A))
@@ -138,21 +149,21 @@ int print_disassembly(FILE *out, struct instruction *i, int flags)
// indices : hex, g->p, op1, op2, op3
static const char *fmts[C_(1,1,1,1,1)+1] = {
//[C_(0,0,0,0,0)] = "%c%c%c %s %c" "%c", // [Z] <- [ ]
- [C_(0,0,0,0,1)] = "%c%c%c %s %c" "%-10d%c", // [Z] <- [ -0]
+ [C_(0,0,0,0,1)] = "%c%c%c %s %c" "%d%c", // [Z] <- [ -0]
[C_(0,0,0,1,0)] = "%c%c%c %s %c" "%c" "%c", // [Z] <- [ Y ]
- [C_(0,0,0,1,1)] = "%c%c%c %s %c" "%c + %-10d%c", // [Z] <- [ Y + -0]
+ [C_(0,0,0,1,1)] = "%c%c%c %s %c" "%c + " "%d%c", // [Z] <- [ Y + -0]
[C_(0,0,1,0,0)] = "%c%c%c %s %c%c" "%c", // [Z] <- [X ]
- [C_(0,0,1,0,1)] = "%c%c%c %s %c%c" " + %-10d%c", // [Z] <- [X + -0]
+ [C_(0,0,1,0,1)] = "%c%c%c %s %c%c" " + " "%d%c", // [Z] <- [X + -0]
[C_(0,0,1,1,0)] = "%c%c%c %s %c%c %-2s " "%c" "%c", // [Z] <- [X - Y ]
- [C_(0,0,1,1,1)] = "%c%c%c %s %c%c %-2s " "%c + %-10d%c", // [Z] <- [X - Y + -0]
+ [C_(0,0,1,1,1)] = "%c%c%c %s %c%c %-2s " "%c + " "%d%c", // [Z] <- [X - Y + -0]
//[C_(0,1,0,0,0)] = "%c%c%c %s %c" "%c", // [Z] <- [ ]
[C_(0,1,0,0,1)] = "%c%c%c %s %c" "%c%c", // [Z] <- [ Y]
- [C_(0,1,0,1,0)] = "%c%c%c %s %c" " %-10d" "%c", // [Z] <- [ -0 ]
- [C_(0,1,0,1,1)] = "%c%c%c %s %c" " %-10d + %c%c", // [Z] <- [ -0 + Y]
+ [C_(0,1,0,1,0)] = "%c%c%c %s %c" "%d" "%c", // [Z] <- [ -0 ]
+ [C_(0,1,0,1,1)] = "%c%c%c %s %c" "%d + %c%c", // [Z] <- [ -0 + Y]
[C_(0,1,1,0,0)] = "%c%c%c %s %c%c" "%c", // [Z] <- [X ]
[C_(0,1,1,0,1)] = "%c%c%c %s %c%c" " + %c%c", // [Z] <- [X + Y]
- [C_(0,1,1,1,0)] = "%c%c%c %s %c%c %-2s " "%-10d" "%c", // [Z] <- [X - -0 ]
- [C_(0,1,1,1,1)] = "%c%c%c %s %c%c %-2s " "%-10d + %c%c", // [Z] <- [X - -0 + Y]
+ [C_(0,1,1,1,0)] = "%c%c%c %s %c%c %-2s " "%d" "%c", // [Z] <- [X - -0 ]
+ [C_(0,1,1,1,1)] = "%c%c%c %s %c%c %-2s " "%d + %c%c", // [Z] <- [X - -0 + Y]
//[C_(1,0,0,0,0)] = "%c%c%c %s %c" "%c", // [Z] <- [ ]
[C_(1,0,0,0,1)] = "%c%c%c %s %c" "0x%08x%c", // [Z] <- [ 0x0]
[C_(1,0,0,1,0)] = "%c%c%c %s %c" "%c" "%c", // [Z] <- [ Y ]
View
17 src/common.c
@@ -5,10 +5,14 @@
#include <stdio.h>
#include <string.h>
+// This file must not be linked into plugins, because of the different way
+// fatal_ and debug_ are handled in main programs vs. plugins. This file should
+// probably be renamed.
+
jmp_buf errbuf;
-void fatal_(int code, const char *file, int line, const char *func,
- const char *fmt, ...)
+static void NORETURN main_fatal_(int code, const char *file, int line,
+ const char *func, const char *fmt, ...)
{
va_list vl;
va_start(vl,fmt);
@@ -24,8 +28,8 @@ void fatal_(int code, const char *file, int line, const char *func,
longjmp(errbuf, code);
}
-void debug_(int level, const char *file, int line, const char *func,
- const char *fmt, ...)
+static void main_debug_(int level, const char *file, int line,
+ const char *func, const char *fmt, ...)
{
#ifndef DEBUG
#define DEBUG 0
@@ -60,3 +64,8 @@ int tree_destroy(struct todo_node **todo, void **tree, traverse *trav, cmp *comp
return 0;
}
+// These are the implementations of the `common` functions, main program version.
+// TODO these should probably be wrapped up in a structure
+void (* NORETURN fatal_)(int code, const char *file, int line, const char *func, const char *fmt, ...) = main_fatal_;
+void (*debug_)(int level, const char *file, int line, const char *func, const char *fmt, ...) = main_debug_;
+
View
12 src/common.h
@@ -36,14 +36,12 @@ extern jmp_buf errbuf;
#define debug(Level,...) \
debug_(Level,__FILE__,__LINE__,__func__,__VA_ARGS__)
-#if !TENYR_PLUGIN
-// tenyr plugins use their own function pointers
-void NORETURN fatal_(int code, const char *file, int line, const char *func,
- const char *fmt, ...);
+// use function pointers to support plugin architecture
+extern void (* NORETURN fatal_)(int code, const char *file, int line, const char
+ *func, const char *fmt, ...);
-void debug_(int level, const char *file, int line, const char *func,
- const char *fmt, ...);
-#endif
+extern void (*debug_)(int level, const char *file, int line, const char *func,
+ const char *fmt, ...);
// represents a most basic linked list, used for collecting nodes with twalk
struct todo_node {
View
26 src/device.h
@@ -1,22 +1,26 @@
-#ifndef DEVICES_H_
-#define DEVICES_H_
+#ifndef DEVICE_H_
+#define DEVICE_H_
#include <stdint.h>
+struct sim_state;
+
#include "common.h"
-#include "sim.h"
+#include "plugin_portable.h"
-typedef int map_init(struct sim_state *s, void *cookie, ...);
-typedef int map_op(struct sim_state *s, void *cookie, int op, uint32_t addr, uint32_t *data);
-typedef int map_cycle(struct sim_state *s, void *cookie);
-typedef int map_fini(struct sim_state *s, void *cookie);
+typedef int map_init(struct guest_ops *gops, void *hostcookie, void *cookie, int nargs, ...);
+typedef int map_op(void *cookie, int op, uint32_t addr, uint32_t *data);
+typedef int map_cycle(void *cookie);
+typedef int map_fini(void *cookie);
struct device {
uint32_t bounds[2]; // lower and upper memory bounds, inclusive
- map_init *init;
- map_op *op;
- map_cycle *cycle;
- map_fini *fini;
+ struct device_ops {
+ map_init *init;
+ map_op *op;
+ map_cycle *cycle;
+ map_fini *fini;
+ } ops;
void *cookie;
};
View
20 src/devices/debugwrap.c
@@ -11,32 +11,32 @@ struct debugwrap_state {
struct device *wrapped;
};
-static int debugwrap_init(struct sim_state *s, void *cookie, ...)
+static int debugwrap_init(struct guest_ops *gops, void *hostcookie, void *cookie, int nargs, ...)
{
// our own init done in debugwrap_add_device ()
struct debugwrap_state *debugwrap = *(void**)cookie;
// TODO varargs ?
- debugwrap->wrapped->init(s, &debugwrap->wrapped->cookie);
+ debugwrap->wrapped->ops.init(gops, hostcookie, &debugwrap->wrapped->cookie, 0);
return 0;
}
-static int debugwrap_fini(struct sim_state *s, void *cookie)
+static int debugwrap_fini(void *cookie)
{
// TODO destroy wrapped device ? or unwrap somehow ?
struct debugwrap_state *debugwrap = cookie;
- debugwrap->wrapped->fini(s, debugwrap->wrapped->cookie);
+ debugwrap->wrapped->ops.fini(debugwrap->wrapped->cookie);
free(debugwrap);
return 0;
}
-static int debugwrap_op(struct sim_state *s, void *cookie, int op, uint32_t addr,
+static int debugwrap_op(void *cookie, int op, uint32_t addr,
uint32_t *data)
{
struct debugwrap_state *debugwrap = cookie;
assert(("Address within address space", !(addr & ~PTR_MASK)));
- debugwrap->wrapped->op(s, debugwrap->wrapped->cookie, op, addr, data);
+ debugwrap->wrapped->ops.op(debugwrap->wrapped->cookie, op, addr, data);
printf("%-5s @ 0x%06x = %#x\n", op ? "write" : "read", addr, *data);
return 0;
@@ -49,9 +49,11 @@ int debugwrap_add_device(struct device **device, struct device *wrap)
**device = (struct device){
.bounds = { wrap->bounds[0], wrap->bounds[1] },
- .op = debugwrap_op,
- .init = debugwrap_init,
- .fini = debugwrap_fini,
+ .ops = {
+ .op = debugwrap_op,
+ .init = debugwrap_init,
+ .fini = debugwrap_fini,
+ },
.cookie = debugwrap,
};
View
21 src/devices/ram.c
@@ -5,6 +5,7 @@
#include "common.h"
#include "device.h"
+#include "sim.h"
#include "ram.h"
struct ram_state {
@@ -13,25 +14,25 @@ struct ram_state {
int32_t mem[RAM_END + 1];
};
-static int ram_init(struct sim_state *s, void *cookie, ...)
+static int ram_init(struct guest_ops *gops, void *hostcookie, void *cookie, int nargs, ...)
{
struct ram_state *ram = *(void**)cookie = malloc(sizeof *ram);
- if (s->conf.should_init)
- for (unsigned long i = 0; i < countof(ram->mem); i++)
- ram->mem[i] = s->conf.initval;
+// if (s->conf.should_init)
+// for (unsigned long i = 0; i < countof(ram->mem); i++)
+// ram->mem[i] = s->conf.initval;
return 0;
}
-static int ram_fini(struct sim_state *s, void *cookie)
+static int ram_fini(void *cookie)
{
struct ram_state *ram = cookie;
free(ram);
return 0;
}
-static int ram_op(struct sim_state *s, void *cookie, int op, uint32_t addr, uint32_t *data)
+static int ram_op(void *cookie, int op, uint32_t addr, uint32_t *data)
{
struct ram_state *ram = cookie;
assert(("Address within address space", !(addr & ~PTR_MASK)));
@@ -50,9 +51,11 @@ int ram_add_device(struct device **device)
{
**device = (struct device){
.bounds = { RAM_BASE, RAM_END },
- .op = ram_op,
- .init = ram_init,
- .fini = ram_fini,
+ .ops = {
+ .op = ram_op,
+ .init = ram_init,
+ .fini = ram_fini,
+ },
};
return 0;
View
15 src/devices/serial.c
@@ -5,20 +5,21 @@
#include "common.h"
#include "device.h"
+#include "sim.h"
#define SERIAL_BASE (1ULL << 5)
-static int serial_init(struct sim_state *s, void *cookie, ...)
+static int serial_init(struct guest_ops *gops, void *hostcookie, void *cookie, int nargs, ...)
{
return 0;
}
-static int serial_fini(struct sim_state *s, void *cookie)
+static int serial_fini(void *cookie)
{
return 0;
}
-static int serial_op(struct sim_state *s, void *cookie, int op, uint32_t addr, uint32_t *data)
+static int serial_op(void *cookie, int op, uint32_t addr, uint32_t *data)
{
int tmp;
@@ -39,9 +40,11 @@ int serial_add_device(struct device **device)
{
**device = (struct device){
.bounds = { SERIAL_BASE, SERIAL_BASE + 1 },
- .op = serial_op,
- .init = serial_init,
- .fini = serial_fini,
+ .ops = {
+ .op = serial_op,
+ .init = serial_init,
+ .fini = serial_fini,
+ },
};
return 0;
View
21 src/devices/sparseram.c
@@ -6,6 +6,7 @@
#include "common.h"
#include "device.h"
+#include "sim.h"
#include "ram.h"
// Allocate space by roughly a page-size (although since there is overhead the
@@ -35,7 +36,7 @@ static int tree_compare(const void *_a, const void *_b)
return b->base - a->base;
}
-static int sparseram_init(struct sim_state *s, void *cookie, ...)
+static int sparseram_init(struct guest_ops *gops, void *hostcookie, void *cookie, int nargs, ...)
{
struct sparseram_state *sparseram = *(void**)cookie = malloc(sizeof *sparseram);
sparseram->mem = NULL;
@@ -45,7 +46,7 @@ static int sparseram_init(struct sim_state *s, void *cookie, ...)
TODO_TRAVERSE_(element)
-static int sparseram_fini(struct sim_state *s, void *cookie)
+static int sparseram_fini(void *cookie)
{
struct sparseram_state *sparseram = cookie;
// tdestroy() is a glibc extension. Here we generate a list of nodes to
@@ -59,7 +60,7 @@ static int sparseram_fini(struct sim_state *s, void *cookie)
return 0;
}
-static int sparseram_op(struct sim_state *s, void *cookie, int op, uint32_t addr,
+static int sparseram_op(void *cookie, int op, uint32_t addr,
uint32_t *data)
{
struct sparseram_state *sparseram = cookie;
@@ -72,9 +73,9 @@ static int sparseram_op(struct sim_state *s, void *cookie, int op, uint32_t addr
// useful optimisation, but we could avoid allocating a page until the
// first write.
struct element *node = malloc(PAGESIZE * sizeof *node->space + sizeof *node);
- if (s->conf.should_init)
- for (unsigned long i = 0; i < PAGESIZE; i++)
- node->space[i] = s->conf.initval;
+// if (s->conf.should_init)
+// for (unsigned long i = 0; i < PAGESIZE; i++)
+// node->space[i] = s->conf.initval;
*node = (struct element){ addr & ~WORDMASK, cookie };
*p = node;
@@ -97,9 +98,11 @@ int sparseram_add_device(struct device **device)
{
**device = (struct device){
.bounds = { RAM_BASE, RAM_END },
- .op = sparseram_op,
- .init = sparseram_init,
- .fini = sparseram_fini,
+ .ops = {
+ .op = sparseram_op,
+ .init = sparseram_init,
+ .fini = sparseram_fini,
+ },
};
return 0;
View
55 src/devices/spi.c
@@ -5,23 +5,17 @@
// "spi.impl" is set, a spi_ops implementation with that stem name is loaded
// using dlsym(). Otherwise, acts as if nothing is attached to the SPI pins.
-// _GNU_SOURCE is needed for RTLD_DEFAULT on GNU/Linux, although that flag
-// works on apple-darwin as well
-#define _GNU_SOURCE 1
+#include "plugin.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-// we use some plugin definitions but are not a plugin ourselves (this is
-// hacky XXX)
-#define TENYR_PLUGIN 0
-#include "plugin.h"
-
#include "common.h"
#include "device.h"
#include "spi.h"
+#include "sim.h"
#define SPI_BASE 0x200
#define SPI_LEN (0x7 * 4) /* seven registers at four addresses each) */
@@ -101,26 +95,27 @@ static void spi_reset_defaults(struct spi_state *spi)
spi->regs.fmt.SS = 0x00000000;
}
-static int spi_emu_init(struct sim_state *s, void *cookie, ...)
+static int spi_emu_init(struct guest_ops *gops, void *hostcookie, void *cookie, int nargs, ...)
{
- struct spi_state *spi = *(void**)cookie = malloc(sizeof *spi);
+ struct spi_state *spi = *(void**)cookie = calloc(1, sizeof *spi);
spi_reset_defaults(spi);
memset(spi->impls, 0, sizeof spi->impls);
const char *implname = NULL;
- if (param_get(s, "spi.impl", &implname)) {
+ if (gops->param_get(hostcookie, "spi.impl", &implname)) {
int inst = 0; // TODO support more than one instance
// If implname contains a slash, treat it as a path ; otherwise, stem
char buf[256];
const char *implpath = NULL;
const char *implstem = NULL;
- param_get(s, "spi.implstem", &implstem); // may not be set ; that's OK
+ gops->param_get(hostcookie, "spi.implstem", &implstem); // may not be set ; that's OK
if (strchr(implname, PATH_SEPARATOR_CHAR)) {
implpath = implname;
} else {
- snprintf(buf, sizeof buf, "lib%s"DYLIB_SUFFIX, implname);
+ snprintf(buf, sizeof buf, ".%clib%s"DYLIB_SUFFIX,
+ PATH_SEPARATOR_CHAR, implname);
buf[sizeof buf - 1] = 0;
implpath = buf;
if (!implstem)
@@ -170,7 +165,7 @@ static int spi_emu_init(struct sim_state *s, void *cookie, ...)
return 0;
}
-static int spi_emu_fini(struct sim_state *s, void *cookie)
+static int spi_emu_fini(void *cookie)
{
struct spi_state *spi = cookie;
@@ -185,8 +180,7 @@ static int spi_emu_fini(struct sim_state *s, void *cookie)
return 0;
}
-static int spi_op(struct sim_state *s, void *cookie, int op, uint32_t addr,
- uint32_t *data)
+static int spi_op(void *cookie, int op, uint32_t addr, uint32_t *data)
{
struct spi_state *spi = cookie;
uint32_t offset = addr - SPI_BASE;
@@ -232,6 +226,9 @@ static int spi_op(struct sim_state *s, void *cookie, int op, uint32_t addr,
spi->regs.raw[regnum] = *data;
}
+ } else {
+ if (op == OP_READ)
+ *data = spi->regs.raw[regnum]; // default dummy read
}
return 0;
@@ -288,7 +285,8 @@ static int spi_slave_cycle(struct spi_state *spi)
push = (spi->regs.raw[(width - 1) / 32] & (1 << inword)) >> inword;
}
- assert(("SPI pushed bit is 0 or 1", (push == 0 || push == 1)));
+ if (push != 0 && push != 1)
+ breakpoint("SPI pushed bit is %d, expected 0 or 1", push);
}
for (int inst = 0; inst < NINST; inst++) {
@@ -319,7 +317,8 @@ static int spi_slave_cycle(struct spi_state *spi)
case SPI_EMU_BUSY: {
if (ops->clock(cookie, 1, push, &pull))
debug(1, "SPI attached instance %d returned nonzero from clock()", inst);
- assert(("SPI generated bit is 0 or 1", (pull == 0 || pull == 1)));
+ if (pull != 0 && pull != 1)
+ breakpoint("SPI generated bit is %d, expected 0 or 1", pull);
do_one_shift(spi, width, pull);
if (!--spi->remaining)
@@ -353,7 +352,7 @@ static int spi_slave_cycle(struct spi_state *spi)
return 0;
}
-static int spi_emu_cycle(struct sim_state *s, void *cookie)
+static int spi_emu_cycle(void *cookie)
{
struct spi_state *spi = cookie;
if (spi->dividend++ >= (unsigned)((spi->regs.fmt.DIVIDER + 1) * 2 - 1)) {
@@ -366,14 +365,22 @@ static int spi_emu_cycle(struct sim_state *s, void *cookie)
return 0;
}
-int spi_add_device(struct device **device)
+void EXPORT tenyr_plugin_init(struct guest_ops *ops)
+{
+ fatal_ = ops->fatal;
+ debug_ = ops->debug;
+}
+
+int EXPORT spi_add_device(struct device **device)
{
**device = (struct device){
.bounds = { SPI_BASE, SPI_END },
- .op = spi_op,
- .init = spi_emu_init,
- .fini = spi_emu_fini,
- .cycle = spi_emu_cycle,
+ .ops = {
+ .op = spi_op,
+ .init = spi_emu_init,
+ .fini = spi_emu_fini,
+ .cycle = spi_emu_cycle,
+ },
};
return 0;
View
7 src/devices/spisd.c
@@ -12,9 +12,6 @@
#define RESET_CYCLE_REQ 50 ///< arbitrary
-void (*fatal_)(int code, const char *file, int line, const char *func, const char *fmt, ...);
-void (*debug_)(int level, const char *file, int line, const char *func, const char *fmt, ...);
-
struct spisd_state {
enum {
SPISD_INVALID = 0,
@@ -243,15 +240,15 @@ static const struct spisd_app_command {
SPISD_APP_COMMANDS(SPISD_APP_ARRAY_ENTRY)
};
-void EXPORT tenyr_plugin_init(struct tenyr_plugin_ops *ops)
+void EXPORT tenyr_plugin_init(struct guest_ops *ops)
{
fatal_ = ops->fatal;
debug_ = ops->debug;
}
int EXPORT spisd_spi_init(void *pcookie)
{
- struct spisd_state *s = malloc(sizeof *s);
+ struct spisd_state *s = calloc(1, sizeof *s);
*(void**)pcookie = s;
s->out_shift_len = 0;
s->state = SPISD_UNINITIALISED;
View
4 src/os/Darwin/plugin.h
@@ -1,11 +1,11 @@
#ifndef PLUGIN_H_
#define PLUGIN_H_
-#include "plugin_portable.h"
-
#include <dlfcn.h>
#define EXPORT
#define EXPORT_CALLING
+#include "plugin_portable.h"
+
#endif
View
6 src/os/Linux/plugin.h
@@ -4,11 +4,15 @@
// this header should be included before all other headers, by any files that
// are compiled into a plugin
-#include "plugin_portable.h"
+// _GNU_SOURCE is needed for RTLD_DEFAULT on GNU/Linux, although that flag
+// works on apple-darwin as well
+#define _GNU_SOURCE 1
#include <dlfcn.h>
#define EXPORT
#define EXPORT_CALLING
+#include "plugin_portable.h"
+
#endif
View
6 src/os/Win32/plugin.h
@@ -1,16 +1,12 @@
#ifndef PLUGIN_H_
#define PLUGIN_H_
-#include "plugin_portable.h"
-
#include <windows.h>
// TODO use __stdcall
#define EXPORT_CALLING __cdecl
#define EXPORT __declspec(dllexport) EXPORT_CALLING
-#include "common.h"
-
// just defined to make compilation work ; ignored
#define RTLD_DEFAULT NULL
#define RTLD_LOCAL -1
@@ -52,5 +48,7 @@ static inline int dlclose(void *handle)
return !FreeLibrary(handle);
}
+#include "plugin_portable.h"
+
#endif
View
93 src/param.c
@@ -0,0 +1,93 @@
+#define _XOPEN_SOURCE 600
+
+#include "param.h"
+
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void param_free(struct param_entry *p);
+
+static int params_cmp(const void *_a, const void *_b)
+{
+ const struct param_entry *a = _a,
+ *b = _b;
+
+ return strcmp(a->key, b->key);
+}
+
+int param_get(struct param_state *pstate, char *key, const char **val)
+{
+ struct param_entry p = { .key = key };
+
+ struct param_entry *q = lfind(&p, pstate->params, &pstate->params_count,
+ sizeof *pstate->params, params_cmp);
+
+ if (!q)
+ return 0;
+
+ *val = q->value;
+
+ return 1;
+}
+
+int param_set(struct param_state *pstate, char *key, char *val, int free_value)
+{
+ while (pstate->params_size <= pstate->params_count)
+ // technically there is a problem here if realloc() fails
+ pstate->params = realloc(pstate->params,
+ (pstate->params_size *= 2) * sizeof *pstate->params);
+
+ struct param_entry p = {
+ .key = key,
+ .value = val,
+ .free_value = free_value,
+ };
+
+ struct param_entry *q = lsearch(&p, pstate->params, &pstate->params_count,
+ sizeof *pstate->params, params_cmp);
+
+ if (!q)
+ return 1;
+
+ if (q->key != p.key) {
+ param_free(q);
+ *q = p;
+ }
+
+ return 0;
+}
+
+int param_add(struct param_state *pstate, const char *optarg)
+{
+ // We can't use getsubopt() here because we don't know what all of our
+ // options are ahead of time.
+ char *dupped = strdup(optarg);
+ char *eq = strchr(dupped, '=');
+ if (!eq) {
+ free(dupped);
+ return 1;
+ }
+
+ // Replace '=' with '\0' to split string in two
+ *eq = '\0';
+
+ return param_set(pstate, dupped, ++eq, 0);
+}
+
+void param_destroy(struct param_state *pstate)
+{
+ while (pstate->params_count--)
+ param_free(&pstate->params[pstate->params_count]);
+
+ free(pstate->params);
+ pstate->params_size = 0;
+}
+
+static void param_free(struct param_entry *p)
+{
+ free(p->key);
+ if (p->free_value)
+ free(p->value);
+}
+
View
24 src/param.h
@@ -0,0 +1,24 @@
+#ifndef PARAM_H_
+#define PARAM_H_
+
+#include <stddef.h>
+
+struct param_state {
+#define DEFAULT_PARAMS_COUNT 16
+ size_t params_count;
+ size_t params_size;
+ struct param_entry {
+ char *key;
+ char *value;
+ int free_value; ///< whether value should be free()d
+ } *params;
+};
+
+/// @c param_get() returns true if key is found, false otherwise
+int param_get(struct param_state *pstate, char *key, const char **val);
+int param_set(struct param_state *pstate, char *key, char *val, int free_value);
+int param_add(struct param_state *pstate, const char *optarg);
+void param_destroy(struct param_state *pstate);
+
+#endif
+
View
7 src/parser.y
@@ -249,11 +249,12 @@ rhs_plain
| unary_op greloc_expr /* responsible for a S/R conflict */
{ $rhs_plain = make_expr_type1(0, $unary_op, $greloc_expr, 0); }
| greloc_expr
- { enum op op = ($greloc_expr->flags & IMM_IS_BITS) ? OP_BITWISE_OR : OP_ADD;
+ { /* When the RHS is just a constant, choose OR or ADD depending on
+ * what kind of constant this is likely to be. */
+ enum op op = ($greloc_expr->flags & IMM_IS_BITS) ? OP_BITWISE_OR : OP_ADD;
$rhs_plain = make_expr_type1(0, op, $greloc_expr, 0); }
| greloc_expr '+' regname[y]
- { enum op op = ($greloc_expr->flags & IMM_IS_BITS) ? OP_BITWISE_OR : OP_ADD;
- $rhs_plain = make_expr_type1(0, op, $greloc_expr, $y); }
+ { $rhs_plain = make_expr_type1(0, OP_ADD, $greloc_expr, $y); }
unary_op
: '~' { $unary_op = OP_BITWISE_XORN; }
View
5 src/plugin.c
@@ -1,13 +1,12 @@
-#define TENYR_PLUGIN 0
#include "plugin.h"
#include "common.h"
int tenyr_plugin_host_init(void *libhandle)
{
void *ptr = dlsym(libhandle, "tenyr_plugin_init");
- plugin_init *init = ALIASING_CAST(plugin_init,ptr);
+ library_init *init = ALIASING_CAST(library_init,ptr);
if (init) {
- struct tenyr_plugin_ops ops = {
+ struct guest_ops ops = {
.fatal = fatal_,
.debug = debug_,
};
View
19 src/plugin_portable.h
@@ -1,24 +1,29 @@
#ifndef PLUGIN_PORTABLE_H_
#define PLUGIN_PORTABLE_H_
+#include "plugin.h"
+
+#include <stdint.h>
+
#define NORETURN __attribute__((noreturn))
+struct plugin_cookie {
+ struct param_state *param;
+};
+
// portable (non-OS-specific) plugin definitions
-struct tenyr_plugin_ops {
+struct guest_ops {
void (* NORETURN fatal)(int code , const char *file, int line, const char *func, const char *fmt, ...);
void (* debug)(int level, const char *file, int line, const char *func, const char *fmt, ...);
+ int (* param_get)(void *cookie, char *key, const char **val);
+ int (* param_set)(void *cookie, char *key, char *val, int free_value);
};
-typedef void plugin_init(struct tenyr_plugin_ops *ops);
+typedef int EXPORT_CALLING library_init(struct guest_ops *ops);
// this is called by plugin hosts
int tenyr_plugin_host_init(void *libhandle);
-// signal to other includes that we are in plugin mode
-#ifndef TENYR_PLUGIN
-#define TENYR_PLUGIN 1
-#endif
-
#endif
View
6 src/pluginimpl.c
@@ -0,0 +1,6 @@
+#include "plugin.h"
+
+// These are the implementations of the `common` functions, plugin version.
+void (* NORETURN fatal_)(int code, const char *file, int line, const char *func, const char *fmt, ...);
+void (* debug_)(int level, const char *file, int line, const char *func, const char *fmt, ...);
+
View
30 src/sim.h
@@ -4,6 +4,9 @@
#include "ops.h"
#include "machine.h"
#include "asm.h"
+#include "plugin.h"
+#include "device.h"
+#include "param.h"
#include <stdint.h>
#include <stddef.h>
@@ -32,16 +35,23 @@ struct sim_state {
int should_init;
uint32_t initval;
-#define DEFAULT_PARAMS_COUNT 16
- size_t params_count;
- size_t params_size;
- struct param_entry {
- char *key;
- char *value;
- int free_value; ///< whether value should be free()d
- } *params;
+ struct param_state params;
+
+ struct guest_ops gops;
+
+ int start_addr;
+ int load_addr;
+ const struct format *fmt;
} conf;
+ struct {
+ struct plugin {
+ void *cookie;
+ struct device_ops ops;
+ } *impls;
+ } *plugins;
+ struct plugin_cookie plugin_cookie;
+
op_dispatcher *dispatch_op;
struct recipe_book *recipes;
@@ -59,10 +69,6 @@ int run_sim(struct sim_state *s, struct run_ops *ops);
int load_sim(op_dispatcher *dispatch_op, void *sud, const struct format *f,
FILE *in, int load_address);
-/// @c param_get() returns true if key is found, false otherwise
-int param_get(struct sim_state *s, char *key, const char **val);
-int param_set(struct sim_state *s, char *key, char *val, int free_value);
-
// TODO convert this to an interrupt in the debugger
#define breakpoint(...) \
fatal(0, __VA_ARGS__)
View
250 src/tsim.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 600
+#include "plugin.h"
#include "ops.h"
#include "common.h"
@@ -36,15 +36,18 @@ struct breakpoint {
_(prealloc, "preallocate memory (higher memory footprint, maybe faster)") \
_(sparse , "use sparse memory (lower memory footprint, maybe slower)") \
_(serial , "enable simple serial device and connect to stdio") \
- _(spi , "enable SPI emulation") \
_(inittrap, "initialise unused memory to the illegal instruction") \
- _(nowrap , "stop when PC wraps around 24-bit boundary")
+ _(nowrap , "stop when PC wraps around 24-bit boundary") \
+ _(plugin , "load plugins specified through param mechanism") \
+ //
#define DEFAULT_RECIPES(_) \
_(sparse) \
_(serial) \
_(inittrap) \
- _(nowrap)
+ _(nowrap) \
+ _(plugin) \
+ //
#define Space(X) STR(X) " "
@@ -53,7 +56,7 @@ struct breakpoint {
static int next_device(struct sim_state *s)
{
- if (s->machine.devices_count >= s->machine.devices_max) {
+ while (s->machine.devices_count >= s->machine.devices_max) {
s->machine.devices_max *= 2;
s->machine.devices = realloc(s->machine.devices,
s->machine.devices_max * sizeof *s->machine.devices);
@@ -68,6 +71,66 @@ static int recipe_abort(struct sim_state *s)
return 0;
}
+static int recipe_plugin(struct sim_state *s)
+{
+ int rc = 0;
+
+ const char *implname = NULL;
+
+ int inst = 0;
+ do {
+ char buf[256];
+ snprintf(buf, sizeof buf, "plugin.impl[%d]", inst);
+ if (param_get(&s->conf.params, buf, &implname)) {
+ // If implname contains a slash, treat it as a path ; otherwise, stem
+ const char *implpath = NULL;
+ const char *implstem = NULL;
+ snprintf(buf, sizeof buf, "plugin.impl[%d].stem", inst);
+ param_get(&s->conf.params, buf, &implstem); // may not be set ; that's OK
+ if (strchr(implname, PATH_SEPARATOR_CHAR)) {
+ implpath = implname;
+ } else {
+ snprintf(buf, sizeof buf, ".%clib%s"DYLIB_SUFFIX,
+ PATH_SEPARATOR_CHAR, implname);
+ buf[sizeof buf - 1] = 0;
+ implpath = buf;
+ if (!implstem)
+ implstem = implname;
+ }
+
+ // TODO consider using RTLD_NODELETE here
+ // (seems to break on Mac OS X)
+ // currently we leak library handles
+ void *libhandle = dlopen(implpath, RTLD_NOW | RTLD_LOCAL);
+ if (!libhandle) {
+ debug(1, "Could not load %s, trying default library search", implpath);
+ libhandle = RTLD_DEFAULT;
+ }
+
+ tenyr_plugin_host_init(libhandle);
+
+ {
+ char buf[128];
+ snprintf(buf, sizeof buf, "%s_add_device", implstem);
+ void *ptr = dlsym(libhandle, buf);
+ typedef int add_device(struct device **);
+ add_device *adder = ALIASING_CAST(add_device,ptr);
+ if (adder) {
+ int index = next_device(s);
+ s->machine.devices[index] = malloc(sizeof *s->machine.devices[index]);
+ rc |= adder(&s->machine.devices[index]);
+ }
+ }
+
+ // if RTLD_NODELETE worked and were standard, we would dlclose() here
+ } else break;
+
+ inst++;
+ } while (!rc);
+
+ return rc;
+}
+
static int recipe_prealloc(struct sim_state *s)
{
int ram_add_device(struct device **device);
@@ -92,14 +155,6 @@ static int recipe_serial(struct sim_state *s)
return serial_add_device(&s->machine.devices[index]);
}
-static int recipe_spi(struct sim_state *s)
-{
- int spi_add_device(struct device **device);
- int index = next_device(s);
- s->machine.devices[index] = malloc(sizeof *s->machine.devices[index]);
- return spi_add_device(&s->machine.devices[index]);
-}
-
static int recipe_nowrap(struct sim_state *s)
{
s->conf.nowrap = 1;
@@ -145,12 +200,13 @@ static int dispatch_op(void *ud, int op, uint32_t addr, uint32_t *data)
// TODO don't send in the whole simulator state ? the op should have
// access to some state, in order to redispatch and potentially use other
// machine.devices, but it shouldn't see the whole state
- return (*device)->op(s, (*device)->cookie, op, addr, data);
+ return (*device)->ops.op((*device)->cookie, op, addr, data);
}
-static const char shortopts[] = "a:df:np:r:s:vhV";
+static const char shortopts[] = "@:a:df:np:r:s:vhV";
static const struct option longopts[] = {
+ { "options" , required_argument, NULL, '@' },
{ "address" , required_argument, NULL, 'a' },
{ "debug" , no_argument, NULL, 'd' },
{ "format" , required_argument, NULL, 'f' },
@@ -183,6 +239,7 @@ static int usage(const char *me)
printf("Usage: %s [ OPTIONS ] image-file\n"
"Options:\n"
+ " -@, --options=X use options from file X\n"
" -a, --address=N load instructions into memory at word address N\n"
" -d, --debug start the simulator in debugger mode\n"
" -f, --format=F select input format (%s)\n"
@@ -242,15 +299,15 @@ static int devices_finalise(struct sim_state *s)
for (unsigned i = 0; i < s->machine.devices_count; i++)
if (s->machine.devices[i])
- s->machine.devices[i]->init(s, &s->machine.devices[i]->cookie);
+ s->machine.devices[i]->ops.init(&s->conf.gops, &s->plugin_cookie, &s->machine.devices[i]->cookie, 0);
return 0;
}
static int devices_teardown(struct sim_state *s)
{
for (unsigned i = 0; i < s->machine.devices_count; i++) {
- s->machine.devices[i]->fini(s, s->machine.devices[i]->cookie);
+ s->machine.devices[i]->ops.fini(s->machine.devices[i]->cookie);
free(s->machine.devices[i]);
}
@@ -262,8 +319,8 @@ static int devices_teardown(struct sim_state *s)
static int devices_dispatch_cycle(struct sim_state *s)
{
for (size_t i = 0; i < s->machine.devices_count; i++)
- if (s->machine.devices[i]->cycle)
- if (s->machine.devices[i]->cycle(s, s->machine.devices[i]->cookie))
+ if (s->machine.devices[i]->ops.cycle)
+ if (s->machine.devices[i]->ops.cycle(s->machine.devices[i]->cookie))
return 1;
return 0;
@@ -552,87 +609,76 @@ static int post_insn(struct sim_state *s, struct instruction *i)
return devices_dispatch_cycle(s);
}
-int set_format(struct sim_state *s, const char *optarg, const struct format **f)
+static int find_format(const char *optarg, const struct format **f)
{
size_t sz = formats_count;
- (void)s;
*f = lfind(&(struct format){ .name = optarg }, formats, &sz,
sizeof formats[0], find_format_by_name);
return !*f;
}
-void param_free(struct param_entry *p)
-{
- free(p->key);
- if (p->free_value)
- free(p->value);
-}
-
-int params_cmp(const void *_a, const void *_b)
-{
- const struct param_entry *a = _a,
- *b = _b;
-
- return strcmp(a->key, b->key);
-}
+static int parse_args(struct sim_state *s, int argc, char *argv[]);
-int param_get(struct sim_state *s, char *key, const char **val)
+static int parse_opts_file(struct sim_state *s, const char *filename)
{
- struct param_entry p = { .key = key };
+ FILE *f = fopen(filename, "r");
+ if (!f)
+ fatal(PRINT_ERRNO, "Options file '%s' not found", filename);
- struct param_entry *q = lfind(&p, s->conf.params, &s->conf.params_count,
- sizeof *s->conf.params, params_cmp);
+ char buf[1024], *p;
+ while ((p = fgets(buf, sizeof buf, f))) {
+ // trim newline
+ int len = strlen(buf);
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
- if (!q)
- return 0;
+ int oi = optind;
+ optind = 0;
+ char *pbuf[] = { NULL, buf, NULL };
+ parse_args(s, 2, pbuf);
+ optind = oi;
+ }
- *val = q->value;
+ int e = ferror(f);
+ fclose(f);
- return 1;
+ return e;
}
-int param_set(struct sim_state *s, char *key, char *val, int free_value)
+static int parse_args(struct sim_state *s, int argc, char *argv[])
{
- while (s->conf.params_size <= s->conf.params_count)
- // technically there is a problem here if realloc() fails
- s->conf.params = realloc(s->conf.params,
- (s->conf.params_size *= 2) * sizeof *s->conf.params);
-
- struct param_entry p = {
- .key = key,
- .value = val,
- .free_value = free_value,
- };
-
- struct param_entry *q = lsearch(&p, s->conf.params, &s->conf.params_count,
- sizeof *s->conf.params, params_cmp);
-
- if (!q)
- return 1;
+ int ch;
+ while ((ch = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
+ switch (ch) {
+ case 'a': s->conf.load_addr = strtol(optarg, NULL, 0); break;
+ case 'd': s->conf.debugging = 1; break;
+ case 'f': if (find_format(optarg, &s->conf.fmt)) exit(usage(argv[0])); break;
+ case '@': if (parse_opts_file(s, optarg)) fatal(PRINT_ERRNO, "Error in opts file"); break;
+ case 'n': s->conf.run_defaults = 0; break;
+ case 'p': param_add(&s->conf.params, optarg); break;
+ case 'r': add_recipe(s, optarg); break;
+ case 's': s->conf.start_addr = strtol(optarg, NULL, 0); break;
+ case 'v': s->conf.verbose++; break;
- if (q->key != p.key) {
- param_free(q);
- *q = p;
+ case 'V': puts(version()); exit(EXIT_SUCCESS);
+ case 'h': usage(argv[0]) ; exit(EXIT_SUCCESS);
+ default : usage(argv[0]) ; exit(EXIT_FAILURE);
+ }
}
return 0;
}
-int param_add(struct sim_state *s, const char *optarg)
+static int plugin_param_get(void *cookie, char *key, const char **val)
{
- // We can't use getsubopt() here because we don't know what all of our
- // options are ahead of time.
- char *dupped = strdup(optarg);
- char *eq = strchr(dupped, '=');
- if (!eq) {
- free(dupped);
- return 1;
- }
-
- // Replace '=' with '\0' to split string in two
- *eq = '\0';
+ struct plugin_cookie *c = cookie;
+ return param_get(c->param, key, val);
+}
- return param_set(s, dupped, ++eq, 0);
+static int plugin_param_set(void *cookie, char *key, char *val, int free_value)
+{
+ struct plugin_cookie *c = cookie;
+ return param_set(c->param, key, val, free_value);
}
int main(int argc, char *argv[])
@@ -644,11 +690,25 @@ int main(int argc, char *argv[])
.verbose = 0,
.run_defaults = 1,
.debugging = 0,
- .params_size = DEFAULT_PARAMS_COUNT,
- .params_count = 0,
- .params = calloc(DEFAULT_PARAMS_COUNT, sizeof *_s.conf.params),
+ .start_addr = RAM_BASE,
+ .load_addr = RAM_BASE,
+ .fmt = &formats[0],
+ .params = {
+ .params_size = DEFAULT_PARAMS_COUNT,
+ .params_count = 0,
+ .params = calloc(DEFAULT_PARAMS_COUNT, sizeof *_s.conf.params.params),
+ },
+ .gops = {
+ .fatal = fatal_,
+ .debug = debug_,
+ .param_get = plugin_param_get,
+ .param_set = plugin_param_set,
+ },
},
.dispatch_op = dispatch_op,
+ .plugin_cookie = {
+ .param = &_s.conf.params,
+ },
}, *s = &_s;
if ((rc = setjmp(errbuf))) {
@@ -657,27 +717,7 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
- int load_address = RAM_BASE, start_address = RAM_BASE;
-
- const struct format *f = &formats[0];
-
- int ch;
- while ((ch = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
- switch (ch) {
- case 'a': load_address = strtol(optarg, NULL, 0); break;
- case 'd': s->conf.debugging = 1; break;
- case 'f': if (set_format(s, optarg, &f)) exit(usage(argv[0])); break;
- case 'n': s->conf.run_defaults = 0; break;
- case 'p': param_add(s, optarg); break;
- case 'r': add_recipe(s, optarg); break;
- case 's': start_address = strtol(optarg, NULL, 0); break;
- case 'v': s->conf.verbose++; break;
-
- case 'V': puts(version()); return EXIT_SUCCESS;
- case 'h': usage(argv[0]) ; return EXIT_SUCCESS;
- default : usage(argv[0]) ; return EXIT_FAILURE;
- }
- }
+ parse_args(s, argc, argv);
if (optind >= argc) {
fatal(DISPLAY_USAGE, "No input files specified on the command line");
@@ -702,8 +742,8 @@ int main(int argc, char *argv[])
run_recipes(s);
devices_finalise(s);
- load_sim(s->dispatch_op, s, f, in, load_address);
- s->machine.regs[15] = start_address & PTR_MASK;
+ load_sim(s->dispatch_op, s, s->conf.fmt, in, s->conf.load_addr);
+ s->machine.regs[15] = s->conf.start_addr & PTR_MASK;
struct run_ops ops = {
.pre_insn = pre_insn,
@@ -720,11 +760,7 @@ int main(int argc, char *argv[])
devices_teardown(s);
- while (s->conf.params_count--)
- param_free(&s->conf.params[s->conf.params_count]);
-
- free(s->conf.params);
- s->conf.params_size = 0;
+ param_destroy(&s->conf.params);
return rc;
}
View
9 test/jzrel.tas.cpp
@@ -0,0 +1,9 @@
+#include "common.th"
+
+ b <- 10
+top:
+ c <- b == 0
+ b <- b - 1
+ jzrel(c,top)
+done:
+ illegal

0 comments on commit e0eb8cf

Please sign in to comment.
Something went wrong with that request. Please try again.