Added clock frequency computations/measurements, and frequency-delay/timer expression.

This commit is contained in:
lephe 2016-08-29 11:29:07 +02:00
parent 0205c39f21
commit d80de5683b
36 changed files with 851 additions and 151 deletions

View file

@ -12,7 +12,7 @@
#--- #---
# Modules # Modules
modules-gint = core keyboard mmu mpu rtc screen timer \ modules-gint = core clock keyboard mmu mpu rtc screen timer \
bopti display gray tales bopti display gray tales
modules-libc = setjmp string stdio stdlib time modules-libc = setjmp string stdio stdlib time
@ -173,7 +173,7 @@ mrproper: clean
distclean: mrproper distclean: mrproper
install: install:
CasioUsbUploader -f $(target-g1a) -w -l 1 p7 send -f $(target-g1a)
.PHONY: all clean mrproper distclean .PHONY: all clean mrproper distclean

65
TODO
View file

@ -1,44 +1,27 @@
Bugs to fix:
- Left-vram overflow when rendering text
- A few key hits ignored after leaving the application (could not reproduce)
- Lost keyboard control at startup (could not reproduce)
- Back-light issues
-------------- Simple improvements:
Lots of things to do - bopti: Monochrome bitmaps blending modes
-------------- - bopti: Partial transparency
- clock: Compute clock frequencies
- demo: Try 284x124 at (-60, -28) (all disadvantages)
- display: Rectangle-based drawing functions
- tales: Test all font encodings
- time: Compute CLOCKS_PER_SEC
- timer: Add duration and frequency settings
- core: Add VBR handlers debugging information (if possible)
- core: Implement all callbacks and a complete user API
@ known bugs Modules to implement:
+ simple improvements - Serial communication
- important milestones - Sound playback and synthesizing
~ needs investigation
Things to investigate:
@ possibility of vram left-overflow with text - Packed bit fields alignment
@ garbage displayed as year in the clock, possibly during edition (could not - Registers that may need to be saved within setjmp()
reproduce) - Registers that may need to be saved and restored by gint
@ a few key hits ignored after leaving the application - Possible bug when optimizing __attribute__((interrupt_handler))
+ rect functions
+ bitmap blending modes
+ minimize use of 7705.h and 7305.h; use local structures instead
+ partial transparency
+ gint vs. ML with 248x124 at (-60, -28)
+ call exit handlers
+ compute frequencies and CLOCKS_PER_SEC
+ test all font encodings
- improve exception handler debugging information (if possible)
- callbacks and complete user API
~ packed bit fields
~ exhaustive save for setjmp()
~ registers that need to be saved when configuring gint
~ possible bug when -O2'ing __attribute__((interrupt_handler))
Some notes
----------
Test cases for bitmap drawing:
- 32-alignment
- monochrome / gray
- small / large
- clipping
# blending modes

View file

