Page 1 of 1
PS2 hangs up - Address Store Exception
Posted: Sun Jul 25, 2004 8:09 pm
by evilo
Hi all,
I'm currently busy on these free days to enjoy some development related to emulation... so I've started a small project but I'm completely blocked at a point and can't figure how to resolve it.
In my software I have a 68k emulated CPU, which makes the ps2 completely CRASH (hard soft required)when executed. (cpu core is the one from MUSASHI v3.3). I can compile it, I can call initialization routines (init mem, submem, etc.. ), but when I send it some code, and ask to run for a couple of cycles, I have the following screen on my ps2 :
http://members.lycos.co.uk/eviloweb/pics/exception.jpg
Does anybody has some experience with this, is there any requirements when dealing with cpu emulation on the ps2 ?
here is my make file for the m68k :
# _____ ___ ____ ___ ____
# ____| | ____| | | |____|
# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
#-----------------------------------------------------------------------
# Copyright 2001-2004.
# Licenced under Academic Free License version 2.0
# Review ps2sdk README & LICENSE files for further details.
EE_LIB = mc68000.a
EE_LFLAGS += -Wall -W -EL -G0 -O0 -nostdlib -DPS2_EE
EE_INCS += -I./obj
EE_OBJS = obj/m68kcpu.o obj/m68kops.o obj/m68kopac.o obj/m68kopdm.o obj/m68kopnz.o
INFILE = m68k_in.c
MSRC = m68kmake.c
MEXE = m68kmake.exe
all: obj $(EE_LIB)
clean:
rm -f $(OBJS) mc68000.a
obj:
mkdir obj
obj/m68kcpu.o: obj/m68kops.h m68k.h m68kconf.h
$(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c m68kcpu.c -o obj/m68kcpu.o
obj/m68kops.o: obj/m68kmake.exe obj/m68kops.h obj/m68kops.c m68k.h m68kconf.h
$(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c obj/m68kops.c -o obj/m68kops.o
obj/m68kopac.o: obj/m68kmake.exe obj/m68kops.h obj/m68kopac.c m68k.h m68kconf.h
$(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c obj/m68kopac.c -o obj/m68kopac.o
obj/m68kopdm.o: obj/m68kmake.exe obj/m68kops.h obj/m68kopdm.c m68k.h m68kconf.h
$(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c obj/m68kopdm.c -o obj/m68kopdm.o
obj/m68kopnz.o: obj/m68kmake.exe obj/m68kops.h obj/m68kopnz.c m68k.h m68kconf.h
$(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c obj/m68kopnz.c -o obj/m68kopnz.o
obj/m68kops.h: obj/m68kmake.exe
obj/m68kmake.exe obj $(INFILE)
obj/m68kmake.exe: m68kmake.c $(INFILE)
$(CC) $(WARNINGS) m68kmake.c -o obj/m68kmake.exe
include $(PS2SDK)/samples/Makefile.pref
include $(PS2SDK)/samples/Makefile.eeglobal
for the rest, I previously made a lot of stuff without any problems, so I don't think this would be a problem with my toolchain.
and note, that I used PS2SDK :)
Thank you beforehand !
Posted: Sun Jul 25, 2004 8:39 pm
by blackdroid
For whatever reason in your code you are trying to store something at 0xffffffff wich ofcourse is illegal and will cause an exception.
Time to debug, with objdump you can disasm your code and the exception screen tells you where the illegal opcode is ( EPC ).
( btw doesnt inlink or ps2client support exception to console ?, abit easier to read cut'n'pasted text than a photo )
Posted: Sun Jul 25, 2004 8:50 pm
by evilo
I thougth also, but it seems not.... or maybe I have something wrong with my install...
anyway, thanks for the tip with the EPC (didn't knew it was the program counter)....
so let's debug !
thx
Posted: Mon Jul 26, 2004 2:11 am
by evilo
well... after a few hour of debug, still no concrete result...
on a other hand, the z80 core has the same behaviour, this time giving a load/save inst execption, and value for EPC like 0101010101...
so I've the impression that everything is completely messed up....
regarding compilation flags, is there any possibility for something needed with this type of dev, is there some emu coders on ps2 outhere ?
Posted: Mon Jul 26, 2004 2:48 am
by blackdroid
try without any -O, how does the code around EPC look like ? does it look like any stack trashing ?
Posted: Mon Jul 26, 2004 5:03 am
by J.F.
Z80 + 68000 emulation... sounds like a Genesis emulation to me. What are you using as the ROM for the CPU to test it? The 68000 pulls its initial SP from 0 and its initial PC from 4, so the SP and PC will be from the memory you allocated to serve as the CPU memory + 0 and +4. This is initially mirrored to the ROM in a Genesis to allow it to boot into the ROM space. If you are not setting up the memory for the 68000 before hand, it will do all sorts of crazy things depending on what is in the allocated memory. If you aren't even allocating memory for the emulated CPU to acces, it will do even crazier things.
Posted: Mon Jul 26, 2004 9:53 am
by evilo
well, this is not a genesis emulator, but effectevely it could be.... anyway, common memory used by both cpu, bios image, and code (not rom...) are correctly loaded (when I make some memory dump using some crappy code, I can see it at the right address), so I think that on that side everything is ok.
In my opinion I have some issue with some pointers, or some type cast/conversion in the core (C core running before on a 32bit PC)... I've tried to changed declared type to be more "ps2 friendly", but without success, still hangs up :) I have no choice now than making some long intensive objdump debug session and try to understand what's going on.... I really miss some real debug now (with step by step, watch, breakpoint....) my dream would be also to find a source code of a compiled and running m68k on the ps2, so I could see if there is some makefile stuff I didn't saw, or anything... this things is getting me crazy !
At the code pointed by the EPC I have :
1178a8: a0c4ffff sb a0,-1(a2)
for me it sounds more like a stack "underflow", than a address issue (as a sub of -1 in a register shouldn't generate an address store execption). Now I must admit that I'm not a pro in MIPS internal hw & programming, so maybe that register is used for address storing, so giving a nice "FFFF..FF" (as the previously value is "00...00") and the shown error !
I think I will also try to play a bit with compilation flags, to see if I have different behaviour.....
Posted: Mon Jul 26, 2004 10:14 am
by blackdroid
well if a2 is = 0 what does that tell you ?
mips abi says a0 - a4 then t0 - t7 are passed as arguments, so a2 is most likely the third argument in some function wich you pass as NULL/unintialized. hence giving a nice exception when trying to store a byte on 0xffffffff
google for 3715.pdf its a nice doc written by IDT about mips.
Posted: Mon Jul 26, 2004 10:51 am
by J.F.
Hmm, if it's not a Genesis emu, it's a Neo Geo emu as those are the only machines to use both a 68000 and a Z80. That's fine... I'd love to see a Neo Geo emu for the PS2.
Remember that the 68000 only had a 24 bit address bus, so while code may access addresses like 0xFFFFDEC8 for speed, the actual address is 0x00FFDEC8. This could really cause wacky operation of an emu if you don't clip the address.
Posted: Mon Jul 26, 2004 6:25 pm
by evilo
Blackdroid,
Yes, a2 reg = 0, so minus -1 gives a nice "FF...FF", but you are right maybe I should read a bit more about MIPS before continuing, at least to understand correctly what I see while debugging !
J.F.
For the moment this is just a alpha proto doing almost nothing and also more a tech trial for my personal entertainement during this summer :-) but If I can resolve that crazy behaviour, we will see !
thanks to both of you, I will keep you inform on my cpu issue !
Posted: Wed Jul 28, 2004 6:28 am
by evilo
Hi there !
Still working on fixing my issue , I finally managed to see where is exactly the problem. in the main execution loop, I have :
case 0x32:
{
sdwCyclesRemaining -= 13;
dwTemp = *pbPC++;
dwTemp |= ((UINT32) *pbPC++ << 8);
psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */
while (psMemWrite->lowAddr != 0xffffffff)
{
if ((dwTemp >= psMemWrite->lowAddr) && (dwTemp <= psMemWrite->highAddr))
{
cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;
if (psMemWrite->memoryCall)
{
psMemWrite->memoryCall(dwTemp, cpu.z80A, psMemWrite);
}
else
{
*((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr)) = cpu.z80A;
}
psMemWrite = NULL;
break;
}
++psMemWrite;
printf ("endwhile\n");
}
if (psMemWrite)
{
cpu.z80Base[dwTemp] = (UINT8) cpu.z80A;
}
break;
with everything crashing when the following function is called
psMemWrite->memoryCall(dwTemp, cpu.z80A, psMemWrite);
psMemWrite being a structure defined as :
struct MemoryWriteByte
{
UINT32 lowAddr;
UINT32 highAddr;
void (*memoryCall)(UINT32, UINT8, struct MemoryWriteByte *);
void *pUserArea;
};
I also tried all possible solution when generating the core using make utility but without success.... without more advanded debugging tools, I don't know how to solve this....
anyone can help... ?
thank beforehand
Posted: Wed Jul 28, 2004 6:40 am
by Drakonite
You may want to start with outputting what values are in lowAddr, highAddr, and any other pertinent variables just before the memoryCall is made.
Examining what exactly memoryCall does and figuring out what point in it things are crashing would help as well.
Posted: Wed Jul 28, 2004 9:14 am
by evilo
Of course, and that's what I made !
the interesting point here is that the highAddr variable contains exactly the value pointed by the EPC (0x01010101) on the exception screen (on the ps2), so additionaly to the objdump info, that's what make me sure it was here !
other strange thing is that *memoryCall is not define anywhere, I also make a search on my whole disk (gcc, sdk, etc...) , but nothing (from what I understood, it should be used to declare some handler and trigger specific function on memory access on defined ranges) , but it compiles, so that's why I ask for help, hoping that somebody would know it... maybe some mz80 expert !
Posted: Wed Jul 28, 2004 9:38 am
by blackdroid
only MOS experts here.
Posted: Thu Jul 29, 2004 12:05 pm
by J.F.
case 0x32:
This is the LD (nn),A opcode.
{
sdwCyclesRemaining -= 13;
This instruction take 13 T-states to execute. 4 for the initial opcode fetch, 3 to fetch the first byte of the word offset, 3 to fetch the second byte of the word offset, and 3 to store the accumulator into the specified offset.
dwTemp = *pbPC++;
Fetch the first byte of the offset.
dwTemp |= ((UINT32) *pbPC++ << 8);
Fetch the second byte of the word offset. The bytes are fetched one at a time and combined via logical instructions to make this code endian independent.
psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */
We have a table of handlers that map the memory space. You start with the first one and loop through looking for a space that matches the offset.
while (psMemWrite->lowAddr != 0xffffffff)
Quick check if reached last handler.
{
if ((dwTemp >= psMemWrite->lowAddr) && (dwTemp <= psMemWrite->highAddr))
Check for valid offset address. If not, try next handler.
{
cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;
pbPC is a pointer in PC memory where the Z80 PC is pointing (to the next opcode), so the Z80 PC variable is updated by setting it equal to pbPC - the start of the Z80 memory the PC is fetching from.
if (psMemWrite->memoryCall)
Quick check to see if this handler needs an update call. For example, writes to RAM don't need a call, but writes to hardware or ROM do. With hardware calls, you take the byte and do something; with ROM, you just throw the byte away.
{
psMemWrite->memoryCall(dwTemp, cpu.z80A, psMemWrite);
Handler needs to call a routine to emulate something! Pass in the offset, the accumulator byte, and a pointer to the handler structure.
}
else
{
*((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr)) = cpu.z80A;
Just write the byte in the accumulator to temp storage for this range.
}
psMemWrite = NULL;
Clear the handler -> we did the write.
break;
}
++psMemWrite;
Try next handler range.
printf ("endwhile\n");
}
if (psMemWrite)
If no handler was found, just write the byte into Z80 memory.
{
cpu.z80Base[dwTemp] = (UINT8) cpu.z80A;
}
break;
To know exactly why it's failing when memoryCall is called, we need to know what routine it points to. You need to print the memory range before the call is made, then go back to the source and look through the table of handlers for the range that blew up.
Posted: Fri Jul 30, 2004 8:03 am
by evilo
IT WORKS !!!!!!!!!!! :lol: :lol: :lol: :lol: :lol:
The error was effectively in the handler .... the struct was containing a wrong type for the address (UINT16 instead of UINT32), and I was missing some initialization for the Z80 core.... and M68K core is running as well now (was needing the z80 to run)!
more important is that I have also graphics output om the screen !! colors are messed up, image is shifted, and half the right heidth but the games runs for 2/3 minutes (but hangs up after... ) well I feel crazy, this is amazing :)
there is still a lot of work, but this is already a big big step !
regarding speed, it's already seems to be fullspeed, even without sound, but with my crappy debug code inside !
I feel so happy guys, thank you so much !
Posted: Fri Jul 30, 2004 10:51 am
by blackdroid
pretty much what I said some posts ago then.
Posted: Fri Jul 30, 2004 5:47 pm
by J.F.
Good to hear. It'll be interesting to see what you come up with once you feel it's ready for others to try.
Posted: Sat Jul 31, 2004 12:39 am
by evilo
Of course,
next points I need to work on are :
- fix/clean up display routines
- Fix "hang up" after a few minutes
- add some basic controller support
There a very few things, but as I don't have full dedicated free time to work on, it will take me some time... but then I should have something starting to be shared and tried !!!!!
maybe I will put some wip page somewhere on the net....
Posted: Sun Aug 15, 2004 5:36 am
by evilo
so, it's out :
http://members.lycos.co.uk/eviloweb/
This is still an alpha version, but some games are almost fully playable, so I thougth it was a good idea to release a first version at this point.
enjoy anyway :)
Posted: Sun Aug 15, 2004 8:54 am
by J.F.
8)
Did I call that or what? Only two systems used both a 68K and a Z80.
Looks nice! I'll give it a try this weekend.