diff --git a/doc/sim65.sgml b/doc/sim65.sgml
index 310de4667..b1e5afbdc 100644
--- a/doc/sim65.sgml
+++ b/doc/sim65.sgml
@@ -44,6 +44,13 @@ The simulator is called as follows:
--version Print the simulator version number
+sim65 will exit with the error code of the simulated program,
+which is limited to an 8-bit result 0-255.
+
+An error in sim65, like bad arguments or an internal problem will exit with Command line options in detail
@@ -126,9 +133,17 @@ a set of built-in paravirtualization functions ([Creating a Test in Assembly]
Assembly tests may similarly be assembled and linked with
-
+
+- Return from
The binary file has a 12 byte header:
diff --git a/src/sim65/6502.c b/src/sim65/6502.c
index 6c23b0dfc..9d2c93da8 100644
--- a/src/sim65/6502.c
+++ b/src/sim65/6502.c
@@ -64,18 +64,12 @@ static CPURegs Regs;
/* Cycles for the current insn */
static unsigned Cycles;
-/* Total number of CPU cycles exec'd */
-static unsigned long TotalCycles;
-
/* NMI request active */
static unsigned HaveNMIRequest;
/* IRQ request active */
static unsigned HaveIRQRequest;
-/* flag to print cycles at program termination */
-int PrintCycles;
-
/*****************************************************************************/
/* Helper functions and macros */
@@ -3277,18 +3271,6 @@ unsigned ExecuteInsn (void)
Handlers[CPU][OPC] ();
}
- /* Count cycles */
- TotalCycles += Cycles;
-
/* Return the number of clock cycles needed by this insn */
return Cycles;
}
-
-
-
-unsigned long GetCycles (void)
-/* Return the total number of cycles executed */
-{
- /* Return the total number of cycles */
- return TotalCycles;
-}
diff --git a/src/sim65/6502.h b/src/sim65/6502.h
index f8e894567..39b995793 100644
--- a/src/sim65/6502.h
+++ b/src/sim65/6502.h
@@ -96,12 +96,6 @@ unsigned ExecuteInsn (void);
** executed instruction.
*/
-unsigned long GetCycles (void);
-/* Return the total number of clock cycles executed */
-
-extern int PrintCycles;
-/* flag to print cycles at program termination */
-
/* End of 6502.h */
diff --git a/src/sim65/error.c b/src/sim65/error.c
index 441b07d2a..fc24ca006 100644
--- a/src/sim65/error.c
+++ b/src/sim65/error.c
@@ -41,6 +41,20 @@
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* flag to print cycles at program termination */
+int PrintCycles = 0;
+
+/* cycles are counted by main.c */
+extern unsigned long long TotalCycles;
+
+
+
/*****************************************************************************/
/* Code */
/*****************************************************************************/
@@ -99,3 +113,14 @@ void Internal (const char* Format, ...)
va_end (ap);
exit (SIM65_ERROR);
}
+
+
+
+void SimExit (int Code)
+/* Exit the simulation with an exit code */
+{
+ if (PrintCycles) {
+ fprintf (stdout, "%llu cycles\n", TotalCycles);
+ }
+ exit (Code);
+}
diff --git a/src/sim65/error.h b/src/sim65/error.h
index ea54fa048..6dbee974c 100644
--- a/src/sim65/error.h
+++ b/src/sim65/error.h
@@ -49,12 +49,17 @@
-#define SIM65_ERROR 0x7F
-/* Does not use EXIT_FAILURE because it may overlap with test results. */
+#define SIM65_ERROR -1
+/* An error result for errors that are not part of the simulated test.
+** Note that set simulated test can only return 8-bit errors 0-255.
+*/
-#define SIM65_ERROR_TIMEOUT 0x7E
+#define SIM65_ERROR_TIMEOUT -2
/* An error result for max CPU instructions exceeded. */
+extern int PrintCycles;
+/* flag to print cycles at program termination */
+
/*****************************************************************************/
@@ -75,6 +80,9 @@ void ErrorCode (int Code, const char* Format, ...) attribute((noreturn, format(p
void Internal (const char* Format, ...) attribute((noreturn, format(printf,1,2)));
/* Print an internal error message and die */
+void SimExit (int Code);
+/* Exit the simulation with an exit code */
+
/* End of error.h */
diff --git a/src/sim65/main.c b/src/sim65/main.c
index d92d52ef6..3c7cdc157 100644
--- a/src/sim65/main.c
+++ b/src/sim65/main.c
@@ -36,7 +36,6 @@
#include
#include
#include
-#include
/* common */
#include "abend.h"
@@ -61,14 +60,14 @@
/* Name of program file */
const char* ProgramFile;
-/* exit simulator after MaxCycles Cycles */
-unsigned long MaxCycles;
+/* count of total cycles executed */
+unsigned long long TotalCycles = 0;
-/* maximum number of cycles that can be tested,
-** requires overhead for longest possible instruction,
-** which should be 7, using 16 for safety.
-*/
-#define MAXCYCLES_LIMIT (ULONG_MAX-16)
+/* exit simulator after MaxCycles Cccles */
+unsigned long long MaxCycles = 0;
+
+/* countdown from MaxCycles */
+unsigned long long RemainCycles;
/* Header signature 'sim65' */
static const unsigned char HeaderSignature[] = {
@@ -145,11 +144,7 @@ static void OptQuitXIns (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
/* quit after MaxCycles cycles */
{
- MaxCycles = strtoul(Arg, NULL, 0);
- /* Guard against overflow. */
- if (MaxCycles >= MAXCYCLES_LIMIT) {
- Error("'-x parameter out of range. Max: %lu",MAXCYCLES_LIMIT);
- }
+ MaxCycles = strtoull(Arg, NULL, 0);
}
static unsigned char ReadProgramFile (void)
@@ -247,6 +242,7 @@ int main (int argc, char* argv[])
unsigned I;
unsigned char SPAddr;
+ unsigned int Cycles;
/* Initialize the cmdline module */
InitCmdLine (&argc, &argv, "sim65");
@@ -309,18 +305,24 @@ int main (int argc, char* argv[])
MemInit ();
SPAddr = ReadProgramFile ();
-
ParaVirtInit (I, SPAddr);
Reset ();
+ RemainCycles = MaxCycles;
while (1) {
- ExecuteInsn ();
- if (MaxCycles && (GetCycles () >= MaxCycles)) {
- ErrorCode (SIM65_ERROR_TIMEOUT, "Maximum number of cycles reached.");
+ Cycles = ExecuteInsn ();
+ TotalCycles += Cycles;
+ if (MaxCycles) {
+ if (Cycles > RemainCycles) {
+ ErrorCode (SIM65_ERROR_TIMEOUT, "Maximum number of cycles reached.");
+ }
+ RemainCycles -= Cycles;
}
}
- /* Return an apropriate exit code */
- return EXIT_SUCCESS;
+ /* Unreachable. sim65 program must exit through paravirtual PVExit
+ ** or timeout from MaxCycles producing an error.
+ */
+ return SIM65_ERROR;
}
diff --git a/src/sim65/paravirt.c b/src/sim65/paravirt.c
index 0b16f89e9..2e52d6e7e 100644
--- a/src/sim65/paravirt.c
+++ b/src/sim65/paravirt.c
@@ -124,11 +124,7 @@ static unsigned PopParam (unsigned char Incr)
static void PVExit (CPURegs* Regs)
{
Print (stderr, 1, "PVExit ($%02X)\n", Regs->AC);
- if (PrintCycles) {
- Print (stdout, 0, "%lu cycles\n", GetCycles ());
- }
-
- exit (Regs->AC);
+ SimExit (Regs->AC); /* Error code in range 0-255. */
}
diff --git a/test/asm/Makefile b/test/asm/Makefile
index 3481dae78..dea53f6b2 100644
--- a/test/asm/Makefile
+++ b/test/asm/Makefile
@@ -12,7 +12,7 @@ endif
WORKDIR = ../testwrk/asm
-SUBDIRS = cpudetect opcodes listing val err
+SUBDIRS = cpudetect opcodes listing val err misc
.PHONY: all continue mostlyclean clean
diff --git a/test/asm/misc/Makefile b/test/asm/misc/Makefile
new file mode 100644
index 000000000..5a9d4f3ef
--- /dev/null
+++ b/test/asm/misc/Makefile
@@ -0,0 +1,70 @@
+# Makefile for the remaining asm tests that need special care in one way or another
+
+ifneq ($(shell echo),)
+ CMD_EXE = 1
+endif
+
+ifdef CMD_EXE
+ S = $(subst /,\,/)
+ NOT = - # Hack
+ EXE = .exe
+ NULLDEV = nul:
+ MKDIR = mkdir $(subst /,\,$1)
+ RMDIR = -rmdir /s /q $(subst /,\,$1)
+else
+ S = /
+ NOT = !
+ EXE =
+ NULLDEV = /dev/null
+ MKDIR = mkdir -p $1
+ RMDIR = $(RM) -r $1
+endif
+
+ifdef QUIET
+ .SILENT:
+ NULLOUT = >$(NULLDEV)
+ NULLERR = 2>$(NULLDEV)
+endif
+
+SIM65FLAGS = -x 200000000
+
+CA65 := $(if $(wildcard ../../../bin/ca65*),..$S..$S..$Sbin$Sca65,ca65)
+LD65 := $(if $(wildcard ../../../bin/ld65*),..$S..$S..$Sbin$Sld65,ld65)
+SIM65 := $(if $(wildcard ../../../bin/sim65*),..$S..$S..$Sbin$Ssim65,sim65)
+
+WORKDIR = ..$S..$S..$Stestwrk$Sasm$Smisc
+
+.PHONY: all clean
+
+SOURCES := $(wildcard *.s)
+TESTS = $(SOURCES:%.s=$(WORKDIR)/%.6502.prg)
+TESTS += $(SOURCES:%.s=$(WORKDIR)/%.65c02.prg)
+
+all: $(TESTS)
+
+$(WORKDIR):
+ $(call MKDIR,$(WORKDIR))
+
+define PRG_template
+
+# sim65 ensure 64-bit wait time does not timeout
+$(WORKDIR)/sim65-timein.$1.prg: sim65-timein.s | $(WORKDIR)
+ $(if $(QUIET),echo misc/sim65-timein.$1.prg)
+ $(CA65) -t sim$1 -o $$(@:.prg=.o) $$< $(NULLERR)
+ $(LD65) -t sim$1 -o $$@ $$(@:.prg=.o) sim$1.lib $(NULLERR)
+ $(SIM65) -x 4400000000 -c $$@ $(NULLOUT) $(NULLERR)
+
+# sim65 ensure 64-bit wait time does timeout
+$(WORKDIR)/sim65-timeout.$1.prg: sim65-timeout.s | $(WORKDIR)
+ $(if $(QUIET),echo misc/sim65-timeout.$1.prg)
+ $(CA65) -t sim$1 -o $$(@:.prg=.o) $$< $(NULLERR)
+ $(LD65) -t sim$1 -o $$@ $$(@:.prg=.o) sim$1.lib $(NULLERR)
+ $(NOT) $(SIM65) -x 4400000000 -c $$@ $(NULLOUT) $(NULLERR)
+
+endef # PRG_template
+
+$(eval $(call PRG_template,6502))
+$(eval $(call PRG_template,65c02))
+
+clean:
+ @$(call RMDIR,$(WORKDIR))
diff --git a/test/asm/misc/sim65-time-wait.inc b/test/asm/misc/sim65-time-wait.inc
new file mode 100644
index 000000000..bc761ac16
--- /dev/null
+++ b/test/asm/misc/sim65-time-wait.inc
@@ -0,0 +1,55 @@
+; Shared timer for:
+; sim65-timein.s
+; sim65-timeout.s
+
+; wait A * 100,000,000 cycles, plus small amount of overhead
+wait100m:
+ tay
+ bne :+
+ rts ; return quickly if A=0
+:
+ jsr wait50331648 ; 50331648
+ jsr wait25165824 ; 75497472
+ jsr wait12582912 ; 88080384
+ jsr wait6291456 ; 94371840
+ jsr wait3145728 ; 97517568
+ jsr wait1572864 ; 99090432
+ jsr wait786432 ; 99876864
+ jsr wait98304 ; 99975168
+ jsr wait24576 ; 99999744
+ jsr wait192 ; 99999936
+ jsr wait48 ; 99999984
+ nop ; 99999986
+ nop ; 99999988
+ php ; 99999991
+ plp ; 99999995
+ dey ; 99999997
+ bne :- ; 100000000
+ rts
+; Note that this branch could cross a page if poorly aligned,
+; adding an additional 1 cycle per loop.
+; This precision is not important for the tests used.
+
+wait50331648: jsr wait25165824
+wait25165824: jsr wait12582912
+wait12582912: jsr wait6291456
+wait6291456: jsr wait3145728
+wait3145728: jsr wait1572864
+wait1572864: jsr wait786432
+wait786432: jsr wait393216
+wait393216: jsr wait196608
+wait196608: jsr wait98304
+wait98304: jsr wait49152
+wait49152: jsr wait24576
+wait24576: jsr wait12288
+wait12288: jsr wait6144
+wait6144: jsr wait3072
+wait3072: jsr wait1536
+wait1536: jsr wait768
+wait768: jsr wait384
+wait384: jsr wait192
+wait192: jsr wait96
+wait96: jsr wait48
+wait48: jsr wait24
+wait24: jsr wait12
+wait12: rts
diff --git a/test/asm/misc/sim65-timein.s b/test/asm/misc/sim65-timein.s
new file mode 100644
index 000000000..13365f0a8
--- /dev/null
+++ b/test/asm/misc/sim65-timein.s
@@ -0,0 +1,17 @@
+; Verifies that sim65 can handle 64-bit timeout counter.
+; sim65 sim65-timein.prg -x 4400000000
+
+.export _main
+.import exit
+
+_main:
+ ; wait ~4,300,000,000 cycles
+ lda #43
+ jsr wait100m
+ ; This is a positive test.
+ ; If the timeout did not occur, returning 0 reports success.
+ lda #0
+ rts
+
+; wait100m
+.include "sim65-time-wait.inc"
diff --git a/test/asm/misc/sim65-timeout.s b/test/asm/misc/sim65-timeout.s
new file mode 100644
index 000000000..6f1778dcd
--- /dev/null
+++ b/test/asm/misc/sim65-timeout.s
@@ -0,0 +1,17 @@
+; Verifies that sim65 can handle 64-bit timeout counter.
+; sim65 sim65-timeout.prg -x 4400000000
+
+.export _main
+.import exit
+
+_main:
+ ; wait ~4,500,000,000 cycles
+ lda #45
+ jsr wait100m
+ ; This is a negative test.
+ ; If the timeout did not occur, returning 0 reports failure.
+ lda #0
+ rts
+
+; wait100m
+.include "sim65-time-wait.inc"
diff --git a/test/asm/readme.txt b/test/asm/readme.txt
index 49b530d1c..9b716e60c 100644
--- a/test/asm/readme.txt
+++ b/test/asm/readme.txt
@@ -36,3 +36,9 @@ val:
Runtime assembly tests using sim65 that should end with an exit code of 0 if
they pass. If they fail the exit code should be either -1, or a number
indicating what part of the test failed.
+
+
+misc:
+-----
+
+This is for tests that require special make steps or conditions.
diff --git a/test/asm/val/Makefile b/test/asm/val/Makefile
index 09a6b91bc..54b1100ec 100644
--- a/test/asm/val/Makefile
+++ b/test/asm/val/Makefile
@@ -22,7 +22,6 @@ ifdef QUIET
NULLERR = 2>$(NULLDEV)
endif
-# sim65 can support 64-bit cycle counts on some platforms, but not all. This must fit in 32-bit.
SIM65FLAGS = -x 4000000000
CA65 := $(if $(wildcard ../../../bin/ca65*),..$S..$S..$Sbin$Sca65,ca65)
diff --git a/test/standard/Makefile b/test/standard/Makefile
index 40299c1bf..bf513c84e 100644
--- a/test/standard/Makefile
+++ b/test/standard/Makefile
@@ -22,7 +22,6 @@ ifdef QUIET
NULLERR = 2>$(NULLDEV)
endif
-# sim65 can support 64-bit cycle counts on some platforms, but not all. This must fit in 32-bit.
SIM65FLAGS = -x 4000000000 -c
CC65 := $(if $(wildcard ../../bin/cc65*),..$S..$Sbin$Scc65,cc65)
diff --git a/test/val/Makefile b/test/val/Makefile
index 158967f9e..56d8e5ff9 100644
--- a/test/val/Makefile
+++ b/test/val/Makefile
@@ -24,7 +24,6 @@ ifdef QUIET
NULLERR = 2>$(NULLDEV)
endif
-# sim65 can support 64-bit cycle counts on some platforms, but not all. This must fit in 32-bit.
SIM65FLAGS = -x 4000000000 -c
CC65 := $(if $(wildcard ../../bin/cc65*),..$S..$Sbin$Scc65,cc65)