Compare commits

..

No commits in common. "dev" and "master" have entirely different histories.
dev ... master

170 changed files with 1050 additions and 3987 deletions

View File

@ -22,7 +22,7 @@ else()
endif()
configure_file(include/gint/config.h.in include/gint/config.h)
set(SOURCES
set(SOURCES_COMMON
# Clock Pulse Generator driver
src/cpg/cpg.c
src/cpg/overclock.c
@ -70,49 +70,6 @@ set(SOURCES
src/fs/fugue/fugue_rmdir.c
src/fs/fugue/fugue_unlink.c
src/fs/fugue/util.c
# GDB remote serial protocol
src/gdb/gdb.c
src/gdb/gdb.S
# Gray engine
src/gray/engine.c
src/gray/gclear.c
src/gray/ggetpixel.c
src/gray/gint_gline.c
src/gray/gpixel.c
src/gray/grect.c
src/gray/gsubimage.c
src/gray/gtext.c
# Image library
src/image/image_alloc.c
src/image/image_alloc_palette.c
src/image/image_alpha.c
src/image/image_clear.c
src/image/image_copy.c
src/image/image_copy_alloc.c
src/image/image_copy_palette.c
src/image/image_create.c
src/image/image_create_vram.c
src/image/image_data_size.c
src/image/image_decode_pixel.c
src/image/image_fill.c
src/image/image_free.c
src/image/image_get_pixel.c
src/image/image_hflip.c
src/image/image_hflip_alloc.c
src/image/image_linear.c
src/image/image_linear.S
src/image/image_linear_alloc.c
src/image/image_rotate.c
src/image/image_rotate_around.c
src/image/image_rotate_around_scale.c
src/image/image_scale.c
src/image/image_set_palette.c
src/image/image_set_pixel.c
src/image/image_sub.c
src/image/image_target.c
src/image/image_valid.c
src/image/image_vflip.c
src/image/image_vflip_alloc.c
# Interrupt Controller driver
src/intc/intc.c
src/intc/inth.s
@ -144,15 +101,10 @@ set(SOURCES
src/kmalloc/kmalloc.c
# MMU driver
src/mmu/mmu.c
# R61524 display driver
src/r61524/r61524.c
# Format-agnostic rendering
src/render/dcircle.c
src/render/dellipse.c
# Rendering
src/render/dhline.c
src/render/dimage.c
src/render/dline.c
src/render/dpoly.c
src/render/dprint.c
src/render/drect_border.c
src/render/dtext.c
@ -160,7 +112,93 @@ set(SOURCES
src/render/dvline.c
src/render/dwindow.c
src/render/topti.c
# RGB Rendering
# RTC driver
src/rtc/rtc.c
src/rtc/rtc_ticks.c
# Sound Processing Unit driver
src/spu/spu.c
# Timer Unit driver
src/tmu/inth-etmu.s
src/tmu/inth-tmu.s
src/tmu/sleep.c
src/tmu/tmu.c
# USB driver
src/usb/asyncio.c
src/usb/classes/ff-bulk.c
src/usb/configure.c
src/usb/pipes.c
src/usb/read4.S
src/usb/setup.c
src/usb/string.c
src/usb/usb.c
src/usb/write4.S
)
set(SOURCES_FX
# Gray engine
src/gray/engine.c
src/gray/gclear.c
src/gray/ggetpixel.c
src/gray/gint_gline.c
src/gray/gpixel.c
src/gray/grect.c
src/gray/gsubimage.c
src/gray/gtext.c
# Rendering
src/render-fx/bopti-asm-gray-scsp.s
src/render-fx/bopti-asm-gray.s
src/render-fx/bopti-asm-mono-scsp.s
src/render-fx/bopti-asm.s
src/render-fx/bopti.c
src/render-fx/dclear.c
src/render-fx/dgetpixel.c
src/render-fx/dpixel.c
src/render-fx/drect.c
src/render-fx/dsubimage.c
src/render-fx/dupdate.c
src/render-fx/gint_dline.c
src/render-fx/masks.c
src/render-fx/topti-asm.s
src/render-fx/topti.c
# T6K11 driver
src/t6k11/t6k11.c
src/usb/classes/ff-bulk-gray.c
)
set(SOURCES_CG
# R61524 driver
src/r61524/r61524.c
# Image library
src/image/image_alloc.c
src/image/image_alloc_palette.c
src/image/image_alpha.c
src/image/image_clear.c
src/image/image_copy.c
src/image/image_copy_alloc.c
src/image/image_copy_palette.c
src/image/image_create.c
src/image/image_create_vram.c
src/image/image_data_size.c
src/image/image_decode_pixel.c
src/image/image_fill.c
src/image/image_free.c
src/image/image_get_pixel.c
src/image/image_hflip.c
src/image/image_hflip_alloc.c
src/image/image_linear.c
src/image/image_linear.S
src/image/image_linear_alloc.c
src/image/image_rotate.c
src/image/image_rotate_around.c
src/image/image_rotate_around_scale.c
src/image/image_scale.c
src/image/image_set_palette.c
src/image/image_set_pixel.c
src/image/image_sub.c
src/image/image_target.c
src/image/image_valid.c
src/image/image_vflip.c
src/image/image_vflip_alloc.c
# Rendering
src/render-cg/dclear.c
src/render-cg/dgetpixel.c
src/render-cg/dpixel.c
@ -169,9 +207,9 @@ set(SOURCES
src/render-cg/dupdate.c
src/render-cg/dvram.c
src/render-cg/gint_dline.c
src/render-cg/topti-asm.S
src/render-cg/topti-asm.s
src/render-cg/topti.c
# Fast RGB image renderer
# Fast image renderer
src/render-cg/image/image.c
src/render-cg/image/image_rgb16.S
src/render-cg/image/image_rgb16_normal.S
@ -188,7 +226,7 @@ set(SOURCES
src/render-cg/image/image_p4_clearbg_alt.S
src/render-cg/image/image_p4_swapcolor.S
src/render-cg/image/image_p4_dye.S
# Interface to the fast RGB image renderer
# Interface to the fast image renderer
src/render-cg/image/image_rgb16.c
src/render-cg/image/image_rgb16_effect.c
src/render-cg/image/image_rgb16_swapcolor.c
@ -202,67 +240,24 @@ set(SOURCES
src/render-cg/image/image_p4_effect.c
src/render-cg/image/image_p4_swapcolor.c
src/render-cg/image/image_p4_dye.c
# Mono rendering
src/render-fx/bopti-asm-gray-scsp.S
src/render-fx/bopti-asm-gray.S
src/render-fx/bopti-asm-mono-scsp.S
src/render-fx/bopti-asm.S
src/render-fx/bopti.c
src/render-fx/dclear.c
src/render-fx/dgetpixel.c
src/render-fx/dpixel.c
src/render-fx/drect.c
src/render-fx/dsubimage.c
src/render-fx/dupdate.c
src/render-fx/gint_dline.c
src/render-fx/masks.c
src/render-fx/topti-asm.S
src/render-fx/topti.c
# RTC driver
src/rtc/rtc.c
src/rtc/rtc_ticks.c
# Sound Processing Unit driver
src/spu/spu.c
# T6K11 display driver
src/t6k11/t6k11.c
# Timer Unit driver
src/tmu/inth-etmu.s
src/tmu/inth-tmu.s
src/tmu/sleep.c
src/tmu/tmu.c
# UBC driver
src/ubc/ubc.c
src/ubc/ubc.S
# USB driver
src/usb/asyncio.c
src/usb/classes/ff-bulk.c
src/usb/classes/ff-bulk-gray.c
src/usb/configure.c
src/usb/pipes.c
src/usb/read4.S
src/usb/setup.c
src/usb/string.c
src/usb/usb.c
src/usb/write4.S
# Video driver interface
src/video/video.c
)
set(ASSETS_FX src/font5x7.png src/gdb/icons-i1msb.png)
set(ASSETS_CG src/font8x9.png src/gdb/icons-rgb565.png)
set(ASSETS_FX src/font5x7.png)
set(ASSETS_CG src/font8x9.png)
fxconv_declare_assets(${ASSETS_FX} ${ASSETS_CG})
include_directories(
"${PROJECT_SOURCE_DIR}/include"
"${PROJECT_BINARY_DIR}/include")
add_compile_options(-Wall -Wextra -std=c11 -Os -g -fstrict-volatile-bitfields -mtas)
add_compile_options(-Wall -Wextra -std=c11 -Os -fstrict-volatile-bitfields -mtas)
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
add_compile_definitions(FX9860G)
set(NAME "gint-fx")
set(LINKER_SCRIPTS
"${CMAKE_CURRENT_BINARY_DIR}/fx9860g.ld")
add_library(${NAME} STATIC ${SOURCES} ${ASSETS_FX} ${LINKER_SCRIPTS})
add_library(gint-fx STATIC ${SOURCES_COMMON} ${SOURCES_FX} ${ASSETS_FX}
${LINKER_SCRIPTS})
endif()
if("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
@ -271,16 +266,8 @@ if("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
set(LINKER_SCRIPTS
"${CMAKE_CURRENT_BINARY_DIR}/fxcg50.ld"
"${CMAKE_CURRENT_BINARY_DIR}/fxcg50_fastload.ld")
add_library(${NAME} STATIC ${SOURCES} ${ASSETS_CG} ${LINKER_SCRIPTS})
endif()
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G_G3A)
add_compile_definitions(FX9860G_G3A)
set(NAME "gint-fxg3a")
set(LINKER_SCRIPTS
"${CMAKE_CURRENT_BINARY_DIR}/fxcg50.ld"
"${CMAKE_CURRENT_BINARY_DIR}/fxcg50_fastload.ld")
add_library(${NAME} STATIC ${SOURCES} ${ASSETS_FX} ${LINKER_SCRIPTS})
add_library(gint-cg STATIC ${SOURCES_COMMON} ${SOURCES_CG} ${ASSETS_CG}
${LINKER_SCRIPTS})
endif()
set_target_properties("${NAME}" PROPERTIES OUTPUT_NAME "${NAME}")

View File

@ -105,17 +105,6 @@ The available options are:
% fxsdk build-cg install
```
**"Cross-Building" a fx-9860G II project for fx-CG 50**
Programs written for fx-9860G can also be built to run on the fx-CG series,
provided no low-level function or hardware-specific behavior (like syscalls) is
used by the program.
```
% fxsdk build-fxg3a
% fxsdk build-fxg3a install
```
## Using in CMake-based add-ins
Find the `Gint` module and link against `Gint::Gint`. gint declares the include
@ -132,16 +121,10 @@ target_link_libraries(<target_name> Gint::Gint)
Projects created with the fxSDK link with gint out-of-the-box. If you're not
using the fxSDK, you will need to:
* Build with `-ffreestanding -fstrict-volatile-bitfields` and either
`-DFX9860G` or `-DFXGC50`;
* Build with `-ffreestanding -fstrict-volatile-bitfields`;
* Link with `-T fx9860g.ld -lgint-fx -lopenlibm -lc` on fx-9860G;
* Link with `-T fxcg50.ld -lgint-cg -lopenlibm -lc` on fx-CG 50.
To manually build the fx-CG executable for an fx-9860G program, mix as follows:
* Use platform flags `-DFXCG50 -DFX9860G_G3A`;
* Link with `-T fxcg50.ld -lgint-fxg3a -lopenlibm -lc`.
If you don't have a standard library such as
[Memallox's port of newlib](/PlaneteCasio/libc), you also need `-nostdlib`. I
typically use `-m3 -mb` or `-m4-nofpu -mb` to specify the platform, but that

44
TODO
View File

@ -3,7 +3,7 @@ Bugs to fix:
Extensions on existing code:
* clock: mono support
* usb: and interrupt pipes
* usb: add PC->calc reading, and interrupt pipes
* fs: support RAM files
* fs: support USB streams as generic file descriptors
* fugue: support glob() to abstract away BFile entirely
@ -17,50 +17,10 @@ Extensions on existing code:
* core: run destructors when a task-switch results in leaving the app
* fs: support read-only files backed with GetBlockAddress() on fx-CG
* kernel: SH4- or G-III-specific linker scripts?
* render: Properly document bopti fx. Also make it faster maybe?
* keysc: global shortcut SHIFT+0+EXIT for abort() as an infinite loop break
Future directions:
* Audio playback using TSWilliamson's libsnd method
* Serial communication
* Make fx9860g projects work out of the box on fxcg50
* Base for Yatis' threads library
TODO:
* SPLIT CONFIG HEADER IN VARIANTS SO THEY DON'T CLASH WHEN INSTALLED
Bits that need to abstract out into APIs:
- display: Toggle backlight (or set level)
-> Have a backlight property with min/max values
@ getkey
@ justui jscene
- os: OS interface to access OS info, like in fxos
@ usb/setup.c set_strings
@ usb/classes/ff-bulk.c identify command
- render: current video mode
@ usb/classes/ff-bulk.c capture_vram
- gray: make gray engine a subset of t6k11 which then supports two modes
Video formats:
- i1msb
- 2i1msb
- rgb565
T6K11:
mode 0 : i1msb 128x64 @64 Hz
mode 1 : 2i1msb 128x64 @64 Hz
R61524:
mode 0 : rgb565 396x224 @? Hz
mode 1 : i3??? 396x224 @? Hz
mode 2 : i1msb 128x64 @? Hz # <- for g1a emulation :)
mode 3 : 2i1msb 128x64 @? Hz # <- for g1a emulation :)
enum {
/* Indexed 1-bit, 0 is white, 1 is black. Row-major, left-to-right, each
row a set of 4-byte values with leftmost pixel on the MSB. */
IMAGE_FORMAT_I1MSB,
/* Indexed 2-bit: white, light gray, dark gray, black. Represented as a
pair of I1MSB buffers, the first being bit #0, the second bit #1. */
IMAGE_FORMAT_2I1MSB,
/* 16-bit RGB565. Row-major, left-to-right. */
IMAGE_FORMAT_RGB565,
};

View File

@ -7,10 +7,6 @@ elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
set(PC fx)
set(INTF_DEFN FX9860G)
set(INTF_LINK "-T;fx9860g.ld")
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G_G3A)
set(PC fxg3a)
set(INTF_DEFN FX9860G_G3A)
set(INTF_LINK "-T;fxcg50.ld")
else()
message(FATAL_ERROR "gint: unknown fxSDK platform '${FXSDK_PLATFORM}'")
endif()

View File

@ -161,11 +161,6 @@ SECTIONS
_silram = SIZEOF(.ilram);
_sxyram = SIZEOF(.xyram);
_lgmapped = ABSOLUTE(0);
_sgmapped = ABSOLUTE(0);
_lreloc = ABSOLUTE(0);
_sreloc = ABSOLUTE(0);
/* gint's uninitialized BSS section, going to static RAM. All the large
data arrays will be located here */
.gint.bss (NOLOAD) : {

View File

@ -5,17 +5,14 @@
configure:
@ fxsdk build-fx -c $(GINT_CMAKE_OPTIONS)
@ fxsdk build-cg -c $(GINT_CMAKE_OPTIONS)
@ fxsdk build-fxg3a -c $(GINT_CMAKE_OPTIONS)
build:
@ fxsdk build-fx
@ fxsdk build-cg
@ fxsdk build-fxg3a
install:
@ fxsdk build-fx install
@ fxsdk build-cg install
@ fxsdk build-fxg3a install
uninstall:
@ if [ -e build-fx/install_manifest.txt ]; then \
@ -24,8 +21,5 @@ uninstall:
@ if [ -e build-cg/install_manifest.txt ]; then \
xargs rm -f < build-cg/install_manifest.txt; \
fi
@ if [ -e build-fxg3a/install_manifest.txt ]; then \
xargs rm -f < build-fxg3a/install_manifest.txt; \
fi
.PHONY: configure build install uninstall

View File

@ -5,6 +5,8 @@
#ifndef GINT_CONFIG
#define GINT_CONFIG
#include <gint/defs/types.h>
/* GINT_VERSION: Latest tag and number of additional commits
"2.1.0" = Release 2.1.0
"2.1.1-5" = 5 commits after release 2.1.1 */
@ -14,30 +16,6 @@
0x03f7c0a0 = Commit 3f7c0a0 */
#define GINT_HASH 0x@GINT_GIT_HASH@
/* GINT_HW_{FX,CG}: Identifies the type of hardware running the program. */
#if defined(FX9860G)
# define GINT_HW_FX 1
# define GINT_HW_CG 0
# define GINT_HW_SWITCH(FX,CG) (FX)
#elif defined(FXCG50)
# define GINT_HW_FX 0
# define GINT_HW_CG 1
# define GINT_HW_SWITCH(FX,CG) (CG)
#endif
/* Shorthand to simplify definitions below. Won't be needed for long. */
#if defined(FX9860G_G3A)
# define GINT_FX9860G_G3A 1
#else
# define GINT_FX9860G_G3A 0
#endif
/* GINT_OS_{FX,CG}: Identifies the type of OS API we're assuming. Currently I
see no reason this would be different from hardware, but who knows. */
#define GINT_OS_FX GINT_HW_FX
#define GINT_OS_CG GINT_HW_CG
#define GINT_OS_SWITCH GINT_HW_SWITCH
/* GINT_NO_OS_STACK: Disables using a chunk of the OS stack as a heap. The top
section covering 355/512 ko is otherwise used. (fx-CG 50) */
#cmakedefine GINT_NO_OS_STACK
@ -63,13 +41,4 @@
/* GINT_USB_DEBUG: Selects whether USB debug functions are enabled */
#cmakedefine GINT_USB_DEBUG
/* GINT_RENDER_DMODE: Selects whether the dmode override is available on
rendering functions. */
#define GINT_RENDER_DMODE (GINT_HW_FX || GINT_FX9860G_G3A)
/* GINT_RENDER_{MONO,RGB}: Enable the mono/rgb rendering API.
Currently these are exclusive. */
#define GINT_RENDER_MONO (GINT_HW_FX || GINT_FX9860G_G3A)
#define GINT_RENDER_RGB (GINT_HW_CG && !GINT_FX9860G_G3A)
#endif /* GINT_CONFIG */

View File

@ -144,19 +144,6 @@ typedef struct {
/* GINT_CALL_NULL: Empty function call */
#define GINT_CALL_NULL ((gint_call_t){ .function = NULL, .args = {} })
/* GINT_CALL_FLAG(): Build an indirect call to an odd address
This is used as a workaround to have an extra flag in gint_call_t structures
without altering their size and exploits the fact that SuperH code has to be
aligned on even addresses.
It is up to the caller to notice the presence of the flag and realign the
address properly.
This flag is currently only checked by gint_inth_callback to specify that the
called function will take the interrupt context as its first argument. */
#define GINT_CALL_FLAG(func, ...) \
GINT_CALL((void*)((uint32_t)(func) | 1), __VA_ARGS__)
/* gint_call(): Perform an indirect call */
static GINLINE int gint_call(gint_call_t cb)
{

View File

@ -15,7 +15,7 @@
#ifndef GINT_DISPLAY_CG
#define GINT_DISPLAY_CG
#if GINT_RENDER_RGB
#ifdef FXCG50
#ifdef __cplusplus
extern "C" {
@ -94,10 +94,6 @@ typedef image_t bopti_image_t;
@main Main VRAM area, used alone if [secondary] is NULL
@secondary Additional VRAM area, enables triple buffering if non-NULL */
// TODO: In gint 3 the triple buffering mechanism will be removed. Applications
// that want to change VRAMs in-between every frame will be able to do so by
// talking directly to the video interface to set VRAM, and wrapping dupdate.
// Basically it will just no longer be handled by gint itself.
void dsetvram(uint16_t *main, uint16_t *secondary);
/* dgetvram() - Get VRAM addresses
@ -108,6 +104,6 @@ void dgetvram(uint16_t **main, uint16_t **secondary);
}
#endif
#endif /* GINT_RENDER_RGB */
#endif /* FXCG50 */
#endif /* GINT_DISPLAY_CG */

View File

@ -9,7 +9,7 @@
#ifndef GINT_DISPLAY_FX
#define GINT_DISPLAY_FX
#if GINT_RENDER_MONO
#ifdef FX9860G
#ifdef __cplusplus
extern "C" {
@ -83,33 +83,14 @@ typedef struct
uint height :12;
/* Raw layer data */
uint8_t *data;
uint8_t data[];
} GPACKED(4) bopti_image_t;
/* Image formats ("profiles") */
enum {
/* MONO: black/white, 1 layer (bw) */
IMAGE_MONO = 0,
/* MONO_ALPHA: black/white/transparent, 2 layers (alpha+bw) */
IMAGE_MONO_ALPHA = 1,
/* GRAY: black/dark/light/white, 2 layers (light+dark) */
IMAGE_GRAY = 2,
/* GRAY_ALPHA: black/dark/light/white/transparent, 3 layres
(alpha+light+dark) */
IMAGE_GRAY_ALPHA = 3,
};
/* Number of layers in the image. */
GINLINE static int image_layer_count(int profile)
{
return profile + (profile <= 1);
}
#ifdef __cplusplus
}
#endif
#endif /* GINT_RENDER_MONO */
#endif /* FX9860G */
#endif /* GINT_DISPLAY_FX */

View File

@ -15,16 +15,15 @@ extern "C" {
#include <gint/defs/types.h>
#include <gint/defs/call.h>
#include <gint/config.h>
/* Platform-specific functions include VRAM management and the definition of
the color_t type. */
#if GINT_RENDER_MONO
#ifdef FX9860G
#include <gint/display-fx.h>
#endif
#if GINT_RENDER_RGB
#ifdef FXCG50
#include <gint/display-cg.h>
#endif
@ -213,53 +212,6 @@ void dhline(int y, int color);
@color Line color (same values as dline() are allowed) */
void dvline(int x, int color);
//---
// Other geometric shapes
//---
/* dcircle(): Circle with border
This function renders a circle defined by its middle point (xm, ym) and a
radius r. The border and fill can be set separately. This function uses
Bresenham's algorithm and only renders circles of odd diameter; if you want
an even diameter, use dellipse() with a bounding box.
@xm @ym Coordinates of center
@r Radius (integer, >= 0)
@fill_color Color of the disc inside the circle, C_NONE to disable
@border_color Color of the circle itself, C_NONE to disable */
void dcircle(int xm, int ym, int r, int fill_color, int border_color);
/* dellipse(): Ellipse with border
This function renders a non-rotated ellipse, defined by its bounding box.
The border and fill can be set separately. The border is as 1-pixel thin
border given by Bresenham's algorithm.
To render an ellipse from its center coordinates (x,y) and semi-major/minor
axes a/b, use dellipse(x-a, y-b, x+a, y+b, fill_color, border_color).
@x1 @y1 @x2 @y2 Ellipse's bounding box (both bounds included, like drect())
@fill_color Color of the surface inside the ellipse, C_NONE to disable
@border_color Color of the ellipse itself, C_NONE to disable */
void dellipse(int x1, int y1, int x2, int y2, int fill_color,
int border_color);
/* dpoly(): Render an arbitrary polygon
Renders the polygon defined by vertices (x[i], y[i]) for 0 < i < N. A fill
color and border color can be specified separately. For filling, N must be
at least 3. For border, N must be at least 2.
Note: this is a fairly slow function, not designed for rendering triangles
in 3D games. There are faster methods for that.
@x @y Arrays of vertex coordinates
@N Number of vertices (length of x and y)
@fill_color Color of the polygon's interior, C_NONE to disable
@border_color Color of the polygon's border, C_NONE to disable */
void dpoly(int const *x, int const *y, int N, int fill_color, int border_color);
//---
// Text rendering (topti)
//---
@ -461,28 +413,6 @@ void dprint_opt(int x, int y, int fg, int bg, int halign, int valign,
Calls dprint_opt() with bg=C_NONE, halign=DTEXT_LEFT and valign=DTEXT_TOP */
void dprint(int x, int y, int fg, char const *format, ...);
//---
// Text rendering utilities
//---
/* dfont_glyph_index(): Obtain the glyph index of a Unicode code point
Returns the position of code_point in the character table of the given font,
or -1 if code_point is not part of that set. */
int dfont_glyph_index(font_t const *font, uint32_t code_point);
/* topti_glyph_offset(): Use a font index to find the location of a glyph
The provided glyph value (usuall obtained by dfont_glyph_index()) 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 ignored. */
int dfont_glyph_offset(font_t const *font, uint glyph_number);
/* dtext_utf8_next(): Read the next UTF-8 code point of a string
Returns the next code point and advances the string. Returns 0 (NUL) at the
end of the string. */
uint32_t dtext_utf8_next(uint8_t const **str_pointer);
//---
// Image rendering (bopti)
//---

View File

@ -158,7 +158,7 @@ typedef struct {
int8_t queue_next;
int8_t queue_end;
/* Number of events lost because of missing queue space */
uint16_t events_lost;
uint events_lost;
/* Event transforms */
keydev_transform_t tr;
@ -183,9 +183,9 @@ typedef struct {
// <Repeats>
/* Candidate key for repeats (or 0 if no key is candidate yet) */
int16_t rep_key;
int rep_key;
/* Number of repeats already sent */
int16_t rep_count;
int rep_count;
/* Time since key was first pressed (us) */
int rep_time;
/* Delay until next repeat, set by the repeat planner (us) */
@ -207,9 +207,6 @@ typedef struct {
/* Parameters for the standard repeat function */
int rep_standard_first, rep_standard_next;
/* State of keys that have changes since the last flip monitoring reset. */
GALIGNED(4) uint8_t state_flips[12];
} keydev_t;
/* keydev_std(): Standard keyboard input device
@ -277,17 +274,6 @@ void keydev_set_async_filter(keydev_t *d, keydev_async_filter_t filter);
/* keydev_keydown(): Check if a key is down according to generated events */
bool keydev_keydown(keydev_t *d, int key);
/* keydev_keypressed(): Check if a key was pressed
This compares to the state at the time of the last keydev_clear_flips(). */
bool keydev_keypressed(keydev_t *d, int key);
/* keydev_keyreleased(): Check if a key was released
This compares to the state at the time of the last keydev_clear_flips(). */
bool keydev_keyreleased(keydev_t *d, int key);
/* keydev_clear_flips(): Reset flip info used by keypressed()/keyreleased() */
void keydev_clear_flips(keydev_t *d);
/* keydev_transform(): Obtain current transform parameters */
keydev_transform_t keydev_transform(keydev_t *d);

View File

@ -49,18 +49,6 @@ void r61524_display(uint16_t *vram, int start, int height, int method);
void r61524_display_rect(uint16_t *vram, int xmin, int xmax, int ymin,
int ymax);
/* r61524_display_mono_128x64(): Display a mono-style VRAM
This experimental function updates the display with the contents of a 128x64
VRAM, used with the fxg3a compilation target.
TODO: Make that a video mode. */
void r61524_display_mono_128x64(uint32_t *vram);
/* r61524_display_mono_128x64(): Display a gray-style VRAM
This experimental function updates the display with the contents of a 128x64
gray VRAM pair, used with the fxg3a compilation target.
TODO: Make that a video mode. */
void r61524_display_gray_128x64(uint32_t *light, uint32_t *dark);
/* r61524_start_frame(): Prepare the display for a region update
This function sets up the display driver to receive graphics data to update

View File

@ -78,7 +78,7 @@ void fs_free_descriptor(int fd);
exact file descriptor reuse_fd is used. (This is useful to reopen standard
streams.) In this case, the only possible return values are -1 and reuse_fd
itself. */
int open_generic(fs_descriptor_type_t const *type, void *data, int reuse_fd);
int open_generic(fs_descriptor_type_t *type, void *data, int reuse_fd);
/* fs_path_normalize(): Normalize a path to eliminate ., .. and redundant /

View File

@ -1,105 +0,0 @@
//---
// gint:gdb - GDB remote serial protocol
//---
#ifndef GINT_GDB
#define GINT_GDB
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/* gdb_cpu_state_t: State of the CPU when breaking
This struct keep the same register indices as those declared by GDB to allow
easy R/W without needing a "translation" table.
See : https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/sh-tdep.c;
h=c402961b80a0b4589243023ea5362d43f644a9ec;hb=4f3e26ac6ee31f7bc4b04abd
8bdb944e7f1fc5d2#l361
*/
// TODO : Should we expose r*b*, ssr, spc ? are they double-saved when breaking
// inside an interrupt handler ?
typedef struct {
union {
struct {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t r12;
uint32_t r13;
uint32_t r14;
uint32_t r15;
uint32_t pc;
uint32_t pr;
uint32_t gbr;
uint32_t vbr;
uint32_t mach;
uint32_t macl;
uint32_t sr;
} reg;
uint32_t regs[23];
};
} gdb_cpu_state_t;
/* gdb_start(): Start the GDB remote serial protocol server
This function starts the GDB stub (program that communicates with GDB). It
takes over USB, and returns once communication is established with a GDB
instance on the computer. Normally this is called by the panic handler after
a crash. It can also be called manually, in which case it should be followed
by a call to gdb_main() with the current state (NULL if you don't have any).
If the GDB stub is already started, this is a no-op. Returns 0 on success
and a negative value if the USB setup fails. */
int gdb_start(void);
/* gdb_main(): Main GDB loop
Main loop for when the program is in a paused state. Communicates with GDB
over USB and mutates the cpu_state struct, memory and the UBC configuration
accordingly. Returns once the program should resume. */
void gdb_main(gdb_cpu_state_t *cpu_state);
/* gdb_start_on_exception(): Set the GDB stub to autostart on crashes
This function sets a crash handler that starts the GDB stub whenever a
System ERROR occurs. */
// TODO: Get some visible signal on-screen when that happens
void gdb_start_on_exception(void);
/* gdb_redirect_streams(): Select whether to redirect stdout/stderr
This function specifies whether stdout and stderr shall be redirected when
debugging. If redirected, stdout and stderr will change from their default
implementation (or the one supplied by the user via open_generic()) to a
stubcall that prints text in the GDB console. This setting must be set
before GDB starts, so usually just after gdb_start_on_exception().
This is intended to be used with debug methods that print text. For example,
if the program has a status() function that prints information useful when
debugging, one might want to invoke it from GDB with "call status()". With
default stdout/stderr this would be at best impractical to read the output
on the calculator, at worst buggy due to the program being interrupted.
Redirecting stdout/stderr allows the result to be printed in GDB.
The default is to not redirect stdout/stderr. */
void gdb_redirect_streams(bool redirect_stdout, bool redirect_stderr);
/** Stubcalls **/
/* Write to a file descriptor on the remote debugger. */
void gdb_stubcall_write(int fd, void const *buf, size_t size);
#ifdef __cplusplus
}
#endif
#endif /* GINT_GDB */

View File

@ -80,56 +80,6 @@ void gint_osmenu_native(void);
@restart 0 to exit, 1 to restart by using gint_osmenu() */
void gint_setrestart(int restart);
/* gint_poweroff(): World switch and power off the calculator
Shows the CASIO logo / poweroff screen if show_logo is true. The program
will resume execution normally after powering on again. Don't call this
function with show_logo=false as a result of pressing AC/ON because the
calculator will restart immediately unless the user releases the AC/ON key
extremely quickly. */
void gint_poweroff(bool show_logo);
/* gint_set_onchip_save_mode(): Specify memory save policy for world switches
World switches can cause corruption in on-chip memory in two ways. First, if
the calculator powers off while in the OS world, on-chip memory will be
wiped because it's not powered when the calculator is off. Second, the OS
may run code that overwrites on-chip memory (we don't have any examples of
that but it's not part of the add-in interface).
As a result, the best option is to backup on-chip memory and restore it when
loading back into the add-in. The issue is that there's 20 kB of on-chip
memory (4 kB ILRAM + 16 kB XYRAM) and on some machines (fx-9860G-like) or in
some applications we don't have that much memory lying around.
This function selects between three modes for handling this save:
* [Reinitialization mode]
Don't save on-chip memory at all, instead just reinitialize the globals
and leave the rest corrupted. This is useful if on-chip memory is used
only for temporaries (e.g. frames in Azur), for which we don't care if
they're corrupted, or code (e.g gint interrupt handling code), which will
be reloaded and is otherwise a constant.
* [Backup mode]
Save on-chip memory to a user-provided buffer of size GINT_ONCHIP_BUFSIZE.
* [Nothing mode]
Don't do anything, and let the world switch function choose its preferred
saving method. This allows application-specific compromises.
This is not a problem on SH3 because on-chip memory is only used on SH4. */
enum {
GINT_ONCHIP_REINITIALIZE = 0,
GINT_ONCHIP_BACKUP = 1,
GINT_ONCHIP_NOTHING = 2,
};
#define GINT_ONCHIP_BUFSIZE (20 << 10)
void gint_set_onchip_save_mode(int mode, void *ptr);
/* gint_get_onchip_save_mode(): Get the current on-chip memory save policy */
int gint_get_onchip_save_mode(void **ptr);
/* This function has been moved to the INTC driver */
__attribute__((deprecated("Use intc_handler() instead")))
static GINLINE void *gint_inthandler(int code, void const *h, size_t size) {
@ -155,29 +105,10 @@ static GINLINE void *gint_inthandler(int code, void const *h, size_t size) {
.callback:
.long _gint_inth_callback
The gint_call_t object can be built with GINT_CALL_FLAG to specify that the
called function should get a pointer to a gint_inth_callback_context_t
strcture as its first argument.
@call Address of a gint_call_t object
Returns the return value of the callback. */
extern int (*gint_inth_callback)(gint_call_t const *call);
/* gint_inth_callback_context_t: Context of the interrupted function when an
interrupt is handled by gint_inth_callback. */
typedef struct {
uint32_t ssr;
uint32_t spc;
uint32_t r7;
uint32_t r6;
uint32_t r5;
uint32_t r4;
uint32_t r3;
uint32_t r2;
uint32_t r1;
uint32_t r0;
} gint_inth_callback_context_t;
/* gint_set_quit_handler(): Setup a call to be invoked when leaving the add-in
This function sets up the provided GINT_CALL() to be invoked when the

View File

@ -18,8 +18,6 @@
extern "C" {
#endif
#include <gint/config.h>
/* For compatibility with ASM, include the following bits only in C code */
#ifndef CPP_ASM
@ -42,14 +40,20 @@ void hw_detect(void);
dual-platform version for libraries.
Warning: this macro is also used hardcoded in exch.s. */
#if GINT_HW_FX
# define isSH3() (gint[HWMPU] & 1)
# define isSH4() (!isSH3())
# define isSlim() (gint[HWCALC] == HWCALC_FX9860G_SLIM)
#elif GINT_HW_CG
# define isSH3() 0
# define isSH4() 1
# define isSlim() 0
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
#define isSH3() (gint[HWMPU] & 1)
#define isSH4() (!isSH3())
#endif
#if defined(FX9860G)
#define isSlim() (gint[HWCALC] == HWCALC_FX9860G_SLIM)
#else
#define isSlim() 0
#endif
#ifdef FXCG50
#define isSH3() 0
#define isSH4() 1
#endif
/* This bit should be set in all data longwords except HWMPU, HWCPUVR, HWCPUPR

View File

@ -34,7 +34,10 @@
extern "C" {
#endif
#include <gint/config.h>
#ifndef FXCG50
#error <gint/image.h> is only supported on FXCG50
#else
#include <gint/defs/attributes.h>
#include <gint/defs/types.h>
@ -166,8 +169,6 @@ enum {
// Image creation and destruction
//---
#if GINT_RENDER_RGB
/* image_alloc(): Create a new (uninitialized) image
This function allocates a new image of the specified dimensions and format.
@ -413,7 +414,7 @@ image_t *image_sub(image_t const *src, int x, int y, int w, int h,
/* Make the last parameter optional */
#define image_sub1(src, x, y, w, h, dst, ...) image_sub(src, x, y, w, h, dst)
#define image_sub(...) image_sub1(__VA_ARGS__, NULL)
#define image_sub(...) image_sub(__VA_ARGS__, NULL)
/* image_at(): Build a reference to a position within a sub-image */
#define image_at(img, x, y) image_sub(img, x, y, -1, -1)
@ -433,9 +434,9 @@ image_t *image_sub(image_t const *src, int x, int y, int w, int h,
// that allocation can fail, so you need to check whether the returned image is
// valid.
//
// (You can still pass invalid images to transform functions. The invalid image
// will be ignored or returned unchanged, so you can chain calls and check for
// validity at the end of the chain.)
// (You can still pass an invalid image to libimg functions when chaining
// transforms. The invalid image will be ignored or returned unchanged, so you
// can check for it at the end of any large chain.)
//
// Some functions support in-place transforms. This means they can be called
// with the source as destination, and will transform the image without needing
@ -837,7 +838,7 @@ bool image_target(image_t const *src, image_t *dst, ...);
#define image_alpha_2(fmt, copy_alpha) \
((copy_alpha) ? 0x10000 : image_alpha(fmt))
#endif /* GINT_RENDER_RGB */
#endif /* FXCG50 */
#ifdef __cplusplus
}

View File

@ -41,8 +41,6 @@ enum {
INTC_DMA_DEI4,
INTC_DMA_DEI5,
INTC_DMA_DADERR,
/* Serial Communication Interface with FIFO (SCIF0) */
INTC_SCIF0,
/* Real-Time Clock [RTC]; a single IPR covers all 3 interrupts */
INTC_RTC_ATI,
INTC_RTC_PRI,
@ -132,11 +130,6 @@ void *intc_handler(int event_code, void const *handler, size_t size);
the numerous constraints of intc_handler(), at the cost of always going back
to userspace and a small time overhead.
Since gint_inth_callback is used to do the heavy lifting of setting up a sane
context for C code, the gint_call_t object can be built with GINT_CALL_FLAG
if the called function expects a gint_inth_callback_context_t structure as its
first argument.
@event_code Identifier of the interrupt block
@function Function to use as a handler
Returns true on success, false if the event code is invalid. */

View File

@ -60,24 +60,6 @@ extern "C" {
* clearevents() reads all pending events from the input queue.
Games are often also interested in whether keys were pressed or released
_since the last frame_. gint doesn't know what a frame is, but you can track
key state flips by using cleareventflips() before reading events and
keypressed() and keyreleased() afterwards.
* keypressed() checks if the specified key is currently down and was up at
the time of the last cleareventflips().
* keyreleased() checks if the specified key is currently up and was down at
the time of the last cleareventflips().
A typical game loop might look like. cleareventflips() must be called
_before_ clearevents().
cleareventflips();
clearevents(); // or pollevent(), waitevent()
if(keydown(KEY_RIGHT)) move();
if(keypressed(KEY_F6)) open_inventory();
The previous functions are quite low-level. GUI programs that look like the
system applications will prefer using a GetKey()-like functions that return
a single key press at a time, heeds for releases, for SHIFT and ALPHA
@ -116,13 +98,13 @@ typedef struct
{
uint time :16; /* Time of event, unique over short periods */
uint :2; /* Reserved for future use */
uint :3; /* Reserved for future use */
uint mod :1; /* Whether modifiers are used */
uint shift :1; /* If mod=1, whether SHIFT was pressed */
uint alpha :1; /* If mod=1, whether ALPHA was pressed */
uint type :3; /* Type of key event */
uint type :2; /* Type of key event */
uint key :8; /* Hit key */
} GPACKED(4) key_event_t;
@ -130,11 +112,10 @@ typedef struct
/* Keyboard event types, as in the [type] field of key_event_t */
enum
{
KEYEV_NONE = 0, /* No event available (poll() only) */
KEYEV_DOWN = 1, /* Key was pressed */
KEYEV_UP = 2, /* Key was released */
KEYEV_HOLD = 3, /* A key that was pressed has been held down */
KEYEV_OSMENU = 4, /* We went to the main menu and back */
KEYEV_NONE = 0, /* No event available (poll() only) */
KEYEV_DOWN = 1, /* Key was pressed */
KEYEV_UP = 2, /* Key was released */
KEYEV_HOLD = 3, /* A key that was pressed has been held down */
};
/* Keyboard frequency analysis is a runtime setting since gint 2.4. This macro
@ -181,12 +162,6 @@ key_event_t waitevent(volatile int *timeout);
/* clearevents(): Read all events waiting in the queue */
void clearevents(void);
/* cleareventflips(): Set the time reference for keypressed()/keyreleased()
The two functions keypressed() and keyreleased() will use the keyboard state
at the time this function was called to determine whether any given key was
just pressed or jut released. */
void cleareventflips(void);
//---
// Key state functions
//---
@ -206,16 +181,6 @@ int keydown_all(int key1, ...);
sequence should be terminated by a 0 integer. */
int keydown_any(int key1, ...);
/* keypressed(): Check if a key was just pressed
This function returns non-zero if the specified key is currently down, *and*
it was up at the time of the last call to cleareventflips(). */
int keypressed(int key);
/* keyreleased(): Check if a key was just released
This function returns non-zero if the specified key is currently up, *and*
it was down at the time of the last call to cleareventflips(). */
int keyreleased(int key);
//---
// High-level functions
//---
@ -240,30 +205,24 @@ key_event_t getkey(void);
/* The following are the option bits for getkey_opt(). */
enum {
/* Enable modifiers keys */
GETKEY_MOD_SHIFT = 0x0001,
GETKEY_MOD_ALPHA = 0x0002,
GETKEY_MOD_SHIFT = 0x01,
GETKEY_MOD_ALPHA = 0x02,
/* SHIFT + OPTN (requires GETKEY_MOD_SHIFT) or LIGHT toggles backlight */
GETKEY_BACKLIGHT = 0x0004,
GETKEY_BACKLIGHT = 0x04,
/* MENU triggers a task switch and displays the main menu */
GETKEY_MENU = 0x0008,
GETKEY_MENU = 0x08,
/* Repeat arrow keys, or even all keys */
GETKEY_REP_ARROWS = 0x0010,
GETKEY_REP_ALL = 0x0020,
GETKEY_REP_ARROWS = 0x10,
GETKEY_REP_ALL = 0x20,
/* Enable custom repeat profiles; see getkey_set_repeat_profile() */
GETKEY_REP_PROFILE = 0x0040,
GETKEY_REP_PROFILE = 0x40,
/* Enable application shortcuts; see getkey_set_feature_function() */
GETKEY_FEATURES = 0x0080,
/* After coming back from the main menu, redraw the screen with dupdate */
GETKEY_MENU_DUPDATE = 0x0100,
/* After coming back from the main menu, send a KEYEV_OSMENU event */
GETKEY_MENU_EVENT = 0x0200,
/* Enable power off with SHIFT + AC/ON */
GETKEY_POWEROFF = 0x0400,
GETKEY_FEATURES = 0x80,
/* No modifiers */
GETKEY_NONE = 0x0000,
GETKEY_NONE = 0x00,
/* Default settings of getkey() */
GETKEY_DEFAULT = 0x05df,
GETKEY_DEFAULT = 0xdf,
};
/* getkey_feature_t: Custom feature function

View File

@ -108,11 +108,6 @@ void kmalloc_init_arena(kmalloc_arena_t *a, bool enable_statistics);
success, false if the maximum number of arenas has been reached. */
bool kmalloc_add_arena(kmalloc_arena_t *arena);
/* kmalloc_remove_arena(): Remove an arena from the heap source
Removes an arena from the heap source. The arena should certainly be empty,
although this function will not check that. */
void kmalloc_remove_arena(kmalloc_arena_t *arena);
//---
// Internal functions
//---

View File

@ -1,90 +0,0 @@
//---
// gint:mpu:ubc - User Break Controller
//---
#ifndef GINT_MPU_UBC
#define GINT_MPU_UBC
#ifdef __cplusplus
extern "C" {
#endif
#include <gint/defs/types.h>
typedef volatile struct
{
lword_union(CBR0, /* Match condition setting 0 */
uint32_t MFE :1; /* Match Flag Enable */
uint32_t AIE :1; /* ASID Enable */
uint32_t MFI :6; /* Match Flag Specify */
uint32_t AIV :8; /* ASID Specify */
uint32_t :1;
uint32_t SZ :3; /* Operand Size Select */
uint32_t :4;
uint32_t CD :2; /* Bus Select */
uint32_t ID :2; /* Ins. Fetch / Operand Access Select */
uint32_t :1;
uint32_t RW :2; /* Bus Command Select */
uint32_t CE :1; /* Channel Enable */
);
lword_union(CRR0, /* Match operation setting 0 */
uint32_t :18;
uint32_t _1 :1; /* Always set to 1 */
uint32_t :11;
uint32_t PCB :1; /* PC Break Select */
uint32_t BIE :1; /* Break Enable */
);
uint32_t CAR0; /* Match address setting 0 */
uint32_t CAMR0; /* Match address mask setting 0 */
pad(0x10);
lword_union(CBR1, /* Match condition setting 1 */
uint32_t MFE :1; /* Match Flag Enable */
uint32_t AIE :1; /* ASID Enable */
uint32_t MFI :6; /* Match Flag Specify */
uint32_t AIV :8; /* ASID Specify */
uint32_t DBE :1; /* Data Value Enable */
uint32_t SZ :3; /* Operand Size Select */
uint32_t ETBE :1; /* Execution Count Value Enable */
uint32_t :3;
uint32_t CD :2; /* Bus Select */
uint32_t ID :2; /* Ins. Fetch / Operand Access Select */
uint32_t :1;
uint32_t RW :2; /* Bus Command Select */
uint32_t CE :1; /* Channel Enable */
);
lword_union(CRR1, /* Match operation setting 1 */
uint32_t :18;
uint32_t _1 :1; /* Always set to 1 */
uint32_t :11;
uint32_t PCB :1; /* PC Break Select */
uint32_t BIE :1; /* Break Enable */
);
uint32_t CAR1; /* Match address setting 1 */
uint32_t CAMR1; /* Match address mask setting 1 */
uint32_t CDR1; /* Match data setting 1 */
uint32_t CDMR1; /* Match data mask setting 1 */
lword_union(CETR1, /* Execution count break 1 */
uint32_t :20;
uint32_t CET :12; /* Execution Count */
);
pad(0x5c4);
lword_union(CCMFR, /* Channel match flag */
uint32_t :30;
uint32_t MF1 :1; /* Channel 1 Condition Match Flag */
uint32_t MF0 :1; /* Channel 0 Condition Match Flag */
);
pad(0x1c);
lword_union(CBCR, /* Break control */
uint32_t :31;
uint32_t UBDE :1; /* User Break Debugging Support Function Enable */
);
} GPACKED(4) sh7305_ubc_t;
#define SH7305_UBC (*(sh7305_ubc_t *)0xff200000)
#ifdef __cplusplus
}
#endif
#endif /* GINT_MPU_UBC */

View File

@ -1,58 +0,0 @@
//---
// gint:ubc - User Break Controller driver
//---
#ifndef GINT_UBC
#define GINT_UBC
#ifdef __cplusplus
extern "C" {
#endif
#include <gint/gdb.h>
/* Read and write the DBR register */
void ubc_setDBR(void* DBR);
void* ubc_getDBR(void);
/* ubc_dbh(): Low level UBC debug handler
The handler will backup the current CPU state and call ubc_debug_handler(). */
void ubc_dbh(void);
/* ubc_debug_handler(): C level UBC debug handler
The execution will be redirected to the handler set by the user or the break
will be ignored in case no handler has been set. */
void ubc_debug_handler(gdb_cpu_state_t* cpu_state);
/* ubc_set_debug_handler(): Set user debug handler
Set a custom debug handler that will be called when a break condition from
the UBC is reached. */
void ubc_set_debug_handler(void (*h)(gdb_cpu_state_t*));
/* ubc_dbh_lock: Lock set by ubc_dbh() when a UBC break is currently being
handled. */
extern uint8_t ubc_dbh_lock;
/* UBC Breakpoint types */
typedef enum {
UBC_BREAK_BEFORE, /* Break before the instruction is executed */
UBC_BREAK_AFTER, /* Break after the instruction is executed :
at this point PC will point to the next instruction. */
} ubc_break_mode_t;
/* ubc_set_breakpoint(): Set a breakpoint in a UBC channel and enable it
Return false when an invalid channel number is provided, true if the
breakpoint was correctly set up. */
bool ubc_set_breakpoint(int channel, void* break_address, ubc_break_mode_t break_mode);
/* ubc_get_break_address(): Get a breakpoint address if it's enabled
If the channel is disabled the function will return false and *break_address
will not be updated. */
bool ubc_get_break_address(int channel, void** break_address);
/* ubc_disable_channel(): Disable a UBC channel
Return true on success. If an invalid channel number is provided, it will
return false. */
bool ubc_disable_channel(int channel);
#ifdef __cplusplus
}
#endif
#endif /* GINT_UBC */

View File

@ -32,7 +32,6 @@ extern "C" {
#endif
#include <gint/usb.h>
#include <gint/config.h>
struct usb_fxlink_header;
/* This bulk transfer interface with class code 0xff/0x77 implements a simple
@ -75,7 +74,7 @@ void usb_fxlink_screenshot(bool onscreen);
automatically send new frames to fxlink. */
void usb_fxlink_videocapture(bool onscreen);
#if GINT_RENDER_MONO
#ifdef FX9860G
/* Similar to usb_fxlink_screenshot(), but takes a gray screenshot if the gray
engine is currently running. */
void usb_fxlink_screenshot_gray(bool onscreen);

View File

@ -90,9 +90,6 @@ void usb_open_wait(void);
/* usb_is_open(): Check whether the USB link is active */
bool usb_is_open(void);
/* usb_is_open_interface(): Check whether a particular interface is open */
bool usb_is_open_interface(usb_interface_t const *interface);
/* usb_close(): Close the USB link
This function closes the link opened by usb_open(), and notifies the host of
@ -520,14 +517,6 @@ uint16_t usb_dc_string(uint16_t const *literal, size_t len);
This is mostly used by the driver to answer GET_DESCRIPTOR requests. */
usb_dc_string_t *usb_dc_string_get(uint16_t id);
//---
// USB interrupts
//---
/* usb_interrupt_context: Context of the function interrupted by a USB interrupt
The pointer is set back to NULL when the interrupt is finished being handled. */
extern gint_inth_callback_context_t* usb_interrupt_context;
#ifdef __cplusplus
}
#endif

View File

@ -1,91 +0,0 @@
//---
// gint:video - Generic video interface
//
// This header defines the interface for video (display) drivers. It allows
// high-level code to manipulate the display independently of the underlying
// hardware.
//---
#ifndef GINT_VIDEO
#define GINT_VIDEO
#ifdef __cplusplus
extern "C" {
#endif
#include <gint/defs/types.h>
#include <gint/drivers.h>
#include <gint/image.h>
/* Video mode offered by a driver for rendering. */
typedef struct {
/* Mode size */
uint16_t width;
uint16_t height;
/* Pixel format */
int16_t format;
/* Refresh frequency, -1 if unknown */
int16_t freq;
} video_mode_t;
/* Flags for the update function of the interface. */
#define VIDEO_UPDATE_ENABLE_DMA 0x01
#define VIDEO_UPDATE_ATOMIC 0x02
/* Video driver interface. */
typedef struct {
/* Associated driver (NULL if there's none). */
gint_driver_t const *driver;
/* List of modes (terminated by an all-0 element). The first mode is the
default mode and it should always be available. */
video_mode_t const *modes;
/* Get current video mode. */
uint (*mode_get)(void);
/* Set a video mode. */
bool (*mode_set)(uint id);
/* Minimum and maximum brightness settings. */
int brightness_min;
int brightness_max;
/* Set a brightness setting. */
bool (*brightness_set)(int setting);
/* Implements video_update(); bounds are checked befoer calling. */
bool (*update)(int x, int y, image_t const *framebuffer, int flags);
} video_interface_t;
/* Get the video interface currently in use. This can be NULL if the program is
being linked without a display driver. */
video_interface_t const *video_get_current_interface(void);
/* Get the index of the current video mode. This can be -1 if there is no
interface; however, if there is an interface, this is always >= 0. */
int video_get_current_mode_index(void);
/* Get the a pointer to the current video mode's definition. */
video_mode_t const *video_get_current_mode(void);
/* Update the contents of the display from a framebuffer image. A combination
of `VIDEO_UPDATE_*` flags can be specified to select the update method:
- `ENABLE_DMA` allows the driver to copy using DMA, when applicable;
- `ATOMIC` requires the driver to use an interrupt-less method.
Returns true on success.
Update flags will be ignored if not applicable (e.g. `ENABLE_DMA` for a
video interface that doesn't support DMA) but will result in an error if
applicable and the specified method fails (e.g. DMA transfer error).
This function is usually called with (x,y) = (0,0) and a contiguous
framebuffer whose size is the video mode size. Specifying images with other
sizes, positions and strides is allowed only when they result in data
transfers that are byte-aligned. DMA support is only guaranteed for
contiguous input and output. The implied rectangle must be in-bounds. */
bool video_update(int x, int y, image_t const *fb, int flags);
#ifdef __cplusplus
}
#endif
#endif /* GINT_VIDEO */

View File

@ -5,7 +5,6 @@
#include <gint/drivers.h>
#include <gint/drivers/states.h>
#include <gint/clock.h>
#include <gint/config.h>
#include <gint/hardware.h>
#include <gint/mpu/cpg.h>
@ -27,7 +26,7 @@ const clock_frequency_t *clock_freq(void)
// SH7705 Clock signals
//---
#if GINT_HW_FX
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
void sh7705_probe(void)
{
@ -58,7 +57,7 @@ void sh7705_probe(void)
freq.Pphi_f = (ckio * pll1) / freq.Pphi_div;
}
#endif
#endif /* FX9860G and platform-agnostic */
//---
// SH7305 clock signals
@ -112,7 +111,7 @@ void cpg_compute_freq(void)
{
/* This avoids warnings about sh7705_probe() being undefined when
building for fxcg50 */
#if GINT_HW_FX
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
isSH3() ? sh7705_probe() :
#endif
sh7305_probe();

View File

@ -141,7 +141,7 @@ void cpg_set_overclock_setting(struct cpg_overclock_setting const *s)
cpu_atomic_end();
}
#if GINT_HW_FX
#ifdef FX9860G
static struct cpg_overclock_setting const settings_fx9860g_sh3[5] = {
/* CLOCK_SPEED_F1 */
@ -312,9 +312,9 @@ static struct cpg_overclock_setting const settings_g35pe2[5] = {
.CS5aWCR = 0x00031B40 },
};
#endif
#endif /* FX9860G */
#if GINT_HW_CG
#ifdef FXCG50
static struct cpg_overclock_setting const settings_prizm[5] = {
/* CLOCK_SPEED_F1 */
@ -432,25 +432,25 @@ static struct cpg_overclock_setting const settings_fxcg50[5] = {
.CS5aWCR = 0x000203C1 },
};
#endif
#endif /* FXCG50 */
static struct cpg_overclock_setting const *get_settings(void)
{
#if GINT_HW_FX
#ifdef FX9860G
if(gint[HWCALC] == HWCALC_FX9860G_SH3)
return settings_fx9860g_sh3;
if(gint[HWCALC] == HWCALC_FX9860G_SH4)
return settings_fx9860g_sh4;
if(gint[HWCALC] == HWCALC_G35PE2)
return settings_g35pe2;
#endif
#endif /* FX9860G */
#if GINT_HW_CG
#ifdef FXCG50
if(gint[HWCALC] == HWCALC_PRIZM)
return settings_prizm;
if(gint[HWCALC] == HWCALC_FXCG50)
return settings_fxcg50;
#endif
#endif /* FXCG50 */
return NULL;
}

View File

@ -42,7 +42,7 @@ void fs_free_descriptor(int fd)
fdtable[fd].data = NULL;
}
int open_generic(fs_descriptor_type_t const *type, void *data, int fd)
int open_generic(fs_descriptor_type_t *type, void *data, int fd)
{
if(!fdtable) {
errno = ENOMEM;
@ -79,7 +79,7 @@ int open_generic(fs_descriptor_type_t const *type, void *data, int fd)
/* Standard streams */
static fs_descriptor_type_t const devnull = {
static fs_descriptor_type_t devnull = {
.read = NULL,
.write = NULL,
.lseek = NULL,

View File

@ -93,8 +93,6 @@ void *fugue_dir_explore(char const *path)
struct BFile_FileInfo info;
char *wildcard=NULL;
uint16_t *fc_path=NULL, *search=NULL;
/* We allocate by batches of 8 */
int sd=-1, rc, allocated=0;
dir_t *dp = malloc(sizeof *dp);
if(!dp) goto alloc_failure;
@ -102,6 +100,8 @@ void *fugue_dir_explore(char const *path)
dp->count = 0;
dp->entries = NULL;
dp->pos = 0;
/* We allocate by batches of 8 */
int sd=-1, rc, allocated=0;
fc_path = malloc(512 * sizeof *fc_path);
if(!fc_path) goto alloc_failure;
@ -118,7 +118,7 @@ void *fugue_dir_explore(char const *path)
if(rc < 0) {
if(rc != BFile_EntryNotFound)
errno = bfile_error_to_errno(rc);
goto error;
goto end;
}
do {
@ -148,9 +148,7 @@ void *fugue_dir_explore(char const *path)
alloc_failure:
errno = ENOMEM;
error:
fugue_dir_close(dp);
dp = NULL;
end:
free(wildcard);
free(search);

View File

@ -63,10 +63,6 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode)
/* If the entry is a directory, open it as such */
if(type == BFile_Type_Directory) {
void *dp = fugue_dir_explore(path);
if(!dp) {
rc = -1;
goto end;
}
fs_descriptor_t data = {
.type = &fugue_dir_descriptor_type,
.data = dp,

View File

@ -1,9 +0,0 @@
icons-i1msb.png:
type: bopti-image
profile: mono
name: gint_gdb_icons_i1msb
icons-rgb565.png:
type: bopti-image
profile: rgb565
name: gint_gdb_icons_rgb565

View File

@ -1,7 +0,0 @@
.global _gdb_stubcall_write
_gdb_stubcall_write:
mov #64, r3
trapa #33
rts
nop

View File

@ -1,881 +0,0 @@
#include <gint/cpu.h>
#include <gint/exc.h>
#include <gint/gdb.h>
#include <gint/ubc.h>
#include <gint/usb-ff-bulk.h>
#include <gint/usb.h>
#include <gint/video.h>
#include <gint/display.h>
#include <gint/config.h>
#include <gint/hardware.h>
#include <gint/fs.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define GDB_VISUAL_FEEDBACK 1
#define GDB_BRIDGE_LOGS 0
/* Note about trap numbers:
- trapa #16...#23 were historically used for Linux's syscall
interface for syscalls with up to 0...7 arguments.
- trapa #31 is unified syscall interface (Linux)
- trapa #32 is GDB software breakpoint
- trapa #33 shall thus be our stubcall. */
#define TRA_SWBREAK 32
#define TRA_STUBCALL 33
#if GDB_VISUAL_FEEDBACK
enum { ICON_WORKING, ICON_ERROR, ICON_COMM, ICON_IDLE };
static void gdb_show_stub_status(int icon)
{
// TODO[3]: Use normal way for both fx and cg (and remove display.h include)
#if GINT_RENDER_MONO
extern bopti_image_t gint_gdb_icons_i1msb;
dsubimage(120, 0, &gint_gdb_icons_i1msb, 8*icon, 0, 8, 5, DIMAGE_NONE);
dupdate();
#else
video_mode_t const *M = video_get_current_mode();
if(!M)
return;
extern image_t gint_gdb_icons_rgb565;
if(M->format == IMAGE_RGB565) {
image_t sub;
image_sub(&gint_gdb_icons_rgb565, 6*icon, 0, 7, 7, &sub);
if(!video_update(M->width-7, 0, &sub, 0))
abort();
}
#endif
}
#else
# define gdb_show_stub_status(...) ((void)0)
#endif
static void gdb_hexlify(char* output_string, const uint8_t* input_buffer, size_t input_size)
{
const char* hex = "0123456789ABCDEF";
for (size_t i = 0; i < input_size; i++) {
uint8_t byte = input_buffer[i];
output_string[i*2 + 0] = hex[(byte & 0xF0) >> 4];
output_string[i*2 + 1] = hex[byte & 0x0F];
}
}
// TODO : bug in fxlibc ? strtoul doesn't support uppercase
static uint32_t gdb_unhexlify_sized(const char* input_string, size_t input_length)
{
uint32_t ret = 0;
for (size_t i = 0; i < input_length; i++) {
uint8_t nibble_hex = tolower(input_string[i]);
uint8_t nibble = nibble_hex >= 'a' && nibble_hex <= 'f' ? nibble_hex - 'a' + 10 :
nibble_hex >= '0' && nibble_hex <= '9' ? nibble_hex - '0' : 0;
ret = (ret << 4) | nibble;
}
return ret;
}
static uint32_t gdb_unhexlify(const char* input_string)
{
return gdb_unhexlify_sized(input_string, strlen(input_string));
}
static bool gdb_started = false;
static void gdb_send(const char *data, size_t size)
{
usb_fxlink_header_t header;
usb_fxlink_fill_header(&header, "gdb", "remote", size);
int pipe = usb_ff_bulk_output();
usb_write_sync(pipe, &header, sizeof(header), false);
usb_write_sync(pipe, data, size, false);
usb_commit_sync(pipe);
}
static void gdb_send_start(void)
{
usb_fxlink_header_t header;
usb_fxlink_fill_header(&header, "gdb", "start", 0);
int pipe = usb_ff_bulk_output();
usb_write_sync(pipe, &header, sizeof(header), false);
usb_commit_sync(pipe);
}
static char *gdb_recv_buffer = NULL;
static const size_t gdb_recv_buffer_capacity = 256;
static size_t gdb_recv_buffer_size = 0;
static ssize_t gdb_recv(char *buffer, size_t buffer_size)
{
if (gdb_recv_buffer_size >= buffer_size) {
memcpy(buffer, gdb_recv_buffer, buffer_size);
memmove(gdb_recv_buffer, &gdb_recv_buffer[buffer_size], gdb_recv_buffer_size - buffer_size);
gdb_recv_buffer_size -= buffer_size;
return buffer_size;
}
usb_fxlink_header_t header;
while (!usb_fxlink_handle_messages(&header)) {
sleep();
}
// TODO : should we abort or find a way to gracefully shutdown the debugger ?
if (strncmp(header.application, "gdb", 16) == 0
&& strncmp(header.type, "remote", 16) == 0) {
if (header.size > gdb_recv_buffer_capacity - gdb_recv_buffer_size) {
abort();
}
usb_read_sync(usb_ff_bulk_input(), &gdb_recv_buffer[gdb_recv_buffer_size], header.size, false);
gdb_recv_buffer_size += header.size;
return gdb_recv(buffer, buffer_size);
} else {
abort();
}
}
static ssize_t gdb_recv_packet(char* buffer, size_t buffer_size)
{
char read_char;
// Waiting for packet start '$'
do {
if (gdb_recv(&read_char, 1) != 1) {
return -1;
}
} while (read_char != '$');
uint8_t checksum = 0;
size_t packet_len = 0;
while (true) {
if (gdb_recv(&read_char, 1) != 1) {
return -1;
}
if (read_char != '#') {
// -1 to ensure space for a NULL terminator
if (packet_len >= (buffer_size - 1)) {
return -1;
}
buffer[packet_len++] = read_char;
checksum += read_char;
} else {
break;
}
}
buffer[packet_len] = '\0';
char read_checksum_hex[3];
if (gdb_recv(read_checksum_hex, 2) != 2) {
return -1;
}
read_checksum_hex[2] = '\0';
uint8_t read_checksum = gdb_unhexlify(read_checksum_hex);
if (read_checksum != checksum) {
read_char = '-';
gdb_send(&read_char, 1);
return -1;
} else {
read_char = '+';
gdb_send(&read_char, 1);
return packet_len;
}
}
static ssize_t gdb_send_packet(const char* packet, size_t packet_length)
{
if (packet == NULL || packet_length == 0) {
// Empty packet
gdb_send("$#00", 4);
return 4;
}
size_t buffer_length = packet_length + 1 + 4;
// TODO : find if it's more efficient to malloc+copy on each packet or send 3 small fxlink messages
char* buffer = malloc(buffer_length);
uint8_t checksum = 0;
for (size_t i = 0; i < packet_length; i++) {
checksum += packet[i];
}
buffer[0] = '$';
memcpy(&buffer[1], packet, packet_length);
snprintf(&buffer[buffer_length - 4], 4, "#%02X", checksum);
// -1 to not send the NULL terminator of snprintf
gdb_send(buffer, buffer_length - 1);
free(buffer);
return buffer_length;
}
#if GDB_BRIDGE_LOGS
static void gdb_send_bridge_log(const char* fmt, ...)
{
char str[256];
va_list args;
va_start(args, fmt);
vsnprintf(str, sizeof str, fmt, args);
va_end(args);
usb_fxlink_text(str, strlen(str));
}
#else
# define gdb_send_bridge_log(...)
#endif
static int gdb_signal_number = 0;
static int gdb_trap_number = 0;
static void gdb_send_stop_reply(void)
{
char str[4] = "S00";
uint8_t num = gdb_signal_number ? gdb_signal_number : 5 /* SIGTRAP */;
gdb_hexlify(str+1, &num, 1);
gdb_send_packet(str, 3);
}
static void gdb_handle_qXfer_packet(const char* packet, const char* data, size_t data_size)
{
char offset_hex[16] = {0}, length_hex[16] = {0};
for (size_t i = 0; i < sizeof(offset_hex); i++) {
offset_hex[i] = *(packet++); // consume offset
if (*packet == ',') break;
}
packet++; // consume ','
for (size_t i = 0; i < sizeof(length_hex); i++) {
length_hex[i] = *(packet++); // consume length
if (*packet == '\0') break;
}
size_t offset = (size_t)gdb_unhexlify(offset_hex);
size_t length = (size_t)gdb_unhexlify(length_hex);
if (offset >= data_size) {
gdb_send_packet("l", 1);
} else if (offset + length >= data_size) {
char *reply_buffer = malloc(data_size - offset + 1);
reply_buffer[0] = 'l';
memcpy(&reply_buffer[1], &data[offset], data_size - offset);
gdb_send_packet(reply_buffer, data_size - offset + 1);
free(reply_buffer);
} else {
char *reply_buffer = malloc(length + 1);
reply_buffer[0] = 'm';
memcpy(&reply_buffer[1], &data[offset], length);
gdb_send_packet(reply_buffer, length + 1);
free(reply_buffer);
}
}
/* We implement the memory-map qXfer extension to mark add-in memory as read-only
* and enforce hardware breakpoints.
* See : https://sourceware.org/gdb/onlinedocs/gdb/Memory-Map-Format.html
* https://sourceware.org/gdb/onlinedocs/gdb/Set-Breaks.html
*/
// TODO : Should we mark other regions as ROM ?
static const char gdb_memory_map_xml[] = "<?xml version=\"1.0\"?>"
"<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\" \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
"<memory-map>"
// P0 mapping of add-in file
"<memory type=\"rom\" start=\"0x00300000\" length=\"0x00200000\"/>"
// P0 mapping of user RAM area
"<memory type=\"ram\" start=\"0x08100000\" length=\"0x00080000\"/>"
// Physical mapping of RAM chip (fx-CG 50)
"<memory type=\"ram\" start=\"0x8c000000\" length=\"0x01000000\"/>"
// Physical mapping of RAM chip (fx-CG 10/20 + emulator)
"<memory type=\"ram\" start=\"0x88000000\" length=\"0x01000000\"/>"
"</memory-map>";
static void gdb_handle_query_packet(const char* packet)
{
if (strncmp("qSupported", packet, 10) == 0) {
const char* qsupported_ans = "PacketSize=255;qXfer:memory-map:read+";
gdb_send_packet(qsupported_ans, strlen(qsupported_ans));
} else if (strncmp("qXfer:memory-map:read::", packet, 23) == 0) {
// -1 to not send the NULL terminator
gdb_handle_qXfer_packet(&packet[23], gdb_memory_map_xml, sizeof(gdb_memory_map_xml) - 1);
} else {
gdb_send_packet(NULL, 0);
}
}
static void gdb_handle_read_general_registers(gdb_cpu_state_t* cpu_state)
{
char reply_buffer[23*8];
if (!cpu_state) {
memset(reply_buffer, 'x', sizeof(reply_buffer));
memcpy(&reply_buffer[offsetof(gdb_cpu_state_t, reg.pc)*2],
"A0000000", 8); // pc needs to be set to make GDB happy
} else {
gdb_hexlify(reply_buffer, (uint8_t*)cpu_state->regs,
sizeof(cpu_state->regs));
}
gdb_send_packet(reply_buffer, sizeof(reply_buffer));
}
static void gdb_handle_read_register(gdb_cpu_state_t* cpu_state, const char* packet)
{
uint8_t register_id = gdb_unhexlify(&packet[1]);
char reply_buffer[8];
if (!cpu_state || register_id >= sizeof(cpu_state->regs)/sizeof(uint32_t)) {
memset(reply_buffer, 'x', sizeof(reply_buffer));
} else {
gdb_hexlify(reply_buffer, (uint8_t*)&cpu_state->regs[register_id],
sizeof(cpu_state->regs[register_id]));
}
gdb_send_packet(reply_buffer, sizeof(reply_buffer));
}
static void gdb_handle_write_general_registers(gdb_cpu_state_t* cpu_state, const char* packet)
{
if (!cpu_state) {
gdb_send_packet(NULL, 0);
return;
}
packet++; // consume 'G'
// Let's not handle incomplete 'G' packets as they're rarely used anyway
if (strlen(packet) != sizeof(cpu_state->regs)*2) {
gdb_send_packet(NULL, 0);
return;
}
for (size_t i = 0; i < sizeof(cpu_state->regs)/sizeof(uint32_t); i++) {
cpu_state->regs[i] = gdb_unhexlify_sized(&packet[i * sizeof(uint32_t) * 2],
sizeof(uint32_t) * 2);
}
gdb_send_packet("OK", 2);
}
static void gdb_handle_write_register(gdb_cpu_state_t* cpu_state, const char* packet)
{
if (!cpu_state) {
gdb_send_packet(NULL, 0);
return;
}
char register_id_hex[16] = {0}, value_hex[16] = {0};
packet++; // consume 'P'
for (size_t i = 0; i < sizeof(register_id_hex); i++) {
register_id_hex[i] = *(packet++); // consume register id
if (*packet == '=') break;
}
packet++; // consume '='
for (size_t i = 0; i < sizeof(value_hex); i++) {
value_hex[i] = *(packet++); // consume register value
if (*packet == '\0') break;
}
uint32_t register_id = gdb_unhexlify(register_id_hex);
uint32_t value = gdb_unhexlify(value_hex);
if (register_id >= sizeof(cpu_state->regs)/sizeof(uint32_t)) {
gdb_send_packet(NULL, 0);
} else {
cpu_state->regs[register_id] = value;
gdb_send_packet("OK", 2);
}
}
static volatile bool gdb_tlbh_enable = false;
static volatile bool gdb_tlbh_caught = false;
static void gdb_handle_read_memory(const char* packet)
{
char address_hex[16] = {0}, size_hex[16] = {0};
uint8_t* read_address;
size_t read_size;
packet++; // consume 'm'
for (size_t i = 0; i < sizeof(address_hex); i++) {
address_hex[i] = *(packet++); // consume address
if (*packet == ',') break;
}
packet++; // consume ','
for (size_t i = 0; i < sizeof(size_hex); i++) {
size_hex[i] = *(packet++); // consume size
if (*packet == '\0') break;
}
read_address = (uint8_t*) gdb_unhexlify(address_hex);
read_size = (size_t) gdb_unhexlify(size_hex);
char *reply_buffer = malloc(read_size * 2);
gdb_tlbh_enable = true;
gdb_tlbh_caught = false;
for (size_t i = 0; i < read_size && !gdb_tlbh_caught; i++) {
gdb_hexlify(&reply_buffer[i * 2], &read_address[i], 1);
}
gdb_tlbh_enable = false;
if (gdb_tlbh_caught) {
gdb_send_packet("E22", 3); // EINVAL
gdb_tlbh_caught = false;
} else {
gdb_send_packet(reply_buffer, read_size * 2);
}
free(reply_buffer);
}
static void cache_ocbwb(void *start, void *end)
{
/* Cache lines are 32-aligned */
void *p = (void *)((uintptr_t)start & -32);
while(p < end) {
__asm__("ocbwb @%0":: "r"(p));
p += 32;
}
}
static void cache_icbi(void *start, void *end)
{
/* Cache lines are 32-aligned */
void *p = (void *)((uintptr_t)start & -32);
while(p < end) {
__asm__("icbi @%0":: "r"(p));
p += 32;
}
}
static void gdb_handle_write_memory(const char* packet)
{
char address_hex[16] = {0}, size_hex[16] = {0};
uint8_t* read_address;
size_t read_size;
packet++; // consume 'M'
for (size_t i = 0; i < sizeof(address_hex); i++) {
address_hex[i] = *(packet++); // consume address
if (*packet == ',') break;
}
packet++; // consume ','
for (size_t i = 0; i < sizeof(size_hex); i++) {
size_hex[i] = *(packet++); // consume size
if (*packet == ':') break;
}
packet++; // consume ':'
read_address = (uint8_t*) gdb_unhexlify(address_hex);
read_size = (size_t) gdb_unhexlify(size_hex);
gdb_tlbh_enable = true;
gdb_tlbh_caught = false;
for (size_t i = 0; i < read_size && !gdb_tlbh_caught; i++) {
read_address[i] = (uint8_t)gdb_unhexlify_sized(&packet[i * 2], 2);
}
gdb_tlbh_enable = false;
cache_ocbwb(read_address, read_address + read_size);
cache_icbi(read_address, read_address + read_size);
if (gdb_tlbh_caught) {
gdb_send_packet("E22", 3); // EINVAL
gdb_tlbh_caught = false;
} else {
gdb_send_packet("OK", 2);
}
}
static bool gdb_parse_hardware_breakpoint_packet(const char* packet, void** read_address)
{
packet++; // consume 'z' or 'Z'
if (*packet != '1') { // hardware breakpoint
return false;
}
packet++; // consume '1'
packet++; // consume ','
char address_hex[16] = {0}, kind_hex[16] = {0};
for (size_t i = 0; i < sizeof(address_hex); i++) {
address_hex[i] = *(packet++); // consume address
if (*packet == ',') break;
}
packet++; // consume ','
for (size_t i = 0; i < sizeof(kind_hex); i++) {
kind_hex[i] = *(packet++); // consume kind
if (*packet == '\0' || *packet == ';') break;
}
*read_address = (void*) gdb_unhexlify(address_hex);
uint32_t read_kind = gdb_unhexlify(kind_hex);
if (read_kind != 2) { // SuperH instructions are 2 bytes long
return false;
}
return true;
}
static void gdb_handle_insert_hardware_breakpoint(const char* packet)
{
void* read_address;
if (!gdb_parse_hardware_breakpoint_packet(packet, &read_address)) {
gdb_send_bridge_log("bad Z packet\n");
gdb_send_packet(NULL, 0);
return;
}
void *channel0_addr, *channel1_addr;
bool channel0_used = ubc_get_break_address(0, &channel0_addr);
bool channel1_used = ubc_get_break_address(1, &channel1_addr);
/* As stated by GDB doc : "the operations should be implemented in an idempotent way."
* Thus we first check if the breakpoint is already placed in one of the UBC channel.
*/
if ((channel0_used && channel0_addr == read_address) ||
(channel1_used && channel1_addr == read_address)) {
gdb_send_bridge_log("hb %p: already exists\n", read_address);
gdb_send_packet("OK", 2);
} else if (!channel0_used) {
ubc_set_breakpoint(0, read_address, UBC_BREAK_BEFORE);
gdb_send_bridge_log("hb %p: using channel 0\n", read_address);
gdb_send_packet("OK", 2);
} else if (!channel1_used) {
ubc_set_breakpoint(1, read_address, UBC_BREAK_BEFORE);
gdb_send_bridge_log("hb %p: using channel 1\n", read_address);
gdb_send_packet("OK", 2);
} else {
/* TODO : We should find a proper way to inform GDB that we are
* limited by the number of UBC channels.
*/
gdb_send_bridge_log("hb %p: channels used (%p, %p)\n", read_address,
channel0_addr, channel1_addr);
gdb_send_packet(NULL, 0);
}
}
static void gdb_handle_remove_hardware_breakpoint(const char* packet)
{
void* read_address;
if (!gdb_parse_hardware_breakpoint_packet(packet, &read_address)) {
gdb_send_packet(NULL, 0);
return;
}
void *channel0_addr, *channel1_addr;
bool channel0_used = ubc_get_break_address(0, &channel0_addr);
bool channel1_used = ubc_get_break_address(1, &channel1_addr);
if (channel0_used && channel0_addr == read_address) {
ubc_disable_channel(0);
}
if (channel1_used && channel1_addr == read_address) {
ubc_disable_channel(1);
}
gdb_send_packet("OK", 2);
}
static void gdb_handle_continue_with_signal(gdb_cpu_state_t* cpu_state,
const char* packet)
{
packet++; // consume 'C'
int signal = gdb_unhexlify_sized(packet, 2);
char exit[4] = { 'X', packet[0], packet[1], 0 };
packet += 2;
if(*packet == ';')
cpu_state->reg.pc = gdb_unhexlify(packet + 1);
// TODO: This is a heuristic replacing the normal signal system
uint32_t kills =
(1 << 4) /* SIGILL */
+ (1 << 6) /* SIGABRT */
+ (1 << 7) /* SIGEMT */
+ (1 << 8) /* SIGFPE */
+ (1 << 9) /* SIGKILL */
+ (1 << 11) /* SIGSEGV */
+ (1 << 15); /* SIGTERM */
// Abort if the signal is kill by default
if((uint)signal < 32 && (kills >> signal) & 1) {
gdb_send_packet(exit, 3);
abort();
}
}
static struct {
bool single_stepped;
bool channel0_used;
bool channel1_used;
void* channel0_addr;
void* channel1_addr;
} gdb_single_step_backup = { false };
static void gdb_handle_single_step(uint32_t pc, ubc_break_mode_t break_mode)
{
gdb_single_step_backup.channel0_used = ubc_get_break_address(0, &gdb_single_step_backup.channel0_addr);
gdb_single_step_backup.channel1_used = ubc_get_break_address(1, &gdb_single_step_backup.channel1_addr);
ubc_disable_channel(0);
ubc_set_breakpoint(1, (void*)pc, break_mode);
gdb_single_step_backup.single_stepped = true;
}
static bool gdb_handle_stubcall(gdb_cpu_state_t* cpu_state)
{
char str[30];
int sc_num = cpu_state->reg.r3;
if(sc_num == 64) { /* write */
int len = snprintf(str, sizeof str, "Fwrite,%x,%08x,%x",
cpu_state->reg.r4,
cpu_state->reg.r5,
cpu_state->reg.r6);
gdb_send_packet(str, len);
return true;
}
return false;
}
void gdb_main(gdb_cpu_state_t* cpu_state)
{
if (!gdb_started && gdb_start()) {
gdb_show_stub_status(ICON_ERROR);
return;
}
gdb_show_stub_status(ICON_IDLE);
if (gdb_single_step_backup.single_stepped) {
if (gdb_single_step_backup.channel0_used) {
ubc_set_breakpoint(0, gdb_single_step_backup.channel0_addr, UBC_BREAK_BEFORE);
} else {
ubc_disable_channel(0);
}
if (gdb_single_step_backup.channel1_used) {
ubc_set_breakpoint(1, gdb_single_step_backup.channel1_addr, UBC_BREAK_BEFORE);
} else {
ubc_disable_channel(1);
}
gdb_single_step_backup.single_stepped = false;
}
if (cpu_state != NULL) {
/* Ajust PC after a software breakpoint */
if (gdb_trap_number == TRA_SWBREAK)
cpu_state->reg.pc -= 2;
/* Handle stubcall but fallback to normal stop if it fails */
if (gdb_trap_number != TRA_STUBCALL || !gdb_handle_stubcall(cpu_state))
gdb_send_stop_reply();
}
while (1) {
gdb_show_stub_status(ICON_COMM);
char packet_buffer[256];
ssize_t packet_size = gdb_recv_packet(packet_buffer, sizeof(packet_buffer));
if (packet_size <= 0) {
// TODO : Should we break or log on recv error ?
continue;
}
gdb_show_stub_status(ICON_WORKING);
switch (packet_buffer[0]) {
case '?': // Halt reason
gdb_send_stop_reply();
break;
case 'q':
gdb_handle_query_packet(packet_buffer);
break;
case 'g':
gdb_handle_read_general_registers(cpu_state);
break;
case 'p':
gdb_handle_read_register(cpu_state, packet_buffer);
break;
case 'm':
gdb_handle_read_memory(packet_buffer);
break;
case 'G':
gdb_handle_write_general_registers(cpu_state, packet_buffer);
break;
case 'P':
gdb_handle_write_register(cpu_state, packet_buffer);
break;
case 'M':
gdb_handle_write_memory(packet_buffer);
break;
case 'k': // Kill request
abort();
case 'Z':
gdb_handle_insert_hardware_breakpoint(packet_buffer);
break;
case 'z':
gdb_handle_remove_hardware_breakpoint(packet_buffer);
break;
case 's':
gdb_handle_single_step(cpu_state->reg.pc, UBC_BREAK_AFTER);
goto ret;
case 'c': // Continue
goto ret;
case 'C': // Continue with signal
gdb_handle_continue_with_signal(cpu_state, packet_buffer);
// We'll often abort() at the signal rather than continuing
goto ret;
case 'F': // Continue after File I/O call response
// TODO: parse 'F' response packets.
goto ret;
default: // Unsupported packet
gdb_send_packet(NULL, 0);
break;
}
gdb_show_stub_status(ICON_IDLE);
}
ret:
// We're started after the first round of exchanges
gdb_started = true;
gdb_signal_number = 0;
gdb_trap_number = 0;
}
static void gdb_notifier_function(void)
{
// We ignore fxlink notifications when we're already inside GDB code.
if (ubc_dbh_lock || !gdb_started)
return;
// We make sure we are called during a USB interrupt.
if (usb_interrupt_context == NULL)
return;
// And we make sure an other step break is not already set up.
if (gdb_single_step_backup.single_stepped)
return;
gdb_handle_single_step(usb_interrupt_context->spc, UBC_BREAK_AFTER);
}
static int gdb_panic_handler(uint32_t code)
{
// Catch memory access errors from GDB trying to read/print stuff
if (gdb_tlbh_enable) {
// We only handle TLB miss reads (0x040) and writes (0x060)
if (code != 0x040 && code != 0x060)
return 1;
gdb_tlbh_caught = true;
// We skip the offending instruction and continue
gint_exc_skip(1);
return 0;
}
// If we are in user code, let's break
else if (!ubc_dbh_lock) {
// We make sure an other step break is not already set up
if (gdb_single_step_backup.single_stepped)
return 1;
// TODO: This only works for re-execution type exceptions
uint32_t spc;
__asm__("stc spc, %0" : "=r"(spc));
gdb_handle_single_step(spc, UBC_BREAK_BEFORE);
// Break reason
if(code == 0x040 || code == 0x060 || code == 0x0e0 || code == 0x100)
gdb_signal_number = 11; /* SIGSEGV */
if(code == 0x160)
gdb_signal_number = 5; /* SIGTRAP */
if(code == 0x180 || code == 0x1a0)
gdb_signal_number = 4; /* SIGILL */
if(code >= 0x1000 && code != 0x10a0)
gdb_signal_number = 5; /* SIGTRAP */
if(code == 0x10a0)
gdb_signal_number = 7; /* SIGEMT (used here for bad UBC breaks) */
// Specific stop reasons
if(code == 0x160) {
uint32_t TRA = isSH3() ? 0xffffffd0 : 0xff000020;
gdb_trap_number = *(uint32_t volatile *)TRA >> 2;
}
return 0;
}
return 1;
}
static bool gdb_redirect_stdout = false;
static bool gdb_redirect_stderr = false;
static fs_descriptor_type_t const redirect_type = {
.read = NULL,
.write = (void *)gdb_stubcall_write,
.lseek = NULL,
.close = NULL,
};
int gdb_start(void)
{
if (gdb_started)
return 0;
gdb_show_stub_status(ICON_WORKING);
if(usb_is_open() && !usb_is_open_interface(&usb_ff_bulk))
usb_close();
if(!usb_is_open()) {
usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL };
if(usb_open(interfaces, GINT_CALL_NULL) < 0)
return -1;
usb_open_wait();
}
usb_fxlink_set_notifier(gdb_notifier_function);
gdb_send_start();
if (!gdb_recv_buffer) {
gdb_recv_buffer = malloc(gdb_recv_buffer_capacity);
}
// Redirect standard streams
if(gdb_redirect_stdout) {
close(STDOUT_FILENO);
open_generic(&redirect_type, (void *)STDOUT_FILENO, STDOUT_FILENO);
}
if(gdb_redirect_stderr) {
close(STDERR_FILENO);
open_generic(&redirect_type, (void *)STDERR_FILENO, STDERR_FILENO);
}
// TODO : Should we detect if other panic or debug handlers are setup ?
gint_exc_catch(gdb_panic_handler);
ubc_set_debug_handler(gdb_main);
return 0;
}
void gdb_start_on_exception(void)
{
gint_exc_catch(gdb_panic_handler);
ubc_set_debug_handler(gdb_main);
}
void gdb_redirect_streams(bool stdout, bool stderr)
{
gdb_redirect_stdout = stdout;
gdb_redirect_stderr = stderr;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 B

View File

@ -11,15 +11,6 @@
#include <stdlib.h>
#include "../render-fx/render-fx.h"
#include "../render/render.h"
#include <gint/config.h>
#if GINT_HW_CG
#include <gint/drivers/r61524.h>
#endif
// TODO: Move the gray "engine" part into the T6K11 driver.
#if GINT_RENDER_MONO
/* Three additional video RAMS, allocated statically if --static-gray was set
at configure time, or with malloc() otherwise. */
@ -30,8 +21,6 @@ GBSS static uint32_t gvrams[3][256];
/* Four VRAMs: two to draw and two to display */
static uint32_t *vrams[4] = { NULL, NULL, NULL, NULL };
#if GINT_HW_FX
/* Current VRAM pair used for drawing; the value can either be 0 (draws to
VRAMs 0 and 1) or 2 (draws to VRAMs 2 and 3). */
static int volatile st = 0;
@ -46,10 +35,6 @@ static int runs = 0;
/* Delays of the light and dark frames for the above setting */
GBSS static int delays[2];
static int gray_int(void);
#endif
/* The alternate rendering mode structure used to override d*() */
static struct rendering_mode const gray_mode = {
.dupdate = gupdate,
@ -78,16 +63,13 @@ static struct rendering_mode const gray_exit_mode = {
// Engine control (init/quit and start/stop)
//---
static int gray_int(void);
static void gray_quit(void);
/* gray_isinit(): Check whether the engine is initialized and ready to run */
static int gray_isinit(void)
{
return (vrams[0] && vrams[1] && vrams[2] && vrams[3]
#if GINT_HW_FX
&& timer >= 0
#endif
);
return (vrams[0] && vrams[1] && vrams[2] && vrams[3] && timer >= 0);
}
/* gray_init(): Initialize the engine
@ -108,7 +90,6 @@ GCONSTRUCTOR static void gray_init(void)
vrams[3] = malloc(1024);
#endif /* GINT_STATIC_GRAY */
#if GINT_HW_FX
/* Default delays from Graph 35+E II are different from other models */
if(gint[HWCALC] == HWCALC_G35PE2)
{
@ -124,7 +105,6 @@ GCONSTRUCTOR static void gray_init(void)
/* Try to obtain the timer right away */
timer = timer_configure(GRAY_TIMER | GRAY_CLOCK, 1000,
GINT_CALL(gray_int));
#endif
/* On failure, release the resources that we obtained */
if(!gray_isinit()) gray_quit();
@ -143,13 +123,10 @@ GDESTRUCTOR static void gray_quit(void)
vrams[3] = NULL;
#endif /* GINT_STATIC_GRAY */
#if GINT_HW_FX
if(timer >= 0) timer_stop(timer);
timer = -1;
#endif
}
#if GINT_HW_FX
/* gray_start(): Start the gray engine */
static void gray_start(void)
{
@ -166,7 +143,6 @@ static void gray_stop(void)
runs = 0;
st = 0;
}
#endif
//---
// Dynamic udpate and rendering mode
@ -220,7 +196,6 @@ int dgray(int mode)
return 0;
}
#if GINT_HW_FX
/* gray_int(): Interrupt handler */
int gray_int(void)
{
@ -252,19 +227,6 @@ int gupdate(void)
st ^= 2;
return 0;
}
#elif GINT_HW_CG
int gupdate(void)
{
if(dmode == &gray_exit_mode)
{
dmode = NULL;
return 1;
}
r61524_display_gray_128x64(vrams[0], vrams[1]);
return 0;
}
#endif
//---
// Query and configuration functions
@ -276,7 +238,6 @@ int dgray_enabled(void)
return (dmode == &gray_mode);
}
#if GINT_HW_FX
/* dgray_setdelays(): Set the gray engine delays */
void dgray_setdelays(uint32_t light, uint32_t dark)
{
@ -308,12 +269,3 @@ void dgray_getscreen(uint32_t **light, uint32_t **dark)
if(light) *light = vrams[base & 2];
if(dark) *dark = vrams[base | 1];
}
#elif GINT_HW_CG
void dgray_getvram(uint32_t **light, uint32_t **dark)
{
*light = vrams[0];
*dark = vrams[1];
}
#endif
#endif /* GINT_RENDER_MONO && GINT_HW_FX */

View File

@ -1,7 +1,4 @@
#include <gint/gray.h>
#include <gint/config.h>
#if GINT_RENDER_MONO
/* gclear(): Fill the screen with a single color */
void gclear(color_t color)
@ -38,5 +35,3 @@ void gclear(color_t color)
dark += 8;
}
}
#endif /* GINT_RENDER_MONO */

View File

@ -1,8 +1,5 @@
#include <gint/gray.h>
#include <gint/defs/types.h>
#include <gint/config.h>
#if GINT_RENDER_MONO
int ggetpixel(int x, int y)
{
@ -16,5 +13,3 @@ int ggetpixel(int x, int y)
bool d = (dark [offset] & mask) != 0;
return (d << 1) | l;
}
#endif /* GINT_RENDER_MONO */

View File

@ -1,8 +1,5 @@
#include <gint/display.h>
#include <gint/defs/util.h>
#include <gint/config.h>
#if GINT_RENDER_MONO
/* gint_ghline(): Optimized horizontal line, but not actually optimized */
void gint_ghline(int x1, int x2, int y, int color)
@ -17,5 +14,3 @@ void gint_gvline(int y1, int y2, int x, int color)
if(y1 > y2) swap(y1, y2);
for(int y = y1; y <= y2; y++) dpixel(x, y, color);
}
#endif /* GINT_RENDER_MONO */

View File

@ -1,8 +1,5 @@
#include <gint/gray.h>
#include <gint/defs/types.h>
#include <gint/config.h>
#if GINT_RENDER_MONO
/* gpixel(): Change a pixel's color */
void gpixel(int x, int y, color_t color)
@ -58,5 +55,3 @@ void gpixel(int x, int y, color_t color)
break;
}
}
#endif /* GINT_RENDER_MONO */

View File

@ -1,9 +1,6 @@
#include <gint/defs/util.h>
#include <gint/gray.h>
#include "../render-fx/render-fx.h"
#include <gint/config.h>
#if GINT_RENDER_MONO
/* grect(): Fill a rectangle on the screen */
void grect(int x1, int y1, int x2, int y2, color_t color)
@ -115,5 +112,3 @@ void grect(int x1, int y1, int x2, int y2, color_t color)
light++, dark++;
}
}
#endif /* GINT_RENDER_MONO */

View File

@ -1,8 +1,6 @@
#include <gint/gray.h>
#include "../render-fx/render-fx.h"
#include <gint/config.h>
#if GINT_RENDER_MONO
#include "../render-fx/bopti-asm.h"
#pragma GCC optimize("O3")
@ -39,5 +37,3 @@ void gsubimage(bopti_image_t const *img, struct rbox *r, GUNUSED int flags)
bopti_render(img, r, light, dark);
}
}
#endif /* GINT_RENDER_MONO */

View File

@ -1,9 +1,6 @@
#include <gint/gray.h>
#include "../render/render.h"
#include "../render-fx/render-fx.h"
#include <gint/config.h>
#if GINT_RENDER_MONO
#include "../render-fx/topti-asm.h"
/* gtext_opt(): Display a string of text */
void gtext_opt(int x, int y, int fg, int bg, int halign, int valign,
@ -26,5 +23,3 @@ void gtext_opt(int x, int y, int fg, int bg, int halign, int valign,
topti_render(x, y, str, topti_font, topti_asm_text[fg],
topti_asm_text[bg], light, dark, size);
}
#endif /* GINT_RENDER_MONO */

View File

@ -5,8 +5,6 @@
#ifndef GINT_IMAGE_FIXED
#define GINT_IMAGE_FIXED
#include <stdint.h>
/* Constants */
#define fconst(x) ((x) * 65536)

View File

@ -1,8 +1,6 @@
#include <gint/image.h>
#include <stdlib.h>
#include <gint/defs/util.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
image_t *image_alloc(int width, int height, int format)
{
@ -27,5 +25,3 @@ image_t *image_alloc(int width, int height, int format)
img->flags |= IMAGE_FLAGS_DATA_ALLOC;
return img;
}
#endif

View File

@ -3,9 +3,6 @@
#include <stdlib.h>
#include <string.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
bool image_alloc_palette(image_t *img, int size)
{
if(!img || !IMAGE_IS_INDEXED(img->format))
@ -32,5 +29,3 @@ bool image_alloc_palette(image_t *img, int size)
img->flags |= IMAGE_FLAGS_PALETTE_ALLOC;
return true;
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
int image_alpha(int format)
{
@ -16,5 +14,3 @@ int image_alpha(int format)
return 0x10000;
}
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_clear(image_t *img)
{
@ -9,5 +7,3 @@ void image_clear(image_t *img)
image_fill(img, image_alpha(img->format));
}
#endif

View File

@ -1,7 +1,5 @@
#include <gint/image.h>
#include <gint/defs/util.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_copy(image_t const *src, image_t *dst, bool copy_alpha)
{
@ -122,5 +120,3 @@ void image_copy(image_t const *src, image_t *dst, bool copy_alpha)
} while(--h > 0);
}
}
#endif

View File

@ -2,9 +2,6 @@
#include <gint/defs/util.h>
#include <string.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
image_t *image_copy_alloc(image_t const *src, int new_format)
{
if(!image_valid(src))
@ -21,5 +18,3 @@ image_t *image_copy_alloc(image_t const *src, int new_format)
image_copy(src, dst, true);
return dst;
}
#endif

View File

@ -2,9 +2,6 @@
#include <gint/defs/util.h>
#include <string.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
bool image_copy_palette(image_t const *src, image_t *dst, int size)
{
if(!image_valid(src) || !dst)
@ -21,5 +18,3 @@ bool image_copy_palette(image_t const *src, image_t *dst, int size)
memcpy(dst->palette, src->palette, 2*N);
return true;
}
#endif

View File

@ -1,9 +1,6 @@
#include <gint/image.h>
#include <stdlib.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
image_t *image_create(int width, int height, int format)
{
if(!IMAGE_IS_RGB16(format) && !IMAGE_IS_P8(format) && !IMAGE_IS_P4(format))
@ -26,5 +23,3 @@ image_t *image_create(int width, int height, int format)
return img;
}
#endif

View File

@ -1,7 +1,5 @@
#include <gint/image.h>
#include <gint/display.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
image_t *image_create_vram(void)
{
@ -13,5 +11,3 @@ image_t *image_create_vram(void)
img->data = gint_vram;
return img;
}
#endif

View File

@ -1,10 +1,6 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
int image_data_size(image_t const *img)
{
return img->stride * img->height;
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
int image_decode_pixel(image_t const *img, int pixel)
{
@ -12,5 +10,3 @@ int image_decode_pixel(image_t const *img, int pixel)
return img->palette[pixel];
return -1;
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_fill(image_t *img, int value)
{
@ -26,5 +24,3 @@ void image_fill(image_t *img, int value)
}
}
}
#endif

View File

@ -2,9 +2,6 @@
#include <gint/mmu.h>
#include <stdlib.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_free(image_t *img)
{
if(!img || mmu_is_rom(img))
@ -17,5 +14,3 @@ void image_free(image_t *img)
free(img);
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
int image_get_pixel(image_t const *img, int x, int y)
{
@ -25,5 +23,3 @@ int image_get_pixel(image_t const *img, int x, int y)
}
return 0;
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_hflip(image_t const *src, image_t *dst, bool copy_alpha)
{
@ -47,5 +45,3 @@ void image_hflip(image_t const *src, image_t *dst, bool copy_alpha)
}
}
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
image_t *image_hflip_alloc(image_t const *src)
{
@ -16,5 +14,3 @@ image_t *image_hflip_alloc(image_t const *src)
image_hflip(src, dst, true);
return dst;
}
#endif

View File

@ -1,6 +1,3 @@
#include <gint/config.h>
#if GINT_RENDER_RGB
.global _image_linear_rgb16
.global _image_linear_p8
@ -127,5 +124,3 @@ _image_linear_rgb16:
_image_linear_p8:
GEN_LINEAR_LOOP mov.b, 1
#endif

View File

@ -2,9 +2,6 @@
#include <gint/defs/util.h>
#include "fixed.h"
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_linear_rgb16(void *src, void *dst, struct image_linear_map *map);
void image_linear_p8(void *src, void *dst, struct image_linear_map *map);
@ -35,5 +32,3 @@ void image_linear(image_t const *src, image_t *dst,
else if(IMAGE_IS_P8(src->format))
image_linear_p8(src->data, dst->data, map);
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
image_t *image_linear_alloc(image_t const *src, struct image_linear_map *map)
{
@ -20,5 +18,3 @@ image_t *image_linear_alloc(image_t const *src, struct image_linear_map *map)
image_linear(src, dst, map);
return dst;
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_rotate(image_t const *src, float angle, bool resize,
struct image_linear_map *map)
@ -13,5 +11,3 @@ void image_rotate(image_t const *src, float angle, bool resize,
image_rotate_around(src, angle, resize, &center_x, &center_y, map);
}
#endif

View File

@ -1,14 +1,9 @@
#include <gint/image.h>
#include "fixed.h"
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_rotate_around(image_t const *src, float angle, bool resize,
int *center_x, int *center_y, struct image_linear_map *map)
{
image_rotate_around_scale(src, angle, fconst(1.0), resize, center_x,
center_y, map);
}
#endif

View File

@ -2,9 +2,6 @@
#include <math.h>
#include "fixed.h"
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_rotate_around_scale(image_t const *src, float alpha, int gamma,
bool resize, int *center_x, int *center_y, struct image_linear_map *map)
{
@ -61,5 +58,3 @@ void image_rotate_around_scale(image_t const *src, float alpha, int gamma,
*center_x = new_center_x;
*center_y = new_center_y;
}
#endif

View File

@ -1,9 +1,6 @@
#include <gint/image.h>
#include "fixed.h"
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_scale(image_t const *src, int gamma_x, int gamma_y,
struct image_linear_map *map)
{
@ -25,5 +22,3 @@ void image_scale(image_t const *src, int gamma_x, int gamma_y,
map->dst_w = fround(src->width * gamma_x);
map->dst_h = fround(src->height * gamma_y);
}
#endif

View File

@ -1,9 +1,6 @@
#include <gint/image.h>
#include <stdlib.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_set_palette(image_t *img, uint16_t *palette, int size, bool owns)
{
if(!img || !IMAGE_IS_INDEXED(img->format))
@ -19,5 +16,3 @@ void image_set_palette(image_t *img, uint16_t *palette, int size, bool owns)
else
img->flags &= ~IMAGE_FLAGS_PALETTE_ALLOC;
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void image_set_pixel(image_t const *img, int x, int y, int value)
{
@ -26,5 +24,3 @@ void image_set_pixel(image_t const *img, int x, int y, int value)
data_u8[x >> 1] = (data_u8[x >> 1] & 0x0f) | (value << 4);
}
}
#endif

View File

@ -3,9 +3,6 @@
#include <string.h>
#undef image_sub
#include <gint/config.h>
#if GINT_RENDER_RGB
static image_t image_sub_default;
image_t *image_sub(image_t const *src, int left, int top, int w, int h,
@ -42,5 +39,3 @@ image_t *image_sub(image_t const *src, int left, int top, int w, int h,
dst->palette = src->palette;
return dst;
}
#endif

View File

@ -1,9 +1,6 @@
#include <gint/image.h>
#undef image_target
#include <gint/config.h>
#if GINT_RENDER_RGB
bool image_target(image_t const *src, image_t *dst, ...)
{
if(!image_valid(src) || !image_valid(dst))
@ -40,5 +37,3 @@ bool image_target(image_t const *src, image_t *dst, ...)
va_end(args);
return true;
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
bool image_valid(image_t const *img)
{
@ -18,5 +16,3 @@ bool image_valid(image_t const *img)
/* Invalid format */
return false;
}
#endif

View File

@ -1,8 +1,6 @@
#include <gint/image.h>
#include <stdlib.h>
#include <string.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
static void copy_row_rgb16(uint16_t *src, uint16_t *dst, int src_alpha,
int dst_alpha, int width)
@ -62,5 +60,3 @@ void image_vflip(image_t const *src, image_t *dst, bool copy_alpha)
free(row);
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/image.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
image_t *image_vflip_alloc(image_t const *src)
{
@ -16,5 +14,3 @@ image_t *image_vflip_alloc(image_t const *src)
image_vflip(src, dst, true);
return dst;
}
#endif

View File

@ -60,8 +60,6 @@ static struct info {
{ IPRF, 0x0f00, IMR5, 0x10, _ },
{ IPRF, 0x0f00, IMR5, 0x20, _ },
{ IPRF, 0x0f00, IMR5, 0x40, _ },
/* SCIF */
{ IPRG, 0xf000, IMR5, 0x01, _ /* Driver not SH3-compatible yet */ },
/* RTC */
{ IPRK, 0xf000, IMR10, 0x04, IPRA, 0x000f },
{ IPRK, 0xf000, IMR10, 0x02, IPRA, 0x000f },

View File

@ -6,7 +6,6 @@
#include <gint/defs/attributes.h>
#include <gint/hardware.h>
#include <gint/gint.h>
#include <gint/config.h>
#include <stdlib.h>
#include <string.h>
@ -60,7 +59,7 @@ GNORETURN static void gint_default_panic(GUNUSED uint32_t code)
dfont(NULL);
#if GINT_RENDER_MONO
#ifdef FX9860G
memset(gint_vram, 0, 1024);
dtext(1, 0, "Exception! (SysERROR)");
for(int i = 0; i < 32; i++) gint_vram[i] = ~gint_vram[i];
@ -79,7 +78,6 @@ GNORETURN static void gint_default_panic(GUNUSED uint32_t code)
if(code == 0x1040) name = "Add-in too large";
if(code == 0x1060) name = "Memory init failed";
if(code == 0x1080) name = "Stack overflow";
if(code == 0x10a0) name = "UBC in bank 1 code";
if(name[0]) dtext(1, 9, name);
else dprint(1, 9, "%03x", code);
@ -98,7 +96,7 @@ GNORETURN static void gint_default_panic(GUNUSED uint32_t code)
}
#endif
#if GINT_RENDER_RGB
#ifdef FXCG50
/* Don't require the DMA driver just for a clear */
memset(gint_vram, 0xff, DWIDTH*DHEIGHT*2);
dtext(6, 3, "An exception occured! (System ERROR)");
@ -120,7 +118,6 @@ GNORETURN static void gint_default_panic(GUNUSED uint32_t code)
if(code == 0x1040) name = "Add-in not fully mapped (too large)";
if(code == 0x1060) name = "Memory initialization failed (heap)";
if(code == 0x1080) name = "Stack overflow during world switch";
if(code == 0x10a0) name = "UBC break in register bank 1 code";
dprint(6, 25, "%03x %s", code, name);

View File

@ -8,7 +8,6 @@
#include <gint/defs/types.h>
#include <gint/defs/util.h>
#include <gint/mpu/pfc.h>
#include <gint/config.h>
#include <string.h>
@ -20,7 +19,7 @@ GBSS uint32_t gint[HW_KEYS];
/* Product Register */
#define PRR (*((volatile uint32_t *)0xff000044))
#if GINT_HW_FX
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
/* mpu_detect() - detect the underlying MPU
Many thanks to Simon Lothar for relevant documentation.
@ -117,7 +116,9 @@ void hw_detect(void)
else utlb_mapped_memory(NULL, NULL);
}
#elif GINT_HW_CG
#endif /* FX9860G and platform-agnostic */
#ifdef FXCG50
/* hw_detect(): Basic hardware detection */
void hw_detect(void)
@ -145,6 +146,4 @@ void hw_detect(void)
utlb_mapped_memory(NULL, NULL);
}
#else
#error unknown hardware type for hw_detect
#endif
#endif /* FXCG50 */

View File

@ -7,11 +7,10 @@
#define CPP_ASM
#include <gint/hardware.h>
#include <gint/config.h>
.global _gint_inth_7305
#if GINT_HW_FX
#ifdef FX9860G
.global _gint_inth_7705
#endif
@ -101,7 +100,7 @@ _gint_inth_7305:
1: .long 0xff000028
.first_entry:
#if GINT_HW_FX
#ifdef FX9860G
/* SH7705-TYPE INTERRUPT HANDLER ENTRY - 56 BYTES */
@ -210,15 +209,11 @@ _gint_inth_callback_reloc:
stc.l r7_bank, @-r15
stc.l spc, @-r15
stc.l ssr, @-r15
/* We backup the address of the gint_inth_callback_context_t built on
the stack to the user bank. */
ldc r15, r4_bank
stc.l sr, @-r15
/* Save some values to user bank; once we enable interrupts, the kernel
bank might be overwritten at any moment. */
ldc r4, r3_bank
ldc r4, r0_bank
/* Enable interrupts and go back to user bank. On SH4, SR.IMASK is set
to the level of the current interrupt, which makes sure we can only
@ -248,25 +243,15 @@ _gint_inth_callback_reloc:
.load_sr:
ldc r1, sr
/* We are now in the user bank with r3 set. Perform the call. We want
/* We are now in the user bank with r0 set. Perform the call. We want
to forward the return value to kernel bank, but this bank can be
changed at any moment since interrupts are enabled. */
sts.l pr, @-r15
/* We only set r4 to the value of the first argument in the gint_call_t
if the address is even (i.e. GINT_CALL_FLAG() was not used). */
mov.l @r3, r0
tst #1, r0
bf .do_not_set_r4
mov.l @(4, r3), r4
.do_not_set_r4:
/* And we make sure to realign the address in case it was odd. */
mov #0xfe, r2
and r2, r0
mov.l @(8, r3), r5
mov.l @(12, r3), r6
mov.l @(16, r3), r7
mov.l @(4, r0), r4
mov.l @(8, r0), r5
mov.l @(12, r0), r6
mov.l @(16, r0), r7
mov.l @r0, r0
jsr @r0
nop
lds.l @r15+, pr

View File

@ -42,7 +42,7 @@ void kinit(void)
{
uint32_t VBR = 0;
#if GINT_HW_FX
#ifdef FX9860G
/* On fx-9860G, VBR is loaded at the end of the user RAM. On SH4, the
end of the user RAM hosts the stack, for which we leave 12 kB
(0x3000 bytes). The VBR space takes about 0x600 bytes on SH3 due to
@ -60,9 +60,9 @@ void kinit(void)
/* VBR is advanced 0x100 bytes because of an unused gap */
uram_end -= (isSH3() ? 0x600 : 0x1100);
VBR = uram_end - 0x100;
#endif
#endif /* FX9860G */
#if GINT_HW_CG
#ifdef FXCG50
/* On fx-CG 50, VBR is loaded at the start of the user RAM; the linker
script leaves 5 kB (0x1400 bytes) before the start of the data
segment. The stack is again placed at the end of the region, and we
@ -96,7 +96,7 @@ void kinit(void)
kmalloc_add_arena(&static_ram);
/* Create an arena in the OS stack as well, for VRAM and more data */
#if GINT_HW_CG && !defined(GINT_NO_OS_STACK)
#if defined(FXCG50) && !defined(GINT_NO_OS_STACK)
static kmalloc_arena_t os_stack = { 0 };
os_stack.name = "_ostk";
os_stack.is_default = true;
@ -107,17 +107,19 @@ void kinit(void)
os_stack.end = os_stack.start + (350 * 1024);
kmalloc_init_arena(&os_stack, true);
kmalloc_add_arena(&os_stack);
#endif
#endif /* FXCG50 && !GINT_NO_OS_STACK */
/* Allocate world buffers for the OS and for gint */
gint_world_os = gint_world_alloc();
gint_world_addin = gint_world_alloc();
gint_driver_flags = malloc(gint_driver_count());
#ifdef FXCG50
/* Allocate VRAMs, which is important for panic screens */
extern bool dvram_init(void);
if(!dvram_init())
abort();
#endif
if(!gint_world_os || !gint_world_addin || !gint_driver_flags)
gint_panic(0x1060);

View File

@ -5,13 +5,6 @@
#ifndef GINT_CORE_KERNEL
#define GINT_CORE_KERNEL
/* gint_load_onchip_sections(): Initialize on-chip memory sections */
void gint_load_onchip_sections(void);
/* gint_copy_vram(): Copy gint's VRAM to the OS to avoid flickering during
certain world switches. */
void gint_copy_vram(void);
/* kinit(): Install and start gint */
void kinit(void);

View File

@ -1,8 +1,6 @@
#include <gint/gint.h>
#include <gint/display.h>
#include <gint/hardware.h>
#include <gint/keyboard.h>
#include "kernel.h"
#include <string.h>
@ -13,6 +11,7 @@ int __Timer_Deinstall(int id);
int __PutKeyCode(int row, int column, int keycode);
int __GetKeyWait(int *col,int *row,int type,int time,int menu,uint16_t *key);
void __ClearKeyBuffer(void); /* ? */
void *__GetVRAMAddress(void);
void __ConfigureStatusArea(int mode);
void __SetQuitHandler(void (*callback)(void));
@ -29,92 +28,29 @@ static void __osmenu_handler(void)
__Timer_Deinstall(__osmenu_id);
}
#if GINT_OS_CG
typedef void (os_menu_function_t)(void);
/* This method is possible thanks to reverse-engineering by Dr-Carlos.
<https://www.cemetech.net/forum/viewtopic.php?t=18944> */
static os_menu_function_t *find_os_menu_function(void)
{
/* Get syscall table address */
uint32_t addr = *(uint32_t *)0x8002007c;
if(addr < 0x80020070 || addr >= 0x81000000 - 0x1e58 * 4)
return NULL;
/* Get pointer to %1e58 SwitchToMainMenu() */
uint16_t const *insns = *(uint16_t const **)(addr + 0x1e58 * 4);
if(addr < 0x80020070 || addr >= 0x81000000)
return NULL;
/* Check up to 150 instructions to find the call to the internal function
SaveAndOpenMainMenu(). This call is in a widget of the shape
mov.l GetkeyToMainFunctionReturnFlag, rX
mov #3, rY
bsr SaveAndOpenMainMenu
mov.b rY, @rX
bra <start of widget>
nop */
for(int i = 0; i < 150; i++) {
/* Match: mov.l @(disp, pc), rX */
if((insns[i] & 0xf000) != 0xd000)
continue;
int rX = (insns[i] >> 8) & 0x0f;
/* Match: mov #3, rY */
if((insns[i+1] & 0xf0ff) != 0xe003)
continue;
int rY = (insns[i+1] >> 8) & 0x0f;
/* Match: bsr @(disp, pc) */
if((insns[i+2] & 0xf000) != 0xb000)
continue;
int disp = (insns[i+2] & 0x0fff);
/* Match: mov.b rX, @rY */
if((insns[i+3] != 0x2000 + (rX << 8) + (rY << 4)))
continue;
/* Match: bra @(_, pc) */
if((insns[i+4] & 0xf000) != 0xa000)
continue;
/* Match: nop */
if(insns[i+5] != 0x0009)
continue;
/* Return the target of the bsr instruction */
uint32_t fun_addr = (uint32_t)&insns[i+2] + 4 + disp * 2;
return (os_menu_function_t *)fun_addr;
}
return NULL;
}
#endif
void gint_osmenu_native(void)
{
__ClearKeyBuffer();
gint_copy_vram();
#if GINT_OS_CG
#ifdef FX9860G
memcpy(__GetVRAMAddress(), gint_vram, 1024);
#endif
#ifdef FXCG50
/* Unfortunately ineffective (main menu probably reenables it)
__ConfigureStatusArea(3); */
/* Try to use the internal function directly if we could figure out its
address by dynamically disassembling */
os_menu_function_t *fun = find_os_menu_function();
if(fun) {
fun();
/* TODO: Improve copied VRAM behavior in gint_osmenu() on fxcg50 */
uint16_t *vram1, *vram2;
dgetvram(&vram1, &vram2);
/* Run an immediate keyboard update, and clear the events so that the
key pressed in order to re-enter the add-in is not also processed in
the application */
extern int keysc_tick(void);
keysc_tick();
clearevents();
uint16_t *dst = __GetVRAMAddress();
uint16_t *src = (gint_vram == vram1) ? vram2 + 6 : vram1 + 6;
return;
for(int y = 0; y < 216; y++, dst+=384, src+=396)
for(int x = 0; x < 384; x++)
{
dst[x] = src[x];
}
#endif

View File

@ -11,7 +11,6 @@
#include <gint/exc.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#include "kernel.h"
@ -25,9 +24,12 @@ extern uint32_t
ldata, sdata, rdata, /* User's data section */
lilram, silram, rilram, /* IL memory section */
lxyram, sxyram, rxyram, /* X and Y memory section */
sbss, rbss, /* User's BSS section */
sbss, rbss; /* User's BSS section */
#ifdef FX9860G
extern uint32_t
lgmapped, sgmapped, /* Permanently mapped functions */
lreloc, sreloc; /* Relocatable references */
#endif
/* Constructor and destructor arrays */
extern void (*bctors)(void), (*ectors)(void);
@ -37,19 +39,19 @@ extern void (*bdtors)(void), (*edtors)(void);
int main(int isappli, int optnum);
/* Whether to restart main through the OS menu rather than returning */
int8_t gint_restart = 0;
int gint_restart = 0;
/* gint_setrestart(): Set whether to restart the add-in after exiting */
void gint_setrestart(int restart)
{
gint_restart = !!restart;
gint_restart = restart;
}
/* Return value of main() */
static int8_t gint_exitcode;
/* Jumping there will properly unwind and leave the add-in (CASIOWIN does not
have an exit syscall and simply wants you to return from main()) */
jmp_buf gint_exitbuf;
/* Return value of main() */
static int gint_exitcode;
/* regcpy(): Copy a memory region using symbol information
@l Source pointer (load address)
@ -92,21 +94,6 @@ static void callarray(void (**f)(void), void (**l)(void))
while(f < l) (*(*f++))();
}
void gint_load_onchip_sections(void)
{
/* Do not load data to ILRAM, XRAM or YRAM on SH3 - the areas don't
exist. If you use them, you're responsible! */
if(!isSH3())
{
/* Clear the areas so that we have less to save in case of a
return to menu leading to a poweroff. */
memset((void *)0xe5200000, 0, 4096);
regcpy(&lilram, &silram, &rilram);
memset((void *)0xe500e000, 0, 16384);
regcpy(&lxyram, &sxyram, &rxyram);
}
}
static int start2(int isappli, int optnum)
{
/* We are currently in a dynamic userspace mapping of an add-in run
@ -133,7 +120,7 @@ static int start2(int isappli, int optnum)
1.00 and the fx-9860G emulator) is not clear yet, so gint can't load
pages dynamically. Load everything preventively (works only if the
add-in is small enough) */
#if GINT_OS_FX
#ifdef FX9860G
if(isSH3())
{
/* Try to map every ROM address up to _srom */
@ -154,10 +141,17 @@ static int start2(int isappli, int optnum)
regcpy(&ldata, &sdata, &rdata);
regclr(&rbss, &sbss);
gint_load_onchip_sections();
/* Do not load data to ILRAM, XRAM or YRAM on SH3 - the areas don't
exist. If you use them, you're responsible! */
if(!isSH3())
{
regcpy(&lilram, &silram, &rilram);
regcpy(&lxyram, &sxyram, &rxyram);
}
/* Copy permanently-mapped code to start of user RAM (this section is
only used on fx-9860G; on fx-CG 50 it's fixed in ILRAM) */
#ifdef FX9860G
/* Copy permanently-mapped code to start of user RAM (on fx-CG 50 it
is loaded along ILRAM contents) */
void *rgmapped = mmu_uram();
regcpy(&lgmapped, &sgmapped, rgmapped);
@ -167,6 +161,7 @@ static int start2(int isappli, int optnum)
{
fixups[i] += (uint32_t)rgmapped;
}
#endif
/* Install gint, switch VBR and initialize drivers */
kinit();

View File

@ -9,8 +9,6 @@
** * File system, because it's a mess and we might ruin the ROM.
*/
#include <gint/config.h>
.text
/* Dynamic allocation */
@ -47,7 +45,6 @@
.global ___SetQuitHandler
/* Reset */
.global ___PowerOff
.global ___Reset
#define syscall_(id, syscall_table) \
@ -60,7 +57,7 @@
#define syscall(id) syscall_(id, syscall_table)
#if GINT_OS_FX
#ifdef FX9860G
/* Dynamic allocation */
@ -123,17 +120,15 @@ ___SetQuitHandler:
/* Reset */
___PowerOff:
syscall(0x3f4)
___Reset:
syscall(0x236)
syscall_table:
.long 0x80010070
#endif /* GINT_OS_FX */
#endif /* FX9860G */
#if GINT_OS_CG
#ifdef FXCG50
/* Dynamic allocation */
@ -203,12 +198,10 @@ ___SpecialMatrixCodeProcessing:
/* Reset */
___PowerOff:
syscall(0x1839)
___Reset:
syscall(0x1187)
syscall_table:
.long 0x80020070
#endif /* GINT_OS_CG */
#endif /* FXCG50 */

View File

@ -1,19 +1,7 @@
#include <gint/config.h>
.global _gint_tlbh
.section .gint.tlbh, "ax"
.align 4
#if GINT_OS_FX
# define SYSCALL_TABLE 0x80010070
# define SYSCALL_TLBH 3
#elif GINT_OS_CG
# define SYSCALL_TABLE 0x80020070
# define SYSCALL_TLBH 12
#else
# error Unknown HW for tlbh.S!
#endif
_gint_tlbh:
sts.l pr, @-r15
stc.l gbr, @-r15
@ -40,9 +28,16 @@ test_tea:
map:
/* If TEA is mappable, map a page and return */
#ifdef FX9860G
mov #3, r0
#endif
#ifdef FXCG50
mov #12, r0
#endif
mov.l .syscall, r2
jsr @r2
mov #SYSCALL_TLBH, r0
nop
lds.l @r15+, macl
lds.l @r15+, mach
@ -78,5 +73,12 @@ panic:
.long 0x00300000
.max_mapped_rom:
.long 0x00300000 + _srom
#ifdef FX9860G
.syscall:
.long SYSCALL_TABLE
.long 0x80010070
#endif
#ifdef FXCG50
.syscall:
.long 0x80020070
#endif

View File

@ -3,12 +3,8 @@
#include <gint/gint.h>
#include <gint/exc.h>
#include <gint/defs/call.h>
#include <gint/hardware.h>
#include <gint/display.h>
#include "kernel.h"
#include <stdlib.h>
#include <string.h>
//---
// World buffer
@ -60,9 +56,6 @@ void gint_world_sync(void)
// World switch with driver state saves
//---
static int onchip_save_mode = GINT_ONCHIP_REINITIALIZE;
static void *onchip_save_buffer = NULL;
void gint_world_switch_in(gint_world_t world_os, gint_world_t world_addin)
{
/* Unbind from the OS driver and complete foreign asynchronous tasks */
@ -151,41 +144,13 @@ int gint_world_switch(gint_call_t call)
extern void *gint_stack_top;
gint_world_switch_out(gint_world_addin, gint_world_os);
void *ILRAM = (void *)0xe5200000;
void *XRAM = (void *)0xe500e000;
void *YRAM = (void *)0xe5010000;
/* Watch out for stack overflows */
uint32_t *canary = gint_stack_top;
if(canary)
*canary = 0xb7c0ffee;
/* Save on-chip memory if requested */
if(!isSH3() && onchip_save_mode == GINT_ONCHIP_BACKUP) {
void *ptr = onchip_save_buffer;
memcpy(ptr, ILRAM, 4096);
ptr += 4096;
memcpy(ptr, XRAM, 8192);
ptr += 8192;
memcpy(ptr, YRAM, 8192);
ptr += 8192;
}
int rc = gint_call(call);
/* Restore or reinitialize on-chip memory */
if(!isSH3() && onchip_save_mode == GINT_ONCHIP_BACKUP) {
void *ptr = onchip_save_buffer;
memcpy(ILRAM, ptr, 4096);
ptr += 4096;
memcpy(XRAM, ptr, 8192);
ptr += 8192;
memcpy(YRAM, ptr, 8192);
ptr += 8192;
}
else if(!isSH3() && onchip_save_mode == GINT_ONCHIP_REINITIALIZE)
gint_load_onchip_sections();
/* The canary check needs to occur before switching in the gint world;
otherwise we just crash due to the overflow. gint_panic() isn't
really designed to work from the OS world, but it does fine on the
@ -202,51 +167,3 @@ void gint_switch(void (*function)(void))
{
gint_world_switch(GINT_CALL(function));
}
void gint_set_onchip_save_mode(int mode, void *ptr)
{
onchip_save_mode = mode;
onchip_save_buffer = ptr;
}
int gint_get_onchip_save_mode(void **ptr)
{
if(ptr)
*ptr = onchip_save_buffer;
return onchip_save_mode;
}
void gint_copy_vram(void)
{
void *__GetVRAMAddress(void);
#if GINT_OS_FX
memcpy(__GetVRAMAddress(), gint_vram, 1024);
#endif
#if GINT_OS_CG && GINT_RENDER_RGB
/* TODO: Improve copied VRAM behavior in gint_osmenu() on fxcg50 */
uint16_t *vram1, *vram2;
dgetvram(&vram1, &vram2);
uint16_t *dst = __GetVRAMAddress();
uint16_t *src = (gint_vram == vram1) ? vram2 + 6 : vram1 + 6;
for(int y = 0; y < 216; y++, dst+=384, src+=396)
for(int x = 0; x < 384; x++)
{
dst[x] = src[x];
}
#endif
#if GINT_OS_CG && GINT_RENDER_MONO
// TODO: VRAM save mechanism for mono video mode on R61524
#endif
}
void gint_poweroff(bool show_logo)
{
void __PowerOff(int show_logo);
gint_copy_vram();
gint_world_switch(GINT_CALL(__PowerOff, (int)show_logo));
}

View File

@ -4,11 +4,10 @@
#include <gint/keyboard.h>
#include <gint/drivers/keydev.h>
#include <gint/display.h>
#include <gint/gint.h>
#include <gint/defs/types.h>
#if GINT_HW_FX
#ifdef FX9860G
#include <gint/drivers/t6k11.h>
#endif
@ -49,7 +48,7 @@ key_event_t getkey_opt(int opt, volatile int *timeout)
continue;
}
#if GINT_HW_FX
#ifdef FX9860G
/* Backlight toggle */
if((opt & GETKEY_BACKLIGHT) && e.type == KEYEV_DOWN &&
((e.key == KEY_LIGHT) ||
@ -65,25 +64,10 @@ key_event_t getkey_opt(int opt, volatile int *timeout)
e.key == KEY_MENU && !e.shift && !e.alpha)
{
gint_osmenu();
if(opt & GETKEY_MENU_DUPDATE)
dupdate();
if(!(opt & GETKEY_MENU_EVENT))
continue;
e.type = KEYEV_OSMENU;
}
/* Poweroff */
if((opt & GETKEY_POWEROFF) && e.type == KEYEV_DOWN &&
e.key == KEY_ACON && e.shift && !e.alpha)
{
gint_poweroff(true);
if(opt & GETKEY_MENU_DUPDATE)
dupdate();
continue;
}
if(e.type != KEYEV_NONE || e.type != KEYEV_UP)
if(e.type == KEYEV_DOWN || e.type == KEYEV_HOLD)
{
/* Custom global features */
bool accepted = false;

View File

@ -5,10 +5,9 @@
#include <gint/defs/types.h>
#include <gint/mpu/pfc.h>
#include <gint/hardware.h>
#include <gint/config.h>
/* This file is SH7705-only. */
#if GINT_HW_FX
#ifdef FX9860G
#define PFC SH7705_PFC
/* iokbd_delay() - wait a bit so that I/O can keep up
@ -163,4 +162,4 @@ void iokbd_scan(uint8_t *scan)
}
}
#endif /* GINT_HW_FX */
#endif /* FX9860G */

View File

@ -142,22 +142,6 @@ void keydev_tick(keydev_t *d, uint us)
d->time++;
/* Disable repeat if the repeating key was released */
if(d->rep_key != 0)
{
int row = (d->rep_key >> 4);
int col = 0x80 >> (d->rep_key & 0x7);
if(!(d->state_now[row] & col))
{
d->rep_key = 0;
d->rep_count = -1;
d->rep_time = -1;
d->rep_delay = -1;
d->delayed_shift = 0;
d->delayed_alpha = 0;
}
}
if(d->rep_key != 0)
{
if(d->rep_delay >= 0)
@ -195,7 +179,6 @@ key_event_t keydev_unqueue_event(keydev_t *d)
if(ev.type == KEYEV_DOWN)
{
d->state_queue[row] |= col;
d->state_flips[row] ^= col;
/* Mark this key as the currently repeating one */
if(d->rep_key == 0 && can_repeat(d, ev.key))
{
@ -208,7 +191,16 @@ key_event_t keydev_unqueue_event(keydev_t *d)
else if(ev.type == KEYEV_UP)
{
d->state_queue[row] &= ~col;
d->state_flips[row] ^= col;
/* End the current repeating streak */
if(d->rep_key == ev.key)
{
d->rep_key = 0;
d->rep_count = -1;
d->rep_time = -1;
d->rep_delay = -1;
d->delayed_shift = 0;
d->delayed_alpha = 0;
}
}
return ev;
@ -227,27 +219,6 @@ bool keydev_keydown(keydev_t *d, int key)
__attribute__((alias("keydev_keydown")))
bool _WEAK_keydev_keydown(keydev_t *d, int key);
bool keydev_keypressed(keydev_t *d, int key)
{
int row = (key >> 4);
int col = 0x80 >> (key & 0x7);
return (d->state_queue[row] & col) && (d->state_flips[row] & col);
}
bool keydev_keyreleased(keydev_t *d, int key)
{
int row = (key >> 4);
int col = 0x80 >> (key & 0x7);
return !(d->state_queue[row] & col) && (d->state_flips[row] & col);
}
void keydev_clear_flips(keydev_t *d)
{
memset(d->state_flips, 0, sizeof d->state_flips);
}
//---
// Event transforms
//---

View File

@ -17,18 +17,18 @@
#include <string.h>
#include <stdlib.h>
/* Keyboard input device for this Key Scan Interface */
static keydev_t keysc_dev;
/* Keyboard scanner timer */
int16_t keysc_tid = -1;
/* Keyboard scan frequency in Hertz. Start with 128 Hz, this frequency *must
be high* for the keyboard to work! Reading at low frequencies produces a lot
of artifacts. See https://www.casiopeia.net/forum/viewtopic.php?p=20592. */
int16_t keysc_scan_Hz = 128;
int keysc_scan_Hz = 128;
/* Approximation in microseconds, used by the timer and repeat delays */
uint32_t keysc_scan_us = 7812; /* 1000000 / keysc_scan_Hz */
/* Keyboard scanner timer */
int keysc_tid = -1;
/* Keyboard input device for this Key Scan Interface */
static keydev_t keysc_dev;
/* keydev_std(): Standard keyboard input device */
keydev_t *keydev_std(void)
{
@ -56,7 +56,7 @@ static void keysc_scan(uint8_t *scan)
}
/* keysc_tick(): Update the keyboard to the next state */
int keysc_tick(void)
static int keysc_tick(void)
{
uint8_t scan[12] = { 0 };
keysc_scan(scan);
@ -102,26 +102,12 @@ void clearevents(void)
while(pollevent().type != KEYEV_NONE);
}
void cleareventflips(void)
{
keydev_clear_flips(&keysc_dev);
}
/* keydown(): Current key state */
int keydown(int key)
{
return keydev_keydown(&keysc_dev, key);
}
int keypressed(int key)
{
return keydev_keypressed(&keysc_dev, key);
}
int keyreleased(int key)
{
return keydev_keyreleased(&keysc_dev, key);
}
//---
// Driver initialization
//---

View File

@ -5,7 +5,6 @@
#include <gint/kmalloc.h>
#include <gint/defs/attributes.h>
#include <gint/defs/util.h>
#include <gint/config.h>
#include <string.h>
@ -44,17 +43,17 @@
link, then one block_t pointer to the next link with LSB=1
* For a larger block, the footer has a 4-byte block size, then a pointer to
the previous link, and a pointer to the next link with LSB=0. */
typedef volatile struct {
uint32_t :5;
typedef struct {
uint :5;
/* Marks the last block of the sequence */
uint32_t last: 1;
uint last: 1;
/* Whether the block is used; in general this can be kept implicit, but
it has to be specified for the last block */
uint32_t used: 1;
uint used: 1;
/* Boundary tag, vital to implement way #2 to merge adjacent blocks */
uint32_t previous_used: 1;
uint previous_used: 1;
/* Block size in bytes. */
uint32_t size: 24;
uint size: 24;
} block_t;
typedef kmalloc_gint_stats_t stats_t;
@ -436,10 +435,7 @@ void kmalloc_init_arena(kmalloc_arena_t *a, bool enable_statistics)
index->stats = (void *)a->start + sizeof(index_t);
entry_block = (void *)index->stats + sizeof(stats_t);
/* Manual 4-byte memset to allow PRAM0 arena */
for(uint i = 0; i < sizeof(stats_t) / 4; i++)
((uint32_t *)index->stats)[i] = 0;
_Static_assert((sizeof(stats_t) & 3) == 0);
memset(index->stats, 0, sizeof(stats_t));
}
else
{

View File

@ -184,12 +184,3 @@ bool kmalloc_add_arena(kmalloc_arena_t *arena)
}
return false;
}
void kmalloc_remove_arena(kmalloc_arena_t *arena)
{
for(int i = 0; i < KMALLOC_ARENA_MAX; i++)
{
if(arenas[i] == arena)
arenas[i] = NULL;
}
}

View File

@ -57,7 +57,7 @@ bool mmu_is_rom(void const *ptr)
// SH7705 TLB
//---
#if GINT_HW_FX
#ifdef FX9860G
/* tlb_addr() - get the P4 address of a TLB address entry */
GINLINE const tlb_addr_t *tlb_addr(uint way, uint E)

View File

@ -9,115 +9,123 @@
#include <gint/drivers/states.h>
#include <gint/dma.h>
#include <gint/drivers/r61524.h>
#include <gint/video.h>
#include <gint/image.h>
#include <gint/config.h>
#if GINT_HW_CG
#define DMA SH7305_DMA
#define POWER SH7305_POWER
/* Registers */
#define REG_DEVICE_CODE_READ 0x000
#define REG_DRIVER_OUTPUT_CTL 0x001
#define REG_ENTRY_MODE 0x003
#define REG_DISPLAY_CTL2 0x008
#define REG_LOW_POWER_CTL 0x00b
#define REG_HADDR 0x200
#define REG_VADDR 0x201
#define REG_DATA 0x202
#define REG_HSTART 0x210
#define REG_HEND 0x211
#define REG_VSTART 0x212
#define REG_VEND 0x213
//---
// Device specification sheet
//---
/* Registers and operations */
enum {
device_code_read = 0x000,
driver_output_control = 0x001,
entry_mode = 0x003,
display_control_2 = 0x008,
low_power_control = 0x00b,
ram_address_horizontal = 0x200,
ram_address_vertical = 0x201,
write_data = 0x202,
horizontal_ram_start = 0x210,
horizontal_ram_end = 0x211,
vertical_ram_start = 0x212,
vertical_ram_end = 0x213,
};
typedef word_union(entry_mode_t,
uint TRI :1;
uint DFM :1;
uint :1;
uint BGR :1;
uint :2;
uint HWM :1;
uint :1;
uint ORG :1;
uint :1;
uint ID :2;
uint AM :1;
uint :1;
uint EPF :2;
);
//---
// Device communication primitives
//---
/* Interface with the controller */
static volatile uint16_t *DISPLAY = (void *)0xb4000000;
static volatile uint16_t *intf = (void *)0xb4000000;
/* Bit 4 of Port R controls the RS bit of the display driver */
static volatile uint8_t *PRDR = (void *)0xa405013c;
/* Select a register */
GINLINE static void select(uint16_t reg)
{
/* Clear RS and write the register number */
*PRDR &= ~0x10;
synco();
*DISPLAY = reg;
*intf = reg;
synco();
/* Set RS=1 to allow consecutive reads/writes after a select() */
/* Set RS back. We don't do this in read()/write() because the display
driver is optimized for consecutive GRAM access. LCD-transfers will
be faster when executing select() followed by several calls to
write(). (Although most applications should use the DMA instead.) */
*PRDR |= 0x10;
synco();
}
GINLINE static uint16_t read(void)
{
return *intf;
}
GINLINE static void write(uint16_t data)
{
*DISPLAY = data;
*intf = data;
}
GINLINE uint16_t r61524_get(int ID)
uint16_t r61524_get(int ID)
{
select(ID);
return *DISPLAY;
return read();
}
GINLINE void r61524_set(int ID, uint16_t value)
void r61524_set(int ID, uint16_t value)
{
select(ID);
*DISPLAY = value;
write(value);
}
//---
// Window management
// Window management
//---
void r61524_win_get(uint16_t *HSA, uint16_t *HEA, uint16_t *VSA, uint16_t *VEA)
{
*HSA = r61524_get(REG_HSTART);
*HEA = r61524_get(REG_HEND);
*VSA = r61524_get(REG_VSTART);
*VEA = r61524_get(REG_VEND);
select(horizontal_ram_start);
*HSA = read();
select(horizontal_ram_end);
*HEA = read();
select(vertical_ram_start);
*VSA = read();
select(vertical_ram_end);
*VEA = read();
}
void r61524_win_set(uint16_t HSA, uint16_t HEA, uint16_t VSA, uint16_t VEA)
{
r61524_set(REG_HSTART, HSA);
r61524_set(REG_HEND, HEA);
r61524_set(REG_VSTART, VSA);
r61524_set(REG_VEND, VEA);
}
select(horizontal_ram_start);
write(HSA);
select(horizontal_ram_end);
write(HEA);
//---
// Backlight management
//---
void r61525_brightness_set(int level)
{
bool GLOBAL_backlight_high_bit[7] = { /* at 0x80399530 */
false, false, false, false,
true, true, true,
};
uint8_t GLOBAL_backlight_table[7] = { /* at 0x80399537 */
0x14, 0x4b, 0x78, 0xd2,
0x6e, 0xa0, 0xc8,
};
uint8_t GLOBAL_0[10] = { /* at 0x8039953e */
0x00, 0x01, 0x02, 0x03, 0x07,
0x0f, 0x1f, 0x3f, 0x7f, 0xff,
};
if(level < 1)
level = 1;
if(level > 5)
level = 5;
int8_t volatile *PNDR = (void *)0xa4050138;
if(GLOBAL_backlight_high_bit[level])
*PNDR |= 0x10;
else
*PNDR &= 0xef;
synco();
r61524_set(0x5a2, GLOBAL_0[(level < 2) ? 9 : 5]);
r61524_set(0x5a1, GLOBAL_backlight_table[level]);
select(vertical_ram_start);
write(VSA);
select(vertical_ram_end);
write(VEA);
}
//---
@ -130,11 +138,13 @@ void r61524_start_frame(int xmin, int xmax, int ymin, int ymax)
{
/* Move the window to the desired region, then select address 0 */
r61524_win_set(395-xmax, 395-xmin, ymin, ymax);
r61524_set(REG_HADDR, 0);
r61524_set(REG_VADDR, 0);
select(ram_address_horizontal);
write(0);
select(ram_address_vertical);
write(0);
/* Bind address 0xb4000000 to the data write command */
select(REG_DATA);
select(write_data);
}
void r61524_display(uint16_t *vram, int start, int height, int method)
@ -186,127 +196,6 @@ void r61524_display_rect(uint16_t *vram, int xmin, int xmax, int ymin,
}
}
void r61524_display_mono_128x64(uint32_t *vram)
{
dma_transfer_wait(0);
r61524_start_frame(0, 395, 0, 223);
int border = 0xe71c; /* C_RGB(28, 28, 28) */
for(int i = 0; i < 16 * 396; i++)
write(border);
for(int y = 0; y < 64; y++) {
/* sub-y position */
for(int sy = 0; sy < 3; sy++) {
for(int i = 0; i < 6; i++)
write(border);
/* longword-x position */
for(int lwx = 0; lwx < 4; lwx++) {
int32_t i = vram[lwx];
/* sub-x position */
for(int sx = 0; sx < 32; sx++) {
int color = ~(i >> 31);
i <<= 1;
write(color);
write(color);
write(color);
}
}
for(int i = 0; i < 6; i++)
write(border);
}
vram += 4;
}
for(int i = 0; i < 16 * 396; i++)
write(border);
}
void r61524_display_gray_128x64(uint32_t *light, uint32_t *dark)
{
dma_transfer_wait(0);
r61524_start_frame(0, 395, 0, 223);
int border = 0xe71c; /* C_RGB(28, 28, 28) */
int colors[] = { 0x0000, 0x528a, 0xad55, 0xffff };
for(int i = 0; i < 16 * 396; i++)
write(border);
for(int y = 0; y < 64; y++) {
/* sub-y position */
for(int sy = 0; sy < 3; sy++) {
for(int i = 0; i < 6; i++)
write(border);
/* longword-x position */
for(int lwx = 0; lwx < 4; lwx++) {
int32_t il = light[lwx];
int32_t id = dark[lwx];
/* sub-x position */
for(int sx = 0; sx < 32; sx++) {
int color = colors[(id >= 0) * 2 + (il >= 0)];
il <<= 1;
id <<= 1;
write(color);
write(color);
write(color);
}
}
for(int i = 0; i < 6; i++)
write(border);
}
light += 4;
dark += 4;
}
for(int i = 0; i < 16 * 396; i++)
write(border);
}
static bool r61524_update(int x, int y, image_t const *fb, int flags)
{
// TODO: r61524_update: Handle the mono cases
if(fb->format != IMAGE_RGB565)
return false;
uint w = fb->width;
uint h = fb->height;
dma_transfer_wait(0);
r61524_start_frame(x, x+w-1, y, y+h-1);
/* DMA if enabled */
bool dma_possible = (!x && w == 396 && fb->stride == 396*2 && !(h%4));
if((flags & VIDEO_UPDATE_ENABLE_DMA) && dma_possible) {
void *src = fb->data;
void *dst = (void *)DISPLAY;
int blocks = 99 * (h / 4);
if(flags & VIDEO_UPDATE_ATOMIC)
dma_transfer_atomic(0, DMA_32B, blocks, src, DMA_INC,
dst, DMA_FIXED);
else
dma_transfer_async(0, DMA_32B, blocks, src, DMA_INC,
dst, DMA_FIXED, GINT_CALL_NULL);
return true;
}
uint16_t *pixels = fb->data;
for(int y = 0; y < fb->height; y++) {
for(int x = 0; x < fb->width; x++)
write(pixels[x]);
pixels = (void *)pixels + fb->stride;
}
return true;
}
//---
// State and driver metadata
//---
@ -328,34 +217,3 @@ gint_driver_t drv_r61524 = {
.state_size = sizeof(r61524_state_t),
};
GINT_DECLARE_DRIVER(26, drv_r61524);
//---
// Video driver interface
//---
static video_mode_t r61524_modes[] = {
/* Standard full-screen full-color mode */
{ 396, 224, IMAGE_RGB565, -1 },
#if 0
/* R61524 8-color mode with lower power consumption */
{ 396, 224, IMAGE_P8_RGB565, -1 }, // TODO: actually P3, that's closest
/* T6K11-emulation black-and-white mode */
{ 128, 64, IMAGE_I1MSB, -1 },
/* T6K11-emulation gray mode */
{ 128, 64, IMAGE_2I1MSB, -1 },
#endif
{ 0 }
};
video_interface_t r61524_video = {
.driver = &drv_r61524,
.modes = r61524_modes,
.mode_get = NULL, // TODO
.mode_set = NULL, // TODO
.brightness_min = 0, // TODO
.brightness_max = 0, // TODO
.brightness_set = NULL,
.update = r61524_update,
};
#endif /* GINT_HW_CG */

View File

@ -1,7 +1,5 @@
#include <gint/display.h>
#include <gint/dma.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void dclear(uint16_t color)
{
@ -18,5 +16,3 @@ void dclear(uint16_t color)
dwindow.bottom - 1, color);
}
}
#endif

View File

@ -1,11 +1,7 @@
#include <gint/display.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
int dgetpixel(int x, int y)
{
if((uint)x >= DWIDTH || (uint)y >= DHEIGHT) return -1;
return gint_vram[DWIDTH * y + x];
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/display.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void dpixel(int x, int y, int color)
{
@ -13,5 +11,3 @@ void dpixel(int x, int y, int color)
if(color == C_INVERT) gint_vram[index] ^= 0xffff;
else gint_vram[index] = color;
}
#endif

View File

@ -1,7 +1,5 @@
#include <gint/defs/util.h>
#include <gint/display.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
void drect(int x1, int y1, int x2, int y2, int color)
{
@ -52,5 +50,3 @@ void drect(int x1, int y1, int x2, int y2, int color)
base += DWIDTH;
}
}
#endif

View File

@ -1,6 +1,4 @@
#include <gint/display.h>
#include <gint/config.h>
#if GINT_RENDER_RGB
/* dsubimage(): Render a section of an image */
void dsubimage(int x, int y, image_t const *img, int left, int top,
@ -13,5 +11,3 @@ void dsubimage(int x, int y, image_t const *img, int left, int top,
else if(IMAGE_IS_P4(img->format))
return dsubimage_p4(x, y, img, left, top, w, h, flags);
}
#endif

View File

@ -1,8 +1,6 @@
#include <gint/display.h>
#include <gint/drivers/r61524.h>
#include "render-cg.h"
#include <gint/config.h>
#if GINT_RENDER_RGB
/* dupdate(): Push the video RAM to the display driver */
void dupdate(void)
@ -21,5 +19,3 @@ void dupdate(void)
}
__attribute__((alias("dupdate")))
void _WEAK_dupdate(void);
#endif

Some files were not shown because too many files have changed in this diff Show More