diff --git a/TODO b/TODO index 360005e..8e540a7 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,11 @@ - multi-getkey repeats (if possible, which doesn't seem likely) -- getkey() may unwantedly repeat a key if it was triggered for multigetkey() - write and test gray engine - full rtc driver (time) - callbacks and complete user API +- exhaustive save for setjmp() +- registers that need to be saved when configuring gint + _ 7305.h _ libc diff --git a/ginttest.c b/ginttest.c index 3211a45..5b5781a 100644 --- a/ginttest.c +++ b/ginttest.c @@ -17,7 +17,7 @@ void print_clear(void) { char *empty_line = " "; int i = 0; - while(i < 8) print(empty_line, 0, i++); + while(i < 8) __Print(empty_line, 0, i++); } void print(const char *str, int x, int y) { @@ -66,30 +66,38 @@ void print_hexa(unsigned int n, int digits, int x, int y) /* Keyboard tests. + The user timer reproduces the parameters of the keyboard timer. */ +void keyboard_test_timer(void) +{ + volatile unsigned char *state = keystate(); + + print_bin(state[0], 0, 1); + print_bin(state[1], 0, 2); + print_bin(state[2], 0, 3); + print_bin(state[3], 0, 4); + print_bin(state[4], 0, 5); + + print_bin(state[5], 9, 1); + print_bin(state[6], 9, 2); + print_bin(state[7], 9, 3); + print_bin(state[8], 9, 4); + print_bin(state[9], 9, 5); +} + void keyboard_test(void) { -/* - print_bin(keyboard_state[0], 0, 2); - print_bin(keyboard_state[1], 0, 3); - print_bin(keyboard_state[2], 0, 4); - print_bin(keyboard_state[3], 0, 5); - print_bin(keyboard_state[4], 0, 6); - - print_bin(keyboard_state[5], 9, 2); - print_bin(keyboard_state[6], 9, 3); - print_bin(keyboard_state[7], 9, 4); - print_bin(keyboard_state[8], 9, 5); - print_bin(keyboard_state[9], 9, 6); -*/ - int x = 0; char str[3]; int keys[4] = { 0 }; int i; + timer_start(TIMER_USER, 1700, TIMER_Po_256, keyboard_test_timer, 0); + print_clear(); + print("Keyboard state:", 0, 0); + print("multi-getkey ^^", 6, 7); while(1) { @@ -114,6 +122,8 @@ void keyboard_test(void) #undef hexa } + + timer_stop(TIMER_USER); } /* diff --git a/ginttest.g1a b/ginttest.g1a index ab24651..4e1da82 100644 Binary files a/ginttest.g1a and b/ginttest.g1a differ diff --git a/icon.bmp b/icon.bmp index c97606c..27f0e48 100644 Binary files a/icon.bmp and b/icon.bmp differ diff --git a/include/display.h b/include/display.h index 20e0240..00b4042 100644 --- a/include/display.h +++ b/include/display.h @@ -35,6 +35,12 @@ enum BlendingMode Blend_Checker = 0x10, }; +/* + enum ImageFormat + Describes the various image formats available. Colors may be encoded + as monochrome (1 layer) or gray (2 layers). Whatever the color map, any + bitmap may also have an additional alpha layer. +*/ enum ImageFormat { ImageFormat_Mono = 0x01, @@ -45,6 +51,13 @@ enum ImageFormat ImageFormat_ColorMask = 0x0f, }; +/* + struct Image + This structure holds information about a bitmap encoded with fxconv. + Data is accessed using longword operations, which *requires* many + sizes to be multiples of 4 (structure alignment, data alignment, layer + size, ...). +*/ struct Image { unsigned char width; @@ -57,11 +70,12 @@ struct Image const unsigned char __attribute__((aligned(4))) data[]; } __attribute__((aligned(4))); - +// Useful shorthand for user code. typedef struct Image Image; +// A few other constants. #define DISPLAY_WIDTH 128 #define DISPLAY_HEIGHT 64 @@ -73,18 +87,31 @@ typedef struct Image Image; /* display_getLocalVRAM() - Returns the local video ram. This address should not be used directly - when running the gray engine. + Returns the local video ram. This function always return the same + address. + The buffer returned by this function should not be used directly when + running the gray engine. @return Video ram address of the monochrome display module. */ void *display_getLocalVRAM(void); +/* + display_getCurrentVRAM() + Returns the current video ram. This function usually returns the + parameter of the last call to display_useVRAM(), unless the gray engine + is running (in which case the result is undefined). Returns the local + vram address by default. +*/ +void *display_getCurrentVRAM(void); + /* display_useVRAM() - Changes the current video ram address. Expects a *4-aligned* 1024-byte - buffer. - Do not use this function while running the gray engine. + Changes the current video ram address. The argument *MUST* be a + 4-aligned 1024 buffer ; otherwise any drawing operation will crash the + program. + This function will most likely have no effect when running the gray + engine. @arg New video ram address. */ @@ -169,7 +196,7 @@ void dline(int x1, int y1, int x2, int y2, enum Color color); /* dimage() - Displays an image in the vram. + Displays an image in the vram. Does a real lot of optimization. @arg image @arg x diff --git a/include/gint.h b/include/gint.h index 34fc394..4468852 100644 --- a/include/gint.h +++ b/include/gint.h @@ -22,19 +22,38 @@ unsigned int gint_getVBR(void); */ unsigned int gint_systemVBR(void); +/* + enum RTCFrequency + Describes the possible frequencies available for the real-time clock + interrupt. +*/ +enum RTCFrequency +{ + RTCFreq_500mHz = 7, + RTCFreq_1Hz = 6, + RTCFreq_2Hz = 5, + RTCFreq_4Hz = 4, + RTCFreq_16Hz = 3, + RTCFreq_64Hz = 2, + RTCFreq_256Hz = 1, +}; + /* gint_setRTCCallback() Sets the callback function for the real-time clock interrupt. If frequency is non-NULL, the clock frequency is set to the given value. + + @arg callback Callback function. + @arg frequency Interrupt frequency. */ -void gint_setRTCCallback(void (*callback)(void), enum GintFrequency frequency); +void gint_setRTCCallback(void (*callback)(void), enum RTCFrequency frequency); /* gint_getRTCCallback() Returns the callback function. If frequency is non-NULL, it is set to the current frequency value. */ -void (*(gint_getRTCCallback)(void))(enum GintFrequency *frequency); +void (*gint_getRTCCallback(enum RTCFrequency *frequency))(void); @@ -89,12 +108,28 @@ void gint_stop_7305(void); gint() Handles interrupts. */ -void gint(void) __attribute__(( - section(".gint.int.entry"), - interrupt_handler -)); -void gint_7705(void) __attribute__((section(".gint.int"))); -void gint_7305(void) __attribute__((section(".gint.int"))); +void gint(void) __attribute__((section(".gint.int.entry"), + interrupt_handler)); +void gint_7705(void) __attribute__((section(".gint.int"))); +void gint_7305(void) __attribute__((section(".gint.int"))); + +/* + gint_setRTCFrequency() + Sets the RTC interrupt frequency and enables interrupts. + + @arg frequency +*/ +void gint_setRTCFrequency_7705(enum RTCFrequency frequency); +void gint_setRTCFrequency_7305(enum RTCFrequency frequency); + +/* + gint_getRTCFrequency() + Returns the RTC interrupt frequency. + + @return RTC interrupt frequency. +*/ +enum RTCFrequency gint_getRTCFrequency_7705(void); +enum RTCFrequency gint_getRTCFrequency_7305(void); diff --git a/include/mpu.h b/include/mpu.h index eb8ddc1..a9132e6 100644 --- a/include/mpu.h +++ b/include/mpu.h @@ -49,4 +49,17 @@ extern enum MPU MPU_CURRENT; */ enum MPU getMPU(void); + + +//--- +// Internal API. +// Referenced here for documentation purposes only. Do not call. +//--- + +/* + mpu_init() + Determines the MPU type and stores the result into MPU_CURRENT. +*/ +void mpu_init(void) __attribute__((constructor)); + #endif // _MPU_H diff --git a/include/screen.h b/include/screen.h index f54d8f8..91a85b6 100644 --- a/include/screen.h +++ b/include/screen.h @@ -1,6 +1,10 @@ #ifndef _SCREEN_H #define _SCREEN_H 1 +//--- +// Public API. +//--- + /* screen_display() Displays contents on the full screen. Expects a 1024-byte buffer. diff --git a/include/setjmp.h b/include/setjmp.h index c43c204..2037b5e 100644 --- a/include/setjmp.h +++ b/include/setjmp.h @@ -17,7 +17,7 @@ typedef unsigned int jmp_buf[16]; @arg env Empty jump buffer. */ -int setjmp(jmp_buf env); +int setjmp(jmp_buf env); /* longjmp() @@ -26,6 +26,6 @@ int setjmp(jmp_buf env); @arg env Jump buffer configure with setjmp(). @arg value setjmp() will return this integer after the jump. */ -void longjmp(jmp_buf env, int value); +void longjmp(jmp_buf env, int value); #endif // _SETJMP_H diff --git a/libc.a b/libc.a index 102244a..8bf5347 100644 Binary files a/libc.a and b/libc.a differ diff --git a/libgint.a b/libgint.a index 82f815b..4425ae3 100644 Binary files a/libgint.a and b/libgint.a differ diff --git a/src/display.c b/src/display.c index 92b2315..d004b1e 100644 --- a/src/display.c +++ b/src/display.c @@ -41,7 +41,7 @@ static int *vram = local_vram; //--- -// Local helper functions. +// Local functions. //--- /* @@ -115,14 +115,25 @@ static void getmasks(int x1, int x2, unsigned int *masks) //--- /* - display_getVRAM() - Returns the current video ram. + display_getLocalVRAM() + Returns the local video ram. @return Video ram address. */ void *display_getLocalVRAM(void) { - return (void*)local_vram; + return (void *)local_vram; +} + +/* + display_getCurrentVRAM() + Returns the current vido ram. + + @return Video ram address. +*/ +void *display_getCurrentVRAM(void) +{ + return (void *)vram; } /* @@ -370,7 +381,7 @@ void dline(int x1, int y1, int x2, int y2, enum Color color) // the same : get a part of the image in an operator, shift it depending // on the drawing x-coordinate, compute a mask that indicates which bits // of the operator contain information, and modify a vram long using the -// operator. +// operator and the mask. //--- /* diff --git a/src/gint.c b/src/gint.c index 19198c9..e63596b 100644 --- a/src/gint.c +++ b/src/gint.c @@ -1,6 +1,7 @@ #include #include #include +#include //--- // Local variables. @@ -10,6 +11,8 @@ static unsigned int new_vbr, sys_vbr; +static void (*rtc_callback)(void) = NULL; + //--- @@ -60,6 +63,42 @@ unsigned int gint_systemVBR(void) return sys_vbr; } +/* + gint_setRTCCallback() + Sets the callback function for the real-time clock interrupt. If + frequency is non-NULL, the clock frequency is set to the given value. + + @arg callback Callback function. + @arg frequency Interrupt frequency. +*/ +void gint_setRTCCallback(void (*callback)(void), enum RTCFrequency frequency) +{ + if(frequency < 1 || frequency > 7) return; + rtc_callback = callback; + + if(isSH3()) + gint_setRTCFrequency_7705(frequency); + else + gint_setRTCFrequency_7305(frequency); +} + +/* + gint_getRTCCallback() + Returns the callback function. If frequency is non-NULL, it is set to + the current frequency value. +*/ +void (*gint_getRTCCallback(enum RTCFrequency *frequency))(void) +{ + if(!frequency) return rtc_callback; + + if(isSH3()) + *frequency = gint_getRTCFrequency_7705(); + else + *frequency = gint_getRTCFrequency_7305(); + + return rtc_callback; +} + /* gint() Handles interrupts. diff --git a/src/gint_7305.c b/src/gint_7305.c index 25330e9..bbdc22c 100644 --- a/src/gint_7305.c +++ b/src/gint_7305.c @@ -15,6 +15,35 @@ +//--- +// Various MPU-dependent procedures. +//--- + +/* + gint_setRTCFrequency() + Sets the RTC interrupt frequency and enables interrupts. + + @arg frequency +*/ +void gint_setRTCFrequency_7305(enum RTCFrequency frequency) +{ + if(frequency < 1 || frequency > 7) return; + RTC.RCR2.BYTE = (frequency << 4) | 0x09; +} + +/* + gint_getRTCFrequency() + Returns the RTC interrupt frequency. + + @return RTC interrupt frequency. +*/ +enum RTCFrequency gint_getRTCFrequency_7305(void) +{ + return (RTC.RCR2.BYTE & 0x70) >> 4; +} + + + //--- // Keyboard management. //--- @@ -272,15 +301,16 @@ void gint_setup_7305(void) { gint_priority_lock_7305(); - // Configuring the RTC to have a 16-Hz keyboard. + // Saving the RTC configuration. rcr2 = RTC.RCR2.BYTE; - RTC.RCR2.BYTE = 0x39; + // Disabling RTC interrupts by default. + RTC.RCR2.BYTE = 0x09; } void gint_stop_7305(void) { gint_priority_unlock_7305(); - // Stopping the RTC interrupt. + // Restoring the RTC configuration. RTC.RCR2.BYTE = rcr2; } diff --git a/src/gint_7705.c b/src/gint_7705.c index 563958b..4a08601 100644 --- a/src/gint_7705.c +++ b/src/gint_7705.c @@ -15,6 +15,35 @@ +//--- +// Various MPU-dependent procedures. +//--- + +/* + gint_setRTCFrequency() + Sets the RTC interrupt frequency and enables interrupts. + + @arg frequency +*/ +void gint_setRTCFrequency_7705(enum RTCFrequency frequency) +{ + if(frequency < 1 || frequency > 7) return; + RTC.RCR2.BYTE = (frequency << 4) | 0x09; +} + +/* + gint_getRTCFrequency() + Returns the RTC interrupt frequency. + + @return RTC interrupt frequency. +*/ +enum RTCFrequency gint_getRTCFrequency_7705(void) +{ + return (RTC.RCR2.BYTE & 0x70) >> 4; +} + + + //--- // Keyboard management. //--- @@ -22,7 +51,7 @@ /* kdelay() Used to be a low-level sleep using the watchdog, as in the system. This - way seems ok at least, and it doesn't create column effects as for + way seems OK at least, and it doesn't create column effects as for SH7305. */ static void kdelay(void) @@ -181,6 +210,7 @@ void gint_7705(void) //--- static unsigned short iprs[8]; +static unsigned char rcr2; static void gint_priority_lock_7705(void) { @@ -230,11 +260,16 @@ void gint_setup_7705(void) { gint_priority_lock_7705(); - // Configuring the RTC to have a 16-Hz keyboard. - RTC.RCR2.BYTE = 0x39; + // Saving the RTC configuration. + rcr2 = RTC.RCR2.BYTE; + // Disabling RTC interrupts by default. + RTC.RCR2.BYTE = 0x09; } void gint_stop_7705(void) { gint_priority_unlock_7705(); + + // Restoring the RTC configuration. + RTC.RCR2.BYTE = rcr2; } diff --git a/src/keyboard.c b/src/keyboard.c index 0ec7a0e..1f44d74 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -214,7 +214,7 @@ int keylast(int *repeat_count) /* keystate() Returns the address of the keyboard state array. The returned address - if the handler's buffer, therefore it contains volatile data. + is the handler's buffer, therefore it contains volatile data. @return 10-byte keyboard state buffer. */ diff --git a/src/mpu.c b/src/mpu.c index ccc38d6..fa5fbea 100644 --- a/src/mpu.c +++ b/src/mpu.c @@ -63,13 +63,13 @@ enum MPU getMPU(void) return MPU_Unknown; } -static void mpu_init(void) - __attribute__(( - section(".pretext"), - constructor - )); -static void mpu_init(void) + +/* + mpu_init() + Determines the MPU type and stores the result into MPU_CURRENT. +*/ +void mpu_init(void) { MPU_CURRENT = getMPU(); } diff --git a/src/timer.c b/src/timer.c index d7afc15..77c9a9d 100644 --- a/src/timer.c +++ b/src/timer.c @@ -2,9 +2,14 @@ #include #include +//--- +// Internal declarations. +// Timer structure and running information (callbacks, repeats etc.) +//--- + /* struct Timer - This structure handles a running timer information. + This structure holds information for a running timer. */ struct Timer { @@ -17,7 +22,8 @@ static struct Timer timers[3] = { { NULL, 0 }, { NULL, 0 }, { NULL, 0 } }; /* struct mod_tmu - This structure allows access to a timer using its address. + This structure holds information about the timer unit (peripheral + module) registers. */ struct mod_tmu { @@ -48,6 +54,10 @@ struct mod_tmu +//--- +// Internal API. +//--- + /* timer_get() @@ -57,7 +67,7 @@ struct mod_tmu @arg tmu mod_tmu structure pointer address. @arg tstr mod_tstr structure pointer address. */ -void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr) +static void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr) { // Using SH7705 information for SH-3-based MPUs. if(MPU_CURRENT == MPU_SH7337 || MPU_CURRENT == MPU_SH7355) @@ -76,6 +86,37 @@ void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr) if(tmu) *tmu += timer; } +/* + timer_interrupt() + Handles the interrupt for the given timer. + + @timer Timer that generated the interrupt. +*/ +void timer_interrupt(int timer) +{ + // Getting the timer address. + struct mod_tmu *tmu; + timer_get(timer, &tmu, NULL); + + // Resetting the interrupt flag. + (*tmu).TCR.UNF = 0; + + // Calling the callback function. + if(timers[timer].callback) timers[timer].callback(); + + // Reducing the number of repetitions left, if not infinite. + if(!timers[timer].repetitions) return; + // And stopping it if necessary. + if(timers[timer].repetitions == 1) timer_stop(timer); + else timers[timer].repetitions--; +} + + + +//--- +// Public API. +//--- + /* timer_start() Configures and starts a timer. @@ -135,28 +176,3 @@ void timer_stop(int timer) // Stopping the timer. *tstr &= ~byte; } - -/* - timer_interrupt() - Handles the interrupt for the given timer. - - @timer Timer that generated the interrupt. -*/ -void timer_interrupt(int timer) -{ - // Getting the timer address. - struct mod_tmu *tmu; - timer_get(timer, &tmu, NULL); - - // Resetting the interrupt flag. - (*tmu).TCR.UNF = 0; - - // Calling the callback function. - if(timers[timer].callback) timers[timer].callback(); - - // Reducing the number of repetitions left, if not infinite. - if(!timers[timer].repetitions) return; - // And stopping it if necessary. - if(timers[timer].repetitions == 1) timer_stop(timer); - else timers[timer].repetitions--; -}