diff options
author | Ian C <ianc@noddybox.co.uk> | 2006-08-20 17:39:42 +0000 |
---|---|---|
committer | Ian C <ianc@noddybox.co.uk> | 2006-08-20 17:39:42 +0000 |
commit | 87ace20633ba711243e336630e2c9a8546516598 (patch) | |
tree | a9c624a08ae8ccc16086781fb009a6709b7a2913 /emma.c | |
parent | 2a5a38a8bd0295b841343062baec242d40267d93 (diff) |
This commit was generated by cvs2svn to compensate for changes in r2,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'emma.c')
-rw-r--r-- | emma.c | 1180 |
1 files changed, 1180 insertions, 0 deletions
@@ -0,0 +1,1180 @@ +/* + + EMMA - Z80 testbed + + Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + +*/ +static const char id[]="$Id$"; + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <signal.h> +#include <stdarg.h> + +#include "z80.h" +#include "expr.h" + + +#define TRUE 1 +#define FALSE 0 + +#define HI(w) (((w)&0xff00)>>8) +#define LO(w) ((w)&0xff) +#define MK(h,l) (((Z80Word)(h))<<8|(l)) + +/* ---------------------------------------- GLOBALS +*/ +static Z80 *z80; +static Z80Byte mem[0x10000]; +static sig_atomic_t stop=FALSE; +static int quit=FALSE; + +static int quiet_run=FALSE; +static int single_step=FALSE; +static int mem_trace=FALSE; + +static Z80Word bottom=0; +static Z80Word top=0xffff; + +static Z80Val int_raise=0; + +static Z80Label *label=NULL; + +static FILE *log=NULL; + + +/* ---------------------------------------- PROTOS +*/ +static void Log(const char *format, ...); +static void Run(char *p); +static Z80Word Address(const char *p); +static const char *GetLabel(Z80 *z80, Z80Word addr); + + +/* ---------------------------------------- SIGNALS +*/ +static void SigInt(int sig) +{ + stop=TRUE; + signal(SIGINT,SigInt); +} + + +/* ---------------------------------------- COMMANDS AND ASSOC UTILS +*/ +static void Log(const char *format, ...) +{ + static char buff[4096]; + + va_list va; + + va_start(va,format); + + vsprintf(buff,format,va); + + printf("%s",buff); + + if (log) + fprintf(log,"%s",buff); + + va_end(va); +} + + +static void *Malloc(size_t len) +{ + void *n; + + n=malloc(len); + + if (!n) + { + fprintf(stderr,"malloc failed\n"); + exit(EXIT_FAILURE); + } + + return n; +} + +static void *Realloc(void *p, size_t len) +{ + void *n; + + n=realloc(p,len); + + if (!n) + { + fprintf(stderr,"realloc failed\n"); + exit(EXIT_FAILURE); + } + + return n; +} + +static char *StrCopy(const char *p) +{ + return strcpy(Malloc(strlen(p)+1),p); +} + +static const int ToHex(char c) +{ + c=toupper(c); + + if (c>='0' && c<='9') + return c-'0'; + + if (c>='A' && c<='F') + return c-'A'+10; + + return 0; +} + +static const char *FlagString(Z80Byte flag) +{ + static char s[]="76543210"; + static char c[]="SZ5H3PNC"; + int f; + + for(f=0;f<8;f++) + if (flag&(1<<(7-f))) + s[f]=c[f]; + else + s[f]='-'; + + return s; +} + + +static void DisplayState(void) +{ + Z80State s; + + Z80GetState(z80,&s); + + Log("A=%2.2x F=%s ",s.AF>>8,FlagString(s.AF&0xff)); + Log("BC=%4.4x DE=%4.4x HL=%4.4x ",s.BC,s.DE,s.HL); + Log("IX=%4.4x IY=%4.4x SP=%4.4x\n",s.IX,s.IY,s.SP); + Log("I=%2.2x IM=%2.2x R=%2.2x ",s.I,s.IM,s.R); + Log("IFF1=%2.2x IFF2=%2.2x\n",s.IFF1,s.IFF2); + Log("%4.4x: ",s.PC); + Log("%s\n",Z80Disassemble(z80,&s.PC)); +} + + +static int StrEq(const char *a, const char *b) +{ + while(*a && *b && tolower(*a)==tolower(*b)) + { + a++; + b++; + } + + if (*a || *b) + return FALSE; + else + return TRUE; +} + + +static int Expand(void *client, const char *p, long *res) +{ + Z80State s; + int ok=TRUE; + + Z80GetState((Z80 *)client,&s); + + if (StrEq(p,"AF")) + *res=s.AF; + else if (StrEq(p,"BC")) + *res=s.BC; + else if (StrEq(p,"DE")) + *res=s.DE; + else if (StrEq(p,"HL")) + *res=s.HL; + else if (StrEq(p,"IX")) + *res=s.IX; + else if (StrEq(p,"IY")) + *res=s.IY; + else if (StrEq(p,"SP")) + *res=s.SP; + else if (StrEq(p,"PC")) + *res=s.PC; + else if (StrEq(p,"A")) + *res=HI(s.AF); + else if (StrEq(p,"F")) + *res=LO(s.AF); + else if (StrEq(p,"B")) + *res=HI(s.BC); + else if (StrEq(p,"C")) + *res=LO(s.BC); + else if (StrEq(p,"D")) + *res=HI(s.DE); + else if (StrEq(p,"E")) + *res=LO(s.DE); + else if (StrEq(p,"H")) + *res=HI(s.HL); + else if (StrEq(p,"L")) + *res=LO(s.HL); + else if (StrEq(p,"AF_")) + *res=s.AF_; + else if (StrEq(p,"BC_")) + *res=s.BC_; + else if (StrEq(p,"DE_")) + *res=s.DE_; + else if (StrEq(p,"HL_")) + *res=s.HL_; + else if (StrEq(p,"A_")) + *res=HI(s.AF_); + else if (StrEq(p,"F_")) + *res=LO(s.AF_); + else if (StrEq(p,"B_")) + *res=HI(s.BC_); + else if (StrEq(p,"C_")) + *res=LO(s.BC_); + else if (StrEq(p,"D_")) + *res=HI(s.DE_); + else if (StrEq(p,"E_")) + *res=LO(s.DE_); + else if (StrEq(p,"H_")) + *res=HI(s.HL_); + else if (StrEq(p,"L_")) + *res=LO(s.HL_); + else if (StrEq(p,"IM")) + *res=s.IM; + else if (StrEq(p,"R")) + *res=s.R; + else if (StrEq(p,"IFF1")) + *res=s.IFF1; + else if (StrEq(p,"IFF2")) + *res=s.IFF2; + else if (p[0]=='@') + { + Z80Word n; + + n=Address(p+1); + *res=mem[n]; + } + else if (p[0]=='#') + { + Z80Word n; + + n=Address(p+1); + *res=MK(mem[n+1],mem[n]); + } + else /* Check for labels */ + { + int f; + + ok=FALSE; + + for(f=0;label && label[f].label;f++) + { + if (StrEq(p,label[f].label)) + { + *res=label[f].address; + ok=TRUE; + break; + } + } + } + + return ok; +} + + +static Z80Word Address(const char *p) +{ + long e=0; + + if (!ExprEval(p,&e,Expand,z80)) + Log("%s\n",ExprError()); + + return (Z80Word)e; +} + + +static Z80Val Val(const char *p) +{ + long e=0; + + if (!ExprEval(p,&e,Expand,z80)) + Log("%s\n",ExprError()); + + return (Z80Val)e; +} + + +static void DoHelp(int no, const char *arg[]) +{ + Log("? - help\n"); + Log("RETURN - Repeat last command if was d, x or n\n"); + Log("!cmd - run shell cmd\n"); + Log(". file - run commands from file\n"); + Log("> [file] - Set logging file (no argument to close)\n"); + Log("l file addr - load file at address\n"); + Log("i file - load intel HEX format file\n"); + Log("d [addr [len]] - disassemble from addr for len bytes\n"); + Log("x [addr [len]] - dump from addr for len bytes\n"); + Log("D file - set disassembly labels\n"); + Log("p [addr] - Set PC to addr [pop PC from stack]\n"); + Log("n - Single step from current PC\n"); + Log("r [addr] - Run from addr [current PC]\n"); + Log("u expr [addr] - Run from addr [current PC] until expr is !0\n"); + Log("z - Show Z80 state\n"); + Log("s - Toggle silent running\n"); + Log("S - Toggle single step\n"); + Log("w bottom top - Set range of writable memory\n"); + Log("I T-state - Raise an interrupt every T-state\n"); + Log("N - Raise an NMI\n"); + Log("T - Toggle memory tracing\n"); + Log("q - quit\n"); +} + + +static void DoScript(int no, const char *arg[]) +{ + FILE *fp; + char buff[1024]; + + if (no<2) + { + Log("Missing arguments\n"); + return; + } + + if (!(fp=fopen(arg[1],"r"))) + { + Log("Failed to open %s\n",arg[1]); + return; + } + + while(fgets(buff,sizeof buff,fp)) + { + Log("EMMA> %s",buff); + + if (buff[0] && buff[0]!='\n') + Run(buff); + } + + fclose(fp); +} + + +static void DoLog(int no, const char *arg[]) +{ + if (no<2) + { + if (log) + fclose(log); + + log=NULL; + return; + } + + if (!(log=fopen(arg[1],"w"))) + { + Log("Failed to open %s\n",arg[1]); + return; + } + else + setbuf(log,NULL); +} + + +static void DoLoad(int no, const char *arg[]) +{ + FILE *fp; + Z80Word addr; + int c; + int total; + + if (no<3) + { + Log("Missing arguments\n"); + return; + } + + addr=Address(arg[2]); + + if (!(fp=fopen(arg[1],"rb"))) + { + Log("Failed to open %s\n",arg[1]); + return; + } + + total=0; + + while((c=getc(fp))!=EOF) + { + mem[addr++]=(Z80Byte)c; + total++; + } + + Log("Read 0x%4.4x bytes from %s\n",total,arg[1]); + + fclose(fp); +} + + +static void DoIntel(int no, const char *arg[]) +{ + FILE *fp; + char buff[1024]; + int done=FALSE; + + if (no<2) + { + Log("Missing arguments\n"); + return; + } + + if (!(fp=fopen(arg[1],"r"))) + { + Log("Failed to open %s\n",arg[1]); + return; + } + + while(!done) + { + if (!fgets(buff,sizeof buff,fp)) + { + Log("Missing EOF record\n"); + done=TRUE; + } + + if (!done && buff[0]!=':') + { + Log("Invalid Intel HEX file\n"); + done=TRUE; + } + + if (!done && buff[8]=='1') + { + Log("<EOF>\n"); + done=TRUE; + } + + if (!done) + { + Z80Word addr; + int len; + int f; + + len=ToHex(buff[1])<<4|ToHex(buff[2]); + + addr=ToHex(buff[3])<<12|ToHex(buff[4])<<8| + ToHex(buff[5])<<4|ToHex(buff[6]); + + Log("Segment of 0x%2.2x bytes at address 0x%4.4x\n",len,addr); + + for(f=0;f<len;f++) + { + Z80Byte b; + + b=ToHex(buff[f*2+9])<<4|ToHex(buff[f*2+10]); + mem[addr++]=b; + } + } + } + + fclose(fp); +} + + +static void DoDis(int no, const char *arg[]) +{ + static Z80Word last=0; + Z80Word addr; + Z80Word len; + Z80Word prev; + + if (no<2) + addr=last; + else + addr=Address(arg[1]); + + if (no<3) + len=32; + else + len=Address(arg[2]); + + prev=len; + + while(len<=prev) + { + Z80Word orig=addr; + const char *l; + + if ((l=GetLabel(z80,orig))) + Log("*** %s ***\n",l); + + Log("%4.4x: %s\n",orig,Z80Disassemble(z80,&addr)); + prev=len; + len-=(addr-orig); + } + + last=addr; +} + + +static void DoDump(int no, const char *arg[]) +{ + static Z80Word last=0; + Z80Word addr; + Z80Word len; + int count=0; + char asc[9]; + + if (no<2) + addr=last; + else + addr=Address(arg[1]); + + if (no<3) + len=32; + else + len=Address(arg[2]); + + while(len>0) + { + if ((count%8)==0) + Log("0x%4.4x: ",addr); + + Log(" 0x%2.2x",mem[addr]); + + if (isprint(mem[addr])) + asc[count%8]=mem[addr]; + else + asc[count%8]='.'; + + asc[(count%8)+1]=0; + + addr++; + count++; + + if ((count%8)==0) + Log(" %s\n",asc); + + len--; + } + + if (count%8) + { + while(count%8) + { + Log(" "); + count++; + } + + Log(" %s\n",asc); + } + + last=addr; +} + + +static void DoLabel(int no, const char *arg[]) +{ + FILE *fp; + char buff[1024]; + int f; + + if (no<2) + { + Log("Missing arguments\n"); + return; + } + + if (!(fp=fopen(arg[1],"r"))) + { + Log("Failed to open %s\n",arg[1]); + return; + } + + for(f=0;label && label[f].label;f++) + free((void *)label[f].label); + + free(label); + label=NULL; + f=0; + + while(fgets(buff,sizeof buff,fp)) + { + char *name=NULL; + char *addr=NULL; + + if (strlen(buff) && buff[strlen(buff)-1]=='\n') + buff[strlen(buff)-1]=0; + + name=strtok(buff," \t"); + + if (name) + addr=strtok(NULL," \t"); + + if (name && addr) + { + label=Realloc(label,sizeof(*label)*(f+2)); + + label[f].label=StrCopy(name); + label[f].address=Address(addr); + + f++; + } + } + + if (label) + label[f].label=NULL; + + fclose(fp); +} + + +static void DoStep(int no, const char *arg[]) +{ + DisplayState(); + Z80SingleStep(z80); + stop=FALSE; +} + + +static void DoSetPC(int no, const char *arg[]) +{ + Z80State s; + + Z80GetState(z80,&s); + + if (no<2) + { + s.PC=MK(mem[s.SP+1],mem[s.SP]); + s.SP+=2; + DisplayState(); + } + else + s.PC=Address(arg[1]); + + Z80SetState(z80,&s); +} + + +static void DoRun(int no, const char *arg[]) +{ + if (no>1) + { + Z80State s; + + Z80GetState(z80,&s); + s.PC=Address(arg[1]); + Z80SetState(z80,&s); + } + + while(!stop) + { + if (!quiet_run) + DisplayState(); + + Z80SingleStep(z80); + + if (single_step) + { + Log("<step>"); + fflush(stdout); + getchar(); + } + } + + stop=FALSE; +} + + +static void DoUntil(int no, const char *arg[]) +{ + if (no<2) + { + Log("Missing arguments\n"); + return; + } + + if (no>2) + { + Z80State s; + + Z80GetState(z80,&s); + s.PC=Address(arg[2]); + Z80SetState(z80,&s); + } + + while(!stop) + { + long e; + + if (!ExprEval(arg[1],&e,Expand,z80)) + Log("%s\n",ExprError()); + + if (e) + { + Log("%s TRUE\n",arg[1]); + stop=TRUE; + } + else + { + if (!quiet_run) + DisplayState(); + + Z80SingleStep(z80); + } + } + + stop=FALSE; +} + + +static void DoShow(int no, const char *arg[]) +{ + DisplayState(); +} + + +static void DoSilent(int no, const char *arg[]) +{ + quiet_run=!quiet_run; + + if (quiet_run) + Log("Quiet running set\n"); + else + Log("Noisy running set\n"); +} + + +static void DoRange(int no, const char *arg[]) +{ + if (no<3) + { + Log("Missing arguments\n"); + return; + } + + bottom=Address(arg[1]); + top=Address(arg[2]); + + Log("Writable memory between 0x%4.4x and 0x%4.4x\n",bottom,top); +} + + +static void DoSingle(int no, const char *arg[]) +{ + single_step=!single_step; + + if (single_step) + Log("Single step running set\n"); + else + Log("Continuous running set\n"); +} + + +static void DoIntRaise(int no, const char *arg[]) +{ + if (no<1) + { + Log("Missing arguments\n"); + return; + } + + int_raise=Val(arg[1]); + + if (int_raise) + Log("Interrupt every %lu T-states\n",int_raise); + else + Log("Interrupt disabled\n"); +} + + +static void DoNMIRaise(int no, const char *arg[]) +{ + Z80NMI(z80); +} + + +static void DoMemTrace(int no, const char *arg[]) +{ + mem_trace=!mem_trace; + + if (mem_trace) + Log("Memory tracing on\n"); + else + Log("Memory tracing off\n"); +} + + +static void DoQuit(int no, const char *arg[]) +{ + quit=TRUE; +} + + +static void Run(char *cmd) +{ + static char last_cmd[1024]={0}; + static const struct + { + const char *cmd; + const int store; + void (*handler)(int no, const char *arg[]); + } cmd_table[]= + { + {"?", FALSE, DoHelp}, + {".", FALSE, DoScript}, + {">", FALSE, DoLog}, + {"l", FALSE, DoLoad}, + {"i", FALSE, DoIntel}, + {"d", TRUE, DoDis}, + {"x", TRUE, DoDump}, + {"D", FALSE, DoLabel}, + {"p", FALSE, DoSetPC}, + {"n", TRUE, DoStep}, + {"r", FALSE, DoRun}, + {"u", FALSE, DoUntil}, + {"z", FALSE, DoShow}, + {"s", FALSE, DoSilent}, + {"S", FALSE, DoSingle}, + {"w", FALSE, DoRange}, + {"I", FALSE, DoIntRaise}, + {"N", FALSE, DoNMIRaise}, + {"T", FALSE, DoMemTrace}, + {"q", FALSE, DoQuit}, + {NULL, FALSE, NULL} + }; + + char buff[1024]; + const char *arg[4]; + int use_last=FALSE; + int no; + + if (cmd[0]!='\n') + { + strcpy(buff,cmd); + } + else + { + strcpy(buff,last_cmd); + use_last=TRUE; + } + + if (buff[0]=='#') + return; + + if (buff[0]=='!') + system(buff+1); + else + { + no=0; + + arg[0]=strtok(buff," \t\n"); + + while(no<3 && arg[no]) + arg[++no]=strtok(NULL," \t\n"); + + if (arg[0]) + { + int f; + int done=FALSE; + + for(f=0;!done && cmd_table[f].cmd;f++) + if (cmd_table[f].cmd[0]==arg[0][0]) + { + if (cmd_table[f].store) + { + if (!use_last) + strcpy(last_cmd,cmd); + } + else + last_cmd[0]=0; + + done=TRUE; + cmd_table[f].handler(no,arg); + } + + if (!done) + Log("Syntax error\n"); + } + } +} + + +/* ---------------------------------------- MEMORY +*/ +static Z80Byte ReadMem(Z80 *z80, Z80Word addr) +{ + if (mem_trace) + Log("PEEK(0x%4.4x)=0x%2.2x\n",addr,mem[addr]); + + return mem[addr]; +} + + +static Z80Word ReadMemWord(Z80 *z80, Z80Word addr) +{ + Z80Word w; + + w=MK(mem[addr+1],mem[addr]); + + if (mem_trace) + Log("PEEKW(0x%4.4x)=0x%4.4x\n",addr,w); + + return w; +} + + +static Z80Byte ReadMemDis(Z80 *z80, Z80Word addr) +{ + return mem[addr]; +} + + +static void WriteMem(Z80 *z80, Z80Word addr, Z80Byte val) +{ + if (addr>=bottom && addr<=top) + { + mem[addr]=val; + + if (mem_trace) + Log("POKE(0x%4.4x)=0x%2.2x\n",addr,mem[addr]); + } + else + { + if (mem_trace) + Log("POKE(0x%4.4x)=0x%2.2x [BLOCKED]\n",addr,mem[addr]); + } +} + + +static void WriteMemWord(Z80 *z80, Z80Word addr, Z80Word val) +{ + static const char *block_str[3]={""," [ONE BYTE BLOCKED]"," [BLOCKED]"}; + Z80Byte lo,hi; + int block=0; + + lo=LO(val); + hi=HI(val); + + if (addr>=bottom && addr<=top) + mem[addr]=lo; + else + block++; + + addr++; + + if (addr>=bottom && addr<=top) + mem[addr]=hi; + else + block++; + + if (mem_trace) + Log("POKEW(0x%4.4x)=0x%4.4x%s\n",addr,val,block_str[block]); +} + + +static Z80Byte ReadPort(Z80 *z80, Z80Word addr) +{ + Z80Byte b=0xff; + Z80Word ptr; + Z80State s; + char expr[1024]; + char *p; + + Z80GetState(z80,&s); + + switch(addr&0xff) + { + case 0x80: + ptr=MK(mem[1],mem[0]); + + p=expr; + + while(mem[ptr]) + *p++=mem[ptr++]; + + *p=0; + + b=(Z80Byte)Address(expr); + + /* Log("%s -> %u\n",expr,b); */ + + break; + + case 0x81: + ptr=s.DE; + + p=expr; + + while(mem[ptr]) + *p++=mem[ptr++]; + + *p=0; + + b=(Z80Byte)Address(expr); + + break; + + default: + Log("Read from port 0x%4.4x\n",(int)addr); + break; + } + + return b; +} + + +static void WritePort(Z80 *z80, Z80Word addr, Z80Byte val) +{ + Z80State s; + + Z80GetState(z80,&s); + + switch(addr&0xff) + { + case 0x80: + putchar(val); + fflush(stdout); + break; + + case 0x81: + Log("Stop requested\n"); + stop=TRUE; + break; + + case 0x82: + while(mem[s.DE]!='$') + { + if (isspace(mem[s.DE]) || isprint(mem[s.DE])) + putchar(mem[s.DE]); + + s.DE++; + } + fflush(stdout); + break; + + case 0x83: + while(mem[s.DE]) + { + putchar(mem[s.DE]); + s.DE++; + } + fflush(stdout); + break; + + case 0x84: + DisplayState(); + break; + + default: + Log("Wrote 0x%2.2x to port 0x%4.4x\n",(int)val,(int)addr); + break; + } +} + + +static const char *GetLabel(Z80 *z80, Z80Word addr) +{ + int f; + + for(f=0;label && label[f].label;f++) + if (label[f].address==addr) + return label[f].label; + + return NULL; +} + + +static int Halt(Z80 *z80, Z80Val v) +{ + Log("Processor halted\n"); + stop=TRUE; + return TRUE; +} + + +static int IntCheck(Z80 *z80, Z80Val v) +{ + if (int_raise && v>int_raise) + { + Log("Interrupt raised\n"); + Z80Interrupt(z80,0xff); + Z80ResetCycles(z80,v-int_raise); + } + + return TRUE; +} + + +/* ---------------------------------------- MAIN +*/ +int main(int argc, char *argv[]) +{ + const char *autoarg[2]={".","auto"}; + char buff[1024]; + + z80=Z80Init(WriteMem,ReadMem,WriteMemWord,ReadMemWord, + WritePort,ReadPort,ReadMemDis); + + if (!z80) + { + printf("Failed to initialise Z80\n"); + return EXIT_FAILURE; + } + + Z80LodgeCallback(z80,eZ80_Halt,Halt); + Z80LodgeCallback(z80,eZ80_Instruction,IntCheck); + + signal(SIGINT,SigInt); + + if (argc>1) + { + if (strcmp(argv[1],"-a")!=0) + { + autoarg[1]=argv[1]; + DoScript(2,autoarg); + } + } + else + DoScript(2,autoarg); + + while(!quit) + { + Log("EMMA> "); + fflush(stdout); + + if (!fgets(buff,sizeof buff,stdin)) + { + quit=TRUE; + continue; + } + + Run(buff); + } + + return EXIT_SUCCESS; +} + + +/* END OF FILE */ + + |