core: better bootlog API and implementation

* Now uses topti instead of fxlib for text (including MMU failure)
* Fit .pretext into 4k for everything before MMU succeeds
* A short version of sprintf() for dynamic messages
* Support a driver function, status(), to allow early driver debug
* Expose more useful platform information in <gint/mpu.h>
* Expose the first of a few CASIOWIN syscalls
This commit is contained in:
lephe 2019-03-06 14:32:51 +01:00
parent 417340ce91
commit f33cb3cf80
27 changed files with 645 additions and 251 deletions

View File

@ -21,7 +21,7 @@ all-targets := $(foreach b,$(builds),all-$b)
all: $(all-targets)
all-build%: build%
@ echo -e "$B::$W Making into $<$N"
@ echo -e "\n$B::$W Making into $<$N"
@ $(MAKE) --no-print-directory -C $<
#
@ -33,7 +33,7 @@ install-targets := $(foreach b,$(builds),install-$b)
install: $(install-targets)
install-build%: build%
@ echo -e "$B::$W Installing from $<$N"
@ echo -e "\n$B::$W Installing from $<$N"
@ $(MAKE) --no-print-directory -C $< install
#
@ -45,7 +45,7 @@ uninstall-targets := $(foreach b,$(builds),uninstall-$b)
uninstall: $(uninstall-targets)
uninstall-build%: build%
@ echo -e "$B::$W Uninstalling from $<$N"
@ echo -e "\n$B::$W Uninstalling from $<$N"
@ $(MAKE) --no-print-directory -C $< uninstall
#

View File

@ -30,7 +30,7 @@ access to the low-level MPU features, among which:
The library also offers powerful higher-level features:
* An enhanced versio of the system's GetKey() and GetKeyWait()
* An enhanced version of the system's GetKey() and GetKeyWait()
* A gray engine that works by rapidly swapping monochrome images on fx-9860G II
* Blazingly fast drawing functions when working with the fxSDK (image rendering
is 10 times faster than MonochromeLib)

120
TODO
View File

@ -1,89 +1,45 @@
# Since compatibility
On the bootlog.
* Better review of .pretext to make sure everything fits in 4k
* Move topti to .pretext to use it in the bootlog, also update() and dclear()
* Use topti in the error message for the missing mappings (hurray o/)
* Use a serious formatted printing function
Another, more recent list of things to do:
- Complete memory functions in [core/memory.c]
- Finish the boot log in <core/bootlog.h>
- Finish the boot log in [core/bootlog.c]
- Document the SH7305 PFC in <gint/mpu/pfc.h>
- Change the description of the version number in <gint/gint.h>
- Define the version number from full Git info
- Do this display in <gint/display-fx.h> and <gint/display-cg.h>
- Remove all mentions of GINT_LAX in the code
- Write exception handlers
- Do overclock in [clock/]
- Test getkey()
Crucial, missing things.
! core: the four basic memory functions
! core: build an exception handler and a TLB miss handler
! core: gint_switch() (driver contexts on stack; arbitrary code?)
* Make keysc/keysc.c/state static and review forgotten global variables
* Find out what happened to the clock frequency on fxcg50
* Implement profiling
* Save and restore interrupt masks
* More keyboard
Tests to run.
* core: run the alignment/size automated tests
* bopti: more sizes, gray
* topti: all charsets, colors
Strange, (irreproducible?) SysERRORs on SH3?
- Happened when dealing with overclock and after a transfer
- SysERROR when add-in fully returns, nothing during execution
- Affects all add-ins of the calculator!
Completeness elements on existing code.
* keyboard: finish the interface
* clock: spread spectrum on fxcg50
* bopti: blending modes for monochrome bitmaps (use topti assembler)
* display: use more of topti's assembler in drect()
* core: use cmp/str for memchr()
* stdio: serious formatted printing function
* timer: try putting the definitions in <gint/mpu/tmu.h>
* Make sure interrupt for extra timers is masked when you ctx_restore to avoid
interrupts
Keep in mind.
* keyboard: make keysc.c@state static and review globals in the project
* prizm: don't hardcode stack address in fxcg50.ld
* prizm: detect P1 static RAM (stack) in TLB
* core: prove and use qdiv10() instead of __sdivsi3
* setjmp: more registers may need to be saved
* core: free heap when a task-switch results in leaving the app
* core: save and restore interrupt masks
* timer: make sure ETMU interrupts are disabled in ctx_restore()
* core: document the SH7305 PFC in <gint/mpu/pfc.h>
* For modules, use #define TMU ((tmu_t *)0xdeadbeef)) instead of tmu_t *TMU
* Don't hardcode fx-cg50 stack address in fxcg50.ld for Prizm compatibility
* Implement the gint_switch()
Future directions.
* File management
* Drawing functions, bopti and tales
* Gray engine
* Overclock
* Add a driver init function to the r61524 driver.
* Finish the bootlog and use the keyboard to control it.
* Save driver contexts on the stack in gint_pause().
* Write the core memory functions.
- Allow arbitrary code in gint_pause() instead of just main menu?
- Dynamically detect P1 static RAM in TLB for runtime Prizm compatibility.
* Use a solid API for boot-time printing (or just use fxlib)
- Use qdiv10() (there should be no __sdivsi3 in gint)
(bootlog, timer_delay(), getkey_repeat(), int2bcd())
* Load an exception handler and a TLB miss handler.
# Before compatibility
Bugs to fix:
- Alignment of ALL .data / .rodata files is required to ensure converted data
is properly aligned -> Ok using ALIGN(4)
- Ensure heap data is freed when a task-switch results in leaving the app (?)
Things to do before 1.0:
- bopti: Test partial transparency
- perf: Try 284x124 at (-60, -28) (all disadvantages)
- project: Check size of *all* library structures
- time: Compute CLOCKS_PER_SEC
Things to do later:
- bopti: Implement blending modes for monochrome bitmaps
- clock: Only measure if requires as option, otherwise trust {FTune}
- clock: Handle overclock (relaunch clocks when overclocking)
- clock: Split code into several files, change clock_config_t type
- core: Remove redundant code linked to environment saves
- display: Try to make this module lighter (lots of code in text section)
- esper: Cleaner playback, synthesizing
- events: Allow customization of keyboard event system (option to return
| events with modifiers, etc)
- events: Generate keyboard events on-the-fly by reading state arrays,
| allowing both a faster interrupt and avoiding supressing other
| events inside getkey() and multigetkey()
- gray: Same as display, it's quite heavy
- serial: Implement a driver
- stdio: More serious formatted printing functions and headers
- string: Use cmp/str to implement memchr() (assembler examples)
- string: Do some tests for memcmp() and memcpy()
- usb: Implement a driver
Things to investigate:
- Registers that may need to be saved within setjmp()
Possibly useful modules:
- DMAC
- SCIF, SCIFA
- TPU
- USB
- CMT on SH7305, WDT on SH7705
* Integrate overclock management
* A library for profiling with manual calls
* Audio playback using Martin Poupe's method
* Serial communication [SCIF] [SCIFA]
* USB communication [USB]
* Driver for the watchdog timer [WDT] [SH7705]

