What's new

Gameboy Advance

OP
F

Flerovium

Member
72p96yfz.png

[MENTION=110864]Shonumi[/MENTION] I think I've just found some kind of emulator protection in Advance Wars =)
When this function is first called r6 is zero, which means that the ROM reads from bios memory. It seems that it compares the value it read with a word which seems to be the word of two thumb instructions.

EDIT: I also noticed similar odd reads in other ROMs and the bios also reads from an odd address in the io ram. Maybe it was common protection to "provoke" special mmu cases back then?
 
Last edited:

Shonumi

EmuTalk Member
[MENTION=110839]Flerovium[/MENTION] - If I remember correctly, it's actually pretty common for games to read from the BIOS like that. I saw that behavior a lot while I was debugging various games. Those reads are supposed to return values from the open bus. It could have been a low-quality anti-piracy/anti-emulation measure. The values are pretty consistent when reading from the BIOS, so it's easy to implement. But it's not a very advanced trick, and most games can even be fooled by passing incorrect values (some games check to make sure it's not zero). Other games do this check, but they boot just fine without any proper emulation of BIOS reads.

One other possibility is that it's just wasting time. I don't know why a game would do that specifically, but a dummy check could wait for a precise number of cycles. Either way, it's odd code. I wonder what the original C source code looked like :)
 
OP
F

Flerovium

Member
Pretty interesting stuff :) I also love this post https://mgba.io//2014/12/28/classic-nes/ about anti-emulation mechanisms of the ported nes games.

I just took a look at armwrestlers source and it looks like it doesn't expect rrx to happen in thumb mode for ROR with zero as amount? Is this actually correct? Because both NO$GBA and VBA-M do not fail this test which means they don't implement rrx. Anyway a friend of mine will lend me his NDS flashcart so I can test how the arm cpu usually behaves. Also I'm interested why ARM ldm tests fail in no$gba, vba-m and also my emulator. I don't quite get it from the armwrestler_new source.

This is btw the part testing ROR
Code:
	@ Test ROR by reg==0
	ldr 	r0,=0x80000000
	mov 	r1,r0	
	mov 	r2,#1
	mov 	r3,#0
	lsr 	r2,r2,#1	@ set carry
	ror 	r0,r3
	bcs 	_ror_ok_1
	orr 	r6,r5
	_ror_ok_1:
	cmp 	r0,r1
	beq 	_ror_ok_2
	lsl 	r4,r5,#Rd_SHIFT
	orr 	r6,r4
	_ror_ok_2:
 
OP
F

Flerovium

Member
[MENTION=110864]Shonumi[/MENTION] I found out why ldm! instructions where failing in my case. It seems like in the case of LDM the write back is only disabled if the current register is the base register AND the current register is NOT the first register in the list. I actually wrote a small test for the NDS which points this out for ldmia.

g7pmtnc9.png


You can find the source code here: http://pastebin.com/CawsS03F
And the binary file here: https://drive.google.com/file/d/0B-fqeILL3aGYdDlaWkJkOHVMRU0/view?usp=sharing

I also could find out that on real hardware RRX will not happen for ROR #0 in thumb mode :)
 

Shonumi

EmuTalk Member
Be very careful about LDM! behavior. It's not the same for the GBA and DS. There are differences between the ARMv4 and ARMv5 architectures. The ARM CPU in the GBA is ARMv4 (technically ARMv4T since it supports THUMB mode). For the DS, both CPUs are ARMv5 as I recall. On ARMv4, if the current register is the base register, and the current register is in the list, writebacks are disabled for LDM! On ARMv5 writebacks are enabled if the current register is the only register in the list, or not the last register in the list.

It's important to know these differences if you're going to make a DS emulator like I plan to ;) See GBATEK about the details -> http://problemkaputt.de/gbatek.htm#armopcodesmemoryblockdatatransferldmstm
 
OP
F

Flerovium

Member
Thanks I thought that the main differences between ARMv4(T) and ARMv5 were the 5-stage instruction pipeline and the newly introduced instructions.
 
OP
F

Flerovium

Member
[MENTION=110864]Shonumi[/MENTION] Do you have the cpu test by deadbody? I sadly cannot find any working download using google.
 
