scePowerSetClockFrequency
-
- Posts: 110
- Joined: Tue Feb 27, 2007 9:43 pm
- Contact:
scePowerSetClockFrequency
In psppower.h, prototype is this:
/**
* Set Clock Frequencies
*
* NOTE: Please use scePowerSetBusClockFrequency and
* scePowerSetCpuClockFrequency instead of this function
* for clock <= 222 and bus <= 111.
*
* @param cpufreq - cpu frequency, valid from 1-333
* @param ramfreq - ram frequency, valid from 1-333
* @param busfreq - bus frequency, valid from 1-166
*/
int scePowerSetClockFrequency(int cpufreq, int ramfreq, int busfreq);
I think should be:
/**
* Set Clock Frequencies
*
* @param pllfreq - pll frequency, valid from 19-333
* @param cpufreq - cpu frequency, valid from 1-333
* @param busfreq - bus frequency, valid from 1-167
*
* and:
*
* cpufreq <= pllfreq
* busfreq*2 <= pllfreq
*
*/
int scePowerSetClockFrequency(int pllfreq, int cpufreq, int busfreq);
/**
* Set Clock Frequencies
*
* NOTE: Please use scePowerSetBusClockFrequency and
* scePowerSetCpuClockFrequency instead of this function
* for clock <= 222 and bus <= 111.
*
* @param cpufreq - cpu frequency, valid from 1-333
* @param ramfreq - ram frequency, valid from 1-333
* @param busfreq - bus frequency, valid from 1-166
*/
int scePowerSetClockFrequency(int cpufreq, int ramfreq, int busfreq);
I think should be:
/**
* Set Clock Frequencies
*
* @param pllfreq - pll frequency, valid from 19-333
* @param cpufreq - cpu frequency, valid from 1-333
* @param busfreq - bus frequency, valid from 1-167
*
* and:
*
* cpufreq <= pllfreq
* busfreq*2 <= pllfreq
*
*/
int scePowerSetClockFrequency(int pllfreq, int cpufreq, int busfreq);
-
- Posts: 110
- Joined: Tue Feb 27, 2007 9:43 pm
- Contact:
Just to confirm:
scePowerGetPllClockFrequencyInt()
scePowerGetCpuClockFrequencyInt()
scePowerGetBusClockFrequencyInt()
does in fact return the 1st, 2nd, & 3rd arguments of
scePowerSetClockFrequency(pllfreq, cpufreq, busfreq);
eg.
setting scePowerSetClockFrequency(333, 266, 111);
then,
scePowerGetPllClockFrequencyInt() returned 333
scePowerGetCpuClockFrequencyInt() returned 265
scePowerGetBusClockFrequencyInt() returned 110
Thus the prototype should be changed accordingly, as per above post.
scePowerGetPllClockFrequencyInt()
scePowerGetCpuClockFrequencyInt()
scePowerGetBusClockFrequencyInt()
does in fact return the 1st, 2nd, & 3rd arguments of
scePowerSetClockFrequency(pllfreq, cpufreq, busfreq);
eg.
setting scePowerSetClockFrequency(333, 266, 111);
then,
scePowerGetPllClockFrequencyInt() returned 333
scePowerGetCpuClockFrequencyInt() returned 265
scePowerGetBusClockFrequencyInt() returned 110
Thus the prototype should be changed accordingly, as per above post.
does this mean that this:
is also not valid anymore? (I guess this was just assumed because the wrong parameters didn't bring the expected results (?))
EDIT: anyway... sorry if this sounds stupid, but what's the "pll frequency" (what does it do)?
Code: Select all
* NOTE: Please use scePowerSetBusClockFrequency and
* scePowerSetCpuClockFrequency instead of this function
* for clock <= 222 and bus <= 111.
EDIT: anyway... sorry if this sounds stupid, but what's the "pll frequency" (what does it do)?
infj
-
- Posts: 110
- Joined: Tue Feb 27, 2007 9:43 pm
- Contact:
The pllfreq is what the cpu & bus freq is derived from. Its based on a ratio of x/511 of the pllfreq. Thats why even trying to set a definite freq eg. scePowerSetClockFrequency(333, 266, 111), cpu & bus wont return that exact frequency.
cpufreq will actually return (approx) 265.89 (which is 408/511 times pllfreq)
busfreq*2 will actually return (appox) 221.57 (which is 340/511 times pllfreq)
The ratio is stored 0xBC200000 for cpu & 0xBC200004 for bus (numerator is 1st 9 bits of upper halfword, denominator is 1st 9 bits of lower halfword).
You can get the ratio's with these:
// Get cpufreq ratio
int sceSysreg_driver_44704E1D(int *numerator, int *denominator);
// get busfreq ratio
int sceSysreg_driver_377F035F(int *numerator, int *denominator);
or set ratio:
// Set cpufreq by ratio
// both values have to between 1-511
// obviously numerator cant be greater than denominator
// eg. sceSysreg_driver_5664F8B5(511, 511) gives 100% of pllfreq
int sceSysreg_driver_5664F8B5(int numerator, int denominator);
// set busfreq ratio
int sceSysreg_driver_584AD989(int numerator, int denominator);
or set/get freq by float value:
// Set cpufreq by float
// Will set to nearest granuality
// eg. sceSysreg_drver_AB3185FD(200.0) will only give 199.84 (460/511 = 90.02% of default pllfreq (222))
int sceSysreg_drver_AB3185FD(float cpufreq);
// Get cpufreq
float sceSysreg_driver_0EA487FA(void);
// set busfreq
int sceSysreg_driver_136E8F5A(float busfreq);
// get busfreq
float sceSysreg_driver_F4811E00(void);
Thats about all I know....
cpufreq will actually return (approx) 265.89 (which is 408/511 times pllfreq)
busfreq*2 will actually return (appox) 221.57 (which is 340/511 times pllfreq)
The ratio is stored 0xBC200000 for cpu & 0xBC200004 for bus (numerator is 1st 9 bits of upper halfword, denominator is 1st 9 bits of lower halfword).
You can get the ratio's with these:
// Get cpufreq ratio
int sceSysreg_driver_44704E1D(int *numerator, int *denominator);
// get busfreq ratio
int sceSysreg_driver_377F035F(int *numerator, int *denominator);
or set ratio:
// Set cpufreq by ratio
// both values have to between 1-511
// obviously numerator cant be greater than denominator
// eg. sceSysreg_driver_5664F8B5(511, 511) gives 100% of pllfreq
int sceSysreg_driver_5664F8B5(int numerator, int denominator);
// set busfreq ratio
int sceSysreg_driver_584AD989(int numerator, int denominator);
or set/get freq by float value:
// Set cpufreq by float
// Will set to nearest granuality
// eg. sceSysreg_drver_AB3185FD(200.0) will only give 199.84 (460/511 = 90.02% of default pllfreq (222))
int sceSysreg_drver_AB3185FD(float cpufreq);
// Get cpufreq
float sceSysreg_driver_0EA487FA(void);
// set busfreq
int sceSysreg_driver_136E8F5A(float busfreq);
// get busfreq
float sceSysreg_driver_F4811E00(void);
Thats about all I know....
Or maybe the ME num/den regs haven't been located yet. I would imagine the PSP kernel would simply set the ME and CPU to 1.0 and the BUS to 0.5. I'm probably complete wrong :), but it seems like the simplest thing to do.hlide wrote:what do you mean ? that me cpu frequency is always 1.0 * pllfreq ?crazyc wrote:It seems, from some quick testing, that the media engine cpu frequency is equal to the pll frequency.
Some more testing shows that the media engine can set it's own frequency using the same rules as above, or so it would seem. When I set 0xbc200000 on the me to 0x00ff01ff or a ratio of 255/511 and set the me to the same, the me goes a lot faster. In fact when I set the pll to 222 and the me to a ratio of .5 the me is at the same clock as the sc when it is set to 191 or 86% of the PLL frequency. The me actually runs at ~50% of pllfreq at a ratio of 55/511.J.F. wrote: Or maybe the ME num/den regs haven't been located yet. I would imagine the PSP kernel would simply set the ME and CPU to 1.0 and the BUS to 0.5. I'm probably complete wrong :), but it seems like the simplest thing to do.
how do you measure the difference on SC and ME processors ? because I don't see any good way to do so. you'd probably need to let SC and ME processors to read their own COP0 Count register, preferrably without any interrupts.
SC processor side :
ME processor side :
_me_count and _sc_count are volatile non cached addresses to be readable for both processors.
ME code would wait until SC synchronizes and start to count cycles. So you should get _sc_count ~= _me_count when they use the same PLL, CPU and BUS frequencies. But you seem to tell us we would rather get something like _sc_count ~= _me_count/2 instead. Is that so ?
if 8192 is too small, just increase it.
NOTE: you could also use the ME/SC mutex to synch them.
SC processor side :
Code: Select all
int i, j;
*_sc_count = 1;
*_me_count = 0;
me_start(); // launch ME code
*_sc_count = 0;
j = _mfc0(COP0_Count);
do { i = _mfc0(COP0_Count) - j; } while ((_me_count != 0) || i > 8192);
*_sc_count = i;
ME processor side :
Code: Select all
int i, j;
while (*_sc_count); // wait for SC synch
j = _mfc0(COP0_Count);
do { i = _mfc0(COP0_Count) - j; } while ((_sc_count != 0) || i > 8192);
*_me_count = i;
ME code would wait until SC synchronizes and start to count cycles. So you should get _sc_count ~= _me_count when they use the same PLL, CPU and BUS frequencies. But you seem to tell us we would rather get something like _sc_count ~= _me_count/2 instead. Is that so ?
if 8192 is too small, just increase it.
NOTE: you could also use the ME/SC mutex to synch them.
Sounds like maybe the ME has a different restriction on the divisor. Maybe it only uses 8bits instead of 9, so 0x00ff01ff is REALLY 255/255, not 255/511. That would account for the speed difference you think you saw.crazyc wrote:Some more testing shows that the media engine can set it's own frequency using the same rules as above, or so it would seem. When I set 0xbc200000 on the me to 0x00ff01ff or a ratio of 255/511 and set the me to the same, the me goes a lot faster. In fact when I set the pll to 222 and the me to a ratio of .5 the me is at the same clock as the sc when it is set to 191 or 86% of the PLL frequency. The me actually runs at ~50% of pllfreq at a ratio of 55/511.J.F. wrote: Or maybe the ME num/den regs haven't been located yet. I would imagine the PSP kernel would simply set the ME and CPU to 1.0 and the BUS to 0.5. I'm probably complete wrong :), but it seems like the simplest thing to do.
The default is 0x01ff01ff and then the me clock is the equal to pllfreq. Also, when I use 1/9 (0x00010009) instead of 55/511 (0x003701ff) the me still runs at ~50% pllfreq.J.F. wrote: Sounds like maybe the ME has a different restriction on the divisor. Maybe it only uses 8bits instead of 9, so 0x00ff01ff is REALLY 255/255, not 255/511. That would account for the speed difference you think you saw.
That's what I did. Added the mutex per your suggestion.how do you measure the difference on SC and ME processors ? because I don't see any good way to do so. you'd probably need to let SC and ME processors to read their own COP0 Count register, preferrably without any interrupts.
Code: Select all
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <psppower.h>
#include <stdlib.h>
#include <string.h>
PSP_MODULE_INFO("me_clock_test", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
#define set_count(val) __asm__ ("mtc0 %0, $9\n"::"r"(val))
#define read_count(val) __asm__ volatile ("mfc0 %0, $9\n":"=r"(val))
#define sysreg_lock *((unsigned int volatile *)0xbc100048)
#define try_lock(cpu) (((sysreg_lock = (cpu+1)) & 3) == (cpu+1))
#define free_lock() (sysreg_lock = 0)
void me_run(void);
void me_end(void);
int main(int argc, char *argv[])
{
SceCtrlData ctl;
unsigned int count, me_count;
int status;
pspDebugScreenInit();
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_DIGITAL);
memcpy((void *)0xbfc00040, me_run, (int)(me_end - me_run));
sceKernelDcacheWritebackAll();
scePowerSetClockFrequency(222, 111, 111);
try_lock(0);
sceSysregMeResetEnable();
sceSysregMeBusClockEnable();
sceSysregMeResetDisable();
sceSysregVmeResetDisable();
status = pspSdkDisableInterrupts();
free_lock();
__asm__("sync\n");
set_count(0);
pspSdkEnableInterrupts(status);
while(1)
{
pspDebugScreenSetXY(0, 1);
sceKernelDcacheWritebackInvalidateAll();
read_count(count);
me_count = _lw(0xbfc00600);
pspDebugScreenPrintf("%08x %08x %f\n", count, me_count, (float)count/(float)me_count);
sceCtrlReadBufferPositive(&ctl, 1);
if(ctl.Buttons & PSP_CTRL_HOME)
{
sceKernelExitGame();
}
sceDisplayWaitVblankStart();
}
sceSysregMeBusClockDisable();
return 0;
}
Code: Select all
.set noreorder
.global me_run
.global me_end
.ent me_run
me_run:
li $2, 0xbc100000
li $3, 7
sw $3, 80($2)
1:
lw $3, 72($2)
bne $3, $0, 1b
nop
mtc0 $0, $9
li $2, 0xbc200000
li $3, 0x00010009
sw $3, 0($2)
li $2, 0xbfc00000
0:
mfc0 $3, $9
b 0b
sw $3, 0x600($2)
me_end:
.end me_run
huh, beware that an access to memory switchs CPU frequency to BUS frequency temporary so you should avoid having a different code when running on SC and ME processors (not speaking about miss cache too).
So you should really have the same code running a certain time as I showed above without any call to external functions for instance.
EDIT:
i read somewhere that instructions like lb/lbu/lh/lhu/lw/lwl/lwr/sb/sh/sw/swl/swr runs at bus frequency and not at cpu frequency. So if you have 63 cycles for a lw instruction (miss-cache), it doesn't mean 63 cycles at 333 MHz but rather at 166 MHz.
So you should really have the same code running a certain time as I showed above without any call to external functions for instance.
EDIT:
i read somewhere that instructions like lb/lbu/lh/lhu/lw/lwl/lwr/sb/sh/sw/swl/swr runs at bus frequency and not at cpu frequency. So if you have 63 cycles for a lw instruction (miss-cache), it doesn't mean 63 cycles at 333 MHz but rather at 166 MHz.
This may be part of the problem, but with this code, if I set cpufreq==pllfreq and the me clock multiplier to 1, both cpus run at very nearly the same rate.hlide wrote:huh, beware that an access to memory switchs CPU frequency to BUS frequency temporary so you should avoid having a different code when running on SC and ME processors (not speaking about miss cache too).
So you should really have the same code running a certain time as I showed above without any call to external functions for instance.
EDIT:
i read somewhere that instructions like lb/lbu/lh/lhu/lw/lwl/lwr/sb/sh/sw/swl/swr runs at bus frequency and not at cpu frequency. So if you have 63 cycles for a lw instruction (miss-cache), it doesn't mean 63 cycles at 333 MHz but rather at 166 MHz.
Hi! :)
I'm not able to set the bus clock to 14Mhz (or anithing less than 37Mhz != 9Mhz).
Can someone help me?
Reading here and also here http://lan.st/archive/index.php/t-854.html that's what I tried:
If I do:
Using these functions
I get this info:
As I understand there's this list of values:
That represent the PLL index.
PLL clock is calculated this way:
While CPU clock is calculated from PLL amd a ratio:
The BUS is:
The strange thing is that if I try:
I obtain this info:
What's that PLL index = 9? Shouldn't it be from 0 to 5?
Also changing numerator and denominator with
doesen't have any affect.
Another strange thing IMHO:
If I do
so the PLL index is equal to 9.
Then execute:
This is the info I get (BUS 9 and CPU 18):
I'm a little confused. ;)
Many thanks :)
Ciaooo
Sakya
I'm not able to set the bus clock to 14Mhz (or anithing less than 37Mhz != 9Mhz).
Can someone help me?
Reading here and also here http://lan.st/archive/index.php/t-854.html that's what I tried:
If I do:
Code: Select all
scePowerSetClockFrequency(222, 222, 111);
Code: Select all
// get pllfreq (default is 222Mhz)
float sceSysreg_driver_B21B6CBF(void);
// get index value (default is 3)
int sceSysreg_driver_B4560C45(void);
// set pllfreq based on table
// index is the index for the float table (0-5)
int sceSysreg_driver_DCA57573(int index);
// get basefreq (hardcoded as 37Mhz in prx)
float sceSysreg_driver_53A6838B(void);
// Get cpufreq ratio
int sceSysreg_driver_44704E1D(int *numerator, int *denominator);
// get busfreq ratio
int sceSysreg_driver_377F035F(int *numerator, int *denominator);
// Set cpufreq by ratio
// both values have to between 1-511
// obviously numerator cant be greater than denominator
// eg. sceSysreg_driver_5664F8B5(511, 511) gives 100% of pllfreq
int sceSysreg_driver_5664F8B5(int numerator, int denominator);
// set busfreq ratio
int sceSysreg_driver_584AD989(int numerator, int denominator);
Code: Select all
CPU : 222
CPU RATIO: 511/511
BUS : 111
BUS RATIO: 511/511
PLL : 222
PLL index: 3
basefreq : 37
Code: Select all
const float table[6] =
{
0x3DE38E39, // == 0.11111111
0x3EE38E39, // == 0.44444445
0x3F124925, // == 0.57142860
0x3F2AAAAB, // == 0.66666669
0x3F4CCCCD, // == 0.80000001
0x3F800000 // == 1
};
PLL clock is calculated this way:
Code: Select all
PLL = 37*9*table[PLL_index]
PLL = 37*9*0.66666669 --> 222
Code: Select all
CPU = PLL * (numerator/denominator)
CPU = 222 * (511/511) --> 222
Code: Select all
BUS = PLL/2 * (numerator/denominator)
BUS = 222/2 * (511/511) --> 111
Code: Select all
scePowerSetClockFrequency(29, 29, 14);
Code: Select all
CPU : 28 = 74*(200/511)
CPU RATIO: 200/511
BUS : 37 = 74/2*(511/511)
BUS RATIO: 511/511
PLL : 74 = 37*9*0,225225225 (?)
PLL index: 9
basefreq : 37
Also changing numerator and denominator with
Code: Select all
sceSysreg_driver_584AD989(280, 511);
BUS = 74/2 * (280/511) --> 20
Another strange thing IMHO:
If I do
Code: Select all
scePowerSetClockFrequency(29, 29, 14);
Then execute:
Code: Select all
sceSysreg_driver_DCA57573(8);
scePowerSetClockFrequency(29, 29, 14);
Code: Select all
CPU : 18
CPU RATIO: 511/511
BUS : 9
BUS RATIO: 511/511
PLL : 18
PLL index: 8
basefreq : 37
Many thanks :)
Ciaooo
Sakya
-
- Posts: 110
- Joined: Tue Feb 27, 2007 9:43 pm
- Contact:
Actually the list is longer then 5. Here's what I came up with after a little testing. I got it to work at 18.6Mhz but only with a light load. For everyone, don't try to set pllfreq to anything higher then 333Mhz unless you can handle wrecking it. I set it to 370 once but only by accident.sakya wrote: What's that PLL index = 9? Shouldn't it be from 0 to 5?
Code: Select all
pll fractions 0xbc100068, to set OR index with 0x80
0 1/9 (.111)
1 4/9 (.444)
2 5/9 (.571)
3 6/9 (.667)
4 7/9 (.8)
5 9/9 (1)
6 0?
7 0?
8 1/18 (.056)
9 2/9 (.222)
a 5/18 (.286)
b 3/9 (.333)
c 7/18 (.4)
d 9/18 (.5)
e 0?
f 0?
pll multiplers 0xbc1000fc 8:16
9
11
13
15
base clock = 37
9 11 13 15
0.056 18.6 (multipler doesn't matter)
0.111 37.0 (")
0.222 74.0 90.4 107 123
0.286 95.2 116 138 159
0.333 111 135 160 184
0.400 133 163 192 222
0.444 148 181 214 246
0.500 167 204 241 278
0.571 190 232 275 317
0.667 222 271 321 370
0.800 266 326 385 444
1.000 333 407 481 555