View File

@ -5,10 +5,18 @@
#ifndef GINT_CORE_BOOTLOG
#define GINT_CORE_BOOTLOG
#include <gint/defs/attributes.h>
/* bootlog_loaded() - section loading stage
Called when RAM sections have been wiped and copied */
void bootlog_loaded(void);
/* bootlog_unmapped() - ROM mapping stage failed
Called if not enough ROM pages have been mapped.
@rom Amount of mapped ROM, in bytes
@size Minimum mapping required */
void bootlog_unmapped(int rom, int size);
/* bootlog_mapped() - ROM mapping stage
Called after all ROM pages have been traversed. All of them may not have
been mapped.
@ -21,11 +29,19 @@ void bootlog_mapped(uint32_t rom, uint32_t ram);
handlers set up. */
void bootlog_kernel(void);
/* bootlog_driver() - driver load
Called for very loaded driver. */
void bootlog_driver(const char *driver_name, const char *status);
void bootlog_driver_summary(void);
/* All these functions are enabled only if GINT_BOOT_LOG is defined */
#ifndef GINT_BOOT_LOG
#define bootlog_loaded(...)
#define bootlog_unmapped(...)
#define bootlog_mapped(...)
#define bootlog_kernel(...)
#define bootlog_driver(...)
#define bootlog_driver_summary(...)
#endif
#endif /* GINT_CORE_BOOTLOG */

View File

@ -1,22 +0,0 @@
//---
// core:memory - Core memory functions
//
// These are the basic standard memory functions required by GCC.
//---
#ifndef GINT_CORE_MEMORY
#define GINT_CORE_MEMORY
/* memcpy() - copy a chunk of memory to a non-overlapping destination */
void *memcpy(void * restrict dest, const void * restrict src, size_t n);
/* memmove() - copy a chunk of memory to any destination */
void *memmove(void *dest, const void *src, size_t n);
/* memcmp() - compare two chunks of memory of the same size */
int memcmp(const void *src1, const void *src2, size_t n);
/* memset() - fill a chunk of memory with a single byte */
void *memset(void *dest, int byte, size_t n);
#endif /* GINT_CORE_MEMORY */

29
include/core/std.h Normal file
View File

@ -0,0 +1,29 @@
//---
// gint:core:std - a few standard functions implemented in gint
//
// There are few enough of them that it felt unnecessary to use a full-
// fledged standard library.
//---
#ifndef GINT_CORE_STD
#define GINT_CORE_STD
#include <gint/defs/types.h>
#include <stdarg.h>
/* memcpy() - copy a chunk of memory to a non-overlapping destination */
void *memcpy(void * restrict dest, const void * restrict src, size_t n);
/* memset() - fill a chunk of memory with a single byte */
void *memset(void *dest, int byte, size_t n);
/* strlen() - length of a NUL-terminated string */
size_t strlen(const char *str);
/* vsprintf() - an almost-empty subset of the real one */
void vsprintf(char *str, const char *format, va_list args);
/* sprintf() - an almost-empty subset of the real one */
void sprintf(char *str, const char *format, ...);
#endif /* GINT_CORE_STD */

11
include/core/syscalls.h Normal file
View File

@ -0,0 +1,11 @@
//---
// gint:core:syscalls - calls to CASIOWIN
//---
#ifndef GINT_CORE_SYSCALLS
#define GINT_CORE_SYSCALLS
/* __os_version(): Get OS version on the form MM.mm.iiii (10 bytes) */
void __os_version(char *version);
#endif /* GINT_CORE_SYSCALLS */

