Added an RTC test (clock), image part drawing and a few standard functions (stdlib, time).

This commit is contained in:
lephe 2016-08-02 07:51:44 +02:00
parent c63d7b812e
commit 1f223f807f
33 changed files with 938 additions and 152 deletions

View file

@ -14,7 +14,7 @@
# Modules # Modules
modules-gint = core keyboard mmu mpu rtc screen timer \ modules-gint = core keyboard mmu mpu rtc screen timer \
bopti display gray tales bopti display gray tales
modules-libc = setjmp string stdio modules-libc = setjmp string stdio stdlib
# Targets # Targets
target-g1a = gintdemo.g1a target-g1a = gintdemo.g1a

6
TODO
View file

@ -10,9 +10,11 @@
@ possibility of vram overflow with text @ possibility of vram overflow with text
@ garbage displayed as year in the clock, possibly during edition (could not
reproduce)
+ bitmap blending modes + bitmap blending modes
+ have timers use structures from 7705.h and 7305.h + minimize use of 7705.h and 7305.h; use local structures instead
+ partial transparency + partial transparency
+ gint vs. ML with 248x124 at (-60, -28) + gint vs. ML with 248x124 at (-60, -28)
+ call exit handlers + call exit handlers
@ -23,7 +25,7 @@
- full rtc driver (time) - full rtc driver (time)
- callbacks and complete user API - callbacks and complete user API
~ shadowy rectangle effect for Shift + Alpha + Left + Down ~ packed bit fields
~ exhaustive save for setjmp() ~ exhaustive save for setjmp()
~ registers that need to be saved when configuring gint ~ registers that need to be saved when configuring gint
~ possible bug when -O2'ing __attribute__((interrupt_handler)) ~ possible bug when -O2'ing __attribute__((interrupt_handler))

View file

@ -33,32 +33,6 @@ void print(int x, int y, const char *format, ...)
locate(x, y, __stdio_buffer); locate(x, y, __stdio_buffer);
} }
/*
text_test()
Renders text.
void text_test(void)
{
extern Font res_font_modern_start;
Font *font = &res_font_modern_start;
text_configure(font);
dclear();
dtext(" !\"#$%&'()*+,-./", 10, 10);
dtext("0123456789:;<=>?", 10, 16);
dtext("@ABCDEFGHIJKLMNO", 10, 22);
dtext("PQRSTUVWXYZ[\\]^_", 10, 28);
dtext("`abcdefghijklmno", 10, 34);
dtext("pqrstuvwxyz{|}~", 10, 40);
dupdate();
while(getkey() != KEY_EXIT);
}
*/
/* /*
printf_test() printf_test()
Tests formatting functions. Tests formatting functions.
@ -534,7 +508,7 @@ int main(void)
test_tales(); test_tales();
break; break;
case 0x0105: case 0x0105:
// test_rtc(); test_rtc();
break; break;
case 0x0106: case 0x0106:
// test_printf(); // test_printf();

BIN
demo/resources/opt_rtc.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

@ -62,9 +62,6 @@ void test_keyboard(void)
while(1) while(1)
{ {
multigetkey(keys, 4, 1);
if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break;
dclear(); dclear();
locate(1, 1, "Keyboard driver"); locate(1, 1, "Keyboard driver");
locate(8, 3, "Pressed keys:"); locate(8, 3, "Pressed keys:");
@ -78,5 +75,8 @@ void test_keyboard(void)
} }
dupdate(); dupdate();
multigetkey(keys, 4, 1);
if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break;
} }
} }

262
demo/test_rtc.c Normal file
View file

@ -0,0 +1,262 @@
#include "gintdemo.h"
#include <display.h>
#include <rtc.h>
#include <keyboard.h>
#include <stddef.h>
#include <ctype.h>
/*
test_rtc()
Just a clock. Of course using all this RTCTime conversion and this / 10
is awfully un-optimized, but it's a test case so it's made to check the
values in the structure are correct.
*/
#include <internals/rtc.h>
#include <mpu.h>
static void draw(struct RTCTime time)
{
extern Image res_rtc_segments_start;
const char *days[7] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
}, *months[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"
};
int x[6] = { 20, 33, 52, 65, 84, 97 };
int digits[6];
int i;
digits[0] = time.hours / 10;
digits[1] = time.hours % 10;
digits[2] = time.minutes / 10;
digits[3] = time.minutes % 10;
digits[4] = time.seconds / 10;
digits[5] = time.seconds % 10;
// Drawing digits.
for(i = 0; i < 6; i++) dimage_part(x[i], 8, &res_rtc_segments_start,
12 * digits[i], 0, 11, 19);
// Drawing ':' between pairs of digits.
for(i = 0; i < 16; i++) dpixel(47 + 32 * (i >= 8) + (i & 1),
14 + 5 * !!(i & 4) + !!(i & 2), Color_Black);
// This should print time.year + 1900 but for the sake of this demo we
// have tweaked the field so that it already contains time.year + 1900.
print(4, 6, "%s %s %02d %4d", days[time.week_day],
months[time.month], time.month_day, time.year);
}
static void callback(void)
{
extern Image res_opt_rtc_start;
struct RTCTime time = rtc_getTime();
time.year += 1900;
dclear();
draw(time);
dimage_part(0, 56, &res_opt_rtc_start, 0, 0, 19, 8);
dupdate();
}
static void set_region(struct RTCTime *time, int region, int value)
{
switch(region)
{
case 0:
time->hours = 10 * value + (time->hours % 10);
break;
case 1:
time->hours = time->hours - (time->hours % 10) + value;
break;
case 2:
time->minutes = 10 * value + (time->minutes % 10);
break;
case 3:
time->minutes = time->minutes - (time->minutes % 10) + value;
break;
case 4:
time->seconds = 10 * value + (time->seconds % 10);
break;
case 5:
time->seconds = time->seconds - (time->seconds % 10) + value;
break;
case 6:
time->week_day = value;
break;
case 7:
time->month = value;
break;
case 8:
time->month_day = 10 * value + (time->month_day % 10);
break;
case 9:
time->month_day = time->month_day - (time->month_day % 10)
+ value;
break;
case 10:
time->year = 1000 * value + (time->year % 1000);
break;
case 11:
time->year = time->year - (time->year % 1000) + 100 * value
+ (time->year % 100);
break;
case 12:
time->year = time->year - (time->year % 100) + 10 * value
+ (time->year % 10);
break;
case 13:
time->year = time->year - (time->year % 10) + value;
break;
}
}
static void set(void)
{
extern Image res_opt_rtc_start;
Image *opt = &res_opt_rtc_start;
struct {
int x, y;
int w, h;
} regions[] = {
{ 19, 7, 13, 21 }, { 32, 7, 13, 21 }, { 51, 7, 13, 21 },
{ 64, 7, 13, 21 }, { 83, 7, 13, 21 }, { 96, 7, 13, 21 },
{ 18, 39, 19, 9 }, { 42, 39, 19, 9 }, { 66, 39, 7, 9 },
{ 72, 39, 7, 9 }, { 84, 39, 7, 9 }, { 90, 39, 7, 9 },
{ 96, 39, 7, 9 }, { 102, 39, 7, 9 },
};
struct RTCTime time = rtc_getTime();
int region_count = 14;
int n = 0, slide = 0, key, leave;
time.year += 1900;
while(1)
{
dclear();
draw(time);
dreverse_area(regions[n].x, regions[n].y, regions[n].x
+ regions[n].w - 1, regions[n].y + regions[n].h - 1);
if(n == 6) dimage_part(0, 56, opt, 0, 9 * (1 + slide), 128, 8);
if(n == 7) dimage_part(0, 56, opt, 0, 9 * (3 + slide), 128, 8);
else dimage_part(0, 56, opt, 22 + 22 * (n == region_count - 1),
0, 19, 8);
dupdate();
do
{
leave = 1;
key = getkey();
if(key == KEY_EXIT) return;
else if(key == KEY_F1 || key == KEY_EXE)
{
n++;
slide = 0;
if(n == region_count)
{
time.year -= 1900;
rtc_setTime(time);
return;
}
}
else if(key == KEY_F6)
{
if(n == 6) slide = (slide + 1) % 2;
if(n == 7) slide = (slide + 1) % 3;
}
else if((key & 0x0f) == 9) // Other F-keys
{
int k = 7 - (key >> 4); // Number of F-key
if(n == 7)
{
int month = k + 4 * slide - 1;
set_region(&time, n, month);
n++;
slide = 0;
}
else if(n == 6 && (slide != 1 || k != 5))
{
int day = k + 4 * slide - 1;
set_region(&time, n, day);
n++;
slide = 0;
}
else leave = 0;
}
else if(isdigit(keychar(key))) // Numbers
{
int val = keychar(key) - '0';
int ok = 1;
if(n == 0) ok = (val <= 2);
if(n == 1)
{
int max = time.hours >= 20 ? 3 : 9;
ok = (val <= max);
}
if(n == 2 || n == 4) ok = (val <= 5);
if(n == 8) ok = (val <= 3);
if(n == 9)
{
int max = time.month_day >= 30 ? 1 : 9;
ok = (val <= max);
}
if(ok)
{
set_region(&time, n, val);
n++;
if(n == region_count)
{
time.year -= 1900;
rtc_setTime(time);
return;
}
slide = 0;
}
else leave = 0;
}
else leave = 0;
} while(!leave);
}
while(getkey() != KEY_EXIT);
}
void test_rtc(void)
{
int key;
rtc_setCallback(callback, RTCFreq_1Hz);
callback();
while(1)
{
key = getkey();
if(key == KEY_EXIT) break;
if(key == KEY_F1)
{
rtc_setCallback(NULL, RTCFreq_1Hz);
set();
callback();
rtc_setCallback(callback, RTCFreq_1Hz);
}
}
rtc_setCallback(NULL, RTCFreq_1Hz);
}

Binary file not shown.

118
include/internals/rtc.h Normal file
View file

