Page 2 of 2

Re: an 8086 PC emulator

Posted: Fri Jun 17, 2011 1:12 pm
by miker00lz
thepowersgang wrote:If you could provide that test program, that would be lovely. I hope to have this running DOS sometime soon :)
here's the code. what it does is exercise the CPU's EA calculation with a ton of different values in every addressing mode, then compare what it came up with against calculating the same using the ADD instruction.

Code: Select all

; testea.asm - A program to test the Intel 8086 CPU's
; various addressing mode calculations. Designed to
; verify correct functionality of my 8086 PC emulator, Fake86.

org 100h

;cli
push cs
pop ds

mov si, offset banner
call printmsg
;call printmsg

mov ax, 0F000h
mov es, ax
jmp loopmain

disptest dw 1234h

loopmain:
mov cx, oper1
add cx, oper2

mov bx, oper1
mov si, oper2
lea ax, [bx+si]
cmp ax, cx
jz bxdi
mov si, offset strfailbxsi
call printmsg

bxdi:
mov bx, oper1
mov di, oper2
lea ax, [bx+di]
cmp ax, cx
jz bpsi
mov si, offset strfailbxdi
call printmsg

bpsi:
mov bp, oper1
mov si, oper2
lea ax, [bp+si]
cmp ax, cx
jz bpdi
mov si, offset strfailbpsi
call printmsg

bpdi:
mov bp, oper1
mov di, oper2
lea ax, [bp+di]
cmp ax, cx
jz testsi
mov si, offset strfailbpdi
call printmsg

testsi:
mov si, oper1
lea ax, [si]
cmp ax, oper1
jz testdi
mov si, offset strfailsi
call printmsg

testdi:
mov di, oper1
lea ax, [di]
cmp ax, oper1
jz testbx
mov si, offset strfaildi
call printmsg

testbx:
mov bx, oper1
lea ax, [bx]
cmp ax, oper1
jz disp16
mov si, offset strfailbx
call printmsg

disp16:
mov bx, oper1
lea ax, [bx+8000h]
add bx, 8000h
cmp ax, bx
jz disp8
mov si, offset strfaildisp16
call printmsg

disp8:
mov bx, oper1
db 8Dh, 01000111b, 80h ;lea ax, [bx+80h]
add bx, 0FF80h
cmp ax, bx
jz nexttest
mov si, offset strfaildisp8
call printmsg

nexttest:
add oper2, 80h
cmp oper2, 0
jnz loopmain
mov si, offset dot
call printmsg
add oper1, 80h
cmp oper1, 0h
jnz loopmain

mov si, offset strgood
call printmsg



finished:
ret

pass:
mov si, offset strgood
call printmsg
ret

fail:
mov si, offset strfail
call printmsg
jmp finished

printmsg:
mov ah, 0Eh
cld
lodsb
cmp al, 0
jz done
int 10h
jmp printmsg
done:
ret

banner   db '8086 CPU effective address calculation test utility',13,10
         db 'Written on 3/4/2011 by Mike Chambers',13,10,13,10
         db 'Testing EA calcs, this may take several minutes.',13,10
         db 'Testing addressing modes', 0

strgood  db 'passed!',13,10,0
strfail  db 'FAILED!',13,10,0     
dot      db '.',0

strfailbxsi   db 'failure in [BX+SI]',13,10,0
strfailbxdi   db 'failure in [BX+DI]',13,10,0
strfailbpsi   db 'failure in [BP+SI]',13,10,0
strfailbpdi   db 'failure in [BP+DI]',13,10,0
strfailsi     db 'failure in [SI]',13,10,0
strfaildi     db 'failure in [DI]',13,10,0
strfaildisp16 db 'failure in [BX+Disp16]',13,10,0
strfaildisp8  db 'failure in [BX+Disp8]',13,10,0
strfailbx     db 'failure in [BX]',13,10,0

oper1 dw 0
oper2 dw 0
disp  dw 0


and here's another one to test your conditional branching:

Code: Select all

; branch.asm - A program to test the Intel 8086 CPU's
; various conditional branching operations. Designed to
; verify corrent functionality of my 8086 PC emulator, Fake86.

