More quality review, more registers saved at startup.

This commit is contained in:
lephe 2017-04-13 21:59:13 +02:00
parent c8170b165a
commit acc0e5fcc1
38 changed files with 673 additions and 563 deletions

View file

@ -104,7 +104,7 @@ hdr-dep = $(wildcard include/*.h include/*/*.h)
#---
# Rule templates.
# Rule templates
#---
# C source file template:
@ -129,7 +129,29 @@ endef
#---
# Building.
# Version management
#---
# Retrieve version information.
version_string := $(shell cat version | sed 's/[-.]/ /g')
version_type := $(word 1,$(version_string))
version_major := $(word 2,$(version_string))
version_minor := $(word 3,$(version_string))
version_build := $(word 4,$(version_string))
# Bump build number and make up the new version integer.
version_build := $(shell echo $$(($(version_build) + 1)))
version_letter := $(shell echo -n $(version_type) | sed -r 's/^(.).*/\1/')
version_symbol := $(shell printf '0x%02x%01x%01x%04x' "'$(version_letter)'" \
$(version_major) $(version_minor) $(version_build))
# Tell the linker to define the version symbol.
ldflags += -Wl,--defsym,GINT_VERSION=$(version_symbol)
#---
# Building
#---
# Generic rules
@ -142,16 +164,20 @@ build:
$(if $(VERBOSE),,@ printf '\e[35;1mdir \u00bb\e[0m mkdir $@\n')
$(if $(VERBOSE),,@) mkdir -p $@
version: $(obj-std) $(obj-lib)
@ echo '$(version_type)-$(version_major).$(version_minor)-$(version_build)' > $@
$(obj-std) $(obj-lib) $(demo-obj): | build
$(target-std): $(obj-std)
$(target-std): $(obj-std) version
$(if $(VERBOSE),,@ printf '\e[35;1mlib \u00bb\e[0m ar $@\n')
$(if $(VERBOSE),,@) $(ar) rcs $@ $(obj-std)
@ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built libc ('
@ printf $$(stat -c %s $@)
@ printf ' bytes)\n\n'
$(target-lib): $(config) $(target-std) $(obj-lib)
$(target-lib): $(config) $(target-std) $(obj-lib) version
$(if $(VERBOSE),,@ printf '\e[35;1mlib \u00bb\e[0m ar $@\n')
$(if $(VERBOSE),,@) $(ar) rcs $@ $(obj-lib)
@ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built libgint ('

44
TODO
View file

@ -1,37 +1,37 @@
Bugs to fix:
- A few key hits ignored after leaving the application (could not reproduce)
- Lost keyboard control at startup (could not reproduce)
- Influence of keyboard on some timers and RTC (maybe interrupt priority)
- Alignment of ALL .data / .rodata files is required to ensure converted data
is properly aligned
- Reported video ram overflow when rendering text at borderline positions
Simple improvements:
- demo: Try 284x124 at (-60, -28) (all disadvantages)
- display: Rectangle-based drawing functions
- time: Compute CLOCKS_PER_SEC
- string: Use cmp/str to implement memchr() (assembler examples)
- string: Do some tests for memcmp()
- core: Register more interrupts (and understand their parameters)
- project: Clean headers that have some internal definitions
- project: Check size of all library structures
Larger improvements:
- errno: Introduce errno and use it more or less everywhere
- bopti: Monochrome bitmaps blending modes
- bopti: Handle partial transparency
- core: Implement all callbacks and a complete user API
* core: Better save registers
Things to do before 1.0:
- bopti: Test partial transparency
* core: Allow return to menu
- serial: Implement a driver
- usb: Implement a driver
- esper: Cleaner playback, synthesizing
- clock: Handle overclock (relaunch clocks when overclocking)
- demo: Try 284x124 at (-60, -28) (all disadvantages)
- display: Implement rectangle-based drawing functions
- project: Add a real build-based version system
- project: Check size of *all* library structures
- project: Clean headers that have some internal definitions
- project: Unify this hellish mess of register access!
- time: Compute CLOCKS_PER_SEC
Things to do later:
- bopti: Implement blending modes for monochrome bitmaps
- clock: Handle overclock (relaunch clocks when overclocking)
- core: Register more interrupts (and understand their parameters)
- core: Remove redundant code linked to environment saves
- core: Review interrupt system (again) - this one is too slow
- errno: Introduce errno and use it more or less everywhere
- esper: Cleaner playback, synthesizing
- serial: Implement a driver
- string: Use cmp/str to implement memchr() (assembler examples)
- string: Do some tests for memcmp() and memcpy()
- usb: Implement a driver
Things to investigate:
- Packed bit fields alignment
- Registers that may need to be saved within setjmp()
- Registers that may need to be saved and restored by gint
- Optimizing core/gint.c leads to raising of an illegal slot exception when
running the interrupt handler, although it ends on rte; lds.l @r15+, mach,
which is totally not an illegal slot.
- Check version registers on SH7705

View file

@ -345,8 +345,8 @@ void main_menu(int *category, int *app)
switch(tab)
{
case 0:
locate(1, 1, "Demo application");
print(2, 3, "gint version: %5s", GINT_VERSION_STR);
print(1, 1, "Demo application");
// print(2, 3, "gint version: %5s", GINT_VERSION_STR);
print(2, 4, "handler size: %5d", gint_size);
print(2, 5, "mpu type: %7s", mpu);
print(2, 6, "romdata: %08x", &romdata);

View file

@ -95,14 +95,10 @@ static image_t *select(image_t *current)
8 * i, 7, 7);
if(i == row)
{
print(2, 2 + i + 1, "%08x", (unsigned int)
images[i].img);
/*
int width, height;
getwh(images[i].img, &width, &height);
print(2, 2 + i + 1, "%d\x04%d", width, height);
locate(10, 2 + i + 1, images[i].info);
*/
}
}
@ -147,7 +143,7 @@ void test_bopti(void)
while(1)
{
if(img && (img->format & Channel_Light))
if(img && (img->format & channel_light))
{
gray_start();
gclear();

View file

@ -14,9 +14,10 @@
*/
#include <internals/rtc.h>
#include <modules/rtc.h>
#include <mpu.h>
static void draw(rtc_time_t time)
static void draw(rtc_time_t *time)
{
extern image_t res_rtc_segments;
@ -30,12 +31,12 @@ static void draw(rtc_time_t time)
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;
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,
@ -46,17 +47,18 @@ static void draw(rtc_time_t time)
// 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);
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_t res_opt_rtc;
rtc_time_t time = rtc_getTime();
rtc_time_t time;
rtc_getTime(&time);
dclear();
draw(time);
draw(&time);
dimage_part(0, 56, &res_opt_rtc, 0, 0, 19, 8);
dupdate();
}
@ -128,14 +130,16 @@ static void set(void)
{ 72, 39, 7, 9 }, { 84, 39, 7, 9 }, { 90, 39, 7, 9 },
{ 96, 39, 7, 9 }, { 102, 39, 7, 9 },
};
rtc_time_t time = rtc_getTime();
rtc_time_t time;
int region_count = 14;
int n = 0, slide = 0, key, leave;
rtc_getTime(&time);
while(1)
{
dclear();
draw(time);
draw(&time);
drect(regions[n].x, regions[n].y, regions[n].x + regions[n].w
- 1, regions[n].y + regions[n].h - 1, color_invert);
@ -157,7 +161,7 @@ static void set(void)
slide = 0;
if(++n == region_count)
{
rtc_setTime(time);
rtc_setTime(&time);
return;
}
}
@ -216,7 +220,7 @@ static void set(void)
n++;
if(n == region_count)
{
rtc_setTime(time);
rtc_setTime(&time);
return;
}
slide = 0;
@ -235,7 +239,7 @@ void test_rtc(void)
{
int key, cb_id;
cb_id = rtc_cb_add(RTCFreq_1Hz, callback, 0);
cb_id = rtc_cb_add(rtc_freq_1Hz, callback, 0);
callback();
while(1)
@ -245,10 +249,10 @@ void test_rtc(void)
if(key == KEY_EXIT) break;
if(key == KEY_F1)
{
rtc_cb_edit(cb_id, RTCFreq_None, NULL);
rtc_cb_edit(cb_id, rtc_freq_none, NULL);
set();
callback();
rtc_cb_edit(cb_id, RTCFreq_1Hz, callback);
rtc_cb_edit(cb_id, rtc_freq_1Hz, callback);
}
}

View file

@ -41,7 +41,7 @@ static void timing_start(void)
timer_attach(htimer, timing_timer, NULL);
timer_start(htimer);
rtc_cb_edit(cb_id, RTCFreq_64Hz, timing_rtc);
rtc_cb_edit(cb_id, rtc_freq_64Hz, timing_rtc);
elapsed_timer = 0;
elapsed_rtc = 0;
@ -247,7 +247,7 @@ void test_timer(void)
elapsed_timer = -1;
elapsed_rtc = -1;
cb_id = rtc_cb_add(RTCFreq_64Hz, timing_start, 0);
cb_id = rtc_cb_add(rtc_freq_64Hz, timing_start, 0);
text_configure(NULL, color_black);

View file

@ -46,8 +46,11 @@ void dimage(int x, int y, image_t *image);
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void dimage_part(int x, int y, image_t *img, int left, int top, int width,
int height);
void dimage_part(
int x, int y,
image_t *img,
int left, int top, int width, int height
);
/*
gimage()
@ -61,7 +64,10 @@ void gimage(int x, int y, image_t *image);
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void gimage_part(int x, int y, image_t *image, int left, int top, int width,
int height);
void gimage_part(
int x, int y,
image_t *image,
int left, int top, int width, int height
);
#endif // _BOPTI_H

View file

@ -15,9 +15,6 @@
#include <stdint.h>
#include <stddef.h>
#define GINT_VERSION 0x000100a3
#define GINT_VERSION_STR "00.01"
//---
// System info provided by the library
//---

View file

@ -1,19 +1,3 @@
//---
//
// gint drawing module: bopti
//
// bopti does every job related to display images. There is only one
// public function, but there are lots of internal optimizations.
//
// Some bit-manipulation expressions may look written out of nowhere. The
// idea is always the same: get a part of the image in an 'operator',
// which is a 32-bit variable, shift this operator so that its bits
// correspond to the desired position for the bitmap on the screen, and
// edit the video-ram long entry which correspond to this position using
// a 'mask' that indicates which bits of the operator contain information.
//
//---
#ifndef _INTERNALS_BOPTI_H
#define _INTERNALS_BOPTI_H
@ -21,40 +5,45 @@
#include <display.h>
/*
enum Channel
Determines the kind of information written into a layer. Every image is
made of one or more channels.
channel_t
Indicates what operation a layer is made for. Each operation affects
the video ram differently (setting or clearing pixels, transparency,
etc). An image is made of several layers.
*/
enum Channel
typedef enum
{
Channel_FullAlpha = 0x01,
Channel_LightAlpha = 0x02,
Channel_DarkAlpha = 0x04,
channel_full_alpha = 0x01,
channel_light_alpha = 0x02,
channel_dark_alpha = 0x04,
Channel_Mono = 0x08,
Channel_Light = 0x10,
Channel_Dark = 0x20,
};
channel_mono = 0x08,
channel_light = 0x10,
channel_dark = 0x20,
} channel_t;
/*
enum Format
Describes the various combination of channels allowed by bopti.
format_t
Describes the various combination of layer channels that are allowed by
bopti. Technically one could try other formats but they're not of much
use (transparent gray is even totally useless).
*/
enum Format
typedef enum
{
Format_Mono = Channel_Mono,
Format_MonoAlpha = Format_Mono | Channel_FullAlpha,
Format_Gray = Channel_Light | Channel_Dark,
Format_GrayAlpha = Format_Gray | Channel_FullAlpha,
Format_GreaterAlpha = Format_Mono | Channel_LightAlpha |
Channel_DarkAlpha
};
format_mono = channel_mono,
format_mono_alpha = format_mono | channel_full_alpha,
format_gray = channel_light | channel_dark,
format_gray_alpha = format_gray | channel_full_alpha,
format_greater_alpha = format_mono | channel_light_alpha |
channel_dark_alpha
} format_t;
/*
struct Structure
Describes an image's structure.
structure_t
Basically an image's dimensions, data pointer, and a few other useful
information such as the pitch in bytes.
*/
struct Structure
typedef struct
{
int width, height;
int layer_size;
@ -62,26 +51,37 @@ struct Structure
const uint8_t *data;
int columns;
int end_size, end_bytes;
};
} structure_t;
/*
struct Command
Contains a drawing operation's parameters.
command_t
The parameters of a drawing operation. A pointer to such a structure is
created by the public functions and passed down to the module's
sub-functions during rendering.
*/
struct Command
typedef struct command_t
{
// Channel being drawn.
enum Channel channel;
channel_t channel;
// Operation used (whether bopti_op_mono() or bopti_op_gray()).
void (*op)(int offset, uint32_t operator, struct Command *command);
void (*op)(int offset, uint32_t operator, struct command_t *command);
// Portion of the bitmap which is drawn. 'top' and 'bottom' refer to
// lines where 'left' and 'right' refer to column ids.
int left, right, top, bottom;
// Position of the bitmap on the screen.
int x, y;
// Rectangle masks.
// Rectangle masks that define the drawing area.
uint32_t masks[4];
};
// Video rams being used.
union {
// Different names, same fate. (Kingdom Hearts II)
uint32_t *vram;
uint32_t *v1;
};
uint32_t *v2;
} command_t;
// The video ram addresses are set by the public functions and used internally
// by the module.
@ -91,7 +91,7 @@ extern uint32_t *bopti_vram, *bopti_v1, *bopti_v2;
//---
// Some bopti routines.
// Internal bopti routines.
//---
/*
@ -100,11 +100,12 @@ extern uint32_t *bopti_vram, *bopti_v1, *bopti_v2;
image information. Since neutral bits are not the same for all
operations, a mask is used to indicate which bits should be used for
the operation. This mask is taken for the image's rectangle masks (see
module display for more information on rectangle masks).
Which operation is performed is determined by the channel setting.
the 'display' module internal header for more information on rectangle
masks). Which operation is performed is determined by the channel
setting of the command argument.
*/
void bopti_op_mono(int offset, uint32_t operator, struct Command *c);
void bopti_op_gray(int offset, uint32_t operator, struct Command *c);
void bopti_op_mono(int offset, uint32_t operator, command_t *c);
void bopti_op_gray(int offset, uint32_t operator, command_t *c);
/*
bopti_grid() -- general form
@ -115,12 +116,11 @@ void bopti_op_gray(int offset, uint32_t operator, struct Command *c);
The need for bopti_grid_a32() is not only linked to optimization,
because bopti_grid() will perform a 32-bit shift when x is a multiple
of 32, which is undefined behavior.
bopti_grid() calls bopti_grid_32() by default.
bopti_grid() automatically calls bopti_grid_a32() when required.
*/
void bopti_grid_a32(const uint32_t *layer, int columns, int height,
struct Command *c);
void bopti_grid(const uint32_t *layer, int columns, int height,
struct Command *c);
command_t *c);
void bopti_grid(const uint32_t *layer, int columns, int height, command_t *c);
/*
bopti_end_get()
Returns an operator for the end of a line, whose width is lower than 32
@ -138,23 +138,25 @@ uint32_t bopti_end_get2(const unsigned char **data);
Draws the end of a layer, which can be considered as a whole layer
whose with is lower than 32. (Actually is it lower or equal to 16;
otherwise it would have been a column and the end would be empty). The
'size' arguments is in bytes.
'size' arguments is in bytes, thus 1 or 2.
Unlike bopti_grid_a32(), bopti_end_nover() is not called automatically
by bopti_end().
*/
void bopti_end_nover(const unsigned char *end, int size, struct Command *c);
void bopti_end(const unsigned char *end, int size, struct Command *c);
void bopti_end_nover(const unsigned char *end, int size, command_t *c);
void bopti_end(const unsigned char *end, int size, command_t *c);
/*
bopti()
Draws a layer in the video ram.
Draws a layer's data in the video ram areas specified in the command
argument.
*/
void bopti(const unsigned char *layer, struct Structure *s, struct Command *c);
void bopti(const unsigned char *layer, structure_t *s, command_t *c);
/*
getStructure()
Determines the image size and data pointer.
Determines the image size (large images have a somehow different
structure), the data pointer and a few dimensions inside the image.
*/
void getStructure(image_t *img, struct Structure *structure);
void getStructure(image_t *img, structure_t *structure);
#endif // _INTERNALS_BOPTI_H

