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-gint = core keyboard mmu mpu rtc screen timer \
bopti display gray tales
modules-libc = setjmp string stdio
modules-libc = setjmp string stdio stdlib
# Targets
target-g1a = gintdemo.g1a

6
TODO
View file

@ -10,9 +10,11 @@
@ possibility of vram overflow with text
@ garbage displayed as year in the clock, possibly during edition (could not
reproduce)
+ 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
+ gint vs. ML with 248x124 at (-60, -28)
+ call exit handlers
@ -23,7 +25,7 @@
- full rtc driver (time)
- callbacks and complete user API
~ shadowy rectangle effect for Shift + Alpha + Left + Down
~ packed bit fields
~ exhaustive save for setjmp()
~ registers that need to be saved when configuring gint
~ 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);
}
/*
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()
Tests formatting functions.
@ -534,7 +508,7 @@ int main(void)
test_tales();
break;
case 0x0105:
// test_rtc();
test_rtc();
break;
case 0x0106:
// 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)
{
multigetkey(keys, 4, 1);
if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break;
dclear();
locate(1, 1, "Keyboard driver");
locate(8, 3, "Pressed keys:");
@ -78,5 +75,8 @@ void test_keyboard(void)
}
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
{
// Timer constant register.
unsigned int TCOR;
// Timer counter.
unsigned int TCNT;
unsigned int TCOR; // Timer constant register.
unsigned int TCNT; // Timer counter.
// Timer control register.
union
{
unsigned short WORD;
struct
{
unsigned :7;
// Underflow flag.
unsigned UNF :1;
unsigned UNF :1; // Underflow flag.
unsigned :2;
// Underflow interrupt enable.
unsigned UNIE :1;
// Clock edge, reserved on SH7305.
unsigned CKEG :2;
// Timer prescaler.
unsigned TPSC :3;
unsigned UNIE :1; // Underflow interrupt enable.
unsigned CKEG :2; // Clock edge (SH7705 only).
unsigned TPSC :3; // Timer prescaler.
};
} TCR;
} TCR; // Timer control register.
};
/*
timer_get()
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

View file

@ -9,6 +9,43 @@
#ifndef _RTC_H
#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.
//---

View file

@ -10,12 +10,33 @@
#ifndef _STDLIB_H
#define _STDLIB_H 1
//---
// Common definitions.
//---
#include <stddef.h>
#include <limits.h>
// Common exit codes.
#define EXIT_SUCCESS 1
#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);
/*
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);
/*
realloc()
Reallocates a memory block and moves its data.
*/
void *realloc(void *ptr, size_t size);
/*
free()
Frees a memory block allocated with malloc().
Frees a memory block allocated by malloc(), calloc() or realloc().
*/
void free(void *ptr);
//---
// Random number generation.
//---
/*
int rand(void)
*/
//---
// Integer arithmetic.
//---
@ -73,8 +114,26 @@ void free(void *ptr);
*/
int abs(int x);
// 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

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.left = ((x < 0) ? (left - x) : left) >> 5;
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;

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.left = ((x < 0) ? (left - x) : left) >> 5;
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;

View file

