mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 20:43: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: $(all-targets)
|
||||||
|
|
||||||
all-build%: build%
|
all-build%: build%
|
||||||
@ echo -e "$B::$W Making into $<$N"
|
@ echo -e "\n$B::$W Making into $<$N"
|
||||||
@ $(MAKE) --no-print-directory -C $<
|
@ $(MAKE) --no-print-directory -C $<
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -33,7 +33,7 @@ install-targets := $(foreach b,$(builds),install-$b)
|
||||||
install: $(install-targets)
|
install: $(install-targets)
|
||||||
|
|
||||||
install-build%: build%
|
install-build%: build%
|
||||||
@ echo -e "$B::$W Installing from $<$N"
|
@ echo -e "\n$B::$W Installing from $<$N"
|
||||||
@ $(MAKE) --no-print-directory -C $< install
|
@ $(MAKE) --no-print-directory -C $< install
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -45,7 +45,7 @@ uninstall-targets := $(foreach b,$(builds),uninstall-$b)
|
||||||
uninstall: $(uninstall-targets)
|
uninstall: $(uninstall-targets)
|
||||||
|
|
||||||
uninstall-build%: build%
|
uninstall-build%: build%
|
||||||
@ echo -e "$B::$W Uninstalling from $<$N"
|
@ echo -e "\n$B::$W Uninstalling from $<$N"
|
||||||
@ $(MAKE) --no-print-directory -C $< uninstall
|
@ $(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:
|
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
|
* 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
|
* Blazingly fast drawing functions when working with the fxSDK (image rendering
|
||||||
is 10 times faster than MonochromeLib)
|
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:
|
Crucial, missing things.
|
||||||
- Complete memory functions in [core/memory.c]
|
! core: the four basic memory functions
|
||||||
- Finish the boot log in <core/bootlog.h>
|
! core: build an exception handler and a TLB miss handler
|
||||||
- Finish the boot log in [core/bootlog.c]
|
! core: gint_switch() (driver contexts on stack; arbitrary code?)
|
||||||
- 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()
|
|
||||||
|
|
||||||
* Make keysc/keysc.c/state static and review forgotten global variables
|
Tests to run.
|
||||||
* Find out what happened to the clock frequency on fxcg50
|
* core: run the alignment/size automated tests
|
||||||
* Implement profiling
|
* bopti: more sizes, gray
|
||||||
* Save and restore interrupt masks
|
* topti: all charsets, colors
|
||||||
* More keyboard
|
|
||||||
|
|
||||||
Strange, (irreproducible?) SysERRORs on SH3?
|
Completeness elements on existing code.
|
||||||
- Happened when dealing with overclock and after a transfer
|
* keyboard: finish the interface
|
||||||
- SysERROR when add-in fully returns, nothing during execution
|
* clock: spread spectrum on fxcg50
|
||||||
- Affects all add-ins of the calculator!
|
* 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
|
Keep in mind.
|
||||||
interrupts
|
* 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
|
Future directions.
|
||||||
* Don't hardcode fx-cg50 stack address in fxcg50.ld for Prizm compatibility
|
|
||||||
* Implement the gint_switch()
|
|
||||||
* File management
|
* File management
|
||||||
* Drawing functions, bopti and tales
|
|
||||||
* Gray engine
|
* Gray engine
|
||||||
* Overclock
|
* Integrate overclock management
|
||||||
* Add a driver init function to the r61524 driver.
|
* A library for profiling with manual calls
|
||||||
* Finish the bootlog and use the keyboard to control it.
|
* Audio playback using Martin Poupe's method
|
||||||
* Save driver contexts on the stack in gint_pause().
|
* Serial communication [SCIF] [SCIFA]
|
||||||
* Write the core memory functions.
|
* USB communication [USB]
|
||||||
- Allow arbitrary code in gint_pause() instead of just main menu?
|
* Driver for the watchdog timer [WDT] [SH7705]
|
||||||
- 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
|
|
||||||
|
|
|
@ -5,10 +5,18 @@
|
||||||
#ifndef GINT_CORE_BOOTLOG
|
#ifndef GINT_CORE_BOOTLOG
|
||||||
#define GINT_CORE_BOOTLOG
|
#define GINT_CORE_BOOTLOG
|
||||||
|
|
||||||
|
#include <gint/defs/attributes.h>
|
||||||
|
|
||||||
/* bootlog_loaded() - section loading stage
|
/* bootlog_loaded() - section loading stage
|
||||||
Called when RAM sections have been wiped and copied */
|
Called when RAM sections have been wiped and copied */
|
||||||
void bootlog_loaded(void);
|
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
|
/* bootlog_mapped() - ROM mapping stage
|
||||||
Called after all ROM pages have been traversed. All of them may not have
|
Called after all ROM pages have been traversed. All of them may not have
|
||||||
been mapped.
|
been mapped.
|
||||||
|
@ -21,11 +29,19 @@ void bootlog_mapped(uint32_t rom, uint32_t ram);
|
||||||
handlers set up. */
|
handlers set up. */
|
||||||
void bootlog_kernel(void);
|
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 */
|
/* All these functions are enabled only if GINT_BOOT_LOG is defined */
|
||||||
#ifndef GINT_BOOT_LOG
|
#ifndef GINT_BOOT_LOG
|
||||||
#define bootlog_loaded(...)
|
#define bootlog_loaded(...)
|
||||||
|
#define bootlog_unmapped(...)
|
||||||
#define bootlog_mapped(...)
|
#define bootlog_mapped(...)
|
||||||
#define bootlog_kernel(...)
|
#define bootlog_kernel(...)
|
||||||
|
#define bootlog_driver(...)
|
||||||
|
#define bootlog_driver_summary(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* GINT_CORE_BOOTLOG */
|
#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 */
|
access sizes silently fail - honestly you don't want this to happen */
|
||||||
#define GPACKED(x) __attribute__((packed, aligned(x)))
|
#define GPACKED(x) __attribute__((packed, aligned(x)))
|
||||||
|
|
||||||
|
/* Weak symbols */
|
||||||
|
#define GWEAK __attribute__((weak))
|
||||||
|
|
||||||
#endif /* GINT_DEFS_ATTRIBUTES */
|
#endif /* GINT_DEFS_ATTRIBUTES */
|
||||||
|
|
|
@ -27,7 +27,9 @@ extern uint32_t *vram;
|
||||||
|
|
||||||
#ifdef FX9860G
|
#ifdef FX9860G
|
||||||
#include <gint/display-fx.h>
|
#include <gint/display-fx.h>
|
||||||
#else
|
#endif
|
||||||
|
|
||||||
|
#ifdef FXCG50
|
||||||
#include <gint/display-cg.h>
|
#include <gint/display-cg.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -9,16 +9,29 @@
|
||||||
#include <gint/defs/types.h>
|
#include <gint/defs/types.h>
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Driver initialization
|
// Driver procedure flow
|
||||||
//
|
//
|
||||||
// Drivers are initialized in linking order. For each driver, the
|
// Drivers are initialized in priority order, and in linking order within
|
||||||
// following functions are called:
|
// the same priority (which is pretty much undefined). Make sure every
|
||||||
// - driver_sh3() [if running on an SH3-based machine]
|
// driver's priority level is higher than those of its dependencies.
|
||||||
// - ctx_save()
|
|
||||||
// - init()
|
|
||||||
//
|
//
|
||||||
// When the driver is unloaded, the following functions are called:
|
// At initialization, the following functions are called:
|
||||||
// - ctx_restore()
|
// 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 */
|
/* gint_driver_t - driver meta-information used by gint */
|
||||||
|
@ -65,6 +78,14 @@ typedef struct
|
||||||
@ctx A context buffer filled by ctx_save() */
|
@ctx A context buffer filled by ctx_save() */
|
||||||
void (*ctx_restore)(void *ctx);
|
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;
|
} GPACKED(4) gint_driver_t;
|
||||||
|
|
||||||
/* GINT_DECLARE_DRIVER() - make a driver visible to gint
|
/* GINT_DECLARE_DRIVER() - make a driver visible to gint
|
||||||
|
@ -81,11 +102,26 @@ typedef struct
|
||||||
GSECTION(".gint.drivers." #level) extern gint_driver_t name;
|
GSECTION(".gint.drivers." #level) extern gint_driver_t name;
|
||||||
|
|
||||||
/* GINT_DRIVER_SH3() - declare a function for SH3-rectification
|
/* 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
|
#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
|
#else
|
||||||
#define GINT_DRIVER_SH3(name) NULL
|
#define GINT_DRIVER_STATUS(name) NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* GINT_DRIVERS */
|
#endif /* GINT_DRIVERS */
|
||||||
|
|
|
@ -8,20 +8,11 @@
|
||||||
#include <gint/defs/types.h>
|
#include <gint/defs/types.h>
|
||||||
|
|
||||||
/* GINT_VERSION - the library version number
|
/* 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
|
gint is versioned from it's repository commits on the master branch. The
|
||||||
+---------------+---------------+---------------+---------------+
|
GINT_VERSION integer contains the short commit hash.
|
||||||
| channel | major | minor | build |
|
|
||||||
+---------------+---------------+---------------+---------------+
|
|
||||||
|
|
||||||
The first field is a letter indicating the type of version ('a'lpha, 'b'eta,
|
For instance, 0x03f7c0a0 means commit 3f7c0a0. */
|
||||||
'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 */
|
|
||||||
extern char GINT_VERSION;
|
extern char GINT_VERSION;
|
||||||
#define GINT_VERSION ((uint32_t)&GINT_VERSION)
|
#define GINT_VERSION ((uint32_t)&GINT_VERSION)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#ifndef GINT_CORE_MPU
|
#ifndef GINT_CORE_MPU
|
||||||
#define GINT_CORE_MPU
|
#define GINT_CORE_MPU
|
||||||
|
|
||||||
|
#include <gint/defs/types.h>
|
||||||
|
|
||||||
/* mpu_t - supported MPUs */
|
/* mpu_t - supported MPUs */
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
@ -22,27 +24,64 @@ typedef enum
|
||||||
mpu_sh7724 = 4, /* For reference */
|
mpu_sh7724 = 4, /* For reference */
|
||||||
} mpu_t;
|
} 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
|
#ifdef FX9860G
|
||||||
|
|
||||||
/* mpu_id() - get the name of the underlying MPU */
|
typedef struct
|
||||||
extern const mpu_t gint_mpu_id;
|
{
|
||||||
#define gint_mpu() (gint_mpu_id)
|
/* 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 */
|
} platform_t;
|
||||||
#define isSH3() (gint_mpu() & 1)
|
|
||||||
#define isSH4() (!isSH3())
|
|
||||||
|
|
||||||
/* mpu_init() - probe the MPU type
|
/* mpu_id() - get the name of the underlying MPU */
|
||||||
This function must be executed before mpu_id() can be used. */
|
#define gint_mpu() (gint_platform.mpu)
|
||||||
void mpu_init(void);
|
|
||||||
|
|
||||||
#else /* FXCG50 */
|
/* Quick SH-3/SH-4 tests. Unknown models are assumed to be SH-4A */
|
||||||
|
#define isSH3() (gint_mpu() & 1)
|
||||||
/* All fxcg50 machines have an SH7305, which makes things simpler. */
|
#define isSH4() (!isSH3())
|
||||||
#define gint_mpu() mpu_sh7305
|
|
||||||
#define isSH3() 0
|
|
||||||
#define isSH4() 1
|
|
||||||
|
|
||||||
#endif /* FX9860G */
|
#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 */
|
#endif /* GINT_CORE_MPU */
|
||||||
|
|
|
@ -65,6 +65,7 @@ typedef volatile struct
|
||||||
uint32_t CKOFF :1; /* CKO Output Stop */
|
uint32_t CKOFF :1; /* CKO Output Stop */
|
||||||
uint32_t :1;
|
uint32_t :1;
|
||||||
);
|
);
|
||||||
|
/* TODO: CPG: Add the SSCGCR register */
|
||||||
pad(0x28);
|
pad(0x28);
|
||||||
|
|
||||||
lword_union(FLLFRQ,
|
lword_union(FLLFRQ,
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <gint/drivers.h>
|
#include <gint/drivers.h>
|
||||||
#include <gint/clock.h>
|
#include <gint/clock.h>
|
||||||
|
#include <core/std.h>
|
||||||
|
|
||||||
#include <gint/mpu.h>
|
#include <gint/mpu.h>
|
||||||
#include <gint/mpu/cpg.h>
|
#include <gint/mpu/cpg.h>
|
||||||
|
@ -53,8 +54,7 @@ static void sh7705_probe(void)
|
||||||
freq.Iphi_div = idiv + 1;
|
freq.Iphi_div = idiv + 1;
|
||||||
freq.Pphi_div = pdiv + 1;
|
freq.Pphi_div = pdiv + 1;
|
||||||
|
|
||||||
/* Deduce the frequency of the main clocks. The following piece of code
|
/* Deduce the frequency of the main clocks. This value is ckio/3 */
|
||||||
hardcodes ckio / 3 and avoids using the division operator */
|
|
||||||
int ckio_3 = 9830400;
|
int ckio_3 = 9830400;
|
||||||
|
|
||||||
/* Exchange the setting values 2 and 3 */
|
/* Exchange the setting values 2 and 3 */
|
||||||
|
@ -68,11 +68,6 @@ static void sh7705_probe(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef CPG
|
#undef CPG
|
||||||
#else
|
|
||||||
|
|
||||||
/* This prototype will silence warnings on fxcg50 */
|
|
||||||
void sh7705_probe(void);
|
|
||||||
|
|
||||||
#endif /* FX9860G */
|
#endif /* FX9860G */
|
||||||
|
|
||||||
//---
|
//---
|
||||||
|
@ -122,15 +117,36 @@ static void sh7305_probe(void)
|
||||||
// Other driver stuff
|
// 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)
|
static void init(void)
|
||||||
{
|
{
|
||||||
isSH3() ? sh7705_probe()
|
/* This avoids warnings about sh7705() not being defined on fxcg50 */
|
||||||
: sh7305_probe();
|
#ifdef FX9860G
|
||||||
|
isSH3() ? sh7705_probe() :
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sh7305_probe();
|
||||||
}
|
}
|
||||||
|
|
||||||
gint_driver_t drv_cpg = {
|
gint_driver_t drv_cpg = {
|
||||||
.name = "CPG",
|
.name = "CPG",
|
||||||
.init = init,
|
.init = init,
|
||||||
|
.status = GINT_DRIVER_STATUS(cpg_status),
|
||||||
.ctx_size = 0,
|
.ctx_size = 0,
|
||||||
.sys_ctx = NULL,
|
.sys_ctx = NULL,
|
||||||
.ctx_save = NULL,
|
.ctx_save = NULL,
|
||||||
|
|
|
@ -2,16 +2,22 @@
|
||||||
// gint:core:bootlog - Boot-time on-screen log for extreme debugging
|
// gint:core:bootlog - Boot-time on-screen log for extreme debugging
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/* TODO: Review, enhance and fix bootlog */
|
|
||||||
|
|
||||||
#include <gint/defs/types.h>
|
#include <gint/defs/types.h>
|
||||||
|
#include <core/std.h>
|
||||||
|
#include <core/mmu.h>
|
||||||
|
|
||||||
#include <gint/mpu.h>
|
#include <gint/mpu.h>
|
||||||
#include <gint/mpu/intc.h>
|
#include <gint/mpu/intc.h>
|
||||||
#include <core/mmu.h>
|
|
||||||
#include <gint/gint.h>
|
#include <gint/gint.h>
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
|
#include <core/syscalls.h>
|
||||||
|
#include <gint/clock.h>
|
||||||
|
|
||||||
#ifdef FXCG50
|
#ifdef FXCG50
|
||||||
|
void Bdisp_AllClr_VRAM(void);
|
||||||
|
void Bdisp_PutDisp_DD(void);
|
||||||
|
|
||||||
#define dclear(c) Bdisp_AllClr_VRAM()
|
#define dclear(c) Bdisp_AllClr_VRAM()
|
||||||
#define dupdate() Bdisp_PutDisp_DD()
|
#define dupdate() Bdisp_PutDisp_DD()
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,28 +28,34 @@ extern char
|
||||||
sgdata, sgbss, sdata, sbss,
|
sgdata, sgbss, sdata, sbss,
|
||||||
btors, mtors, etors;
|
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 */
|
/* bootlog_loaded() - section loading stage */
|
||||||
|
GSECTION(".pretext")
|
||||||
void bootlog_loaded(void)
|
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 */
|
/* Size of memory sections */
|
||||||
uint32_t rom_size = (uint32_t)&srom;
|
uint32_t rom_size = (uint32_t)&srom;
|
||||||
uint32_t ram_size = (uint32_t)&sdata + (uint32_t)&sbss;
|
uint32_t ram_size = (uint32_t)&sdata + (uint32_t)&sbss;
|
||||||
uint32_t gint_size = (uint32_t)&sgdata + (uint32_t)&sgbss;
|
uint32_t gint_size = (uint32_t)&sgdata + (uint32_t)&sgbss;
|
||||||
|
|
||||||
/* MPU type */
|
/* MPU type */
|
||||||
mpu_t mpu = gint_mpu();
|
mpu_t mpu = gint_mpu();
|
||||||
|
@ -51,68 +63,121 @@ void bootlog_loaded(void)
|
||||||
|
|
||||||
/* TODO: Use a solid API for boot-time printing */
|
/* TODO: Use a solid API for boot-time printing */
|
||||||
dclear(color_white);
|
dclear(color_white);
|
||||||
print(1, 1, str);
|
print(1, 1, "gint @%7x SLmkd", GINT_VERSION);
|
||||||
print(15, 1, " Loaded");
|
|
||||||
|
|
||||||
if((uint)mpu < 4) print(16, 2, names + 8 * (mpu - 1));
|
if((uint)mpu < 4) print(1, 2, names + 8 * (mpu - 1));
|
||||||
else print_dec(16, 2, mpu, 6);
|
else print(1, 2, "%6d", mpu);
|
||||||
|
|
||||||
print(1, 2, "ROM RAM GINT");
|
#ifdef FX9860G
|
||||||
print(4, 3, "k c d");
|
print(8, 2, "%c?-", gint_platform.extended_ram ? 'R' : 'r');
|
||||||
print_dec(1, 3, (rom_size + 0x3ff) >> 10, 3);
|
#endif
|
||||||
print_dec(6, 3, ram_size, 4);
|
|
||||||
print_dec(11, 3, gint_size, 4);
|
#ifdef FXCG50
|
||||||
print_dec(17, 3, &mtors - &btors, 2);
|
print(8, 2, "--%c", gint_platform.prizm ? 'P' : 'p');
|
||||||
print_dec(20, 3, &etors - &mtors, 2);
|
#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();
|
dupdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bootlog_mapped() - ROM mapping stage */
|
/* bootlog_mapped() - ROM mapping stage */
|
||||||
|
GSECTION(".pretext")
|
||||||
void bootlog_mapped(int rom, int ram)
|
void bootlog_mapped(int rom, int ram)
|
||||||
{
|
{
|
||||||
rom = (rom + 0x3ff) >> 10;
|
/* Check whether all ROM is mapped */
|
||||||
ram = (ram + 0x3ff) >> 10;
|
uint32_t rom_size = (uint32_t)&srom;
|
||||||
|
|
||||||
print(15, 1, " Mapped");
|
print(20, 3, "%c%c", (rom >= (int)rom_size) ? 'F' : 'f',
|
||||||
print(1, 4, "MMU ROM: k RAM: k");
|
isSH3() ? 'u' : 'U');
|
||||||
(rom < 0) ? print(9, 4, "???") : print_dec(9, 4, rom, 3);
|
print(9, 2, (ram > 8192) ? "E" : "e");
|
||||||
(ram < 0) ? print(18, 4, "???") : print_dec(18, 4, ram, 3);
|
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();
|
dupdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bootlog_kernel() - gint loading stage */
|
/* bootlog_kernel() - gint loading stage */
|
||||||
void bootlog_kernel(void)
|
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(21, 4, "+");
|
||||||
print_hex( 6, 5, SH7705_INTC._.IPRA->word, 4);
|
return;
|
||||||
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(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();
|
dupdate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#include <gint/gint.h>
|
#include <gint/gint.h>
|
||||||
#include <core/memory.h>
|
#include <core/std.h>
|
||||||
#include <gint/mpu.h>
|
#include <gint/mpu.h>
|
||||||
#include <gint/mpu/intc.h>
|
#include <gint/mpu/intc.h>
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,11 @@
|
||||||
#include <gint/defs/types.h>
|
#include <gint/defs/types.h>
|
||||||
#include <gint/defs/util.h>
|
#include <gint/defs/util.h>
|
||||||
|
|
||||||
/* This file is only useful on fx9860g machines because all fxcg50 are SH4 */
|
/* Holds information about the current MPU */
|
||||||
#ifdef FX9860G
|
GBSS const platform_t gint_platform;
|
||||||
|
|
||||||
/* Holds the name of the current MPU; initialized at startup by mpu_init() */
|
/* This function is only used on fx9860g because all fxcg50 are SH4 */
|
||||||
GBSS const mpu_t gint_mpu_id;
|
#ifdef FX9860G
|
||||||
|
|
||||||
/* mpu_detect() - detect the underlying MPU
|
/* mpu_detect() - detect the underlying MPU
|
||||||
Many thanks to Simon Lothar for relevant documentation.
|
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).
|
by testing writable bits in the Port L Control Register (PLCR).
|
||||||
|
|
||||||
Returns the detected MPU type, falling back on mpu_unknown */
|
Returns the detected MPU type, falling back on mpu_unknown */
|
||||||
|
GSECTION(".pretext")
|
||||||
static mpu_t mpu_detect(void)
|
static mpu_t mpu_detect(void)
|
||||||
{
|
{
|
||||||
/* Processor Version Register */
|
/* Processor Version Register */
|
||||||
|
@ -53,9 +54,37 @@ static mpu_t mpu_detect(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mpu_init() - detect and save information about the underlying MPU */
|
/* 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/gint.h>
|
||||||
#include <gint/drivers.h>
|
#include <gint/drivers.h>
|
||||||
#include <core/memory.h>
|
#include <core/std.h>
|
||||||
#include <core/setup.h>
|
#include <core/setup.h>
|
||||||
#include <gint/mpu.h>
|
#include <gint/mpu.h>
|
||||||
#include <gint/mpu/intc.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>
|
#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
|
redirecting interrupts and reimplementing drivers, so we can't rely
|
||||||
too much on the system. Ladies and gentlemen, let's have fun! ;D */
|
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
|
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 */
|
processor with some incompatible features */
|
||||||
|
|
||||||
/* Detect architecture - this will tell SH3 from SH4 on fx9860g */
|
/* Detect architecture - this will tell SH3 from SH4 on fx9860g */
|
||||||
#ifdef FX9860G
|
uint32_t stack;
|
||||||
mpu_init();
|
__asm__("mov r15, %0" : "=r"(stack));
|
||||||
#endif
|
mpu_init(stack);
|
||||||
|
|
||||||
/* Load data sections and wipe the bss section. This has to be done
|
/* Load data sections and wipe the bss section. This has to be done
|
||||||
first for static and global variables to be initialized */
|
first for static and global variables to be initialized */
|
||||||
|
@ -134,32 +134,20 @@ int start(int isappli, int optnum)
|
||||||
: utlb_mapped_memory(&rom, &ram);
|
: utlb_mapped_memory(&rom, &ram);
|
||||||
bootlog_mapped(rom, ram);
|
bootlog_mapped(rom, ram);
|
||||||
|
|
||||||
//---
|
/* Cancel add-in execution if not all pages are mapped */
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
if(rom < (uint32_t)&srom)
|
if(rom < (uint32_t)&srom)
|
||||||
{
|
{
|
||||||
Bdisp_AllClr_VRAM();
|
bootlog_unmapped(rom, (uint32_t)&srom);
|
||||||
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();
|
|
||||||
while(1);
|
while(1);
|
||||||
// delay(20);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---
|
|
||||||
|
|
||||||
/* Install gint and switch VBR */
|
/* Install gint and switch VBR */
|
||||||
gint_install();
|
gint_install();
|
||||||
bootlog_kernel();
|
bootlog_kernel();
|
||||||
|
|
||||||
/* We are now running on our own in kernel mode. Since we have taken
|
/* 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
|
will break it. We'll limit our use of syscalls and do device driving
|
||||||
ourselves. (Hopefully we can add cool features in the process.) */
|
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->ctx_save) drv->ctx_save(drv->sys_ctx);
|
||||||
if(drv->init) drv->init();
|
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
|
/* With gint fully initialized, we are ready to start the hosted user
|
||||||
application. We have already loaded the RAM sections earlier; all
|
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)
|
static int callback(GUNUSED volatile void *arg)
|
||||||
|
@ -192,6 +192,18 @@ static void unload(void)
|
||||||
timer_stop(tid);
|
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
|
// Driver structure definition
|
||||||
//---
|
//---
|
||||||
|
@ -199,6 +211,7 @@ static void unload(void)
|
||||||
gint_driver_t drv_keysc = {
|
gint_driver_t drv_keysc = {
|
||||||
.name = "KEYSC",
|
.name = "KEYSC",
|
||||||
.init = init,
|
.init = init,
|
||||||
|
.status = GINT_DRIVER_STATUS(keysc_status),
|
||||||
.unload = unload,
|
.unload = unload,
|
||||||
.ctx_size = 0,
|
.ctx_size = 0,
|
||||||
.sys_ctx = NULL,
|
.sys_ctx = NULL,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
void dpixel(int x, int y, color_t color)
|
void dpixel(int x, int y, color_t color)
|
||||||
{
|
{
|
||||||
/* Sanity checks */
|
/* 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 *lword = vram + (y << 2) + (x >> 5);
|
||||||
uint32_t mask = 1 << (~x & 31);
|
uint32_t mask = 1 << (~x & 31);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#define GINT_NEED_VRAM
|
#define GINT_NEED_VRAM
|
||||||
#include <gint/defs/types.h>
|
#include <gint/defs/types.h>
|
||||||
|
#include <gint/defs/attributes.h>
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
#include "topti-asm.h"
|
#include "topti-asm.h"
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ extern font_t gint_font5x6;
|
||||||
font_t const * topti_font = &gint_font5x6;
|
font_t const * topti_font = &gint_font5x6;
|
||||||
|
|
||||||
/* dfont() - set the default font for text rendering */
|
/* dfont() - set the default font for text rendering */
|
||||||
|
GSECTION(".pretext")
|
||||||
void dfont(font_t const * font)
|
void dfont(font_t const * font)
|
||||||
{
|
{
|
||||||
topti_font = font ? font : &gint_font5x6;
|
topti_font = font ? font : &gint_font5x6;
|
||||||
|
@ -28,6 +30,7 @@ enum charset
|
||||||
/* charset_size(): Number of elements in each character set
|
/* charset_size(): Number of elements in each character set
|
||||||
@set Character set ID
|
@set Character set ID
|
||||||
Returns the expected number of glyphs, -1 if charset ID is invalid. */
|
Returns the expected number of glyphs, -1 if charset ID is invalid. */
|
||||||
|
GSECTION(".pretext")
|
||||||
int charset_size(enum charset set)
|
int charset_size(enum charset set)
|
||||||
{
|
{
|
||||||
int size[] = { 10, 26, 52, 62, 95, 128 };
|
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.
|
-1 if [c] is not part of that set.
|
||||||
@set Any character set
|
@set Any character set
|
||||||
@c Character to decode */
|
@c Character to decode */
|
||||||
|
GSECTION(".pretext")
|
||||||
int charset_decode(enum charset set, uint c)
|
int charset_decode(enum charset set, uint c)
|
||||||
{
|
{
|
||||||
int x, y;
|
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.
|
@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
|
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. */
|
using a proportional font, the size array is not heeded for. */
|
||||||
|
GSECTION(".pretext")
|
||||||
int topti_offset(font_t const *f, uint glyph)
|
int topti_offset(font_t const *f, uint glyph)
|
||||||
{
|
{
|
||||||
/* Non-proportional fonts don't need an index */
|
/* 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
|
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
|
topti_draw() then do another pass of topti_split() to recover the missing
|
||||||
information. */
|
information. */
|
||||||
|
GSECTION(".pretext")
|
||||||
int topti_split(uint32_t const * glyph, int width, int height, int free,
|
int topti_split(uint32_t const * glyph, int width, int height, int free,
|
||||||
uint32_t *operators)
|
uint32_t *operators)
|
||||||
{
|
{
|
||||||
|
@ -174,6 +180,7 @@ int topti_split(uint32_t const * glyph, int width, int height, int free,
|
||||||
@f Font
|
@f Font
|
||||||
@asm_fg Assembler function for text rendering
|
@asm_fg Assembler function for text rendering
|
||||||
@asm_bg Assembler function for background rendering */
|
@asm_bg Assembler function for background rendering */
|
||||||
|
GSECTION(".pretext")
|
||||||
void topti_render(int x, int y, const char *str, font_t const *f,
|
void topti_render(int x, int y, const char *str, font_t const *f,
|
||||||
asm_text_t *asm_fg, asm_text_t *asm_bg)
|
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 */
|
/* dtext() - display a string of text */
|
||||||
|
GSECTION(".pretext")
|
||||||
void dtext(int x, int y, const char *str, color_t fg, color_t bg)
|
void dtext(int x, int y, const char *str, color_t fg, color_t bg)
|
||||||
{
|
{
|
||||||
if((uint)fg >= 8 || (uint)bg >= 8) return;
|
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);
|
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
|
// Driver structure definition
|
||||||
//---
|
//---
|
||||||
|
@ -205,6 +220,7 @@ static void ctx_restore(void *buf)
|
||||||
gint_driver_t drv_t6k11 = {
|
gint_driver_t drv_t6k11 = {
|
||||||
.name = "T6K11",
|
.name = "T6K11",
|
||||||
.init = NULL,
|
.init = NULL,
|
||||||
|
.status = GINT_DRIVER_STATUS(t6k11_status),
|
||||||
.ctx_size = sizeof(ctx_t),
|
.ctx_size = sizeof(ctx_t),
|
||||||
.sys_ctx = &sys_ctx,
|
.sys_ctx = &sys_ctx,
|
||||||
.ctx_save = ctx_save,
|
.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
|
// Context system for this driver
|
||||||
//---
|
//---
|
||||||
|
@ -444,6 +488,7 @@ gint_driver_t drv_tmu = {
|
||||||
.name = "TMU",
|
.name = "TMU",
|
||||||
.driver_sh3 = GINT_DRIVER_SH3(driver_sh3),
|
.driver_sh3 = GINT_DRIVER_SH3(driver_sh3),
|
||||||
.init = init,
|
.init = init,
|
||||||
|
.status = GINT_DRIVER_STATUS(tmu_status),
|
||||||
.ctx_size = sizeof(ctx_t),
|
.ctx_size = sizeof(ctx_t),
|
||||||
.sys_ctx = &sys_ctx,
|
.sys_ctx = &sys_ctx,
|
||||||
.ctx_save = ctx_save,
|
.ctx_save = ctx_save,
|
||||||
|
|
Loading…
Reference in a new issue