• Please review our updated Terms and Rules here

8086 emulator tech discussion

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
yep, i have it. i haven't been able to come up with any answers from it quite yet. i'm wondering if maybe something is up with my GRP2 bitshifting opcodes. i'm pretty sure my flags are alright now. warning this code is messy:

Code:
Sub op_grp2(ByVal word)
Dim signval, bits, maxval, oldcf as UInteger
If oper2 = 0 Then Exit Sub
If word Then signval = 32768: maxval = 65535: bits = 16 Else signval = 128: maxval = 255: bits = 8
Select Case reg
    Case 0 'ROL
        temp1 = (oper1 Shl (oper2 And (bits-1))) Or (oper1 Shr (bits - (oper2 And (bits-1))))
        cf = temp1 And 1
        of = ((temp1 Shr (bits-1)) Xor temp1) And 1
        
    Case 1 'ROR
    	  temp1 = (oper1 Shr (oper2 And (bits-1))) Or (oper1 Shl (bits - (oper2 And (bits-1))))
    	  cf = ((temp1 And signval) \ signval) And 1
    	  If oper2 = 1 Then of = (((temp1 Xor oper1) And signval) \ signval) And 1
        
    Case 2 'RCL
    	oper1 = oper1 Or (cf Shl bits)
        temp1 = (oper1 Shl (oper2 Mod (bits+1))) Or (oper1 Shr ((bits+1) - (oper2 Mod (bits+1))))
        cf = ((temp1 and (maxval+1)) \ (maxval+1)) And 1
        of = ((((temp1 Shr 1) Xor temp1) And signval) \ signval) And 1
        
    Case 3 'RCR
    	  oper1 = oper1 Or (cf Shl bits)
    	  temp1 = (oper1 Shr (oper2 Mod (bits+1))) Or (oper1 Shl ((bits+1) - (oper2 Mod (bits+1))))
    	  cf = ((temp1 And (maxval+1)) \ (maxval+1)) And 1
    	  If oper1 = 1 Then of = (((temp1 Xor oper1) And signval) \ signval) And 1

	 Case 4, 6 'SHL/SAL
		  If (oper2 > bits) Then temp1 = 0 Else temp1 = oper1 Shl oper2
		  If word Then flag_szp16 temp1 Else flag_szp8 temp1
		  cf = ((temp1 And (maxval+1)) \ (maxval+1)) And 1
		  of = ((((temp1 Shr 1) Xor temp1) And signval) \ signval) And 1

	 Case 5 'SHR
	 	  If (oper2 > bits) Then temp1 = 0 Else temp1 = (oper1 Shr (oper2 - 1))
	 	  cf = temp1 And 1
	 	  temp1 = temp1 Shr 1
	 	  If word Then flag_szp16 temp1 Else flag_szp8 temp1
	 	  of = ((((temp1 Shl 1) Xor temp1) And signval) \ signval) And 1

	 Case 7 'SAR
	 	  If word Then temp1 = &hFFFF0000& Else temp1 = &hFF00&
        If (oper1 And signval) = signval Then oper1 = oper1 Or temp1
        If (oper2 >= bits) Then temp1 = oper1 Shr (bits - 1) Else temp1 = oper1 Shr (oper2-1)
        cf = temp1 And 1
        temp1 = (temp1 Shr 1) And maxval
        If word Then flag_szp16 temp1 Else flag_szp8 temp1
        of = 0
End Select
result = temp1 And maxval
End Sub
 

basman74

Experienced Member
Joined
Feb 16, 2010
Messages
123
Location
Melbourne Australia
yep, i have it. i haven't been able to come up with any answers from it quite yet. i'm wondering if maybe something is up with my GRP2 bitshifting opcodes. i'm pretty sure my flags are alright now. warning this code is messy:

*** Code snipped!

Well, I can't see how you're modifying the zero flag in the SHL/SHR and SAL/SAR opcodes (you should be!).

In punching out my own emulator code, I found that correct flags testing/modification to be absolutely critical to successful trouble-free 8088 operation, so it's very important to get this right. The only real concession to this (in my case) was that I didn't push so hard on the parity flag, though a good part of my emulator still modifies the parity flag when it is supposed to..

Don't know if you already have this, but I found this CodeTable guide helpful for my own emulator development.

Hope this helps,
Valentin
 

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
great PDF, thanks for the link! i printed that out. i do modify the zero flag there actually. wherever you see flag_szp8 or flag_szp16, the "szp" stands for sign/zero/parity it calls one of these:

Code:
Sub flag_szp8(ByVal value as UByte)
If value = 0 Then zf = 1 Else zf = 0
If (value And &H80&) Then sf = 1 Else sf = 0
pf = Parity(value)
End Sub

Sub flag_szp16(ByVal value as UShort)
If value = 0 Then zf = 1 Else zf = 0
If (value And &H8000&) Then sf = 1 Else sf = 0
pf = Parity(value And 255)
End Sub
 

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
hey, i see on that chart that a lot of the conditional jump operations are unsigned? i didn't know that, i've been sign extending ALL of my conditional jumps.

edit: if i remove the sign extending for the ones the chart calls unsigned, it breaks everything. now i'm just confused. more so than usual. are they still supposed to be relative jumps, or does it make them absolute? i would imagine relative, as they're still 8-bit values.
 
Last edited:

basman74

Experienced Member
Joined
Feb 16, 2010
Messages
123
Location
Melbourne Australia
hey, i see on that chart that a lot of the conditional jump operations are unsigned? i didn't know that, i've been sign extending ALL of my conditional jumps.

edit: if i remove the sign extending for the ones the chart calls unsigned, it breaks everything. now i'm just confused. more so than usual. are they still supposed to be relative jumps, or does it make them absolute? i would imagine relative, as they're still 8-bit values.

Actually Mike, the 'unsigned' conditional jump opcodes only relate to conditional jump operations where the CPU sign flag is not part of the conditional test (and nothing more).

Note that the conditional test is separate from the relative short jump that occurs if the condition is found to be true.

To clarify, here's an example right from my own emulator (it's in C, sorry!):

Code:
//SJMP relative8
void go_sjmp(void) 
{
	[B]signed[/B] char blah = 0;

	read_opcode();
	IP88++;
	blah = opcode;
	IP88 = IP88 + blah;
	new_iploaded = 1;	
}


And from one conditional jump opcode in my main instruction decoder loop
.
.
.
case 0x7C:        //	JL/JNGE:     IF ZF = 0 AND SF <> OF THEN JUMP (OK!)
	if((cpu_zero == 0) && (cpu_sign != cpu_oflow))
	{
		go_sjmp();
	}	
	else
	{
		IP88++;
	}	
	new_iploaded = 1;		
	break;

Cheers Valentin
 

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
okay, yeah thanks. i've been doing them right then.

Code:
    Case &H7C '7C JL Jb
        temp16 = signext(read86(cs * 16 + ip)): StepIP 1
        If sf <> of Then ip = ip + temp16

the C is no bother, i can write C as well as BASIC. i thought an 8086 emu in BASIC would be kind of unique. ;)

something i've noticed, some emulators out there examine the zero flag as well as sign/overflow when evaluating 0x7C and 0x7D condition, and others don't examine the zero flag.
 

basman74

Experienced Member
Joined
Feb 16, 2010
Messages
123
Location
Melbourne Australia
okay, yeah thanks. i've been doing them right then.

Code:
    Case &H7C '7C JL Jb
        temp16 = signext(read86(cs * 16 + ip)): StepIP 1
        If sf <> of Then ip = ip + temp16

the C is no bother, i can write C as well as BASIC. i thought an 8086 emu in BASIC would be kind of unique. ;)

something i've noticed, some emulators out there examine the zero flag as well as sign/overflow when evaluating 0x7C and 0x7D condition, and others don't examine the zero flag.

Don't know about other emulators, but I've found that my test method for JL/JNGE opcode works better :)
 

basman74

Experienced Member
Joined
Feb 16, 2010
Messages
123
Location
Melbourne Australia
i trust you. sounds like your stuff is working well, i'll make mine do the same.

Perhaps it will be helpful if I explain why I think you should also include the zero flag check on JL/JNGE..

It is supposed to guard against the situation where the zero flag is set (thus implying that the previously compared operands were equal) prior to JL/JNGE execution, resulting in the correct behavior of JL/JNGE by not jumping if the zero flag is set..
 
Last edited:

Chuck(G)

25k Member
Joined
Jan 11, 2007
Messages
40,218
Location
Pacific Northwest, USA
It's easy enough to try. Consider:

Code:
-rf
NV UP EI PL NZ NA PO NC  -zr ng
-rf
NV UP EI NG ZR NA PO NC  -
-a100
13BF:0100 jnge 104
13BF:0102 int 3
13BF:0103 nop
13BF:0104 int 3
13BF:0105
-g=100

AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=13BF  ES=13BF  SS=13BF  CS=13BF  IP=0104   NV UP EI NG ZR NA PO NC
13BF:0104 CC            INT     3
-

