SC/ME processors : memory mappings

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

SC/ME processors : memory mappings

Post by hlide »

SC and ME have the same revision code (PRId) "31040125", so we can expect a lot of similarities between them indeed.

Code: Select all

COP0 registers :
       [    SC   ]   [    ME    ]    
15 - 31040125 - 31040125 - PRId
16 - 00000480 - 00000480 - Config
I suspect both CPUs using a FM (Fix Mapped) MMU which could explain the current mapping and the lack of a TLB MMU.

COP0.Config is the same so they almost share the same memory mapping :

0x00000000-0x3fffffff : KUSEG0 -> kernel/user mapped.
0x40000000-0x7fffffff : KUSEG1 -> kernel/user mapped.
0x80000000-0x9fffffff : KSEG0 -> kernel unmapped cached
0xA0000000-0xbfffffff : KSEG1 -> kernel unmapped uncached

SC Processor :

Code: Select all

0x04000000 - 2MB   : cached VRAM
0x08000000 - 32MB : cached main memory

0x44000000 - 2MB   : uncached VRAM 
0x48000000 - 32MB : uncached main memory

0x84000000 - 2MB   : cached VRAM 
0x88000000 - 32MB : cached main memory

0xA4000000 - 2MB   : uncached VRAM
0xA8000000 - 32MB : uncached main memory
ME processor :

Code: Select all

0x04000000 - 2MB   : cached ???, mirror of 0x84000000 
0x08000000 - 32MB : cached main memory, mirror of 0x88000000

0x44000000 - 2MB   : uncached ???, mirror of 0xA4000000 
0x48000000 - 32MB : uncached main memory, mirror of 0xA8000000

0x80000000 - 2MB   : cached eDRAM
0x84000000 - 2MB   : cached ??? (can modify contents only in cache) 
0x88000000 - 32MB : cached main memory

0xA0000000 - 2MB   : uncached eDRAM
0xA4000000 - 2MB   : uncached ??? (unmodifiable contents)
0xA8000000 - 32MB : uncached main memory
ME processor has a weird memory starting at 0x?4000000. I dunno if it is for VRAM. If so, we probably need to enable its access through an unknown setting of a controller.
Last edited by hlide on Thu Dec 07, 2006 8:24 am, edited 3 times in total.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

if someone has more details about how to raise an interrupt from ME into SC and vice versa, I'm very interested.

Anyway, it would be interesting to check if ME processor can use the same exceptions than SC processor. They are necessary for creating a small kernel for ME processor that would be more robuste that the actual code we have. If we can figure the way how to signal the other processor to give an order or a result, it would be cool.

EDIT : I don't mean running SC exceptions code into ME processor but to have the same way to handle the exceptions with ME processor
TyRaNiD
Posts: 907
Joined: Sun Jan 18, 2004 12:23 am

Post by TyRaNiD »

Code: Select all

asm("sync\n");
_sw(1, 0xBC100044);
asm("sync\n");
Should raise interrupt 31 on the ME and vice versa.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

TyRaNiD wrote:

Code: Select all

asm("sync\n");
_sw(1, 0xBC100044);
asm("sync\n");
Should raise interrupt 31 on the ME and vice versa.
cool !!!! thanx very much !

EDIT: it doesn't seem to work. I probably miss something :/

According to yad4psp :

interrupt 31 : SYS_REG ME Codec. So this is not an exception but an interrupt. Maybe this interrupt is by default a "nop" so it may explain why i cannot receive anything (or this interrupt is masked ?)
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

hummm SYSREG_driver (FW 1.5) gives us :

Code: Select all

// sceSysregInterruptToOther ???
int 880790ac(void)
{
  _sync();
  _writew(1, 0xbc100044);
  _sync();
  return 0;
}

// sceSysregSemaTryLock ???
int 880790cc(void)
{
  _sync();
  v0 = _mfc0(22); // CPUId (0 -> SC / 1 -> ME)
  a2 = v0 + 1; // 1 -> SC / 2 -> ME
  _writew(a2, 0xbc100048); // try to acquire semaphore
  a3 = _readw(0xbc100048) & 3; // who owns semaphore ?
  return -((a2 ^ a3) != 0); // 0 if successful or -1 if not
}

