Clock Pulse Generator

From WikiPrizm
Jump to: navigation, search

The Clock-Pulse Generator on the Prizm, similar to the SH7724's CPG, allows executing code to dynamically alter the operating frequencies of the various clocks in the SH7305.

Registers

This section is incorrect as it doesn't mention the FLL and the individual divisors. Also, there are more than one FRQCR registers.

Frequency Control Register (FRQCR1)

The FRQCR1 is a longword memory-mapped to 0xA4150000 which can only be accessed as a longword for Read and Write operations. A description of it in technical bit-field breakdown is below:

/* 
* FRQCR 
* 31: Kick 
*   Writing 1 here updates CPG settings 
* 29-24: PLL 
*   Multiplier = (PLL + 1) * 2 
* 23-20: I_CLK 
*   CPU Clock Divisor 
* 15-12: SH_CLK 
*   SuperHighway Clock Divisor 
* 11-8: B_CLK 
*   Bus Clock Divisor 
* 3-0: P_CLK 
*   Peripheral Clock Divisor 
* 
* Divisor values: 
*   0000 x1/2 
*   0001 x1/3 
*   0010 x1/4 
*   0011 x1/6 
*   0100 x1/8 
*   0101 x1/12 
*   0110 x1/16 
*   1000 x1/24 
*   1001 x1/32 
*   1010 x1/36 
*   1011 x1/48 
*   1101 x1/72 
* 
* Updates to the FRQCR do not go into effect until 1 is written to the kick bit. 
*--------------------------------------------------------------------------------- 
* 
* Before using the watchdog timer it migt be necessary to call enable_mtspcr(0, 13), 
* this will enable the RCLK signal to the WDT. 
*/ 

FRQCR2

Todo

FLL

Todo

Divisors

Todo

Usage

Changing clock frequencies

This is wrong. The clock speed is effected by the CPU divisor, the PLL, and the FLL multiplier and divisor.

The one circuit that needs to be changed to make a difference in clock speed is the PLL circuit. The Prizm runs at 16x frequency, which is 58MHz (the base frequency is ~3.6MHz). It can be overclocked to at most 87MHz. One can simply write a new longword with the new PLL multiplication value to the FRQCR, and then rewrite it again with the top bit [31] (the FRQCR Kick, which needs to be set to 1 to "kick" the new value into place) set to change the frequencies. Valid PLL multiplication ratios are:

#define PLL_24x 0b010111 // 87 MHz
#define PLL_18x 0b010001 // 65.25 MHz
#define PLL_16x 0b001111 // 58 MHz (NORMAL SPEED)
#define PLL_15x 0b001110 // 54.37 MHz
#define PLL_12x 0b001011 // 43.5 MHz
#define PLL_8x  0b000111 // 29 MHz
#define PLL_6x  0b000101 // 21.75 MHz
#define PLL_4x  0b000011 // 14.5 MHz
#define PLL_3x  0b000010 // 10.8 MHz
#define PLL_2x  0b000001 // 7.25 MHz
#define PLL_1x  0b000000 // 3.6 MHz

Note that there are higher values that you may go to safely if you properly adjust the FLL

Example code

The below code can be used to change the PLL circuit multiplication:

void change_freq(int mult) {
	__asm__(
		"mov r4, r0\n\t"
		"and #0x3F, r0\n\t" 
		"shll16 r0\n\t" 
		"shll8 r0\n\t" 
		"mov.l frqcr, r1\n\t"  
		"mov.l pll_mask, r3\n\t"  
		"mov.l @r1, r2\n\t"  
		"and r3, r2\n\t"  
		"or r0, r2\n\t" 
		"mov.l r2, @r1\n\t" 
		"mov.l frqcr_kick_bit, r0\n\t" 
		"mov.l @r1, r2\n\t"
		"or r0, r2\n\t"
		"rts\n\t"
		"mov.l r2, @r1\n\t"
		".align 4\n\t"
		"frqcr_kick_bit: .long 0x80000000\n\t"
		"pll_mask: .long 0xC0FFFFFF\n\t" 
		"frqcr: .long 0xA4150000\n\t"
	);
}

For example, to change into 24x (87MHz) frequency, and back again:

change_freq(PLL_24x);

...

change_freq(PLL_16x);

Notes

Precautions when changing clock frequencies

Making the PLL circuit multiplier a non-valid value, will lead to the Prizm crashing.

Note that the Prizm actually uses non-valid values for the divisors, so the list of valid values may be questionable.