Added clock frequency computations/measurements, and frequency-delay/timer expression.
4
Makefile
|
@ -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
|
@ -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
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
BIN
demo/resources/clock_7305.bmp
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
demo/resources/clock_7705.bmp
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
demo/resources/clock_chars.bmp
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
BIN
demo/resources/opt_timer.bmp
Normal file
After Width: | Height: | Size: 3.1 KiB |
|
@ -178,7 +178,6 @@ void test_bopti(void)
|
||||||
dupdate();
|
dupdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
leave = 1;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
leave = 1;
|
leave = 1;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
@ -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
|
@ -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);
|
|
@ -65,11 +65,11 @@ 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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
@ -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);
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
.global ___GLibAddinAplExecutionCheck
|
.global ___GLibAddinAplExecutionCheck
|
||||||
.global _malloc
|
.global _malloc
|
||||||
.global _calloc
|
|
||||||
.global _free
|
.global _free
|
||||||
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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"
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#include <internals/tales.h>
|
|
||||||
#include <internals/stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
45
src/tales/tales_gray.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
|
|
@ -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.
|
||||||
|
|