View file

@ -37,7 +37,7 @@ void gint_setvbr(uint32_t vbr, void (*setup)(void));
//---
// Initialization and termination routines.
// Initialization and termination routines, environment saves.
//---
/*
@ -53,29 +53,80 @@ void gint_init(void);
*/
void gint_quit(void);
#include <modules/rtc.h>
#include <modules/timer.h>
/*
environment_t
Structure where all registers used by gint are saved by default to
ensure that the operating system is not disturbed.
*/
typedef struct
{
// Interrupt controller.
uint16_t IPR[8];
// Real-Time Clock.
uint8_t RCR1, RCR2;
// Timer Unit.
mod_tmu_timer_t TMU0, TMU1, TMU2;
uint8_t TSTR;
// I/O ports for the keyboard driver.
uint16_t PACR, PBCR, PMCR;
uint8_t PADR, PBDR, PMDR;
} environment_7705_t;
typedef struct
{
// Interrupt controller.
uint16_t IPR[12];
// Real-Time Clock.
uint8_t RCR1, RCR2;
// Timer Unit.
mod_tmu_timer_t TMU0, TMU1, TMU2;
uint8_t TSTR;
// I/O ports for the keyboard driver.
uint16_t PMCR, PNCR, PZCR;
uint8_t PMDR, PNDR, PZDR;
uint8_t key;
} environment_7305_t;
typedef union
{
environment_7705_t env_7705;
environment_7305_t env_7305;
} environment_t;
/*
gint_save()
Saves many registers into a buffer to ensure that the system is not
upset by gint's configuration when the application ends.
Saves many registers into an internal environment buffer.
*/
// void gint_save_7705(gint_save_buffer_t *buffer);
// void gint_save_7305(gint_save_buffer_t *buffer);
void gint_save_7705(environment_7705_t *env);
void gint_save_7305(environment_7305_t *env);
/*
gint_setup()
Configures interrupt priorities and some parameters to allow gint to
take control of the interrupt flow.
gint_lock_and_setup()
Locks all interrupts (ie. disables them by default) and sets initial
values to all registers, allows specific interrupts, etc.
*/
void gint_setup_7705(void);
void gint_setup_7305(void);
void gint_lock_and_setup_7705(void);
void gint_lock_and_setup_7305(void);
/*
gint_restore()
Restores the parameters saved in a save buffer to give back the
interrupt control to the system.
gint_restore_and_unlock()
Restores the parameters saved in the environment buffer to give back
the interrupt control to the system.
*/
// void gint_restore_7705(gint_save_buffer_t *buffer);
// void gint_restore_7305(gint_save_buffer_t *buffer);
void gint_restore_and_unlock_7705(environment_7705_t *env);
void gint_restore_and_unlock_7305(environment_7305_t *env);
/*
gint_reg()

View file

@ -5,11 +5,12 @@
#include <timer.h>
#include <clock.h>
// Keyboard variables.
// Current keyboard state and keyboard interrupt flag.
extern volatile uint8_t keyboard_state[10];
extern volatile int interrupt_flag;
// Key statistics.
// Delays (milliseconds) before repetitions, last key pressed, how many times
// it has been repeated already, time elapsed since last repetition (ms).
extern int repeat_first, repeat_next;
extern int last_key, last_repeats, last_time;

View file

@ -3,8 +3,8 @@
// gint core module: mmu
//
// A wise application should avoid tampering with the system's
// configuration of the MMU and the TLB. This module implicitly calls the
// system but does nothing by itself.
// configuration of the MMU and the TLB. This module implicitly forces the
// system to load the required pages but does not interact with the TLB.
//
//---

View file

@ -9,20 +9,21 @@
#endif
/*
struct rtc_cb
An RTC callback.
rtc_callback_t
An RTC callback with a unique id.
*/
struct rtc_cb
typedef struct
{
rtc_frequency_t freq;
int id;
void (*callback)(void);
int repeats;
};
} rtc_callback_t;
// The callback array.
struct rtc_cb cb_array[RTC_CB_ARRAY_SIZE];
rtc_callback_t cb_array[RTC_CB_ARRAY_SIZE];
/*
rtc_perodic_interrupt()
@ -37,118 +38,4 @@ void rtc_periodic_interrupt(void);
*/
void rtc_cb_interrupt(void);
/*
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

@ -3,6 +3,15 @@
#include <stdint.h>
// Padding is just empty space, we don't want to give it a name. There's also
// some subtle preprocessor trick to automatically add a (supposedly) unique
// name to each padding member. For instance the substitution may operate as:
// name(__LINE__) -> namesub(78) -> _##78 -> _78
#define namesub(x) _##x
#define name(x) namesub(x)
#define pad(bytes) \
uint8_t name(__LINE__)[bytes] \
// Fixed-width types for bit field are totally meaningless.
typedef unsigned uint;

131
include/modules/rtc.h Normal file
View file

@ -0,0 +1,131 @@
#ifndef _MODULES_RTC_H
#define _MODULES_RTC_H
#include <modules/macros.h>
#include <stdint.h>
/*
mod_rtc_rcr1_t
First RTC configuration register.
*/
typedef struct
{
byte_union(,
uint CF :1; /* Carry flag */
uint :2;
uint CIE :1; /* Carry interrupt enable */
uint AIE :1; /* Alarm interrupt enable */
uint :2;
uint AF :1; /* Alarm flag */
);
} __attribute__((packed)) mod_rtc_rcr1_t;
/*
mod_rtc_rcr2_t
Second RTC configuration register.
*/
typedef struct
{
byte_union(,
uint PEF :1; /* Periodic interrupt flag */
uint PES :3; /* Periodic interrupt interval */
uint :1;
uint ADJ :1; /* 30-second adjustment */
uint RESET :1; /* Reset */
uint START :1; /* Start bit */
);
} __attribute__((packed)) mod_rtc_rcr2_t;
/*
mod_rtc_rcr3_t
Third RTC configuration register.
typedef struct
{
byte_union(,
uint YAEN :1;
uint :7;
);
} __attribute__((packed)) mod_rtc_rcr3_t;
*/
/*
mod_rtc_time_t
A set of registers describing the current time in BCD format.
*/
typedef struct
{
const uint8_t R64CNT; /* More or less a 64-Hz counter */
pad(1);
byte_union(RSECCNT, /* Second count */
uint :1;
uint TENS :3;
uint ONES :4;
);
pad(1);
byte_union(RMINCNT, /* Minute count */
uint :1;
uint TENS :3;
uint ONES :4;
);
pad(1);
byte_union(RHRCNT, /* Hour count */
uint :2;
uint TENS :2;
uint ONES :4;
);
pad(1);
/* 0 = Sunday .. 6 = Saturday, other settings are prohibited. */
uint8_t RWKCNT; /* Day of week */
pad(1);
byte_union(RDAYCNT, /* Day count */
uint :2;
uint TENS :2;
uint ONES :4;
);
pad(1);
byte_union(RMONCNT, /* Month count */
uint :3;
uint TENS :1;
uint ONES :4;
);
pad(1);
word_union(RYRCNT, /* Year count */
uint THOUSANDS :4;
uint HUNDREDS :4;
uint TENS :4;
uint ONES :4;
);
} __attribute__((packed, aligned(2))) mod_rtc_time_t;
/*
mod_rtc_t (resides into gint memory)
Three control registers and timer information.
*/
typedef struct
{
/* RCR1, RCR2, and RCR3 are the same for both platforms. */
volatile mod_rtc_rcr1_t *RCR1;
volatile mod_rtc_rcr2_t *RCR2;
// volatile mod_rtc_rcr3_t *RCR3;
/* Current time in register memory */
volatile mod_rtc_time_t *time;
} mod_rtc_t;
// All you need to use is this structure, initialized by gint, which contains
// address that work with your execution platform.
extern mod_rtc_t RTC;
#endif // _INTERNALS_RTC_H