@ -0,0 +1,118 @@
#ifndef _INTERNALS_RTC_H
#define _INTERNALS_RTC_H 1
/*
struct mod_rtc
This structure describes the arrangement of RTC register in the memory.
Curious thing, on SH7705, registers RYRAR and RCR3 are at a completely
different address than the other ones. This module does not use these
registers, so they were not included in the structure.
*/
#pragma pack(push, 1)
struct mod_rtc
{
unsigned char const R64CNT;
unsigned char _1;
union {
unsigned char BYTE;
struct {
unsigned :1;
unsigned TENS :3;
unsigned ONES :4;
};
} RSECCNT;
unsigned char _2;
union {
unsigned char BYTE;
struct {
unsigned :1;
unsigned TENS :3;
unsigned ONES :4;
};
} RMINCNT;
unsigned char _3;
union {
unsigned char BYTE;
struct {
unsigned :2;
unsigned TENS :2;
unsigned ONES :4;
};
} RHRCNT;
unsigned char _4;
// 0 = Sunday, 1 = Monday, ..., 6 = Saturday, 7 = prohibited setting.
unsigned char RWKCNT;
unsigned char _5;
union {
unsigned char BYTE;
struct {
unsigned :2;
unsigned TENS :2;
unsigned ONES :4;
};
} RDAYCNT;
unsigned char _6;
union {
unsigned char BYTE;
struct {
unsigned :3;
unsigned TENS :1;
unsigned ONES :4;
};
} RMONCNT;
unsigned char _7;
union {
unsigned short WORD;
struct {
unsigned THOUSANDS :4;
unsigned HUNDREDS :4;
unsigned TENS :4;
unsigned ONES :4;
};
} RYRCNT;
unsigned char _8[12];
union {
unsigned char BYTE;
struct {
unsigned CF :1;
unsigned :2;
unsigned CIE :1;
unsigned AIE :1;
unsigned :2;
unsigned AF :1;
};
} RCR1;
unsigned char _9;
union {
unsigned char BYTE;
struct {
unsigned PEF :1;
unsigned PES :3;
unsigned :1;
unsigned ADJ :1;
unsigned RESET :1;
unsigned START :1;
};
} RCR2;
} __attribute__((packed));
#pragma pack(pop)
/*
We don't need to access the registers in a complicated way like the
function of the timer module. Let's make it simple.
*/
#define RTC_SH7705 ((volatile struct mod_rtc *)0xfffffec0)
#define RTC_SH7305 ((volatile struct mod_rtc *)0xa413fec0)
#endif // _INTERNALS_RTC_H

View file

@ -20,35 +20,29 @@ extern struct Timer timers[3];
*/ */
struct mod_tmu struct mod_tmu
{ {
// Timer constant register. unsigned int TCOR; // Timer constant register.
unsigned int TCOR; unsigned int TCNT; // Timer counter.
// Timer counter.
unsigned int TCNT;
// Timer control register.
union union
{ {
unsigned short WORD; unsigned short WORD;
struct struct
{ {
unsigned :7; unsigned :7;
// Underflow flag. unsigned UNF :1; // Underflow flag.
unsigned UNF :1;
unsigned :2; unsigned :2;
// Underflow interrupt enable. unsigned UNIE :1; // Underflow interrupt enable.
unsigned UNIE :1; unsigned CKEG :2; // Clock edge (SH7705 only).
// Clock edge, reserved on SH7305. unsigned TPSC :3; // Timer prescaler.
unsigned CKEG :2;
// Timer prescaler.
unsigned TPSC :3;
}; };
} TCR; } TCR; // Timer control register.
}; };
/* /*
timer_get() timer_get()
Returns the timer and TSTR register addresses. Returns the timer and TSTR register addresses.
*/ */
void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr); void timer_get(int timer, volatile struct mod_tmu **tmu,
volatile unsigned char **tstr);
#endif // _INTERNALS_TIMER_H #endif // _INTERNALS_TIMER_H

View file

@ -9,6 +9,43 @@
#ifndef _RTC_H #ifndef _RTC_H
#define _RTC_H 1 #define _RTC_H 1
//---
// Time access.
//---
/*
struct RTCTime
Defines a point in time. This structure *is* the standard struct tm to
avoid useless data copy in the interface between this module and the
standard time module.
*/
struct RTCTime
{
int seconds; // Seconds in range 0-59
int minutes; // Minutes in range 0-59
int hours; // Hours in range 0-23
int month_day; // Day of month in range 1-31
int month; // Month in range 0-11
int year; // Number of years since 1900
int week_day; // Day of week in range 0(Sunday)-6(Saturday).
int year_day; // Day of the year in range 0-365.
int daylight_saving; // As far as I known the RTC does not use DST.
};
/*
rtc_getTime()
Reads the current time from the RTC.
*/
struct RTCTime rtc_getTime(void);
/*
rtc_setTime()
Sets the time in the RTC registers.
*/
void rtc_setTime(struct RTCTime time);
//--- //---
// Callback API. // Callback API.
//--- //---

View file

@ -10,12 +10,33 @@
#ifndef _STDLIB_H #ifndef _STDLIB_H
#define _STDLIB_H 1 #define _STDLIB_H 1
//---
// Common definitions.
//---
#include <stddef.h> #include <stddef.h>
#include <limits.h>
// Common exit codes. // Common exit codes.
#define EXIT_SUCCESS 1 #define EXIT_SUCCESS 1
#define EXIT_FAILURE 0 #define EXIT_FAILURE 0
// Number of atexit() registrations guaranteed.
#define ATEXIT_MAX 16
// Maximum value returned by rand().
#define RAND_MAX INT_MAX
// Integer division result.
typedef struct
{
int quot, rem;
} div_t;
typedef struct
{
long quot, rem;
} ldiv_t;
//--- //---
@ -35,6 +56,12 @@ void abort(void);
*/ */
void exit(int status); void exit(int status);
/*
atexit()
Registers a function to be called at normal program termination.
*/
int atexit(void (*function)(void));
//--- //---
@ -55,14 +82,28 @@ void *malloc(size_t size);
*/ */
void *calloc(size_t n, size_t size); void *calloc(size_t n, size_t size);
/*
realloc()
Reallocates a memory block and moves its data.
*/
void *realloc(void *ptr, size_t size);
/* /*
free() free()
Frees a memory block allocated with malloc(). Frees a memory block allocated by malloc(), calloc() or realloc().
*/ */
void free(void *ptr); void free(void *ptr);
//---
// Random number generation.
//---
/*
int rand(void)
*/
//--- //---
// Integer arithmetic. // Integer arithmetic.
//--- //---
@ -75,6 +116,24 @@ int abs(int x);
// Use a macro instead, when possible. // Use a macro instead, when possible.
#define abs(x) ((x) < 0 ? -(x) : (x)) #define abs(x) ((x) < 0 ? -(x) : (x))
/*
labs()
Returns the absolute value of a long integer.
*/
long labs(long x);
// Use a macro instead.
#define labs(x) ((x) < 0 ? -(x) : (x))
/*
div()
Computes the integer division of numerator by denominator.
*/
div_t div(int numerator, int denominator);
/*
ldiv()
Computes the integer division of two long integers.
*/
ldiv_t ldiv(long numerator, long denominator);
#endif // _STDLIB_H #endif // _STDLIB_H

