Mike Chambers
Veteran Member
- Joined
- Sep 2, 2006
- Messages
- 2,621
oh my lookie here.. finally!
Congratulations! And also, you've won an award for the most screen captures in a thread .. ;-0
On an administrative note, please consider posting thumbnails that link to a full size image, and cut your .sig down a little bit - we're trying to keep things readable and have asked others to do the same recently.
Congratulations, Mike.
What's your next step? Convert the emulator into VHDL and dump it into an FPGA?
Total instructions executed: 189,954,994
Average instructions/sec: 7,550,172
Hi Mike,
Congratulations on getting your emulator to this stage! Really nice effort!
Doesn't matter that you wrote it in FreeBASIC. The horsepower gap between classic and current is so wide, I reckon you probably could've written that emulator in MS QBASIC, and still emulate a 4.77MHz 8088 system on any modern PC close enough in speed to the real thing, IMHO..
Like the CGA implementation - palettes look good
Regards,
Valentin Angelovski
thanks valentin! very true about the speed. at 3.2 GHz it's roughly the speed of a slow 286. i've always wondered how tough it would be to code an x86 emulator. now i know. very!
thanks to this project, i'm comfortable with writing assembly now since i got to learn exactly what each operation does.
what's kind of funny, is that if i really wanted to, i could take the Fake86 code, spend about 15 minutes making minor changes, drop the emulated memory size to say 32 KB, then compile it in QuickBASIC 4.x/7.1 and run it on an 8088. oh god................
Indeed it is, but the most important thing is you now have a good portion of it working!
BTW, if you ever feel the need for speed(tm), here are a few more tips:
1.) Probably an obvious one, I found it matters when and how you calculate the equivalent address. One method I use to speed things up here for my emulator, is to perform the 4-bits left shift portion of the EA calculation only when a jump/call is executed. This saves time, since one would normally fully calculate the equivalent address i.e. EA = (CS*16) + IP at every opcode fetch..
2.) Fetching four opcode bytes at a time in four-byte 'chunks' helps speed things up considerably on any inline assembly executed on the virtual CPU. For example, my Flea86 XT went from 130KIPS/sec to more than 320KIPS/sec average instruction throughput on this technique alone!
reptype = 0:
useseg = ds
segoverride = 0
Do
savecs = cs: saveip = ip: opcode = getmem8(cs, ip): StepIP 1
totalexec = totalexec + 1
'segment prefix check
Select Case opcode
Case &H2E 'segment CS
useseg = cs: segoverride = 1
Case &H3E 'segment DS
useseg = ds: segoverride = 1
Case &H26 'segment ES
useseg = es: segoverride = 1
Case &H36 'segment SS
useseg = ss: segoverride = 1
'repetition prefix check
Case &HF3 'REP/REPE/REPZ
reptype = 1
Case &HF2 'REPNE/REPNZ
reptype = 2
Case Else
Exit Do
End Select
Wend
Sub modregrm()
temp1 = getmem8(cs, ip): StepIP 1
mode = temp1 Shr 6
reg = (temp1 Shr 3) And 7
rm = temp1 And 7
Select Case mode
Case 0
If rm = 6 Then Disp = getmem16(cs, ip): StepIP 2
If ((rm = 2) Or (rm = 3)) And (segoverride = 0) Then useseg = ss
Case 1
Disp = signextend(getmem8(cs, ip)): StepIP 1
If ((rm = 2) Or (rm = 3) Or (rm = 6)) And (segoverride = 0) Then useseg = ss
Case 2
Disp = getmem16(cs, ip): StepIP 2
If ((rm = 2) Or (rm = 3) Or (rm = 6)) And (segoverride = 0) Then useseg = ss
Case Else
Disp = 0
End Select
Select Case mode
Case 0
Select Case rmval
Case 0: EAptr = (useseg Shl 4) + getreg16(bx) + si
Case 1: EAptr = (useseg Shl 4) + getreg16(bx) + di
Case 2: EAptr = (useseg Shl 4) + bp + si
Case 3: EAptr = (useseg Shl 4) + bp + di
Case 4: EAptr = (useseg Shl 4) + si
Case 5: EAptr = (useseg Shl 4) + di
Case 6: EAptr = (useseg Shl 4) + Disp
Case 7: EAptr = (useseg Shl 4) + getreg16(bx)
End Select
Case 1, 2
Select Case rmval
Case 0: EAptr = (useseg Shl 4) + getreg16(bx) + si + Disp
Case 1: EAptr = (useseg Shl 4) + getreg16(bx) + di + Disp
Case 2: EAptr = (useseg Shl 4) + bp + si + Disp
Case 3: EAptr = (useseg Shl 4) + bp + di + Disp
Case 4: EAptr = (useseg Shl 4) + si + Disp
Case 5: EAptr = (useseg Shl 4) + di + Disp
Case 6: EAptr = (useseg Shl 4) + bp + Disp
Case 7: EAptr = (useseg Shl 4) + getreg16(bx) + Disp
End Select
End Select
End Sub
Quite a heck of a way to learn though, isn't it?
I mean, couldn't one just open up a book and read up on it or something? ;-)
That made me laugh so hard, once I digested the meaning of that statement. :happy7:
In any case, it sounds like you're having fun as well and there's still some more fun in store for you. Once again great work!
PS: Just for the record, I also tried running other classic home computer emulators on top of my emulator (pretty silly huh?). Whilst they ran very slow, they might actually run ok if I had more processor 'oomph available. Some of these early vintage computer emulators included Tandy (CoCo1/2), Apple II and Sinclair (ZX80/81)..
hmm, yeah. the way i'm doing it now, i fetch an opcode byte and any prefixes for it like this:
/* Prefix opcode checking code snipped */
and then what follows is of course a big select case statement with all the other possible opcodes, and if the opcode being executed has a ModRegRM byte, i call my ModRegRM function which looks like this and calculates the EA:
/* ModRegRM byte handler code snipped */
thanks, yeah i'm having a great time. it would be interesting to see it run on an 8088 though, no?
have you considering upgrading the CPU you are using? that would be really cool.
ah i thought you were referring to calculating the address that the modregrm byte calculates for all those wacky addressing modes for some reason. reading your post again, i don't know how i came to that conclusion lol. yeah that would be faster definitely. i'm just calculating it every time. didn't even think of that.
i actually started re-writing the whole emulator in C last night, btw. i decided i'd like it to be faster and portable to non-x86 platforms.
... and JIT has WHAT to do with portable C code exactly?!? JIT compilation is by definition processor target specific and ASSEMBLY LANGUAGE coding... since it involves recompiling the code you want to emulate to the processor target.In that case, I would recommend searching up on 'Just-in-time (JIT) processor emulation techniques. Note that it does add an extra layer of complexity and also increases emulator resource requirements, though the resultant speedup may be worth it..
... and JIT has WHAT to do with portable C code exactly?!? JIT compilation is by definition processor target specific and ASSEMBLY LANGUAGE coding... since it involves recompiling the code you want to emulate to the processor target.
i see an A>
typing stuff at the prompt just fills the screen with garbage though. hmm.
i wonder what is going on here.