OP
F

Flerovium

Member
Thanks, you're my lifesaver! Well now I have a reason to implement mode 0 :p
Let's see if I can finally get something commercial running in the next days :p
I already tested Super Dodge Ball but it doesn't get any further than the developers logo..

EDIT: [MENTION=110864]Shonumi[/MENTION] Does the cpu test store its result on screen? Or does it store it in memory? Because I only get a "done with tests"?
 
Last edited:

Shonumi

EmuTalk Member
Deadbody's CPUTest doesn't store results on screen. If it doesn't see a problem, it won't print anything other than "done with tests". The ROM is very basic, so I'd use ARMWrestler if you want something more exact.

Also, good work getting the to the "ATLUS" screen in Super Dodge Ball! It's a small step, but it's an important one. If I recall, you need to implement DMA 3 (immediate transfer) and the VBlankIntrWait SWI. If your emulated CPU is accurate enough, that should get you to the title screen.
 
OP
F

Flerovium

Member
[MENTION=110864]Shonumi[/MENTION] Well at least I thought I got the entire "ATLUS" screen. I wrote a very basic and specialized mode0 renderer and it only showed up partially (the bottom half was black). Don't whats wrong there yet. I don't even get at the point where it first calls "VBlankIntrWait", it just does weird stuff from a specific point on. Don't know whats wrong there. According to armwrestler there are no bugs in my current thumb implementation, my arm implementation has some (I think they come from wrong ROR/RRX and ASR? implementation). So I think I will have to look at points that armwrestler doesn't check?
 
Last edited:

Shonumi

EmuTalk Member
Well, when I got Super Dodge Ball booting, I failed a lot of tests in armwrestler. I don't think you need to be perfect (although being perfect certainly helps :p)

Try to debug things step by step. Take an emulator like VBA-M, no$gba, or mGBA and run it against yours. Try to see if you run code that those emulators don't (this means your code is messing up somewhere). Another handy trick is set a breakpoint for yourself, then check the registers between your emulator and others. If anything looks different, try to go through everything in reverse until you can find out where your emulator deviates from others. Hope that makes sense. Good luck :D
 
OP
F

Flerovium

Member
[MENTION=110864]Shonumi[/MENTION] That's already what I'm doing at the moment :p Do you know if Super Dodge Ball requires proper memory mirrors? Not sure if I got them all correct :p Also maybe something with my interrupt handling is wrong.. At the moment I'm attempting LLE, maybe I should write some HLE code and see if that gets Super Dodge Ball running.

EDIT: I just found a very stupid cpu bug. SWI instructions always were detected as conditional branch ^^
This is what my code looked like^^ I hope that my fix will fix a lot of stuff, including Super Dodge Ball!
Code:
else if ((instruction & 0xF000) == 0xD000)
        {
            // THUMB.16 Conditional Branch
            return THUMB_16;
        }
        else if ((instruction & 0xFF00) == 0xDF00)
        {
            // THUMB.17 Software Interrupt
            return THUMB_17;
        }

EDIT2: And there was another bug in SWI for thumb XD I was writing the return address in r14_usr/sys. Now the swi_demo works. I will report later if other games do work now too :D
 
Last edited:

Shonumi

EmuTalk Member
[MENTION=110839]Flerovium[/MENTION] - No, Super Dodge Ball does not make use of memory mirror as far as I know. The only games that really do are the NES Classics. The code for Super Dodge Ball is pretty standard; it does not do a lot of tricks.
 
OP
F

Flerovium