// sceSysregSemaUnlock ???
void 880790fc(void)
{
  _sync();
  _writew(0, 0xbc100048); // owner releases semaphore
  _sync();
  return;
}
Last edited by hlide on Thu Dec 07, 2006 11:48 pm, edited 2 times in total.
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

We appreciate the work you're doing on the ME, hlide. This could really improve a variety of programs, being able to run some things on the ME.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

ok, semaphore is working. I am able to sync SC and ME with 0xBC100048.

now, i want to use int 31. Running PSPINSIDE, i can see it is activated and calls a function which sets an event flag.

pspsdk really lacks of functions on interrupts. I'm wondering how to proceed. I can see several interesting functions in http://pspdev.ofcode.com/api2.0/index.php?type=2&id=34 but i have no detail about them (i'm under FW1.5).

There could be one solution, to access the interrupt table and set our own interrupt for int 31... but it is very dirty. :/

EDIT: talking about semaphore, it is much more like a mutex indeed.
rapso
Posts: 140
Joined: Mon Mar 28, 2005 6:35 am

Re: SC/ME processors : memory mappings

Post by rapso »

hlide wrote:ME processor has a weird memory starting at 0x?4000000. I dunno if it is for VRAM. If so, we probably need to enable its access through an unknown setting of a controller.
afaik, before the psp was released, there were rumors talkin about 4MB VRam. maybe it's the upper or lower 2MB of that VRam, so maybe u cannot access it by the main cpu, but maybe set it as frontbuffer/display?

[edit]
I searched it and found the description on this side: http://www.hartware.de/review_492_3.html
Neben den 32 MB besitzen die CPUs, wie schon gesagt, rund 4 MB eDRAM. Diese 4 MB verteilen sich auf die Media Engine und den Grafikkern.
except of the 32MB main memory, 4MB eDRAM are available, splited to the ME and GU.
Wie bei der Haupt-CPU ist der Takt der Media Engine von 1 bis 333 MHz regelbar. Diese verfügt aber über 2 MB der insgesamt 4 MB eDRAM. Diese 2 MB hängen dabei an einem Bus, der mit der halben Taktfrequenz der Media Engine läuft, das heißt maximal 166 Mhz.
As the main CPU, the ME can be set from 1 to 333MHz, it has access to 2MB of the whole 4MB eDRAM. Those 2MB are running with the same speed as the bus of the ME, 166MHz.

[/edit]
maybe it's just for movie playing, but maybe we could even use it as 2MB additional texture memory (maybe even motion-textures)
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

I managed to set my own exceptions but i would like to be able to use the one already provided if possible.
This is the function set by default into cop0 status register EBASE :

Code: Select all

ctc0 $v0, $4
ctc0 $v1, $5
lui $v1, 0xBC200000
lui $v0, 0x1FF0000
ori $v0, 0x1FF
sw $v0, ($v1)
mfc0 $v0, $13
ctc0 $v0, $3
andi $v0, 0x7C
mfc0 $v1, $14
ctc0 $v1, $0
cfc0 $v1, $8
add $v1, $v0
lw $v1, ($v1)
mfc0 $v0, $12
jr $v1
ctc0 $v0, $2
I cannot find what 0xBC200000 is (not documented in yad4psp). Any idea ? is it something usable only for ME ?

cop0 control register 8 doesn't seem to contain a valid address on a 32-entry exception table, but we can set ours here.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

okay, now SC processor can display exception details coming from ME using 'pspDebugDumpException'. At least it should be a help to develop on ME processor.

I'm still clueless about how to deroute int 31 in SC processor so ME can signal an exception for instance. :/

Next task : SC signaling ME via int 31.

I'll plan to release a ME library which should allow ME and SC to communicate to each other and catch ME exceptions too when evrything is okay.

Maybe a small RPC-like mechanism can be added to allow ME processor to "borrow" SC ressources.
Chrighton
Posts: 58
Joined: Wed Jun 15, 2005 8:24 pm

Post by Chrighton »

Nice work, hlide. Thanks for keeping us up to date on your findings.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

since i'm unsuccessful with int 31, i tried to discover much about SYSREG functions :

Code: Select all

int sceSysregIntrInit(void)
{
  sceKernelRegisterIntrHandler(31, 1, 0x88080118, 0, 0x88089DF0);
  sceKernelEnableIntr(a0 = 31);
  return 0;
}

