summaryrefslogtreecommitdiff
path: root/emma.c
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2006-08-20 17:39:42 +0000
committerIan C <ianc@noddybox.co.uk>2006-08-20 17:39:42 +0000
commit87ace20633ba711243e336630e2c9a8546516598 (patch)
treea9c624a08ae8ccc16086781fb009a6709b7a2913 /emma.c
parent2a5a38a8bd0295b841343062baec242d40267d93 (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.c1180
1 files changed, 1180 insertions, 0 deletions
diff --git a/emma.c b/emma.c
new file mode 100644
index 0000000..f2ae2c2
--- /dev/null
+++ b/emma.c
@@ -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 */
+
+