Last visit was: Thu May 01, 2025 5:16 pm
|
It is currently Thu May 01, 2025 5:16 pm
|
Emulation accuracy - request for help
Author |
Message |
mercury0x000d
Joined: Tue Jun 03, 2014 2:40 pm Posts: 139
|
Hey, y'all! Long time no see, eh?  Since my last project - EPiC - has been retroactively changed into a handheld, I've recently found reason to revisit all my 68000-ish materials. Part of what I'm working on now involves making an emulator under which I can write and test OS code prior to completing the hardware on which it will run. To that end, I've been working on a simulator which runs in a web browser - think something like EASy68K, but running online. You just type in the URL, load up an S-Record file, and start running your code! As the project evolves, I'm pitting my work against the excellent testing resource found at https://github.com/SingleStepTests/680x0 to make sure my simulator does what is expected of it. In this manner, I've gotten several instructions (AND, EOR, LSL, LSR, NOP, NOT, OR, SWAP, TAS, and TST, so far) working to 100% accuracy through over 8,000 tests each, but I'm stuck on the ABCD instruction which performs an add on a pair of BCD encoded numbers. One of the tests in the repo is for ABCD D7, D7, where D7 = 0x397C714F and the X bit is clear. The test specifies the answer should be 0x397C7104 but, just like EASy68K, my code gets a result of 0x397C71A4. I need to determine if EASy68K and I are wrong or the testing file is. And given that no product is without the possibility of a bug, and EASy68K is no exception despite how accurate it has always seemed to be in my experience, I initially set off on a search for a different, hopefully better, simulator to test against and act as a tie-breaker of sorts when my results don't match up with what the tests say it should be. But that got me thinking... as long as I'm using a simulator, there's always going to be the potential for inaccuracy. The only way to make sure I'm doing exactly what a real 68K would do is to actually see what a real 68K would do. And since I have no 68K computer in my lab, I got the bright idea to ask some of you fine folks to test this out for me!  So, that all being said, is there anyone with a real 68000-based computer who is willing to give the aforementioned instruction a shot and settle the issue? Many thanks in advance to whoever helps me get to the bottom of this! 
|
Sun Nov 03, 2024 10:55 pm |
|
 |
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1821
|
My Amiga is packed away, but in case it helps anyone, here's an assembly listing of an idea of a minimal test program - I'm supposing it might be easiest to poke this into memory and then somehow call it, then see the results at the carefully-chosen destinations: Code: 00001000 3E3C 1234 11 move.w #$1234, d7 00001004 CF07 12 abcd d7,d7 00001006 31C7 2230 13 move.w d7, $2230 0000100A 3E3C 714F 14 move.w #$714f, d7 0000100E CF07 15 abcd d7,d7 00001010 31C7 2240 16 move.w d7, $2240 00001014 4E75 17 rts
|
Tue Nov 05, 2024 1:24 pm |
|
 |
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1821
|
Aha - Ingo Paschker has run the testcase on an Amiga 1000 https://mastodon.social/@ipaschke/113431025069940663"My Amiga also thinks it's $397c7104..." (Thanks Ingo!)
|
Tue Nov 05, 2024 6:56 pm |
|
 |
rwiker
Joined: Tue Aug 08, 2017 1:33 pm Posts: 12
|
Maybe something like this:
decimal adjustment of 0x4f is 0x55 (note: for some reason, just adjust one of the operands... could be that the destination operand is assumed to be valid bcd) 0x4f + 0x55 = 0xa4 decimal adjust of 0xa4 = 0x04 (leaving X set, I guess)
|
Tue Nov 05, 2024 8:02 pm |
|
 |
mercury0x000d
Joined: Tue Jun 03, 2014 2:40 pm Posts: 139
|
That is AWESOME! I was really hoping someone would be able to verify this and you guys delivered.  I got the BCD math code working mostly on my own, but had some inconsistencies with the high nibble, which I straightened out by looking at EASy68K's source code to handle BCD, which is as follows: Code: // perform the ABCD operation result = ((SR & xbit) >> 4) + (source & 0xf) + (dest & 0xf); if (result > 9) { result = result - 10; carry = 1; } else carry = 0; temp_result = ((source >> 4) & 0xf) + ((dest >> 4) & 0xf) + carry; if (temp_result > 9) { temp_result = temp_result - 10; carry = 1; } else carry = 0;
result = result + (temp_result << 4); Turns out I had been ORing the two nibbles together to pack them back into a byte, when they should be added instead. Changing that made my code work on ever test case except two, one of which being the one you guys just solved. *sigh* Back to the drawing board, I guess...
|
Tue Nov 05, 2024 8:14 pm |
|
 |
mercury0x000d
Joined: Tue Jun 03, 2014 2:40 pm Posts: 139
|
I noticed the test suite to which I linked prior does have some open accuracy issues, like the two mentioned at https://github.com/SingleStepTests/680x0/issues/4 so I assumed the ABCD inaccuracy might have been another bug which had not yet been reported. Thanks for setting things straight! 
|
Tue Nov 05, 2024 8:17 pm |
|
 |