org 100h

cli
push cs
pop ds

mov si, offset banner
call printmsg

testjc:
mov si, offset strjc
call printmsg
call blankflags
call setcf
jc testjc2
call fail
jmp testjnc
testjc2:
call blankflags
mov bx, offset testjnc
push bx
jc fail
pop bx ;not used, just cleaning up the stack
call pass


testjnc:
mov si, offset strjnc
call printmsg
call blankflags
jnc testjnc2
call fail
jmp testjz
testjnc2:
call blankflags
call setcf
mov bx, offset testjz
push bx
jnc fail
pop bx
call pass


testjz:
mov si, offset strjz
call printmsg
call blankflags
call setzf
jz testjz2
call fail
jmp testjnz
testjz2:
call blankflags
mov bx, offset testjnz
push bx
jz fail
pop bx
call pass


testjnz:
mov si, offset strjnz
call printmsg
call blankflags
jnz testjnz2
call fail
jmp testjs
testjnz2:
call blankflags
call setzf
mov bx, offset testjs
push bx
jnz fail
pop bx
call pass


testjs:
mov si, offset strjs
call printmsg
call blankflags
call setsf
js testjs2
call fail
jmp testjns
testjs2:
call blankflags
mov bx, offset testjns
push bx
js fail
pop bx
call pass


testjns:
mov si, offset strjns
call printmsg
call blankflags
jns testjns2
call fail
jmp testjo
testjns2:
call blankflags
call setsf
mov bx, offset testjo
push bx
jns fail
pop bx
call pass


testjo:
mov si, offset strjo
call printmsg
call blankflags
call setof
jo testjo2
call fail
jmp testjno
testjo2:
call blankflags
mov bx, offset testjno
push bx
jo fail
pop bx
call pass


testjno:
mov si, offset strjno
call printmsg
call blankflags
jno testjno2
call fail
jmp testjp
testjno2:
call blankflags
call setof
mov bx, offset testjp
push bx
jno fail
pop bx
call pass


testjp:
mov si, offset strjp
call printmsg
call blankflags
call setpf
jp testjp2
call fail
jmp testjnp
testjp2:
call blankflags
mov bx, offset testjnp
push bx
jp fail
pop bx
call pass


testjnp:
mov si, offset strjnp
call printmsg
call blankflags
jnp testjnp2
call fail
jmp testja
testjnp2:
call blankflags
call setpf
mov bx, offset testja
push bx
jnp fail
pop bx
call pass


testja:
mov si, offset strja
call printmsg
call blankflags ;case 1
ja testja2
call fail
jmp testjbe
testja2: ;case 2
call blankflags
call setcf
mov bx, offset testjbe
push bx
ja fail
pop bx
testja3:
call blankflags
call setzf
mov bx, offset testjbe
push bx
ja fail
pop bx
testja4:
call blankflags
call setcf
call setzf
mov bx, offset testjbe
push bx
ja fail
pop bx
call pass


testjbe:
mov si, offset strjbe
call printmsg
call blankflags ;case 1
call setcf
jbe testjbe2
call fail
jmp testjg
testjbe2:
call blankflags
call setzf
jbe testjbe3
call fail
jmp testjg
testjbe3:
call blankflags
call setcf
call setzf
jbe testjbe4
call fail
jmp testjg
testjbe4:
call blankflags
mov bx, offset testjg
push bx
jbe fail
pop bx
call pass


testjg:
mov si, offset strjg
call printmsg
call blankflags
jg testjg2:
call fail
jmp testjge
testjg2:
call blankflags
call setzf
mov bx, offset testjge
push bx
jg fail
pop bx
testjg3:
call blankflags
call setsf
call setzf
mov bx, offset testjge
push bx
jg fail
pop bx
testjg4:
call blankflags
call setof
call setzf
mov bx, offset testjge
push bx
jg fail
pop bx
testjg5:
call blankflags
call setsf
call setof
call setzf
mov bx, offset testjge
push bx
jg fail
pop bx
testjg6:
call blankflags
call setsf
call setof
mov bx, offset testjge
push bx
jg pass
pop bx
call fail


