mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23:36 +01:00
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:
parent
417340ce91
commit
f33cb3cf80
27 changed files with 645 additions and 251 deletions
6
Makefile
6
Makefile
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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
120
TODO
|
@ -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]
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
29
include/core/std.h
Normal 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
11
include/core/syscalls.h
Normal 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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
50
src/core/syscalls.S
Normal 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 */
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
96
src/std/string.c
Normal 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);
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue