|
|
Introduction
The intent of this document is to show the steps necessary in building your own XScale speed modification utility. There are a number of other various attributes of the XScale processor that can be modified. Using the techniques below other processor modification programs could be written. Modifying your processor settings can be risky and potentially damaging to the to processor or other system components. I cannot take responsibility for any damage resulting in modifications made using the techniques below. I also am not an ARM assembly expert and there are even a few things in the assembly code that I do not understand. I am learning and trying to fill in the gaps. I will comment the lines that I am not completely sure about the functionality. You are welcome to mail any questions or explanations riser@elevatedstudios.com or to post them to the message board
If you want to download the
Tools needed
The great thing is you don't need any other special tools! All the instructions are either found in eVC++ or are standard ARM assembly instructions. Just download the above two tools and you can follow the instructions below and start overclocking on your own today!
Steps
Intro Steps ( You can skip these if you already know VC++ wizards and MFC)
Global Defines
Add the following lines to a header file. You can use the header file generated for the dialog. That should be named APPNAMEDlg.h, where APPNAME is the name of the project created.
| // All speeds are given in MHz values
rounded up from the true MHz value, ex 290.6 = 291 // Run rates with no turbo #define SPEED_100 289 //010 01 00001 #define SPEED_118 290 //010 01 00010 #define SPEED_133 291 //010 01 00011 #define SPEED_148 292 //010 01 00100 #define SPEED_166 293 //010 01 00101 #define SPEED_199 321 //010 10 00001 #define SPEED_236 322 //010 10 00010 #define SPEED_266 323 //010 10 00011 #define SPEED_295 324 //010 10 00100 #define SPEED_332 325 //010 10 00101 // Turbo Rates 1.5 #define SPEED_TURBO15_295 449 //011 10 00100 - 294.9 MHz // Turbo Rates 2 #define SPEED_TURBO2_199 545 //100 01 00001 #define SPEED_TURBO2_236 546 //100 01 00010 #define SPEED_TURBO2_265 547 //100 01 00011 #define SPEED_TURBO2_295 548 //100 01 00100 #define SPEED_TURBO2_332 549 //100 01 00101 #define SPEED_TURBO2_398 577 //100 10 00001 // Turbo Rates 3 #define SPEED_TURBO3_299 801 //110 01 00001 #define SPEED_TURBO3_354 802 //110 01 00010 #define SPEED_TURBO3_398 803 //110 01 00011 // Freqency & turbo switch modes #define MODE_TURBOSWITCH 1 // Enter or exit turbo mode only (use with turbo speed switches) #define MODE_FREQSWITCH 2 // Enter the mode to switch the frequency #define MODE_ALLSWITCH 3 // Enter or exit turbo mode and switch frequency if necessary |
The above table captures all the valid run rates. There are more, but the values are not supported by the PXA250 according to the specs.
Also add the next section must be added to the header file. It will be explained a little further down
| // setProcSwitch() is the function declaration for the
assembly function which will start the frequency shift and/or enter turbo
mode extern "C" int setProcSwitch(int mode); // Virtual copy is used to make a program accessible copy of a memory location in physical memory extern "C" BOOL VirtualCopy(LPVOID dest, LPVOID src, DWORD size, DWORD flags); |
Function Definitions
Now create the following function:
| iint CSpeedStepperDlg::setSpeed(int speed, int mode) { // Hard coded in, but could comment out and use the mode argument for more flexibility. // Switching both the turbo mode and freqency if necessary will work for all cases // even if only one or the other is being changed. mode = MODE_ALLSWITCH; // 0x41300000 is the location of the CCCR register in memory. We will need this to change the // frequency multipliers. Why do I divide this by 256? Because I have to! Its a requirement // when using PAGE_PHYSICAL. Not really sure why though. LPVOID CCCR = (LPVOID)(0x41300000 / 256); int i = 0; // i contains the success value. // Allocate the space for the virtual reference to CCCR LPVOID VirtualCCCR = VirtualAlloc(0, sizeof(DWORD), MEM_RESERVE, PAGE_NOACCESS); // Copy the pointer from real memory into virtual memory. // If successful then the CCCR register can be updated and the // assembly code to start the switch can be called. if(!VirtualCopy((LPVOID)VirtualCCCR, CCCR, sizeof(DWORD), PAGE_READWRITE |PAGE_NOCACHE | PAGE_PHYSICAL)) { // Copy failed, back out and return an error value i = -1; VirtualFree(VirtualCCCR,0,MEM_RELEASE); VirtualCCCR = NULL; } else{ // Copy succeded // Copy the new speed into the CCCR register *(int *)VirtualCCCR = speed; // Call the assembly function to actually perform the turbo and/or frequency switch. i = setProcSwitch(mode); // Clean up memory by freeing the virtual register. VirtualFree(VirtualCCCR,0,MEM_RELEASE); VirtualCCCR = NULL; } // Return the error code return i; } |
Now you can call that function from the handler created for the button. Pass one of the speed settings from the #defines into the function and it will attempt to switch the processor to that speed. For instance calling setSpeed(SPEED_TURBO15_295, 3) will set the processor to 295 MHz.
Assembly Code
Next the assembly code must be created. Lets call the file overclock.asm. The first thing is to create the file. Next add it to your workspace. Once that is done, eVC++ must be configured to compile it. Go into project->settings menu. Select overclock.asm from the tree on the left. Then add the following configuration lines under the "Custom Build" tab. For commands put in something like the following
| armasm overclock.asm ARMDbg\overclock.obj |
Then for output put
| ARMDbg\overclock.obj |
in the box. Those two lines will instruct the project to use the arm assembler to compile the file. The project will automatically attemp to link the file that is created, overclock.obj into the project when it is built. This is also why the header file containing the line "extern "C" int setProcSwitch(int mode);" was necessary. This will act translation between C & assembly so the function can be run.
Now we have to actually code the assembly. I am not sure if mine is all that great, but it gets the job done. Here it is. I commented it pretty well. Just place it as is in the overclock.obj file. Basically all it does is copy the value you passed in as an argument into a register. Then it copies that register into a register on coprocessor 14. That register is the CLKCFG register. Once written into the CLKCFG register the turbo mode and/or frequency shifts are performed. It is VERY important to have the spacing the same as below. The lines that are indented must remain indented, the ones that are not indented must stay not indented.
| AREA |C$$code|, CODE,
READONLY ; The following code is a C listing |x$codeseg| ; The following section is code EXPORT setProcSwitch ; Export the function setProcSwitch, use an extern in c ; to map the function ; extern "C" int setProcSwitch(int mode) ; r0 will contain the paramater mode ; mode = 1 enter turbo, mode = 2 change processor speed, ; mode = 3 enter turbo and change processor speed. setProcSwitch ; The function name (exported above) MOV r3, r0 ; Move r0, the argument to setProcSwitch, into register r3 MCR p14, 0, r3, c6, c0, 0 ; Copy the contents of r3 into register c6 on ; coprocessor 14. MOV r0,#1 ; return 1 for success in register a1 MOV pc,lr ; return execution to where it last left off |x$dataseg| ; Data segment, there is nothing here END ; Must have the end statement |
That should be about it. Just compile everything and try it out. If you linked everything up together correctly then pressing the button should be enough to enable the switch.
I still plan to post the entire project, but the UI code is nothing special, but this stuff is pretty cool.
visitors since 1/17/2003