View File

@ -27,4 +27,7 @@
access sizes silently fail - honestly you don't want this to happen */
#define GPACKED(x) __attribute__((packed, aligned(x)))
/* Weak symbols */
#define GWEAK __attribute__((weak))
#endif /* GINT_DEFS_ATTRIBUTES */

View File

@ -27,7 +27,9 @@ extern uint32_t *vram;
#ifdef FX9860G
#include <gint/display-fx.h>
#else
#endif
#ifdef FXCG50
#include <gint/display-cg.h>
#endif

View File

@ -9,16 +9,29 @@
#include <gint/defs/types.h>
//---
// Driver initialization
// Driver procedure flow
//
// Drivers are initialized in linking order. For each driver, the
// following functions are called:
// - driver_sh3() [if running on an SH3-based machine]
// - ctx_save()
// - init()
// Drivers are initialized in priority order, and in linking order within
// the same priority (which is pretty much undefined). Make sure every
// driver's priority level is higher than those of its dependencies.
//
// When the driver is unloaded, the following functions are called:
// - ctx_restore()
// At initialization, the following functions are called:
// 1. driver_sh3() [if not NULL, SH3 fx9860G only]
// 2. ctx_save(sys_ctx) [if not NULL]
// 3. init() [if not NULL]
//
// Then, if the on-screen boot log is enabled, the status() function is
// called and the returned function is displayed (21 characters max).
// 4. status() [if not NULL, if GINT_BOOT_LOG is defined]
//
// If the gint_switch() function is called to temporarily give back
// control to the operating system, the state of each driver is saved to
// the stack, then restored from there.
// 5. ctx_save(stack) [if not NULL]
// 6. ctx_restore(stack) [if not NULL]
//
// When finally the driver is unloaded, the system context is restored.
// 7. ctx_restore(sys_ctx) [if not NULL]
//---
/* gint_driver_t - driver meta-information used by gint */
@ -65,6 +78,14 @@ typedef struct
@ctx A context buffer filled by ctx_save() */
void (*ctx_restore)(void *ctx);
/* status() - status string generation
When the boot log is defined, this function is called to print
information returned by the driver, for debugging purposes. This is
expected to be a short (max 21 bytes) string because only a few
lines are available for all drivers.
Returns a pointer to a string; a static buffer is suitable. */
const char * (*status)(void);
} GPACKED(4) gint_driver_t;
/* GINT_DECLARE_DRIVER() - make a driver visible to gint
@ -81,11 +102,26 @@ typedef struct
GSECTION(".gint.drivers." #level) extern gint_driver_t name;
/* GINT_DRIVER_SH3() - declare a function for SH3-rectification
This macros allows the argument function to not exist on fxcg50. */
This macro makes its argument NULL on fxcg50, this way the named function
can be defined under #ifdef FX9860G while keeping the structure clean. */
#ifdef FX9860G
#define GINT_DRIVER_SH3(name) name
#define GINT_DRIVER_SH3(name) name
#endif
#ifdef FXCG50
#define GINT_DRIVER_SH3(name) NULL
#endif
/* GINT_DRIVER_STATUS() - declare a function for status string generation
This macro makes its argument NULL when GINT_BOOT_LOG is defuned, this way
the named function can be defined under #ifdef GINT_BOOT_LOG while keeping
the structure clean. */
#ifdef GINT_BOOT_LOG
#define GINT_DRIVER_STATUS(name) name
#else
#define GINT_DRIVER_SH3(name) NULL
#define GINT_DRIVER_STATUS(name) NULL
#endif
#endif /* GINT_DRIVERS */

View File

@ -8,20 +8,11 @@
#include <gint/defs/types.h>
/* GINT_VERSION - the library version number
Provides gint's running version number, which is made of four fields:
31 24 23 20 19 16 15 0
+---------------+---------------+---------------+---------------+
| channel | major | minor | build |
+---------------+---------------+---------------+---------------+
gint is versioned from it's repository commits on the master branch. The
GINT_VERSION integer contains the short commit hash.
The first field is a letter indicating the type of version ('a'lpha, 'b'eta,
'r'elease, 'd'ev, etc). The second and third field are the version number on
the form "major.minor". The last field is the build number for this version.
The build number uniquely identifies a binary version of the library.
For instance, 0x72100053 translates as "release 1.0 build 83". */
/* TODO: Fix version number */
For instance, 0x03f7c0a0 means commit 3f7c0a0. */
extern char GINT_VERSION;
#define GINT_VERSION ((uint32_t)&GINT_VERSION)

View File

