diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-12-30 18:11:22 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-12-30 18:11:22 +0000 |
commit | c5ba5065cbf2b43101f4c311f56d55a0ff99bad6 (patch) | |
tree | 9474382abd0ef37493aeab7fc9026ae797105bb6 | |
parent | 041fcd3ad11b63569c9fa41946787bf9eb0d4276 (diff) | |
download | px4-nuttx-c5ba5065cbf2b43101f4c311f56d55a0ff99bad6.tar.gz px4-nuttx-c5ba5065cbf2b43101f4c311f56d55a0ff99bad6.tar.bz2 px4-nuttx-c5ba5065cbf2b43101f4c311f56d55a0ff99bad6.zip |
Z80 simulator
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@462 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | misc/sims/z80sim/example/Makefile | 44 | ||||
-rw-r--r-- | misc/sims/z80sim/example/example.asm | 84 | ||||
-rw-r--r-- | misc/sims/z80sim/src/Makefile | 32 | ||||
-rw-r--r-- | misc/sims/z80sim/src/Z80-081707.zip | bin | 0 -> 29532 bytes | |||
-rw-r--r-- | misc/sims/z80sim/src/main.c | 471 |
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 Binary files differnew file mode 100644 index 000000000..9a2339481 --- /dev/null +++ b/misc/sims/z80sim/src/Z80-081707.zip 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; +} |