Note that even with the zero flag set, the jump is taken.

When it doubt, try the real thing.
 

basman74

Experienced Member
Joined
Feb 16, 2010
Messages
123
Location
Melbourne Australia
It's easy enough to try. Consider:

** savvy debug usage snipped!

Note that even with the zero flag set, the jump is taken.

When it doubt, try the real thing.

You know Chuck, your very elegant example works equally well under DOSBox, pce-ibmpc and NTDVM.. :)

So, looks like the zero flag has no bearing on JL then? Shoot, I guess this now means MY emulator is broken! lol
 

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
if anybody feels like having a peek, here's everything i have so far:

http://rubbermallet.org/fake86-0.3.1.11.zip

there is the source files, a binary, required ROMs, and a folder with a few .com graphical demos.

for some reason, at some point (which point i'm not sure unfortunately) the ROM BASIC quit working from the bootstrap menu, but if you're quick you can hit space during the POST screen and that will still make it go to BASIC. to play with the source, i recommend you get FBEdit. i included a .fbp project file for that editor, and it makes things much easier. the actual FreeBASIC compiler is at http://www.freebasic.net

a couple notes, to start it with a floppy image inserted into it's first floppy drive the syntax is:

fake86.exe diskimage.img


to just directly load a .com file into memory, syntax is like this:

fake86.exe /com comfile.com




as far as where my problems are, i am suspecting at this point any of the following:
-division operations
-general flag calculations (i'm somewhat confident they're okay, but maybe there's a mistake i'm not catching)
-bitshift operations

but of course with a program this complicated, errors will snowball so who knows.

also, the source is a bit ugly... especially some of the indents are all over the place. it's partly FBEdit's handling of them, and partly my laziness.

a word about the graphical demos that i included.. none of them look exactly correct in fake86. compare them with dosbox and you'll see what i mean.
 

Chuck(G)

25k Member
Joined
Jan 11, 2007
Messages
40,218
Location
Pacific Northwest, USA
Are you using any of the Intel x86 books as a reference? The ones published by Osborne-McGraw hill are generally pretty good and quite specific. The one I keep by my desk is the i486 book, though I have the i386 books, complete with instructions never implmented... :)
 

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
Are you using any of the Intel x86 books as a reference? The ones published by Osborne-McGraw hill are generally pretty good and quite specific. The one I keep by my desk is the i486 book, though I have the i386 books, complete with instructions never implmented... :)

yeah i've got the intel 8086 reference book as a PDF. check out what i just got though:

fake86-pcdos.png


it's not handling the commands quite right yet, but that's a HUGE step in the right direction. :D

EDIT: scratch that last bit, some commands work. dir keeps reporting file not found, but i can run executables from disk and use most built-in DOS commands. there are still glitches to fix.
 
Last edited:

Chuck(G)

25k Member
Joined
Jan 11, 2007
Messages
40,218
Location
Pacific Northwest, USA
Mike, I'm surprised that you didn't set up a test suite for the various instructions and run it on the real hardware for verification. There are only 8 flags that really matter, so you could set up a table of 256 flag bytes and test every jump instruction, recording whether or not it actually took a branch.

Compare with what you get with the real hardware and if it matches, you know that you have the implementation correct.

Writing verification software is a huge job when working with one of the hardware description languages (VHDL or Verliog). In fact, it's often a bigger job than writing the HDL for the implementation itself.

Good test writers are worth their weight in diamonds...
 

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
i was giving that some thought, it will be complicated but i probably need to. i'm sure the condition checking is fine. there are probably problems elsewhere in calculations and setting flags.
 

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
i have an inkling that the problem(s) are in some sort of mathematical calculation or the flag settings from it. i say this because when i boot the PC-DOS 1.00 image, it lets me load and run .com files off the disk image just fine. when i try to run anything that's an .exe it craps out with an "Error in EXE file" message and drops back to the A> prompt.

makes me think it's determining a bad checksum on the file, since com files have no header, there is no checksum to calculate.
 

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
i've had this running in my emu in BASIC.COM under PC-DOS 1 for over an hour, with no hiccups:

fake86-diskbasic-small.png
 

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
transcendental? sorry, i never got good grades in math class..... although i find math really interesting now. high school had a way of making it boring. i'll try some floating point now and see what it does.



it failed with flying colors:

fake86-mathfail.png



time to go bug-hunting. i'm surprised it even boots PC-DOS 1.00 with errors like that. it's probably safe to assume whatever's causing this could be responsible for no other versions of DOS booting.
 
Last edited:
Top