Hi,
nick8325 wrote:You can tell how many cycles each instruction will take to execute on 386, though - google for 386intel and look at the instruction reference. Perhaps you could run some long instruction lots of times and see how long it takes. That just leaves the 486...
If you select the instruction well, the same timing code can be used for 386 and 486. I'd pick a small instruction like "shl eax,1", which costs 3 cycles on both 80386 and 80486, and then do a lot of them (being careful not to use too many L1 cache lines), with some tricks for the loop itself. For example:
Code: Select all
get_old_CPU_speed:
push ecx
mov eax,IRQhandlerA
call set_timer_IRQ_handler ;Change IRQ handler
jmp $ ;Do nothing until first timer IRQ occurs
endTiming:
mov eax,ecx
pop ecx
ret
align 32 ;Make sure it starts on it's own cache line
startTiming:
clr ecx ;Clear counter and cause initial cache miss
.wait:
times 66 shl eax,1 ;3 cycles (total of 198 cycles)
inc ecx ;2 cycles on 386, 1 cycle on 486
jmp .wait ;8 cycles on 386, 3 cycles on 486
IRQhandlerA:
mov eax,IRQhandlerB
call set_timer_IRQ_handler ;Change IRQ handler
mov al,0x20
out 0x20,al
add esp,12 ;Clean stack (remove CS, EIP and EFLAGS)
sti
jmp startTiming
IRQhandlerB:
mov eax,original_IRQhandler
call set_timer_IRQ_handler ;Restore original IRQ handler
mov al,0x20
out 0x20,al
add esp,12 ;Clean stack (remove CS, EIP and EFLAGS)
sti
jmp endTiming
For an 80386 this adds up to 207 cycles per iteration, while for 80486 it's 201 cycles.
I'd set the PIT for slightly longer than 25 ms. For example, a PIT count of 30000 would give you 25.14 ms between IRQs. Then I'd calculate the CPUs frequency:
[tt] CPUfreq = count * 1/0.025[/tt]
This will always be slightly too high because of differences in the number of cycles for 80386 and 80486, and the slightly longer amount of time between IRQs. Because it's always slightly too high, it's perfect for rounding down to the nearest 1/3 MHz. After this it should be 100 % accurate.
Of course you'd need to disable all IRQs except for the timer itself to get a reliable measurement, but this shouldn't be a problem - I assume you'd only want to measure it once during boot (don't have to worry about things like SpeedStep or LongRun for these CPUs).
Cheers,
Brendan