@ -12,6 +12,8 @@
#ifndef GINT_CORE_MPU
#define GINT_CORE_MPU
#include <gint/defs/types.h>
/* mpu_t - supported MPUs */
typedef enum
{
@ -22,27 +24,64 @@ typedef enum
mpu_sh7724 = 4, /* For reference */
} mpu_t;
/* On fx9860g, the 256k byte RAM might be extended to 512k if the machine is
recent enough. This includes all SH4 and many SH3 fx-9750 GII; the only
model known to not have it is the old fx-9860G. */
#ifdef FX9860G
/* mpu_id() - get the name of the underlying MPU */
extern const mpu_t gint_mpu_id;
#define gint_mpu() (gint_mpu_id)
typedef struct
{
/* MPU type, one of the above values */
mpu_t mpu;
/* Extended RAM area (8804'0000:256k) is available */
int extended_ram;
/* Quick SH-3/SH-4 tests. Unknown models are assumed to be SH-4A */
#define isSH3() (gint_mpu() & 1)
#define isSH4() (!isSH3())
} platform_t;
/* mpu_init() - probe the MPU type
This function must be executed before mpu_id() can be used. */
void mpu_init(void);
/* mpu_id() - get the name of the underlying MPU */
#define gint_mpu() (gint_platform.mpu)
#else /* FXCG50 */
/* All fxcg50 machines have an SH7305, which makes things simpler. */
#define gint_mpu() mpu_sh7305
#define isSH3() 0
#define isSH4() 1
/* Quick SH-3/SH-4 tests. Unknown models are assumed to be SH-4A */
#define isSH3() (gint_mpu() & 1)
#define isSH4() (!isSH3())
#endif /* FX9860G */
/* On fxcg50, the processor is always SH4. We can still differentiate between
modern fx-CG 50 and older fx-CG 10/20 which are called here "Prizm". (This
is done by observing the initial stack pointer.) */
#ifdef FXCG50
typedef struct
{
/* MPU type (always sh7305) */
mpu_t mpu;
/* Whether this is an fx-CG 10/20 Prizm instead of an fx-CG 50 */
int prizm;
} platform_t;
/* All fxcg50 machines have an SH7305, which makes things simpler. */
#define gint_mpu() mpu_sh7305
#define isSH3() 0
#define isSH4() 1
#endif /* FX9860G */
/* Platform details collected by mpu_init() */
extern const platform_t gint_platform;
/* mpu_init() - detect hardware information
This function must be executed before other functions of this header can be
used successfully.
@stack Starting stack address (roughly is enough) */
void mpu_init(uint32_t stack);
#endif /* GINT_CORE_MPU */

View File