View file

@ -59,6 +59,6 @@ typedef struct
// The actual thing is there. It's initialized by gint at startup and contains
// addresses and information suitable for the current platform.
extern volatile mod_tmu_t TMU;
extern mod_tmu_t TMU;
#endif // _MODULES_TIMER

View file

@ -49,7 +49,7 @@ typedef enum
// Global MPU variable, accessible for direct tests. Initialized at the
// beginning of execution.
extern mpu_t MPU_CURRENT;
extern const mpu_t MPU_CURRENT;
// Quick SH3 test. It is safer to assume that an unknown model is SH4 because
// SH3-based models are not produced anymore.

View file

@ -2,7 +2,10 @@
//
// gint core module: rtc
//
// Manages RTC. This module is used behind standard module time.
// Manages the Real-Time Clock (RTC). This module provides access to the
// current time as well as regular callbacks at predefined frequencies,
// more or less like a timer.
// The standard time module is built upon this one.
//
//---
@ -36,14 +39,14 @@ typedef struct
Reads the current time from the RTC. There is no guarantee that the
week day is correct (use the time API for that).
*/
rtc_time_t rtc_getTime(void);
void rtc_getTime(rtc_time_t *time);
/*
rtc_setTime()
Sets the time in the RTC registers. The week day is set to 0 if greater
than 6. Other fields are not checked.
*/
void rtc_setTime(rtc_time_t time);
void rtc_setTime(const rtc_time_t *time);
@ -58,14 +61,14 @@ void rtc_setTime(rtc_time_t time);
*/
typedef enum
{
RTCFreq_500mHz = 7,
RTCFreq_1Hz = 6,
RTCFreq_2Hz = 5,
RTCFreq_4Hz = 4,
RTCFreq_16Hz = 3,
RTCFreq_64Hz = 2,
RTCFreq_256Hz = 1,
RTCFreq_None = 0,
rtc_freq_500mHz = 7,
rtc_freq_1Hz = 6,
rtc_freq_2Hz = 5,
rtc_freq_4Hz = 4,
rtc_freq_16Hz = 3,
rtc_freq_64Hz = 2,
rtc_freq_256Hz = 1,
rtc_freq_none = 0,
} rtc_frequency_t;
@ -94,7 +97,7 @@ void rtc_cb_end(int id);
-1 Callback does not exist
-2 Invalid parameters
This function never removes a callback. Call rtc_cb_end() for this. One
can set the function to NULL or the frequency to RTCFreq_None to
can set the function to NULL or the frequency to rtc_freq_none to
temporarily disable the callback.
*/
int rtc_cb_edit(int id, rtc_frequency_t new_freq, void (*new_function)(void));