testjge:
mov si, offset strjge
call printmsg
call blankflags
jge testjge2
call fail
jmp testjl
testjge2:
call blankflags
call setsf
mov bx, offset testjl
push bx
jge fail
pop bx
testjge3:
call blankflags
call setof
mov bx, offset testjl
push bx
jge fail
pop bx
call pass


testjl:
mov si, offset strjl
call printmsg
call blankflags
call setsf
jl testjl2
call fail
jmp testjle
testjl2:
call blankflags
call setof
jl testjl3
call fail
jmp testjle
testjl3:
call blankflags
call setsf
call setof
mov bx, offset testjle
push bx
jl fail
pop bx
testjl4:
call blankflags
mov bx, offset testjle
push bx
jl fail
pop bx
call pass


testjle:
mov si, offset strjle
call printmsg
call blankflags
call setzf
jle testjle2
call fail
jmp finished
testjle2:
call blankflags
call setsf
jle testjle3
call fail
jmp finished
testjle3:
call blankflags
call setof
jle testjle4
call fail
jmp finished
testjle4:
call blankflags
call setsf
call setzf
jle testjle5
call fail
jmp finished
testjle5:
call blankflags
call setof
call setzf
jle testjle6
call fail
jmp finished
testjle6:
call blankflags
call setsf
call setof
call setzf
jle testjle7
call fail
jmp finished
testjle7:
call blankflags
mov bx, offset finished
push bx
jle fail
call pass


finished:
ret

pass:
mov si, offset strgood
call printmsg
ret

fail:
mov si, offset strfail
call printmsg
ret

blankflags:
xor ax, ax
push ax
popf
ret

setcf:
stc
ret

setof:
pushf
pop ax
or ah, 00001000b
push ax
popf
ret

setsf:
pushf
pop ax
or al, 10000000b
push ax
popf
ret

setzf:
pushf
pop ax
or al, 01000000b
push ax
popf
ret

setpf:
pushf
pop ax
or al, 00000100b
push ax
popf
ret

printmsg:
mov ah, 0Eh
cld
lodsb
cmp al, 0
jz done
int 10h
jmp printmsg
done:
ret

banner db '8086 CPU conditional branch test utility',13,10
       db 'Written on 3/4/2011 by Mike Chambers',13,10,13,10,0
strjc  db 'Testing JC/JB/JNAE (jump if CF=1)... ',0
strjnc db 'Testing JNC/JNB/JAE (jump if CF=0)... ',0
strjz  db 'Testing JZ/JE (jump if ZF=1)... ',0
strjnz db 'Testing JNZ/JNE (jump if ZF=0)... ',0
strjs  db 'Testing JS (jump if SF=1)... ',0
strjns db 'Testing JNS (jump if SF=0)... ',0
strjo  db 'Testing JO (jump if OF=1)... ',0
strjno db 'Testing JNO (jump if OF=0)... ',0
strjp  db 'Testing JP/JPE (jump if PF=1)... ',0
strjnp db 'Testing JNP/JPO (jump if PF=0)... ',0
strja  db 'Testing JA/JNBE (jump if CF=0 and ZF=0)... ',0
strjbe db 'Testing JBE/JNA (jump if CF=1 or ZF=1)... ',0
strjg  db 'Testing JG/JNLE (jump if SF=OF and ZF=0)... ',0
strjge db 'Testing JGE/JNL (jump if SF=OF)... ',0
strjl  db 'Testing JL/JNGE (jump if SF<>OF)... ',0
strjle db 'Testing JLE/JNG (jump if SF<>OF or ZF=1)... ',0

strgood db 'passed!',13,10,0
strfail db 'FAILED!',13,10,0

Re: an 8086 PC emulator

Posted: Fri Jun 17, 2011 1:14 pm
by miker00lz
berkus wrote:
miker00lz wrote:alsooooooo... i added attack and decay to my adlib code http://rubbermallet.org/fake86-adlib(attack-decay).mp3
Sounds good!
thanks. it's generating square waves though, and i think i should change it to sine.

