CPU Clocks

From WikiPrizm
Jump to navigationJump to search

The SH7724 processor used by the Casio Prizm, a SuperH 4-A with no FPU, utilizes four clocks to regulate commands. These clocks are known as the CPU clock, the data bus clock, the SH clock and the peripheral clock.

CPU clock

The CPU clock is the main clock used by the processor. It directly controls the speed of the processor. The CPU clock itself is controlled by a clock pulse generator (CPG). The CPG consists of a input clock signal from a Crystal oscillator which is divided to achieve the standard 58 MHz clock frequency of the Prizm. The circuit also contains two internal phase locked loops (PLL circuits) which output data about the state of the CPG.

Peripheral clock

The peripheral clock operates similarly to the CPU clock and is derived from the same CPG signal. It's used to operate peripheral modules and also controls several registers with the CPG control unit, such as the FRQCR (Frequency Control Register)

Bus clock

This clock controls the speed of memory reads and other hardware related functions. Its frequency is determined upon boot by the load on the CKIO pin and can take the the value of either 1x or 4x the frequency of the crystal oscillator. This value cannot be changed after startup. The bus clock is also used as the signal source for the Peripheral and CPU clocks. If the set division ratio correlates to a speed over 200Mhz, memory operations may go haywire.

SH clock

This clock, the SuperHyway clock, affects the speed of the SuperHyway bus that connects most operations within the processor, such as instruction fetching/sending, and IL data access.

Registers

There is one register used to modify the CPG. This is the Frequency Control Register (FRQCR), 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. 
*/ 

Changing clock frequencies

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

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);

Precautions when changing clock frequencies

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

References

<references/>