@ -65,6 +65,7 @@ typedef volatile struct
uint32_t CKOFF :1; /* CKO Output Stop */
uint32_t :1;
);
/* TODO: CPG: Add the SSCGCR register */
pad(0x28);
lword_union(FLLFRQ,

View File

@ -4,6 +4,7 @@
#include <gint/drivers.h>
#include <gint/clock.h>
#include <core/std.h>
#include <gint/mpu.h>
#include <gint/mpu/cpg.h>
@ -53,8 +54,7 @@ static void sh7705_probe(void)
freq.Iphi_div = idiv + 1;
freq.Pphi_div = pdiv + 1;
/* Deduce the frequency of the main clocks. The following piece of code
hardcodes ckio / 3 and avoids using the division operator */
/* Deduce the frequency of the main clocks. This value is ckio/3 */
int ckio_3 = 9830400;
/* Exchange the setting values 2 and 3 */
@ -68,11 +68,6 @@ static void sh7705_probe(void)
}
#undef CPG
#else
/* This prototype will silence warnings on fxcg50 */
void sh7705_probe(void);
#endif /* FX9860G */
//---
@ -122,15 +117,36 @@ static void sh7305_probe(void)
// Other driver stuff
//---
#ifdef GINT_BOOT_LOG
static const char *cpg_status(void)
{
static char status[18];
sprintf(status, "I%3d B%3d P%3d C%c",
freq.Iphi_f / 1000000,
freq.Bphi_f / 1000000,
freq.Pphi_f / 1000000,
isSH3() ? 'e' : 'E'
);
return status;
}
#endif /* GINT_BOOT_LOG */
static void init(void)
{
isSH3() ? sh7705_probe()
: sh7305_probe();
/* This avoids warnings about sh7705() not being defined on fxcg50 */
#ifdef FX9860G
isSH3() ? sh7705_probe() :
#endif
sh7305_probe();
}
gint_driver_t drv_cpg = {
.name = "CPG",
.init = init,
.status = GINT_DRIVER_STATUS(cpg_status),
.ctx_size = 0,
.sys_ctx = NULL,
.ctx_save = NULL,

View File

@ -2,16 +2,22 @@
// gint:core:bootlog - Boot-time on-screen log for extreme debugging
//---
/* TODO: Review, enhance and fix bootlog */
#include <gint/defs/types.h>
#include <core/std.h>
#include <core/mmu.h>
#include <gint/mpu.h>
#include <gint/mpu/intc.h>
#include <core/mmu.h>
#include <gint/gint.h>
#include <gint/display.h>
#include <core/syscalls.h>
#include <gint/clock.h>
#ifdef FXCG50
void Bdisp_AllClr_VRAM(void);
void Bdisp_PutDisp_DD(void);
#define dclear(c) Bdisp_AllClr_VRAM()
#define dupdate() Bdisp_PutDisp_DD()
#endif
@ -22,28 +28,34 @@ extern char
sgdata, sgbss, sdata, sbss,
btors, mtors, etors;
/* print() - formatted printing shorthand */
static void print(int x, int y, const char *format, ...)
{
char str[45];
va_list args;
va_start(args, format);
vsprintf(str + 2, format, args);
#ifdef FX9860G
dtext(6 * (x - 1) + 1, 7 * (y - 1), str + 2, color_black, color_white);
#endif
#ifdef FXCG50
PrintXY(x, y, str, 0, 0);
#endif
va_end(args);
}
/* bootlog_loaded() - section loading stage */
GSECTION(".pretext")
void bootlog_loaded(void)
{
/* Version string - the string constant resides in ROM */
const char *base = "gint @";
const char *hexa = "0123456789abcdef";
char str[14];
for(int i = 0; i < 6; i++) str[i] = base[i];
str[13] = 0;
/* Retrieve the commit number */
for(int i = 0; i < 7; i++)
{
int shift = 24 - (i << 2);
str[i + 6] = hexa[(GINT_VERSION >> shift) & 0xf];
}
/* Size of memory sections */
uint32_t rom_size = (uint32_t)&srom;
uint32_t ram_size = (uint32_t)&sdata + (uint32_t)&sbss;
uint32_t gint_size = (uint32_t)&sgdata + (uint32_t)&sgbss;
uint32_t rom_size = (uint32_t)&srom;
uint32_t ram_size = (uint32_t)&sdata + (uint32_t)&sbss;
uint32_t gint_size = (uint32_t)&sgdata + (uint32_t)&sgbss;
/* MPU type */
mpu_t mpu = gint_mpu();
@ -51,68 +63,121 @@ void bootlog_loaded(void)
/* TODO: Use a solid API for boot-time printing */
dclear(color_white);
print(1, 1, str);
print(15, 1, " Loaded");
print(1, 1, "gint @%7x SLmkd", GINT_VERSION);
if((uint)mpu < 4) print(16, 2, names + 8 * (mpu - 1));
else print_dec(16, 2, mpu, 6);
if((uint)mpu < 4) print(1, 2, names + 8 * (mpu - 1));
else print(1, 2, "%6d", mpu);
print(1, 2, "ROM RAM GINT");
print(4, 3, "k c d");
print_dec(1, 3, (rom_size + 0x3ff) >> 10, 3);
print_dec(6, 3, ram_size, 4);
print_dec(11, 3, gint_size, 4);
print_dec(17, 3, &mtors - &btors, 2);
print_dec(20, 3, &etors - &mtors, 2);
#ifdef FX9860G
print(8, 2, "%c?-", gint_platform.extended_ram ? 'R' : 'r');
#endif
#ifdef FXCG50
print(8, 2, "--%c", gint_platform.prizm ? 'P' : 'p');
#endif
char os[11];
__os_version(os);
print(12, 2, "OS%2s%2s%4s", os, os+3, os+6);
print(1, 3, "ROM%4dk RAM%3d+%1dk ??",
(rom_size + 0x3ff) >> 10,
(ram_size + 0x3ff) >> 10,
(gint_size + 0x3ff) >> 10);
dupdate();
}
/* bootlog_mapped() - ROM mapping stage */
GSECTION(".pretext")
void bootlog_mapped(int rom, int ram)
{
rom = (rom + 0x3ff) >> 10;
ram = (ram + 0x3ff) >> 10;
/* Check whether all ROM is mapped */
uint32_t rom_size = (uint32_t)&srom;
print(15, 1, " Mapped");
print(1, 4, "MMU ROM: k RAM: k");
(rom < 0) ? print(9, 4, "???") : print_dec(9, 4, rom, 3);
(ram < 0) ? print(18, 4, "???") : print_dec(18, 4, ram, 3);
print(20, 3, "%c%c", (rom >= (int)rom_size) ? 'F' : 'f',
isSH3() ? 'u' : 'U');
print(9, 2, (ram > 8192) ? "E" : "e");
print(19, 1, "M");
dupdate();
}
/* bootlog_unmapped() - ROM mapping stage failure */
void bootlog_unmapped(int rom, int size)
{
print(1, 6, "MMU: add-in too large");
print(1, 7, "%8x < %8x", rom, size);
dupdate();
}
/* bootlog_kernel() - gint loading stage */
void bootlog_kernel(void)
{
print(15, 1, " Kernel");
print(20, 1, "K");
}
if(isSH3())
/* bootlog_driver() - driver load
Called for very loaded driver. */
void bootlog_driver(const char *drv, const char *status)
{
/* Positioning for the driver name */
static int x = 1, y = 4;
if(y > 5)
{
print(1, 5, "ABCD");
print_hex( 6, 5, SH7705_INTC._.IPRA->word, 4);
print_hex(10, 5, SH7705_INTC._.IPRB->word, 4);
print_hex(14, 5, SH7705_INTC._.IPRC->word, 4);
print_hex(18, 5, SH7705_INTC._.IPRD->word, 4);
print(1, 6, "EFGH");
print_hex( 6, 6, SH7705_INTC._.IPRE->word, 4);
print_hex(10, 6, SH7705_INTC._.IPRF->word, 4);
print_hex(14, 6, SH7705_INTC._.IPRG->word, 4);
print_hex(18, 6, SH7705_INTC._.IPRH->word, 4);
}
else
{
print(1, 5, "ACFG");
print_hex( 6, 5, SH7305_INTC._->IPRA.word, 4);
print_hex(10, 5, SH7305_INTC._->IPRC.word, 4);
print_hex(14, 5, SH7305_INTC._->IPRF.word, 4);
print_hex(18, 5, SH7305_INTC._->IPRG.word, 4);
print(1, 6, "HJKL");
print_hex( 6, 6, SH7305_INTC._->IPRH.word, 4);
print_hex(10, 6, SH7305_INTC._->IPRJ.word, 4);
print_hex(14, 6, SH7305_INTC._->IPRK.word, 4);
print_hex(18, 6, SH7305_INTC._->IPRL.word, 4);
print(21, 4, "+");
return;
}
print(x, y, "%3s", drv);
x += 4;
if(x + y >= 22) y++;
/* Positioning for the driver message */
if(!status) return;
int len = strlen(status);
static int mx = 1, my = 6;
if(mx + len > 22) mx = 1, my++;
if(my > 9) return;
print(mx, my, "%s", status);
mx += len + 1;
dupdate();
}
/* bootlog_driver_summary() - all drivers loaded */
void bootlog_driver_summary(void)
{
int interrupts = 0;
uint16_t ipr;
print(21, 1, "D");
/* Count number of enabled interrupts */
if(isSH3()) for(int i = 0; i < 8; i++)
{
ipr = *SH7705_INTC.IPRS[i];
while(ipr > 0)
{
interrupts += (ipr & 0xf) != 0;
ipr >>= 4;
}
}
else for(int i = 0; i < 12; i++)
{
ipr = SH7305_INTC.IPRS[2 * i];
while(ipr > 0)
{
interrupts += (ipr & 0xf) != 0;
ipr >>= 4;
}
}
print(19, 5, "#%2d", interrupts);
dupdate();
}

View File

@ -3,7 +3,7 @@
//---
#include <gint/gint.h>
#include <core/memory.h>
#include <core/std.h>
#include <gint/mpu.h>
#include <gint/mpu/intc.h>

View File

@ -7,11 +7,11 @@
#include <gint/defs/types.h>
#include <gint/defs/util.h>
/* This file is only useful on fx9860g machines because all fxcg50 are SH4 */
#ifdef FX9860G
/* Holds information about the current MPU */
GBSS const platform_t gint_platform;
/* Holds the name of the current MPU; initialized at startup by mpu_init() */
GBSS const mpu_t gint_mpu_id;
/* This function is only used on fx9860g because all fxcg50 are SH4 */
#ifdef FX9860G
/* mpu_detect() - detect the underlying MPU
Many thanks to Simon Lothar for relevant documentation.
@ -21,6 +21,7 @@ GBSS const mpu_t gint_mpu_id;
by testing writable bits in the Port L Control Register (PLCR).
Returns the detected MPU type, falling back on mpu_unknown */
GSECTION(".pretext")
static mpu_t mpu_detect(void)
{
/* Processor Version Register */
@ -53,9 +54,37 @@ static mpu_t mpu_detect(void)
}
/* mpu_init() - detect and save information about the underlying MPU */
void mpu_init(void)
GSECTION(".pretext")
void mpu_init(GUNUSED uint32_t stack)
{
const_cast(gint_mpu_id, mpu_t) = mpu_detect();
const_cast(gint_platform.mpu, mpu_t) = mpu_detect();
/* Detect additional RAM */
volatile uint8_t *after_ram = (void *)0x88040000;
volatile uint8_t *start_ram = (void *)0x88000000;
uint8_t backup = *after_ram;
*after_ram = ~backup;
int ext = (*start_ram == backup);
*after_ram = backup;
const_cint(gint_platform.extended_ram) = ext;
}
#endif
#endif /* FX9860G */
#ifdef FXCG50
/* mpu_init() - detect and save information about the underlying MPU */
GSECTION(".pretext")
void mpu_init(uint32_t stack)
{
const_cast(gint_platform.mpu, mpu_t) = mpu_sh7305;
/* Detect Prizm models */
int prizm = (stack < 0x8c160000);
const_cint(gint_platform.prizm) = prizm;
}
#endif /* FXCG50 */

View File

@ -4,7 +4,7 @@
#include <gint/gint.h>
#include <gint/drivers.h>
#include <core/memory.h>
#include <core/std.h>
#include <core/setup.h>
#include <gint/mpu.h>
#include <gint/mpu/intc.h>

View File

@ -1,5 +1,5 @@
//---
// gint:core:start - Kernel initialization and C runtime
// gint:core:start - Kernel initialisation and C runtime
//--
#include <gint/defs/attributes.h>
@ -108,15 +108,15 @@ int start(int isappli, int optnum)
redirecting interrupts and reimplementing drivers, so we can't rely
too much on the system. Ladies and gentlemen, let's have fun! ;D */
/* For now, we rely on the system to map ROM pages. RAM is always
/* For now, we use the system's memory mapper for ROM. RAM is always
fully mapped, but we need to initialize it. We also need to do some
hardware detection because old fx9860g models have an different
hardware detection because old fx9860g models have a different
processor with some incompatible features */
/* Detect architecture - this will tell SH3 from SH4 on fx9860g */
#ifdef FX9860G
mpu_init();
#endif
uint32_t stack;
__asm__("mov r15, %0" : "=r"(stack));
mpu_init(stack);
/* Load data sections and wipe the bss section. This has to be done
first for static and global variables to be initialized */
@ -134,32 +134,20 @@ int start(int isappli, int optnum)
: utlb_mapped_memory(&rom, &ram);
bootlog_mapped(rom, ram);
//---
/* Cancel add-in execution if not all pages are mapped
TODO: Resort to better graphical display, although still fxlib since
add-in is not mapped yet */
/* Cancel add-in execution if not all pages are mapped */
if(rom < (uint32_t)&srom)
{
Bdisp_AllClr_VRAM();
PrintXY(0, 0, "Missing memory!", 0);
print_hex(1, 2, rom, 8);
PrintXY(0, 16, "<", 0);
print_hex(1, 4, (uint32_t)&srom, 8);
Bdisp_PutDisp_DD();
bootlog_unmapped(rom, (uint32_t)&srom);
while(1);
// delay(20);
return 1;
}
//---
/* Install gint and switch VBR */
gint_install();
bootlog_kernel();
/* We are now running on our own in kernel mode. Since we have taken
control of interrupts, pretty much any interaction with the sytem
control of interrupts, pretty much any interaction with the system
will break it. We'll limit our use of syscalls and do device driving
ourselves. (Hopefully we can add cool features in the process.) */
@ -173,7 +161,13 @@ int start(int isappli, int optnum)
if(drv->ctx_save) drv->ctx_save(drv->sys_ctx);
if(drv->init) drv->init();
#ifdef GINT_BOOT_LOG
const char *status = drv->status ? drv->status() : NULL;
bootlog_driver(drv->name, status);
#endif
}
bootlog_driver_summary();
/* With gint fully initialized, we are ready to start the hosted user
application. We have already loaded the RAM sections earlier; all

50
src/core/syscalls.S Normal file
View File

@ -0,0 +1,50 @@
/*
** gint:core:syscalls - calls to CASIOWIN
**
** This files can be seen as a list of everywhere gint relies on the
** underlying OS. Although I wish to make gint free-standing, there are
** still a few hard dependencies, namely:
** * MMU management, because doing it wrong might break the calculator.
** * Dynamic allocation, because we can't trash the system heap.
** * File system, because it's a mess and we might ruin the ROM.
*/
/* Dynamic allocation */
.global ___malloc
.global ___calloc
.global ___free
.global ___realloc
/* OS version, for debugging purposes */
.global ___os_version
.section ".pretext"
#ifdef FX9860G
/* OS version */
___os_version:
mov.l syscall_table, r2
mov.l 1f, r0
jmp @r2
nop
1: .long 0x02ee
syscall_table:
.long 0x80010070
#endif /* FX9860G */
#ifdef FXCG50
___os_version:
mov.l syscall_table, r2
mov.l 1f, r0
jmp @r2
nop
1: .long 0x1406
syscall_table:
.long 0x80020070
#endif /* FXCG50 */

