January 5th, 2011, 01:29 Posted By: wraggster
Pate has posted more news concerning his Dos Emulator for the DS:
Happy New Year! Thanks for all the feedback and bug reports you have been sending from the DS2x86 alpha 0.01 version. Those will help me focus my development efforts.
DSTwo SDK frustration
Sadly, the past week was mostly spent fighting with the DS2 SDK. Just before I released the alpha version, I noticed a problem with the key reading. I could not figure out what caused the problem, but I noticed that setting the screen refresh rate to 15fps made the problem much less severe, so I did that as a first aid fix in order to get the alpha version released. On Monday this week I then began working on a small test program that would display similar problematic key reading behaviour, and after a few hours of work I managed to get exactly the same symptoms.
When quickly pressing keys (for example D-Pad up/down keys), every now and then (every 15 seconds or so) there was a period of almost half a second when no key events (presses or releases) got recognized. I first noticed this when testing Wolfenstein 3D, in which a problem like that is very annoying. My small test program exhibited the same behaviour, and also stopped updating the lower screen during some testing runs, at about the same time when the first key reading problem for that test run appeared. I sent my test program as an email attachment to the SuperCard SDK contact person "king d", but haven't yet received a reply.
I assumed the most probable cause for the problem was my using the timer interrupt to update the screens, but curiously, after I changed the test program to only update a flag in the timer interrupt and perform the actual screen update in the main loop (when the flag is on), the problem continued to appear. At that point I had no theories what could cause the problem, so I began digging into the SDK internals in an attempt to get a better understanding of how it works and what I should do to get rid of this problem.
I spent all of Tuesday deciphering the dump file and testing and debugging various things, and learned quite a lot of interesting information about the SDK internals. I first started by hooking into the main interrupt handler (the source code for which is provided by the included specs/start.S file in the SDK). I found out that the actual interrupts that the SDK uses have something to do with the GPIO2 I/O system of the processor, and are numbered 155 and 156, and the handlers for these interrupts are called cmd_line_interrupt and data_line_interrupt. I found out that the cmd_line_interrupt is called on the average 128 times per second in my test program, while the data_line_interrupt is called over 3000 times per second.
I looked at the dump file for the cmd_line_interrupt, and noticed that it reads 4 halfwords (8 bytes) from address 0xB4000000 (which is not documented in the JZ4740.h header file, so I believe it is something specific to the DSTwo), and stores these into memory area called cmd_buf32. Then it jumps to different locations in the code based on the first byte of this command buffer. Looking at what happens in the different command handlers (and testing the contents of the command buffer using my test program) I was able to determine that command 0xC3 is a key event command, command 0xC1 seems to clear the "buffer busy" flag (meaning it is some sort of an acknowledgement for a received screen or audio buffer), and command 0xC5 gets sent after every 30 seconds or so if nothing else is happening (so it might be some sort of a keep-alive or idle command).
So, finding the command 0xC3 gave me the idea of hooking directly into this interrupt (instead of using my timer interrupt) to handle key presses and releases. This should mean no missed key events, as immediately when I get the interrupt from the SDK interface I can call the ds2_getrawInput() function of the SDK, put the key event into a buffer and launch an emulated IRQ9 (which is the x86 keyboard interrupt). I did this, and the key input began to work properly in the test program, but the weird occasional hangs still remained.
On Wednesday I then continued looking into the hanging problem, and after various failed tests I suddenly noticed that I had used the wrong offset into the pmain_buf variable when checking whether the lower buffer is free! Argh! Well, I fixed this to use the correct offset, and after that my test program began to work correcly, even when updating the screen from inside the timer interrupt.
I then made the same changes to DS2x86 itself (changed the key input to use the cmd_line_interrupt hook and using the correct offset in the pmain_buf to check whether the lower screen buffer is free). Quite frustratingly, though, this did not fix the problems in DS2x86 itself. I am currently pretty much at loss as to what exactly is wrong in my method of using the SDK, as no changes I do seem to fix the problems completely. By Thursday morning I got fed up with this problem, and reverted to the same code I used in the Alpha 0.01 version (but with the pmain_buf access fix), so that it still keeps missing the key presses every now and then, but the lower screen seems to update properly. I hope I will eventually get an idea about how to fix the key input.
Improved exception handling
There is already a simple exception handling code in the 0.01 Alpha version, but I have now improved it a bit further. This new exception handling has helped me a lot while coding, as I occasionally write some severe bug in the code that crashes the system completely. Earlier when I did not have the exception handler installed the DSTwo would just hang, and then I had a lot of trouble trying to guess which of my changes caused this and why. Now I get an exact address in the code, and I also this week added some more information, like a text message describing the reason (in addition to printing "Exception 5", I print "Address error on stote at address 0x12345678!" or something like that. That will show me also the faulting data address together with the code address. I can then check the dump file to see exactly where in the code the problem is. I found a good list of the possible exception codes at some Harvard University course notes.
This exception message printing only works because I use the timer interrupt to handle the screen updating. Even when the actual emulator code has crashed and will not progress further, the timer interrupts still run and can send data to the NDS side from the MIPS side. I added some code to the specs/start.S code provided with the SDK to store the exception address, cause and failing address to global variables, and in my timer interrupt handler I can then check whether these variables are set, and if so, show the "Blue Screen of Death" on the lower screen. The code that I added to the start.S exception_handler routine looks like this:
mfc0 k0, C0_CAUSE
ori k1, zero, (0x08<<2) //Only detect SYSTEM CALL exception
andi k0, k0, (0x1F<<2)
beq k1, k0, 1f //is SYSTEM CALL exception
// ----- DS2x86 addition -----
la AT, ds2x86_exception_address // Get address of the exception address store
sw k0, 4(AT) // Save exception cause
lw k1, (4*30)(sp) // Get the exception address
sw k1, 0(AT) // Save exception address
mfc0 k1, C0_BADVADDR // Failing address (on certain exceptions)
sw k1, 8(AT) // Save failing address
lw AT, (4*27)(sp) // Restore AT
// ----- DS2x86 addition -----
and in the same start.S source code I added the global variables that can then be accessed from my timer interrupt handler:
// ----- DS2x86 addition -----
// ----- DS2x86 addition -----
Protected mode work
On Thursday, after I got fed up with the SDK problems, I then went through some of the log files you have been sending (thanks again for those!), and downloaded a couple of games to use as a test bench when improving DS2x86. I decided to try and get the protected mode features working a bit further, so I selected three games, Zone 66 which uses a newer version of the same PMODE header that my Trekmo demo used, Jazz Jackrabbit, which uses some Borland DPMI extender, and of course Doom, which uses the DOS4GW extender used by many other DOS 386-specific games as well. To save time (as the DS2x86.plg has grown so big that it now takes about 7 minutes to FTP-transfer to my SD card), I test each of those three games, and then add all three opcodes (or other required features) before testing the three games again. Currently all three are in protected mode, and I just added support for changing the interrupt vector start address (for Zone 66), and am about to add protected mode LES opcode handling (for Jazz Jackrabbit) and the protected mode LAR opcode handling (for Doom).
Before I started work on these games, though, I increased the emulated PC RAM size, which also meant increasing the page map table. Now I emulate 16MB of RAM (1MB conventional and 15MB extended), so the 4DOS memory command shows the following. I had to fix the CPU flags handling before the 4DOS "memory" command started working at all, as my flags worked like Pentium flags so that 4DOS thought it was running on a Pentium and tried to use the cpuid opcode.
Curiously, after I had increased the PC RAM size, the keyboard reading problem got much worse. Almost every second keypress was not recognized even on the DOS prompt, and playing Wolfenstein 3D was pretty much impossible, as you had to keep clicking on the keys for several times before any key events happened. This was quite weird, and it began to look like the key reading problem has something to do with the size of the plg file, and especially with the .bss section size of the file. I looked at the symbol dump, and noticed that the main irq_table was AFTER my emulated PC RAM area (which now was 16MB, half of the total memory size of the DSTwo). So, I then spent some time looking into ways to make the linker put my emulated RAM area last in the unitialized data section. I finally found a GNU LD manual that showed me a way to change the specs/link.xn file so that my RAM area was put last. Immediately after I did this, the key reading began to work like it did before my RAM increase, so that the DOS prompt seems to work fine but Wolfenstein 3D still experiences some problems. Interesting that the location of variables in the memory causes such problems! Perhaps this the reason why my test program works fine, as it is so much smaller. But, in any case, now I have had to make changes to both of the files in the specs directory, which will probably get overwritten when installing a new SDK version, so I need to make sure I have my own copies of these files in a safe place.
For more information and downloads, click here!
There are 0 comments - Join In and Discuss Here