rwiker
Joined: Tue Aug 08, 2017 1:33 pm Posts: 12
|
rwiker wrote: Maybe something like this:
decimal adjustment of 0x4f is 0x55 (note: for some reason, just adjust one of the operands... could be that the destination operand is assumed to be valid bcd) 0x4f + 0x55 = 0xa4 decimal adjust of 0xa4 = 0x04 (leaving X set, I guess) That's needlessly complicated... you get the same result by adding, then decimal-adjusting the result: 0x4f + 0x4f = 0x9e => 0xa4 => 0x04
|
Tue Nov 05, 2024 8:57 pm |
|
 |
mercury0x000d
Joined: Tue Jun 03, 2014 2:40 pm Posts: 139
|
Ah, nice. I'll have to try incorporating that into my ABCD revisions. Basic BCD makes total sense. 0x97 is 97, 0x25 is 25, etc. The thing that initially threw me is when seemingly invalid digits are thrown in the mix, like 0xE2 or 0xF1. I was like... how do I interpret that?? I've also found the Double Dabble algorithm ( https://en.wikipedia.org/wiki/Double_dabble) which seems to unpack a packed BCD number quite nicely. I'll have to modify my code and see if I can finally pass all the ABCD tests. I'll keep you all posted! 
|
Tue Nov 05, 2024 9:18 pm |
|
 |
mercury0x000d
Joined: Tue Jun 03, 2014 2:40 pm Posts: 139
|
In the time since I last posted about this, I've had time to run through several implementations of the ABCD instruction. First and foremost, I wanted to try rwiker's suggestions: A. 0x4F normalizes to 0x55, 0x4F + 0x55 = 0xA4, 0xA4 normalizes to 0x04 B. 0x4F + 0x4F = 0x9E, 0x9E normailzes to 0xa4, which then normlaizes further to 0x04 While both work on the specific example specified, sadly neither works in all test cases. Pressing on, I tried using routines found on Wikipedia to convert both input values from BCD to normal values, then adding normally, then converting back to BCD, which also failed horribly. As I neared one week of beating my brain off of this problem, I got an idea: what if I scoured the internet for all the existing 68000 emulators I could find, poring over all of there source code to see how they did it? So that's exactly what I did. I found source for several emulators, and determined they all use one of three various implementations for the ABCD instruction. Code: Easier68k n/a https://github.com/Chris-Johnston/Easier68k Moira Method B https://github.com/dirkwhoffmann/Moira Moo68k n/a https://github.com/dd86k/Moo68k Musashi Method B https://github.com/kstenerud/Musashi Sim68K Method A https://github.com/ProfKelly/EASy68K Tricky68k n/a https://github.com/shysaur/Tricky68k WinUAE Method C https://github.com/tonioni/WinUAE
n/a = Instruction does not appear to be implemented
I compared the three prevailing implementations, converting the algorithm used in the original code to JavaScript, my language of choice for this project. This is Method A, used only by the Sim68K component of Professor Chuck Kelly's EASy68K simulator: Code: var temp = 0;
var sourceLow = (source & 0x0F); var destLow = (dest & 0x0F); var resultLow = sourceLow + destLow + carry;
if (resultLow > 9) { resultLow = resultLow - 10; carry = 1; } else { carry = 0; }
var sourceHigh = (source & 0xF0) >> 4; var destHigh = (dest & 0xF0) >> 4; var resultHigh = sourceHigh + destHigh + carry;
if (resultHigh > 9) { resultHigh = resultHigh - 10; carry = 1; } else { carry = 0; }
temp = resultLow + (resultHigh << 4);
When compared against the testing suite I mentioned previously ( https://github.com/SingleStepTests/680x0) Method A results in: Code: Tests run: 8064 Tests failed: 20 Success Percentage: 99.752 My initial ABCD function had an error which I was able to fix based on this code, but 99.752% success rate is what prompted me to create this thread to begin with. The D7 = 0x397C714F, ABCD D7, D7 problem was one of the 20 failed tests, so I had to make sure the testing suite wasn't in error. And, as you all already know, it wasn't. Moving on, this is my JavaScript implementation of Method B, used by Moira, Muashi, and a couple others of which I neglected to make note. This is by far the most popular method used of the projects I've seen. Code: temp = (source & 0x0F) + (dest & 0x0F) + carry; if (temp > 9) temp = temp + 6; temp = temp + (source & 0xF0) + (dest & 0xF0); if (temp > 0x99) temp = temp - 0xA0;
Which results in: Code: Tests run: 8064 Tests failed: 58 Success Percentage: 99.281
What? 99.281%?? That's even worse! Since those were the only two versions I found initially, I was about to give up, thinking that there would really be no good solution to this problem until I have the time to build a 68000 single board computer one day and can run the test suite against it to make sure there are no erroneous tests in the suite, and then determine exactly how the 68000 comes to the results it does. Regardless, I decided to press on just a little further, holding out hope that I would stumble upon a hidden gem. A thread I found on Atari-Forum.com ( https://www.atari-forum.com/viewtopic.php?p=393758) contained posts from a lot of folks who, like me, seemed also interested in making their emulated 68K cores work as close to 100% accuracy as possible. I thought to myself that maybe, just maybe, this would be a good place to look for further information, and I was not disappointed - I found one more implementation to try. This is Method C, used exclusively (to the extent of my testing) in the WinUAE emulator: Code: var nibbleLow = (source & 0x0F) + (dest & 0x0F) + carry; var nibbleHigh = (source & 0xF0) + (dest & 0xF0); var temp = nibbleHigh + nibbleLow; if (nibbleLow > 9) temp = temp + 6; if ((temp & 0x3F0) > 0x90) temp = temp + 0x60;
I cautiously executed the tests, and found... Code: Tests run: 8064 Tests failed: 0 Success Percentage: 100.000
Did I read that right? YES! YES A SOLUTION HAS BEEN FOUND!! ABCD NOW FUNCTIONS AT 100% ACCURACY! This means that, when my simulator is done, I'll be able to say it's more accurate than EASy68K  I feel like throwing a party now lol
|
Sat Nov 09, 2024 9:58 pm |
|
 |
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2307 Location: Canada
|
You could also have a look at hardware emulators, verilog code used for 68k emulators running in an FPGA for instance. There is TG68k, rf68000 and ao68000, and some others.
For rf68000 BCD is converted to binary, the add is performed, then the result converted back into BCD.
_________________Robert Finch http://www.finitron.ca
|
Wed Nov 13, 2024 10:20 am |
|
 |
mercury0x000d
Joined: Tue Jun 03, 2014 2:40 pm Posts: 139
|
robfinch wrote: You could also have a look at hardware emulators, verilog code used for 68k emulators running in an FPGA for instance. There is TG68k, rf68000 and ao68000, and some others.
For rf68000 BCD is converted to binary, the add is performed, then the result converted back into BCD. Checking out Verilog code is a great idea! That never even occurred to me. Thank you.  Also, if anyone wants to follow along with development, I've been committing to the project's GitLab ( https://gitlab.com/mercury0x0d/Easiest68K) regularly; I'll create a project announcement here in a new thread once it's all ready to run real code.
|
Thu Nov 14, 2024 5:43 am |
|
 |
mercury0x000d
Joined: Tue Jun 03, 2014 2:40 pm Posts: 139
|
I did promise an update...  Since my last post, Easiest68K has evolved to the point of passing 100% of the testing suite's tests. A minor inaccuracy does exist, which only crops up in the case of an exception; since Easiest68K is not bound to a 16-bit bus, it will happily grab an entire long word from memory when requested to do so, but this means that the fault address pushed onto the stack in the event of an address exception can vary slightly from what an actual 68000 would push. Further, this only occurs in the case of the MOVE instruction - all others report their PC value properly in an exception. Over time I plan to introduce some compensatory fixups to the MOVE instruction to mitigate this, but right now I'm simply not that worried about such a tiny edge case. After achieving full test compatibility, it was time to begin work on the EASy68K API. To get an idea of how well my simulator would perform, the first application I wanted to run on it was Lee Davison's "MHz" program ( http://www.easy68k.com/easy68kexamples.htm) which measures the speed of a 68000, either real or virtual. Since this program only requires two different calls into the EASy68K API, I implemented those first - one to get the number of milliseconds since program start, and another to output characters to the screen. After these were in place, I loaded up the .S68 file from MHz ZIP file and hit run on my simulator. It works! And the results aren't half bad considering that the language of choice for this project, JavaScript, is horribly inefficient for this kind of use. According to MHz.S68, my machine initially performed at a paltry 0.1 MHz, but I made a few tweaks which majorly boosted execution speed. It now reportedly performs similar to a real 68000 CPU running at around 2.5 MHz. That's a great improvement but, for comparison, running the actual EASy68K simulator in a VirtualBox virtual machine under Windows XP (yep, it's that old lol) gives an average speed of about 119 MHz. JavaScript may not break any speed records, but it is a convenient way to kind of "rapid prototype" a project, at least for me. There are several more optimizations I need to make to the code before it will be suitable for public use, but at least right now it's functional, and it runs. And that's a start. 
|
Fri Dec 20, 2024 9:07 pm |
|
 |
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1821
|
well done!
|
Fri Dec 20, 2024 9:58 pm |
|
 |
mercury0x000d
Joined: Tue Jun 03, 2014 2:40 pm Posts: 139
|
Thank you!  Today, I added support for a few of EASy68K's graphics-related API calls. The result? Well... 
You do not have the required permissions to view the files attached to this post.
|
Sun Dec 22, 2024 12:59 am |
|
 |
rwiker
Joined: Tue Aug 08, 2017 1:33 pm Posts: 12
|
Nice!
|
Sun Dec 22, 2024 5:47 am |
|
Who is online |
Users browsing this forum: claudebot and 0 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|