85
include/time.h Normal file
View file

@ -0,0 +1,85 @@
//---
//
// standard library module: time
//
// Provides time manipulation and representation functions.
//
//---
#ifndef _TIME_H
#define _TIME_H 1
#include <stddef.h>
//---
// Some related types.
//---
/*
struct tm
Represents a point in time and gives some date information.
*/
struct tm
{
int tm_sec; // Seconds in range 0-59
int tm_min; // Minutes in range 0-59
int tm_hour; // Hours in range 0-23
int tm_mday; // Day of month in range 1-31
int tm_mon; // Month in range 0-11
int tm_year; // Number of years since 1900
int tm_wday; // Day of week in range 0(Sunday)-6(Saturday).
int tm_yday; // Day of the year in range 0-365.
int tm_isdst; // Always -1 (not available).
};
/*
clock_t
Only used by clock().
*/
typedef signed int clock_t;
/*
time_t
Number of seconds elapsed since 1970-01-01 00:00:00.
*/
typedef signed int time_t;
//---
// Time access.
//---
/*
clock()
Should return elapsed CPU time since beginning of program execution.
This is currently not implemented and returns -1.
*/
clock_t clock(void);
/*
difftime()
Returns the number of seconds between the given points.
*/
double difftime(time_t end, time_t beginning);
// But this macro should do.
#define difftime(end, beginning) ((double)((end) - (beginning)))
//---
// Time representation.
//---
//---
//
//---
/*
mktime()
Computes fields tm_wday and tm_yday using the other fields. Member
structures outside their range are normalized and tm_isdst is set.
*/
time_t mktime(struct tm *time);
#endif // _TIME_H

BIN
libc.a

Binary file not shown.

BIN
libgint.a

Binary file not shown.

View file

