diff --git a/Makefile b/Makefile index 0789106..54a2101 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ #--- # Modules -modules-gint = core keyboard mmu mpu rtc screen timer \ +modules-gint = core clock keyboard mmu mpu rtc screen timer \ bopti display gray tales modules-libc = setjmp string stdio stdlib time @@ -173,7 +173,7 @@ mrproper: clean distclean: mrproper install: - CasioUsbUploader -f $(target-g1a) -w -l 1 + p7 send -f $(target-g1a) .PHONY: all clean mrproper distclean diff --git a/TODO b/TODO index cbef227..39e6d9e 100644 --- a/TODO +++ b/TODO @@ -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 - -------------- - Lots of things to do - -------------- +Simple improvements: +- 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 - + simple improvements - - important milestones - ~ needs investigation +Modules to implement: +- Serial communication +- Sound playback and synthesizing - -@ possibility of vram left-overflow with text -@ garbage displayed as year in the clock, possibly during edition (could not - reproduce) -@ a few key hits ignored after leaving the application - -+ 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 +Things to investigate: +- Packed bit fields alignment +- Registers that may need to be saved within setjmp() +- Registers that may need to be saved and restored by gint +- Possible bug when optimizing __attribute__((interrupt_handler)) diff --git a/demo/gintdemo.c b/demo/gintdemo.c index 8e4249f..32bba87 100644 --- a/demo/gintdemo.c +++ b/demo/gintdemo.c @@ -305,7 +305,7 @@ void main_menu(int *category, int *app) "Image rendering", "Text rendering", "Real-time clock", - "Text formatting", + "Clocks and timers", NULL }; const char *list_perfs[] = { @@ -511,7 +511,7 @@ int main(void) test_rtc(); break; case 0x0106: -// test_printf(); + test_timer(); break; case 0x0201: diff --git a/demo/gintdemo.h b/demo/gintdemo.h index a7805a3..1d32bcd 100644 --- a/demo/gintdemo.h +++ b/demo/gintdemo.h @@ -76,10 +76,10 @@ void test_tales(void); void test_rtc(void); /* - test_printf() - Some text formatting. + test_timer() + Clock timer and timer precision. */ -void test_printf(void); +void test_timer(void); diff --git a/demo/gintdemo.ld b/demo/gintdemo.ld index cf7bb2f..49062c9 100644 --- a/demo/gintdemo.ld +++ b/demo/gintdemo.ld @@ -3,12 +3,9 @@ output. Note how symbols romdata, bbss, ebss, bdata and edata are used in the initialization routine (crt0.c) to initialize the application. - Two ram areas are specified. It happens, if I'm not wrong, that the - "real ram" is accessed directly while the "common" ram is accessed - through the mmu. The interrupt handler resides in "real ram" because it - 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. + Two ram areas are specified. The "real ram" is accessed direcly while + the other area is virtualized. It is not possible to execute code in + virtualized ram. */ OUTPUT_ARCH(sh3) diff --git a/demo/resources/clock_7305.bmp b/demo/resources/clock_7305.bmp new file mode 100644 index 0000000..83690f6 Binary files /dev/null and b/demo/resources/clock_7305.bmp differ diff --git a/demo/resources/clock_7705.bmp b/demo/resources/clock_7705.bmp new file mode 100644 index 0000000..d711160 Binary files /dev/null and b/demo/resources/clock_7705.bmp differ diff --git a/demo/resources/clock_chars.bmp b/demo/resources/clock_chars.bmp new file mode 100644 index 0000000..6edc348 Binary files /dev/null and b/demo/resources/clock_chars.bmp differ diff --git a/demo/resources/opt_gray.bmp b/demo/resources/opt_gray.bmp index a44613d..87ba1c7 100644 Binary files a/demo/resources/opt_gray.bmp and b/demo/resources/opt_gray.bmp differ diff --git a/demo/resources/opt_timer.bmp b/demo/resources/opt_timer.bmp new file mode 100644 index 0000000..1d7cb9c Binary files /dev/null and b/demo/resources/opt_timer.bmp differ diff --git a/demo/test_bopti.c b/demo/test_bopti.c index 3b9ee45..57695d5 100644 --- a/demo/test_bopti.c +++ b/demo/test_bopti.c @@ -178,7 +178,6 @@ void test_bopti(void) dupdate(); } - leave = 1; do { leave = 1; diff --git a/demo/test_gray.c b/demo/test_gray.c index 55c23ef..61d06aa 100644 --- a/demo/test_gray.c +++ b/demo/test_gray.c @@ -11,25 +11,30 @@ static void draw(int delay1, int delay2, int selected) { extern Image res_opt_gray_start; - int *vl = gray_lightVRAM(); - int *vd = gray_darkVRAM(); + unsigned int *vl = gray_lightVRAM(); + unsigned int *vd = gray_darkVRAM(); 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; - vl[o] = vl[o + 1] = -((i & 31) < 16); - vd[o] = vd[o + 1] = -(i < 32); + int o = ((i + 12) << 2) + 2; + unsigned light = -((i % 24) < 12); + 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"); - print(3, 3, "%d", delay1); + locate(3, 3, "light"); + print(4, 4, "%d", delay1); 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); gupdate(); @@ -64,10 +69,14 @@ void test_gray(void) selected = !selected; break; case KEY_F2: - delays[0] = isSH3() ? 985 : 994; - delays[1] = 1609; + delays[0] = 912; + delays[1] = 1343; break; case KEY_F3: + delays[0] = 993; + delays[1] = 1609; + break; + case KEY_F4: delays[0] = 860; delays[1] = 1298; break; diff --git a/demo/test_rtc.c b/demo/test_rtc.c index 93a15c6..e3c0a09 100644 --- a/demo/test_rtc.c +++ b/demo/test_rtc.c @@ -179,7 +179,7 @@ static void set(void) if(n == 7) { - int month = k + 4 * slide - 1; + int month = k + 4 * slide - 2; set_region(&time, n, month); n++; slide = 0; diff --git a/demo/test_timer.c b/demo/test_timer.c new file mode 100644 index 0000000..9191508 --- /dev/null +++ b/demo/test_timer.c @@ -0,0 +1,284 @@ +#include "gintdemo.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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; + } + } +} diff --git a/include/clock.h b/include/clock.h new file mode 100644 index 0000000..744d341 --- /dev/null +++ b/include/clock.h @@ -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); diff --git a/include/gray.h b/include/gray.h index c77cf83..625c84f 100644 --- a/include/gray.h +++ b/include/gray.h @@ -65,11 +65,11 @@ void gray_getDelays(int *light, int *dark); values stability stripes colors --------------------------------------------------------- - 860, 1298 excellent worst static good - 912, 1343 bad none very good - 993, 1609 medium light fast good (default) + 860, 1298 excellent worst static good + 912, 1343 bad none very good (default) + 993, 1609 medium light fast good + 1325, 1607 bad light fast excellent --------------------------------------------------------- - */ void gray_setDelays(int light, int dark); diff --git a/include/mpu.h b/include/mpu.h index 33a08c8..fd4a498 100644 --- a/include/mpu.h +++ b/include/mpu.h @@ -2,11 +2,20 @@ // // gint core module: mpu // -// Determines which kind of MPU is running the program. This module only -// provides the following test: +// Determines which kind of MPU is running the program. This module +// provides macro tests isSH3(), isSH4(), and the identifier of the MPU, +// which is stored in a global variable MPU_CURRENT. // -// if(isSH3()) { ... } -// else { ... } +// If you need to do MPU-dependant jobs, prefer the following alternative: +// +// if(isSH3()) +// { +// ... +// } +// else +// { +// ... +// } // //--- diff --git a/src/clock/clock.c b/src/clock/clock.c new file mode 100644 index 0000000..b785a07 --- /dev/null +++ b/src/clock/clock.c @@ -0,0 +1,288 @@ +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/src/core/crt0.c b/src/core/crt0.c index ab92620..15da267 100644 --- a/src/core/crt0.c +++ b/src/core/crt0.c @@ -3,6 +3,7 @@ #include #include +#include #include void __Hmem_SetMMU(unsigned int, unsigned int, int); @@ -57,8 +58,14 @@ int start(void) mmu_pseudoTLBInit(); - // Initializing everything. + // Initializing gint. gint_init(); + + // Measure clock frequencies. + clock_measure(); + clock_measure_end(); + + // Calling global constructors. init(); diff --git a/src/core/gint.c b/src/core/gint.c index ec3a2cb..4dcf136 100644 --- a/src/core/gint.c +++ b/src/core/gint.c @@ -113,7 +113,7 @@ void gint_quit(void) #define print(str, x, y) dtext(6 * (x) - 5, 8 * (y) - 7, str) #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[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() Handles exceptions. @@ -144,7 +151,7 @@ void gint_exc(void) dclear(); print("Exception raised!", 3, 1); - dreverse_area(0, 0, 127, 8); + reverse(); print(gint_strerror(0), 2, 3); print("expevt", 2, 4); @@ -181,7 +188,7 @@ void gint_tlb(void) dclear(); print("TLB error!", 6, 1); - dreverse_area(0, 0, 127, 8); + reverse(); print(gint_strerror(1), 2, 3); print("expevt", 2, 4); diff --git a/src/core/syscalls.s b/src/core/syscalls.s index 621a84a..ffe3a43 100644 --- a/src/core/syscalls.s +++ b/src/core/syscalls.s @@ -7,7 +7,6 @@ .global ___GLibAddinAplExecutionCheck .global _malloc - .global _calloc .global _free diff --git a/src/display/font_system.bmp b/src/display/font_system.bmp index 5e7a0a7..cee82be 100644 Binary files a/src/display/font_system.bmp and b/src/display/font_system.bmp differ diff --git a/src/gray/gray_engine.c b/src/gray/gray_engine.c index 7938891..639c750 100644 --- a/src/gray/gray_engine.c +++ b/src/gray/gray_engine.c @@ -152,6 +152,6 @@ void gray_init(void) vrams[2] = (const void *)internal_vrams[1]; vrams[3] = (const void *)internal_vrams[2]; - delays[0] = isSH3() ? 985 : 994; - delays[1] = 1609; + delays[0] = 912; + delays[1] = 1343; } diff --git a/src/keyboard/keyboard_config.c b/src/keyboard/keyboard_config.c index f3a9361..f657479 100644 --- a/src/keyboard/keyboard_config.c +++ b/src/keyboard/keyboard_config.c @@ -1,5 +1,7 @@ #include #include +#include +#include /* keyboard_setFrequency() @@ -7,6 +9,9 @@ */ void keyboard_setFrequency(int frequency) { + int setting = clock_setting(frequency, Clock_Hz); + if(setting <= 0) return; + timer_reload(TIMER_KEYBOARD, setting); } /* diff --git a/src/keyboard/keyboard_interrupt.c b/src/keyboard/keyboard_interrupt.c index 4273445..c75c542 100644 --- a/src/keyboard/keyboard_interrupt.c +++ b/src/keyboard/keyboard_interrupt.c @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -42,7 +43,8 @@ void keyboard_interrupt(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); } /* diff --git a/src/keyboard/sleep.c b/src/keyboard/sleep.c deleted file mode 100644 index 8e71e84..0000000 --- a/src/keyboard/sleep.c +++ /dev/null @@ -1,13 +0,0 @@ -#include - -/* - sleep() - Puts the CPU to sleep and waits for an interrupt. -*/ -void sleep(void) -{ - __asm__ - ( - "sleep\n\t" - ); -} diff --git a/src/mmu/pseudoTLBInit.c b/src/mmu/pseudoTLBInit.c index d9e827b..b27d60d 100644 --- a/src/mmu/pseudoTLBInit.c +++ b/src/mmu/pseudoTLBInit.c @@ -1,5 +1,7 @@ #include +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" + /* mmu_pseudoTLBInit() 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; } } + +#pragma GCC diagnostic pop diff --git a/src/stdio/snprintf.c b/src/stdio/snprintf.c index eed74db..6c5eb20 100644 --- a/src/stdio/snprintf.c +++ b/src/stdio/snprintf.c @@ -12,7 +12,8 @@ int snprintf(char *str, size_t size, const char *format, ...) va_start(args, format); int x = __printf(size, format, args); - strncpy(str, __stdio_buffer, size); + memcpy(str, __stdio_buffer, x + 1); + va_end(args); return x; diff --git a/src/stdio/sprintf.c b/src/stdio/sprintf.c index a283635..f0a018e 100644 --- a/src/stdio/sprintf.c +++ b/src/stdio/sprintf.c @@ -12,7 +12,7 @@ int sprintf(char *str, const char *format, ...) va_start(args, format); int x = __printf(0, format, args); - strncpy(str, __stdio_buffer, __stdio_buffer_size); + memcpy(str, __stdio_buffer, x + 1); va_end(args); return x; diff --git a/src/stdio/stdio_format.c b/src/stdio/stdio_format.c index c7db02f..5a8ecfb 100644 --- a/src/stdio/stdio_format.c +++ b/src/stdio/stdio_format.c @@ -401,8 +401,7 @@ int __printf(size_t size, const char *string, va_list args) struct Format format; // Avoiding overflow by adjusting the size argument. - if(!size || size > __stdio_buffer_size) - size = __stdio_buffer_size; + if(!size || size > __stdio_buffer_size) size = __stdio_buffer_size; // Initializing character() variables. written = 0; diff --git a/src/stdio/vsnprintf.c b/src/stdio/vsnprintf.c index 5cc13e3..0bfafd4 100644 --- a/src/stdio/vsnprintf.c +++ b/src/stdio/vsnprintf.c @@ -9,7 +9,7 @@ int vsnprintf(char *str, size_t size, const char *format, va_list args) { int x = __printf(size, format, args); - strncpy(str, __stdio_buffer, size); + memcpy(str, __stdio_buffer, x + 1); return x; } diff --git a/src/stdio/vsprintf.c b/src/stdio/vsprintf.c index 448c9da..0571fc0 100644 --- a/src/stdio/vsprintf.c +++ b/src/stdio/vsprintf.c @@ -9,7 +9,7 @@ int vsprintf(char *str, const char *format, va_list args) { int x = __printf(0, format, args); - strncpy(str, __stdio_buffer, __stdio_buffer_size); + memcpy(str, __stdio_buffer, x + 1); return x; } diff --git a/src/tales/gprint.c b/src/tales/gprint.c deleted file mode 100644 index f67f3c1..0000000 --- a/src/tales/gprint.c +++ /dev/null @@ -1,4 +0,0 @@ -#include -#include -#include - diff --git a/src/tales/tales_gray.c b/src/tales/tales_gray.c new file mode 100644 index 0000000..4b9b02a --- /dev/null +++ b/src/tales/tales_gray.c @@ -0,0 +1,45 @@ +#include +#include +#include + +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; + } +} diff --git a/src/tales/tales_internals.c b/src/tales/tales_internals.c index 4cb412a..dbef3dd 100644 --- a/src/tales/tales_internals.c +++ b/src/tales/tales_internals.c @@ -120,47 +120,6 @@ void operate_mono(OPERATE_ARGS) 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() diff --git a/src/tales/tales_text.c b/src/tales/tales_text.c index 8b7977c..3729f7d 100644 --- a/src/tales/tales_text.c +++ b/src/tales/tales_text.c @@ -1,9 +1,6 @@ #include #include -#include -#include - /* dtext() Prints the given string, without any analysis.