@ -305,7 +305,7 @@ void main_menu(int *category, int *app)
"Image rendering", "Image rendering",
"Text rendering", "Text rendering",
"Real-time clock", "Real-time clock",
"Text formatting", "Clocks and timers",
NULL NULL
}; };
const char *list_perfs[] = { const char *list_perfs[] = {
@ -511,7 +511,7 @@ int main(void)
test_rtc(); test_rtc();
break; break;
case 0x0106: case 0x0106:
// test_printf(); test_timer();
break; break;
case 0x0201: case 0x0201:

View file

@ -76,10 +76,10 @@ void test_tales(void);
void test_rtc(void); void test_rtc(void);
/* /*
test_printf() test_timer()
Some text formatting. Clock timer and timer precision.
*/ */
void test_printf(void); void test_timer(void);

View file

@ -3,12 +3,9 @@
output. Note how symbols romdata, bbss, ebss, bdata and edata are used output. Note how symbols romdata, bbss, ebss, bdata and edata are used
in the initialization routine (crt0.c) to initialize the application. in the initialization routine (crt0.c) to initialize the application.
Two ram areas are specified. It happens, if I'm not wrong, that the Two ram areas are specified. The "real ram" is accessed direcly while
"real ram" is accessed directly while the "common" ram is accessed the other area is virtualized. It is not possible to execute code in
through the mmu. The interrupt handler resides in "real ram" because it virtualized ram.
couldn't execute well in ram. While SH7335 and SH7355 had no problems,
executing the interrupt handler in the common ram on SH7305-based new
models caused trouble to the OS, apparently overwriting ram data.
*/ */
OUTPUT_ARCH(sh3) OUTPUT_ARCH(sh3)

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -178,7 +178,6 @@ void test_bopti(void)
dupdate(); dupdate();
} }
leave = 1;
do do
{ {
leave = 1; leave = 1;

View file

@ -11,25 +11,30 @@
static void draw(int delay1, int delay2, int selected) static void draw(int delay1, int delay2, int selected)
{ {
extern Image res_opt_gray_start; extern Image res_opt_gray_start;
int *vl = gray_lightVRAM(); unsigned int *vl = gray_lightVRAM();
int *vd = gray_darkVRAM(); unsigned int *vd = gray_darkVRAM();
gclear(); gclear();
locate(1, 1, "Gray engine");
for(int i = 0; i < 63; i++) for(int i = 0; i < 36; i++)
{ {
int o = (i << 2) + 2; int o = ((i + 12) << 2) + 2;
vl[o] = vl[o + 1] = -((i & 31) < 16); unsigned light = -((i % 24) < 12);
vd[o] = vd[o + 1] = -(i < 32); unsigned dark = -(i < 24);
vl[o] = light >> 8;
vl[o + 1] = light << 8;
vd[o] = dark >> 8;
vd[o + 1] = dark << 8;
} }
locate(3, 2, "light"); locate(3, 3, "light");
print(3, 3, "%d", delay1); print(4, 4, "%d", delay1);
locate(3, 5, "dark"); locate(3, 5, "dark");
print(3, 6, "%d", delay2); print(4, 6, "%d", delay2);
locate(2, selected ? 6 : 3, "\x02"); locate(3, selected ? 6 : 4, "\x02");
gimage(0, 56, &res_opt_gray_start); gimage(0, 56, &res_opt_gray_start);
gupdate(); gupdate();
@ -64,10 +69,14 @@ void test_gray(void)
selected = !selected; selected = !selected;
break; break;
case KEY_F2: case KEY_F2:
delays[0] = isSH3() ? 985 : 994; delays[0] = 912;
delays[1] = 1609; delays[1] = 1343;
break; break;
case KEY_F3: case KEY_F3:
delays[0] = 993;
delays[1] = 1609;
break;
case KEY_F4:
delays[0] = 860; delays[0] = 860;
delays[1] = 1298; delays[1] = 1298;
break; break;

View file

@ -179,7 +179,7 @@ static void set(void)
if(n == 7) if(n == 7)
{ {
int month = k + 4 * slide - 1; int month = k + 4 * slide - 2;
set_region(&time, n, month); set_region(&time, n, month);
n++; n++;
slide = 0; slide = 0;

284
demo/test_timer.c Normal file
View file

@ -0,0 +1,284 @@
#include "gintdemo.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <internals/timer.h>
#include <timer.h>
#include <display.h>
#include <keyboard.h>
#include <clock.h>
#include <mpu.h>
#include <rtc.h>
static void draw(int new_tab);
static struct ClockConfig conf;
//---
// Timer-RTC comparison.
// The precision of the timer is measured by comparing it to the RTC.
//---
static volatile int elapsed_timer = -1;
static volatile int elapsed_rtc = -1;
static void timing_rtc(void)
{
elapsed_rtc++;
}
static void timing_timer(void)
{
elapsed_timer++;
}
static void timing_start(void)
{
timer_start(TIMER_USER, clock_setting(16, Clock_Hz), TIMER_Po_4,
timing_timer, 0);
rtc_setCallback(timing_rtc, RTCFreq_16Hz);
elapsed_timer = 0;
elapsed_rtc = 0;
}
//---
// Drawing.
//---
/*
small_text()
Renders small text using a minimalist bitmap-based font.
*/
static void small_text(int x, int y, const char *text, int alignment)
{
extern Image res_clock_chars_start;
Image *chars = &res_clock_chars_start;
const char *table = "0123456789kMHz*/";
if(alignment) x -= 2 * strlen(text) - 1, y -= 2;
int c;
while(*text)
{
const char *ptr = strchr(table, *text++);
if(!ptr) continue;
c = ptr - table;
dimage_part(x, y, chars, c << 2, 0, 3, 5);
x += 4;
}
}
/*
getFreq()
Prints the given frequency in a string on the form:
332kHz
<-><->
3 3
There are 1, 2 or 3 characters for the value, and 2 or 3
characters for the unit. The string is compacted.
*/
void getFreq(char *str, int freq)
{
if(freq < 1000)
{
sprintf(str, "%dHz", freq);
return;
}
if(freq < 1000000)
{
sprintf(str, "%dkHz", (freq + 500) / 1000);
return;
}
sprintf(str, "%dMHz", (freq + 500000) / 1000000);
}
/*
dislay_freq()
Displays a frequency value a unit, in an simple form.
*/
static void display_freq(int x, int y, int freq)
{
int ratio, letter, dot, i;
char buffer[10];
if(freq <= 0)
{
dtext(x, y, "Unknown");
return;
}
if(freq < 10000)
{
dprint(x, y, "%5d", freq);
small_text(x + 31, y + 2, "Hz", 0);
return;
}
if(freq < 10000000) ratio = 1, letter = 'k';
else ratio = 1000, letter = 'M';
dot = 1 + (freq >= 10000 * ratio) + (freq >= 100000 * ratio);
freq += (ratio * (1 + 9 * (dot >= 2) + 90 * (dot >= 3))) / 2;
snprintf(buffer, 6, "%d", freq);
for(i = 4; i > dot; i--) buffer[i] = buffer[i - 1];
buffer[dot] = '.';
dprint(x, y, buffer);
sprintf(buffer, "%cHz", letter);
small_text(x + 31, y + 2, buffer, 0);
}
/*
draw()
Draws the test interface.
*/
static void draw(int tab)
{
extern Image res_opt_timer_start;
extern Image res_clock_7705_start;
extern Image res_clock_7305_start;
char buffer[16];
dclear();
dimage(0, 56, &res_opt_timer_start);
if(!tab)
{
locate(1, 1, "Clock frequency");
dtext(7, 20, "B\x1e");
display_freq(24, 20, conf.Bphi_f);
dtext(7, 28, "I\x1e");
display_freq(24, 28, conf.Iphi_f);
dtext(7, 36, "P\x1e");
display_freq(24, 36, conf.Pphi_f);
if(isSH3())
{
dimage(64, 0, &res_clock_7705_start);
getFreq(buffer, conf.CKIO_f);
small_text(84, 16, buffer, 1);
sprintf(buffer, "*%d", conf.PLL1);
small_text(84, 34, buffer, 1);
if(conf.Iphi_div1 == 1)
dline(85, 43, 99, 43, Color_Black);
else
{
sprintf(buffer, "/%d", conf.Iphi_div1);
small_text(89, 41, buffer, 0);
}
if(conf.Pphi_div1 == 1)
dline(85, 50, 99, 50, Color_Black);
else
{
sprintf(buffer, "/%d", conf.Pphi_div1);
small_text(89, 48, buffer, 0);
}
}
else
{
dimage(64, 0, &res_clock_7305_start);
getFreq(buffer, conf.RTCCLK_f);
small_text(84, 14, buffer, 1);
sprintf(buffer, "*%d", conf.FLL);
small_text(84, 25, buffer, 1);
sprintf(buffer, "*%d", conf.PLL);
small_text(84, 36, buffer, 1);
sprintf(buffer, "/%d", conf.Bphi_div1);
small_text(89, 43, buffer, 0);
sprintf(buffer, "/%d", conf.Iphi_div1);
small_text(89, 50, buffer, 0);
sprintf(buffer, "/%d", conf.Pphi_div1);
small_text(89, 57, buffer, 0);
}
}
else
{
locate(1, 1, "Timer/RTC comparison");
locate(2, 3, "Timer");
if(elapsed_timer >= 0) print(12, 3, "%04x", elapsed_timer);
else locate(12, 3, "...");
locate(2, 4, "RTC");
if(elapsed_rtc >= 0) print(12, 4, "%04x", elapsed_rtc);
else locate(12, 4, "...");
// We define the accuracy of the timer as the square of the
// ratio between the two counters.
locate(2, 5, "Accuracy");
if(elapsed_rtc > 0 && elapsed_timer > 0)
{
int ratio;
if(elapsed_timer <= elapsed_rtc)
ratio = (10000 * elapsed_timer) / elapsed_rtc;
else
ratio = (10000 * elapsed_rtc) / elapsed_timer;
ratio = (ratio * ratio) / 10000;
print(12, 5, "%d.%02d %%", ratio / 100, ratio % 100);
}
else locate(12, 5, "...");
}
dupdate();
}
//---
// Timer/clock test.
//---
/*
test_timer()
Clock timer and timer precision.
*/
void test_timer(void)
{
int tab = 0;
clock_measure();
clock_measure_end();
conf = clock_config();
elapsed_timer = -1;
elapsed_rtc = -1;
rtc_setCallback(timing_start, RTCFreq_16Hz);
text_configure(NULL, Color_Black);
while(1)
{
draw(tab);
switch(getkey_opt(Getkey_NoOption, 1))
{
case KEY_EXIT:
timer_stop(TIMER_USER);
rtc_setCallback(NULL, RTCFreq_1Hz);
return;
case KEY_F1:
tab = 0;
break;
case KEY_F2:
tab = 1;
break;
}
}
}

123
include/clock.h Normal file
View file

@ -0,0 +1,123 @@
//---
//
// gint core module: clock
//
// Measures the frequency of the MPU clocks. This module assumes that the
// clock mode is 3 on SH7305 (as does FTune).
//
//---
//---
// Some type declarations.
//---
enum Clock
{
Clock_CKIO = 0, // SH7705
Clock_RTCCLK = 1, // SH7305
Clock_Bphi = 2,
Clock_Iphi = 3,
Clock_Pphi = 4,
};
enum ClockUnit
{
Clock_us = 0,
Clock_ms = 1,
Clock_s = 2,
Clock_Hz = 10,
Clock_kHz = 11,
Clock_MHz = 12,
};
struct ClockConfig
{
union
{
int PLL1; // SH7705
int FLL; // SH7305
};
union
{
int PLL2; // SH7705
int PLL; // SH7305
};
int Bphi_div1;
int Iphi_div1;
int Pphi_div1;
union
{
int CKIO_f; // SH7705
int RTCCLK_f; // SH7305
};
int Bphi_f;
int Iphi_f;
int Pphi_f;
};
//---
// Public API.
//---
/*
clock_frequency()
Returns the approximate frequency, in Hz, of the given clock. The
measurements need to have been done. Returns a negative number on
error.
*/
int clock_frequency(enum Clock clock);
/*
clock_setting()
Returns the P_phi / 4 timer setting that will last for the given time.
Several units can be used. Be aware that the result is approximate, and
very high frequencies or very short delays will yield important errors.
*/
int clock_setting(int duration, enum ClockUnit unit);
/*
clock_config()
Returns a copy of the clock configuration.
*/
struct ClockConfig clock_config(void);
/*
sleep()
Sleeps until an interrupt is accepted.
*/
void sleep(void);
/*
sleep_us()
Sleeps for the given number of us using the user timer. The result will
always be slightly less than required.
*/
void sleep_us(int us_delay);
//---
// Internal API.
// Referenced for documentation purposes only. Do not use.
//---
/*
clock_measure()
Begins the frequency measurements. The measurements will end
automatically. While doing measurements, do not use the RTC interrupt
or the user timer.
Call clock_measure_end() to wait until the measurements are finished.
It is possible to execute code during the measurements, so that less
time is spent.
*/
void clock_measure(void);
/*
clock_measure_end()
Waits until the measurements are finished. This may be immediate.
*/
void clock_measure_end(void);

View file

@ -66,10 +66,10 @@ void gray_getDelays(int *light, int *dark);
values stability stripes colors values stability stripes colors
--------------------------------------------------------- ---------------------------------------------------------
860, 1298 excellent worst static good 860, 1298 excellent worst static good
912, 1343 bad none very good 912, 1343 bad none very good (default)
993, 1609 medium light fast good (default) 993, 1609 medium light fast good
1325, 1607 bad light fast excellent
--------------------------------------------------------- ---------------------------------------------------------
*/ */
void gray_setDelays(int light, int dark); void gray_setDelays(int light, int dark);

View file

@ -2,11 +2,20 @@
// //
// gint core module: mpu // gint core module: mpu
// //
// Determines which kind of MPU is running the program. This module only // Determines which kind of MPU is running the program. This module
// provides the following test: // provides macro tests isSH3(), isSH4(), and the identifier of the MPU,
// which is stored in a global variable MPU_CURRENT.
// //
// if(isSH3()) { ... } // If you need to do MPU-dependant jobs, prefer the following alternative:
// else { ... } //
// if(isSH3())
// {
// ...
// }
// else
// {
// ...
// }
// //
//--- //---

288
src/clock/clock.c Normal file
View file

@ -0,0 +1,288 @@
#include <clock.h>
#include <timer.h>
#include <internals/timer.h>
#include <rtc.h>
#include <stddef.h>
#include <mpu.h>
static struct ClockConfig conf = {
.FLL = -1, .PLL = -1,
.Bphi_div1 = -1, .Iphi_div1 = -1, .Pphi_div1 = -1,
.CKIO_f = -1,
.Bphi_f = -1, .Iphi_f = -1, .Pphi_f = -1
};
/*
clock_frequency()
Returns the approximate frequency, in Hz, of the given clock. The
measurements need to have been done. Returns a negative number on
error.
*/
int clock_frequency(enum Clock clock)
{
switch(clock)
{
case Clock_CKIO:
return conf.CKIO_f;
case Clock_RTCCLK:
return conf.RTCCLK_f;
case Clock_Bphi:
return conf.Bphi_f;
case Clock_Iphi:
return conf.Iphi_f;
case Clock_Pphi:
return conf.Pphi_f;
default:
return -2;
}
}
/*
clock_setting()
Returns the P_phi / 4 timer setting that will last for the given time.
Several units can be used. Be aware that the result is approximate, and
very high frequencies or very short delays will yield important errors.
*/
int clock_setting(int duration, enum ClockUnit unit)
{
if(conf.Pphi_f <= 0) return -1;
int f = conf.Pphi_f >> 2;
switch(unit)
{
case Clock_us:
return (duration * f) / 1000000;
case Clock_ms:
return (duration * f) / 1000;
case Clock_s:
return (duration * f);
case Clock_Hz:
return f / duration;
case Clock_kHz:
return f / (duration * 1000);
case Clock_MHz:
return f / (duration * 1000000);
default:
return -1;
}
}
/*
clock_config()
Returns a copy of the clock configuration.
*/
struct ClockConfig clock_config(void)
{
return conf;
}
/*
sleep()
Sleeps until an interrupt is accepted.
*/
void sleep(void)
{
__asm__(
"sleep\n\t"
);
}
/*
sleep_us()
Sleeps for the given number of us using the user timer. The result will
always be slightly less than required.
*/
static volatile int sleep_us_done = 0;
static void sleep_us_callback(void)
{
sleep_us_done = 1;
}
void sleep_us(int us_delay)
{
sleep_us_done = 0;
timer_start(TIMER_USER, clock_setting(us_delay, Clock_us), TIMER_Po_4,
sleep_us_callback, 1);
do sleep();
while(!sleep_us_done);
}
//---
// Clock frequency measurements -- Public API.
//---
// Indicates whether the measurements are finished.
static volatile int clock_measure_done = 0;
// Once again SH7705 and SH7305 need different methods...
static void clock_measure_7705();
static void clock_compute_7305();
/*
clock_measure()
Measures or computes the clock frequencies.
*/
void clock_measure(void)
{
// On SH7705 we cannot have the value of CKIO simply, so we measure
// P_phi using a timer/RTC combination, and we deduce CKIO.
if(isSH3())
{
// We prepare the timer manually, without starting it, so that
// we only have to push the running bit to start it when the
// measurements begin. This might look of little effect but the
// timer configuration time (lost from the measurement) would
// make the precision no more than 97-98%.
volatile struct mod_tmu *tmu;
timer_get(TIMER_USER, &tmu, NULL);
tmu->TCOR = 0xffffffff;
tmu->TCNT = tmu->TCOR;
tmu->TCR.TPSC = TIMER_Po_4;
tmu->TCR.UNF = 0;
tmu->TCR.UNIE = 1;
tmu->TCR.CKEG = 0;
timers[TIMER_USER].callback = NULL;
timers[TIMER_USER].repeats = 0;
rtc_setCallback(clock_measure_7705, RTCFreq_256Hz);
}
// On SH7305, assuming clock mode 3, we can compute the clock
// frequencies because we know that RTC_CLK oscillates at 32768 Hz.
else
{
clock_compute_7305();
clock_measure_done = 1;
}
}
/*
clock_measure_end()
Waits until the measurements are finished. This may be immediate.
*/
void clock_measure_end(void)
{
while(!clock_measure_done) sleep();
}
//---
// Clock frequency measurements -- SH7305.
//---
/*
clock_compute_7305()
Computes the clock frequencies according to the CPG parameters.
*/
static void clock_compute_7305(void)
{
volatile unsigned int *FRQCRA = (void *)0xa4150000;
volatile unsigned int *PLLCR = (void *)0xa4150024;
volatile unsigned int *FLLFRQ = (void *)0xa4150050;
// Surely the documentation of SH7724 does not meet the specification
// if SH7305 for the PLL setting, because the register accepts other
// values than the ones specified by SH7724. The formula given by
// Sentaro21 (thanks again!) yields good results though.
int pll = (*FRQCRA >> 24) & 0x3f; // Raw setting
pll = pll + 1; // Resulting multiplier
conf.PLL = pll;
// This one is simpler. The FLL ratio is actually the setting value.
int fll = *FLLFRQ & 0x7ff; // Raw setting = multiplier
if(*FLLFRQ & (1 << 14)) fll >>= 1; // Halve-output flag
conf.FLL = fll;
// The divider1 ratios are NOT those of SH7724. The relation between
// the values below and the divider ratios is given by Sentaro21
// (thanks to him!) and satisfies ratio = 1 / (2 ** (setting + 1)).
int div1_bphi = (*FRQCRA >> 8) & 0xf;
int div1_iphi = (*FRQCRA >> 20) & 0xf;
int div1_pphi = (*FRQCRA ) & 0xf;
conf.Bphi_div1 = 1 << (div1_bphi + 1);
conf.Iphi_div1 = 1 << (div1_iphi + 1);
conf.Pphi_div1 = 1 << (div1_pphi + 1);
// Computing the frequency of the signal, which is input to divider 1.
int base = 32768;
if(*PLLCR & (1 << 12)) base *= fll;
if(*PLLCR & (1 << 14)) base *= pll;
conf.RTCCLK_f = 32768;
conf.Bphi_f = base >> (div1_bphi + 1);
conf.Iphi_f = base >> (div1_iphi + 1);
conf.Pphi_f = base >> (div1_pphi + 1);
}
//---
// Clock frequency measurements -- SH7705.
//---
/*
clock_measure_7705_finalize()
Given the number of P_phi / 4 timer ticks elapsed between two RTC
256 Hz interrupts, determines the clock configuration.
*/
static void clock_measure_7705_finalize(int elapsed)
{
volatile unsigned int *FRQCR = (void *)0xffffff80;
conf.Pphi_f = elapsed * 4 * 256;
if(conf.Pphi_f <= 0) return;
conf.PLL1 = ((*FRQCR >> 8) & 0x03) + 1;
conf.PLL2 = -1;
conf.Bphi_div1 = 0;
conf.Iphi_div1 = ((*FRQCR >> 4) & 0x03) + 1;
conf.Pphi_div1 = ((*FRQCR ) & 0x03) + 1;
conf.CKIO_f = (conf.Pphi_f * conf.Pphi_div1) / conf.PLL1;
conf.Bphi_f = conf.CKIO_f;
conf.Iphi_f = (conf.CKIO_f * conf.PLL1) / conf.Iphi_div1;
}
/*
clock_measure_7705_callback()
Starts measurements. Measurements will end automatically. Do not use
RTC interrupt or the user timer will doing measurements.
Call clock_measure_end() when you need to use those, to ensure
measurements are finished.
*/
static void clock_measure_7705_callback(void)
{
timer_stop(TIMER_USER);
rtc_setCallback(NULL, RTCFreq_1Hz);
volatile struct mod_tmu *tmu;
timer_get(TIMER_USER, &tmu, NULL);
int elapsed = 0xffffffff - tmu->TCNT;
clock_measure_7705_finalize(elapsed);
clock_measure_done = 1;
}
/*
clock_measure_7705()
Programs the clock measurements. We need to have the user timer and the
RTC synchronized for this operation, so we wait for an RTC interrupt
and we prepare the timer beforehand to avoid losing processor time in
configuring the registers.
*/
static void clock_measure_7705(void)
{
volatile unsigned char *tstr;
timer_get(TIMER_USER, NULL, &tstr);
*tstr |= (1 << TIMER_USER);
rtc_setCallback(clock_measure_7705_callback, RTCFreq_256Hz);
}

View file

@ -3,6 +3,7 @@
#include <setjmp.h> #include <setjmp.h>
#include <gint.h> #include <gint.h>
#include <clock.h>
#include <internals/mmu.h> #include <internals/mmu.h>
void __Hmem_SetMMU(unsigned int, unsigned int, int); void __Hmem_SetMMU(unsigned int, unsigned int, int);
@ -57,8 +58,14 @@ int start(void)
mmu_pseudoTLBInit(); mmu_pseudoTLBInit();
// Initializing everything. // Initializing gint.
gint_init(); gint_init();
// Measure clock frequencies.
clock_measure();
clock_measure_end();
// Calling global constructors.
init(); init();

View file

@ -113,7 +113,7 @@ void gint_quit(void)
#define print(str, x, y) dtext(6 * (x) - 5, 8 * (y) - 7, str) #define print(str, x, y) dtext(6 * (x) - 5, 8 * (y) - 7, str)
#define hexdigit(n) ((n) + '0' + 39 * ((n) > 9)) #define hexdigit(n) ((n) + '0' + 39 * ((n) > 9))
void hex(unsigned int x, int digits, char *str) static void hex(unsigned int x, int digits, char *str)
{ {
str[0] = '0'; str[0] = '0';
str[1] = 'x'; str[1] = 'x';
@ -127,6 +127,13 @@ void hex(unsigned int x, int digits, char *str)
} }
} }
static void reverse(void)
{
int *vram = display_getCurrentVRAM();
int i;
for(i = 0; i < 36; i++) vram[i] = ~vram[i];
}
/* /*
gint_exc() gint_exc()
Handles exceptions. Handles exceptions.
@ -144,7 +151,7 @@ void gint_exc(void)
dclear(); dclear();
print("Exception raised!", 3, 1); print("Exception raised!", 3, 1);
dreverse_area(0, 0, 127, 8); reverse();
print(gint_strerror(0), 2, 3); print(gint_strerror(0), 2, 3);
print("expevt", 2, 4); print("expevt", 2, 4);
@ -181,7 +188,7 @@ void gint_tlb(void)
dclear(); dclear();
print("TLB error!", 6, 1); print("TLB error!", 6, 1);
dreverse_area(0, 0, 127, 8); reverse();
print(gint_strerror(1), 2, 3); print(gint_strerror(1), 2, 3);
print("expevt", 2, 4); print("expevt", 2, 4);

View file

@ -7,7 +7,6 @@
.global ___GLibAddinAplExecutionCheck .global ___GLibAddinAplExecutionCheck
.global _malloc .global _malloc
.global _calloc
.global _free .global _free

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -152,6 +152,6 @@ void gray_init(void)
vrams[2] = (const void *)internal_vrams[1]; vrams[2] = (const void *)internal_vrams[1];
vrams[3] = (const void *)internal_vrams[2]; vrams[3] = (const void *)internal_vrams[2];
delays[0] = isSH3() ? 985 : 994; delays[0] = 912;
delays[1] = 1609; delays[1] = 1343;
} }

View file

@ -1,5 +1,7 @@
#include <internals/keyboard.h> #include <internals/keyboard.h>
#include <keyboard.h> #include <keyboard.h>
#include <clock.h>
#include <timer.h>
/* /*
keyboard_setFrequency() keyboard_setFrequency()
@ -7,6 +9,9 @@
*/ */
void keyboard_setFrequency(int frequency) void keyboard_setFrequency(int frequency)
{ {
int setting = clock_setting(frequency, Clock_Hz);
if(setting <= 0) return;
timer_reload(TIMER_KEYBOARD, setting);
} }
/* /*

View file

@ -1,6 +1,7 @@
#include <keyboard.h> #include <keyboard.h>
#include <timer.h> #include <timer.h>
#include <mpu.h> #include <mpu.h>
#include <clock.h>
#include <internals/keyboard.h> #include <internals/keyboard.h>
@ -42,7 +43,8 @@ void keyboard_interrupt(void)
*/ */
void keyboard_init(void) void keyboard_init(void)
{ {
timer_start(TIMER_KEYBOARD, 1700, TIMER_Po_256, keyboard_interrupt, 0); int delay = clock_setting(16, Clock_Hz);
timer_start(TIMER_KEYBOARD, delay, TIMER_Po_4, keyboard_interrupt, 0);
} }
/* /*

View file

@ -1,13 +0,0 @@
#include <internals/keyboard.h>
/*
sleep()
Puts the CPU to sleep and waits for an interrupt.
*/
void sleep(void)
{
__asm__
(
"sleep\n\t"
);
}

View file

@ -1,5 +1,7 @@
#include <internals/mmu.h> #include <internals/mmu.h>
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
/* /*
mmu_pseudoTLBInit() mmu_pseudoTLBInit()
We need the system to fill the TLB for us, so that it knows what We need the system to fill the TLB for us, so that it knows what
@ -23,3 +25,5 @@ void mmu_pseudoTLBInit(void)
address += 0x1000; address += 0x1000;
} }
} }
#pragma GCC diagnostic pop

View file

@ -12,7 +12,8 @@ int snprintf(char *str, size_t size, const char *format, ...)
va_start(args, format); va_start(args, format);
int x = __printf(size, format, args); int x = __printf(size, format, args);
strncpy(str, __stdio_buffer, size); memcpy(str, __stdio_buffer, x + 1);
va_end(args); va_end(args);
return x; return x;

View file

@ -12,7 +12,7 @@ int sprintf(char *str, const char *format, ...)
va_start(args, format); va_start(args, format);
int x = __printf(0, format, args); int x = __printf(0, format, args);
strncpy(str, __stdio_buffer, __stdio_buffer_size); memcpy(str, __stdio_buffer, x + 1);
va_end(args); va_end(args);
return x; return x;

View file

@ -401,8 +401,7 @@ int __printf(size_t size, const char *string, va_list args)
struct Format format; struct Format format;
// Avoiding overflow by adjusting the size argument. // Avoiding overflow by adjusting the size argument.
if(!size || size > __stdio_buffer_size) if(!size || size > __stdio_buffer_size) size = __stdio_buffer_size;
size = __stdio_buffer_size;
// Initializing character() variables. // Initializing character() variables.
written = 0; written = 0;

View file

@ -9,7 +9,7 @@
int vsnprintf(char *str, size_t size, const char *format, va_list args) int vsnprintf(char *str, size_t size, const char *format, va_list args)
{ {
int x = __printf(size, format, args); int x = __printf(size, format, args);
strncpy(str, __stdio_buffer, size); memcpy(str, __stdio_buffer, x + 1);
return x; return x;
} }

View file

@ -9,7 +9,7 @@
int vsprintf(char *str, const char *format, va_list args) int vsprintf(char *str, const char *format, va_list args)
{ {
int x = __printf(0, format, args); int x = __printf(0, format, args);
strncpy(str, __stdio_buffer, __stdio_buffer_size); memcpy(str, __stdio_buffer, x + 1);
return x; return x;
} }

View file

@ -1,4 +0,0 @@
#include <internals/tales.h>
#include <internals/stdio.h>
#include <stdarg.h>

45
src/tales/tales_gray.c Normal file
View file

@ -0,0 +1,45 @@
#include <internals/tales.h>
#include <display.h>
#include <gray.h>
void operate_gray(OPERATE_ARGS)
{
int *vl = gray_lightVRAM();
int *vd = gray_darkVRAM();
int vram_offset = (x >> 5) + (y << 2);
uint32_t op;
int i;
for(i = 0; i < height; i++)
{
op = operators[i];
switch(color)
{
case Color_White:
vl[vram_offset] &= ~op;
vd[vram_offset] &= ~op;
break;
case Color_Light:
vl[vram_offset] |= op;
vd[vram_offset] &= ~op;
break;
case Color_Dark:
vl[vram_offset] &= ~op;
vd[vram_offset] |= op;
break;
case Color_Black:
vl[vram_offset] |= op;
vd[vram_offset] |= op;
break;
case Color_Invert:
vl[vram_offset] ^= op;
vd[vram_offset] ^= op;
break;
default:
break;
}
vram_offset += 4;
}
}

View file

@ -120,47 +120,6 @@ void operate_mono(OPERATE_ARGS)
vram_offset += 4; vram_offset += 4;
} }
} }
void operate_gray(OPERATE_ARGS)
{
int *vl = gray_lightVRAM();
int *vd = gray_darkVRAM();
int vram_offset = (x >> 5) + (y << 2);
uint32_t op;
int i;
for(i = 0; i < height; i++)
{
op = operators[i];
switch(color)
{
case Color_White:
vl[vram_offset] &= ~op;
vd[vram_offset] &= ~op;
break;
case Color_Light:
vl[vram_offset] |= op;
vd[vram_offset] &= ~op;
break;
case Color_Dark:
vl[vram_offset] &= ~op;
vd[vram_offset] |= op;
break;
case Color_Black:
vl[vram_offset] |= op;
vd[vram_offset] |= op;
break;
case Color_Invert:
vl[vram_offset] ^= op;
vd[vram_offset] ^= op;
break;
default:
break;
}
vram_offset += 4;
}
}
/* /*
update() update()

View file

@ -1,9 +1,6 @@
#include <internals/tales.h> #include <internals/tales.h>
#include <tales.h> #include <tales.h>
#include <display.h>
#include <gray.h>
/* /*
dtext() dtext()
Prints the given string, without any analysis. Prints the given string, without any analysis.