@ -38,7 +38,7 @@ void dimage_part(int x, int y, struct Image *img, int left, int top,
command.bottom = top + ((y + height > 64) ? (64 - y) : height); command.bottom = top + ((y + height > 64) ? (64 - y) : height);
command.left = ((x < 0) ? (left - x) : left) >> 5; command.left = ((x < 0) ? (left - x) : left) >> 5;
actual_width = (x + width > 128) ? (128 - x) : width; actual_width = (x + width > 128) ? (128 - x) : width;
command.right = left + ((actual_width + 31) >> 5) - 1; command.right = ((left + actual_width + 31) >> 5) - 1;
command.op = bopti_op_mono; command.op = bopti_op_mono;

View file

@ -57,7 +57,7 @@ void gimage_part(int x, int y, struct Image *img, int left, int top,
command.bottom = top + ((y + height > 64) ? (64 - y) : height); command.bottom = top + ((y + height > 64) ? (64 - y) : height);
command.left = ((x < 0) ? (left - x) : left) >> 5; command.left = ((x < 0) ? (left - x) : left) >> 5;
actual_width = (x + width > 128) ? (128 - x) : width; actual_width = (x + width > 128) ? (128 - x) : width;
command.right = left + ((actual_width + 31) >> 5) - 1; command.right = ((left + actual_width + 31) >> 5) - 1;
command.op = bopti_op_gray; command.op = bopti_op_gray;

View file

@ -23,6 +23,10 @@ extern unsigned int
static int exit_code = EXIT_SUCCESS; static int exit_code = EXIT_SUCCESS;
static jmp_buf env; static jmp_buf env;
// Exit handlers.
void (*atexit_handlers[ATEXIT_MAX])(void);
int atexit_index = 0;
/* /*
@ -69,6 +73,9 @@ int start(void)
// Remember to flush and close opened streams. // Remember to flush and close opened streams.
// Calling exit handlers.
while(atexit_index > 0) (*atexit_handlers[--atexit_index])();
// Un-initializing everything. // Un-initializing everything.
fini(); fini();
gint_quit(); gint_quit();
@ -76,6 +83,10 @@ int start(void)
return exit_code; return exit_code;
} }
/*
init()
Calls the constructors.
*/
static void init(void) static void init(void)
{ {
extern void extern void
@ -83,7 +94,6 @@ static void init(void)
(*ectors)(void); (*ectors)(void);
void (**func)(void) = &bctors; void (**func)(void) = &bctors;
// Calling the constructors.
while(func < &ectors) while(func < &ectors)
{ {
(*(*func))(); (*(*func))();
@ -91,6 +101,10 @@ static void init(void)
} }
} }
/*
fini()
Calls the destructors.
*/
static void fini(void) static void fini(void)
{ {
extern void extern void
@ -98,7 +112,6 @@ static void fini(void)
(*edtors)(void); (*edtors)(void);
void (**func)(void) = &bdtors; void (**func)(void) = &bdtors;
// Calling the destructors.
while(func < &edtors) while(func < &edtors)
{ {
(*(*func))(); (*(*func))();
@ -112,10 +125,13 @@ static void fini(void)
abort() abort()
Immediately ends the program without invoking the exit handlers. Immediately ends the program without invoking the exit handlers.
*/ */
void abort(void) void abort(void)
{ {
exit_code = EXIT_FAILURE; exit_code = EXIT_FAILURE;
// Avoiding any exit handler call.
atexit_index = 0;
longjmp(env, 1); longjmp(env, 1);
} }
@ -129,10 +145,21 @@ void abort(void)
of achieving this goal while minimizing interaction with the operating of achieving this goal while minimizing interaction with the operating
system. system.
*/ */
void exit(int status) void exit(int status)
{ {
exit_code = status; exit_code = status;
longjmp(env, 1); longjmp(env, 1);
} }
/*
atexit()
Registers a function to be called at normal program termination.
*/
int atexit(void (*function)(void))
{
if(atexit_index >= ATEXIT_MAX) return 1;
atexit_handlers[atexit_index++] = function;
return 0;
}

53
src/rtc/rtc_getTime.c Normal file
View file

@ -0,0 +1,53 @@
#include <internals/rtc.h>
#include <rtc.h>
#include <mpu.h>
/*
integer()
Converts a BCD value to an integer.
*/
static int integer8(int bcd)
{
return (bcd & 0x0f) + 10 * (bcd >> 4);
}
static int integer16(int bcd)
{
return (bcd & 0xf) + 10 * ((bcd >> 4) & 0xf) + 100 * ((bcd >> 8) & 0xf)
+ 1000 * (bcd >> 12);
}
static int year_day(int year, int year_bcd, int month, int month_day)
{
int days_in_month[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int leap;
int hundreds = integer8(year_bcd >> 8);
int day, i;
leap = !(year & 3); // Take multiples of 4
if(!((year_bcd >> 8) & 0xf)) leap = 0; // Remove multiples of 100
if(!(hundreds & 3)) leap = 1; // Take multiples of 400
day = leap && (month > 2);
for(i = 0; i < month - 1; i++) day += days_in_month[i];
return day + month_day - 1;
}
struct RTCTime rtc_getTime(void)
{
volatile struct mod_rtc *rtc = isSH3() ? RTC_SH7705 : RTC_SH7305;
struct RTCTime time;
time.seconds = integer8(rtc->RSECCNT.BYTE);
time.minutes = integer8(rtc->RMINCNT.BYTE);
time.hours = integer8(rtc->RHRCNT.BYTE);
time.month_day = integer8(rtc->RDAYCNT.BYTE);
time.month = integer8(rtc->RMONCNT.BYTE);
time.year = integer16(rtc->RYRCNT.WORD) - 1900;
time.week_day = rtc->RWKCNT;
time.year_day = year_day(time.year + 1900, rtc->RYRCNT.WORD,
time.month, time.month_day);
time.daylight_saving = 0;
return time;
}

31
src/rtc/rtc_setTime.c Normal file
View file

@ -0,0 +1,31 @@
#include <internals/rtc.h>
#include <rtc.h>
#include <mpu.h>
/*
bcd()
Converts an integer to a BCD value.
*/
static int bcd8(int integer)
{
integer %= 100;
return ((integer / 10) << 4) | (integer % 10);
}
static int bcd16(int integer)
{
integer %= 10000;
return (bcd8(integer / 100) << 8) | bcd8(integer % 100);
}
void rtc_setTime(struct RTCTime time)
{
volatile struct mod_rtc *rtc = isSH3() ? RTC_SH7705 : RTC_SH7305;
rtc->RSECCNT.BYTE = bcd8(time.seconds);
rtc->RMINCNT.BYTE = bcd8(time.minutes);
rtc->RHRCNT.BYTE = bcd8(time.hours);
rtc->RDAYCNT.BYTE = bcd8(time.month_day);
rtc->RMONCNT.BYTE = bcd8(time.month);
rtc->RYRCNT.WORD = bcd16(time.year + 1900);
rtc->RWKCNT = time.week_day < 7 ? time.week_day : 0;
}

View file

@ -9,7 +9,7 @@
Internal buffer. Internal buffer.
Using a buffer *really* simplifies everything. But it also has Using a buffer *really* simplifies everything. But it also has
disadvantages, such a memory loss and limited output size. disadvantages, such as some memory loss and limited output size.
So, in case we find a possibility to get rid of this buffer, we will So, in case we find a possibility to get rid of this buffer, we will
just have to change function character(), which is for now the only just have to change function character(), which is for now the only
@ -20,35 +20,34 @@ char __stdio_buffer[__stdio_buffer_size];
/* /*
Format composed types. Composed types for format definition.
Format structure handles everything in a format, from data type to The Format structure handles everything in a format: data type, value,
given value, including alternative forms, alignment and digit numbers. alternative forms, alignment and character number, precision... there
are mainly a data type (altered by a size option), a value to print
and a number of characters.
A format is made of a data type, which can be altered by a size option, Other options are handled by The FormatFlags enumeration. See the
a number of integer and decimal digits, and additional flags. description of functions __printf() for further description on option
precedence and influence.
The FormatFlags enumeration handles the various flags that can be added
to a printf()-family format.
*/ */
enum FormatFlags enum FormatFlags
{ {
// Option '#' specifies alternatives forms, mainly '0' and '0x' // Alternatives forms add '0' and '0x' prefixes in octal and
// prefixes in integer display. // hexadecimal bases. (#)
Alternative = 1, Alternative = 1,
// Under specific conditions, zero-padding may be used instead of // Under specific conditions, zero-padding may be used instead of
// whitespace-padding. // whitespace-padding. (0)
ZeroPadded = 2, ZeroPadded = 2,
// Left alignment specifies that additional spaces should be added // Left alignment specifies that additional spaces should be added
// after the value. // after the value instead of before. (-)
LeftAlign = 4, LeftAlign = 4,
// In numeric display, this forces a blank sign to be written before // In numeric display, this forces a blank sign to be written before
// positive values. // positive values. ( )
BlankSign = 8, BlankSign = 8,
// In numeric display, this forces an explicit sign in all cases. This // In numeric display, this forces an explicit sign in all cases. This
// option overrides BlankSign (see __printf() description for further // option overrides BlankSign. (+)
// information on option precedence and influence).
ForceSign = 16 ForceSign = 16
}; };
@ -72,7 +71,7 @@ struct Format
{ {
// Signed int with formats %c, %d and %i. // Signed int with formats %c, %d and %i.
signed int _int; signed int _int;
// Insigned int with formats %o, %u, %x and %X. // Unsigned int with formats %o, %u, %x and %X.
unsigned int _unsigned; unsigned int _unsigned;
// Double with formats %f, %F, %e, %E, %g and %G. // Double with formats %f, %F, %e, %E, %g and %G.
// double _double; // double _double;
@ -364,8 +363,7 @@ static void get_spacing(struct Format format, int *begin_spaces, int *sign,
__printf() __printf()
Basic buffered formatted printing function. Fully-featured, so that Basic buffered formatted printing function. Fully-featured, so that
ant call to a printf()-family function can be translated into a any call to a printf()-family function can be performed by __printf().
__printf() call.
It always returns the number of characters of the theoretic formatted It always returns the number of characters of the theoretic formatted
output. The real output may be limited in size by the given size output. The real output may be limited in size by the given size
@ -376,30 +374,27 @@ static void get_spacing(struct Format format, int *begin_spaces, int *sign,
argument handling (because flag effects depend on format type, which argument handling (because flag effects depend on format type, which
is unknown when the flags are read). Also, length modifiers 'hh' is is unknown when the flags are read). Also, length modifiers 'hh' is
stored as 'i' to simplify structure handling. 'll' is not supported. stored as 'i' to simplify structure handling. 'll' is not supported.
Format '%LF' is allowed by C99 and therefore supported. Support for format '%lf' (C99) is planned.
Generic information on options precedence and influence. Generic information on options precedence and influence.
- Influences of integer part and mantissa digit numbers depend on - Number of characters and precision represent different lengths
the type of data that is being displayed. depending on the data type.
- Option '#' doesn't contend with any other. - '#' is independent.
- Option '+' overrides options ' '. - '+' overrides ' '.
- In integer display, option '0' translates spaces to zeros, but - In integer display, '0' replaces spaces to zeros, only if no
only if no decimal digit number is specified. precision (decimal digit number) is specified.
The option '-' also overrides it, forcing whitespaces to be - '-' also overrides it, forcing whitespaces to be written at the end.
written at the end of the format.
Limit of function. Limits of function.
- Internal buffer size (should be customizable with a -D option - Internal buffer size (there should be a loop to allow larger data).
when compiling). - Precision values (format %a.b) are limited to 127.
- Precision values (format %a.b) are written on 8 bits, therefore
limited to 127.
Unsupported features. Unsupported features.
- Flag character ''' (single quote) for thousands grouping - ''' (single quote) (thousands grouping)
- Flag character 'I', that outputs locale's digits (glibc 2.2) - 'I' (outputs locale's digits (glibc 2.2))
- Length modifiers 'll' and 'q' (libc 5 and 4.4 BSD) - Length modifiers 'll' and 'q' (libc 5 and 4.4 BSD)
- This is not really a feature but incorrect characters in - This is not really a feature but incorrect characters in formats are
formats are ignored and don't invalidate the format. ignored and don't invalidate the format.
*/ */
int __printf(size_t size, const char *string, va_list args) int __printf(size_t size, const char *string, va_list args)
{ {
@ -409,7 +404,7 @@ int __printf(size_t size, const char *string, va_list args)
if(!size || size > __stdio_buffer_size) if(!size || size > __stdio_buffer_size)
size = __stdio_buffer_size; size = __stdio_buffer_size;
// Initializing character() working values. // Initializing character() variables.
written = 0; written = 0;
total = 0; total = 0;
max = size; max = size;
@ -437,8 +432,7 @@ int __printf(size_t size, const char *string, va_list args)
format = get_format(&string); format = get_format(&string);
if(!format.type) break; if(!format.type) break;
/* /* Some debugging...
// Displaying an information message.
printf( printf(
"Format found :%s%c%c, options %d, and %d.%d " "Format found :%s%c%c, options %d, and %d.%d "
"digits\n", "digits\n",
@ -448,8 +442,7 @@ int __printf(size_t size, const char *string, va_list args)
format.flags, format.flags,
format.digits, format.digits,
format.mantissa format.mantissa
); ); */
*/
switch(format.type) switch(format.type)
{ {
@ -459,15 +452,8 @@ int __printf(size_t size, const char *string, va_list args)
format._int = va_arg(args, signed int); format._int = va_arg(args, signed int);
// Reducing value depending on format size. // Reducing value depending on format size.
switch(format.size) if(format.size == 'h') format._int &= 0x0000ffff;
{ if(format.size == 'i') format._int &= 0x000000ff;
case 'h':
format._int &= 0x0000ffff;
break;
case 'i':
format._int &= 0x000000ff;
break;
}
format_di(format); format_di(format);
break; break;
@ -877,7 +863,7 @@ void format_p(struct Format format)
unsigned int x = format._unsigned; unsigned int x = format._unsigned;
int bspaces, zeros, digits = 0, espaces; int bspaces, zeros, digits = 0, espaces;
int c; int c, i;
digits = x ? 10 : 5; digits = x ? 10 : 5;
get_spacing(format, &bspaces, NULL, &zeros, digits, &espaces); get_spacing(format, &bspaces, NULL, &zeros, digits, &espaces);
@ -889,7 +875,7 @@ void format_p(struct Format format)
{ {
character('0'); character('0');
character('x'); character('x');
while(x) for(i = 0; i < 8; i++)
{ {
c = x >> 28; c = x >> 28;
c += '0' + 39 * (c > 9); c += '0' + 39 * (c > 9);

View file

@ -1,7 +0,0 @@
#include <stdlib.h>
#undef abs
int abs(int x)
{
return (x < 0) ? (-x) : (x);
}

View file

@ -1,4 +1,5 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
/* /*
calloc() calloc()

13
src/stdlib/stdlib_abs.c Normal file
View file

@ -0,0 +1,13 @@
#include <stdlib.h>
#undef abs
#undef labs
int abs(int x)
{
return (x < 0) ? (-x) : x;
}
long labs(long x)
{
return (x < 0) ? (-x) : x;
}

29
src/stdlib/stdlib_div.c Normal file
View file

@ -0,0 +1,29 @@
#include <stdlib.h>
/*
div()
Computes the integer division of numerator by denominator.
*/
div_t div(int numerator, int denominator)
{
div_t result;
result.quot = numerator / denominator;
result.rem = numerator - result.quot * denominator;
return result;
}
/*
ldiv()
Computes the integer division of two long integers.
*/
ldiv_t ldiv(long numerator, long denominator)
{
ldiv_t result;
result.quot = numerator / denominator;
result.rem = numerator - result.quot * denominator;
return result;
}

14
src/stdlib/stdlib_rand.c Normal file
View file

@ -0,0 +1,14 @@
#include <stdlib.h>
static unsigned int seed = 1;
void srand(unsigned int new_seed)
{
seed = new_seed;
}
int rand(void)
{
seed = seed * 1103515245 + 12345;
return seed & 0x7fffffff;
}

93
src/time/mktime.c Normal file
View file

@ -0,0 +1,93 @@
#include <time.h>
/*
isLeap()
Determines whether the given year is a leap year.
*/
int isLeap(int year)
{
int leap = !(year & 3); // Take multiples of 4
if(!(year % 100)) leap = 0; // Remove multiples of 100
if(!(year % 400)) leap = 1; // Take multiples of 400
return leap;
}
/*
daysInMonth()
Returns number of days for the given month (between 0 and 11) and year.
*/
int daysInMonth(int month, int year)
{
int days[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
if(month != 1) return days[month];
return days[month] + isLeap(year);
}
/*
mktime()
Computes fields tm_wday and tm_yday using the other fields. Member
structures outside their range are normalized and tm_isdst is set.
*/
time_t mktime(struct tm *time)
{
int first, leaps, yr;
int days, i;
time_t elapsed;
// Normalizing time.
time->tm_min += (time->tm_sec / 60);
time->tm_hour += (time->tm_min / 60);
time->tm_mday += (time->tm_hour / 24);
time->tm_sec %= 60;
time->tm_min %= 60;
time->tm_hour %= 24;
// Normalizing date.
days = daysInMonth(time->tm_mon, time->tm_year + 1900);
while(time->tm_mday >= days)
{
time->tm_mday -= days;
if(++time->tm_mon == 12)
{
time->tm_mon = 0;
time->tm_year++;
}
days = daysInMonth(time->tm_mon, time->tm_year + 1900);
}
// Setting the year day.
days = 0;
for(i = 0; i < time->tm_mon; i++)
days += daysInMonth(i, time->tm_year + 1900);
time->tm_yday = days + time->tm_mday;
// Setting the week day. The calendar is periodic over 400 years and
// 1601-01-01 was a Monday.
// Years completely elapsed since last 400n + 1 year (1601-2001-etc).
yr = (time->tm_year + 1900 - 1) % 400;
// Leap years in these yr years.
leaps = (yr / 4) - (yr >= 100) - (yr >= 200) - (yr >= 300);
// Days completely elapsed since last 400n + 1 year, 01-01.
days = 365 * yr + leaps + time->tm_yday;
// Current day of week (1 means Monday 1601-01-01).
time->tm_wday = (1 + days) % 7;
// This RTC does not seem to have any DST feature.
time->tm_isdst = 0;
if(time->tm_year + 1900 < 1970) return (time_t)-1;
// 134774 is the number of days between 1601-01-01 and 1970-01-01. Thus
// days become the number of days elapsed since 1970-01-01.
days -= 134774;
// days may become negative, so add the calendar period.
if(days < 0) days += 146097;
return (24 * 3600) * days + 3600 * time->tm_hour + 60 * time->tm_min +
time->tm_sec;
}

20
src/time/time_misc.c Normal file
View file

@ -0,0 +1,20 @@
#include <time.h>
/*
clock()
Should return elapsed CPU time since beginning of program execution.
This is currently not implemented and returns -1.
*/
clock_t clock(void)
{
return (clock_t)-1;
}
/*
difftime()
Returns the number of seconds between the given points.
*/
double difftime(time_t end, time_t beginning)
{
return (double)(end - beginning);
}

View file

@ -5,21 +5,21 @@
timer_get() timer_get()
Returns the timer and TSTR register addresses. Returns the timer and TSTR register addresses.
*/ */
void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr) void timer_get(int timer, volatile struct mod_tmu **tmu,
volatile unsigned char **tstr)
{ {
// Using SH7705 information for SH-3-based MPUs. // Using SH7705 information for SH-3-based MPUs.
if(isSH3()) if(isSH3())
{ {
if(tstr) *tstr = (unsigned char *)0xfffffe92; if(tstr) *tstr = (volatile unsigned char *)0xfffffe92;
if(tmu) *tmu = (struct mod_tmu *)0xfffffe94; if(tmu) *tmu = (volatile struct mod_tmu *)
(0xfffffe94 + 12 * timer);
} }
// Assuming SH7305 by default. // Assuming SH7305 by default.
else else
{ {
if(tstr) *tstr = (unsigned char *)0xa4490004; if(tstr) *tstr = (volatile unsigned char *)0xa4490004;
if(tmu) *tmu = (struct mod_tmu *)0xa4490008; if(tmu) *tmu = (volatile struct mod_tmu *)
(0xa4490008 + 12 * timer);
} }
// Shifting tmu value to get to the timer-nth timer in the unit.
if(tmu) *tmu += timer;
} }

View file

@ -11,11 +11,11 @@ struct Timer timers[3] = { { NULL, 0 }, { NULL, 0 }, { NULL, 0 } };
*/ */
void timer_interrupt(int timer) void timer_interrupt(int timer)
{ {
struct mod_tmu *tmu; volatile struct mod_tmu *tmu;
timer_get(timer, &tmu, NULL); timer_get(timer, &tmu, NULL);
// Resetting the interrupt flag. // Resetting the interrupt flag.
(*tmu).TCR.UNF = 0; tmu->TCR.UNF = 0;
// Calling the callback function. // Calling the callback function.
if(timers[timer].callback) timers[timer].callback(); if(timers[timer].callback) timers[timer].callback();

View file

@ -8,14 +8,14 @@
*/ */
void timer_reload(int timer, int new_delay) void timer_reload(int timer, int new_delay)
{ {
struct mod_tmu *tmu; volatile struct mod_tmu *tmu;
unsigned char *tstr; volatile unsigned char *tstr;
int byte = (1 << timer); int byte = (1 << timer);
timer_get(timer, &tmu, &tstr); timer_get(timer, &tmu, &tstr);
// Setting the constant and the delay. // Setting the constant and the delay.
(*tmu).TCOR = new_delay; tmu->TCOR = new_delay;
(*tmu).TCNT = new_delay; tmu->TCNT = new_delay;
// Starting the timer. // Starting the timer.
*tstr |= byte; *tstr |= byte;

View file

@ -8,31 +8,28 @@
void timer_start(int timer, int delay, int prescaler, void (*callback)(void), void timer_start(int timer, int delay, int prescaler, void (*callback)(void),
int repeats) int repeats)
{ {
// Getting the timer address. Using a byte to alter TSTR. volatile struct mod_tmu *tmu;
struct mod_tmu *tmu; volatile unsigned char *tstr;
unsigned char *tstr;
int byte = (1 << timer); int byte = (1 << timer);
timer_get(timer, &tmu, &tstr); timer_get(timer, &tmu, &tstr);
// Setting the constant register. // Loading the counter, the constant and the prescaler/
(*tmu).TCOR = delay; tmu->TCOR = delay;
// Loading the delay in the counter. tmu->TCNT = delay;
(*tmu).TCNT = delay; tmu->TCR.TPSC = prescaler;
// Resetting underflow flag. // Resetting underflow flag and enabling interruptions.
(*tmu).TCR.UNF = 0; tmu->TCR.UNF = 0;
// Enabling interruptions on underflow. tmu->TCR.UNIE = 1;
(*tmu).TCR.UNIE = 1;
// Counting on rising edge. On SH7305 these two bits are reserved but // Counting on rising edge (ignored on SH7305).
// writing 0 is ignored. tmu->TCR.CKEG = 0;
(*tmu).TCR.CKEG = 0;
// Setting the prescaler.
(*tmu).TCR.TPSC = prescaler;
// Loading the structure information. // Loading the structure information.
timers[timer].callback = callback; timers[timer].callback = callback;
timers[timer].repeats = repeats; timers[timer].repeats = repeats;
// Starting the timer and returning. // Starting the timer.
*tstr |= byte; *tstr |= byte;
} }

View file

@ -10,11 +10,9 @@
*/ */
void timer_stop(int timer) void timer_stop(int timer)
{ {
// Getting TSTR address and the corresponding byte. volatile unsigned char *tstr;
unsigned char *tstr;
int byte = (1 << timer); int byte = (1 << timer);
timer_get(timer, NULL, &tstr);
// Stopping the timer. timer_get(timer, NULL, &tstr);
*tstr &= ~byte; *tstr &= ~byte;
} }