From c5ba5065cbf2b43101f4c311f56d55a0ff99bad6 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sun, 30 Dec 2007 18:11:22 +0000 Subject: Z80 simulator git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@462 42af7a65-404d-4744-a932-0658087f49c3 --- misc/sims/z80sim/example/Makefile | 44 ++++ misc/sims/z80sim/example/example.asm | 84 +++++++ misc/sims/z80sim/src/Makefile | 32 +++ misc/sims/z80sim/src/Z80-081707.zip | Bin 0 -> 29532 bytes misc/sims/z80sim/src/main.c | 471 +++++++++++++++++++++++++++++++++++ 5 files changed, 631 insertions(+) create mode 100644 misc/sims/z80sim/example/Makefile create mode 100644 misc/sims/z80sim/example/example.asm create mode 100644 misc/sims/z80sim/src/Makefile create mode 100644 misc/sims/z80sim/src/Z80-081707.zip create mode 100644 misc/sims/z80sim/src/main.c (limited to 'misc/sims') 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 Binary files /dev/null and b/misc/sims/z80sim/src/Z80-081707.zip 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 +#include +#include +#include +#include +#include +#include + +#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 : 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] \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; +} -- cgit v1.2.3