Path: vanilla!asbach!noris.net!blackbush.xlink.net!tank.news.pipex.net!pipex!peer-news.britain.eu.net!lyra.csx.cam.ac.uk!mgr11 From: mgr11@cus.cam.ac.uk (M.G. Rison) Newsgroups: comp.sys.sinclair Subject: Re: Overflow and Half Carry Flag (and DAA) Date: 7 Feb 1996 14:07:57 GMT Organization: University of Cambridge, England Lines: 52 Message-ID: <4fabnt$hce@lyra.csx.cam.ac.uk> References: <1996Feb6.110909.24289@zippy.dct.ac.uk> <4f7omm$6mi@bignews.shef.ac.uk> <4f8031$8pb@bignews.shef.ac.uk> <4f83sb$a9e@bignews.shef.ac.uk> Reply-To: rison@hep.phy.cam.ac.uk NNTP-Posting-Host: ursa.cus.cam.ac.uk En la artikolo <4f83sb$a9e@bignews.shef.ac.uk>, Damion Yates skribis: > Thats what the daa instruction appears to do but the algorith is far more > complex than that! > (well a little bit) for example I know it used the N flag to see if the last > instruction was a sub or add, a friend of mine who is writing a cpc emu for arcs > pasted this in to a technical talker I use (to the ACS: only dcs machines!) I'm the friend. I want to point out immediately that this code is taken from yaze (yet another Z80 emulator) by Frank Cringle, fdc@cliwe.ping.de , available from ftp://oak.oakland.edu/pub/unix-c/cpm/yaze-1.00.tar.gz if they've restored it (it disappeared one day for no good reason). > case 0x27: /* DAA */ > acu = hreg(AF); > temp = ldig(acu); > cbits = TSTFLAG(C); > if (TSTFLAG(N)) { /* last operation was a subtract */ > int hd = cbits || acu > 0x99; > if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ > if (temp > 5) > SETFLAG(H, 0); > acu -= 6; > acu &= 0xff; > } > if (hd) /* adjust high digit */ > acu -= 0x160; > } > else { /* last operation was an add */ > if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ > SETFLAG(H, (temp > 9)); > acu += 6; > } > if (cbits || ((acu & 0x1f0) > 0x90)) /* adjust high digit */ > acu += 0x60; > } > cbits |= (acu >> 8) & 1; > acu &= 0xff; > AF = (acu << 8) | (acu & 0xa8) | ((acu == 0) << 6) | > (AF & 0x12) | partab[acu] | cbits; > break; Can anybody beat this and produce a more concise algorithm which still gets it exactly right (including the effects on *all* the bits of F)? Mark "that must have been horrible to suss out!" ====================================================================== | rison@hep.phy.cam.ac.uk | Esperanto - lingvo inter-nacia | | rison@vxcern.cern.ch | * Mi estas riisto * | ====================================================================== ---- Path: vanilla!asbach!noris.net!blackbush.xlink.net!tank.news.pipex.net!pipex!howland.reston.ans.net!newsfeed.internetmci.com!in1.uu.net!news.technocom.co.uk!morse.ukonline.co.uk!bath.ac.uk!niss!warwick!bham!bhamcs!news.ox.ac.uk!news From: imc@ecs.ox.ac.uk (Ian Collier) Newsgroups: comp.sys.sinclair Subject: Re: Overflow and Half Carry Flag (and DAA) Date: 7 Feb 1996 14:39:58 GMT Organization: Oxford University Computing Laboratory Lines: 56 Message-ID: <7836.imc@comlab.ox.ac.uk> References: <1996Feb6.110909.24289@zippy.dct.ac.uk> <4f7omm$6mi@bignews.shef.ac.uk> <4f8031$8pb@bignews.shef.ac.uk> <4f83sb$a9e@bignews.shef.ac.uk> NNTP-Posting-Host: boothp2.ecs.ox.ac.uk X-Local-Date: Wednesday, 7th February 1996 at 2:39pm GMT In article <4f83sb$a9e@bignews.shef.ac.uk>, thdb86%teach@dcs.shef.ac.uk (Damion Yates) wrote: >Thats what the daa instruction appears to do but the algorith is far more >complex than that! >(well a little bit) for example I know it used the N flag to see if the last >instruction was a sub or add, a friend of mine who is writing a cpc emu for arcs >pasted this in to a technical talker I use (to the ACS: only dcs machines!) > case 0x27: /* DAA */ [29 lines of code] > break; > >Of course this is rather messy and confusing but it helps. Well, if we're quoting code... instr(39,4); { unsigned char incr=0, carry=cy; if((f&0x10) || (a&0x0f)>9) incr=6; if((f&1) || (a>>4)>9) incr|=0x60; if(f&2)suba(incr,0); else { if(a>0x90 && (a&15)>9)incr|=0x60; adda(incr,0); } f=((f|carry)&0xfb)|parity(a); } endinstr; There, much easier. No? Well, I do admit the macros are rather confusing: #define adda(x,c) /* 8-bit add */ do{unsigned short y;\ unsigned char z=(x);\ y=a+z+(c);\ f=(y&0xa8)|(y>>8)|(((a&0x0f)+(z&0x0f)+(c)>15)<<4)|\ (((~a^z)&0x80&(y^a))>>5);\ f|=(!(a=y))<<6;\ } while(0) #define suba(x,c) /* 8-bit subtract */ do{unsigned short y;\ unsigned char z=(x);\ y=(a-z-(c))&0x1ff;\ f=(y&0xa8)|(y>>8)|(((a&0x0f)<(z&0x0f)+(c))<<4)|\ (((a^z)&0x80&(y^a))>>5)|2;\ f|=(!(a=y))<<6;\ } while(0) There's probably a much faster way to calculate those flags, but never mind. Ian Collier - imc@comlab.ox.ac.uk - WWW Home Page (including Spectrum section): http://www.comlab.ox.ac.uk/oucl/users/ian.collier/index.html New to this group? Answers to frequently-asked questions can be had from http://www.nvg.unit.no/spectrum/ . Sam Coupé FAQ: http://www.soton.ac.uk/~tsp93/Coupe/FAQ.txt ---- Path: vanilla!asbach!noris.net!blackbush.xlink.net!howland.reston.ans.net!swrinde!newsfeed.internetmci.com!btnet!zippy.dct.ac.uk!zippy.dct.ac.uk!nntp Newsgroups: comp.sys.sinclair Subject: Re: Overflow and Half Carry Flag (and DAA) Message-ID: <1996Feb8.123458.24357@zippy.dct.ac.uk> From: James McKay Date: 8 Feb 96 12:34:57 GMT References: <1996Feb6.110909.24289@zippy.dct.ac.uk> <4f7omm$6mi@bignews.shef.ac.uk> <4f8031$8pb@bignews.shef.ac.uk> <4f83sb$a9e@bignews.shef.ac.uk> <4fabnt$hce@lyra.csx.cam.ac.uk> Nntp-Posting-Host: diana20.paisley.ac.uk X-Mailer: Mozilla 1.1N (X11; I; SunOS 4.1.3 sun4c) MIME-Version: 1.0 X-URL: news:4fabnt$hce@lyra.csx.cam.ac.uk Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii Lines: 31 Here is how I do daa: void daa(void) { UC daa_select; daa_select=af.B.l&19; /* HNC flags */ if(daa_select>3) /* Hf Set (DAA) */ { af.B.l=daa_f[daa_select-12][af.B.h]; af.B.h=daa_a[daa_select-12][af.B.h]; } else /* Hf not set (DAS) */ { af.B.l=daa_f[daa_select][af.B.h]; af.B.h=daa_a[daa_select][af.B.h]; } t_state+=4; } Where daa_f is the outputs of the flags and daa_a is the outputs of the a register, the values are read in from a file I generated from the Spectrum. N & C flags generate the values 0-3 and the H flag is the high bit giving a total of 8 values (array is daa_a[8][256];). So the daa_a array takes up 4096 bytes! -- James McKay, com40014@paisley.ac.uk ---- Newsgroups: comp.sys.sinclair Path: vanilla!asbach!noris.net!blackbush.xlink.net!tank.news.pipex.net!pipex!news.mathworks.com!newsfeed.internetmci.com!in2.uu.net!news.technocom.co.uk!morse.ukonline.co.uk!bath.ac.uk!uwe-bristol!knife!rff-ribe From: rff-ribe@csm.uwe.ac.uk (R Ribeiro) Subject: Re: Overflow and Half Carry Flag (and DAA) Message-ID: <1996Feb8.124447.16208@pat.uwe.ac.uk> To: imc@ecs.ox.ac.uk (Ian Collier), mgr11@cus.cam.ac.uk, 4f83sb$a9e@bignews.shef.ac.uk, thdb86%teach@dcs.shef.ac.uk, ACA95SAP@shef.ac.uk Sender: usenet@pat.uwe.ac.uk (uwe nntp usenet poster) Nntp-Posting-Host: usenet@pat.uwe.ac.uk (uwe nntp usenet poster) Organization: University of the West of England. X-Newsreader: xrn 7.04-beta-2 References: <1996Feb6.110909.24289@zippy.dct.ac.uk> <4f7omm$6mi@bignews.shef.ac.uk> <4f8031$8pb@bignews.shef.ac.uk> <4f83sb$a9e@bignews.shef.ac.uk> <7836.imc@comlab.ox.ac.uk> Date: Thu, 8 Feb 1996 12:44:47 GMT Lines: 116 Hello: I am writing a Spectrum emulator and tought I could give here my contribution: (when you see a var flags._something it can only be 0 or 1). flags._X is the undocumented flag in bit 5 and _Y in bit 3. Macro BIT_5 is 0x20 Macro BIT_3 is 0x04 /*=========================================================================* * daa * *=========================================================================*/ void daa() { if(flags._H = (((A & (UCHAR)0xF) > (UCHAR)9) || flags._H )) A += (flags._N) ? (UCHAR)(-6) : (UCHAR)6; if(flags._C = ((A > (UCHAR)0x9F) || flags._C )) A += (flags._N) ? (UCHAR)(-0x60) : (UCHAR)0x60; flags._S = ( A & (UCHAR)BIT_7); flags._Z = !A; flags._P = parity(A); flags._X = A & (UCHAR)BIT_5; flags._Y = A & (UCHAR)BIT_3; } /*=========================================================================* * parity * *=========================================================================*/ /* parity -- in Z80 parity is even */ USHORT parity(num) UCHAR num; { LOCAL UCHAR parit; LOCAL UCHAR number; number = num; parit = 1; while(number) { if((UCHAR)0x01 & number) parit ^= (UCHAR)1; number >>= 1; } return((USHORT)parit); } What do you say of this? I know, parity can be improved by a lookup table or inline-assembly code...don't bother to talk about that with me. Bye, Rui Ribeiro In article <7836.imc@comlab.ox.ac.uk>, imc@ecs.ox.ac.uk (Ian Collier) writes: > In article <4f83sb$a9e@bignews.shef.ac.uk>, thdb86%teach@dcs.shef.ac.uk (Damion Yates) wrote: > >Thats what the daa instruction appears to do but the algorith is far more > >complex than that! > > >(well a little bit) for example I know it used the N flag to see if the last > >instruction was a sub or add, a friend of mine who is writing a cpc emu for arcs > >pasted this in to a technical talker I use (to the ACS: only dcs machines!) > > > case 0x27: /* DAA */ > [29 lines of code] > > break; > > > > >Of course this is rather messy and confusing but it helps. > > Well, if we're quoting code... > > instr(39,4); > { > unsigned char incr=0, carry=cy; > if((f&0x10) || (a&0x0f)>9) incr=6; > if((f&1) || (a>>4)>9) incr|=0x60; > if(f&2)suba(incr,0); > else { > if(a>0x90 && (a&15)>9)incr|=0x60; > adda(incr,0); > } > f=((f|carry)&0xfb)|parity(a); > } > endinstr; > > There, much easier. No? Well, I do admit the macros are rather confusing: > > #define adda(x,c) /* 8-bit add */ do{unsigned short y;\ > unsigned char z=(x);\ > y=a+z+(c);\ > f=(y&0xa8)|(y>>8)|(((a&0x0f)+(z&0x0f)+(c)>15)<<4)|\ > (((~a^z)&0x80&(y^a))>>5);\ > f|=(!(a=y))<<6;\ > } while(0) > #define suba(x,c) /* 8-bit subtract */ do{unsigned short y;\ > unsigned char z=(x);\ > y=(a-z-(c))&0x1ff;\ > f=(y&0xa8)|(y>>8)|(((a&0x0f)<(z&0x0f)+(c))<<4)|\ > (((a^z)&0x80&(y^a))>>5)|2;\ > f|=(!(a=y))<<6;\ > } while(0) > > There's probably a much faster way to calculate those flags, but never mind. > > Ian Collier - imc@comlab.ox.ac.uk - WWW Home Page (including Spectrum section): > http://www.comlab.ox.ac.uk/oucl/users/ian.collier/index.html > > New to this group? Answers to frequently-asked questions can be had from > http://www.nvg.unit.no/spectrum/ . > Sam Coupé FAQ: http://www.soton.ac.uk/~tsp93/Coupe/FAQ.txt ---- Path: vanilla!asbach!noris.net!blackbush.xlink.net!tank.news.pipex.net!pipex!dish.news.pipex.net!pipex!news00.sunet.se!sunic!news99.sunet.se!news.kth.se!xbyse.nada.kth.se!d88-bli From: d88-bli@xbyse.nada.kth.se (Bo Lindbergh) Newsgroups: comp.sys.sinclair Subject: Re: Overflow and Half Carry Flag (and DAA) Date: 8 Feb 1996 22:56:16 GMT Organization: Royal Institute of Technology, Stockholm, Sweden Lines: 45 Message-ID: <4fdv2g$jhr@news.kth.se> References: <4f8031$8pb@bignews.shef.ac.uk> <4f83sb$a9e@bignews.shef.ac.uk> <4fabnt$hce@lyra.csx.cam.ac.uk> NNTP-Posting-Host: xbyse.nada.kth.se Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit In article <4fabnt$hce@lyra.csx.cam.ac.uk> rison@hep.phy.cam.ac.uk writes: > [28 quoted lines of code featuring no less than six if statements snipped] > > Can anybody beat this and produce a more concise algorithm which still > gets it exactly right (including the effects on *all* the bits of F)? /* * Supposing you have these variables... * reg_f is used for the sign flag and the two unused flags. * flag_n holds 0xFF for subtract and 0x00 for add. * flag_pv holds 0x04 for even parity and 0x00 for odd parity. * flag_z, flag_h, and flag_c each hold either 0x01 or 0x00. */ unsigned char op8,reg_a,reg_f,flag_z,flag_h,flag_pv,flag_n,flag_c; int res,cy; /* * The critical line is of course the calculation of op8, * the explanation of which I'll leave as an exercise. */ case daa: cy=(reg_a+0x66)^reg_a; flag_c|=(cy>>8)&0x01; flag_h|=(cy>>4)&0x01; op8=(((0x88-((flag_c<<4)|flag_h))&0x66)^flag_n)-flag_n; res=reg_a+op8; cy=reg_a^res; flag_h=(cy>>4)&0x01; reg_a=res; flag_z=(0x100-reg_a)>>8; reg_f=reg_a&0xA8; flag_pv=reg_a^(reg_a>>4); flag_pv^=flag_pv<<2; flag_pv=((~flag_pv)^(flag_pv>>1))&0x04; break; /* * Utterly unreadable, right? */ /Bo Lindbergh