Re: an 8086 PC emulator

Posted: Fri Jun 17, 2011 1:22 pm
by miker00lz
i've got a question i'm hoping somebody has a solution for.. to keep track of timing (needs to be extremely precise) i've been using QueryPerformanceCounter() for windows builds, and clock_gettime (with CLOCK_REALTIME) for linux builds. they are definitely precise enough, but i hate the fact that i need to waste so much CPU to poll these so often. they are extremely slow.

what i really want is a roughly microsecond-accurate timer that triggers interrupts which i can use too hook onto a callback function. am i out of luck with this? surely there must be some way to do this with the windows and linux APIs?... and i'd like to keep it compatible with relatively recent versions of windows, ideally all the way back to win2k. something running an older windows than that is probably not the kind of system you want to run a PC emulator on... :lol:




EDIT: i was thinking that on x86 hosts, i could just branch a thread to keep doing CPUID+RDTSC with inline asm and lock it to a single CPU core but i want to make it portable.

Re: an 8086 PC emulator

Posted: Fri Jun 17, 2011 2:27 pm
by Artlav
Nice work.

If you're interested, here is my collection of testsuites for EPC's 80186:
http://orbides.1gb.ru/80186_tests.zip
res_*.bin contains the results expected at the offset 0x0 when you run *.bin test placed as a BIOS.

Although, if you have win 3.0 booting these are a little late.

About the timing - do you want to get precise real-time experience or something?
You won't get away from CPU overuse without many tricks. There is nothing better then scheduling to free the CPU (like sleep(1);), but it's hard to predict the duration.
Best results will be with rdtsc and active waiting, but you're still subjected to task switching.
Why bother?

Re: an 8086 PC emulator

Posted: Fri Jun 17, 2011 3:42 pm
by miker00lz
Artlav wrote:Nice work.

If you're interested, here is my collection of testsuites for EPC's 80186:
http://orbides.1gb.ru/80186_tests.zip
res_*.bin contains the results expected at the offset 0x0 when you run *.bin test placed as a BIOS.

Although, if you have win 3.0 booting these are a little late.

About the timing - do you want to get precise real-time experience or something?
You won't get away from CPU overuse without many tricks. There is nothing better then scheduling to free the CPU (like sleep(1);), but it's hard to predict the duration.
Best results will be with rdtsc and active waiting, but you're still subjected to task switching.
Why bother?
yeah the timing is for generating the real-time clock interrupt, as well as generating audio samples for output at the proper intervals. also, that link you gave is a 404. even though i've got win 3.0 booting, i'd still like to run it and see what happens. thanks.

Re: an 8086 PC emulator