View File

@ -159,7 +159,7 @@ key_event_t waitevent(volatile int *timeout)
}
//---
// Driver initialization
// Driver initialization and status
//---
static int callback(GUNUSED volatile void *arg)
@ -192,6 +192,18 @@ static void unload(void)
timer_stop(tid);
}
#ifdef GINT_BOOT_LOG
/* keysc_status() - status string of the driver */
static const char *keysc_status(void)
{
static char str[3] = "Sw";
if(isSH3()) str[0] = 's';
return str;
}
#endif /* GINT_BOOT_LOG */
//---
// Driver structure definition
//---
@ -199,6 +211,7 @@ static void unload(void)
gint_driver_t drv_keysc = {
.name = "KEYSC",
.init = init,
.status = GINT_DRIVER_STATUS(keysc_status),
.unload = unload,
.ctx_size = 0,
.sys_ctx = NULL,

View File

@ -6,7 +6,7 @@
void dpixel(int x, int y, color_t color)
{
/* Sanity checks */
if((uint)x >= 64 || (uint)y >= 128) return;
if((uint)x >= 128 || (uint)y >= 64) return;
uint32_t *lword = vram + (y << 2) + (x >> 5);
uint32_t mask = 1 << (~x & 31);

View File

@ -1,5 +1,6 @@
#define GINT_NEED_VRAM
#include <gint/defs/types.h>
#include <gint/defs/attributes.h>
#include <gint/display.h>
#include "topti-asm.h"
@ -8,6 +9,7 @@ extern font_t gint_font5x6;
font_t const * topti_font = &gint_font5x6;
/* dfont() - set the default font for text rendering */
GSECTION(".pretext")
void dfont(font_t const * font)
{
topti_font = font ? font : &gint_font5x6;
@ -28,6 +30,7 @@ enum charset
/* charset_size(): Number of elements in each character set
@set Character set ID
Returns the expected number of glyphs, -1 if charset ID is invalid. */
GSECTION(".pretext")
int charset_size(enum charset set)
{
int size[] = { 10, 26, 52, 62, 95, 128 };
@ -39,6 +42,7 @@ int charset_size(enum charset set)
-1 if [c] is not part of that set.
@set Any character set
@c Character to decode */
GSECTION(".pretext")
int charset_decode(enum charset set, uint c)
{
int x, y;
@ -76,6 +80,7 @@ int charset_decode(enum charset set, uint c)
@glyph Glyph number obtained by charset_decode(), must be nonnegative.
Returns the offset the this glyph's data in the font's data array. When
using a proportional font, the size array is not heeded for. */
GSECTION(".pretext")
int topti_offset(font_t const *f, uint glyph)
{
/* Non-proportional fonts don't need an index */
@ -110,6 +115,7 @@ int topti_offset(font_t const *f, uint glyph)
0, call topti_draw() and reset the operators. If it's neative, call
topti_draw() then do another pass of topti_split() to recover the missing
information. */
GSECTION(".pretext")
int topti_split(uint32_t const * glyph, int width, int height, int free,
uint32_t *operators)
{
@ -174,6 +180,7 @@ int topti_split(uint32_t const * glyph, int width, int height, int free,
@f Font
@asm_fg Assembler function for text rendering
@asm_bg Assembler function for background rendering */
GSECTION(".pretext")
void topti_render(int x, int y, const char *str, font_t const *f,
asm_text_t *asm_fg, asm_text_t *asm_bg)
{
@ -291,6 +298,7 @@ void dsize(const char *str, font_t const * f, int *w, int *h)
}
/* dtext() - display a string of text */
GSECTION(".pretext")
void dtext(int x, int y, const char *str, color_t fg, color_t bg)
{
if((uint)fg >= 8 || (uint)bg >= 8) return;

96
src/std/string.c Normal file
View File

@ -0,0 +1,96 @@
//---
// gint:core:string - replicas of a few string functions
//---
#include <gint/defs/types.h>
#include <gint/defs/attributes.h>
#include <stdarg.h>
GWEAK size_t strlen(const char *str)
{
int len = 0;
while(str[len]) len++;
return len;
}
/* vsprintf() - a trimmed-down version of the function
This function supports formats '%%', '%nd', '%nx' and '%s' where 'n' is a
1-digit size, and is mandatory. For '%d' and '%x', '0' is always set.
Always outputs exactly the requested number of characters, even if it's not
enough to completely print the value.
Does whatever it wants if the format is invalid. This is really a basic
function to format output without needing 18 kB of code. */
GWEAK void vsprintf(char *str, const char *format, va_list args)
{
#define in() (c = *format++)
const char *digits = "0123456789abcdef";
int c, len;
while(in())
{
if(c != '%')
{
*str++ = c;
continue;
}
in();
/* Length indications (only one character, not '%12d') */
if(c >= '0' && c <= '9') len = c - '0', in();
else len = -1;
if(c == '%')
{
*str++ = '%';
}
else if(c == 'd')
{
int n = va_arg(args, int);
if(n < 0) *str++ = '-', n = -n, len--;
for(int i = len - 1; i >= 0; i--)
{
int m = n / 10;
str[i] = digits[n - 10 * m];
n = m;
}
str += len;
}
else if(c == 'x')
{
uint32_t n = va_arg(args, uint32_t);
for(int i = len - 1; i >= 0; i--)
{
str[i] = digits[n & 0xf];
n >>= 4;
}
str += len;
}
else if(c == 'c')
{
int c = va_arg(args, int);
*str++ = c;
}
else if(c == 's')
{
const char *s = va_arg(args, const char *);
while(*s && len) *str++ = *s++, len--;
}
}
*str = 0;
#undef in
#undef out
}
/* sprintf() */
GWEAK void sprintf(char *str, const char *format, ...)
{
va_list args;
va_start(args, format);
vsprintf(str, format, args);
va_end(args);
}

View File

@ -198,6 +198,21 @@ static void ctx_restore(void *buf)
command(reg_counter, cnt);
}
//---
// Driver status string
//---
#ifdef GINT_BOOT_LOG
/* t6k11_status() - status string of the driver */
static const char *t6k11_status(void)
{
/* TODO: t6k11: Detect backlight existence */
return "6K11-cB";
}
#endif /* GINT_BOOT_LOG */
//---
// Driver structure definition
//---
@ -205,6 +220,7 @@ static void ctx_restore(void *buf)
gint_driver_t drv_t6k11 = {
.name = "T6K11",
.init = NULL,
.status = GINT_DRIVER_STATUS(t6k11_status),
.ctx_size = sizeof(ctx_t),
.sys_ctx = &sys_ctx,
.ctx_save = ctx_save,

View File

@ -367,6 +367,50 @@ static void init(void)
}
}
//---
// Status function
//---
#ifdef GINT_BOOT_LOG
/* tmu_status() - status string of extra TMUs for the boot log
The status string has a two-character code for each of the extra timers.
The first character is a digit character describing a value between 0 and 7.
* Bit 0 is set if TCOR=0xffffffff
* Bit 1 is set if TCNT=0xffffffff
* Bit 2 is set if TSTR=0
The second character indicates the status of interrupts.
* "D" (Disabled) if UNIE=0, UNF=0
* "L" (Low) if UNIE=1, UNF=0
* "H" (High) if UNIE=1, UNF=1
* "!" (Error) if UNIE=0, UNF=1
So the normal status string would be made of "7D"'s. */
static const char *tmu_status(void)
{
static char status[18] = "ETMU ";
int j = 5;
for(int i = 3; i < timer_count(); i++)
{
tmu_extra_t *t = timers[i].tmu;
int v1 = (!(t->TCOR + 1))
| (!(t->TCNT + 1) << 1)
| (!(t->TSTR) << 2);
int v2 = (t->TCR.UNF << 1) | (t->TCR.UNIE);
status[j++] = '0' + v1;
status[j++] = "DLH!"[v2];
}
status[j] = 0;
return status;
}
#endif /* GINT_BOOT_LOG */
//---
// Context system for this driver
//---
@ -444,6 +488,7 @@ gint_driver_t drv_tmu = {
.name = "TMU",
.driver_sh3 = GINT_DRIVER_SH3(driver_sh3),
.init = init,
.status = GINT_DRIVER_STATUS(tmu_status),
.ctx_size = sizeof(ctx_t),
.sys_ctx = &sys_ctx,
.ctx_save = ctx_save,