Member
[MENTION=110864]Shonumi[/MENTION] It is quite funny that MSR/MRS are better documentated in GBATEK than in the official documentation of the ARM7TDMI-S :p I have fixed this issue now, but it only helped with the inoffical hle-bios from mgba which I was testing. I must have some serious issues in my ARM interpreter because some games seem to crash when calling some SWIs (Super Mario Advance 4 for example when calling swi 0xB or 0xC, I don't exactly remember). Currently I don't exactly where to start searching. Armwrestler reports bugs in mov, and all ldr instructions with register offsets (which all are caused wrong ASR/ROR handling) but I can't imagine that those would affect the control flow...). In thumb mode there are no reported bugs..

EDIT: Super Dodge Ball Advance doesn't even reach the point where it unsets the "forced blank" bit. Neither it enabled BG0. Super Mario Advance 4, only with hle-bios from mGBA or HLE of SWI 0xB/0xC gets to the "Gameboy Player" screen.

EDIT2: My condition for throwing an interrupt was wrong (I think). I checked IME != 0 AND (IE AND IF != 0) but it seemingly is IME != AND IF != 0. Now Super Dodge Ball disables "Force Blank" and also enables BG0. Kirby also seems to display "something" (the graphics looks very glitchy /distorted, have to check why that is happening)
 
Last edited:

Shonumi

EmuTalk Member
Kirby is also another good game to get running. It does not do a lot of fancy stuff, if I recall. The only thing is that it requires LZ77 decompression (SWI 0x12) and Huffman decompression (SWI 0x13). Huffman decompression is only used for the graphics shown at the pause screen (the ones that describe Kirby's abilities). Super Mario Advance 4 might need EEPROM support to boot, I'm not sure. Super Mario Advance (the 1st one) needs it to boot properly.
 
OP
F

Flerovium

Member
[MENTION=110864]Shonumi[/MENTION] Yes, the bug in kirby comes from some sort of CPU bug which I'll try to "hunt down" tonight. Because of that bug SWI 0x12 does strange things. I suppose that the bug occurs when processing compressed blocks because of the structure of the picture.

This is what it looked like:
g88vaahl.png


As you can see it misses the parts where the picture is filled with one color.

I wrote some small HLE code for LZ77 decompression and now I get at least to the titlescreen. I also implemented BG transparency and priority for mode 0 last night.

EDIT:

I just wanted to share with you that there is a tool called "ida pro 6.1" which I used in the past to analyze code. It organizes the disassembly as a control flow chart. This is what my current analysis of swi 0x12 looks like:
rnj6fgzt.png
 
Last edited:
OP
F

Flerovium

Member
[MENTION=110864]Shonumi[/MENTION] I fixed a small issue regarding shifts today. This bug actually was the reason why lz77uncompvram (SWI 0x12) went insane, so if you want to do LLE as I attempt currently, you'll have to implement this. I believe (I just looked at your source code, I didn't compile and check this) that your code suffers from this oddness, too. You know the special cases for #0 shift amount, right? These special cases are only applied when the shift amount is specified as immediate value, not if the shift amount is register specified.

EDIT: Now no tests (beside from ldmia, which should fail because it behaves different on ARMv4T) fail for me in armwrestler :D Nevertheless, weird things happen and I think the reason is that an interrupt gets issued while executing an software interrupt (I don't know why this happen because I take care of the IRQ-disable bit, maybe the bit gets lost at some mode switch? :S) Even Kirby suffers from this bug and randomly crashes.
 
Last edited:

Shonumi

EmuTalk Member
Flerovium said:
I believe (I just looked at your source code, I didn't compile and check this) that your code suffers from this oddness, too. You know the special cases for #0 shift amount, right? These special cases are only applied when the shift amount is specified as immediate value, not if the shift amount is register specified.

I actually already take care of this. You can see it in ARM.5 here -> https://github.com/shonumi/gbe-plus/blob/master/src/gba/arm_instr.cpp#L201. It doesn't perform any shifts at all if the shift amount is a register and that amount is zero. In these cases, technically the carry-out of a zero shift should be the old CPSR C Flag, but that information is only used in a handful of ARM.5 instructions (ADC, SBC, and RSC).

Anyway, keep up the good work. Can't wait to see what games you get playable :)
 
Last edited:
OP
F

Flerovium

Member
[MENTION=110864]Shonumi[/MENTION] Ahh my fault. I had theorized that this must happen because oft the swi 0x12 code. I tested it then in no$gba and I compared it with what you and mGBA do. I was too lazy check outside the arm7.cpp so I assumed you wouldn't check that. xD I added an parameter for each shifting function (expect LSL because it doesn't matter there) which for me is the nicer way :D
 
Last edited:

Top