Compare commits
No commits in common. "dev" and "master" have entirely different histories.
211
CMakeLists.txt
211
CMakeLists.txt
|
@ -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}")
|
||||
|
|
19
README.md
19
README.md
|
@ -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
44
TODO
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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) : {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
//---
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 /
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
//---
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -1,7 +0,0 @@
|
|||
.global _gdb_stubcall_write
|
||||
|
||||
_gdb_stubcall_write:
|
||||
mov #64, r3
|
||||
trapa #33
|
||||
rts
|
||||
nop
|
881
src/gdb/gdb.c
881
src/gdb/gdb.c
|
@ -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 |
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#ifndef GINT_IMAGE_FIXED
|
||||
#define GINT_IMAGE_FIXED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Constants */
|
||||
#define fconst(x) ((x) * 65536)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, ¢er_x, ¢er_y, map);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
//---
|
||||
|
|
|
@ -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
|
||||
//---
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue