summaryrefslogtreecommitdiff
path: root/misc/sims
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2007-12-30 18:11:22 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2007-12-30 18:11:22 +0000
commitc5ba5065cbf2b43101f4c311f56d55a0ff99bad6 (patch)
tree9474382abd0ef37493aeab7fc9026ae797105bb6 /misc/sims
parent041fcd3ad11b63569c9fa41946787bf9eb0d4276 (diff)
downloadnuttx-c5ba5065cbf2b43101f4c311f56d55a0ff99bad6.tar.gz
nuttx-c5ba5065cbf2b43101f4c311f56d55a0ff99bad6.tar.bz2
nuttx-c5ba5065cbf2b43101f4c311f56d55a0ff99bad6.zip
Z80 simulator
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@462 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'misc/sims')
-rw-r--r--misc/sims/z80sim/example/Makefile44
-rw-r--r--misc/sims/z80sim/example/example.asm84
-rw-r--r--misc/sims/z80sim/src/Makefile32
-rw-r--r--misc/sims/z80sim/src/Z80-081707.zipbin0 -> 29532 bytes
-rw-r--r--misc/sims/z80sim/src/main.c471
5 files changed, 631 insertions, 0 deletions
diff --git a/misc/sims/z80sim/example/Makefile b/misc/sims/z80sim/example/Makefile
new file mode 100644
index 000000000..1b12d3d75
--- /dev/null
+++ b/misc/sims/z80sim/example/Makefile
@@ -0,0 +1,44 @@
+AS = /usr/local/bin/as-z80
+ASFLAGS = -xlosp
+
+CPP = /usr/local/bin/sdcpp
+CPPFLAGS = -D__ASSEMBLY__
+
+CC = /usr/local/bin/sdcc
+CFLAGS = -mz80 --stack-auto --int-long-reent --float-reent
+
+LD = /usr/local/bin/link-z80
+LDFLAGS =
+
+ASMEXT = .asm
+OBJEXT = .rel
+LIBEXT = .lib
+EXEEXT = .hex
+
+ASRCS = example.asm
+AOBJS = $(ASRCS:$(ASMEXT)=$(OBJEXT))
+
+CSRCS =
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+SRCS = $(SSRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
+
+BIN = example$(EXEEXT)
+
+all: $(BIN)
+default: $(BIN)
+
+$(AOBJS): $(ASRCS)
+ $(AS) $(ASFLAGS) $@ $<
+
+$(COBJS) $(TESTOBJS): %$(OBJEXT): %.c
+ $(CC) -c $(CFLAGS) $< -o $@
+
+$(BIN): $(OBJS)
+ $(CC) $(LDFLAGS) $< -o $@
+
+clean:
+ @rm -f $(BIN) *.o *.rel *.lst *.sym *.adb *.ihx *.map *.mem *.rst *.lnk *~
+
+distclean: clean
diff --git a/misc/sims/z80sim/example/example.asm b/misc/sims/z80sim/example/example.asm
new file mode 100644
index 000000000..ae0fc4f41
--- /dev/null
+++ b/misc/sims/z80sim/example/example.asm
@@ -0,0 +1,84 @@
+;************************************************************************
+; example.s
+;************************************************************************
+
+ .title z80sim Test
+ .module example
+
+;************************************************************************
+; Constants
+;************************************************************************
+
+ STACKBASE == 0xFFFF
+
+;************************************************************************
+; Data
+;************************************************************************
+
+ .area DATA (ABS,OVR)
+ .org 0x8000
+hello:
+ .ascii "Hello, World!\n\0"
+
+;************************************************************************
+; Reset entry point
+;************************************************************************
+
+ .area TEXT (ABS,OVR)
+ .org 0x0000
+ di ; Disable interrupts
+ ld SP, #STACKBASE ; Set stack pointer
+ im 1 ; Set interrupt mode 1
+ jp start ; jump to start of program
+
+;************************************************************************
+; Interrupt handler
+;************************************************************************
+
+ .org 0x0038 ; Int mode 1
+ reti ; return from interrupt
+
+;************************************************************************
+; NMI interrupt handler
+;************************************************************************
+
+ .org 0x0066
+ retn
+
+;************************************************************************
+; Start of program
+;************************************************************************
+
+ .org 0x0100
+start:
+ ;ei ; Enable interrrupts
+ ld hl, #hello ; Say hello
+ call print
+
+forever: ; Then stop execution
+ jp forever
+
+;******************************************************************
+; print *
+; Funktion....: Sen tekst and data with serielport *
+; Input.......: hl points at text start adr *
+; Output......: Text to serielport *
+; uses........: a,hl*
+; call........: TX_BUSY tst 28-4-1994 *
+;******************************************************************
+
+print:
+ push af
+loop:
+ ld a, (hl) ; Get character to print
+ cp #0 ; Null terminates the string
+ jp z, done
+
+ out (0xbe), a ; Send character
+ inc hl ; Increment to next character
+ jp loop ; Loop til done
+done:
+ pop af
+ ret
+
+
diff --git a/misc/sims/z80sim/src/Makefile b/misc/sims/z80sim/src/Makefile
new file mode 100644
index 000000000..c673f5803
--- /dev/null
+++ b/misc/sims/z80sim/src/Makefile
@@ -0,0 +1,32 @@
+CC = gcc
+CFLAGS = -g -Wall -IZ80 -DLSB_FIRST=1 -DDEBUG=1 -DJUMPZ80
+
+LD = gcc
+LDFLAGS =
+
+SRCS = main.c Debug.c Z80.c
+OBJS = $(SRCS:.c=.o)
+
+BIN = z80sim
+
+VPATH = Z80
+
+all: $(BIN)
+default: $(BIN)
+
+$(OBJS): %.o: %.c
+ $(CC) -c $(CFLAGS) $< -o $@
+
+
+Z80: Z80-081707.zip
+ unzip Z80-081707.zip
+
+z80sim: Z80 $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS) -o $@
+
+clean:
+ @rm -f $(BIN) *.o *.rel *.asm *.lst *.sym *.adb *~
+
+distclean: clean
+ rm -rf Z80
+
diff --git a/misc/sims/z80sim/src/Z80-081707.zip b/misc/sims/z80sim/src/Z80-081707.zip
new file mode 100644
index 000000000..9a2339481
--- /dev/null
+++ b/misc/sims/z80sim/src/Z80-081707.zip
Binary files differ
diff --git a/misc/sims/z80sim/src/main.c b/misc/sims/z80sim/src/main.c
new file mode 100644
index 000000000..0f42f230c
--- /dev/null
+++ b/misc/sims/z80sim/src/main.c
@@ -0,0 +1,471 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "Z80.h"
+
+/* This is the simulated z80 16-bit address space */
+
+static unsigned char memory[65536];
+
+/* This is the simulatin execution context */
+
+static Z80 gR;
+
+/* Command line options */
+
+static int gtrace = 0;
+static const char *gfilename = NULL;
+
+/* Name: RdZ80 and WrZ80
+ * Description: These functions are called when access to RAM occurs.
+ * They allow to control memory access.
+ */
+
+void WrZ80(register word Addr, register byte Value)
+{
+ memory[Addr] = Value;
+}
+
+byte RdZ80(register word Addr)
+{
+ return memory[Addr];
+}
+
+/* Name: InZ80 and OutZ80
+ * Description: Z80 emulation calls these functions to read/write from
+ * I/O ports. There can be 65536 I/O ports, but only first
+ * 256 are usually used.
+ */
+
+void OutZ80(register word Port,register byte Value)
+{
+ /* We recognize only one port, 0xbe, which is mapped to stdout */
+
+ if ((Port & 0x00ff) == 0xbe)
+ {
+ putchar(Value);
+ fflush(stdout);
+ }
+}
+
+byte InZ80(register word Port)
+{
+ /* We recognize only one port, 0xbe, which is mapped to stdin */
+
+ if ((Port & 0x00ff) == 0xbe)
+ {
+ return getchar();
+ }
+ return 0;
+}
+
+/* Name: PatchZ80
+ * Description: Z80 emulation calls this function when it encounters a
+ * special patch command (ED FE) provided for user needs.
+ * For example, it can be called to emulate BIOS calls,
+ * such as disk and tape access. Replace it with an empty
+ * macro for no patching.
+ */
+
+void PatchZ80(register Z80 *R)
+{
+}
+
+/* Name: LoopZ80
+ * Description: Z80 emulation calls this function periodically to check
+ * if the system hardware requires any interrupts. This
+ * function must return an address of the interrupt vector
+ * (0x0038, 0x0066, etc.) or INT_NONE for no interrupt.
+ * Return INT_QUIT to exit the emulation loop.
+ */
+
+word LoopZ80(register Z80 *R)
+{
+ return INT_NONE;
+}
+
+/* Name: JumpZ80
+ * Description: Z80 emulation calls this function when it executes a
+ * JP, JR, CALL, RST, or RET. You can use JumpZ80() to
+ * trap these opcodes and switch memory layout.
+ */
+
+#ifdef JUMPZ80
+void JumpZ80(word PC)
+{
+ if (gtrace)
+ {
+ printf("PC: %04x\n", PC);
+ }
+}
+#endif
+
+/* Intel hex code based largely on code taken from the PJRC website */
+
+/* Name: parse_hex
+ * Description: Parse one line from an Intel hex file
+ */
+
+static int parse_hex(const char *hex, unsigned char *binary, int *addr, int *nbytes, int *code)
+{
+ const char *ptr;
+ int accum;
+ int chksum;
+ int len;
+
+ *nbytes = 0;
+
+ /* Each valid hex begins with a colon */
+
+ ptr = hex;
+ if (*hex != ':')
+ {
+ return 0;
+ }
+ ptr++;
+
+ /* The minimun size is ':'(1) + (0) + addr(4) + type(2) + data(2) + chechksum(2) = 11 */
+
+ if (strlen(hex) < 11)
+ {
+ return 0;
+ }
+
+ /* Get the length byte */
+
+ if (!sscanf(ptr, "%02x", &len))
+ {
+ return 0;
+ }
+ ptr += 2;
+
+ /* Now verify the length is ':'(1) + l2*len + addr(4) + type(2) + data(2) + chechksum(2) */
+
+ if (strlen(hex) < (11 + (2*len)))
+ {
+ return 0;
+ }
+
+ /* Get the address */
+
+ if (!sscanf(ptr, "%04x", addr))
+ {
+ return 0;
+ }
+ ptr += 4;
+
+ /* Get the code byte */
+
+ if (!sscanf(ptr, "%02x", code))
+ {
+ return 0;
+ }
+ ptr += 2;
+
+ /* Copy the data and calculate the chechksum */
+
+ accum = len + (*addr >> 8) + *addr + *code;
+ while (*nbytes < len)
+ {
+ int tmp;
+
+ /* Get the next data byte */
+
+ if (!sscanf(ptr, "%02x", &tmp))
+ {
+ return 0;
+ }
+ ptr += 2;
+
+ /* Transfer the data to the user binary */
+
+ binary[*nbytes] = tmp;
+
+ /* Update the accum */
+
+ accum += binary[*nbytes];
+ (*nbytes)++;
+ }
+
+ /* Get the checksum */
+
+ if (!sscanf(ptr, "%02x", &chksum))
+ {
+ return 0;
+ }
+
+ /* Verify the checksum */
+
+ if (((accum + chksum) & 0xff) != 0)
+ {
+ return 0;
+ }
+ return 1;
+}
+
+/* Name: load_file
+ * Description: Read an entire Intel hex file into (simulated) z80 memory
+ */
+
+int load_file(const char *filename)
+{
+ char hex[1000];
+ FILE *stream;
+ unsigned char binary[256];
+ int i;
+ int total = 0;
+ int lineno = 1;
+ int minaddr = 65536;
+ int maxaddr = 0;
+ int addr;
+ int nbytes;
+ int status;
+
+ /* Open the ascii hex file */
+
+ stream = fopen(filename, "r");
+ if (stream == NULL)
+ {
+ printf("ERROR: Failed to open file '%s' for reading: %s\n", filename, strerror(errno));
+ return 0;
+ }
+
+ /* Loop until every line has been read */
+
+ while (!feof(stream) && !ferror(stream))
+ {
+ /* Read the next line from the Intel hex file */
+
+ hex[0] = '\0';
+ fgets(hex, 1000, stream);
+
+ /* Remove any trailing CR/LF */
+
+ if (hex[strlen(hex)-1] == '\n')
+ {
+ hex[strlen(hex)-1] = '\0';
+ }
+
+ if (hex[strlen(hex)-1] == '\r')
+ {
+ hex[strlen(hex)-1] = '\0';
+ }
+
+ /* Parse the hex line */
+
+ if (parse_hex(hex, binary, &addr, &nbytes, &status))
+ {
+ /* Valid data? */
+
+ if (status == 0)
+ {
+ /* Yes.. move it into the z80 memory image */
+
+ for (i = 0; i <= (nbytes-1); i++)
+ {
+ memory[addr] = binary[i];
+ total++;
+
+ /* Keep track of the highest and lowest addresses written */
+
+ if (addr < minaddr)
+ {
+ minaddr = addr;
+ }
+
+ if (addr > maxaddr)
+ {
+ maxaddr = addr;
+ }
+ addr++;
+ }
+ }
+
+ /* End of file? */
+
+ else if (status == 1)
+ {
+ fclose(stream);
+ printf("Loaded %d bytes between %04x to %04x\n", total, minaddr, maxaddr);
+ return 1;
+ }
+ else if (status != 2) /* begin of file */
+ {
+ printf("ERROR: Unrecognized status=%d at line=%d\n", status, lineno);
+ return 0;
+ }
+ }
+ else
+ {
+ printf("ERROR: Failed to parse %s at line: %d\n", filename, lineno);
+ return 0;
+ }
+ lineno++;
+ }
+ printf("ERROR: No end of file marker encountered in %s\n", filename);
+ return 0;
+}
+
+/* Name: sighandler
+ * Description: Catch program termination via control-C
+ */
+
+void sighandler(int signo)
+{
+ char command[80];
+ int i;
+ int j;
+
+ printf("AF:%04X HL:%04X DE:%04X BC:%04X PC:%04X SP:%04X IX:%04X IY:%04X I:%02X\n",
+ gR.AF.W, gR.HL.W, gR.DE.W, gR.BC.W, gR.PC.W, gR.SP.W, gR.IX.W, gR.IY.W, gR.I);
+
+ printf("AT PC: [%02X] AT SP: [%04X] %s: %s\n",
+ RdZ80(gR.PC.W), RdZ80(gR.SP.W) + RdZ80(gR.SP.W+1) * 256,
+ gR.IFF & 0x04? "IM2" : gR.IFF & 0x02? "IM1" : "IM0",
+ gR.IFF & 0x01? "EI" : "DI");
+
+ for (;;)
+ {
+ printf("\n[Command,'?']-> ");
+ fflush(stdout);
+ fflush(stdin);
+
+ fgets(command, 50, stdin);
+
+ switch(command[0])
+ {
+ case 'H':
+ case 'h':
+ case '?':
+ puts("\n***** Built-in Z80 Debugger Commands *****");
+ puts("m <addr> : Memory dump at addr");
+ puts("?,h : Show this help text");
+ puts("q : Exit Z80 emulation");
+ break;
+
+ case 'M':
+ case 'm':
+ {
+ unsigned short addr;
+
+ if (strlen(command) > 1)
+ {
+ sscanf(command+1, "%hX", &addr);
+ }
+ else
+ {
+ addr = gR.PC.W;
+ }
+
+ puts("");
+ for (j = 0; j < 16; j++)
+ {
+ printf("%04X: ",addr);
+ for (i = 0; i < 16; i++, addr++)
+ {
+ printf("%02X ", memory[addr]);
+ }
+ printf(" | ");
+ addr -= 16;
+ for (i = 0; i < 16; i++, addr++)
+ {
+ putchar(isprint(memory[addr])? memory[addr]:'.');
+ }
+ puts("");
+ }
+ }
+ break;
+
+ case 'Q':
+ case 'q':
+ exit(0);
+ }
+ }
+ exit(0);
+}
+
+static void show_usage(const char *progname, int exitcode)
+{
+ fprintf(stderr, "\nUSAGE: %s [OPTIONS] <Intel-Hex-File>\n", progname);
+ fprintf(stderr, "\nWhere [OPTIONS] include:\n");
+ fprintf(stderr, "\n\t-t\tEnable trace output\n");
+ fprintf(stderr, "\t-h\tShow this message\n");
+ exit(exitcode);
+}
+
+static void parse_commandline(int argc, char **argv)
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, ":th")) != -1)
+ {
+ switch (opt)
+ {
+ case 't':
+ gtrace++;
+ break;
+ case 'h':
+ show_usage(argv[0], 0);
+ break;
+ case '?':
+ fprintf(stderr, "ERROR: Unrecognized option: %c\n", optopt);
+ show_usage(argv[0], 1);
+ break;
+ case ':':
+ fprintf(stderr, "ERROR: Missing argument to option: %c\n", optopt);
+ show_usage(argv[0], 1);
+ break;
+ }
+ }
+
+ if (optind >= argc)
+ {
+ fprintf(stderr, "ERROR: Missing filename argument\n");
+ show_usage(argv[0], 1);
+ }
+
+ gfilename = argv[optind];
+ optind++;
+
+ if (optind < argc)
+ {
+ fprintf(stderr, "ERROR: Extra stuff on command line after filename\n");
+ show_usage(argv[0], 1);
+ }
+}
+
+/* Name: main
+ * Description: Program entry point
+ */
+
+int main(int argc, char **argv, char **envp)
+{
+ /* Parse the command line options */
+
+ parse_commandline(argc, argv);
+
+ /* Set all simulated z80 memory to a known value and load the Intel hex file */
+
+ memset(memory, 0, 65536);
+ load_file(gfilename);
+
+ /* Configure the simulation */
+
+ memset(&gR, 0, sizeof(Z80));
+ gR.IPeriod = 10000; /* 100Hz at 10MHz */
+ gR.IAutoReset = 1;
+
+ /* Set up to catch SIGINT (control-C from console) */
+
+ (void)signal(SIGINT, sighandler);
+
+ /* Then start the simulation */
+
+ RunZ80(&gR);
+ return 0;
+}