mirror of
https://github.com/cc65/cc65.git
synced 2026-01-23 08:16:38 +00:00
118 lines
3.6 KiB
C
118 lines
3.6 KiB
C
/*
|
|
* Sim65 timer example.
|
|
*
|
|
* Description
|
|
* -----------
|
|
*
|
|
* This example tests the clock cycle counter feature of sim65.
|
|
*
|
|
* The function 'timestamp' obtains the lower 32-bits of the clock cycle counter.
|
|
*
|
|
* The function 'calc_sum_terms' calculates the sum of a range of integers
|
|
* starting at zero. It simply iterates over all terms, which means that its
|
|
* runtime is a linear function of its input value.
|
|
*
|
|
* In the main function, we first derive an 'offset' value by getting two timestamp
|
|
* values, with nothing happening in between. Ideally this should yield a 0 clock
|
|
* cycle duration, but due to the overhead of calling the 'timestamp' function,
|
|
* and the 'timestamp' function itself, the difference between these timestamp
|
|
* will be non-zero. We store this value in the 'overhead' variable, and subtract
|
|
* this value in later measurements.
|
|
*
|
|
* Next, we measure the duration of calling the function 'calc_sum_terms' with two
|
|
* input values, 0, and 1. The duration includes storing the result in the 'result'
|
|
* variable.
|
|
*
|
|
* Extrapolating from these two measurements, and assuming that the runtime of
|
|
* calling 'calc_sum_terms' and storing its result scales linearly with its argument,
|
|
* we can predict the duration of a call to 'calc_sum_terms' with a much larger
|
|
* argument (max_terms = 10000).
|
|
*
|
|
* Finally, we actually measure the duration with max_terms = 10000. If the
|
|
* duration measured is equal to the predicted value, we exit successfully. If not,
|
|
* we exit with failure.
|
|
*
|
|
* Running the example
|
|
* -------------------
|
|
*
|
|
* cl65 -t sim6502 -O timer_example.c -o timer_example.prg
|
|
* sim65 timer_example.prg
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <sim65.h>
|
|
|
|
static uint32_t timestamp(void)
|
|
{
|
|
peripherals.counter.select = COUNTER_SELECT_CLOCKCYCLE_COUNTER;
|
|
peripherals.counter.latch = 0;
|
|
return peripherals.counter.value32[0];
|
|
}
|
|
|
|
static unsigned long calc_sum_terms(unsigned max_term)
|
|
/* A function with a runtime that scales linearly with its argument. */
|
|
{
|
|
unsigned k;
|
|
unsigned long sum = 0;
|
|
for (k = 0; k <= max_term; ++k)
|
|
{
|
|
sum += k;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
unsigned max_term;
|
|
unsigned long result;
|
|
uint32_t t1, t2, overhead;
|
|
int32_t d0, d1, duration;
|
|
int32_t predicted_duration;
|
|
|
|
/* Calibration measurement of zero clock cycles, to determine the overhead. */
|
|
|
|
overhead = 0;
|
|
t1 = timestamp();
|
|
t2 = timestamp() - overhead;
|
|
overhead = (t2 - t1);
|
|
|
|
/* Calculate call duration (including assignment of result) for argument value 0. */
|
|
|
|
max_term = 0;
|
|
t1 = timestamp();
|
|
result = calc_sum_terms(max_term);
|
|
t2 = timestamp();
|
|
d0 = (t2 - t1) - overhead;
|
|
printf("max_term = %u -> result = %lu; duration = %ld\n", max_term, result, d0);
|
|
|
|
/* Calculate call duration (including assignment of result) for argument value 1. */
|
|
|
|
max_term = 1;
|
|
t1 = timestamp();
|
|
result = calc_sum_terms(max_term);
|
|
t2 = timestamp();
|
|
d1 = (t2 - t1) - overhead;
|
|
printf("max_term = %u -> result = %lu; duration = %ld\n", max_term, result, d1);
|
|
|
|
/* Predict runtime for a much bigger argument value, 10000. */
|
|
|
|
max_term = 10000;
|
|
predicted_duration = d0 + max_term * (d1 - d0);
|
|
|
|
printf("predicted duration for max_term = %u: %ld\n", max_term, predicted_duration);
|
|
|
|
/* Do the actual measurement for max_term = 10000.
|
|
* Note: equality between the prediction and the measurement is only achieved if we compile with -O.
|
|
*/
|
|
|
|
t1 = timestamp();
|
|
result = calc_sum_terms(max_term);
|
|
t2 = timestamp();
|
|
duration = (t2 - t1) - overhead;
|
|
printf("max_term = %u -> result = %lu; duration = %ld\n", max_term, result, duration);
|
|
|
|
|
|
return 0;
|
|
}
|