NOTE : 	0x88080118 seems to be in the .text section of module sceDMACPLUS_Driver.
 
int sceSysregIntrEnd(void)
{
  sceKernelReleaseIntrHandler(31);
  return 0;
}

int sceSysregInterruptToOther(void)
{
  _sync();
  _sw(0xbc100044) = 1;
  _sync();
  return 0;
}

int sceSysregSemaTryLock(void)
{
  _sync();
  v0 = _mfc0(22); // CPUId (0 -> SC / 1 -> ME)
  a2 = v0 + 1; // 1 -> SC / 2 -> ME
  _sw(0xbc100048) = a2; // try to acquire semaphore
  a3 = _lw(0xbc100048) & 3; // who owns semaphore ?
  return -(a2 != a3); // 0 if successful or -1 if not
}

void sceSysregSemaUnlock(void)
{
  _sync();
  _sw(0xbc100048) = 0; // owner releases semaphore
  _sync();
  return;
}
 
bool sceSysregEnableIntr(int no)
{
  if (no > 31) return 0x80000102;
  v0 = sceKernelCpuSuspendIntr();
  t0 = _lw(0x880089E04);
  _sw&#40;0x880089E04&#41; = t0 | &#40;1 << no&#41;
  sceKernelCpuResumeIntr&#40;v0&#41;;
  return &#40;t0 >> no&#41; & 1;
&#125;

bool sceSysregDisableIntr&#40;int no&#41;
&#123;
  if &#40;no > 31&#41; return 0x80000102;
  v0 = sceKernelCpuSuspendIntr&#40;&#41;;
  t0 = _lw&#40;0x880089E04&#41;;
  _sw&#40;0x880089E04&#41; = t0 & ~&#40;1 << no&#41;
  sceKernelCpuResumeIntr&#40;v0&#41;;
  return &#40;t0 >> no&#41; & 1;
&#125;

int sceSysregRequestIntr&#40;int cpu, int no&#41;
&#123;
  if &#40;&#40;no > 31&#41; || &#40;cpu > 1&#41;&#41; return 0x80000102;
  s0 = cpu;
  s1 = no;
  while &#40;sceSysregSemaTryLock&#40;&#41; < 0&#41;;
  t0 = 0xBFC00400 + &#40;cpu << 2&#41;;
  _sw&#40;t0&#41; = _lw&#40;t0&#41; | &#40;1 << no&#41;;
  sceSysregSemaUnlock&#40;&#41;;
  if &#40;_mfc0&#40;22&#41; != cpu&#41; sceSysregInterruptToOther&#40;&#41;;
  return 0;
&#125;

those functions are definitely weird... it seems to imply the interrupt can be "shared" between SC and ME. SYSREG seems to be used in such way that ME and SC can know what is in charge of such interrupt. I guess we should have a look on meAudio or meCodec instead.
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

Well, it makes sense that they would share the int. Think about how you would communicate with one int and one semaphore...

Both CPUs watch the same int.
CPU 1 decides it needs CPU 2 to do something for it.
CPU 1 tries to acquire the semaphore and is successful.
CPU 1 generates the int.
CPU 1's int handler sees it has the semaphore and exits.
CPU 2's int handler sees that CPU 1 has the semaphore and does what is needed to respond to CPU 1.
CPU 1 sees CPU 2 responding and releases the semaphore.
CPU 2 finishes and tries for the semaphore and is (maybe eventually) successful.
CPU 2 generates the int to show it finished.
CPU 2's int handler sees it has the semaphore and exits.
CPU 1's int handler sees CPU 2 has the semaphore and does what is needed to acknowledge CPU 2 is done.
CPU 2 releases the semaphore.

Something like that...
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

I prefer to say mutex instead of semaphore, for mutex is more appropriate according to what I saw. In fact, there are uses as "enter_critical_session" and "leave_critical_session".

This mutex protects access to 0xBFC00400/0xBFC00404 (i don't think they are part of interrupt controller but a "shared" data between SC and ME) and doesn't last very long indeed.

This mutex is not held when generating an int.

Those functions don't act really on interrupt controller. So I suppose you cannot use them solely but probably must be used along with functions having a real effect on interrupt controler.
Post Reply