View file

@ -12,17 +12,17 @@ uint32_t *bopti_vram, *bopti_v1, *bopti_v2;
module display for more information on rectangle masks).
Which operation is performed is determined by the channel setting.
*/
void bopti_op_mono(int offset, uint32_t operator, struct Command *c)
void bopti_op_mono(int offset, uint32_t operator, command_t *c)
{
operator &= c->masks[offset & 3];
switch(c->channel)
{
case Channel_FullAlpha:
case channel_full_alpha:
bopti_vram[offset] &= ~operator;
break;
case Channel_Mono:
case channel_mono:
bopti_vram[offset] |= operator;
break;
@ -30,31 +30,31 @@ void bopti_op_mono(int offset, uint32_t operator, struct Command *c)
break;
}
}
void bopti_op_gray(int offset, uint32_t operator, struct Command *c)
void bopti_op_gray(int offset, uint32_t operator, command_t *c)
{
operator &= c->masks[offset & 3];
switch(c->channel)
{
case Channel_FullAlpha:
case channel_full_alpha:
bopti_v1[offset] &= ~operator;
bopti_v2[offset] &= ~operator;
break;
case Channel_LightAlpha:
case Channel_DarkAlpha:
case channel_light_alpha:
case channel_dark_alpha:
break;
case Channel_Mono:
case channel_mono:
bopti_v1[offset] |= operator;
bopti_v2[offset] |= operator;
break;
case Channel_Light:
case channel_light:
bopti_v1[offset] |= operator;
break;
case Channel_Dark:
case channel_dark:
bopti_v2[offset] |= operator;
break;
}
@ -71,7 +71,7 @@ void bopti_op_gray(int offset, uint32_t operator, struct Command *c)
of 32, which is undefined behavior.
*/
void bopti_grid_a32(const uint32_t *layer, int column_count, int height,
struct Command *c)
command_t *c)
{
int vram_column_offset = (c->y << 2) + (c->x >> 5);
int vram_offset = vram_column_offset;
@ -91,7 +91,7 @@ void bopti_grid_a32(const uint32_t *layer, int column_count, int height,
}
}
void bopti_grid(const uint32_t *layer, int column_count, int height,
struct Command *c)
command_t *c)
{
if(!column_count) return;
if(!(c->x & 31))
@ -177,9 +177,9 @@ uint32_t bopti_end_get2(const unsigned char **data)
Draws the end of a layer, which can be considered as a whole layer
whose with is lower than 32. (Actually is it lower or equal to 16;
otherwise it would have been a column and the end would be empty).
otherwise it would have been a column and the end would be empty.)
*/
void bopti_end_nover(const unsigned char *end, int size, struct Command *c)
void bopti_end_nover(const unsigned char *end, int size, command_t *c)
{
uint32_t (*get)(const unsigned char **data) =
(size == 2) ? bopti_end_get2 : bopti_end_get1;
@ -199,19 +199,17 @@ void bopti_end_nover(const unsigned char *end, int size, struct Command *c)
{
operator = (*get)(&end);
operator <<= shift;
(c->op)(vram_offset, operator, c);
(c->op)(vram_offset, operator, c);
vram_offset += 4;
}
}
void bopti_end(const unsigned char *end, int size, struct Command *c)
void bopti_end(const unsigned char *end, int size, command_t *c)
{
uint32_t (*get)(const unsigned char **data) =
(size == 2) ? (bopti_end_get2) : (bopti_end_get1);
int vram_offset = (c->y << 2) + (c->x >> 5);
uint32_t row_data, operator;
uint32_t row_data;
int row;
int shift_base = (32 - (size << 3));
@ -225,15 +223,8 @@ void bopti_end(const unsigned char *end, int size, struct Command *c)
for(row = c->top; row < c->bottom; row++)
{
row_data = (*get)(&end);
operator = row_data >> shift1;
(c->op)(vram_offset, operator, c);
operator = row_data << shift2;
(c->op)(vram_offset + 1, operator, c);
(c->op)(vram_offset, row_data >> shift1, c);
(c->op)(vram_offset + 1, row_data << shift2, c);
vram_offset += 4;
}
}
@ -248,7 +239,7 @@ void bopti_end(const unsigned char *end, int size, struct Command *c)
bopti()
Draws a layer in the video ram.
*/
void bopti(const unsigned char *layer, struct Structure *s, struct Command *c)
void bopti(const unsigned char *layer, structure_t *s, command_t *c)
{
const unsigned char *grid, *end;
int grid_columns, has_end;
@ -283,9 +274,10 @@ void bopti(const unsigned char *layer, struct Structure *s, struct Command *c)
/*
getStructure()
Determines the image size and data pointer.
Determines the image size (large images have a somehow different
structure), the data pointer and a few dimensions inside the image.
*/
void getStructure(image_t *img, struct Structure *s)
void getStructure(image_t *img, structure_t *s)
{
int column_count, end, end_bytes, layer;

View file

@ -12,12 +12,12 @@ void dimage_part(int x, int y, image_t *img, int left, int top, int width,
{
if(!img || img->magic != 0x01) return;
struct Structure s;
struct Command command;
structure_t s;
command_t command;
int actual_width;
int format = img->format, i = 0;
if(format != Format_Mono && format != Format_MonoAlpha) return;
if(format != format_mono && format != format_mono_alpha) return;
getStructure(img, &s);
if(width < 0) width = s.width;
if(height < 0) height = s.height;

View file

@ -13,8 +13,8 @@ void gimage_part(int x, int y, image_t *img, int left, int top, int width,
{
if(!img || img->magic != 0x01) return;
struct Structure s;
struct Command command;
structure_t s;
command_t command;
int actual_width;
int format = img->format, i = 0;

View file

@ -143,7 +143,7 @@ void clock_measure(void)
{
htimer_7705 = htimer_setup(timer_user, 0xffffffff, timer_Po_4,
1);
cb_id_7705 = rtc_cb_add(RTCFreq_256Hz, clock_measure_7705, 0);
cb_id_7705 = rtc_cb_add(rtc_freq_256Hz, clock_measure_7705, 0);
}
// On SH7305, assuming clock mode 3, we can compute the clock
@ -268,5 +268,5 @@ static void clock_measure_7705_callback(void)
static void clock_measure_7705(void)
{
timer_start(htimer_7705);
rtc_cb_edit(cb_id_7705, RTCFreq_256Hz, clock_measure_7705_callback);
rtc_cb_edit(cb_id_7705, rtc_freq_256Hz, clock_measure_7705_callback);
}

View file

@ -20,7 +20,7 @@ extern uint32_t
etext, btext, // Location of .text section
bdata, edata, // Location of .data section
bbss, ebss, // Location of .bss section
bgint, egint, // Location of interrut handler and gint data
bgint, egint, // Location of interrupt handler and gint data
gint_vbr, // VBR address
romdata; // ROM address of .data section contents
@ -45,7 +45,7 @@ __attribute__((section(".pretext.entry"))) int start(void)
{
#ifdef GINT_DIAGNOSTICS
// Ok, so fill as much information as possible so that in case anything
// OK, so fill as much information as possible so that in case anything
// goes wrong we can try to analyze what's been going on.
volatile gint_diagnostics_t *dg = gint_diagnostics();
@ -77,7 +77,7 @@ __attribute__((section(".pretext.entry"))) int start(void)
dg->section_data.length = (uint32_t)&edata - (uint32_t)&bdata;
dg->section_bss.address = (uint32_t)&bbss;
dg->section_bss.length = (uint32_t)&ebss - (uint32_t)&bbss;
dg->romdata = (uint32_t)&romdata;
dg->romdata = (uint32_t)&romdata;
// Basic information about the running library.
dg->vbr_address = (uint32_t)&gint_vbr;
@ -108,10 +108,11 @@ __attribute__((section(".pretext.entry"))) int start(void)
dg->stage = stage_mmu;
#endif
// Detecting the MPU type, initializing the register module addresses,
// and initializing gint.
mpu_init();
mod_init();
// Initializing gint, which does several things:
// - Detect the MPU and platform
// - Initialize register addresses in a platform-independent way
// - Save the current environment information in a large buffer
// - Set up the interrupt handler and configure everything gint needs
gint_init();
#ifdef GINT_DIAGNOSTICS
@ -148,16 +149,15 @@ __attribute__((section(".pretext.entry"))) int start(void)
if(!x) exit_code = main();
#ifdef GINT_DIAGNOSTICS
dg->stage = stage_leaving;
#endif
/* TODO Flush and close opened streams. */
// Calling exit handlers.
// Calling exit handlers and destructors.
while(atexit_index > 0) (*atexit_handlers[--atexit_index])();
// Calling the destructors.
fini();
#ifdef GINT_DIAGNOSTICS

View file

@ -33,8 +33,8 @@ static void show_error(const char *name, uint32_t *access_mode, uint32_t *tea,
{
uint32_t *vram = display_getCurrentVRAM();
uint32_t spc, ssr;
__asm__("stc spc, %0" : "=rm"(spc));
__asm__("stc ssr, %0" : "=rm"(ssr));
__asm__("stc spc, %0" : "=r"(spc));
__asm__("stc ssr, %0" : "=r"(ssr));
dclear();
text_configure(NULL, color_black);

View file

@ -1,12 +1,3 @@
//---
//
// gint core module: interrupt handler
//
// Central point of the library. Controls the interrupt handler and
// defines a few functions to configure callbacks for some interrupts.
//
//---
#include <internals/gint.h>
#include <internals/interrupt_maps.h>
#include <internals/exceptions.h>
@ -110,10 +101,10 @@ void gint_invoke(uint8_t type, uint8_t subtype)
uint16_t *pc;
// Getting some initial information to work with.
__asm__("stc spc, %0" : "=rm"(pc));
__asm__("stc spc, %0" : "=r"(pc));
tea = gint_reg(register_tea);
tra = gint_reg(register_tra);
tcpr_2 = (void *)0xfffffeb8;
tcpr_2 = (void *)0xfffffeb8; /* SH7705 only */
// Building up the argument list.
for(int i = 0; i < 3; i++) switch(gint_handlers[type].args[i])

View file

@ -1,15 +1,6 @@
//---
//
// gint core module: sh7305 interrupt handler
//
// Of course all the work related to interrupts is heavily platform-
// dependent. This module handles interrupts and configures the MPU to
// save and restore the system's configuration when execution ends.
//
//---
#include <internals/gint.h>
#include <internals/rtc.h>
#include <modules/timer.h>
#include <modules/rtc.h>
#include <gint.h>
#include <timer.h>
#include <7305.h>
@ -38,108 +29,108 @@ volatile void *gint_reg_7305(gint_register_t reg)
//---
// Setup.
// Register saves, setup, interrupt locks, register restoration.
//---
static unsigned short ipr[12];
static unsigned char rcr2;
// Saves of the keyboard registers. Could be better.
static unsigned short inj1, inj2, det;
static unsigned char data1, data2, keys, reg;
static void gint_priority_lock_7305(void)
void gint_save_7305(environment_7305_t *e)
{
// Saving the current interrupt priorities.
ipr[0] = INTX.IPRA.WORD;
ipr[1] = INTX.IPRB.WORD;
ipr[2] = INTX.IPRC.WORD;
ipr[3] = INTX.IPRD.WORD;
ipr[4] = INTX.IPRE.WORD;
ipr[5] = INTX.IPRF.WORD;
ipr[6] = INTX.IPRG.WORD;
ipr[7] = INTX.IPRH.WORD;
ipr[8] = INTX.IPRI.WORD;
ipr[9] = INTX.IPRJ.WORD;
ipr[10] = INTX.IPRK.WORD;
ipr[11] = INTX.IPRL.WORD;
// Saving interrupt priorities.
e->IPR[0] = INTX.IPRA.WORD;
e->IPR[1] = INTX.IPRB.WORD;
e->IPR[2] = INTX.IPRC.WORD;
e->IPR[3] = INTX.IPRD.WORD;
e->IPR[4] = INTX.IPRE.WORD;
e->IPR[5] = INTX.IPRF.WORD;
e->IPR[6] = INTX.IPRG.WORD;
e->IPR[7] = INTX.IPRH.WORD;
e->IPR[8] = INTX.IPRI.WORD;
e->IPR[9] = INTX.IPRJ.WORD;
e->IPR[10] = INTX.IPRK.WORD;
e->IPR[11] = INTX.IPRL.WORD;
// Saving RTC registers.
e->RCR1 = RTC.RCR1->byte;
e->RCR2 = RTC.RCR2->byte;
// Saving TMU registers.
e->TMU0 = *(TMU.timers[0]);
e->TMU1 = *(TMU.timers[1]);
e->TMU2 = *(TMU.timers[2]);
e->TSTR = TMU.TSTR->byte;
// Saving port data used to access the keyboard.
e->PMCR = *((volatile uint16_t *)0xa4050116);
e->PMDR = *((volatile uint8_t *)0xa4050136);
e->PNCR = *((volatile uint16_t *)0xa4050118);
e->PNDR = *((volatile uint8_t *)0xa4050138);
e->PZCR = *((volatile uint16_t *)0xa405014c);
e->PZDR = *((volatile uint8_t *)0xa405016c);
e->key = *((volatile uint8_t *)0xa40501c6);
}
void gint_lock_and_setup_7305(void)
{
// Disabling everything by default to avoid freezing on non-handled
// interrupts.
INTX.IPRA.WORD = 0x0000;
INTX.IPRB.WORD = 0x0000;
INTX.IPRC.WORD = 0x0000;
INTX.IPRD.WORD = 0x0000;
INTX.IPRE.WORD = 0x0000;
INTX.IPRF.WORD = 0x0000;
INTX.IPRG.WORD = 0x0000;
INTX.IPRH.WORD = 0x0000;
INTX.IPRI.WORD = 0x0000;
INTX.IPRJ.WORD = 0x0000;
INTX.IPRK.WORD = 0x0000;
INTX.IPRL.WORD = 0x0000;
INTX.IPRA.WORD = 0x0000;
INTX.IPRB.WORD = 0x0000;
INTX.IPRC.WORD = 0x0000;
INTX.IPRD.WORD = 0x0000;
INTX.IPRE.WORD = 0x0000;
INTX.IPRF.WORD = 0x0000;
INTX.IPRG.WORD = 0x0000;
INTX.IPRH.WORD = 0x0000;
INTX.IPRI.WORD = 0x0000;
INTX.IPRJ.WORD = 0x0000;
INTX.IPRK.WORD = 0x0000;
INTX.IPRL.WORD = 0x0000;
// Saving keyboard registers.
inj1 = *((volatile unsigned short *)0xa4050116);
data1 = *((volatile unsigned char *)0xa4050136);
inj2 = *((volatile unsigned short *)0xa4050118);
data2 = *((volatile unsigned char *)0xa4050138);
det = *((volatile unsigned short *)0xa405014c);
keys = *((volatile unsigned char *)0xa405016c);
reg = *((volatile unsigned char *)0xa40501c6);
// Allowing RTC. Keyboard analysis is done regularly using a RTC
// because SH7305's special KEYSC interface does not allow us to clear
// the keyboard interrupt flags.
// Allowing RTC and timer to schedule automatic tasks such as keyboard
// analysis.
INTX.IPRK._RTC = 10;
INTX.IPRA.TMU0_0 = 12;
INTX.IPRA.TMU0_1 = 12;
INTX.IPRA.TMU0_2 = 12;
// Don't enable the RTC interrupt by default.
RTC.RCR2->byte = 0x09;
}
static void gint_priority_unlock_7305(void)
void gint_restore_and_unlock_7305(environment_7305_t *e)
{
// Restoring the interrupt priorities.
INTX.IPRA.WORD = ipr[0];
INTX.IPRB.WORD = ipr[1];
INTX.IPRC.WORD = ipr[2];
INTX.IPRD.WORD = ipr[3];
INTX.IPRE.WORD = ipr[4];
INTX.IPRF.WORD = ipr[5];
INTX.IPRG.WORD = ipr[6];
INTX.IPRH.WORD = ipr[7];
INTX.IPRI.WORD = ipr[8];
INTX.IPRJ.WORD = ipr[9];
INTX.IPRK.WORD = ipr[10];
INTX.IPRL.WORD = ipr[11];
INTX.IPRA.WORD = e->IPR[0];
INTX.IPRB.WORD = e->IPR[1];
INTX.IPRC.WORD = e->IPR[2];
INTX.IPRD.WORD = e->IPR[3];
INTX.IPRE.WORD = e->IPR[4];
INTX.IPRF.WORD = e->IPR[5];
INTX.IPRG.WORD = e->IPR[6];
INTX.IPRH.WORD = e->IPR[7];
INTX.IPRI.WORD = e->IPR[8];
INTX.IPRJ.WORD = e->IPR[9];
INTX.IPRK.WORD = e->IPR[10];
INTX.IPRL.WORD = e->IPR[11];
// Restoring keyboard registers.
*((volatile unsigned short *)0xa4050116) = inj1;
*((volatile unsigned char *)0xa4050136) = data1;
*((volatile unsigned short *)0xa4050118) = inj2;
*((volatile unsigned char *)0xa4050138) = data2;
*((volatile unsigned short *)0xa405014c) = det;
*((volatile unsigned char *)0xa405016c) = keys;
*((volatile unsigned char *)0xa40501c6) = reg;
}
void gint_setup_7305(void)
{
volatile struct mod_rtc *RTC = RTC_SH7305;
gint_priority_lock_7305();
// Saving the RTC configuration.
rcr2 = RTC->RCR2.BYTE;
// Disabling RTC interrupts by default.
RTC->RCR2.BYTE = 0x09;
}
void gint_stop_7305(void)
{
volatile struct mod_rtc *RTC = RTC_SH7305;
gint_priority_unlock_7305();
// Restoring the RTC configuration.
RTC->RCR2.BYTE = rcr2;
// Restoring RTC registers.
RTC.RCR1->byte = e->RCR1;
RTC.RCR2->byte = e->RCR2;
// Restoring TMU registers.
*(TMU.timers[0]) = e->TMU0;
*(TMU.timers[1]) = e->TMU1;
*(TMU.timers[2]) = e->TMU2;
TMU.TSTR->byte = e->TSTR;
// Restoring keyboard-related I/O port registers. However the backlight
// pin is in PNDR and we would like the backlight to persist when we
// leave the application, so we just keep this bit.
*((volatile uint16_t *)0xa4050116) = e->PMCR;
*((volatile uint8_t *)0xa4050136) = e->PMDR;
*((volatile uint16_t *)0xa4050118) = e->PNCR;
*((volatile uint8_t *)0xa4050138) &= 0x10;
*((volatile uint8_t *)0xa4050138) |= (e->PNDR & ~0x10);
*((volatile uint16_t *)0xa405014c) = e->PZCR;
*((volatile uint8_t *)0xa405016c) = e->PZDR;
*((volatile uint8_t *)0xa40501c6) = e->key;
}

View file

@ -1,15 +1,5 @@
//---
//
// gint core module: sh7705 interrupt handler
//
// Of course all the work related to interrupts is heavily platform-
// dependent. This module handles interrupts and configures the MPU to
// save and restore the system's configuration when execution ends.
//
//---
#include <internals/gint.h>
#include <internals/rtc.h>
#include <modules/rtc.h>
#include <gint.h>
#include <timer.h>
#include <7705.h>
@ -38,74 +28,92 @@ volatile void *gint_reg_7705(gint_register_t reg)
//---
// Setup.
// Register saves, setup, interrupt locks, register restoration.
//---
static unsigned short iprs[8];
static unsigned char rcr2;
static void gint_priority_lock_7705(void)
void gint_save_7705(environment_7705_t *e)
{
// Saving the interrupt masks from registers IPRA to IPRH.
iprs[0] = INTC.IPRA.WORD;
iprs[1] = INTC.IPRB.WORD;
iprs[2] = INTX.IPRC.WORD;
iprs[3] = INTX.IPRD.WORD;
iprs[4] = INTX.IPRE.WORD;
iprs[5] = INTX.IPRF.WORD;
iprs[6] = INTX.IPRG.WORD;
iprs[7] = INTX.IPRH.WORD;
e->IPR[0] = INTC.IPRA.WORD;
e->IPR[1] = INTC.IPRB.WORD;
e->IPR[2] = INTX.IPRC.WORD;
e->IPR[3] = INTX.IPRD.WORD;
e->IPR[4] = INTX.IPRE.WORD;
e->IPR[5] = INTX.IPRF.WORD;
e->IPR[6] = INTX.IPRG.WORD;
e->IPR[7] = INTX.IPRH.WORD;
// Saving RTC registers.
e->RCR1 = RTC.RCR1->byte;
e->RCR2 = RTC.RCR2->byte;
// Saving TMU registers.
e->TMU0 = *(TMU.timers[0]);
e->TMU1 = *(TMU.timers[1]);
e->TMU2 = *(TMU.timers[2]);
e->TSTR = TMU.TSTR->byte;
// Saving port data used to access the keyboard.
e->PACR = PFC.PACR.WORD;
e->PADR = PA.DR.BYTE;
e->PBCR = PFC.PBCR.WORD;
e->PBDR = PB.DR.BYTE;
e->PMCR = PFC.PMCR.WORD;
e->PMDR = PM.DR.BYTE;
}
void gint_lock_and_setup_7705(void)
{
// Disabling everything by default to avoid receiving an interrupt that
// the handler doesn't handle, which would cause the user program to
// freeze.
INTC.IPRA.WORD = 0x0000;
INTC.IPRB.WORD = 0x0000;
INTX.IPRC.WORD = 0x0000;
INTX.IPRD.WORD = 0x0000;
INTX.IPRE.WORD = 0x0000;
INTX.IPRF.WORD = 0x0000;
INTX.IPRG.WORD = 0x0000;
INTX.IPRH.WORD = 0x0000;
INTC.IPRA.WORD = 0x0000;
INTC.IPRB.WORD = 0x0000;
INTX.IPRC.WORD = 0x0000;
INTX.IPRD.WORD = 0x0000;
INTX.IPRE.WORD = 0x0000;
INTX.IPRF.WORD = 0x0000;
INTX.IPRG.WORD = 0x0000;
INTX.IPRH.WORD = 0x0000;
// Allowing RTC, which handles keyboard.
// Allowing RTC and timer (which handles keyboard and a whole bunch of
// other things).
INTC.IPRA.BIT._RTC = 10;
INTC.IPRA.BIT._TMU0 = 12;
INTC.IPRA.BIT._TMU1 = 12;
INTC.IPRA.BIT._TMU2 = 12;
// Don't enable RTC periodic signals by default.
RTC.RCR2->byte = 0x09;
}
static void gint_priority_unlock_7705(void)
void gint_restore_and_unlock_7705(environment_7705_t *e)
{
// Restoring the saved states.
INTC.IPRA.WORD = iprs[0];
INTC.IPRB.WORD = iprs[1];
INTX.IPRC.WORD = iprs[2];
INTX.IPRD.WORD = iprs[3];
INTX.IPRE.WORD = iprs[4];
INTX.IPRF.WORD = iprs[5];
INTX.IPRG.WORD = iprs[6];
INTX.IPRH.WORD = iprs[7];
}
void gint_setup_7705(void)
{
volatile struct mod_rtc *RTC = RTC_SH7705;
gint_priority_lock_7705();
// Saving the RTC configuration.
rcr2 = RTC->RCR2.BYTE;
// Disabling RTC interrupts by default.
RTC->RCR2.BYTE = 0x09;
}
void gint_stop_7705(void)
{
volatile struct mod_rtc *RTC = RTC_SH7705;
gint_priority_unlock_7705();
// Restoring the RTC configuration.
RTC->RCR2.BYTE = rcr2;
INTC.IPRA.WORD = e->IPR[0];
INTC.IPRB.WORD = e->IPR[1];
INTX.IPRC.WORD = e->IPR[2];
INTX.IPRD.WORD = e->IPR[3];
INTX.IPRE.WORD = e->IPR[4];
INTX.IPRF.WORD = e->IPR[5];
INTX.IPRG.WORD = e->IPR[6];
INTX.IPRH.WORD = e->IPR[7];
// Restoring RTC registers.
RTC.RCR1->byte = e->RCR1;
RTC.RCR2->byte = e->RCR2;
// Restoring TMU registers.
*(TMU.timers[0]) = e->TMU0;
*(TMU.timers[1]) = e->TMU1;
*(TMU.timers[2]) = e->TMU2;
TMU.TSTR->byte = e->TSTR;
// Restoring keyboard-related I/O port registers.
PFC.PACR.WORD = e->PACR;
PA.DR.BYTE = e->PADR;
PFC.PBCR.WORD = e->PBCR;
PB.DR.BYTE = e->PBDR;
PFC.PMCR.WORD = e->PMCR;
PM.DR.BYTE = e->PMDR;
}

View file

@ -49,7 +49,7 @@ _gint_setvbr:
jsr @r5
nop
/* Activating interrupts again. */
/* Enabling interrupts again. */
mov.l sr_block, r0
not r0, r0
stc sr, r3

View file

@ -1,9 +1,11 @@
#include <internals/gint.h>
#include <internals/interrupt_maps.h>
#include <internals/modules.h>
#include <gint.h>
#include <mpu.h>
gint_info_t gint;
static environment_t env;
//---
// Initialization routines
@ -16,10 +18,17 @@ gint_info_t gint;
*/
static void setup(void)
{
isSH3() ? gint_setup_7705() : gint_setup_7305();
isSH3() ? gint_lock_and_setup_7705()
: gint_lock_and_setup_7305();
}
void gint_init(void)
{
// Detecting the MPU type. I don't like const-casting but this is still
// better than allowing the user to change the variable by mistake.
*((mpu_t *)&MPU_CURRENT) = getMPU();
// Loading the register addresses of the current platform.
mod_init();
// Linker script symbols -- gint.
extern uint32_t
gint_vbr,
@ -32,6 +41,9 @@ void gint_init(void)
// Loading the interrupt handler into the memory.
while(ptr < &egint) *ptr++ = *src++;
isSH3() ? gint_save_7705(&env.env_7705)
: gint_save_7305(&env.env_7305);
// Installing gint's default exception/interrupt handlers.
for(int i = 0; i < exc_type_max; i++)
{
@ -59,7 +71,8 @@ void gint_init(void)
*/
static void stop(void)
{
isSH3() ? gint_stop_7705() : gint_stop_7305();
isSH3() ? gint_restore_and_unlock_7705(&env.env_7705)
: gint_restore_and_unlock_7305(&env.env_7305);
}
void gint_quit(void)
{

View file

@ -1,4 +1,6 @@
#include <modules/timer.h>
#include <modules/rtc.h>
#include <stddef.h>
#include <mpu.h>
@ -11,7 +13,8 @@
// confront to the hardware directly.
//---
volatile mod_tmu_t TMU;
mod_tmu_t TMU;
mod_rtc_t RTC;
@ -26,6 +29,10 @@ static void mod_init_7705(void)
TMU.timers[2] = (void *)0xfffffeac;
TMU.TSTR = (void *)0xfffffe92;
TMU.TCPR2 = (void *)0xfffffeb8;
RTC.RCR1 = (void *)0xfffffedc;
RTC.RCR2 = (void *)0xfffffede;
RTC.time = (void *)0xfffffec0;
}
static void mod_init_7305(void)
@ -35,6 +42,10 @@ static void mod_init_7305(void)
TMU.timers[2] = (void *)0xa4490020;
TMU.TSTR = (void *)0xa4490004;
TMU.TCPR2 = NULL;
RTC.RCR1 = (void *)0xa413fedc;
RTC.RCR2 = (void *)0xa413fede;
RTC.time = (void *)0xa413fec0;
}
/*

View file

@ -8,7 +8,7 @@
#include <mpu.h>
mpu_t MPU_CURRENT;
const mpu_t MPU_CURRENT;
/*
getMPU()
@ -67,14 +67,3 @@ mpu_t getMPU(void)
// By default, the MPU is unknown.
return mpu_unknown;
}
/*
mpu_init()
Determines the MPU type and stores the result into MPU_CURRENT.
*/
__attribute__((constructor)) void mpu_init(void)
{
MPU_CURRENT = getMPU();
}

View file

@ -30,6 +30,8 @@
many keys on the same column are pressed, other keys of the same column
may be triggered.
(The following values do not apply to the latest tests, even if the
trend remains the same.)
- Less Bad key detection.
- 8 Very few column effects. Most often, three keys may be pressed
simultaneously. However, [UP] has latencies and is globally not
@ -49,7 +51,8 @@ static void kdelay(void)
__asm__
(
"nop\n\t"
r4(r4("nop\n\t"))
r4(r4("nop\n\t"))
);
#undef r4

View file

@ -1,13 +1,14 @@
#include <internals/rtc.h>
#include <modules/rtc.h>
#include <rtc.h>
#include <mpu.h>
// Array holding callback informations.
struct rtc_cb cb_array[RTC_CB_ARRAY_SIZE] = { 0 };
rtc_callback_t cb_array[RTC_CB_ARRAY_SIZE] = { 0 };
// Callback identifier (unique).
static int unique_id = 1;
// Current RTC interrupt frequency.
static rtc_frequency_t rtc_freq = RTCFreq_None;
static rtc_frequency_t rtc_freq = rtc_freq_none;
// 256-Hz tick count. This counter is stopped when no callback is registered.
static unsigned elapsed256 = 0;
@ -21,7 +22,7 @@ static unsigned elapsed256 = 0;
*/
static void rtc_cb_update(void)
{
rtc_frequency_t max = RTCFreq_None;
rtc_frequency_t max = rtc_freq_none;
int n;
for(n = 0; n < RTC_CB_ARRAY_SIZE; n++) if(cb_array[n].id)
@ -33,8 +34,7 @@ static void rtc_cb_update(void)
if(rtc_freq == max) return;
rtc_freq = max;
volatile struct mod_rtc *RTC = isSH3() ? RTC_SH7705 : RTC_SH7305;
RTC->RCR2.BYTE = (rtc_freq << 4) | 0x09;
RTC.RCR2->byte = (rtc_freq << 4) | 0x09;
}
/*
@ -49,7 +49,7 @@ static void rtc_cb_update(void)
int rtc_cb_add(rtc_frequency_t freq, void (*function)(void), int repeats)
{
int n = 0;
if(freq == RTCFreq_None || !function || repeats < 0) return -2;
if(freq == rtc_freq_none || !function || repeats < 0) return -2;
while(n < RTC_CB_ARRAY_SIZE && cb_array[n].id) n++;
if(n >= RTC_CB_ARRAY_SIZE) return -1;
@ -77,7 +77,7 @@ void rtc_cb_end(int id)
if(n >= RTC_CB_ARRAY_SIZE) return;
cb_array[n].id = 0;
cb_array[n].freq = RTCFreq_None;
cb_array[n].freq = rtc_freq_none;
cb_array[n].callback = NULL;
cb_array[n].repeats = 0;
@ -134,7 +134,7 @@ void rtc_cb_interrupt(void)
for(n = 0; n < RTC_CB_ARRAY_SIZE; n++)
{
struct rtc_cb *cb = &cb_array[n];
rtc_callback_t *cb = &cb_array[n];
if(!cb->id || !cb->freq) continue;
// Only execute callback when the number of elapsed 256-Hz

View file

@ -1,16 +1,17 @@
#include <internals/rtc.h>
#include <modules/rtc.h>
#include <rtc.h>
#include <mpu.h>
/*
integer()
integer8(), integer16() [static]
Converts a BCD value to an integer.
*/
static int integer8(int bcd)
static int integer8(uint8_t bcd)
{
return (bcd & 0x0f) + 10 * (bcd >> 4);
}
static int integer16(int bcd)
static int integer16(uint16_t bcd)
{
return (bcd & 0xf) + 10 * ((bcd >> 4) & 0xf) + 100 * ((bcd >> 8) & 0xf)
+ 1000 * (bcd >> 12);
@ -19,26 +20,23 @@ static int integer16(int bcd)
/*
rtc_getTime()
Reads the current time from the RTC. There is no guarantee that the
week day is correct (use the time API for that).
week day will contain a correct value (use the time API for that).
*/
rtc_time_t rtc_getTime(void)
void rtc_getTime(rtc_time_t *time)
{
volatile struct mod_rtc *rtc = isSH3() ? RTC_SH7705 : RTC_SH7305;
rtc_time_t time;
if(!time) return;
do
{
rtc->RCR1.CF = 0;
RTC.RCR1->CF = 0;
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);
time.week_day = rtc->RWKCNT;
time->seconds = integer8(RTC.time->RSECCNT.byte);
time->minutes = integer8(RTC.time->RMINCNT.byte);
time->hours = integer8(RTC.time->RHRCNT .byte);
time->month_day = integer8(RTC.time->RDAYCNT.byte);
time->month = integer8(RTC.time->RMONCNT.byte);
time->year = integer16(RTC.time->RYRCNT.word);
time->week_day = RTC.time->RWKCNT;
}
while(rtc->RCR1.CF != 0);
return time;
while(RTC.RCR1->CF != 0);
}

View file

@ -1,9 +1,8 @@
#include <internals/rtc.h>
#include <modules/rtc.h>
#include <rtc.h>
#include <mpu.h>
int rtc_carry_flag = 0;
/*
rtc_periodic_interrupt()
Handles an RTC interrupt by calling the callback.
@ -12,6 +11,5 @@ void rtc_periodic_interrupt(void)
{
rtc_cb_interrupt();
volatile struct mod_rtc *RTC = isSH3() ? RTC_SH7705 : RTC_SH7305;
RTC->RCR2.PEF = 0;
RTC.RCR2->PEF = 0;
}

View file

@ -1,17 +1,18 @@
#include <internals/rtc.h>
#include <modules/rtc.h>
#include <rtc.h>
#include <mpu.h>
/*
bcd()
bcd8(), bcd16() [static]
Converts an integer to a BCD value.
*/
static int bcd8(int integer)
static uint8_t bcd8(int integer)
{
integer %= 100;
return ((integer / 10) << 4) | (integer % 10);
}
static int bcd16(int integer)
static uint16_t bcd16(int integer)
{
integer %= 10000;
return (bcd8(integer / 100) << 8) | bcd8(integer % 100);
@ -22,22 +23,22 @@ static int bcd16(int integer)
Sets the time in the RTC registers. The week day is set to 0 if greater
than 6. Other fields are not checked.
*/
void rtc_setTime(rtc_time_t time)
void rtc_setTime(const rtc_time_t *time)
{
volatile struct mod_rtc *rtc = isSH3() ? RTC_SH7705 : RTC_SH7305;
int wday = (time.week_day < 7) ? (time.week_day) : (0);
if(!time) return;
int wday = (time->week_day < 7) ? (time->week_day) : (0);
do
{
rtc->RCR1.CF = 0;
RTC.RCR1->CF = 0;
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);
rtc->RWKCNT = wday;
RTC.time->RSECCNT.byte = bcd8(time->seconds);
RTC.time->RMINCNT.byte = bcd8(time->minutes);
RTC.time->RHRCNT .byte = bcd8(time->hours);
RTC.time->RDAYCNT.byte = bcd8(time->month_day);
RTC.time->RMONCNT.byte = bcd8(time->month);
RTC.time->RYRCNT .word = bcd16(time->year);
RTC.time->RWKCNT = wday;
}
while(rtc->RCR1.CF != 0);
while(RTC.RCR1->CF != 0);
}

View file

@ -12,10 +12,11 @@
*/
time_t time(time_t *timeptr)
{
rtc_time_t rtc = rtc_getTime();
rtc_time_t rtc;
struct tm tm;
time_t calendar;
rtc_getTime(&rtc);
tm.tm_sec = rtc.seconds;
tm.tm_min = rtc.minutes;
tm.tm_hour = rtc.hours;

1
version Normal file
View file

@ -0,0 +1 @@
beta-0.9-289