Clock Pulse Generator

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.