From 57a7e1c2d42481849a9c2adcd6e7955a208c0645 Mon Sep 17 00:00:00 2001 From: lephe Date: Thu, 13 Apr 2017 21:59:13 +0200 Subject: [PATCH] More quality review, more registers saved at startup. --- Makefile | 34 +++++- TODO | 44 ++++---- demo/gintdemo.c | 4 +- demo/test_bopti.c | 6 +- demo/test_rtc.c | 40 +++---- demo/test_timer.c | 4 +- include/bopti.h | 14 ++- include/gint.h | 3 - include/internals/bopti.h | 130 ++++++++++++----------- include/internals/gint.h | 81 +++++++++++--- include/internals/keyboard.h | 5 +- include/internals/mmu.h | 4 +- include/internals/rtc.h | 125 ++-------------------- include/modules/macros.h | 9 ++ include/modules/rtc.h | 131 +++++++++++++++++++++++ include/modules/timer.h | 2 +- include/mpu.h | 2 +- include/rtc.h | 27 ++--- src/bopti/bopti_internals.c | 54 ++++------ src/bopti/dimage.c | 6 +- src/bopti/gimage.c | 4 +- src/clock/clock.c | 4 +- src/core/crt0.c | 20 ++-- src/core/exceptions.c | 4 +- src/core/gint.c | 13 +-- src/core/gint_sh7305.c | 189 ++++++++++++++++----------------- src/core/gint_sh7705.c | 136 +++++++++++++----------- src/core/gint_vbr.s | 2 +- src/core/init_quit.c | 17 ++- src/core/modules.c | 13 ++- src/core/mpu.c | 13 +-- src/keyboard/keyboard_sh7305.c | 5 +- src/rtc/rtc_callback.c | 16 +-- src/rtc/rtc_getTime.c | 34 +++--- src/rtc/rtc_interrupt.c | 6 +- src/rtc/rtc_setTime.c | 31 +++--- src/time/time.c | 3 +- version | 1 + 38 files changed, 673 insertions(+), 563 deletions(-) create mode 100644 include/modules/rtc.h create mode 100644 version diff --git a/Makefile b/Makefile index 04677b1..26db109 100755 --- a/Makefile +++ b/Makefile @@ -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 (' diff --git a/TODO b/TODO index 9134ce0..88f4c3c 100644 --- a/TODO +++ b/TODO @@ -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 diff --git a/demo/gintdemo.c b/demo/gintdemo.c index 98d1ac5..41e4d6e 100644 --- a/demo/gintdemo.c +++ b/demo/gintdemo.c @@ -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); diff --git a/demo/test_bopti.c b/demo/test_bopti.c index a908823..9b137c8 100644 --- a/demo/test_bopti.c +++ b/demo/test_bopti.c @@ -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(); diff --git a/demo/test_rtc.c b/demo/test_rtc.c index 1211aed..4b8fa65 100644 --- a/demo/test_rtc.c +++ b/demo/test_rtc.c @@ -14,9 +14,10 @@ */ #include +#include #include -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); } } diff --git a/demo/test_timer.c b/demo/test_timer.c index d64e6c0..011f365 100644 --- a/demo/test_timer.c +++ b/demo/test_timer.c @@ -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); diff --git a/include/bopti.h b/include/bopti.h index 8889359..95465c7 100644 --- a/include/bopti.h +++ b/include/bopti.h @@ -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 diff --git a/include/gint.h b/include/gint.h index 887b960..57486a1 100644 --- a/include/gint.h +++ b/include/gint.h @@ -15,9 +15,6 @@ #include #include -#define GINT_VERSION 0x000100a3 -#define GINT_VERSION_STR "00.01" - //--- // System info provided by the library //--- diff --git a/include/internals/bopti.h b/include/internals/bopti.h index 31a87e0..2c93153 100644 --- a/include/internals/bopti.h +++ b/include/internals/bopti.h @@ -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 /* - 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 diff --git a/include/internals/gint.h b/include/internals/gint.h index 601ff70..fd51e06 100644 --- a/include/internals/gint.h +++ b/include/internals/gint.h @@ -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 +#include + +/* + 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() diff --git a/include/internals/keyboard.h b/include/internals/keyboard.h index 738c1ee..2ed7f9e 100644 --- a/include/internals/keyboard.h +++ b/include/internals/keyboard.h @@ -5,11 +5,12 @@ #include #include -// 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; diff --git a/include/internals/mmu.h b/include/internals/mmu.h index ced7211..1fcf6ac 100644 --- a/include/internals/mmu.h +++ b/include/internals/mmu.h @@ -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. // //--- diff --git a/include/internals/rtc.h b/include/internals/rtc.h index 4f3e348..4b9f9e0 100644 --- a/include/internals/rtc.h +++ b/include/internals/rtc.h @@ -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 diff --git a/include/modules/macros.h b/include/modules/macros.h index 5f4403b..664fc7d 100644 --- a/include/modules/macros.h +++ b/include/modules/macros.h @@ -3,6 +3,15 @@ #include +// 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; diff --git a/include/modules/rtc.h b/include/modules/rtc.h new file mode 100644 index 0000000..7eb7ef0 --- /dev/null +++ b/include/modules/rtc.h @@ -0,0 +1,131 @@ +#ifndef _MODULES_RTC_H +#define _MODULES_RTC_H + +#include +#include + +/* + 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 diff --git a/include/modules/timer.h b/include/modules/timer.h index 3a8b187..46657ae 100644 --- a/include/modules/timer.h +++ b/include/modules/timer.h @@ -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 diff --git a/include/mpu.h b/include/mpu.h index dd183bc..d3c751f 100644 --- a/include/mpu.h +++ b/include/mpu.h @@ -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. diff --git a/include/rtc.h b/include/rtc.h index 771ac2c..2c65876 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -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)); diff --git a/src/bopti/bopti_internals.c b/src/bopti/bopti_internals.c index c42d128..0469e81 100644 --- a/src/bopti/bopti_internals.c +++ b/src/bopti/bopti_internals.c @@ -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; diff --git a/src/bopti/dimage.c b/src/bopti/dimage.c index 3d05d72..fe34859 100644 --- a/src/bopti/dimage.c +++ b/src/bopti/dimage.c @@ -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; diff --git a/src/bopti/gimage.c b/src/bopti/gimage.c index c6c51c0..e570634 100644 --- a/src/bopti/gimage.c +++ b/src/bopti/gimage.c @@ -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; diff --git a/src/clock/clock.c b/src/clock/clock.c index 9da10f8..8084c4d 100644 --- a/src/clock/clock.c +++ b/src/clock/clock.c @@ -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); } diff --git a/src/core/crt0.c b/src/core/crt0.c index a343a98..c00aeb9 100644 --- a/src/core/crt0.c +++ b/src/core/crt0.c @@ -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 diff --git a/src/core/exceptions.c b/src/core/exceptions.c index 9491221..ad2ac4a 100644 --- a/src/core/exceptions.c +++ b/src/core/exceptions.c @@ -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); diff --git a/src/core/gint.c b/src/core/gint.c index 608bce5..6d309f9 100644 --- a/src/core/gint.c +++ b/src/core/gint.c @@ -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 #include #include @@ -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]) diff --git a/src/core/gint_sh7305.c b/src/core/gint_sh7305.c index 7410084..9c54118 100644 --- a/src/core/gint_sh7305.c +++ b/src/core/gint_sh7305.c @@ -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 -#include +#include +#include #include #include #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; } diff --git a/src/core/gint_sh7705.c b/src/core/gint_sh7705.c index 9f5ac26..d19924d 100644 --- a/src/core/gint_sh7705.c +++ b/src/core/gint_sh7705.c @@ -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 -#include +#include #include #include #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; } diff --git a/src/core/gint_vbr.s b/src/core/gint_vbr.s index 7253a91..067aadb 100644 --- a/src/core/gint_vbr.s +++ b/src/core/gint_vbr.s @@ -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 diff --git a/src/core/init_quit.c b/src/core/init_quit.c index ac16dd0..a50d287 100644 --- a/src/core/init_quit.c +++ b/src/core/init_quit.c @@ -1,9 +1,11 @@ #include #include +#include #include #include 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) { diff --git a/src/core/modules.c b/src/core/modules.c index aad3491..60cc146 100644 --- a/src/core/modules.c +++ b/src/core/modules.c @@ -1,4 +1,6 @@ #include +#include + #include #include @@ -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; } /* diff --git a/src/core/mpu.c b/src/core/mpu.c index 13f621c..a952e67 100644 --- a/src/core/mpu.c +++ b/src/core/mpu.c @@ -8,7 +8,7 @@ #include -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(); -} diff --git a/src/keyboard/keyboard_sh7305.c b/src/keyboard/keyboard_sh7305.c index cae413a..68e1fc8 100644 --- a/src/keyboard/keyboard_sh7305.c +++ b/src/keyboard/keyboard_sh7305.c @@ -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 diff --git a/src/rtc/rtc_callback.c b/src/rtc/rtc_callback.c index 488d0ce..1efeb24 100644 --- a/src/rtc/rtc_callback.c +++ b/src/rtc/rtc_callback.c @@ -1,13 +1,14 @@ #include +#include #include #include // 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 diff --git a/src/rtc/rtc_getTime.c b/src/rtc/rtc_getTime.c index 5a460e9..dab7074 100644 --- a/src/rtc/rtc_getTime.c +++ b/src/rtc/rtc_getTime.c @@ -1,16 +1,17 @@ #include +#include #include #include /* - 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); } diff --git a/src/rtc/rtc_interrupt.c b/src/rtc/rtc_interrupt.c index 32a2c73..c3e0df6 100644 --- a/src/rtc/rtc_interrupt.c +++ b/src/rtc/rtc_interrupt.c @@ -1,9 +1,8 @@ #include +#include #include #include -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; } diff --git a/src/rtc/rtc_setTime.c b/src/rtc/rtc_setTime.c index 4e71e7f..27c8a3a 100644 --- a/src/rtc/rtc_setTime.c +++ b/src/rtc/rtc_setTime.c @@ -1,17 +1,18 @@ #include +#include #include #include /* - 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); } diff --git a/src/time/time.c b/src/time/time.c index e6a6727..e3edd16 100644 --- a/src/time/time.c +++ b/src/time/time.c @@ -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; diff --git a/version b/version new file mode 100644 index 0000000..91cef21 --- /dev/null +++ b/version @@ -0,0 +1 @@ +beta-0.9-289