Posted: Sat Jun 18, 2011 6:59 am
by Artlav
Try again, i don't usually delete hosted files, so i didn't bother to check. :(

About timer/RTC interrupt - isn't it related only to the CPU?
There should be a clock counter in CPU emulation, based on instructions executed, and the interrupt is called based on that.
You can then pad the CPU to average it at a given clock rate per real second, and you'll get a real-time system.
About the sound - no ideas, never implemented it.

Re: an 8086 PC emulator

Posted: Sat Jun 18, 2011 11:33 am
by miker00lz
Artlav wrote:Try again, i don't usually delete hosted files, so i didn't bother to check. :(

About timer/RTC interrupt - isn't it related only to the CPU?
There should be a clock counter in CPU emulation, based on instructions executed, and the interrupt is called based on that.
You can then pad the CPU to average it at a given clock rate per real second, and you'll get a real-time system.
About the sound - no ideas, never implemented it.
no the timer interrupt is based on a 1,193,180 Hz master clock regardless of CPU speed. it's divided by the value that you program into PIT channel 0. a PC's BIOS initially sets the dividier to 65536, which is 18.2 Hz. games often change it to go faster.

for the audio, i'm using it to generate correct frequencies for the PC speaker and adlib channels based on sample rate divided by output freq per channel. it's working well as i have it, i was just hoping for a less CPU intensive method than constant polling.

also, i got the tests zip. thanks!

Re: an 8086 PC emulator

Posted: Fri Jun 24, 2011 6:06 pm
by miker00lz
big update..

so, i've uploaded a current snapshot which should be considered unstable, but it's got Adlib emulation (not the greatest yet), plus Disney Sound Source, PC speaker, and networking support. if anybody wants to try it and let me know how it works for them, that would be awesome. :)

some programs dont like work with the networking yet for some reason, for example arachne. i'm trying to find out why. some things run fine with it.

my announcement of it with more detailed info:
http://fake86.rubbermallet.org/?article ... le-release

download the win32 compiled binaries package:
http://fake86.rubbermallet.org/?downloa ... -win32-zip

or, if you're on linux, the source tarball. run build.sh in it:
http://fake86.rubbermallet.org/?downloa ... -24-tar-gz

you must have the libsdl 1.2 development library installed to compile. in debian/ubuntu - apt-get install libsdl1.2-dev

and here is a 20 MB sample hard drive image with FreeDOS pre-installed, along with Wolfenstein 3D (which is really nice now with complete sound) and some other games:
http://fake86.rubbermallet.org/?downloa ... 6_drive-7z

^extract that to the folder you have the fake86 binary in and run fake86 -hd0 drive.raw

have fun! the code is quick enough to play Wolf3D smoothly on a 1 GHz pentium 3. :twisted:

Re: an 8086 PC emulator

Posted: Sat Jan 19, 2013 12:02 am
by ASMMan
Thanks for share it. Great job,man. I really like it. I'm performing some testing now. I been to able to run MS-DOS. I explored it,really. I played the game that you included thanks. But I'm not able to run a small kernel write with as86(by the way, what assembler are you using?) assembler. It run fine in my computer. I have maked the .iso file by using dd and mkisofs UNIX's programs combination. And so I write it to a CD-ROM. Ran fine as I've mentioned. By in the fake86 it disn't work. By default it doesn't print any error message(right?) and so I was looking for some way to get some state of current running process. I added the -verbose flag and I can see

Code: Select all

Set video mode 30h
Set video mode 20h
Set video mode 07h
Set video mode 03h
Illegal opcode: 65 @ 0000:0108
Illegal opcode: 65 @ F000:E03B
Illegal opcode: 65 @ F000:E03B
Illegal opcode: 65 @ F000:E03B
Illegal opcode: 65 @ F000:E03B
Set video mode 00h
why I'm getting this errors messages? what does this that mean?

Code: Select all

entry start
start:
      mov ax,#0xb800
      mov es,ax
      seg es
      mov [0],#0x41
      seg es
      mov [1],#0x1f
loop1: jmp loop1
The OS code is very very simple. Just print the 'a' letter in black color with blue background. I have get it from a page in the internet. A tutorial that I have read. This is as86 syntax; I had never touched it before.

I have make the file with:

Code: Select all

as86 boot.s -o boot.o
ld86 -d boot.o -o boot
boot.s is the above assembly code.

Another thing that I noticed,sometimes the emulator doesn't run correctly and exit because a segmentation fault error has been happened. As it just happen sometimes,I think that we have an UB in your C program?

and +1 thanks for provide a easy-to-install program. Unlike almost all linux programs where usually you enter in a stupid iteration of miss-packages. Not all cases a programs such as apt-get and zypper are enough.

Also, I'm a C programmer. I will read the source code. If a can provide some help to emulator, I will do.

(sorry for my bad english; not my native language speaker)

Re: an 8086 PC emulator

Posted: Sun Jan 20, 2013 6:43 pm
by ASMMan
I solved the problem of 'Ilegal opcodes'. It's fine now. The problem was because I had not put the PC signature in the binary file. 0x55 and 0xAA at byte 511 and 512 respectively. I have another question,not sure if an error in the program. But sometimes the emulator open the emulator itself in full screen mode,even if -fullscreen isn't passed in the command-line-options. And when it happens,I have no idea how to get out from there. My GUI environment is KDE,CTRL+ESC open the system process management,but it doesn't work. But after release the mouse by ctrl+alt keys combination and then I need to force the computer to reboot.

Also,thanks so much again for share it this program. I'm looking for sometime to contribute by some way.