@ -23,6 +23,10 @@ extern unsigned int
static int exit_code = EXIT_SUCCESS;
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.
// Calling exit handlers.
while(atexit_index > 0) (*atexit_handlers[--atexit_index])();
// Un-initializing everything.
fini();
gint_quit();
@ -76,6 +83,10 @@ int start(void)
return exit_code;
}
/*
init()
Calls the constructors.
*/
static void init(void)
{
extern void
@ -83,7 +94,6 @@ static void init(void)
(*ectors)(void);
void (**func)(void) = &bctors;
// Calling the constructors.
while(func < &ectors)
{
(*(*func))();
@ -91,6 +101,10 @@ static void init(void)
}
}
/*
fini()
Calls the destructors.
*/
static void fini(void)
{
extern void
@ -98,7 +112,6 @@ static void fini(void)
(*edtors)(void);
void (**func)(void) = &bdtors;
// Calling the destructors.
while(func < &edtors)
{
(*(*func))();
@ -112,10 +125,13 @@ static void fini(void)
abort()
Immediately ends the program without invoking the exit handlers.
*/
void abort(void)
{
exit_code = EXIT_FAILURE;
// Avoiding any exit handler call.
atexit_index = 0;
longjmp(env, 1);
}
@ -129,10 +145,21 @@ void abort(void)
of achieving this goal while minimizing interaction with the operating
system.
*/
void exit(int status)
{
exit_code = status;
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.
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
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
given value, including alternative forms, alignment and digit numbers.
The Format structure handles everything in a format: data type, value,
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,
a number of integer and decimal digits, and additional flags.
The FormatFlags enumeration handles the various flags that can be added
to a printf()-family format.
Other options are handled by The FormatFlags enumeration. See the
description of functions __printf() for further description on option
precedence and influence.
*/
enum FormatFlags
{
// Option '#' specifies alternatives forms, mainly '0' and '0x'
// prefixes in integer display.
// Alternatives forms add '0' and '0x' prefixes in octal and
// hexadecimal bases. (#)
Alternative = 1,
// Under specific conditions, zero-padding may be used instead of
// whitespace-padding.
// whitespace-padding. (0)
ZeroPadded = 2,
// Left alignment specifies that additional spaces should be added
// after the value.
// after the value instead of before. (-)
LeftAlign = 4,
// In numeric display, this forces a blank sign to be written before
// positive values.
// positive values. ( )
BlankSign = 8,
// In numeric display, this forces an explicit sign in all cases. This
// option overrides BlankSign (see __printf() description for further
// information on option precedence and influence).
// option overrides BlankSign. (+)
ForceSign = 16
};
@ -72,7 +71,7 @@ struct Format
{
// Signed int with formats %c, %d and %i.
signed int _int;
// Insigned int with formats %o, %u, %x and %X.
// Unsigned int with formats %o, %u, %x and %X.
unsigned int _unsigned;
// Double with formats %f, %F, %e, %E, %g and %G.
// double _double;
@ -364,8 +363,7 @@ static void get_spacing(struct Format format, int *begin_spaces, int *sign,
__printf()
Basic buffered formatted printing function. Fully-featured, so that
ant call to a printf()-family function can be translated into a
__printf() call.
any call to a printf()-family function can be performed by __printf().
It always returns the number of characters of the theoretic formatted
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
is unknown when the flags are read). Also, length modifiers 'hh' is
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.
- Influences of integer part and mantissa digit numbers depend on
the type of data that is being displayed.
- Option '#' doesn't contend with any other.
- Option '+' overrides options ' '.
- In integer display, option '0' translates spaces to zeros, but
only if no decimal digit number is specified.
The option '-' also overrides it, forcing whitespaces to be
written at the end of the format.
- Number of characters and precision represent different lengths
depending on the data type.
- '#' is independent.
- '+' overrides ' '.
- In integer display, '0' replaces spaces to zeros, only if no
precision (decimal digit number) is specified.
- '-' also overrides it, forcing whitespaces to be written at the end.
Limit of function.
- Internal buffer size (should be customizable with a -D option
when compiling).
- Precision values (format %a.b) are written on 8 bits, therefore
limited to 127.
Limits of function.
- Internal buffer size (there should be a loop to allow larger data).
- Precision values (format %a.b) are limited to 127.
Unsupported features.
- Flag character ''' (single quote) for thousands grouping
- Flag character 'I', that outputs locale's digits (glibc 2.2)
- Length modifiers 'll' and 'q' (libc 5 and 4.4 BSD)
- This is not really a feature but incorrect characters in
formats are ignored and don't invalidate the format.
- ''' (single quote) (thousands grouping)
- 'I' (outputs locale's digits (glibc 2.2))
- Length modifiers 'll' and 'q' (libc 5 and 4.4 BSD)
- This is not really a feature but incorrect characters in formats are
ignored and don't invalidate the format.
*/
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)
size = __stdio_buffer_size;
// Initializing character() working values.
// Initializing character() variables.
written = 0;
total = 0;
max = size;
@ -437,8 +432,7 @@ int __printf(size_t size, const char *string, va_list args)
format = get_format(&string);
if(!format.type) break;
/*
// Displaying an information message.
/* Some debugging...
printf(
"Format found :%s%c%c, options %d, and %d.%d "
"digits\n",
@ -448,8 +442,7 @@ int __printf(size_t size, const char *string, va_list args)
format.flags,
format.digits,
format.mantissa
);
*/
); */
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);
// Reducing value depending on format size.
switch(format.size)
{
case 'h':
format._int &= 0x0000ffff;
break;
case 'i':
format._int &= 0x000000ff;
break;
}
if(format.size == 'h') format._int &= 0x0000ffff;
if(format.size == 'i') format._int &= 0x000000ff;
format_di(format);
break;
@ -877,7 +863,7 @@ void format_p(struct Format format)
unsigned int x = format._unsigned;
int bspaces, zeros, digits = 0, espaces;
int c;
int c, i;
digits = x ? 10 : 5;
get_spacing(format, &bspaces, NULL, &zeros, digits, &espaces);
@ -889,7 +875,7 @@ void format_p(struct Format format)
{
character('0');
character('x');
while(x)
for(i = 0; i < 8; i++)
{
c = x >> 28;
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 <string.h>
/*
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()
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.
if(isSH3())
{
if(tstr) *tstr = (unsigned char *)0xfffffe92;
if(tmu) *tmu = (struct mod_tmu *)0xfffffe94;
if(tstr) *tstr = (volatile unsigned char *)0xfffffe92;
if(tmu) *tmu = (volatile struct mod_tmu *)
(0xfffffe94 + 12 * timer);
}
// Assuming SH7305 by default.
else
{
if(tstr) *tstr = (unsigned char *)0xa4490004;
if(tmu) *tmu = (struct mod_tmu *)0xa4490008;
if(tstr) *tstr = (volatile unsigned char *)0xa4490004;
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)
{
struct mod_tmu *tmu;
volatile struct mod_tmu *tmu;
timer_get(timer, &tmu, NULL);
// Resetting the interrupt flag.
(*tmu).TCR.UNF = 0;
tmu->TCR.UNF = 0;
// Calling the callback function.
if(timers[timer].callback) timers[timer].callback();

View file

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

View file

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

View file

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