@frontein1
To supplement my previous post (you may wish to re-read that because I added edits to it throughout the day yesterday), I have even more info for you.
@phipli offers his C SOURCE CODE here:
Based on the discovery and code from Mustermann that it is possible to change the clock speed of the LC 475 and similar Macintosh computers, from software alone. This project is a user controllable...
github.com
It contains his MEMCjr configuration routines.
When using his
475 Overclock Control Panel, the "Advanced" settings look like this...
Phipli told me in the past to read the following datasheet to make sense of
Ni,
Mi and
P settings:
https://bitsavers.computerhistory.org/components/sierra/SC11412.pdf
I still was unclear on what numbers to type into the fields (see "Advanced" dialog box above), so I spoke to Mustermann, who laid the coding groundwork for Phipli's later coding work. He told me the following in regards to the
SC11412.pdf I linked above, noting that his mention of "Phipli's Tool" is referring to the 475 Overclock Control Panel and Extension combo. (Also note what
Mustermann says here about Gazelle, on the LC475, being a SC11412.)
There are 2 clock generators in the [SC11412] chip. One is managing PCLK the other one is managing MCLK.
Both are programmed using a common 20-bit shift register.
DS0 (first bit) of the register decide if you are programming clock generator 1 or clock generator 2.
Within my code and Phipli's tool, DS0 is always 1 so programming clock generator 1, controlling PCLK that is connected to MC88920/16. If you switch that to 0, you can change pixelclock (but I never tried that).
Don't worry about MCLK is controlling pixelclock. Apple just used them the other way round.
Next is about "P" [field]:
There are two bits DS4 and DS5 in the shift register selecting P divider.
So this part of the register can be 00=0,01=1,10=2,11=3.
As you can see from the datasheet, 11 set divider to 1/8, 10 to 1/4, 01 to 1/2 and 00 to 1/1
My code and Phipli's tool both use the binary value of DS4 and DS5.
So at the end clock is divided by Pi(in the calculation in the datasheet) = 2^P (from the tool).
I am not sure about the greyed-out Mi/Ni ["Ni value" field].
This is how calculation works:
CPUfreq = 2 (that is what MC88920 is doing) * N/(M*2^P)* 31.3344MHz(Frequency of Crystal oscilator)
48,01238 = 2 * 95 / ( 31 * 4) * 31.3344
"Min" and "Max" [fields] are more tricky.
Both choose a set of values for different registers. This has some influence to wait states of RAM, VRAM and ROM.
As the software is not able to read the data from the shift register and so does not know the current frequency some of these registers need to be set to a minimum value and some of the need to be set to a maximum value prior switch frequency. That is where these names came from.
After switching the values are set to an appropriate other value of the the table using the same subroutines.
That is why fields are named min and max.
Phipli's tool is able to chose one of 4 datasets for min group and another one of 4 for max group.
These datasets are populated with the values proposed by the MEMCjr (memory controller) datasheet for 20Mhz, 25Mhz, 33Mhz and 40Mhz.
If you choose a lower (if i remember right it was this order) one that appropriate you may reduce wait states,
operate RAM or ROM or VRAM out of specifications but may reach higher performance.
"Min" and "Max" are setting these registers:
MEMCjr "Configuration" is setting RAM and ROM wait states
MEMCjr "RefreshInterval" is changing RAM refresh timing
MEMCjr "FrameBufferConfiguration" is setting VRAM wait states
"BIOSTimeout" is set by the ROM as well but I was not able to determine in detail what it is doing
"BIOSConfig" is set by the ROM as well but I was not able to determine in detail what it is doing
Recommended values for Configuration, Refresh and FrameBufferConfiguration can be read from MEMCjr datasheet.
I then asked Mustermann about the
setregistermax &
setregistermin functions in the provided C code (see "
INIT.c.bin" linked above), and he provided this info:
Lets start with the setregistermax function:
Depending on the parameter (0-3) the function set one parameter Set.
In case level = 0 it is just doing the case 0 part.
case 0:
*((unsigned long*)(MEMCjrHoldingRegister)) = 0x0101>>6;
*((unsigned long*)(MEMCjrConfiguration)) = 0x0101;
config = 0x0000003f & *((unsigned long*)(FrameBufferConfiguration));
config = config + ((0x0000003f & *((unsigned long*)(MEMCjrHoldingRegister)))<<6);
config = config & 0x000000ff;
*((unsigned long*)(MEMCjrHoldingRegister)) = config>>6;
*((unsigned long*)(FrameBufferConfiguration)) = config;
break;
MEMCjr has only 6bit databus, but registers are usualy 12bit.
So to write 12bit you need first write the upper 6bit into MEMCjrHoldingRegister and then write the lower 6bit into the target register.
So the lines...
*((unsigned long*)(MEMCjrHoldingRegister)) = 0x0101>>6;
*((unsigned long*)(MEMCjrConfiguration)) = 0x0101;
...just write 0x0101 into Configuration Register of MEMCjr.
For the FrameBufferConfiguration register, the bits 0-7 shall not be changed by the function.
So it first reads the register (again with support of HoldingRegister)...
config = 0x0000003f & *((unsigned long*)(FrameBufferConfiguration));
config = config + ((0x0000003f & *((unsigned long*)(MEMCjrHoldingRegister)))<<6);
...then sets the bits 8-11 to 0 (that is the parameter for level 0)
config = config & 0x000000ff;
and write back the result
*((unsigned long*)(MEMCjrHoldingRegister)) = config>>6;
*((unsigned long*)(FrameBufferConfiguration)) = config;
For Level=0
Configuration is set to 0x0101
FrameBufferConfiguration is set to 0x00?? (?? because these bits were not changed)
For Level=1
Configuration is set to 0x001A
FrameBufferConfiguration is set to 0x00?? (?? because these bits were not changed)
For Level=2
Configuration is set to 0x00DC
FrameBufferConfiguration is set to 0x02?? (?? because these bits were not changed)
For Level=3
Configuration is set to 0x02DC
FrameBufferConfiguration is set to 0x0A?? (?? because these bits were not changed)
Configuration register is setting wait states for RAM and ROM
FrameBufferConfiguration is setting wait states for RAM and ROM
E.g., Level 0 is 1 ROM waitstate, Level 1 is 2 ROM waitstate, Level 2 is 4 ROM waitstate and level 3 is 4 ROM waitstates.
As all these registers are about waitstates, for security reasons.
it is better to have more waitstates. So if frequency is between 2 datasets read from datasheet (e.g. between 25Mhz and 33Mhz the values should set to maximum of the values of the edges.
That is why the function is named setregistermax.
As I have a programmable ROM added to my LC475 that is quite fast (55ns, instead of 100ns or 120ns as the onboard ROM is) it makes sense for me to reduce ROMwaitstates at higher frequencies as well.
Current version of the Extension is not able to do this.
From my experience, ROM speed and waitstates have a significant impact to overall speed.
Lastly, Phipli's 475 Overclock Software is COMPATIBLE with the following Macs:
• LC475, P475, P476, Q605
• LC575, P577
EDIT: For those of you who want to learn more about the 475 Overclock software, I have a
comprehensive video about it.