mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2025-04-04 09:37:10 +02:00
Compare commits
240 commits
Author | SHA1 | Date | |
---|---|---|---|
|
badbd0fd2b | ||
|
52c17ccb05 | ||
|
88eb5413a6 | ||
|
da05e89b1c | ||
|
f70f1d9ae3 | ||
|
371e593f1d | ||
|
58eb5d92d7 | ||
|
1fc7290b09 | ||
|
84a4dd7ca9 | ||
|
335326692f | ||
|
ea5f21d1dc | ||
|
4a2b60b785 | ||
|
e3105701d9 | ||
|
5b16888d9d | ||
|
5626713f40 | ||
|
789ba7caa5 | ||
|
5c3dc3220a | ||
|
7ac2ae25f2 | ||
|
d065a17063 | ||
|
0afd05848a | ||
|
b4c0fc7cea | ||
|
2755596d59 | ||
|
ab528b27a8 | ||
|
d9414bb6f2 | ||
|
4623d790cc | ||
|
faead4bc1d | ||
|
f8208d093b | ||
|
946d4d9a6f | ||
|
3a42b5d386 | ||
|
ee109e4977 | ||
|
5548bf68ab | ||
|
28bea2e1ce | ||
|
b2b1f00d04 | ||
|
5ff6a518f6 | ||
|
bc74586a2c | ||
|
e0ac25fbb0 | ||
|
b802e8edef | ||
|
d8005b5d49 | ||
|
e50769c824 | ||
|
542b4f0a81 | ||
|
1e220af616 | ||
|
caa68b08bf | ||
|
833025f5dd | ||
|
fd5a70e21b | ||
|
5655699cd8 | ||
|
235fa8a361 | ||
|
18a7b9ae5b | ||
|
2bb5294578 | ||
|
6d86c54507 | ||
|
16259deb20 | ||
|
6f53fa7842 | ||
|
5087a91101 | ||
|
7d3663483f | ||
|
6efcfa6018 | ||
|
0b7d8d6800 | ||
|
9c22ecea8d | ||
|
02a97719ac | ||
|
33dae5d218 | ||
|
21ff5c1d53 | ||
|
76c82beec6 | ||
|
eca05ec64c | ||
|
2f6ee59d43 | ||
|
3aa11b4252 | ||
|
eab3184dbb | ||
|
238bccddbe | ||
|
aa0ff7b10b | ||
|
0bea485f4b | ||
|
dcb876dfe0 | ||
|
82258b9f89 | ||
|
eb49f0258d | ||
|
b5f0f08183 | ||
|
1423f40a96 | ||
|
3a2a194693 | ||
|
4983849510 | ||
|
fc1f510288 | ||
|
c59b2f90fb | ||
|
eb1f9a35a1 | ||
|
f4e13afa84 | ||
|
911691461f | ||
|
aee67a76f3 | ||
|
c0671649df | ||
|
53c67af52d | ||
|
6910714c2c | ||
|
af5c16a3d3 | ||
|
1a61e97ef0 | ||
|
a091efc894 | ||
|
6f758cd36c | ||
|
18e0db3886 | ||
|
cf2b86deaa | ||
|
db50c9b192 | ||
|
42853103aa | ||
|
c28d06002f | ||
|
ac6b1c7d70 | ||
|
45881995e9 | ||
|
70dccc29da | ||
|
7e859169fe | ||
|
b3416dcc25 | ||
|
736b58f205 | ||
|
478fdaea76 | ||
|
d3b29c50e6 | ||
|
1272a6a71a | ||
|
723bae134b | ||
|
3bc3892524 | ||
|
211d236496 | ||
|
a4cf3516e7 | ||
|
177879d432 | ||
|
feb74a38ec | ||
|
3192078c4c | ||
|
a5fb6d3401 | ||
|
e2c507855f | ||
|
813af222fd | ||
|
984f162cb2 | ||
|
6426406043 | ||
|
2fe67412cc | ||
|
f807b528bb | ||
|
ad0da59de6 | ||
|
56e5c2452a | ||
|
8442e0b9cf | ||
|
5461d54083 | ||
|
386303136c | ||
|
8a6f3bfdce | ||
|
d6e8b096b5 | ||
|
4df3d69d8c | ||
|
74438f5da5 | ||
|
45fa6c87c2 | ||
|
5e35871c98 | ||
|
5f9553f3b8 | ||
|
93e055cfba | ||
|
d110ab608e | ||
|
45e90b55ba | ||
|
bbda77769d | ||
|
7b662987f8 | ||
|
252bd4eb41 | ||
|
48db9bf09d | ||
|
1d5675c99f | ||
|
16890ab71b | ||
|
c9df6326e4 | ||
|
97701e8eed | ||
|
a735e074d8 | ||
|
ddf340cccd | ||
|
5c331e5fa0 | ||
|
98fea4f2ec | ||
|
a4adc5e1bd | ||
|
b23ed9629e | ||
|
2b4075c8f9 | ||
|
e95a91d5ab | ||
|
3e5c45c5ad | ||
|
9924dc4684 | ||
|
4f9b141b79 | ||
|
02150d90e5 | ||
|
126d1506ac | ||
|
6ea2f991a3 | ||
|
4e1136d0ac | ||
|
1c3c9727a5 | ||
|
e8b4bcc9cb | ||
|
b17d4de4a8 | ||
|
f69f92b938 | ||
|
8c9c48a91e | ||
|
291c3cef17 | ||
|
b942bc5d19 | ||
|
c2ff07427b | ||
|
09c13676d3 | ||
|
780acb3fc9 | ||
|
818f950fff | ||
|
9468a8d725 | ||
|
fc6f7d3051 | ||
|
5a69e44078 | ||
|
7822899b1f | ||
|
d2f788a3fc | ||
|
667f43b45c | ||
|
ede19fc878 | ||
|
a4df076214 | ||
|
7a3604ccbb | ||
|
f219e5c882 | ||
|
904ab74984 | ||
|
8210524152 | ||
|
26c5b76037 | ||
|
e57efb5e37 | ||
|
0c2935055e | ||
|
fdadb0dd71 | ||
|
b10c065abe | ||
|
a3ce29b7b8 | ||
|
a7bcf6cd77 | ||
|
4223164063 | ||
|
93169e8803 | ||
|
2bf5dd93f4 | ||
|
f300338a57 | ||
|
48325fc54d | ||
|
36d66a6317 | ||
|
d8b85a9fab | ||
|
227c06631b | ||
|
d6ada7f11f | ||
|
8aea762e7a | ||
|
59a3b39fb4 | ||
|
ef8707ee9d | ||
|
3aa1471ac5 | ||
|
9b02f5f1db | ||
|
472f1245c7 | ||
|
b549fd68ba | ||
|
ed30895a49 | ||
|
aed90d9b3c | ||
|
9cae0040b5 | ||
|
34c73ba0ba | ||
|
6903bd58d5 | ||
|
321d6937e0 | ||
|
8635880bbb | ||
|
71de4dcb95 | ||
|
2e5e56f82e | ||
|
86fad757e1 | ||
|
b7173a5109 | ||
|
055c8f405b | ||
|
caf585b0a1 | ||
|
1384c54b5f | ||
|
73446aae61 | ||
|
192ff17303 | ||
|
7adcdea5f1 | ||
|
2d0e18f2d8 | ||
|
97934cc18e | ||
|
d3a2cf07a0 | ||
|
8713d2644f | ||
|
545db2f9ce | ||
|
02c1b551cd | ||
|
89d540ee91 | ||
|
8d444b4f78 | ||
|
03ef59521c | ||
|
5bd04a9613 | ||
|
658413ba19 | ||
|
10180d31bc | ||
|
9939896c6a | ||
|
824a150dfb | ||
|
086ad19d13 | ||
|
57531e63bf | ||
|
73ab18e457 | ||
|
8e730c2f78 | ||
|
20b7238057 | ||
|
edcebff311 | ||
|
fc6fb9dc09 | ||
|
3a6165f026 | ||
|
b25924d740 | ||
|
991b616a10 |
290 changed files with 17123 additions and 5045 deletions
310
CMakeLists.txt
310
CMakeLists.txt
|
@ -1,14 +1,15 @@
|
|||
# Build system for the gint unikernel
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(Gint VERSION 2.5.1 LANGUAGES C ASM)
|
||||
project(Gint VERSION 2.11.0 LANGUAGES C ASM)
|
||||
|
||||
include(GitVersionNumber)
|
||||
include(Fxconv)
|
||||
|
||||
option(GINT_USER_VRAM "Put all VRAMs into the user stack (fx-CG 50 only)")
|
||||
option(GINT_NO_OS_STACK "Do not use the OS stack as a memory pool (fx-CG only)")
|
||||
option(GINT_STATIC_GRAY "Use static memory instead of malloc for gray buffers (fx-9860G only)")
|
||||
option(GINT_KMALLOC_DEBUG "Enable debug functions for kmalloc")
|
||||
option(GINT_USB_DEBUG "Enable debug functions for the USB driver")
|
||||
|
||||
set(CMAKE_INSTALL_MESSAGE LAZY)
|
||||
|
||||
|
@ -16,23 +17,106 @@ set(CMAKE_INSTALL_MESSAGE LAZY)
|
|||
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
git_version_number(SHORT_HASH "GINT_GIT_HASH" TAG_RELATIVE "GINT_GIT_VERSION")
|
||||
else()
|
||||
set(GINT_GIT_HASH "")
|
||||
set(GINT_GIT_HASH "0000000")
|
||||
set(GINT_GIT_VERSION "${PROJECT_VERSION}")
|
||||
endif()
|
||||
configure_file(include/gint/config.h.in include/gint/config.h)
|
||||
|
||||
set(SOURCES_COMMON
|
||||
set(SOURCES
|
||||
# Clock Pulse Generator driver
|
||||
src/cpg/cpg.c
|
||||
src/cpg/overclock.c
|
||||
# CPU driver
|
||||
src/cpu/atomic.c
|
||||
src/cpu/cpu.c
|
||||
src/cpu/ics.s
|
||||
src/cpu/registers.s
|
||||
src/cpu/sleep.c
|
||||
# Direct Memory Access driver
|
||||
src/dma/dma.c
|
||||
src/dma/inth.s
|
||||
src/dma/memcpy.c
|
||||
src/dma/memset.c
|
||||
# Filesystem interface
|
||||
src/fs/close.c
|
||||
src/fs/closedir.c
|
||||
src/fs/creat.c
|
||||
src/fs/fdopendir.c
|
||||
src/fs/fs.c
|
||||
src/fs/lseek.c
|
||||
src/fs/mkdir.c
|
||||
src/fs/open.c
|
||||
src/fs/opendir.c
|
||||
src/fs/pread.c
|
||||
src/fs/pwrite.c
|
||||
src/fs/read.c
|
||||
src/fs/readdir.c
|
||||
src/fs/rename.c
|
||||
src/fs/rewinddir.c
|
||||
src/fs/rmdir.c
|
||||
src/fs/seekdir.c
|
||||
src/fs/stat.c
|
||||
src/fs/telldir.c
|
||||
src/fs/unlink.c
|
||||
src/fs/write.c
|
||||
# Filesystem interface to Fugue
|
||||
src/fs/fugue/BFile_Ext_Stat.c
|
||||
src/fs/fugue/fugue.c
|
||||
src/fs/fugue/fugue_dir.c
|
||||
src/fs/fugue/fugue_open.c
|
||||
src/fs/fugue/fugue_mkdir.c
|
||||
src/fs/fugue/fugue_stat.c
|
||||
src/fs/fugue/fugue_rename.c
|
||||
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
|
||||
# Kernel
|
||||
src/kernel/exch.c
|
||||
src/kernel/exch.s
|
||||
src/kernel/hardware.c
|
||||
|
@ -40,129 +124,209 @@ set(SOURCES_COMMON
|
|||
src/kernel/kernel.c
|
||||
src/kernel/osmenu.c
|
||||
src/kernel/start.c
|
||||
src/kernel/start.S
|
||||
src/kernel/syscalls.S
|
||||
src/kernel/tlbh.S
|
||||
src/kernel/world.c
|
||||
# Key Scan Interface driver
|
||||
src/keysc/getkey.c
|
||||
src/keysc/iokbd.c
|
||||
src/keysc/keycodes.c
|
||||
src/keysc/keydev.c
|
||||
src/keysc/keydev_idle.c
|
||||
src/keysc/keydev_process_key.c
|
||||
src/keysc/keydown_all.c
|
||||
src/keysc/keydown_any.c
|
||||
src/keysc/keysc.c
|
||||
src/keysc/scan_frequency.c
|
||||
# Memory allocator
|
||||
src/kmalloc/arena_gint.c
|
||||
src/kmalloc/arena_osheap.c
|
||||
src/kmalloc/kmalloc.c
|
||||
src/kprint/kprint.c
|
||||
src/kprint/kformat_fp.c
|
||||
# MMU driver
|
||||
src/mmu/mmu.c
|
||||
# R61523 display driver
|
||||
src/r61523/r61523.c
|
||||
# R61524 display driver
|
||||
src/r61524/r61524.c
|
||||
# Format-agnostic rendering
|
||||
src/render/dcircle.c
|
||||
src/render/dellipse.c
|
||||
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
|
||||
src/render/dupdate_hook.c
|
||||
src/render/dvline.c
|
||||
src/render/dwindow.c
|
||||
src/render/topti.c
|
||||
src/rtc/rtc.c
|
||||
src/rtc/rtc_ticks.c
|
||||
src/spu/spu.c
|
||||
src/std/aprint.c
|
||||
src/std/malloc.c
|
||||
src/std/print.c
|
||||
src/tmu/inth-etmu.s
|
||||
src/tmu/inth-tmu.s
|
||||
src/tmu/sleep.c
|
||||
src/tmu/tmu.c
|
||||
src/usb/classes/ff-bulk.c
|
||||
src/usb/configure.c
|
||||
src/usb/pipes.c
|
||||
src/usb/setup.c
|
||||
src/usb/string.c
|
||||
src/usb/usb.c
|
||||
src/3rdparty/tinymt32/rand.c
|
||||
src/3rdparty/tinymt32/tinymt32.c
|
||||
src/3rdparty/grisu2b_59_56/grisu2b_59_56.c
|
||||
)
|
||||
set(SOURCES_FX
|
||||
src/gray/engine.c
|
||||
src/gray/gclear.c
|
||||
src/gray/gint_gline.c
|
||||
src/gray/gpixel.c
|
||||
src/gray/grect.c
|
||||
src/gray/gsubimage.c
|
||||
src/gray/gtext.c
|
||||
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
|
||||
# RGB Rendering
|
||||
src/render-cg/dclear.c
|
||||
src/render-cg/dgetpixel.c
|
||||
src/render-cg/dpixel.c
|
||||
src/render-cg/drect.c
|
||||
src/render-cg/dsubimage.c
|
||||
src/render-cg/dupdate.c
|
||||
src/render-cg/dvram.c
|
||||
src/render-cg/dvram.S
|
||||
src/render-cg/gint_dline.c
|
||||
src/render-cg/topti-asm.S
|
||||
src/render-cg/topti.c
|
||||
# Fast RGB image renderer
|
||||
src/render-cg/image/image.c
|
||||
src/render-cg/image/image_rgb16.S
|
||||
src/render-cg/image/image_rgb16_normal.S
|
||||
src/render-cg/image/image_rgb16_clearbg_dye.S
|
||||
src/render-cg/image/image_rgb16_swapcolor.S
|
||||
src/render-cg/image/image_p8.S
|
||||
src/render-cg/image/image_p8_normal.S
|
||||
src/render-cg/image/image_p8_clearbg.S
|
||||
src/render-cg/image/image_p8_swapcolor.S
|
||||
src/render-cg/image/image_p8_dye.S
|
||||
src/render-cg/image/image_p4.S
|
||||
src/render-cg/image/image_p4_normal.S
|
||||
src/render-cg/image/image_p4_clearbg.S
|
||||
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
|
||||
src/render-cg/image/image_rgb16.c
|
||||
src/render-cg/image/image_rgb16_effect.c
|
||||
src/render-cg/image/image_rgb16_swapcolor.c
|
||||
src/render-cg/image/image_rgb16_dye.c
|
||||
src/render-cg/image/image_p8.c
|
||||
src/render-cg/image/image_p8_effect.c
|
||||
src/render-cg/image/image_p8_swapcolor.c
|
||||
src/render-cg/image/image_p8_dye.c
|
||||
src/render-cg/image/image_p4.c
|
||||
src/render-cg/image/image_p4_clearbg_alt.c
|
||||
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-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
|
||||
)
|
||||
set(SOURCES_CG
|
||||
src/r61524/r61524.c
|
||||
src/render-cg/bopti-asm.s
|
||||
src/render-cg/bopti.c
|
||||
src/render-cg/dclear.c
|
||||
src/render-cg/dpixel.c
|
||||
src/render-cg/drect.c
|
||||
src/render-cg/dsubimage.c
|
||||
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.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)
|
||||
set(ASSETS_CG src/font8x9.png)
|
||||
set(ASSETS_FX src/font5x7.png src/gdb/icons-i1msb.png)
|
||||
set(ASSETS_CG src/font8x9.png src/gdb/icons-rgb565.png)
|
||||
set(ASSETS_CP ${ASSETS_CG})
|
||||
fxconv_declare_assets(${ASSETS_FX} ${ASSETS_CG})
|
||||
|
||||
include_directories(
|
||||
"${PROJECT_SOURCE_DIR}/include"
|
||||
"${PROJECT_BINARY_DIR}/include"
|
||||
"${FXSDK_COMPILER_INSTALL}/include/openlibm")
|
||||
add_compile_options(-Wall -Wextra -std=c11 -Os -fstrict-volatile-bitfields -mtas)
|
||||
|
||||
# Silence extended warnings on Grisu2b code
|
||||
set_source_files_properties(src/3rdparty/grisu2b_59_56/grisu2b_59_56.c PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-all;-Wno-extra")
|
||||
"${PROJECT_BINARY_DIR}/include")
|
||||
add_compile_options(-Wall -Wextra -std=c11 -Os -g -fstrict-volatile-bitfields -mtas -flto)
|
||||
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
||||
add_compile_definitions(FX9860G)
|
||||
add_library(gint-fx STATIC ${SOURCES_COMMON} ${SOURCES_FX} ${ASSETS_FX})
|
||||
set(NAME "gint-fx")
|
||||
set(LINKER_SCRIPT "fx9860g.ld")
|
||||
set(LINKER_SCRIPTS
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/fx9860g.ld")
|
||||
add_library(${NAME} STATIC ${SOURCES} ${ASSETS_FX} ${LINKER_SCRIPTS})
|
||||
endif()
|
||||
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
|
||||
add_compile_definitions(FXCG50)
|
||||
add_library(gint-cg STATIC ${SOURCES_COMMON} ${SOURCES_CG} ${ASSETS_CG})
|
||||
set(NAME "gint-cg")
|
||||
set(LINKER_SCRIPT "fxcg50.ld")
|
||||
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})
|
||||
endif()
|
||||
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fxCP)
|
||||
add_compile_definitions(FXCP)
|
||||
set(NAME "gint-cp")
|
||||
set(LINKER_SCRIPTS
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/fxcp_hh2.ld")
|
||||
add_library(${NAME} STATIC ${SOURCES} ${ASSETS_CP} ${LINKER_SCRIPTS})
|
||||
endif()
|
||||
|
||||
set_target_properties("${NAME}" PROPERTIES OUTPUT_NAME "${NAME}")
|
||||
|
||||
# Generate the archive with gcc-ar instead of ar as it will load the LTO plugin
|
||||
# which is required to generate a usable archive.
|
||||
set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_C_COMPILER_AR} qcs <TARGET> <OBJECTS>")
|
||||
# Also the ranlib rule (useless because ar is passed the s flag anyway)
|
||||
set(CMAKE_C_ARCHIVE_FINISH "${CMAKE_C_COMPILER_RANLIB} <TARGET>")
|
||||
|
||||
# Generate linker scripts
|
||||
macro(generate_linker_script OUTPUT INPUT OPTIONS)
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT}"
|
||||
COMMAND ${FXSDK_TOOLCHAIN}cpp "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}"
|
||||
-P -C -traditional-cpp ${OPTIONS} -o "${OUTPUT}"
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}")
|
||||
endmacro()
|
||||
generate_linker_script("fx9860g.ld" "fx9860g.ld.c" "")
|
||||
generate_linker_script("fxcg50.ld" "fxcg50.ld.c" "")
|
||||
generate_linker_script("fxcg50_fastload.ld" "fxcg50.ld.c" "-DFXCG50_FASTLOAD")
|
||||
generate_linker_script("fxcp_hh2.ld" "fxcp_hh2.ld.c" "")
|
||||
|
||||
# Library file
|
||||
install(TARGETS "${NAME}" DESTINATION "${FXSDK_COMPILER_INSTALL}")
|
||||
# Linker script
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/${LINKER_SCRIPT}"
|
||||
DESTINATION "${FXSDK_COMPILER_INSTALL}")
|
||||
install(TARGETS "${NAME}" DESTINATION "${FXSDK_LIB}")
|
||||
# Linker scripts
|
||||
install(FILES ${LINKER_SCRIPTS} DESTINATION "${FXSDK_LIB}")
|
||||
# Headers
|
||||
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
DESTINATION "${FXSDK_COMPILER_INSTALL}"
|
||||
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/"
|
||||
DESTINATION "${FXSDK_INCLUDE}"
|
||||
FILES_MATCHING PATTERN "*.h")
|
||||
# Auto-generated config header
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/gint/config.h"
|
||||
DESTINATION "${FXSDK_COMPILER_INSTALL}/include/gint")
|
||||
DESTINATION "${FXSDK_INCLUDE}/gint")
|
||||
# CMake module to find gint
|
||||
install(FILES cmake/FindGint.cmake DESTINATION "${FXSDK_CMAKE_MODULE_PATH}")
|
||||
|
|
46
README.md
46
README.md
|
@ -12,16 +12,9 @@ new, richer API that takes advantage of the full capabilities of the machine.
|
|||
This is free software: you may use it for any purpose, share it, modify it, and
|
||||
share your changes. Credit is not required, but please let me know!
|
||||
|
||||
gint also includes third-party code that is distributed under its own license.
|
||||
Currently, this includes:
|
||||
|
||||
* A stripped-down version of the [TinyMT random number generator](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html)
|
||||
([GitHub repository](https://github.com/MersenneTwister-Lab/TinyMT)) by
|
||||
Mutsuo Saito and Makoto Matsumoto. See `src/3rdparty/tinymt32/LICENSE.txt`.
|
||||
* A stripped-down version of the [Grisu2b floating-point representation
|
||||
algorithm](https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf)
|
||||
with α=-59 and γ=-56, by Florian Loitsch. See `src/3rdparty/grisu2b_59_56/README`
|
||||
for details, and [the original code here](https://drive.google.com/open?id=0BwvYOx00EwKmejFIMjRORTFLcTA).
|
||||
gint used to include third-party code that has now been moved to the FxLibc. If
|
||||
you stumble upon it in the history, check the README file at that time for
|
||||
license details.
|
||||
|
||||
## Programming interface
|
||||
|
||||
|
@ -39,7 +32,7 @@ The library also offers powerful higher-level features:
|
|||
|
||||
* An enhanced version of the system's GetKey() and GetKeyWait()
|
||||
* A gray engine that works by rapidly swapping monochrome images on fx-9860G II
|
||||
* Blazingly fast rendering functions (image rendering is 10 times faster tha
|
||||
* Blazingly fast rendering functions (image rendering is 10 times faster than
|
||||
MonochromeLib)
|
||||
* Integrated font management
|
||||
|
||||
|
@ -73,12 +66,6 @@ CMake environment for the calculator. gint is always installed in the
|
|||
compiler's install path (as given by `sh-elf-gcc --print-search-dirs`) which is
|
||||
detected automatically, so normally you don't need to set the install prefix.
|
||||
|
||||
fx-CG 50 developers probably want a g3a wrapper as well; the reference
|
||||
implementation is Tari's [mkg3a](https://gitlab.com/taricorp/mkg3a). This is
|
||||
needed at the very last compilation step to create the g3a file. On Arch Linux,
|
||||
you can use the [AUR/mkg3a](https://aur.archlinux.org/packages/mkg3a) package
|
||||
maintained directly by Tari.
|
||||
|
||||
gint depends on OpenLibm and fxlibc (linked above). Both can be installed
|
||||
easily (essentially copy-paste the command from the respective READMEs). You
|
||||
can technically use another libc but there be dragons.
|
||||
|
@ -96,6 +83,7 @@ Run without `-c` to build. This configures automatically.
|
|||
|
||||
```
|
||||
% fxsdk build-fx
|
||||
% fxsdk build-fx install
|
||||
```
|
||||
|
||||
The available options are:
|
||||
|
@ -112,6 +100,22 @@ The available options are:
|
|||
|
||||
* `-DGINT_USER_VRAM=1`: Store all VRAMs in the user stack (takes up 350k/512k)
|
||||
|
||||
```
|
||||
% fxsdk build-cg
|
||||
% 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
|
||||
|
@ -128,10 +132,16 @@ 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`;
|
||||
* Build with `-ffreestanding -fstrict-volatile-bitfields` and either
|
||||
`-DFX9860G` or `-DFXGC50`;
|
||||
* 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
|
||||
|
|
78
TODO
78
TODO
|
@ -1,22 +1,82 @@
|
|||
Bugs to fix:
|
||||
* render: figure out why fx-CG dclear() now takes 4.1 ms instead of 2.6 ms
|
||||
|
||||
Extensions on existing code:
|
||||
* clock: mono support
|
||||
* usb: and interrupt pipes
|
||||
* fs: support RAM files
|
||||
* fs: support USB streams as generic file descriptors
|
||||
* fugue: support glob() to abstract away BFile entirely
|
||||
* fugue/fs: offer a primitive to remove recursively, which is native in Fugue
|
||||
* bfile: implement the optimization-restart as realized by Kbd2
|
||||
* kernel: better restore to userspace before panic (ensure BL=0 IMASK=0)
|
||||
* project: add license file
|
||||
* kernel: group linker script symbols in a single header file
|
||||
* bopti: try to display fullscreen images with TLB access + DMA on fxcg50
|
||||
* core: try to leave add-in without reset in case of panic
|
||||
* core: use cmp/str for memchr()
|
||||
* r61524: brightness control and clean the file
|
||||
* core: review forgotten globals and MPU addresses not in <gint/mpu/*.h>
|
||||
* core: run destructors when a task-switch results in leaving the app
|
||||
* core rtc: use qdiv10 to massively improve division performance
|
||||
* 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?
|
||||
|
||||
Future directions.
|
||||
* A complete file system abstraction
|
||||
* Integrate overclock management
|
||||
Future directions:
|
||||
* Audio playback using TSWilliamson's libsnd method
|
||||
* Serial communication
|
||||
* USB communication, using Yatis' reverse-engineering of the module
|
||||
* Make fx9860g projects work out of the box on fxcg50
|
||||
* Use the DSP to enhance parallel computation
|
||||
* Base for Yatis' threads library
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
fx-CP port progress.
|
||||
DONE:
|
||||
- kernel can start add-ins, take over interrupts (but no interrupt sources yet)
|
||||
- panic handler works (no interactive choices, only RESET)
|
||||
- no OS menu (likely never) and poweroff (maybe later)
|
||||
- memory: 64 kB total + OS heap (no gint arena, no MMU)
|
||||
- r61523: prototype display driver
|
||||
- can use the rendering pipeline with no DMA acceleration
|
||||
IN-PROGRESS:
|
||||
- unification of the image/video interface
|
||||
TODO:
|
||||
- hardware info: rom and fs type
|
||||
- quit handler
|
||||
- DMA acceleration for dclear and dupdate
|
||||
- keyboard and touch screen input
|
||||
- drivers: cpg, dma, intc, rtc, tmu
|
||||
- find more memory, 64 kB is not enough
|
||||
- benchmark memory and display performance
|
||||
- improve API and performance of display driver
|
||||
- way off: filesystem, remote debugging, usb
|
||||
|
|
|
@ -1,12 +1,30 @@
|
|||
macro(get_linker_script_path OUTVAR NAME)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} -print-file-name=${NAME}
|
||||
OUTPUT_VARIABLE ${OUTVAR}
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endmacro()
|
||||
|
||||
# Determine platform Code
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
|
||||
set(PC cg)
|
||||
set(INTF_DEFN FXCG50)
|
||||
set(INTF_LINK "-T;fxcg50.ld")
|
||||
get_linker_script_path(LS1 fxcg50_fastload.ld)
|
||||
get_linker_script_path(LS2 fxcg50.ld)
|
||||
set(INTF_LINKER_SCRIPT
|
||||
"$<IF:$<CONFIG:FastLoad>,${LS1},${LS2}>")
|
||||
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
||||
set(PC fx)
|
||||
set(INTF_DEFN FX9860G)
|
||||
set(INTF_LINK "-T;fx9860g.ld")
|
||||
get_linker_script_path(INTF_LINKER_SCRIPT "fx9860g.ld")
|
||||
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G_G3A)
|
||||
set(PC fxg3a)
|
||||
set(INTF_DEFN FX9860G_G3A)
|
||||
get_linker_script_path(INTF_LINKER_SCRIPT "fxcg50.ld")
|
||||
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCP)
|
||||
set(PC cp)
|
||||
set(INTF_DEFN FXCP)
|
||||
get_linker_script_path(INTF_LINKER_SCRIPT "fxcp_hh2.ld")
|
||||
else()
|
||||
message(FATAL_ERROR "gint: unknown fxSDK platform '${FXSDK_PLATFORM}'")
|
||||
endif()
|
||||
|
@ -14,13 +32,16 @@ endif()
|
|||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} -print-file-name=libgint-${PC}.a
|
||||
OUTPUT_VARIABLE GINT_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} -print-file-name=include/gint/config.h
|
||||
OUTPUT_VARIABLE GINT_CONFIG_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
COMMAND ${CMAKE_C_COMPILER} -print-file-name=libc.a
|
||||
OUTPUT_VARIABLE FXLIBC_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(
|
||||
COMMAND fxsdk path include
|
||||
OUTPUT_VARIABLE FXSDK_INCLUDE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(GINT_CONFIG_PATH "${FXSDK_INCLUDE}/gint/config.h")
|
||||
|
||||
if("${GINT_PATH}" STREQUAL "libgint-${PC}.a")
|
||||
unset(PATH_TO_LIBGINT)
|
||||
|
@ -35,13 +56,25 @@ else()
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if("${FXLIBC_PATH}" STREQUAL "libc.a")
|
||||
unset(PATH_TO_FXLIBC)
|
||||
else()
|
||||
set(PATH_TO_FXLIBC TRUE)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Gint
|
||||
REQUIRED_VARS PATH_TO_LIBGINT
|
||||
VERSION_VAR GINT_VERSION
|
||||
)
|
||||
REQUIRED_VARS PATH_TO_FXLIBC PATH_TO_LIBGINT
|
||||
VERSION_VAR GINT_VERSION)
|
||||
|
||||
if(Gint_FOUND)
|
||||
if(NOT TARGET Gint::Fxlibc)
|
||||
add_library(Gint::Fxlibc UNKNOWN IMPORTED)
|
||||
endif()
|
||||
set_target_properties(Gint::Fxlibc PROPERTIES
|
||||
IMPORTED_LOCATION "${FXLIBC_PATH}"
|
||||
INTERFACE_LINK_OPTIONS "-lgcc")
|
||||
|
||||
if(NOT TARGET Gint::Gint)
|
||||
add_library(Gint::Gint UNKNOWN IMPORTED)
|
||||
endif()
|
||||
|
@ -49,8 +82,10 @@ if(Gint_FOUND)
|
|||
IMPORTED_LOCATION "${GINT_PATH}"
|
||||
INTERFACE_COMPILE_OPTIONS -fstrict-volatile-bitfields
|
||||
INTERFACE_COMPILE_DEFINITIONS "${INTF_DEFN}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${FXSDK_COMPILER_INSTALL}/include/openlibm"
|
||||
INTERFACE_LINK_LIBRARIES "-lc;-lopenlibm;-lgcc"
|
||||
INTERFACE_LINK_OPTIONS "${INTF_LINK}"
|
||||
)
|
||||
INTERFACE_LINK_LIBRARIES "-lopenlibm;-lgcc"
|
||||
INTERFACE_LINK_OPTIONS "-T;${INTF_LINKER_SCRIPT}"
|
||||
INTERFACE_LINK_DEPENDS "${INTF_LINKER_SCRIPT}")
|
||||
|
||||
target_link_libraries(Gint::Gint INTERFACE Gint::Fxlibc)
|
||||
target_link_libraries(Gint::Fxlibc INTERFACE Gint::Gint)
|
||||
endif()
|
||||
|
|
|
@ -35,8 +35,7 @@ MEMORY
|
|||
/* On-chip IL memory */
|
||||
ilram (rwx): o = 0xe5200000, l = 4k
|
||||
/* On-chip X and Y memory */
|
||||
xram (rwx): o = 0xe5007000, l = 8k
|
||||
yram (rwx): o = 0xe5017000, l = 8k
|
||||
xyram (rwx): o = 0xe500e000, l = 16k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
|
@ -62,19 +61,19 @@ SECTIONS
|
|||
*(.text.entry)
|
||||
|
||||
_bctors = . ;
|
||||
*(.ctors .ctors.*)
|
||||
KEEP(*(.ctors .ctors.*))
|
||||
_ectors = . ;
|
||||
|
||||
_bdtors = . ;
|
||||
*(.dtors .dtors.*)
|
||||
KEEP(*(.dtors .dtors.*))
|
||||
_edtors = . ;
|
||||
|
||||
_gint_exch_start = . ;
|
||||
*(.gint.exch)
|
||||
KEEP(*(.gint.exch))
|
||||
_gint_exch_size = ABSOLUTE(. - _gint_exch_start);
|
||||
|
||||
_gint_tlbh_start = . ;
|
||||
*(.gint.tlbh)
|
||||
KEEP(*(.gint.tlbh))
|
||||
_gint_tlbh_size = ABSOLUTE(. - _gint_tlbh_start);
|
||||
|
||||
*(.text .text.*)
|
||||
|
@ -110,6 +109,7 @@ SECTIONS
|
|||
*(.rodata.4)
|
||||
|
||||
*(.rodata .rodata.*)
|
||||
*(.gint.rodata.sh3)
|
||||
} > rom
|
||||
|
||||
|
||||
|
@ -128,7 +128,7 @@ SECTIONS
|
|||
.bss (NOLOAD) : {
|
||||
_rbss = . ;
|
||||
|
||||
*(.bss COMMON)
|
||||
*(.bss .bss.* COMMON)
|
||||
*(B R)
|
||||
|
||||
. = ALIGN(16);
|
||||
|
@ -188,29 +188,18 @@ SECTIONS
|
|||
. = ALIGN(16);
|
||||
} > ilram AT> rom
|
||||
|
||||
. = ORIGIN(xram);
|
||||
.xram ALIGN(4) : ALIGN(4) {
|
||||
_lxram = LOADADDR(.xram);
|
||||
_rxram = . ;
|
||||
. = ORIGIN(xyram);
|
||||
.xyram ALIGN(4) : ALIGN(4) {
|
||||
_lxyram = LOADADDR(.xyram);
|
||||
_rxyram = . ;
|
||||
|
||||
*(.xram)
|
||||
*(.xram .yram .xyram)
|
||||
|
||||
. = ALIGN(16);
|
||||
} > xram AT> rom
|
||||
|
||||
. = ORIGIN(yram);
|
||||
.yram ALIGN(4) : ALIGN(4) {
|
||||
_lyram = LOADADDR(.yram);
|
||||
_ryram = . ;
|
||||
|
||||
*(.yram)
|
||||
|
||||
. = ALIGN(16);
|
||||
} > yram AT> rom
|
||||
} > xyram AT> rom
|
||||
|
||||
_silram = SIZEOF(.ilram);
|
||||
_sxram = SIZEOF(.xram);
|
||||
_syram = SIZEOF(.yram);
|
||||
_sxyram = SIZEOF(.xyram);
|
||||
|
||||
|
||||
|
||||
|
@ -237,9 +226,6 @@ SECTIONS
|
|||
*/
|
||||
|
||||
/DISCARD/ : {
|
||||
/* Debug sections (often from libgcc) */
|
||||
*(.debug_info .debug_abbrev .debug_loc .debug_aranges
|
||||
.debug_ranges .debug_line .debug_str)
|
||||
/* Java class registration (why are they even here?!) */
|
||||
*(.jcr)
|
||||
/* Asynchronous unwind tables: no C++ exception handling */
|
|
@ -10,19 +10,24 @@ OUTPUT_FORMAT(elf32-sh)
|
|||
/* Located in core/start.c */
|
||||
ENTRY(_start)
|
||||
|
||||
#ifdef FXCG50_FASTLOAD
|
||||
# define _ROM_REGION 0x8c200000
|
||||
#else
|
||||
# define _ROM_REGION 0x00300000
|
||||
#endif
|
||||
|
||||
MEMORY
|
||||
{
|
||||
/* Userspace mapping of the add-in (without G3A header) */
|
||||
rom (rx): o = 0x00300000, l = 2M
|
||||
rom (rx): o = _ROM_REGION, l = 2M
|
||||
/* Static RAM; stack grows down from the end of this region.
|
||||
The first 5k (0x1400 bytes) are reserved by gint for the VBR space,
|
||||
which is loaded dynamically and accessed through P1 */
|
||||
ram (rw): o = 0x08101400, l = 507k
|
||||
ram (rw): o = 0x08101400, l = 491k
|
||||
/* On-chip IL memory */
|
||||
ilram (rwx): o = 0xe5200000, l = 4k
|
||||
/* On-chip X and Y memory */
|
||||
xram (rwx): o = 0xe5007000, l = 8k
|
||||
yram (rwx): o = 0xe5017000, l = 8k
|
||||
xyram (rwx): o = 0xe500e000, l = 16k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
|
@ -32,7 +37,7 @@ SECTIONS
|
|||
*/
|
||||
|
||||
/* First address to be mapped to ROM */
|
||||
_brom = 0x00300000;
|
||||
_brom = ORIGIN(rom);
|
||||
/* Size of ROM mappings */
|
||||
_srom = SIZEOF(.text) + SIZEOF(.rodata)
|
||||
+ SIZEOF(.gint.drivers) + SIZEOF(.gint.blocks);
|
||||
|
@ -45,19 +50,19 @@ SECTIONS
|
|||
*(.text.entry)
|
||||
|
||||
_bctors = . ;
|
||||
*(.ctors .ctors.*)
|
||||
KEEP(*(.ctors .ctors.*))
|
||||
_ectors = . ;
|
||||
|
||||
_bdtors = . ;
|
||||
*(.dtors .dtors.*)
|
||||
KEEP(*(.dtors .dtors.*))
|
||||
_edtors = . ;
|
||||
|
||||
_gint_exch_start = . ;
|
||||
*(.gint.exch)
|
||||
KEEP(*(.gint.exch))
|
||||
_gint_exch_size = ABSOLUTE(. - _gint_exch_start);
|
||||
|
||||
_gint_tlbh_start = . ;
|
||||
*(.gint.tlbh)
|
||||
KEEP(*(.gint.tlbh))
|
||||
_gint_tlbh_size = ABSOLUTE(. - _gint_tlbh_start);
|
||||
|
||||
*(.text .text.*)
|
||||
|
@ -102,8 +107,7 @@ SECTIONS
|
|||
.bss (NOLOAD) : {
|
||||
_rbss = . ;
|
||||
|
||||
*(.bss.vram)
|
||||
*(.bss COMMON)
|
||||
*(.bss .bss.* COMMON)
|
||||
|
||||
. = ALIGN(16);
|
||||
} > ram :NONE
|
||||
|
@ -144,29 +148,23 @@ SECTIONS
|
|||
. = ALIGN(16);
|
||||
} > ilram AT> rom
|
||||
|
||||
. = ORIGIN(xram);
|
||||
.xram ALIGN(4) : ALIGN(4) {
|
||||
_lxram = LOADADDR(.xram);
|
||||
_rxram = . ;
|
||||
. = ORIGIN(xyram);
|
||||
.xyram ALIGN(4) : ALIGN(4) {
|
||||
_lxyram = LOADADDR(.xyram);
|
||||
_rxyram = . ;
|
||||
|
||||
*(.xram)
|
||||
*(.xram .yram .xyram)
|
||||
|
||||
. = ALIGN(16);
|
||||
} > xram AT> rom
|
||||
|
||||
. = ORIGIN(yram);
|
||||
.yram ALIGN(4) : ALIGN(4) {
|
||||
_lyram = LOADADDR(.yram);
|
||||
_ryram = . ;
|
||||
|
||||
*(.yram)
|
||||
|
||||
. = ALIGN(16);
|
||||
} > yram AT> rom
|
||||
} > xyram AT> rom
|
||||
|
||||
_silram = SIZEOF(.ilram);
|
||||
_sxram = SIZEOF(.xram);
|
||||
_syram = SIZEOF(.yram);
|
||||
_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 */
|
||||
|
@ -188,10 +186,7 @@ SECTIONS
|
|||
|
||||
/DISCARD/ : {
|
||||
/* SH3-only data sections */
|
||||
*(.gint.data.sh3 .gint.bss.sh3)
|
||||
/* Debug sections (often from libgcc) */
|
||||
*(.debug_info .debug_abbrev .debug_loc .debug_aranges
|
||||
.debug_ranges .debug_line .debug_str)
|
||||
*(.gint.rodata.sh3 .gint.data.sh3 .gint.bss.sh3)
|
||||
/* Java class registration (why are they even here?!) */
|
||||
*(.jcr)
|
||||
/* Asynchronous unwind tables: no C++ exception handling */
|
206
fxcp_hh2.ld.c
Normal file
206
fxcp_hh2.ld.c
Normal file
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
Linker script for fxCP add-ins linking with HollyHock2.
|
||||
*/
|
||||
|
||||
OUTPUT_ARCH(sh4)
|
||||
OUTPUT_FORMAT(elf32-sh)
|
||||
ENTRY(_start_header)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
/* VRAM backup - our main fixed area to load code, size 320x528x2 */
|
||||
ram (rwx): o = 0x8c052800, l = 337920
|
||||
/* End-of-RAM area, 104 kB are safe to use according to experience. What
|
||||
happens is HollyHock itself is loaded at 0x8cfe0000 (128 kB before the
|
||||
end) so we have to fit after it. CPBoy uses 0x8cfe6000, follow that. */
|
||||
eram (rwx): o = 0x8cfe6000, l = 102144 /* 104k - 0x1100 */
|
||||
/* Space for the vbr */
|
||||
vbr (rwx): o = 0x8cffef00, l = 0x1100
|
||||
/* On-chip IL memory */
|
||||
ilram (rwx): o = 0xe5200000, l = 4k
|
||||
/* On-chip X and Y memory */
|
||||
xyram (rwx): o = 0xe500e000, l = 16k
|
||||
/* Flat binary space, used to have everything in the correct order in the
|
||||
binary. This is just for the bin file layout. */
|
||||
bin (rwx): o = 0x00000000, l = 1M
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/*
|
||||
** ROM sections
|
||||
*/
|
||||
|
||||
/* First address to be mapped to ROM */
|
||||
_brom = ORIGIN(ram);
|
||||
/* Size of ROM mappings */
|
||||
_srom = SIZEOF(.text) + SIZEOF(.rodata)
|
||||
+ SIZEOF(.gint.drivers) + SIZEOF(.gint.blocks);
|
||||
|
||||
/* Machine code going to ROM:
|
||||
- Entry function (.text.entry)
|
||||
- Compiler-provided constructors (.ctors) and destructors (.dtors)
|
||||
- All text from .text and .text.* (including user code) */
|
||||
.hh2 : {
|
||||
KEEP(*(.hh2.header))
|
||||
KEEP(*(.hh2.info))
|
||||
KEEP(*(.hh2.stage2))
|
||||
. = ALIGN(16);
|
||||
} > eram AT> bin
|
||||
|
||||
_gint_hh2_stage2_offset = SIZEOF(.hh2);
|
||||
_gint_hh2_stage2_load = ORIGIN(ram);
|
||||
|
||||
.text : {
|
||||
*(.text.entry)
|
||||
|
||||
_bctors = . ;
|
||||
*(.ctors .ctors.*)
|
||||
_ectors = . ;
|
||||
|
||||
_bdtors = . ;
|
||||
*(.dtors .dtors.*)
|
||||
_edtors = . ;
|
||||
|
||||
. = ALIGN(0x10);
|
||||
_gint_exch_start = . ;
|
||||
*(.gint.exch)
|
||||
_gint_exch_size = ABSOLUTE(. - _gint_exch_start);
|
||||
|
||||
. = ALIGN(0x10);
|
||||
_gint_tlbh_start = . ;
|
||||
*(.gint.tlbh)
|
||||
_gint_tlbh_size = ABSOLUTE(. - _gint_tlbh_start);
|
||||
|
||||
*(.text .text.*)
|
||||
} > ram AT> bin
|
||||
|
||||
/* gint's interrupt handler blocks (.gint.blocks)
|
||||
Although gint's blocks end up in VBR space, they are relocated at
|
||||
startup by the library/drivers, so we store them here for now */
|
||||
.gint.blocks ALIGN(4) : ALIGN(4) {
|
||||
KEEP(*(.gint.blocks));
|
||||
} > ram AT> bin
|
||||
|
||||
/* Exposed driver interfaces (.gint.drivers)
|
||||
The driver information is required to start and configure the
|
||||
driver, even if the symbols are not referenced */
|
||||
.gint.drivers ALIGN(4) : ALIGN(4) {
|
||||
_gint_drivers = . ;
|
||||
KEEP(*(SORT_BY_NAME(.gint.drivers.*)));
|
||||
_gint_drivers_end = . ;
|
||||
} > ram AT> bin
|
||||
|
||||
/* Read-only data going to ROM:
|
||||
- Resources or assets from fxconv or similar converters
|
||||
- Data marked read-only by the compiler (.rodata and .rodata.*) */
|
||||
.rodata ALIGN(4) : ALIGN(4) SUBALIGN(4) {
|
||||
/* Put these first, they need to be 4-aligned */
|
||||
*(.rodata.4)
|
||||
|
||||
*(.rodata .rodata.*)
|
||||
} > ram AT> bin
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** RAM sections
|
||||
*/
|
||||
|
||||
/* Read-write data sections going to RAM (.data and .data.*) */
|
||||
.data ALIGN(4) : ALIGN(4) {
|
||||
_ldata = LOADADDR(.data);
|
||||
_rdata = . ;
|
||||
|
||||
*(.data .data.*)
|
||||
/* Code that must remain mapped; no MMU on HH2, so fine */
|
||||
*(.gint.mapped)
|
||||
/* References to mapped code - no relocation needed */
|
||||
*(.gint.mappedrel)
|
||||
|
||||
. = ALIGN(16);
|
||||
} > ram AT> bin
|
||||
|
||||
/* Read-write data sub-aligned to 4 bytes (mainly from fxconv) */
|
||||
.data.4 ALIGN(4) : ALIGN(4) SUBALIGN(4) {
|
||||
*(.data.4)
|
||||
. = ALIGN(16);
|
||||
} > ram AT> bin
|
||||
|
||||
_sdata = SIZEOF(.data) + SIZEOF(.data.4);
|
||||
|
||||
/* On-chip memory sections: IL, X and Y memory */
|
||||
|
||||
. = ORIGIN(ilram);
|
||||
.ilram ALIGN(4) : ALIGN(4) {
|
||||
_lilram = ABSOLUTE(LOADADDR(.ilram) + ORIGIN(ram));
|
||||
_rilram = . ;
|
||||
|
||||
*(.ilram)
|
||||
|
||||
. = ALIGN(16);
|
||||
} > ilram AT> bin
|
||||
|
||||
. = ORIGIN(xyram);
|
||||
.xyram ALIGN(4) : ALIGN(4) {
|
||||
_lxyram = ABSOLUTE(LOADADDR(.xyram) + ORIGIN(ram));
|
||||
_rxyram = . ;
|
||||
|
||||
*(.xram .yram .xyram)
|
||||
|
||||
. = ALIGN(16);
|
||||
|
||||
} > xyram AT> bin
|
||||
|
||||
/* .text and .xyram are the first and last section in the stage-2 load. */
|
||||
_gint_hh2_stage2_size = LOADADDR(.xyram) + SIZEOF(.xyram) - LOADADDR(.text);
|
||||
|
||||
_silram = SIZEOF(.ilram);
|
||||
_sxyram = SIZEOF(.xyram);
|
||||
|
||||
_lgmapped = ABSOLUTE(0);
|
||||
_sgmapped = ABSOLUTE(0);
|
||||
_lreloc = ABSOLUTE(0);
|
||||
_sreloc = ABSOLUTE(0);
|
||||
_gint_region_vbr = ORIGIN(vbr);
|
||||
|
||||
/* BSS data going to RAM. The BSS section is to be stripped from the
|
||||
ELF file later, and wiped at startup */
|
||||
.bss (NOLOAD) : {
|
||||
_rbss = . ;
|
||||
|
||||
*(.bss .bss.* COMMON)
|
||||
|
||||
. = ALIGN(16);
|
||||
} > ram :NONE
|
||||
|
||||
_sbss = SIZEOF(.bss);
|
||||
|
||||
/* gint's uninitialized BSS section, going to static RAM. All the large
|
||||
data arrays will be located here */
|
||||
.gint.bss (NOLOAD) : {
|
||||
*(.gint.bss)
|
||||
. = ALIGN(16);
|
||||
|
||||
/* End of user RAM */
|
||||
_euram = . ;
|
||||
} > ram :NONE
|
||||
|
||||
_sgbss = SIZEOF(.gint.bss);
|
||||
|
||||
/*
|
||||
** Unused sections
|
||||
*/
|
||||
|
||||
/DISCARD/ : {
|
||||
/* SH3-only data sections */
|
||||
*(.gint.rodata.sh3 .gint.data.sh3 .gint.bss.sh3)
|
||||
/* Java class registration (why are they even here?!) */
|
||||
*(.jcr)
|
||||
/* Asynchronous unwind tables: no C++ exception handling */
|
||||
*(.eh_frame_hdr)
|
||||
*(.eh_frame)
|
||||
/* Comments or anything the compiler might generate */
|
||||
*(.comment)
|
||||
}
|
||||
}
|
|
@ -5,14 +5,17 @@
|
|||
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 \
|
||||
|
@ -21,5 +24,8 @@ 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
|
||||
|
|
|
@ -1,98 +1,235 @@
|
|||
//---
|
||||
// gint:bfile - BFile interface
|
||||
// gint:bfile - BFile interface
|
||||
//
|
||||
// The system's file system is a nightmare and the risk of corrupting it
|
||||
// or the flash by driving it manually is too great to risk. This module
|
||||
// interfaces with the BFile syscalls for file management.
|
||||
// BFile is the OS's native interface to the filesystem. It has quite a bit of
|
||||
// legacy, so it's not very easy to use. Please note that BFile cannot be used
|
||||
// from within gint, so do a gint_world_switch() (<gint/gint.h>) to call BFile
|
||||
// functions; otherwise the add-in is likely to crash.
|
||||
//
|
||||
// There are two different filesystems:
|
||||
// * An older, in-house one made by CASIO and informally called CASIOWIN (which
|
||||
// is the name of the OS itself), which is incomplete, hard to use, and very
|
||||
// limiting, but also very fast.
|
||||
// * A newer one, designed by Kyoto Software Research and called Fugue, which
|
||||
// is mostly complete and behaves as a regular filesystem, though very slow.
|
||||
//
|
||||
// You can detect which one is used by querying gint[HWFS] (<gint/hardware.h>):
|
||||
// * HWFS_FUGUE is the newer one; it is found in:
|
||||
// - The fx-CG series (in France: Prizm and Graph 90+E)
|
||||
// - The fx G-III series (in France: Graph 35+E II)
|
||||
// * HWFS_CASIOWIN is the older one; it is found in all older black-and-white
|
||||
// model that have a storage memory.
|
||||
//
|
||||
// Wherever Fugue is used, gint supports the Unix file API (open, read, write,
|
||||
// etc) and the C99 standard file API (fopen, fread, fwrite, etc), so there is
|
||||
// no need to call into BFile directly (you should still do a world switch
|
||||
// before using these functions).
|
||||
//
|
||||
// You should only have to use BFile if you're dealing with the CASIOWIN
|
||||
// filesystem. With Fugue, not only are the Unix/C99 APIs easier to use, but
|
||||
// the meanings of arguments and return values in BFile calls also change
|
||||
// compared to the CASIOWIN filesystem, so there's little to gain anyway.
|
||||
//
|
||||
// If you're here for the CASIOWIN filesystem, be aware of its limitations. In
|
||||
// general reading files will work fine; expect no issues with that. Modifying
|
||||
// files is where things get difficult. Keep the following in mind:
|
||||
//
|
||||
// * Non-standard meanings of arguments and return values (eg. BFile_Read()
|
||||
// returns the number of readable bytes between the new position and EOF).
|
||||
// * Files must be created with a fixed size indicated in BFile_Create() and
|
||||
// are initialized with 0xff.
|
||||
// * A write to a file can only replace 1's with 0's, meaning in practice a
|
||||
// file can only be written to once. (That's why it's created with 0xff.)
|
||||
// * All writes must be of even size; writing an odd number of bytes can mess
|
||||
// up the file and confuse the filesystem.
|
||||
// * Only one level of folders is supported; attempting to create second-level
|
||||
// subfolders results in weird recursive directories (don't do that).
|
||||
//
|
||||
// File paths in the OS use the non-standard FONTCHARACTER encoding, which is a
|
||||
// 16-bit fixed-width encoding. Most users don't care about special characters;
|
||||
// in GCC, you can get a 16-bit literal string with the u"" prefix, eg.
|
||||
// u"\\\\fls0\\data.bin"
|
||||
// which is what you usually supply as the [uint16_t const *path] argument.
|
||||
//
|
||||
// All functions return nonnegative values on success. If no return value is
|
||||
// described then a successful call returns 0. Unless specified otherwise, all
|
||||
// functions can also return a negative error code as documented near the end
|
||||
// of this header.
|
||||
//---
|
||||
|
||||
#ifndef GINT_BFILE
|
||||
#define GINT_BFILE
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* BFile_Remove(): Remove a file
|
||||
Also works if the file does not exist.
|
||||
//---
|
||||
// Common file access functions
|
||||
//---
|
||||
|
||||
@file FONTCHARACTER file path
|
||||
Returns a BFile error code. */
|
||||
int BFile_Remove(uint16_t const *file);
|
||||
/* Remove a file or folder (also works if the entry does not exist). */
|
||||
int BFile_Remove(uint16_t const *path);
|
||||
|
||||
/* Rename a file (can move folders; Fugue only). */
|
||||
int BFile_Rename(uint16_t const *oldpath, uint16_t const *newpath);
|
||||
|
||||
#define BFile_File 1
|
||||
#define BFile_Folder 5
|
||||
|
||||
/* BFile_Create(): Create a new file or folder
|
||||
|
||||
/* BFile_Create(): Create a new entry
|
||||
The file or directory must not exist. For a file the size pointer must point
|
||||
to the desired file size (which is fixed), for a folder it is ignored.
|
||||
to the desired file size (which is fixed), for a folder it is ignored. With
|
||||
CASIOWIN this is the final size of the file. With Fugue the file can be
|
||||
resized dynamically and is usually created with initial size 0.
|
||||
|
||||
@file FONTCHARACTER file path
|
||||
@type Entry type
|
||||
@size Pointer to file size if [type = BFile_File], use NULL otherwise
|
||||
Returns a BFile error code. */
|
||||
enum BFile_EntryType
|
||||
{
|
||||
BFile_File = 1,
|
||||
BFile_Folder = 5,
|
||||
};
|
||||
int BFile_Create(uint16_t const *file, enum BFile_EntryType type, int *size);
|
||||
@path FONTCHARACTER file path
|
||||
@type Entry type (BFile_File or BFile_Folder)
|
||||
@size Pointer to file size if type is BFile_File, use NULL otherwise */
|
||||
int BFile_Create(uint16_t const *path, int type, int *size);
|
||||
|
||||
/* BFile_Open(): Open an existing file
|
||||
The file must exist.
|
||||
#define BFile_ReadOnly 0x01
|
||||
#define BFile_WriteOnly 0x02
|
||||
#define BFile_ReadWrite (BFile_ReadOnly | BFile_WriteOnly)
|
||||
#define BFile_Share 0x80
|
||||
#define BFile_ReadShare (BFile_ReadOnly | BFile_Share)
|
||||
#define BFile_ReadWriteShare (BFile_ReadWrite | BFile_Share)
|
||||
|
||||
@file FONTCHARACTER file path
|
||||
/* BFile_Open(): Open a file for reading or writing
|
||||
|
||||
The file must exist, even when opening in writing mode. The meaning of the
|
||||
[Share] flag isn't clear; I believe it's simply ignored in the CASIOWIN
|
||||
filesystem.
|
||||
|
||||
@path FONTCHARACTER file path
|
||||
@mode Desired access mode
|
||||
Returns a file descriptor on success, or a negative BFile error code. */
|
||||
enum BFile_OpenMode
|
||||
{
|
||||
BFile_ReadOnly = 0x01,
|
||||
BFile_WriteOnly = 0x02,
|
||||
BFile_ReadWrite = BFile_ReadOnly | BFile_WriteOnly,
|
||||
};
|
||||
int BFile_Open(uint16_t const *file, enum BFile_OpenMode mode);
|
||||
Returns a file descriptor (or a negative error code). */
|
||||
int BFile_Open(uint16_t const *path, int mode);
|
||||
|
||||
/* BFile_Close(): Close a file descriptor
|
||||
@fd Open file descriptor
|
||||
Returns a BFile error code. */
|
||||
/* Close an open file descriptor. */
|
||||
int BFile_Close(int fd);
|
||||
|
||||
/* BFile_Size(): Retrieve size of an open file
|
||||
@fd Open file descriptor
|
||||
Returns the file size in bytes, or a negative BFile error code*/
|
||||
/* Get the size of an open file. */
|
||||
int BFile_Size(int fd);
|
||||
|
||||
/* BFile_Write(): Write data to an open file
|
||||
Second and third argument specify the data and length to write.
|
||||
|
||||
WARNING: The file systems has shown to become inconsistent if an odd number
|
||||
of bytes is written with BFile_Write(). Keep it even!
|
||||
WARNING: The CASIOWIN fs is known to become inconsistent if an odd number of
|
||||
bytes is written with BFile_Write(). Always keep it even!
|
||||
|
||||
@fd File descriptor open for writing
|
||||
@data Data to write
|
||||
@even_size Size to write (must be even, yes)
|
||||
Returns a BFile error code. */
|
||||
With CASIOWIN, returns the new file offset after writing (or an error code).
|
||||
With Fugue, returns the amount of data written (or an error code). */
|
||||
int BFile_Write(int fd, void const *data, int even_size);
|
||||
|
||||
/* BFile_Read(): Read data from an open file
|
||||
The second and third argument specify where to store and how much to read.
|
||||
The location from where the data is read depends on [whence]:
|
||||
|
||||
The extra argument [whence] specifies where data is read from in the style
|
||||
of pread(2), and is supported with both filesystems.
|
||||
|
||||
* If [whence >= 0], it is taken as an absolute location within the file;
|
||||
* If [whence == -1], BFile_Read() reads from the current position.
|
||||
|
||||
@fd File descriptor open for reading
|
||||
@data Buffer of at least [size] bytes to store data to
|
||||
@size Number of bytes to read
|
||||
@whence Starting position of the data to read in the file
|
||||
Returns a BFile error code. */
|
||||
With Fugue this function can read past end of file and return the requested
|
||||
amount of bytes even when the file does not have enough data to read that
|
||||
much. It seems that extra bytes read as zeros. Reading past the end does
|
||||
*not* extend the file size.
|
||||
|
||||
With CASIOWIN, returns how much data can be read from the updated file
|
||||
offset (ie. how many bytes until end of file), or an error code.
|
||||
With Fugue, returns the amount of data read (or an error code). */
|
||||
int BFile_Read(int handle, void *data, int size, int whence);
|
||||
|
||||
/* BFile_FindFirst(): Search a directory for file with matching name
|
||||
Doesn't work on Main memory. Only four search handle can be opened, you need
|
||||
to close them to be able to reuse them. Search is NOT case sensitive and *
|
||||
can be used as a wildcard.
|
||||
/* BFile_Seek(): Seek to a relative or absolute position within an open file
|
||||
|
||||
With CASIOWIN, moves [offset] bytes relative to the current position, and
|
||||
returns how much data can be read from the new position. BFile_Seek(fd, 0)
|
||||
combined with BFile_Size(fd) can be used to determine the current position.
|
||||
|
||||
With Fugue, moves to the absolute position [offset] within the file, and
|
||||
returns the amount of allocated space following the new position (usually
|
||||
larger than the amount of data until end-of-file because files are allocated
|
||||
in units of 4096 bytes). There is no way to seek relative to the current
|
||||
position unless the target is precomputed with BFile_GetPos(). */
|
||||
int BFile_Seek(int fd, int offset);
|
||||
|
||||
/* BFile_GetPos(): Get the current position in an open file
|
||||
|
||||
This call does not exist in the CASIOWIN interface, so this function always
|
||||
returns -1 on models with a CASIOWIN filesystem.
|
||||
|
||||
This call exists in Fugue, however some Fugue models have their syscall list
|
||||
inherited from the CASIOWIN era and don't have an entry point for it (or if
|
||||
there's one it's escape scrutiny so far).
|
||||
|
||||
* Prizm / Graph 90+E / fx-CG series: this function works as intended.
|
||||
* Graph 35+E II / G-III series: the call is missing, returns -1.
|
||||
|
||||
For the latter models there is no easily reliable way of knowing the current
|
||||
position within an open file! */
|
||||
int BFile_GetPos(int fd);
|
||||
|
||||
//---
|
||||
// Error codes
|
||||
//---
|
||||
|
||||
#define BFile_EntryNotFound -1
|
||||
#define BFile_IllegalParam -2
|
||||
#define BFile_IllegalPath -3
|
||||
#define BFile_DeviceFull -4
|
||||
#define BFile_IllegalDevice -5
|
||||
#define BFile_IllegalFilesystem -6
|
||||
#define BFile_IllegalSystem -7
|
||||
#define BFile_AccessDenied -8
|
||||
#define BFile_AlreadyLocked -9
|
||||
#define BFile_IllegalTaskID -10
|
||||
#define BFile_PermissionError -11
|
||||
#define BFile_EntryFull -12
|
||||
#define BFile_AlreadyExists -13
|
||||
#define BFile_ReadOnlyFile -14
|
||||
#define BFile_IllegalFilter -15
|
||||
#define BFile_EnumerateEnd -16
|
||||
#define BFile_DeviceChanged -17
|
||||
//#define BFile_NotRecordFile -18 // Not used
|
||||
#define BFile_IllegalSeekPos -19
|
||||
#define BFile_IllegalBlockFile -20
|
||||
//#define BFile_NoSuchDevice -21 // Not used
|
||||
//#define BFile_EndOfFile -22 // Not used
|
||||
#define BFile_NotMountDevice -23
|
||||
#define BFile_NotUnmountDevice -24
|
||||
#define BFile_CannotLockSystem -25
|
||||
#define BFile_RecordNotFound -26
|
||||
//#define BFile_NotDualRecordFile -27 // Not used
|
||||
#define BFile_NoAlarmSupport -28
|
||||
#define BFile_CannotAddAlarm -29
|
||||
#define BFile_FileFindUsed -30
|
||||
#define BFile_DeviceError -31
|
||||
#define BFile_SystemNotLocked -32
|
||||
#define BFile_DeviceNotFound -33
|
||||
#define BFile_FileTypeMismatch -34
|
||||
#define BFile_NotEmpty -35
|
||||
#define BFile_BrokenSystemData -36
|
||||
#define BFile_MediaNotReady -37
|
||||
#define BFile_TooManyAlarms -38
|
||||
#define BFile_SameAlarmExists -39
|
||||
#define BFile_AccessSwapArea -40
|
||||
#define BFile_MultimediaCard -41
|
||||
#define BFile_CopyProtection -42
|
||||
#define BFile_IllegalFileData -43
|
||||
|
||||
//---
|
||||
// Search API
|
||||
//
|
||||
// The search API is described below. It's somewhat unreliable, with unclear
|
||||
// semantics and a history of breaking in seemingly reasonable programs. One
|
||||
// day probably we'll know how to use it properly and reliably.
|
||||
//
|
||||
// Note: always close search handles or trouble will ensue (eg. add-in
|
||||
// discovery failing).
|
||||
//---
|
||||
|
||||
@search FONTCHARACTER file path to match
|
||||
@shandle Search handle to pass to BFile_FindNext or BFile_FindClose
|
||||
@founfile FONTCHARACTER found file path
|
||||
@fileinfo Structure containing a lot of information on the found file
|
||||
Returns 0 on success, -1 if no file found, or negative value on error. */
|
||||
struct BFile_FileInfo
|
||||
{
|
||||
uint16_t index;
|
||||
|
@ -105,36 +242,74 @@ struct BFile_FileInfo
|
|||
/* Address of first fragment (do not use directly) */
|
||||
void *address;
|
||||
};
|
||||
enum BFile_FileType
|
||||
{
|
||||
BFile_Type_Directory = 0x0000,
|
||||
BFile_Type_File = 0x0001,
|
||||
BFile_Type_Addin = 0x0002,
|
||||
BFile_Type_Eact = 0x0003,
|
||||
BFile_Type_Language = 0x0004,
|
||||
BFile_Type_Bitmap = 0x0005,
|
||||
BFile_Type_MainMem = 0x0006,
|
||||
BFile_Type_Temp = 0x0007,
|
||||
BFile_Type_Dot = 0x0008,
|
||||
BFile_Type_DotDot = 0x0009,
|
||||
BFile_Type_Volume = 0x000a,
|
||||
BFile_Type_Archived = 0x0041,
|
||||
};
|
||||
int BFile_FindFirst(uint16_t const *search, int *shandle, uint16_t *foundfile,
|
||||
|
||||
#define BFile_Type_Directory 0x0000
|
||||
#define BFile_Type_File 0x0001
|
||||
#define BFile_Type_Addin 0x0002
|
||||
#define BFile_Type_Eact 0x0003
|
||||
#define BFile_Type_Language 0x0004
|
||||
#define BFile_Type_Bitmap 0x0005
|
||||
#define BFile_Type_MainMem 0x0006
|
||||
#define BFile_Type_Temp 0x0007
|
||||
#define BFile_Type_Dot 0x0008
|
||||
#define BFile_Type_DotDot 0x0009
|
||||
#define BFile_Type_Volume 0x000a
|
||||
#define BFile_Type_Archived 0x0041
|
||||
|
||||
/* BFile_FindFirst(): Search the storage memory for paths matching a pattern
|
||||
|
||||
This if for the storage memory only. There are only four search handles;
|
||||
make sure to close them, there is no automatic device to close them for you
|
||||
even after the add-in exists.
|
||||
|
||||
Search is NOT case sensitive. '*' can be used as a wildcard, although it's
|
||||
unclear whether more than one '*' is supported, whether '*' can match in a
|
||||
directory name, whether multiple folders can be searched simultaneously, and
|
||||
whether directories can be matched.
|
||||
|
||||
@pattern FONTCHARACTER glob pattern
|
||||
@shandle Will receive search handle (to use in BFile_FindNext/FindClose)
|
||||
@foundfile Will receive FONTCHARACTER path of matching entry
|
||||
@fileinfo Will receive metadata of matching entry
|
||||
|
||||
On success, returns 0, stores the search handle in *shandle, and stores
|
||||
information about the first match in foundfile and fileinfo. The negative
|
||||
error code BFile_EntryNotFound should be interpreted as an empty result (ie.
|
||||
no entry matched) rather than an error.
|
||||
|
||||
Returns 0 on success or a negative error code. BFile_EntryNotFound should be
|
||||
interpreted as an empty result (ie. no file matched). */
|
||||
int BFile_FindFirst(uint16_t const *pattern, int *shandle, uint16_t *foundfile,
|
||||
struct BFile_FileInfo *fileinfo);
|
||||
|
||||
/* BFile_FindNext(): Continue a search a directory for file with matching name
|
||||
/* BFile_FindNext(): Continue a search
|
||||
|
||||
@shandle Search handle from BFile_FindFirst
|
||||
@founfile FONTCHARACTER found file path
|
||||
@fileinfo Structure containing a lot of information on the found file
|
||||
Returns 0 on success, -1 if end is reached, or negative value on error. */
|
||||
Continues the search for matches. The search handle is the value set in
|
||||
*shandle in BFile_FindFirst(). As before, *foundfile receives the matching
|
||||
entry's path and *fileinfo its metadata.
|
||||
|
||||
Returns 0 on success. The negative error code BFile_EnumerateEnd should be
|
||||
interpreted as the end of the search (ie. all matching files have been
|
||||
returned) rather than an error. */
|
||||
int BFile_FindNext(int shandle, uint16_t *foundfile,
|
||||
struct BFile_FileInfo *fileinfo);
|
||||
|
||||
/* BFile_FindClose(): Close the specified search handle
|
||||
@shandle Search handle from BFile_FindFirst
|
||||
Return 0 on success or negative value on error. */
|
||||
/* Close a search handle (with or without exhausting the matches). */
|
||||
int BFile_FindClose(int shandle);
|
||||
|
||||
//---
|
||||
// Additional functions
|
||||
//
|
||||
// The following functions are implemented in gint using lower-level BFile
|
||||
// functions. They add abstraction/convenience to the API, but can be pretty
|
||||
// slow as they result in more BFile calls being made.
|
||||
//---
|
||||
|
||||
/* BFile_Ext_Stat(): Stat an entry for type and size */
|
||||
int BFile_Ext_Stat(uint16_t const *path, int *type, int *size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_BFILE */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_CLOCK
|
||||
#define GINT_CLOCK
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
/* This header used to expose the sleep() function; include <gint/cpu.h> to
|
||||
ensure this is still the case */
|
||||
|
@ -48,11 +52,108 @@ typedef struct
|
|||
module; this address never changes. */
|
||||
const clock_frequency_t *clock_freq(void);
|
||||
|
||||
/* cpg_compute_freq(): Compute the current clock frequency
|
||||
This function updates the data structure returned by clock_freq() by
|
||||
determining the current clock frequencies from the CPG. */
|
||||
void cpg_compute_freq(void);
|
||||
|
||||
//---
|
||||
// Overclock
|
||||
//---
|
||||
|
||||
/* TODO: All overclock */
|
||||
/* The following enumerations define the clock speed settings supported by
|
||||
gint. These are always the settings from Ftune/Ptune, which are the most
|
||||
widely tested and gint treats as the standard. */
|
||||
enum {
|
||||
/* Combinations of hardware settings that are none of Ftune's levels */
|
||||
CLOCK_SPEED_UNKNOWN = 0,
|
||||
|
||||
/* Ftune's 5 default overclock levels. The main settings are listed
|
||||
below, though many more are involved.
|
||||
|
||||
On SH3 fx-9860G-like:
|
||||
F1: CPU @ 29 MHz [Default speed]
|
||||
F2: CPU @ 58 MHz [Similar to G-III default]
|
||||
F3: CPU @ 88 MHz
|
||||
F4: CPU @ 118 MHz [Fastest CPU option]
|
||||
F5: CPU @ 118 MHz [Reduced memory wait times]
|
||||
On SH4 fx-9860G-like:
|
||||
F1: CPU @ 29 MHz, BFC @ 29 MHz [Default speed]
|
||||
F2: CPU @ 58 MHz, BFC @ 29 MHz [Similar to G-III default]
|
||||
F3: CPU @ 29 MHz, BFC @ 29 MHz [SH3 default]
|
||||
F4: CPU @ 118 MHz, BFC @ 59 MHz
|
||||
F5: CPU @ 236 MHz, BFC @ 118 MHz [Fastest option]
|
||||
On G-III / Graph 35+E II:
|
||||
F1: CPU @ 58 MHz, BFC @ 29 MHz [Default speed]
|
||||
F2: CPU @ 58 MHz, BFC @ 29 MHz [fx-CG 10/20 default]
|
||||
F3: CPU @ 29 MHz, BFC @ 29 MHz [SH3 default]
|
||||
F4: CPU @ 118 MHz, BFC @ 58 MHz
|
||||
F5: CPU @ 235 MHz, BFC @ 58 MHz [Fastest option]
|
||||
On fx-CG 10/20:
|
||||
F1: CPU @ 58 MHz, BFC @ 29 MHz [Default speed]
|
||||
F2: CPU @ 58 MHz, BFC @ 29 MHz [Improved memory speed]
|
||||
F3: CPU @ 118 MHz, BFC @ 58 MHz [Faster than F2]
|
||||
F4: CPU @ 118 MHz, BFC @ 118 MHz [Fastest bus option]
|
||||
F5: CPU @ 191 MHz, BFC @ 94 MHz [Fastest CPU option]
|
||||
On fx-CG 50:
|
||||
F1: CPU @ 116 MHz, BFC @ 58 MHz [Default speed]
|
||||
F2: CPU @ 58 MHz, BFC @ 29 MHz [fx-CG 10/20 default]
|
||||
F3: CPU @ 94 MHz, BFC @ 47 MHz [Clearly slow: F2 < F3 < F1]
|
||||
F4: CPU @ 232 MHz, BFC @ 58 MHz [Fastest CPU option]
|
||||
F5: CPU @ 189 MHz, BFC @ 94 MHz [Fastest bus option] */
|
||||
|
||||
CLOCK_SPEED_F1 = 1,
|
||||
CLOCK_SPEED_F2 = 2,
|
||||
CLOCK_SPEED_F3 = 3,
|
||||
CLOCK_SPEED_F4 = 4,
|
||||
CLOCK_SPEED_F5 = 5,
|
||||
|
||||
/* The default clock speed is always Ftune's F1 */
|
||||
CLOCK_SPEED_DEFAULT = CLOCK_SPEED_F1,
|
||||
};
|
||||
|
||||
/* clock_get_speed(): Determine the current clock speed
|
||||
|
||||
This function compares the current hardware state with the settings for each
|
||||
speed level and returns the current one. If the hardware state does not
|
||||
correspond to any of Ftune's settings, CLOCK_SPEED_UNKNOWN is returned. */
|
||||
int clock_get_speed(void);
|
||||
|
||||
/* clock_set_speed(): Set the current clock speed
|
||||
|
||||
This function sets the clock speed to the desired level. This is "the
|
||||
overclock function", although depending on the model or settings it is also
|
||||
the downclocking function.
|
||||
|
||||
The process of changing clock speeds is non-trivial, requires waiting for
|
||||
the DMA to finish its work and slightly affects running timers. You should
|
||||
avoid changing the clock speed constantly if not necessary. If this function
|
||||
detects that the desired clock speed is already in use, it returns without
|
||||
performing any change.
|
||||
|
||||
Currently the clock speed is not reset during a world switch nor when
|
||||
leaving the add-in. */
|
||||
void clock_set_speed(int speed);
|
||||
|
||||
/* If you want to faithfully save and restore the clock state while properly
|
||||
handling clock speeds that are not Ftune/PTune's defaults, you can get a
|
||||
full copy of the settings.
|
||||
|
||||
WARNING: Applying random settings with cpg_set_overclock_setting() might
|
||||
damage your calculator! */
|
||||
|
||||
struct cpg_overclock_setting
|
||||
{
|
||||
uint32_t FLLFRQ, FRQCR;
|
||||
uint32_t CS0BCR, CS2BCR, CS3BCR, CS5aBCR;
|
||||
uint32_t CS0WCR, CS2WCR, CS3WCR, CS5aWCR;
|
||||
};
|
||||
|
||||
/* Queries the clock setting from the hardware. */
|
||||
void cpg_get_overclock_setting(struct cpg_overclock_setting *s);
|
||||
|
||||
/* Applies the specified overclock setting. */
|
||||
void cpg_set_overclock_setting(struct cpg_overclock_setting const *s);
|
||||
|
||||
//---
|
||||
// Sleep functions
|
||||
|
@ -72,4 +173,8 @@ void sleep_us_spin(uint64_t delay_us);
|
|||
/* sleep_ms(): Sleep for a fixed duration in milliseconds */
|
||||
#define sleep_ms(delay_ms) sleep_us((delay_ms) * 1000ull)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_CLOCK */
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#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 */
|
||||
|
@ -16,10 +14,50 @@
|
|||
0x03f7c0a0 = Commit 3f7c0a0 */
|
||||
#define GINT_HASH 0x@GINT_GIT_HASH@
|
||||
|
||||
/* GINT_USER_VRAM: Selects whether to store VRAMs in the user stack (occupying
|
||||
350k/512k of the area) or in the system stack (the default). (fx-CG 50) */
|
||||
/* 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_CP 0
|
||||
# define GINT_HW_SWITCH(FX,CG,CP) (FX)
|
||||
#elif defined(FXCG50)
|
||||
# define GINT_HW_FX 0
|
||||
# define GINT_HW_CG 1
|
||||
# define GINT_HW_CP 0
|
||||
# define GINT_HW_SWITCH(FX,CG,CP) (CG)
|
||||
#elif defined(FXCP)
|
||||
# define GINT_HW_FX 0
|
||||
# define GINT_HW_CG 0
|
||||
# define GINT_HW_CP 1
|
||||
# define GINT_HW_SWITCH(FX,CG,CP) (CP)
|
||||
#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_CP GINT_HW_CP
|
||||
#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
|
||||
|
||||
/* GINT_USER_VRAM: Selects whether to store VRAMs in the user stack or in the
|
||||
OS stack. Deprecated, now controlled by GINT_NO_OS_STACK. (fx-CG 50) */
|
||||
#cmakedefine GINT_USER_VRAM
|
||||
|
||||
#ifdef GINT_USER_VRAM
|
||||
# define GINT_NO_OS_STACK
|
||||
#endif
|
||||
|
||||
/* GINT_STATIC_GRAY: Selects whether additional gray VRAMs are allocated
|
||||
statically or in the system heap (fx-9860G) */
|
||||
#cmakedefine GINT_STATIC_GRAY
|
||||
|
@ -30,4 +68,16 @@
|
|||
enabled or disabled at runtime. */
|
||||
#cmakedefine GINT_KMALLOC_DEBUG
|
||||
|
||||
/* 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_HW_CP) && !GINT_FX9860G_G3A)
|
||||
|
||||
#endif /* GINT_CONFIG */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_CPU
|
||||
#define GINT_CPU
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
//---
|
||||
|
@ -107,6 +111,36 @@ void sleep_block(void);
|
|||
/* sleep_unblock(): Cancel a processor sleep block */
|
||||
void sleep_unblock(void);
|
||||
|
||||
//---
|
||||
// Interrupt-cancellable sleeps
|
||||
//
|
||||
// The sleep() function has the significant drawback of not synchronizing with
|
||||
// interrupts. Programs usually run [while(<interrupt not occurred>) sleep()],
|
||||
// which fails if the interrupt occurs between the time the condition is
|
||||
// checked and time the sleep instruction is executed.
|
||||
//
|
||||
// Interrupt-cancellable sleep is a software mechanism by which the interrupt
|
||||
// disables the sleep instruction itself (by replacing it with a nop), which
|
||||
// ensures that the CPU cannot go to sleep after the interrupt occurs.
|
||||
//---
|
||||
|
||||
/* cpu_csleep_t: A cancellable sleep function
|
||||
This object holds sleep code that can be disabled by an interrupt. The size
|
||||
and layout of this variable is dependent on some assembler code. This should
|
||||
be allocated on the stack, heap, or on-chip memory, because the data segment
|
||||
is not executable! */
|
||||
typedef GALIGNED(4) uint8_t cpu_csleep_t[20];
|
||||
|
||||
/* cpu_csleep_init(): Create an ICS function
|
||||
This function initializes the provided ICS routine. */
|
||||
void cpu_csleep_init(cpu_csleep_t *ics);
|
||||
|
||||
/* cpu_csleep(): Run the sleep function until the sleep is cancelled */
|
||||
void cpu_csleep(cpu_csleep_t *ics);
|
||||
|
||||
/* cpu_csleep_cancel(): Cancel the sleep function from within an interrupt */
|
||||
void cpu_csleep_cancel(cpu_csleep_t *ics);
|
||||
|
||||
//---
|
||||
// Configuration
|
||||
//---
|
||||
|
@ -117,4 +151,8 @@ void sleep_unblock(void);
|
|||
configure(), this is reset to 0. */
|
||||
void cpu_configure_VBR(uint32_t VBR);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_CPU */
|
||||
|
|
|
@ -10,12 +10,13 @@
|
|||
/* Objects from the gint's uninitialized BSS section */
|
||||
#define GBSS __attribute__((section(".gint.bss")))
|
||||
/* Additional sections that are only needed on SH3 */
|
||||
#define GRODATA3 __attribute__((section(".gint.rodata.sh3")))
|
||||
#define GDATA3 __attribute__((section(".gint.data.sh3")))
|
||||
#define GBSS3 __attribute__((section(".gint.bss.sh3")))
|
||||
/* Objects for the ILRAM, XRAM and YRAM regions */
|
||||
#define GILRAM __attribute__((section(".ilram")))
|
||||
#define GXRAM __attribute__((section(".xram")))
|
||||
#define GYRAM __attribute__((section(".yram")))
|
||||
#define GXRAM __attribute__((section(".xyram")))
|
||||
#define GYRAM __attribute__((section(".xyram")))
|
||||
|
||||
/* Unused parameters or variables */
|
||||
#define GUNUSED __attribute__((unused))
|
||||
|
@ -33,6 +34,9 @@
|
|||
/* Transparent unions */
|
||||
#define GTRANSPARENT __attribute__((transparent_union))
|
||||
|
||||
/* Functions and globals that are visible through whole-program optimization */
|
||||
#define GVISIBLE __attribute__((externally_visible))
|
||||
|
||||
/* Weak symbols */
|
||||
#define GWEAK __attribute__((weak))
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
#ifndef GINT_DEFS_CALL
|
||||
#define GINT_DEFS_CALL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* gint_call_arg_t: All types of arguments allowed in an indirect call
|
||||
|
||||
Because a function call cannot be easily pieced together, there are
|
||||
|
@ -111,28 +115,59 @@ typedef struct {
|
|||
* error: cast to union type from type not present in union
|
||||
-> This is emitted if you pass a parameter of an invalid type. */
|
||||
#define GINT_CALL(func, ...) \
|
||||
((gint_call_t){ .function = func, .args = { \
|
||||
((gint_call_t){ .function = (void *)func, .args = { \
|
||||
__VA_OPT__(GINT_CALL_ARGS1(__VA_ARGS__)) \
|
||||
}})
|
||||
#define GINT_CALL_ARGS1(a1, ...) \
|
||||
(gint_call_arg_t)(a1), __VA_OPT__(GINT_CALL_ARGS2(__VA_ARGS__))
|
||||
GINT_CALL_ARG(a1), __VA_OPT__(GINT_CALL_ARGS2(__VA_ARGS__))
|
||||
#define GINT_CALL_ARGS2(a2, ...) \
|
||||
(gint_call_arg_t)(a2), __VA_OPT__(GINT_CALL_ARGS3(__VA_ARGS__))
|
||||
GINT_CALL_ARG(a2), __VA_OPT__(GINT_CALL_ARGS3(__VA_ARGS__))
|
||||
#define GINT_CALL_ARGS3(a3, ...) \
|
||||
(gint_call_arg_t)(a3), __VA_OPT__(GINT_CALL_ARGS4(__VA_ARGS__))
|
||||
GINT_CALL_ARG(a3), __VA_OPT__(GINT_CALL_ARGS4(__VA_ARGS__))
|
||||
#define GINT_CALL_ARGS4(a4, ...) \
|
||||
({ __VA_OPT__(_Static_assert(0, \
|
||||
"GINT_CALL: too many arguments (maximum 4)");) \
|
||||
(gint_call_arg_t)(a4); })
|
||||
GINT_CALL_ARG(a4); })
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* Kind of ugly but I don't have super cool templated logic right now.
|
||||
TODO: Allow any 4-byte type using C++ magic. */
|
||||
#define GINT_CALL_ARG(expr) ({ \
|
||||
auto __arg = (expr); \
|
||||
(*reinterpret_cast<gint_call_arg_t *>(&__arg)); \
|
||||
})
|
||||
#else
|
||||
/* GCC extension: Cast to union */
|
||||
#define GINT_CALL_ARG(expr) (gint_call_arg_t)(expr)
|
||||
#endif
|
||||
|
||||
/* 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)
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
int (*f)(int r4, int r5, int r6, int r7) = (decltype(f))cb.function;
|
||||
#else
|
||||
int (*f)(int r4, int r5, int r6, int r7) = cb.function;
|
||||
return f(cb.args[0].i, cb.args[1].i, cb.args[2].i, cb.args[3].i);
|
||||
#endif
|
||||
|
||||
gint_call_arg_t *args = cb.args;
|
||||
return f ? f(args[0].i, args[1].i, args[2].i, args[3].i) : -1;
|
||||
}
|
||||
|
||||
//---
|
||||
|
@ -195,4 +230,8 @@ static GINLINE gint_call_t GINT_CALL_INC_STOP(int volatile *pointer)
|
|||
return GINT_CALL(GINT_CALL_INC_STOP_function, pointer);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_DEFS_CALL */
|
||||
|
|
36
include/gint/defs/timeout.h
Normal file
36
include/gint/defs/timeout.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
//---
|
||||
// gint:defs:timeout - RTC-based timeouts
|
||||
//
|
||||
// This header provides an interface for simplistic timers used for timeout
|
||||
// waiting. Currently they are based on the RTC with a resolution of 1/128 s.
|
||||
//---
|
||||
|
||||
#ifndef GINT_DEFS_TIMEOUT
|
||||
#define GINT_DEFS_TIMEOUT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Object holding information about a timeout (specifically, when it expires).
|
||||
TODO: timeout: consider using a struct timespec with clock_gettime()? */
|
||||
typedef clock_t timeout_t;
|
||||
|
||||
static inline timeout_t timeout_make_ms(int ms)
|
||||
{
|
||||
return clock() + (int64_t)ms * CLOCKS_PER_SEC / 1000;
|
||||
}
|
||||
|
||||
static inline bool timeout_elapsed(timeout_t const *t)
|
||||
{
|
||||
return t && clock() >= *t;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_DEFS_TIMEOUT */
|
|
@ -13,13 +13,27 @@
|
|||
#include <stdint.h>
|
||||
/* For human-readable boolean types */
|
||||
#include <stdbool.h>
|
||||
/* Common system types: ssize_t, off_t, etc. */
|
||||
#include <sys/types.h>
|
||||
/* For va_list */
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Fixed-width types for bit fields are quite meaningless */
|
||||
typedef unsigned int uint;
|
||||
/* Signed size_t */
|
||||
typedef signed int ssize_t;
|
||||
/* Offset in file (used in standard functions) */
|
||||
typedef unsigned int off_t;
|
||||
|
||||
//---
|
||||
// Short types
|
||||
//---
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
|
||||
//---
|
||||
// Structure elements
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
#define GAUTOTYPE __auto_type
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <algorithm>
|
||||
using std::min;
|
||||
using std::max;
|
||||
#else
|
||||
/* min(), max() (without double evaluation) */
|
||||
#define min(a, b) ({ \
|
||||
GAUTOTYPE _a = (a); \
|
||||
|
@ -25,6 +30,7 @@
|
|||
GAUTOTYPE _b = (b); \
|
||||
_a > _b ? _a : _b; \
|
||||
})
|
||||
#endif
|
||||
|
||||
/* sgn() (without double evaluation) */
|
||||
#define sgn(s) ({ \
|
||||
|
|
|
@ -1,23 +1,37 @@
|
|||
//---
|
||||
// gint:display-cg - fxcg50 rendering functions
|
||||
// gint:display-cg - fx-CG 50 rendering functions
|
||||
//
|
||||
// This module covers all 16-bit opaque rendering functions. For
|
||||
// gamma-related functions, color composition, check out a color library.
|
||||
// This module covers rendering functions specific to the fx-CG 50. In addition
|
||||
// to triple-buffering management, this mainly includes image manipulation
|
||||
// tools as well as the very versatile dimage_effect() and dsubimage_effect()
|
||||
// functions that support high-performance image rendering with a number of
|
||||
// geometric and color effects.
|
||||
//
|
||||
// All the functions in this module work on a 396x224 resolution - gint
|
||||
// lets you use the full surface!
|
||||
// The fx-CG OS restricts the display to a 384x216 rectangle rougly around the
|
||||
// center, leaving margins on three sides. However, gint configures the display
|
||||
// to use the full 396x224 surface!
|
||||
//---
|
||||
|
||||
#ifndef GINT_DISPLAY_CG
|
||||
#define GINT_DISPLAY_CG
|
||||
|
||||
#ifdef FXCG50
|
||||
#if GINT_RENDER_RGB
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/image.h>
|
||||
|
||||
/* Dimensions of the VRAM */
|
||||
#if GINT_HW_CG
|
||||
#define DWIDTH 396
|
||||
#define DHEIGHT 224
|
||||
#elif GINT_HW_CP
|
||||
#define DWIDTH 320
|
||||
#define DHEIGHT 528
|
||||
#endif
|
||||
|
||||
/* gint VRAM address. This value must always point to a 32-aligned buffer of
|
||||
size 177408. Any function can use it freely to perform rendering or store
|
||||
|
@ -53,76 +67,81 @@ enum {
|
|||
green is not used). */
|
||||
#define C_RGB(r,g,b) (((r) << 11) | ((g) << 6) | (b))
|
||||
|
||||
//---
|
||||
// Image rendering (bopti)
|
||||
//---
|
||||
/* See <gint/image.h> for the details on image manipulation. */
|
||||
typedef image_t bopti_image_t;
|
||||
|
||||
/* bopti_image_t: Image files encoded for bopti
|
||||
This format is created by the fxSDK's [fxconv] tool from standard images. */
|
||||
typedef struct
|
||||
{
|
||||
/* Color profile (type of palette), could be extended into a bit field
|
||||
later on */
|
||||
uint16_t profile;
|
||||
|
||||
/* Color code assigned to transparent pixels (unused in 16-bit) */
|
||||
uint16_t alpha;
|
||||
|
||||
/* Full width and height, in pixels */
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
|
||||
/* Color palette:
|
||||
* 16-bit and 16-bit alpha: none
|
||||
* 8-bit: 256 colors (total 512 bytes)
|
||||
* 4-bit: 16 colors (total 32 bytes)
|
||||
Then raw pixel data in row-major order. */
|
||||
uint16_t data[];
|
||||
|
||||
} GPACKED(4) bopti_image_t;
|
||||
|
||||
/* Old alias to image_t, now deprecated because of libimg */
|
||||
typedef bopti_image_t image_t __attribute__((deprecated(
|
||||
"image_t has been renamed to bopti_image_t")));
|
||||
|
||||
//---
|
||||
// Video RAM management
|
||||
//---
|
||||
|
||||
/* dsetvram() - Control video RAM address and triple buffering
|
||||
/* dsetvram(): Control video RAM address and triple buffering
|
||||
|
||||
Normal rendering under gint uses double-buffering: there is one image
|
||||
displayed on the screen and one in memory, in a region called the video RAM
|
||||
(VRAM). The application draws frames in the VRAM then sends them to the
|
||||
screen only when they are finished, using dupdate().
|
||||
|
||||
On fxcg50, the performance bottleneck is almost always the graphical
|
||||
rendering (especially in games) because the high amount of data, 173 kB per
|
||||
frame in full-resolution, makes graphics manipulation computationally
|
||||
expensive. The transfer also takes about 10 ms in itself.
|
||||
On fx-CG, sending frames with dupdate() is a common bottleneck because it
|
||||
takes about 11 ms. Fortunately, while the DMA is sending the frame to the
|
||||
display, the CPU is available to do work in parallel. This function sets up
|
||||
triple buffering (ie. a second VRAM) so that the CPU can start working on
|
||||
the next frame while the DMA is sending the current one.
|
||||
|
||||
Since gint transfers data to the screen using the DMA, it is possible to run
|
||||
the application while the finished frame is being transferred. However,
|
||||
writing to the VRAM during this period will cause display artifacts since
|
||||
the VRAM it is still being read by the DMA.
|
||||
However, experience shows minimal performance improvements, because writing
|
||||
to main RAM does not parallelize with DMA transfers. Since gint 2.8, this
|
||||
is no longer the default, and the memory for the extra VRAM is instead
|
||||
available via malloc().
|
||||
|
||||
The solution to this is to use triple-buffering with the display and two
|
||||
VRAMs that are alternately being written to while the other is being
|
||||
transferred. The VRAM switching is handled by dupdate() and is activated
|
||||
whenever two VRAMs are configured.
|
||||
|
||||
By default gint uses triple buffering with two VRAMs in the system stack.
|
||||
|
||||
VRAMs must be contiguous, 32-aligned, (2*396*224)-byte buffers.
|
||||
VRAMs must be contiguous, 32-aligned, (2*396*224)-byte buffers with 32 bytes
|
||||
of extra data on each side (ie. 32 bytes into a 32-aligned buffer of size
|
||||
177472).
|
||||
|
||||
@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
|
||||
Returns the VRAM buffer addresses used to render on fx-CG 50. */
|
||||
void dgetvram(uint16_t **main, uint16_t **secondary);
|
||||
|
||||
#endif /* FXCG50 */
|
||||
|
||||
//---
|
||||
// VRAM backup
|
||||
// On the fx-CP gint backs up the VRAM when loading and restores it when
|
||||
// leaving. While this is a transparent mechanism, the following parts of the
|
||||
// implementation are exposed at the internal API level.
|
||||
//---
|
||||
|
||||
/* Encode the VRAM contents between [in_start] and [in_end] at [output]. While
|
||||
[*in_end] is excluded from the encoding, it will be modified temporarily to
|
||||
serve as bounds check, so it must not be accessed asynchronously during the
|
||||
encoding. The size of the output is not known but is at most the distance
|
||||
between in_end and in_start in bytes. Setting output = in_start to compress
|
||||
in-place is supported. Returns the end pointer after encoding. */
|
||||
uint8_t *gint_vrambackup_encode(
|
||||
uint8_t *output, uint16_t *in_start, uint16_t *in_end);
|
||||
|
||||
/* Predefine palette based on the GUI at the Hollyhock loading screen. Contains
|
||||
109 entries plus a 110th dummy entry used internally as bounds check. */
|
||||
extern uint16_t gint_vrambackup_palette[110];
|
||||
|
||||
/* Get the pointer to the encoded VRAM backup created at load time. If [size]
|
||||
is not NULL, sets the size in [*size]. The pointer is heap allocated and
|
||||
remains owned by gint. */
|
||||
void *gint_vrambackup_get(int *size);
|
||||
|
||||
/* Decode the load-time VRAM backup back to VRAM. */
|
||||
void gint_vrambackup_show(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_RENDER_RGB */
|
||||
|
||||
#endif /* GINT_DISPLAY_CG */
|
||||
|
|
|
@ -9,7 +9,11 @@
|
|||
#ifndef GINT_DISPLAY_FX
|
||||
#define GINT_DISPLAY_FX
|
||||
|
||||
#ifdef FX9860G
|
||||
#if GINT_RENDER_MONO
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
|
@ -79,10 +83,33 @@ typedef struct
|
|||
uint height :12;
|
||||
|
||||
/* Raw layer data */
|
||||
uint8_t data[];
|
||||
uint8_t *data;
|
||||
|
||||
} GPACKED(4) bopti_image_t;
|
||||
|
||||
#endif /* FX9860G */
|
||||
/* 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 /* GINT_DISPLAY_FX */
|
||||
|
|
|
@ -9,21 +9,25 @@
|
|||
#ifndef GINT_DISPLAY
|
||||
#define GINT_DISPLAY
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#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. */
|
||||
|
||||
#ifdef FX9860G
|
||||
#if GINT_RENDER_MONO
|
||||
#include <gint/display-fx.h>
|
||||
#endif
|
||||
|
||||
#ifdef FXCG50
|
||||
#if GINT_RENDER_RGB
|
||||
#include <gint/display-cg.h>
|
||||
#endif
|
||||
|
||||
/* TODO: dinfo() or similar */
|
||||
|
||||
//---
|
||||
// Video RAM management
|
||||
//---
|
||||
|
@ -58,6 +62,50 @@
|
|||
fx-CG 50: 11 ms */
|
||||
void dupdate(void);
|
||||
|
||||
/* dupdate_set_hook(): Define a function to be called after each dupdate()
|
||||
|
||||
This functions configures the update hook, which is called after each
|
||||
dupdate() has sent VRAM to the display (but before VRAMs are switched when
|
||||
triple-buffering is used on fx-CG 50).
|
||||
|
||||
The hook is mostly useful to send a copy of the frame to another medium,
|
||||
typically through a USB connection to a projector-style application. See
|
||||
usb_fxlink_videocapture() in <gint/usb-ff-bulk.h> for an example.
|
||||
|
||||
The function is an indirect call; create one with the GINT_CALL() macro from
|
||||
<gint/defs/call.h>. Pass GINT_CALL_NULL to disable the feature.
|
||||
|
||||
@function Indirect call to perform after each dupdate(). */
|
||||
void dupdate_set_hook(gint_call_t function);
|
||||
|
||||
/* dupdate_get_hook(): Get a copy of the dupdate() hook */
|
||||
gint_call_t dupdate_get_hook(void);
|
||||
|
||||
//---
|
||||
// Rendering mode control
|
||||
//---
|
||||
|
||||
/* dmode: Rendering mode settings
|
||||
|
||||
This structure indicates the current window settings. Rendering is limited
|
||||
to the rectangle spanning from (left,top) included, to (right,bottom)
|
||||
excluded. The default is from (0,0) to (DWIDTH,DHEIGHT). */
|
||||
struct dwindow {
|
||||
int left, top;
|
||||
int right, bottom;
|
||||
};
|
||||
extern struct dwindow dwindow;
|
||||
|
||||
/* dwindow_set(): Set the rendering window
|
||||
|
||||
This function changes [dwindow] settings to limit rendering to a sub-surface
|
||||
of the VRAM. Note that this doesn't change the coordinate system; the pixel
|
||||
at (DWIDTH/2, DHEIGHT/2) is always in the middle of the screen regardless of
|
||||
the window setting. However, it might be masked out by the window.
|
||||
|
||||
Returns the old dwindow settings (if it needs to be restored later). */
|
||||
struct dwindow dwindow_set(struct dwindow new_mode);
|
||||
|
||||
//---
|
||||
// Area rendering functions
|
||||
//---
|
||||
|
@ -127,6 +175,11 @@ void drect_border(int x1, int y1, int x2, int y2,
|
|||
*: When the gray engine is on, see dgray(). */
|
||||
void dpixel(int x, int y, int color);
|
||||
|
||||
/* dgetpixel(): Get a pixel's color
|
||||
Returns the current color of any pixel in the VRAM. This function ignores
|
||||
the rendering window. Returns -1 if (x,y) is out of bounds. */
|
||||
int dgetpixel(int x, int y);
|
||||
|
||||
/* dline(): Render a straight line
|
||||
|
||||
This function draws a line using a Bresenham-style algorithm. Please note
|
||||
|
@ -160,6 +213,53 @@ 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)
|
||||
//---
|
||||
|
@ -361,6 +461,28 @@ 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)
|
||||
//---
|
||||
|
@ -398,4 +520,8 @@ enum {
|
|||
void dsubimage(int x, int y, bopti_image_t const *image, int left, int top,
|
||||
int width, int height, int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_DISPLAY */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_DMA
|
||||
#define GINT_DMA
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/defs/call.h>
|
||||
|
||||
|
@ -117,4 +121,8 @@ void *dma_memset(void *dst, uint32_t pattern, size_t size);
|
|||
void *dma_memcpy(void * __restrict dst, const void * __restrict src,
|
||||
size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_DMA */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_DRIVERS
|
||||
#define GINT_DRIVERS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
|
@ -263,7 +267,7 @@ typedef void **gint_world_t;
|
|||
the section name and the linker then sorts by name. If your driver has a
|
||||
level lower than 10, you must add a leading 0. */
|
||||
#define GINT_DECLARE_DRIVER(level, name) \
|
||||
GSECTION(".gint.drivers." #level) extern gint_driver_t name;
|
||||
GSECTION(".gint.drivers." #level) GVISIBLE extern gint_driver_t name;
|
||||
|
||||
//---
|
||||
// Internal driver control
|
||||
|
@ -300,4 +304,8 @@ void gint_world_switch_in(gint_world_t world_os, gint_world_t world_addin);
|
|||
/* Switch from a gint-managed world to the OS world */
|
||||
void gint_world_switch_out(gint_world_t world_addin, gint_world_t world_os);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_DRIVERS */
|
||||
|
|
293
include/gint/drivers/asyncio.h
Normal file
293
include/gint/drivers/asyncio.h
Normal file
|
@ -0,0 +1,293 @@
|
|||
//---
|
||||
// gint:usb:asyncio - Asynchronous I/O common definitions
|
||||
//---
|
||||
|
||||
#ifndef GINT_USB_ASYNCIO
|
||||
#define GINT_USB_ASYNCIO
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/defs/call.h>
|
||||
|
||||
/* Data tracking the progress of a multi-part multi-round async I/O operation.
|
||||
|
||||
* Writes are multi-part because they are constructed over several calls to
|
||||
write(2) followed by a "commit" with fynsc(2). They are additionally
|
||||
multi-round because each call to write(2) requires mutiple rounds of
|
||||
hardware communication when the hardware buffer is smaller than the data.
|
||||
|
||||
* Reads are multi-part because each transaction from the host requires
|
||||
several calls to read(2) ("user segments") if the user's buffer is shorter
|
||||
than the full transaction. In addition, reads are multi-round because a
|
||||
single read(2) to a user buffer takes multiple rounds of hardware
|
||||
communication ("hardware segments") whenever the user buffer is larger
|
||||
than the hardware buffer.
|
||||
|
||||
The process of performing such an I/O operation, as tracked by this
|
||||
structure and use throughout gint, is as follows.
|
||||
|
||||
## Writes
|
||||
|
||||
WRITING ---------------------.
|
||||
^ | | HW buffer
|
||||
Start writing | | Not full | full: start
|
||||
| | | transmission
|
||||
write(2) | v v
|
||||
--> IDLE ------------------> PENDING <------------- FLYING-WRITE
|
||||
^ ^ | DONE interrupt
|
||||
| DONE write(2) | |
|
||||
| interrupt | |
|
||||
| | | Data exhausted
|
||||
| fsync(2): start | v
|
||||
FLYING-SYNC <------------ IN-PROGRESS
|
||||
transmission
|
||||
|
||||
Initially the operation is in the IDLE state. When a write(2) is issued, it
|
||||
interacts with hardware then transitions to the IN-PROGRESS state, where it
|
||||
remains for any subsequent write(2). A fsync(2) will properly commit data to
|
||||
the hardware, finish the operation and return to the IDLE state.
|
||||
|
||||
The FLYING-WRITE and FLYING-SYNC states refer to waiting periods, after
|
||||
issuing hardware commands, during which hardware communicates. Usually an
|
||||
interrupt signals when hardware is ready to resume work.
|
||||
|
||||
Note that in a series of write(2), hardware is only instructed to send data
|
||||
once the hardware buffer is full. Therefore, a write(2) might transition
|
||||
directly from IDLE or IN-PROGRESS, to PENDING, to IN-PROGRESS, without
|
||||
actually communicating with the outside world.
|
||||
|
||||
An asynchronous write(2) might return to the caller as soon as writing is
|
||||
finished even if the operation is left in the FLYING-WRITE state, and it may
|
||||
even return while the operation is in the WRITING state if the DMA is used.
|
||||
|
||||
The invariants and meaning for each state are as follow:
|
||||
|
||||
State(s) Characterization Description
|
||||
============================================================================
|
||||
IDLE type == ASYNCIO_NONE No I/O operation
|
||||
----------------------------------------------------------------------------
|
||||
PENDING data_w && round_size == 0 Ready to write pending data
|
||||
----------------------------------------------------------------------------
|
||||
WRITING, round_size > 0 CPU/DMA write to HW in progress
|
||||
FLYING-WRITE HW transmission in progress
|
||||
----------------------------------------------------------------------------
|
||||
IN-PROGRESS !data_w && type == WRITE Waiting for write(2) or fsync(2)
|
||||
----------------------------------------------------------------------------
|
||||
FLYING-SYNC type == ASYNCIO_SYNC HW commit in progress
|
||||
============================================================================
|
||||
|
||||
The series of asyncio_op function calls for a write is as follows:
|
||||
|
||||
transaction ::= write* fsync
|
||||
write ::= asyncio_op_start_write round+ asyncio_op_finish_write
|
||||
round ::= asyncio_op_start_write_round asyncio_op_finish_write_round
|
||||
fsync ::= asyncio_op_start_sync asyncio_op_finish_sync
|
||||
|
||||
Each write(2) (with a single user-provided buffer) is split into multiple
|
||||
rounds that each fill the (small) hardware buffer. More writes can follow
|
||||
until an fynsc(2) commits the pipe.
|
||||
|
||||
## Reads
|
||||
|
||||
IN interrupt
|
||||
--> IDLE-EMPTY --------------> IDLE-READY
|
||||
| \ read(2) | ^
|
||||
read(2) | \ Transaction | | User buffer
|
||||
| \ exhausted* | | filled
|
||||
| '----<----------. | |
|
||||
| \ | |
|
||||
| IN interrupt \ | |
|
||||
v .--------->--------. \ v | .---. Read from
|
||||
WAITING READING v hardware
|
||||
'---------<--------' '---'
|
||||
HW buffer exhausted with
|
||||
user buffer not full
|
||||
|
||||
On this diagram, the right side indicates the presence of data to read from
|
||||
hardware while the bottom side indicates a read(2) request by the user.
|
||||
Notice the diagonal arrow back to IDLE-EMPTY insteaf of WAITING, which
|
||||
highlights that read(2) will always return at the end of a transaction even
|
||||
if the user-provided buffer is not full (to avoid waiting).
|
||||
|
||||
A read(2) request (a "user segment") might consume several full hardware
|
||||
buffers ("hardware segments") if the user buffer is large, thus looping
|
||||
repeatedly between WAITING and READING. Conversely, each hardware segment
|
||||
might fulfill many read(2) requests if the user buffer is small, thus
|
||||
looping between IDLE-READY and READING.
|
||||
|
||||
* Note that if the transaction finishes right as the user buffer fills up,
|
||||
we return to IDLE-READY and the next call to read(2) will successfully read
|
||||
0 bytes and transition back to IDLE-EMPTY. This allows the user to read the
|
||||
entire transaction by reading data until they get fewer bytes than requested
|
||||
without running the risk of blocking on the next transaction.
|
||||
|
||||
The invariants and meaning for each state are as follow. The right side
|
||||
(presence of a hardware segment) is indicated by `buffer_used >= 0`, while
|
||||
the bottom side (presence of a read(2) request) is indicated by `size > 0`.
|
||||
As an exception, IDLE-EMPTY uses `buffer_used == 0` so that the default
|
||||
zero-initialization of transfer data is sufficient.
|
||||
|
||||
State Invariant characterization Description
|
||||
============================================================================
|
||||
IDLE-EMPTY type == ASYNCIO_NONE No I/O operation, the pipe is
|
||||
&& buffer_used == 0 idle with no request and no
|
||||
&& size == 0 hardware segment (but we might
|
||||
&& round_size == 0 still be mid-transaction)
|
||||
----------------------------------------------------------------------------
|
||||
IDLE-READY type == ASYNCIO_READ There is a hardware segment not
|
||||
&& buffer_used >= 0 marked as complete, but no
|
||||
&& size == 0 read(2) request to consume it
|
||||
&& round_size == 0
|
||||
----------------------------------------------------------------------------
|
||||
WAITING type == ASYNCIO_READ There is a read(2) request but
|
||||
&& buffer_used < 0 no hardware segment, and either
|
||||
&& size > 0 the request is new or the
|
||||
&& round_size == 0 transaction isn't exhausted
|
||||
----------------------------------------------------------------------------
|
||||
READING type == ASYNCIO_READ A read round in progress and
|
||||
&& buffer_used >= 0 either the read(2) request or
|
||||
&& size > 0 hardware segment will be
|
||||
&& round_size > 0 exhausted when it ends
|
||||
============================================================================
|
||||
|
||||
The series of asyncio_op function calls for a read is a bit more complicated
|
||||
because transactions are divided into two non-comparable sequences of
|
||||
segments: one for packets received by the hardware buffer (on BRDY), one for
|
||||
the data being copied to user buffers (on read(2)).
|
||||
|
||||
|<------ Transaction from the host (no size limit) ------>|
|
||||
|
||||
v BRDY v BRDY v BRDY v BRDY v BRDY
|
||||
+-----------+-----------+-----------+-----------+---------+
|
||||
| HW buffer | HW buffer | HW buffer | HW buffer | (short) | HW segments
|
||||
+-----------+------+----+-----------+-----------+---------+
|
||||
| R1 | R2 | R3 | R4 | R5 | R6 | Read rounds
|
||||
+-----------+------+----+-----------+-----------+---------+
|
||||
| User buffer #1 | User buffer #2 | (short) | User segments
|
||||
+------------------+----------------------------+---------+
|
||||
^ read(2) ^ read(2) ^ read(2)
|
||||
|
||||
Reads rounds are exactly the intersections between hardware segments and
|
||||
read(2) user segments.
|
||||
|
||||
States can be checked and transitioned with the API functions below. */
|
||||
|
||||
enum { ASYNCIO_NONE, ASYNCIO_READ, ASYNCIO_WRITE, ASYNCIO_SYNC };
|
||||
|
||||
typedef volatile struct
|
||||
{
|
||||
/* Type of I/O operation (NONE/WRITE/SYNC/READ) */
|
||||
uint8_t type;
|
||||
/* Whether the DMA should be used for hardware access */
|
||||
bool dma :1;
|
||||
/* For reading pipes, whether the transaction is expected to continue with
|
||||
another hardware segment after the current one */
|
||||
bool cont_r :1;
|
||||
/* For reading pipes, interrupt flag signaling an incoming hardware segment
|
||||
not yet added to the operation */
|
||||
bool interrupt_r :1;
|
||||
/* For reading pipes, whether the current read call should close the
|
||||
current hardware segment if all the data is read even if the read call
|
||||
is not partial */
|
||||
bool autoclose_r :1;
|
||||
/* Hardware resource being used for access (meaning depends on hardware).
|
||||
Usually, this is assigned for the duration of hardware transaction.
|
||||
This value is user-managed and not modified by asyncio_op functions. */
|
||||
uint8_t controller;
|
||||
|
||||
/* Number of bytes in short buffer (0..3) */
|
||||
uint8_t shbuf_size;
|
||||
/* Short buffer */
|
||||
uint32_t shbuf;
|
||||
|
||||
/* Size of data currently in the hardware buffer */
|
||||
int16_t buffer_used;
|
||||
/* Size of data being read/written in the current round (which may itself
|
||||
be asynchronous if it's using the DMA) */
|
||||
uint16_t round_size;
|
||||
|
||||
union {
|
||||
/* Address of data to transfer, incremented gradually [write] */
|
||||
void const *data_w;
|
||||
/* Address of buffer to store data to, incremented gradually [read] */
|
||||
void *data_r;
|
||||
};
|
||||
/* Size of data left to transfer to satisfy the complete request */
|
||||
int size;
|
||||
/* For reading operations, pointer to total amount of transferred data */
|
||||
int *realized_size_r;
|
||||
/* Callback at the end of the current write, final commit, or read */
|
||||
gint_call_t callback;
|
||||
|
||||
} asyncio_op_t;
|
||||
|
||||
//---
|
||||
// Initialization and query functions
|
||||
//---
|
||||
|
||||
/* asyncio_op_clear(): Initialize/clear the storage for an I/O operation */
|
||||
void asyncio_op_clear(asyncio_op_t *op);
|
||||
|
||||
/* asyncio_op_busy(): Check whether the transfer is busy for syscalls
|
||||
|
||||
This function checks whether the transfer is in a state where the CPU is
|
||||
busy wrt. starting a new syscall, ie. read(2), write(2) or fsync(2). Returns
|
||||
true if the CPU is busy and the call has to wait, false if the call can
|
||||
proceed immediately. */
|
||||
bool asyncio_op_busy(asyncio_op_t const *op);
|
||||
|
||||
//---
|
||||
// I/O functions
|
||||
//---
|
||||
|
||||
/* Start/finish a write(2) call. */
|
||||
void asyncio_op_start_write(asyncio_op_t *op,
|
||||
void const *data, size_t size, bool use_dma, gint_call_t const *callback);
|
||||
void asyncio_op_finish_write(asyncio_op_t *op);
|
||||
|
||||
/* Start/finish a single-block write to hardware. */
|
||||
void asyncio_op_start_write_round(asyncio_op_t *op, size_t size);
|
||||
void asyncio_op_finish_write_round(asyncio_op_t *op);
|
||||
|
||||
/* Start an fsync(2) operation (after one or more writes) and finish it. */
|
||||
void asyncio_op_start_sync(asyncio_op_t *op, gint_call_t const *callback);
|
||||
void asyncio_op_finish_sync(asyncio_op_t *op);
|
||||
|
||||
/* Start a read(2) call. The call will finish automatically when the final
|
||||
round finishes. If `autoclose` is set, the current hardware segment will
|
||||
be marked as completed if the round reads it entirely, even if the request
|
||||
is fulfilled. */
|
||||
void asyncio_op_start_read(asyncio_op_t *op, void *data, size_t size,
|
||||
bool use_dma, int *realized_size, bool autoclose,
|
||||
gint_call_t const *callback);
|
||||
|
||||
/* Start a hardware segment. `cont` should be true if there will be another
|
||||
segment in the same transaction. The segment will finish automatically when
|
||||
it is completely consumed by a read round. */
|
||||
void asyncio_op_start_read_hwseg(asyncio_op_t *op, size_t size, bool cont);
|
||||
|
||||
bool asyncio_op_has_read_call(asyncio_op_t const *op);
|
||||
|
||||
bool asyncio_op_has_read_hwseg(asyncio_op_t const *op);
|
||||
|
||||
/* Start a single-block read from hardware. The requested size is automatically
|
||||
t->size, however the round may of course be smaller depending on how much
|
||||
data is available. Returns the round size. */
|
||||
int asyncio_op_start_read_round(asyncio_op_t *op);
|
||||
|
||||
enum {
|
||||
ASYNCIO_HWSEG_EXHAUSTED = 0x01,
|
||||
ASYNCIO_REQUEST_FINISHED = 0x02,
|
||||
ASYNCIO_TRANSACTION_EXHAUSTED = 0x04,
|
||||
};
|
||||
|
||||
/* Finish a single-block read from hardware. This function also finishes the
|
||||
current hardware segment and read call if appropriate, *except* that it
|
||||
doesn't invoke the read(2) callback. You should make a copy of it before
|
||||
calling and invoke it manually after. Returns a combination of the above
|
||||
flags indicating what finished along with the round. */
|
||||
int asyncio_op_finish_read_round(asyncio_op_t *op);
|
||||
|
||||
/* Cancel a read call. This keeps the hardware segment part intact. */
|
||||
void asyncio_op_cancel_read(asyncio_op_t *op);
|
||||
|
||||
#endif /* GINT_USB_ASYNCIO */
|
|
@ -7,6 +7,10 @@
|
|||
#ifndef GINT_DRIVERS_IOKBD
|
||||
#define GINT_DRIVERS_IOKBD
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
/* iokbd_scan() - scan ports A/B/M to generate 12 rows of key data
|
||||
|
@ -14,4 +18,8 @@
|
|||
@scan 12-byte buffer filled with row data */
|
||||
void iokbd_scan(uint8_t *scan);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_DRIVERS_IOKBD */
|
||||
|
|
|
@ -2,27 +2,19 @@
|
|||
// gint:keydev - Kernel's keyboard input devices
|
||||
//---
|
||||
|
||||
#include <gint/keyboard.h>
|
||||
|
||||
#ifndef GINT_KEYDEV
|
||||
#define GINT_KEYDEV
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/keyboard.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Size of the buffer event queue */
|
||||
#define KEYBOARD_QUEUE_SIZE 32
|
||||
|
||||
/* keydev_event_t: Change of state in a full row */
|
||||
typedef struct {
|
||||
/* Device time for the event */
|
||||
uint16_t time;
|
||||
/* Keys that changed state */
|
||||
uint8_t changed;
|
||||
/* Row number */
|
||||
uint8_t row :4;
|
||||
/* Type of change, either KEYEV_DOWN or KEYEV_UP */
|
||||
uint8_t kind :4;
|
||||
|
||||
} keydev_event_t;
|
||||
|
||||
/* Event transforms
|
||||
|
||||
Every keyboard input device has a built-in event stream editor that can
|
||||
|
@ -80,14 +72,26 @@ typedef struct {
|
|||
enum {
|
||||
/* Delayed SHIFT: Pressing then immediately releasing SHIFT when the
|
||||
keyboard is idle applies SHIFT to the next repeat streak. */
|
||||
KEYDEV_TR_DELAYED_SHIFT = 0x01,
|
||||
KEYDEV_TR_DELAYED_SHIFT = 0x01, /* = GETKEY_MOD_SHIFT */
|
||||
/* Delayed ALPHA: Idem with the ALPHA key */
|
||||
KEYDEV_TR_DELAYED_ALPHA = 0x02,
|
||||
KEYDEV_TR_DELAYED_ALPHA = 0x02, /* = GETKEY_MOD_ALPHA */
|
||||
/* Combination of the delayed modifiers */
|
||||
KEYDEV_TR_DELAYED_MODS = KEYDEV_TR_DELAYED_SHIFT
|
||||
| KEYDEV_TR_DELAYED_ALPHA,
|
||||
|
||||
/* Instant SHIFT: Each individual event of every repeat streak gets
|
||||
SHIFT applied if SHIFT is pressed at the time of the repeat. */
|
||||
KEYDEV_TR_INSTANT_SHIFT = 0x04,
|
||||
/* Instant ALPHA: Idem with the ALPHA key */
|
||||
KEYDEV_TR_INSTANT_ALPHA = 0x08,
|
||||
/* Combination of the instance modifiers */
|
||||
KEYDEV_TR_INSTANT_MODS = KEYDEV_TR_INSTANT_SHIFT
|
||||
| KEYDEV_TR_INSTANT_ALPHA,
|
||||
|
||||
/* Combination of all modifiers */
|
||||
KEYDEV_TR_ALL_MODS = KEYDEV_TR_DELAYED_MODS
|
||||
| KEYDEV_TR_INSTANT_MODS,
|
||||
|
||||
/* Repeats: Keys are repeated according to a repeat filter function */
|
||||
KEYDEV_TR_REPEATS = 0x10,
|
||||
/* Delete Modifiers: Remove modifier keys from generated events, which
|
||||
|
@ -97,6 +101,9 @@ enum {
|
|||
KEYDEV_TR_DELETE_RELEASES = 0x40,
|
||||
};
|
||||
|
||||
/* keydev_repeat_profile_t: Function deciding when and how to repeat keys. */
|
||||
typedef int (*keydev_repeat_profile_t)(int key, int duration, int count);
|
||||
|
||||
/* keydev_transform_t: Full specification for transforms on the event stream */
|
||||
typedef struct {
|
||||
/* List of enabled transforms. The order is cannot be changed because
|
||||
|
@ -118,10 +125,13 @@ typedef struct {
|
|||
that the precision of the delay is limited by the speed at which the
|
||||
keyboard is scanned, which is nowhere near microsecond-level. By
|
||||
default (128 Hz) the precision is about 7.8 ms. */
|
||||
int (*repeater)(int key, int duration, int count);
|
||||
keydev_repeat_profile_t repeater;
|
||||
|
||||
} GPACKEDENUM keydev_transform_t;
|
||||
|
||||
/* keydev_async_filter_t: Low-level asynchronous event filter. */
|
||||
typedef bool (*keydev_async_filter_t)(key_event_t event);
|
||||
|
||||
/* keydev_t: Keyboard device
|
||||
|
||||
This structure represents the state and settings of a keyboard device that
|
||||
|
@ -129,9 +139,9 @@ typedef struct {
|
|||
is useful for demo/replays that input events without the physical keyboard,
|
||||
and a couple of corner uses like control over USB.
|
||||
|
||||
The keyboard device has built-in event transformations, which modifty the
|
||||
The keyboard device has built-in event transformations, which modify the
|
||||
stream of events by adding information, combining modifiers, and removing
|
||||
undesired events. Because the event transformation reky on the current state
|
||||
undesired events. Because the event transformation rely on the current state
|
||||
of the keyboard, they must be run by the driver whenever events are read, so
|
||||
they are tied to the device.
|
||||
|
||||
|
@ -139,35 +149,27 @@ typedef struct {
|
|||
keydown() are shortcuts for keydev functions using the physical keyboard as
|
||||
their input. */
|
||||
typedef struct {
|
||||
/* Latest state of keys we are aware of. At every processing step, the
|
||||
different between this and the fresh information is queued and this
|
||||
is updated. state_now is identical to the real state obtained from
|
||||
the device unless earlier events failed to be queued, in which case
|
||||
a difference is maintained so they will be reconsidered later. */
|
||||
GALIGNED(4) uint8_t state_now[12];
|
||||
/* State of keys based on produced events. (state_queue + queue) is
|
||||
always identical to (state_now). When the queue is empty both states
|
||||
are the same. This is the user's view of the keyboard. */
|
||||
GALIGNED(4) uint8_t state_queue[12];
|
||||
/* Current device time in scanning-ticks */
|
||||
uint time;
|
||||
/* Last time when repeats were considered */
|
||||
uint time_repeats;
|
||||
|
||||
/* Event queue (circular buffer) */
|
||||
keydev_event_t queue[KEYBOARD_QUEUE_SIZE];
|
||||
/* Next event in queue, position after last event in queue */
|
||||
int8_t queue_next;
|
||||
int8_t queue_end;
|
||||
/* Number of events lost because of missing queue space */
|
||||
uint events_lost;
|
||||
/* Crafted events waiting to be picked up */
|
||||
key_event_t out[8];
|
||||
int out_size;
|
||||
uint16_t events_lost;
|
||||
|
||||
/* Event transforms */
|
||||
keydev_transform_t tr;
|
||||
|
||||
/* Asynchronous event filter. This is a low-level filter which is
|
||||
called when events are generated to process and filter them. It
|
||||
provides the unique ability to run keyboard-triggered code even if
|
||||
the program's main thread is busy, for instance running some sort of
|
||||
infinite loop. */
|
||||
keydev_async_filter_t async_filter;
|
||||
|
||||
// <Delayed Modifiers>
|
||||
|
||||
/* delayed_* is set when the delayed modifier is active (after a press/
|
||||
|
@ -181,14 +183,33 @@ typedef struct {
|
|||
// <Repeats>
|
||||
|
||||
/* Candidate key for repeats (or 0 if no key is candidate yet) */
|
||||
int rep_key;
|
||||
/* Number of repeats alreay sent */
|
||||
int rep_count;
|
||||
int16_t rep_key;
|
||||
/* Number of repeats already sent */
|
||||
int16_t rep_count;
|
||||
/* Time since key was first pressed (us) */
|
||||
int rep_time;
|
||||
/* Delay until next repeat, set by the repeat planner (us) */
|
||||
int rep_delay;
|
||||
|
||||
/* Latest state of keys we are aware of. At every processing step, the
|
||||
difference between this and the fresh information is queued and this
|
||||
is updated. state_now is identical to the real state obtained from
|
||||
the device unless earlier events failed to be queued, in which case
|
||||
a difference is maintained so they will be reconsidered later. */
|
||||
GALIGNED(4) uint8_t state_now[12];
|
||||
/* State of keys based on produced events. (state_queue + queue) is
|
||||
always identical to (state_now). When the queue is empty both states
|
||||
are the same. This is the user's view of the keyboard. */
|
||||
GALIGNED(4) uint8_t state_queue[12];
|
||||
/* Event queue (circular buffer) */
|
||||
key_event_t queue[KEYBOARD_QUEUE_SIZE];
|
||||
|
||||
/* 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
|
||||
|
@ -214,6 +235,12 @@ void keydev_process_state(keydev_t *d, uint8_t state[12]);
|
|||
devices (such as demo replays) to feed in new events. */
|
||||
void keydev_process_key(keydev_t *d, int keycode, bool state);
|
||||
|
||||
/* keydev_repeat_event(): Generate a repeat event if applicable
|
||||
At the end of every scan tick, this source will generate a repeat event if
|
||||
the repeat transform is enabled and the conditions for a repeat are
|
||||
satisfied. */
|
||||
key_event_t keydev_repeat_event(keydev_t *d);
|
||||
|
||||
/* keydev_tick(): Prepare the next tick
|
||||
This function maintains time trackers in the device and should be called in
|
||||
each frame after the scanning is finished and the keydev_process_*()
|
||||
|
@ -227,24 +254,22 @@ void keydev_tick(keydev_t *d, uint us);
|
|||
|
||||
/* keydev_unqueue_event(): Retrieve the next keyboard event in queue
|
||||
|
||||
This source provides the queued KEYEV_UP and KEYEV_DOWN events generated
|
||||
from the regular scans in chronological order. It does not generate the
|
||||
KEYEV_HOLD events though, keyev_repeat_event() must be used to obtain these
|
||||
at the end of every tick. */
|
||||
This source provides the queued KEYEV_UP, KEYEV_DOWN and KEYEV_HOLD events
|
||||
generated from the regular scans in chronological order. It does not apply
|
||||
transforms; to do this, use keydev_read(). */
|
||||
key_event_t keydev_unqueue_event(keydev_t *d);
|
||||
|
||||
/* keydev_repeat_event(): Generate a repeat event if applicable
|
||||
|
||||
At the end of every scan tick (or later if the application is unable to keep
|
||||
up), this source will generate a repeat event if the repeat transform is
|
||||
enabled and the conditions for a repeat are satisfied. */
|
||||
key_event_t keydev_repeat_event(keydev_t *d);
|
||||
|
||||
/* keydev_idle(): Check if all keys are released
|
||||
A list of keys to ignore can be specified as variable arguments. The list
|
||||
must be terminated by a 0 keycode. */
|
||||
bool keydev_idle(keydev_t *d, ...);
|
||||
|
||||
/* keydev_async_filter(): Obtain current async filter */
|
||||
keydev_async_filter_t keydev_async_filter(keydev_t const *d);
|
||||
|
||||
/* keydev_set_async_filter(): Set low-level async filter */
|
||||
void keydev_set_async_filter(keydev_t *d, keydev_async_filter_t filter);
|
||||
|
||||
//---
|
||||
// High-level API to read from the device
|
||||
//---
|
||||
|
@ -252,13 +277,52 @@ bool keydev_idle(keydev_t *d, ...);
|
|||
/* 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);
|
||||
|
||||
/* keydev_set_transform(): Set transform parameters */
|
||||
void keydev_set_transform(keydev_t *d, keydev_transform_t tr);
|
||||
|
||||
/* keydev_read(): Retrieve the next transformed event */
|
||||
key_event_t keydev_read(keydev_t *d);
|
||||
/* keydev_set_standard_repeats(): Enable a simple repeater
|
||||
|
||||
This function changes the [repeater] member of the devices's transform. It
|
||||
loads the default repeat profile which applies one delay (in us) before the
|
||||
first repeat, and then a second, usually shorter delay, between subsequent
|
||||
repeats.
|
||||
|
||||
The unit of the argument is in microseconds, but the granularity of the
|
||||
delay is dependent on the keyboard scan frequency. In the default setting
|
||||
(128 Hz scans), the possible repeat delays are approximately 8 ms, 16 ms,
|
||||
23 ms, 31 ms. The system default is (500 ms, 125 ms). With the 128 Hz
|
||||
setting, this default is reached exactly without approximation. gint's
|
||||
default is (400 ms, 40 ms) for more reactivity.
|
||||
|
||||
Note: Due to a current API limitation, every input device uses the delays
|
||||
for the physical keyboard.
|
||||
|
||||
@first_us Delay between key press and first repeat (microseconds)
|
||||
@next_us Delay between subsequent repeats (microseconds) */
|
||||
void keydev_set_standard_repeats(keydev_t *d, int first_us, int next_us);
|
||||
|
||||
/* keydev_read(): Retrieve the next transformed event
|
||||
If there is no event, returns an event with type KEYEV_NONE, unless
|
||||
[wait=true], in which case waits for an event to occur or *timeout to
|
||||
become non-zero (if timeout is not NULL), whichever comes first. */
|
||||
key_event_t keydev_read(keydev_t *d, bool wait, volatile int *timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_KEYDEV */
|
||||
|
|
26
include/gint/drivers/r61523.h
Normal file
26
include/gint/drivers/r61523.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
//---
|
||||
// gint:drivers:r61523 - Reneses R61523 driver
|
||||
//
|
||||
// This driver is used to control the 16-bit color LCD of the fx-CP 400.
|
||||
//---
|
||||
|
||||
#ifndef GINT_DRIVERS_R61523
|
||||
#define GINT_DRIVERS_R61523
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
/* r61523_display(): Update the entire display (320x528) */
|
||||
void r61523_display(uint16_t *vram);
|
||||
|
||||
/* r61523_win_set(): Set the display window */
|
||||
void r61523_win_set(int x1, int x2, int y1, int y2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_DRIVERS_R61523 */
|
|
@ -8,6 +8,10 @@
|
|||
#ifndef GINT_DRIVERS_R61524
|
||||
#define GINT_DRIVERS_R61524
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
enum {
|
||||
|
@ -31,6 +35,46 @@ enum {
|
|||
@method Transfer method, see above */
|
||||
void r61524_display(uint16_t *vram, int start, int height, int method);
|
||||
|
||||
/* r61524_display_rect(): Send a rectangular section of VRAM to the display
|
||||
|
||||
This function updates the rectangle going from (xmin,ymin) to (xmax,ymax) in
|
||||
the VRAM to the display (both ends included). This can be faster than a full
|
||||
dupdate() or a striped r61524_display() depending on the situation. However,
|
||||
because the source VRAM is not contiguous, the transfer is only possible by
|
||||
CPU, so this is only interesting for small regions.
|
||||
|
||||
@vram Source VRAM with a stride of 396*2 bytes
|
||||
@xmin @xmax Horizontal range to be updated (both included)
|
||||
@ymin @ymax Vertical range to be updated (both included) */
|
||||
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
|
||||
the rectangle going from (xmin,ymin) to (xmax,ymax) (both included). This is
|
||||
the initial step of r61524_display(), which is normally followed by writing
|
||||
all the data to 0xb4000000.
|
||||
|
||||
In order to write with the DMA, it is necessary to write the full horizontal
|
||||
range and select ymin and ymax to be congruent to 0 and 3 modulo 4.
|
||||
|
||||
This function can be used to implement additional display driver update
|
||||
methods or alternate rendering pipelines. */
|
||||
void r61524_start_frame(int xmin, int xmax, int ymin, int ymax);
|
||||
|
||||
/* r162524_win_get() and r61524_win_set(): Manipulate the display window
|
||||
|
||||
These functions change the screen rectangle where data is shown. Normally
|
||||
|
@ -43,4 +87,20 @@ void r61524_display(uint16_t *vram, int start, int height, int method);
|
|||
void r61524_win_get(uint16_t *HSA, uint16_t *HEA, uint16_t *VSA,uint16_t *VEA);
|
||||
void r61524_win_set(uint16_t HSA, uint16_t HEA, uint16_t VSA, uint16_t VEA);
|
||||
|
||||
//---
|
||||
// Low-level functions
|
||||
//---
|
||||
|
||||
/* r61524_get(): Read the value of an R61524 register
|
||||
This is provided for testing and if you know what you're doing. */
|
||||
uint16_t r61524_get(int ID);
|
||||
|
||||
/* r61524_set(): Write the value of an R61524 register
|
||||
This is provided for testing and if you know what you're doing. */
|
||||
void r61524_set(int ID, uint16_t value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_DRIVERS_R61524 */
|
||||
|
|
|
@ -9,11 +9,18 @@
|
|||
#ifndef GINT_DRIVERS_STATES
|
||||
#define GINT_DRIVERS_STATES
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/config.h>
|
||||
#include <gint/mpu/dma.h>
|
||||
#include <gint/clock.h>
|
||||
|
||||
/* Clock Pulse Generator (see cpg/cpg.c) */
|
||||
typedef struct {
|
||||
uint32_t SSCGCR;
|
||||
struct cpg_overclock_setting speed;
|
||||
} cpg_state_t;
|
||||
|
||||
/* CPU (see cpu/cpu.c) */
|
||||
|
@ -21,6 +28,7 @@ typedef struct {
|
|||
uint32_t SR;
|
||||
uint32_t VBR;
|
||||
uint32_t CPUOPM;
|
||||
uint32_t rN_bank[8];
|
||||
} cpu_state_t;
|
||||
|
||||
/* Direct Memory Access controller (see dma/dma.c) */
|
||||
|
@ -82,13 +90,27 @@ typedef struct {
|
|||
typedef struct {
|
||||
/* Control and power-up. We don't save power-related registers from other
|
||||
modules nor UPONCR, because they must be changed to use the module */
|
||||
uint16_t SYSCFG, DVSTCTR, TESTMODE, REG_C2;
|
||||
/* FIFO configuration */
|
||||
uint16_t CFIFOSEL, D0FIFOSEL, D1FIFOSEL;
|
||||
uint16_t SYSCFG, BUSWAIT, DVSTCTR, SOFCFG, TESTMODE, REG_C2;
|
||||
/* Interrupt configuration */
|
||||
uint16_t INTENB0, BRDYENB, NRDYENB, BEMPENB, SOFCFG;
|
||||
/* Default Control Pipe (maybe not needed) */
|
||||
uint16_t DCPCFG, DCPMAXP, DCPCTR;
|
||||
uint16_t INTENB0, INTENB1, BRDYENB, NRDYENB, BEMPENB;
|
||||
/* Default Control Pipe */
|
||||
uint16_t DCPMAXP;
|
||||
|
||||
#ifdef GINT_USB_DEBUG
|
||||
/* Registers tracked read-only for state analysis and debugging */
|
||||
uint16_t SYSSTS, FRMNUM, UFRMNUM;
|
||||
uint16_t CFIFOSEL, D0FIFOSEL, D1FIFOSEL, CFIFOCTR, D0FIFOCTR, D1FIFOCTR;
|
||||
uint16_t INTSTS0, INTSTS1, BRDYSTS, NRDYSTS, BEMPSTS;
|
||||
uint16_t DCPCFG, DCPCTR;
|
||||
uint16_t USBADDR, USBREQ, USBVAL, USBINDX, USBLENG;
|
||||
uint16_t PIPESEL, PIPECFG[9], PIPEnCTR[9], PIPEBUF[9];
|
||||
/* Ignored: UPONCR, PIPEnMAXP, PIPEnPERI, PIPEnTRN, PIPEnTRE, DEVADDn */
|
||||
#endif
|
||||
|
||||
} usb_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_DRIVERS_STATES */
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
#ifndef GINT_DRIVERS_T6K11
|
||||
#define GINT_DRIVERS_T6K11
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
/* t6k11_display() - send vram data to the LCD device
|
||||
|
@ -51,4 +55,8 @@ void t6k11_contrast(int contrast);
|
|||
@setting Requested backlight setting */
|
||||
void t6k11_backlight(int setting);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_DRIVERS_T6K11 */
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#ifndef GINT_EXC
|
||||
#define GINT_EXC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -64,4 +68,8 @@ void gint_exc_catch(int (*handler)(uint32_t code));
|
|||
@instructions Number of instructions to skip (usually only one) */
|
||||
void gint_exc_skip(int instructions);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_EXC */
|
||||
|
|
107
include/gint/fs.h
Normal file
107
include/gint/fs.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
//---
|
||||
// gint:fs - Filesystem abstraction
|
||||
//---
|
||||
|
||||
#ifndef GINT_FS
|
||||
#define GINT_FS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Maximum number of file descriptors */
|
||||
#define FS_FD_MAX 16
|
||||
|
||||
/* fs_descriptor_type_t: Overloaded file descriptor functions
|
||||
|
||||
This structure provides the base functions for every type of file
|
||||
descriptor. The prototypes are standard, except that the first argument
|
||||
(int fd) is replaced by (void *data) which points to the custom data
|
||||
allocator for the descriptor. */
|
||||
typedef struct {
|
||||
/* See <unistd.h> for a description of these functions */
|
||||
ssize_t (*read)(void *data, void *buf, size_t size);
|
||||
ssize_t (*write)(void *data, void const *buf, size_t size);
|
||||
off_t (*lseek)(void *data, off_t offset, int whence);
|
||||
int (*close)(void *data);
|
||||
|
||||
} fs_descriptor_type_t;
|
||||
|
||||
/* fs_descriptor_t: File descriptor information
|
||||
This internal type describes the entries of the descriptor table. */
|
||||
typedef struct {
|
||||
/* Interface functions */
|
||||
fs_descriptor_type_t const *type;
|
||||
/* Custom data (can also be an integer cast to (void *)) */
|
||||
void *data;
|
||||
|
||||
} fs_descriptor_t;
|
||||
|
||||
/* fs_get_descriptor(): Get a file descriptor's data
|
||||
|
||||
This function is used internally in order to implement read(), write(), and
|
||||
other standard functions functions. It could be useful for other APIs that
|
||||
want to present their resources as file descriptors but still implement
|
||||
extra non-standard functions; this allows them to use the file descriptor as
|
||||
input and still access the custom data.
|
||||
|
||||
Returns NULL if there is no file descriptor with this number, in which case
|
||||
the caller probably needs to set errno = EBADF. */
|
||||
fs_descriptor_t const *fs_get_descriptor(int fd);
|
||||
|
||||
/* fs_create_descriptor(): Create a new file descriptor
|
||||
|
||||
This function is used in open() and its variants to allocate new file
|
||||
descriptors. The descriptor's data is created with a copy of the provided
|
||||
structure, which must include a non-NULL type attribute.
|
||||
|
||||
This function always returns the smallest file descriptor that is unused by
|
||||
the application and is not 0, 1 or 2; unless it runs out of file
|
||||
descriptors, in which case it returns -1 and the caller might want to set
|
||||
errno = ENFILE. */
|
||||
int fs_create_descriptor(fs_descriptor_t const *data);
|
||||
|
||||
/* fs_free_descriptor(): Close a file descriptor's slot
|
||||
|
||||
This function frees the specified file descriptor. It is automatically
|
||||
called by close() after the descriptor type's close() function, so there is
|
||||
normally no need to call this function directly. */
|
||||
void fs_free_descriptor(int fd);
|
||||
|
||||
/* open_generic(): Open a file descriptor using custom file functions
|
||||
|
||||
Opens a new file descriptor of the specified type with the provided user
|
||||
data. If reuse_fd < 0, a new file descriptor is allocated, otherwise the
|
||||
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);
|
||||
|
||||
/* fs_path_normalize(): Normalize a path to eliminate ., .. and redundant /
|
||||
|
||||
This function creates a copy of the specified path which is an absolute path
|
||||
with redundant / removed and . and .. components resolved. For instance:
|
||||
|
||||
"" -> "/"
|
||||
"/subfolder/./" -> "/subfolder"
|
||||
"/../subfolder/../subfolder" -> "/subfolder"
|
||||
"/../../x/y/../t" -> "/x/t"
|
||||
|
||||
The new string is created with malloc() and should be free()'d after use. */
|
||||
char *fs_path_normalize(char const *path);
|
||||
|
||||
/* fs_path_normalize_fc(): Normalize a path and translate it to FONTCHARACTER
|
||||
|
||||
This function is similar to fs_path_normalize(), but it creates a 16-bit
|
||||
string that starts with \\fls0\ rather than /, and can be used in direct
|
||||
calls to BFile. */
|
||||
uint16_t *fs_path_normalize_fc(char const *path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_FS */
|
105
include/gint/gdb.h
Normal file
105
include/gint/gdb.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
//---
|
||||
// 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 */
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_GINT
|
||||
#define GINT_GINT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/defs/call.h>
|
||||
#include <gint/config.h>
|
||||
|
@ -37,6 +41,13 @@ int gint_world_switch(gint_call_t function);
|
|||
__attribute__((deprecated("Use gint_world_switch() instead")))
|
||||
void gint_switch(void (*function)(void));
|
||||
|
||||
/* gint_world_sync(): Synchronize asynchronous drivers
|
||||
|
||||
This function waits for asynchronous tasks to complete by unbinding all
|
||||
drivers. This is useful in certain hardware operations while remaining in
|
||||
gint. */
|
||||
void gint_world_sync(void);
|
||||
|
||||
/* gint_osmenu(): Call the calculator's main menu
|
||||
|
||||
This function safely invokes the calculator's main menu with gint_switch().
|
||||
|
@ -48,18 +59,77 @@ void gint_switch(void (*function)(void));
|
|||
call to getkey(), but can also be called manually. */
|
||||
void gint_osmenu(void);
|
||||
|
||||
/* gint_osmenu_native(): Like gint_osmenu() without the world switch
|
||||
This is a replacement for gint_osmenu() which can be used when the current
|
||||
kernel is already the native OS kernel. */
|
||||
void gint_osmenu_native(void);
|
||||
|
||||
/* gint_setrestart(): Set whether to restart the add-in after exiting
|
||||
|
||||
An add-in that reaches the end of its code exits. On the calculator, except
|
||||
using OS-dependent settings, it cannot be started again unless another
|
||||
application is launched first.
|
||||
An add-in that returns from its main() function automatically exits to the
|
||||
OS' main menu. However, when this happens the OS does not allow the add-in
|
||||
to be restarted unless another add-in is launched first. (This is because
|
||||
the OS tries to *resume* the current add-in, which then proceeds to exit
|
||||
again immediately.)
|
||||
|
||||
This setting allows the add-in to restart by calling gint_osmenu() instead
|
||||
of exiting. This can give a proper illusion of restarting if used correctly.
|
||||
This function enables a gint trick where after main() returns the add-in
|
||||
will invoke the main menu with gint_osmenu() rather than exiting. If the
|
||||
add-in is selected again, gint will jump back to the entry point, creating
|
||||
the illusion that the add-in exited and was then restarted.
|
||||
|
||||
@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) {
|
||||
|
@ -85,8 +155,51 @@ 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
|
||||
add-in is unloaded, which is either when we exit from main() or when
|
||||
starting another application from the main menu. Crucially, this is only
|
||||
*after* selecting an application, not before opening the main menu. The
|
||||
quit handler is not invoked if the user re-enters the add-in.
|
||||
|
||||
This is based on the SetQuitHandler() syscall, and therefore the callback
|
||||
runs in the OS world by default. If [run_in_os_world] is set to false, a
|
||||
world switch will be performed to run the callback in the gint world.
|
||||
|
||||
TODO: Currently the quit handler is not called when exiting from main().
|
||||
TODO: Detail how this interacts with destructor functions!
|
||||
TODO: [run_in_os_world == false] is not honored yet (because unstable)
|
||||
|
||||
@call Callback to be performed when leaving add-in
|
||||
@run_in_os_world true to stay in OS world, false to use gint world */
|
||||
void gint_set_quit_handler(gint_call_t gcall, bool run_in_os_world);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_GINT */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_GRAY
|
||||
#define GINT_GRAY
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/display.h>
|
||||
|
||||
|
@ -148,4 +152,8 @@ void dgray_getvram(uint32_t **light, uint32_t **dark);
|
|||
These pointers can be used to make screen captures. */
|
||||
void dgray_getscreen(uint32_t **light, uint32_t **dark);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_GRAY */
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
#ifndef GINT_HARDWARE
|
||||
#define GINT_HARDWARE
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/config.h>
|
||||
|
||||
/* For compatibility with ASM, include the following bits only in C code */
|
||||
#ifndef CPP_ASM
|
||||
|
||||
|
@ -36,14 +42,14 @@ void hw_detect(void);
|
|||
dual-platform version for libraries.
|
||||
Warning: this macro is also used hardcoded in exch.s. */
|
||||
|
||||
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
|
||||
#define isSH3() (gint[HWMPU] & 1)
|
||||
#define isSH4() (!isSH3())
|
||||
#endif
|
||||
|
||||
#ifdef FXCG50
|
||||
#define isSH3() 0
|
||||
#define isSH4() 1
|
||||
#if GINT_HW_FX
|
||||
# define isSH3() (gint[HWMPU] & 1)
|
||||
# define isSH4() (!isSH3())
|
||||
# define isSlim() (gint[HWCALC] == HWCALC_FX9860G_SLIM)
|
||||
#elif GINT_HW_CG || GINT_HW_CP
|
||||
# define isSH3() 0
|
||||
# define isSH4() 1
|
||||
# define isSlim() 0
|
||||
#endif
|
||||
|
||||
/* This bit should be set in all data longwords except HWMPU, HWCPUVR, HWCPUPR
|
||||
|
@ -66,6 +72,7 @@ void hw_detect(void);
|
|||
#define HWKBD 8 /* Keyboard */
|
||||
#define HWKBDSF /* Deprecated: use keysc_scan_frequency() */
|
||||
#define HWDD /* Deprecated: use the T6K11/R61524 API */
|
||||
#define HWFS 11 /* Filesystem type */
|
||||
|
||||
/*
|
||||
** MPU type
|
||||
|
@ -100,6 +107,10 @@ void hw_detect(void);
|
|||
#define HWCALC_FXCG50 5
|
||||
/* fx-CG 50 emulator, hardcoded in kernel/inth.S */
|
||||
#define HWCALC_FXCG_MANAGER 6
|
||||
/* fx-9860G Slim, SH-3-based fx-9860G with hardware differences */
|
||||
#define HWCALC_FX9860G_SLIM 7
|
||||
/* fx-CP 400 */
|
||||
#define HWCALC_FXCP400 8
|
||||
|
||||
/*
|
||||
** Keyboard
|
||||
|
@ -114,4 +125,19 @@ void hw_detect(void);
|
|||
/* The keyboard uses a KEYSC-based scan method. This is only possible on SH4 */
|
||||
#define HWKBD_KSI 0x04
|
||||
|
||||
/*
|
||||
** Filesystem type
|
||||
*/
|
||||
|
||||
/* Unknown or no filesystem. */
|
||||
#define HWFS_NONE 0
|
||||
/* CASIO's in-house filesystem, now deprecated. */
|
||||
#define HWFS_CASIOWIN 1
|
||||
/* Wrapper around Kyoto Software Research's Fugue VFAT implementation. */
|
||||
#define HWFS_FUGUE 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_HARDWARE */
|
||||
|
|
846
include/gint/image.h
Normal file
846
include/gint/image.h
Normal file
|
@ -0,0 +1,846 @@
|
|||
//---
|
||||
// gint:image - Image manipulation and rendering
|
||||
//
|
||||
// Note: this module is currently only available on fx-CG.
|
||||
//
|
||||
// This header provides image manipulation functions. This mainly consists of a
|
||||
// reference-based image format, various access and modification functions, and
|
||||
// a number of high-performance transformations and rendering effects. If you
|
||||
// find yourself limited by rendering time, note that RAM writing speed is
|
||||
// often the bottleneck, and image rendering is much faster in Azur (which is
|
||||
// what the renderer was initially designed for).
|
||||
//
|
||||
// This module supports 3 bit depths: full-color 16-bit (RGB565), indexed 8-bit
|
||||
// (P8) and indexed 4-bit (P4). All three have an "alpha" variation where one
|
||||
// color is treated as transparent, leading to 6 total formats.
|
||||
//
|
||||
// The image renderers support so-called *dynamic effects*, which are image
|
||||
// transformations performed on-the-fly while rendering, without generating an
|
||||
// intermediate image. They comprise straightforward transformations that
|
||||
// achieve similar performance to straight rendering and can be combined to
|
||||
// some extent, which makes them reliable whenever applicable.
|
||||
//
|
||||
// For images of the RGB16 and P8 bit depths, the module supports a rich API
|
||||
// with image subsurfaces and a fairly large sets of geometric and color
|
||||
// transforms, including some in-place. P4 is not supported in most of these
|
||||
// functions because the dense bit packing is both impractical and slower for
|
||||
// these applications.
|
||||
//---
|
||||
|
||||
#ifndef GINT_IMAGE
|
||||
#define GINT_IMAGE
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/config.h>
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
struct dwindow;
|
||||
|
||||
//---
|
||||
// Image structures
|
||||
//---
|
||||
|
||||
/* Image formats. Note that transparency really only indicates the default
|
||||
rendering method, as a transparent background can always be added or removed
|
||||
by a dynamic effect on any image. */
|
||||
enum {
|
||||
IMAGE_RGB565 = 0, /* RGB565 without alpha */
|
||||
IMAGE_RGB565A = 1, /* RGB565 with one transparent color */
|
||||
IMAGE_P8_RGB565 = 4, /* 8-bit palette, all opaque colors */
|
||||
IMAGE_P8_RGB565A = 5, /* 8-bit with one transparent color */
|
||||
IMAGE_P4_RGB565 = 6, /* 4-bit palette, all opaque colors */
|
||||
IMAGE_P4_RGB565A = 3, /* 4-bit with one transparent color */
|
||||
|
||||
IMAGE_DEPRECATED_P8 = 2,
|
||||
};
|
||||
|
||||
/* Quick macros to compare formats by storage size */
|
||||
#define IMAGE_IS_RGB16(format) \
|
||||
((format) == IMAGE_RGB565 || (format) == IMAGE_RGB565A)
|
||||
#define IMAGE_IS_P8(format) \
|
||||
((format) == IMAGE_P8_RGB565 || (format) == IMAGE_P8_RGB565A)
|
||||
#define IMAGE_IS_P4(format) \
|
||||
((format) == IMAGE_P4_RGB565 || (format) == IMAGE_P4_RGB565A)
|
||||
/* Check whether image format has an alpha color */
|
||||
#define IMAGE_IS_ALPHA(format) \
|
||||
((format) == IMAGE_RGB565A || \
|
||||
(format) == IMAGE_P8_RGB565A || \
|
||||
(format) == IMAGE_P4_RGB565A)
|
||||
/* Check whether image format uses a palette */
|
||||
#define IMAGE_IS_INDEXED(format) \
|
||||
(IMAGE_IS_P8(format) || IMAGE_IS_P4(format))
|
||||
|
||||
/* Image flags. These are used for memory management, mostly. */
|
||||
enum {
|
||||
IMAGE_FLAGS_DATA_RO = 0x01, /* Data is read-only */
|
||||
IMAGE_FLAGS_PALETTE_RO = 0x02, /* Palette is read-only */
|
||||
IMAGE_FLAGS_DATA_ALLOC = 0x04, /* Data is malloc()'d */
|
||||
IMAGE_FLAGS_PALETTE_ALLOC = 0x08, /* Palette is malloc()'d */
|
||||
};
|
||||
|
||||
/* image_t: gint's native bitmap image format
|
||||
Images of this format can be created through this header's API but also by
|
||||
using the fxSDK's built-in image converters with fxconv. */
|
||||
typedef struct
|
||||
{
|
||||
/* Color format, one of the IMAGE_* values defined above */
|
||||
uint8_t format;
|
||||
/* Additional flags, a combination of IMAGE_FLAGS_* values */
|
||||
uint8_t flags;
|
||||
/* Number of colors in the palette; this includes alpha for transparent
|
||||
images, as alpha is always the first entry.
|
||||
RGB16: 0
|
||||
P8: Ranges between 1 and 256
|
||||
P4: 16 */
|
||||
int16_t color_count;
|
||||
/* Full width and height, in pixels */
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
/* Byte stride between lines */
|
||||
int stride;
|
||||
|
||||
/* Pixel data in row-major order, left to right.
|
||||
- RGB16: 2 bytes per entry, each row padded to 4 bytes for alignment.
|
||||
Each 2-byte value is an RGB565 color.
|
||||
- P8: 1 signed byte per entry. Each byte is a palette index shifted by
|
||||
128 (to access the color, use palette[<value>+128]).
|
||||
- P4: 4 bits per entry, each row padded to a full byte. Each entry is a
|
||||
direct palette index between 0 and 15. */
|
||||
void *data;
|
||||
|
||||
/* For P8 and P4, color palette. The number of entries allocated in the
|
||||
array is equal to the color_count attribute. */
|
||||
uint16_t *palette;
|
||||
|
||||
} GPACKED(4) image_t;
|
||||
|
||||
/* Dynamic effects: these transformations can be applied on images while
|
||||
rendering. Not all effects can be combined; unless specified otherwise:
|
||||
- HFLIP and VFLIP can both be added regardless of any other effect
|
||||
- At most one color effect can be applied */
|
||||
enum {
|
||||
/* Value 0x01 is reserved, because it is DIMAGE_NOCLIP, which although
|
||||
part of the old API still needs to be supported. */
|
||||
|
||||
/* [Any]: Skip clipping the command against the source image */
|
||||
IMAGE_NOCLIP_INPUT = 0x04,
|
||||
/* [Any]: Skip clipping the command against the output VRAM */
|
||||
IMAGE_NOCLIP_OUTPUT = 0x08,
|
||||
/* [Any]: Skip clipping both */
|
||||
IMAGE_NOCLIP = IMAGE_NOCLIP_INPUT | IMAGE_NOCLIP_OUTPUT,
|
||||
|
||||
// Geometric effects. These values should remain at exactly bit 8 and
|
||||
// following, or change gint_image_mkcmd() along with it.
|
||||
|
||||
/* [Any]: Flip image vertically */
|
||||
IMAGE_VFLIP = 0x0100,
|
||||
/* [Any]: Flip image horizontally */
|
||||
IMAGE_HFLIP = 0x0200,
|
||||
|
||||
// Color effects
|
||||
|
||||
/* [RGB565, P8_RGB565, P4_RGB565]: Make a color transparent
|
||||
Adds one argument:
|
||||
* Color to clear (RGB16: 16-bit value; P8/P4: palette index) */
|
||||
IMAGE_CLEARBG = 0x10,
|
||||
/* [RGB565, P8_RGB565, P4_RGB565]: Turn a color into another
|
||||
Adds two arguments:
|
||||
* Color to replace (RGB16: 16-bit value; P8/P4: palette index)
|
||||
* Replacement color (16-bit value) */
|
||||
IMAGE_SWAPCOLOR = 0x20,
|
||||
/* [RGB565A, P8_RGB565A, P4_RGB565A]: Add a background
|
||||
Adds one argument:
|
||||
* Background color (16-bit value) */
|
||||
IMAGE_ADDBG = 0x40,
|
||||
/* [RGB565A, P8_RGB565A, P4_RGB565A]: Dye all non-transparent pixels
|
||||
Adds one argument:
|
||||
* Dye color (16-bit value) */
|
||||
IMAGE_DYE = 0x80,
|
||||
};
|
||||
|
||||
//---
|
||||
// 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.
|
||||
It always allocates a new data array; if you need to reuse a data array, use
|
||||
the lower-level image_create() or image_create_sub().
|
||||
|
||||
The first parameters [width] and [height] specify the dimensions of the new
|
||||
image in pixels. The [format] should be one of the IMAGE_* formats, for
|
||||
example IMAGE_RGB565A or IMAGE_P4_RGB565.
|
||||
|
||||
This function does not specify or initialize the palette of the new image;
|
||||
use image_set_palette(), image_alloc_palette() or image_copy_palette()
|
||||
after calling this function.
|
||||
|
||||
The returned image structure must be freed with image_free() after use.
|
||||
|
||||
@width Width of the new image
|
||||
@height Height of the new image
|
||||
@format Pixel format; one of the IMAGE_* formats defined above */
|
||||
image_t *image_alloc(int width, int height, int format);
|
||||
|
||||
/* image_set_palette(): Specify an external palette for an image
|
||||
|
||||
This function sets the image's palette to the provided address. The number
|
||||
of entries allocated must be specified in size. It is also the caller's
|
||||
responsibility to ensure that the palette covers all the indices used in the
|
||||
image data.
|
||||
|
||||
The old palette, if owned by the image, is freed. If [owns=true] the
|
||||
palette's ownership is given to the image, otherwise it is kept external. */
|
||||
void image_set_palette(image_t *img, uint16_t *palette, int size, bool owns);
|
||||
|
||||
/* image_alloc_palette(): Allocate a new palette for an image
|
||||
|
||||
This function allocates a new palette for an image. The number of entries is
|
||||
specified in size; for P8 it can vary between 1 and 256, for P4 it is
|
||||
ignored (P4 images always have 16 colors).
|
||||
|
||||
The old palette, if owned by the image, is freed. The entries of the new
|
||||
palette are all initialized to 0. If size is -1, the format's default
|
||||
palette size is used. Returns true on success. */
|
||||
bool image_alloc_palette(image_t *img, int size);
|
||||
|
||||
/* image_copy_palette(): Copy another image's palette
|
||||
|
||||
This function allocates a new palette for an image, and initializes it with
|
||||
a copy of another image's palette. For P8 the palette can be resized by
|
||||
specifying a value other than -1 as the size; by default, the source image's
|
||||
palette size is used (within the limits of the new format). Retuns true on
|
||||
success. */
|
||||
bool image_copy_palette(image_t const *src, image_t *dst, int size);
|
||||
|
||||
/* image_create(): Create a bare image with no data/palette
|
||||
|
||||
This function allocates a new image structure but without data or palette.
|
||||
The [data] and [palette] members are NULL, [color_count] and [stride] are 0.
|
||||
|
||||
This function is useful to create images that reuse externally-provided
|
||||
information. It is intended that the user of this function sets the [data]
|
||||
and [stride] fields themselves, along with the IMAGE_FLAGS_DATA_ALLOC flag
|
||||
if the image should own its data.
|
||||
|
||||
The [palette] and [color_count] members can be set with image_set_palette(),
|
||||
image_alloc_palette(), image_copy_palette(), or manually.
|
||||
|
||||
The returned image structure must be freed with image_free() after use. */
|
||||
image_t *image_create(int width, int height, int format);
|
||||
|
||||
/* image_create_vram(): Create a reference to gint_vram
|
||||
|
||||
This function creates a new RGB565 image that references gint_vram. Using
|
||||
this image as target for transformation functions can effectively render
|
||||
transformed images to VRAM.
|
||||
|
||||
The value of gint_vram is captured when this function is called, and does
|
||||
not update after dupdate() when triple-buffering is used. The user should
|
||||
account for this option. (Using this function twice then replacing one of
|
||||
the [data] pointers is allowed.)
|
||||
|
||||
The VRAM image owns no data but it does own its own structure so it must
|
||||
still be freed with image_free() after use. */
|
||||
image_t *image_create_vram(void);
|
||||
|
||||
/* image_free(): Free and image and the data it owns
|
||||
|
||||
This function frees the provided image structure and the data that it owns.
|
||||
Images converted by fxconv should not be freed; nonetheless, this functions
|
||||
distinguishes them and should work. Images are not expected to be created on
|
||||
the stack.
|
||||
|
||||
If the image has the IMAGE_FLAGS_DATA_ALLOC flag, the data pointer is also
|
||||
freed. Similarly, the image has the IMAGE_FLAGS_PALETTE_ALLOC flag, the
|
||||
palette is freed. Make sure to not free images when references to them still
|
||||
exist, as this could cause the reference's pointers to become dangling. */
|
||||
void image_free(image_t *img);
|
||||
|
||||
//---
|
||||
// Basic image access and information
|
||||
//---
|
||||
|
||||
/* image_valid(): Check if an image is valid
|
||||
An image is considered valid if it has a valid profile, a non-NULL data
|
||||
pointer, and for palette formats a valid palette pointer. */
|
||||
bool image_valid(image_t const *img);
|
||||
|
||||
/* image_alpha(): Get the alpha value for an image format
|
||||
|
||||
This function returns the alpha value for any specific image format:
|
||||
* RGB16: 0x0001
|
||||
* P8: -128 (0x80)
|
||||
* P4: 0
|
||||
For non-transparent formats, it returns a value that is different from all
|
||||
valid pixel values of the format, which means it is always safe to compare a
|
||||
pixel value to the image_alpha() of the format. */
|
||||
int image_alpha(int format);
|
||||
|
||||
/* image_get_pixel(): Read a pixel from the data array
|
||||
|
||||
This function reads a pixel from the image's data array at position (x,y).
|
||||
It returns the pixel's value, which is either a full-color value (RGB16) or
|
||||
a possibly-negative palette index (P8/P4). See the description of the [data]
|
||||
field of image_t for more details. The value of the pixel can be decoded
|
||||
into a 16-bit color either manually or by using the image_decode_pixel()
|
||||
function.
|
||||
|
||||
Note that reading large amounts of image data with this function will be
|
||||
slow; if you need reasonable performance, consider iterating on the data
|
||||
array manually. */
|
||||
int image_get_pixel(image_t const *img, int x, int y);
|
||||
|
||||
/* image_decode_pixel(): Decode a pixel value
|
||||
|
||||
This function decodes a pixel's value obtained from the data array (for
|
||||
instance with image_get_pixel()). For RGB16 formats this does nothing, but
|
||||
for palette formats this accesses the palette at a suitable position.
|
||||
|
||||
Note that reading large amounts of data with this function will be slow; if
|
||||
you need reasonable performance, consider inlining the format-specific
|
||||
method or iterating on the data array manually. */
|
||||
int image_decode_pixel(image_t const *img, int pixel);
|
||||
|
||||
/* image_data_size(): Compute the size of the [data] array
|
||||
This function returns the size of the data array, in bytes. This can be used
|
||||
to duplicate it. Note that for sub-images this is a subsection of another
|
||||
image's data array, and might be much larger than the sub-image. */
|
||||
int image_data_size(image_t const *img);
|
||||
|
||||
//---
|
||||
// Basic image modifications
|
||||
//---
|
||||
|
||||
/* image_set_pixel(): Set a pixel in the data array
|
||||
|
||||
This function writes a pixel into the image's data array at position (x,y).
|
||||
The pixel value must be of the proper format, as specified in the definition
|
||||
of the [data] field of image_t.
|
||||
|
||||
Formats: RGB16, P8, P4 */
|
||||
void image_set_pixel(image_t const *img, int x, int y, int value);
|
||||
|
||||
/* image_copy(): Convert and copy an image
|
||||
|
||||
This function copies an image into another image while converting certain
|
||||
formats. Unlike transforms, this function does clip, so there are no
|
||||
conditions on the size of the target.
|
||||
|
||||
If [copy_alpha] is true, transparent pixels are copied verbatim, which
|
||||
effectively replaces the top-left corner of [dst] with [src]. If it's false,
|
||||
transparent pixels of [src] are skipped, effectively rendering [src] over
|
||||
the top-left corner of [src].
|
||||
|
||||
This function converts between all formats except from RGB16 to P8/P4, since
|
||||
this requires generating a palette (which is a complex endeavour).
|
||||
Conversions from P8/P4 to RGB16 simply decode the palette. Conversions
|
||||
between P8/P4 preserve the contents but renumber the palette entries. From
|
||||
P4 to P8, the image is always preserved. From P8 to P4, the image is only
|
||||
preserved if it has less than 16 colors (this is intended to allow P4 images
|
||||
to be converted to P8 for edition by this library, and then back to P4). The
|
||||
following table summarizes the conversions:
|
||||
|
||||
Source format → RGB16 P8 P4
|
||||
Target format ↓ +-----------+----------------+------------------+
|
||||
RGB16 | Copy Decode palette Decode palette |
|
||||
P8 | - Copy Enlarge palette |
|
||||
P4 | - Narrow palette Copy |
|
||||
+-----------+----------------+------------------+
|
||||
|
||||
Note that conversions to RGB16 are not lossless because RGB565, P8 and P4
|
||||
can represent any color; if a color equal to image_alpha(IMAGE_RGB565A) is
|
||||
found during conversion, this function transforms it slightly to look
|
||||
similar instead of erroneously generating a transparent pixel.
|
||||
|
||||
Formats: RGB16 → RGB16, P8 → Anything, P4 → Anything
|
||||
Size requirement: none (clipping is performed)
|
||||
Supports in-place: No (useless) */
|
||||
void image_copy(image_t const *src, image_t *dst, bool copy_alpha);
|
||||
|
||||
/* image_copy_alloc(): Convert and copy into a new image
|
||||
This function is similar to image_copy(), but it allocates a target image of
|
||||
the desired format before copying. */
|
||||
image_t *image_copy_alloc(image_t const *src, int new_format);
|
||||
|
||||
/* image_fill(): Fill an image with a single pixel value */
|
||||
void image_fill(image_t *img, int value);
|
||||
|
||||
/* image_clear(): Fill a transparent image with its transparent value */
|
||||
void image_clear(image_t *img);
|
||||
|
||||
//---
|
||||
// Sub-image extraction
|
||||
//---
|
||||
|
||||
/* image_sub(): Build a reference to a sub-image
|
||||
|
||||
This function is used to create references to sub-images of RGB16 and P8
|
||||
images. The [data] pointer of the sub-image points somewhere within the data
|
||||
array of the source, and its [palette] pointer is identical to the source's.
|
||||
|
||||
The last parameter is a pointer to a preallocated image_t structure (usually
|
||||
on the stack) that gets filled with the data. Doing this instead of
|
||||
allocating a new object with malloc() means that there is no need to
|
||||
image_free() the sub-image, and thus it can be used inline:
|
||||
|
||||
image_t tmp;
|
||||
image_hflip(src, image_sub(dst, x, y, w, h, &tmp));
|
||||
|
||||
A preprocessor macro is used to make the last parameter optional. If it's
|
||||
not specified, a pointer to a static image_t will be returned instead. This
|
||||
is useful in inline calls as shown above, which then simplify to:
|
||||
|
||||
image_hflip(src, image_sub(dst, x, y, w, h));
|
||||
|
||||
However, another call to image_sub() or image_at() will override the
|
||||
sub-image, so you should only use this in such temporary settings. If you
|
||||
need multiple image_sub() or image_at() calls in the same statement, only
|
||||
one can use the short form.
|
||||
|
||||
If the requested rectangle does not intersect the source, the sub-image will
|
||||
be of dimension 0x0. If the image format does not support sub-images (P4),
|
||||
the sub-image will test invalid with image_valid(). */
|
||||
image_t *image_sub(image_t const *src, int x, int y, int w, int h,
|
||||
image_t *dst);
|
||||
|
||||
/* 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)
|
||||
|
||||
/* 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)
|
||||
|
||||
//---
|
||||
// Geometric image transforms
|
||||
//
|
||||
// All geometric transforms render to position (0,0) of the target image and
|
||||
// fail if the target image is not large enough to hold the transformed result
|
||||
// (unlike the rendering functions which render only the visible portion).
|
||||
//
|
||||
// To render at position (x,y) of the target image, use img_at(). For instance:
|
||||
// image_hflip(src, image_at(dst, x, y));
|
||||
//
|
||||
// Each transform function has an [_alloc] variant which does the same
|
||||
// transform but allocates the target image on the fly and returns it. Remember
|
||||
// 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.)
|
||||
//
|
||||
// Some functions support in-place transforms. This means they can be called
|
||||
// with the source as destination, and will transform the image without needing
|
||||
// new memory. For instance, image_hflip(src, src) flips in-place and replaces
|
||||
// src with a flipped version of itself.
|
||||
//
|
||||
// (However, it is not possible to transform in-place if the source and
|
||||
// destination intersect in non-trivial ways. The result will be incorrect.)
|
||||
//
|
||||
// When transforming to a new image, transparent pixels are ignored, so if the
|
||||
// destination already has some data, it will not be erased automatically. Use
|
||||
// image_clear() beforehand to achieve that effect. This allows alpha blending
|
||||
// while transforming, which is especially useful on the VRAM.
|
||||
//---
|
||||
|
||||
/* image_hflip(): Flip horizontally
|
||||
Formats: RGB16, P8
|
||||
Size requirement: destination at least as large as source (no clipping)
|
||||
Supports in-place: Yes */
|
||||
void image_hflip(image_t const *src, image_t *dst, bool copy_alpha);
|
||||
image_t *image_hflip_alloc(image_t const *src);
|
||||
|
||||
/* image_vflip(): Flip vertically
|
||||
Formats: RGB16, P8
|
||||
Size requirement: destination at least as large as source (no clipping)
|
||||
Supports in-place: Yes */
|
||||
void image_vflip(image_t const *src, image_t *dst, bool copy_alpha);
|
||||
image_t *image_vflip_alloc(image_t const *src);
|
||||
|
||||
/* image_linear(): Linear transformation
|
||||
|
||||
This function implements a generic linear transformation. This is a powerful
|
||||
function that can perform any combination of rotation, mirroring and scaling
|
||||
with nearest-neighbor sampling.
|
||||
|
||||
The [image_linear_map] structure defines the settings for the transform.
|
||||
Users familiar with linear algebra might want to use it directly, but they
|
||||
are most conveniently generated with the rotation and scaling functions
|
||||
listed below.
|
||||
|
||||
Note: Currently the structure for the transform is modified by the
|
||||
operation and cannot be reused.
|
||||
|
||||
The image_linear_alloc() variant allocates a new image in addition to
|
||||
performing the transform. The image is created with size (map->dst_w,
|
||||
map->dst_h) which is always a reasonable default. If a target image of
|
||||
smaller size is supplied to image_linear(), clipping is performed; only the
|
||||
top-left corner of the full output is actually rendered.
|
||||
|
||||
Formats: RGB16, P8
|
||||
Size requirement: none (clipping is performed)
|
||||
Supports in-place: No */
|
||||
|
||||
struct image_linear_map {
|
||||
/* Dimensions of the source and destination */
|
||||
int src_w, src_h, dst_w, dst_h;
|
||||
/* Input and output stride in bytes */
|
||||
int src_stride, dst_stride;
|
||||
|
||||
/* The following parameters define the linear transformation as a mapping
|
||||
from coordinates in the destination image (x and y) into coordinates in
|
||||
the source image (u and v).
|
||||
- (u, v) indicate where the top-left corner of the destination lands in
|
||||
the source image.
|
||||
- (dx_u, dx_v) indicate the source-image movement for each movement of
|
||||
x += 1 in the destination.
|
||||
- (dy_u, dy_v) indicate the source-image movement for each movement of
|
||||
y += 1 in the destination.
|
||||
All of these values are specified as 16:16 fixed-point, ie. they encode
|
||||
decimal values by multiplying them by 65536. */
|
||||
int u, v, dx_u, dx_v, dy_u, dy_v;
|
||||
};
|
||||
|
||||
void image_linear(image_t const *src, image_t *dst,
|
||||
struct image_linear_map *map);
|
||||
image_t *image_linear_alloc(image_t const *src,
|
||||
struct image_linear_map *map);
|
||||
|
||||
/* image_scale(): Upscale or downscale an image
|
||||
|
||||
This function generates a linear map to be used in image_linear() to scale
|
||||
the input image. The scaling factor gamma can be specified independently for
|
||||
the x and y dimensions. It is expressed as 16:16 fixed-point; you can set
|
||||
any decimal value multiplied by 65536, for instance 1.5*65536 to increase
|
||||
the width and height by 50%. */
|
||||
void image_scale(image_t const *src, int gamma_x, int gamma_y,
|
||||
struct image_linear_map *map);
|
||||
|
||||
/* image_rotate(): Rotate an image around its center
|
||||
|
||||
This function generates a linear map to be used in image_linear() to perform
|
||||
a rotation around the center of an image. If [resize=true], the target is
|
||||
enlarged to make sure all the rotated pixels can be represented. This can
|
||||
increase the final surface by a factor of up to 2. If the original image
|
||||
doesn't extend to its corners, it is recommended to leave [resize=false] as
|
||||
it noticeably affects performance. */
|
||||
void image_rotate(image_t const *src, float angle, bool resize,
|
||||
struct image_linear_map *map);
|
||||
|
||||
/* image_rotate_around(): Rotate an image around any point
|
||||
|
||||
This function generalizes image_rotate() by allowing rotations around any
|
||||
center, even a point not within the image. The center is specified through
|
||||
two coordinates (*center_x, *center_y). If the center is near the side of
|
||||
the image, a normal rotation would move most of the pixels out of frame;
|
||||
this function moves the frame to make sure the whole image remains visible.
|
||||
*center_x and *center_y are updated to indicate the position of the center
|
||||
of rotation within the new frame (the target image). */
|
||||
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(): Rotate an image around any point and scale it
|
||||
|
||||
This function generalizes image_rotate_around() by adding a scaling factor
|
||||
to the transformation. The scaling factor gamma is expressed as 16:16
|
||||
fixed-point. If [resize=true] the image is further extended to make sure no
|
||||
parts are cut out, as in other rotation functions. */
|
||||
void image_rotate_around_scale(
|
||||
image_t const *src, float angle, int gamma,
|
||||
bool resize, int *center_x, int *center_y,
|
||||
struct image_linear_map *map);
|
||||
|
||||
//---
|
||||
// Color transforms
|
||||
//---
|
||||
|
||||
/* TODO: Color transforms */
|
||||
|
||||
//---
|
||||
// Image rendering functions
|
||||
//
|
||||
// The following functions extend dimage() and dsubimage(). The [effects]
|
||||
// parameter takes a combination of IMAGE_* flags and effects, limited to the
|
||||
// combinations previously described, with additional arguments depending on
|
||||
// the color effect being applied.
|
||||
//
|
||||
// dimage_effect(x, y, img, effects, ...)
|
||||
// dsubimage_effect(x, y, img, left, top, w, h, effects, ...)
|
||||
//
|
||||
// However if you use these super-generic functions you will link the code for
|
||||
// all effects and all formats into your add-in, which takes a fair amount of
|
||||
// space. If that's a problem, you can use the more specific functions below:
|
||||
//
|
||||
// * dimage_<FORMAT>_<EFFECT>() for one particular format (rgb16, p8, p4) along
|
||||
// with one particular color effect (clearbg, swapcolor, addbg, dye).
|
||||
// * dimage_<FORMAT>() is like the above when no color effect is applied.
|
||||
//
|
||||
// All of them support the HFLIP and VFLIP flags. For effect-specific functions
|
||||
// the corresponding effect flag can be omitted (fi. IMAGE_CLEARBG is implicit
|
||||
// when using dimage_p8_clearbg()).
|
||||
//---
|
||||
|
||||
/* dimage_effect(): Generalized dimage() supporting dynamic effects */
|
||||
#define dimage_effect(x, y, img, eff, ...) \
|
||||
dsubimage_effect(x, y, img, 0, 0, (img)->width, (img)->height, eff, \
|
||||
##__VA_ARGS__)
|
||||
/* dsubimage_effect(): Generalized dsubimage() supporting dynamic effects */
|
||||
void dsubimage_effect(int x, int y, image_t const *img,
|
||||
int left, int top, int w, int h, int effects, ...);
|
||||
|
||||
/* Specific versions for each format */
|
||||
#define DIMAGE_SIG1(NAME, ...) \
|
||||
void dimage_ ## NAME(int x, int y, image_t const *img,##__VA_ARGS__); \
|
||||
void dsubimage_ ## NAME(int x, int y, image_t const *img, \
|
||||
int left, int top, int w, int h, ##__VA_ARGS__);
|
||||
#define DIMAGE_SIG(NAME, ...) \
|
||||
DIMAGE_SIG1(rgb16 ## NAME, ##__VA_ARGS__) \
|
||||
DIMAGE_SIG1(p8 ## NAME, ##__VA_ARGS__) \
|
||||
DIMAGE_SIG1(p4 ## NAME, ##__VA_ARGS__)
|
||||
|
||||
/* d[sub]image_{rgb16,p8,p4}_effect(..., effects, <extra arguments>) */
|
||||
DIMAGE_SIG(_effect, int effects, ...)
|
||||
/* d[sub]image_{rgb16,p8,p4}(..., effects) (no color effect, like dimage()) */
|
||||
DIMAGE_SIG(, int effects)
|
||||
/* d[sub]image_{rgb16,p8,p4}_clearbg(..., effects, bg_color_or_index) */
|
||||
DIMAGE_SIG(_clearbg, int effects, int bg_color_or_index)
|
||||
/* d[sub]image_{rgb16,p8,p4}_swapcolor(..., effects, source, replacement) */
|
||||
DIMAGE_SIG(_swapcolor, int effects, int source, int replacement)
|
||||
/* d[sub]image_{rgb16,p8,p4}_addbg(..., effects, bg_color) */
|
||||
DIMAGE_SIG(_addbg, int effects, int bg_color)
|
||||
/* d[sub]image_{rgb16,p8,p4}_dye(..., effects, dye_color) */
|
||||
DIMAGE_SIG(_dye, int effects, int dye_color)
|
||||
|
||||
/* d[sub]image_p4_clearbg_alt(..., effects, bg_index)
|
||||
This is functionally identical to CLEARBG, but it uses an alternative
|
||||
rendering method that is faster for larger images with wide transparent
|
||||
areas. You can swap it with the normal CLEARBG freely. */
|
||||
DIMAGE_SIG1(p4_clearbg_alt, int effects, int bg_index)
|
||||
|
||||
#define dimage_rgb16_effect(x, y, img, eff, ...) \
|
||||
dsubimage_rgb16_effect(x, y, img, 0, 0, (img)->width, (img)->height, \
|
||||
eff, ##__VA_ARGS__)
|
||||
#define dimage_p8_effect(x, y, img, eff, ...) \
|
||||
dsubimage_p8_effect(x, y, img, 0, 0, (img)->width, (img)->height, \
|
||||
eff, ##__VA_ARGS__)
|
||||
#define dimage_p4_effect(x, y, img, eff, ...) \
|
||||
dsubimage_p4_effect(x, y, img, 0, 0, (img)->width, (img)->height, \
|
||||
eff, ##__VA_ARGS__)
|
||||
|
||||
#undef DIMAGE_SIG
|
||||
#undef DIMAGE_SIG1
|
||||
|
||||
//---
|
||||
// Clipping utilities
|
||||
//---
|
||||
|
||||
/* Double box specifying both a source and target area */
|
||||
struct gint_image_box
|
||||
{
|
||||
/* Target location of top-left corner */
|
||||
int x, y;
|
||||
/* Width and height of rendered sub-image */
|
||||
int w, h;
|
||||
/* Source bounding box (low included, high excluded) */
|
||||
int left, top;
|
||||
};
|
||||
|
||||
/* Clip the provided box against the input. If, after clipping, the box no
|
||||
longer intersects the output window, returns false. Otherwise, returns
|
||||
true. */
|
||||
bool gint_image_clip_input(image_t const *img, struct gint_image_box *box,
|
||||
struct dwindow const *window);
|
||||
|
||||
/* Clip the provided box against the output. */
|
||||
void gint_image_clip_output(struct gint_image_box *b,
|
||||
struct dwindow const *window);
|
||||
|
||||
//---
|
||||
// Internal image rendering routines
|
||||
//
|
||||
// The following functions (or non-functions) are implemented in assembler and
|
||||
// make up the internal interface of the image renderer. If you just want to
|
||||
// display images, use dimage() and variations; these are only useful if you
|
||||
// have a different rendering system and wish to use image rendering with
|
||||
// dynamic effects in it.
|
||||
//---
|
||||
|
||||
/* Renderer command. This structure includes most of the information used by
|
||||
the image renderer to perform blits. Some of the information on the target
|
||||
is also passed as direct arguments, which is more convenient and slightly
|
||||
faster.
|
||||
|
||||
Most of the values here can be set with gint_image_mkcmd(). The last two
|
||||
members, along with the return values of the gint_image_FORMAT_loop()
|
||||
functions, are used to update the command if one needs to draw *parts* of
|
||||
the image and resume the rendering later. This is used in Azur. */
|
||||
struct gint_image_cmd
|
||||
{
|
||||
/* Shader ID. This is used in Azur, and ignored in gint */
|
||||
uint8_t shader_id;
|
||||
/* Dynamic effects not already dispatched by renderer
|
||||
Bit 0: VFLIP
|
||||
Bit 1: HFLIP */
|
||||
uint8_t effect;
|
||||
|
||||
/* Number of pixels to render per line. For formats that force either x
|
||||
or width alignment (most of them), this is already adjusted to a
|
||||
suitable multiple (usually a multiple of 2). */
|
||||
int16_t columns;
|
||||
|
||||
/* Stride of the input image (number of pixels between each row), in
|
||||
pixels, without subtracting the number of columns */
|
||||
int16_t input_stride;
|
||||
|
||||
/* Number of lines in the command. This can be adjusted freely, and is
|
||||
particularly useful in Azur for fragmented rendering. */
|
||||
uint8_t lines;
|
||||
|
||||
/* [Any effect]: Offset of first edge */
|
||||
int8_t edge_1;
|
||||
|
||||
/* Core loop; this is an internal label of the renderer */
|
||||
void const *loop;
|
||||
/* Output pixel array, offset by target x/y */
|
||||
void const *output;
|
||||
/* Input pixel array, offset by source x/y. For formats that force x
|
||||
alignment, this is already adjusted. */
|
||||
void const *input;
|
||||
/* Palette, when applicable */
|
||||
uint16_t const *palette;
|
||||
|
||||
/* [Any effect]: Offset of right edge */
|
||||
int16_t edge_2;
|
||||
/* [CLEARBG, SWAPCOLOR]: Source color */
|
||||
uint16_t color_1;
|
||||
/* [SWAPCOLOR]: Destination color */
|
||||
uint16_t color_2;
|
||||
|
||||
/* Remaining height (for updates between fragments) */
|
||||
int16_t height;
|
||||
/* Local x position (for updates between fragments) */
|
||||
int16_t x;
|
||||
};
|
||||
|
||||
/* gint_image_mkcmd(): Prepare a rendering command with dynamic effects
|
||||
|
||||
This function crafts an image renderer command. It loads all the settings
|
||||
except for effect-dependent parameters: the [.loop] label, the color section
|
||||
of [.effect], and color effect settings. See the effect-specific functions
|
||||
to see how they are defined.
|
||||
|
||||
The benefit of this approach is that the rendering code does not need to be
|
||||
linked in unless an effect is actually used, which avoids blowing up the
|
||||
size of the add-in as the number of support dynamic effects increases.
|
||||
|
||||
@box Requested on-screen box (will be clipped depending on effects)
|
||||
@img Source image
|
||||
@effects Set of dynamic effects to be applied, as an [IMAGE_*] bitmask
|
||||
@left_edge Whether to force 2-alignment on the input (box->left)
|
||||
@right_edge Whether to force 2-alignment on the width
|
||||
@cmd Command to be filled
|
||||
@window Rendering window (usually {0, 0, DWIDTH, DHEIGHT})
|
||||
|
||||
Returns false if there is nothing to render because of clipping (in which
|
||||
case [cmd] is unchanged), true otherwise. [*box] is also updated to reflect
|
||||
the final box after clipping but not accounting for edges. */
|
||||
bool gint_image_mkcmd(struct gint_image_box *box, image_t const *img,
|
||||
int effects, bool left_edge, bool right_edge,
|
||||
struct gint_image_cmd *cmd, struct dwindow const *window);
|
||||
|
||||
/* Entry point of the renderers. These functions can be called normally as long
|
||||
as you can build the commands (eg. by using gint_image_mkcmd() then filling
|
||||
the effect-specific information). */
|
||||
void *gint_image_rgb16_loop (int output_width, struct gint_image_cmd *cmd);
|
||||
void *gint_image_p8_loop (int output_width, struct gint_image_cmd *cmd);
|
||||
void *gint_image_p4_loop (int output_width, struct gint_image_cmd *cmd);
|
||||
|
||||
/* Renderer fragments. The following can absolutely not be called from C code
|
||||
as they aren't full functions (and this isn't their prototype). These are
|
||||
continuations to be specified in the [.loop] field of a command before using
|
||||
one of the functions above. */
|
||||
|
||||
void gint_image_rgb16_normal(void);
|
||||
void gint_image_rgb16_clearbg(void);
|
||||
void gint_image_rgb16_swapcolor(void);
|
||||
void gint_image_rgb16_dye(void);
|
||||
|
||||
void gint_image_p8_normal(void);
|
||||
void gint_image_p8_clearbg(void);
|
||||
void gint_image_p8_swapcolor(void);
|
||||
void gint_image_p8_dye(void);
|
||||
|
||||
void gint_image_p4_normal(void);
|
||||
void gint_image_p4_clearbg(void);
|
||||
void gint_image_p4_clearbg_alt(void);
|
||||
void gint_image_p4_swapcolor(void);
|
||||
void gint_image_p4_dye(void);
|
||||
|
||||
//---
|
||||
// Image library utilities
|
||||
//
|
||||
// The following functions and macros are mostly internal utilities; they are
|
||||
// exposed here in case user applications want to extend the set of image
|
||||
// transforms with custom additions.
|
||||
//---
|
||||
|
||||
/* image_target(): Check if an image can be used as target for a transform
|
||||
|
||||
This function is used to quickly check whether a transform from [src] to
|
||||
[dst] is possible. It requires image_valid(src) and image_valid(dst), plus
|
||||
any optional constraints specified as variadic arguments. These constraints
|
||||
can be:
|
||||
|
||||
* NOT_P4: fails if [dst] is P4.
|
||||
* DATA_RW: fails if [dst] is not data-writable.
|
||||
* PALETTE_RW: fails if [dst] is not palette-writable.
|
||||
* SAME_SIZE: fails if [dst] is not at least as large as [src].
|
||||
|
||||
For example, in image_hflip(), we write:
|
||||
if(!image_target(src, dst, NOT_P4, DATA_RW, SAME_SIZE)) return; */
|
||||
|
||||
enum {
|
||||
IMAGE_TARGET_NONE,
|
||||
IMAGE_TARGET_NOT_P4,
|
||||
IMAGE_TARGET_DATA_RW,
|
||||
IMAGE_TARGET_PALETTE_RW,
|
||||
IMAGE_TARGET_SAME_SIZE,
|
||||
IMAGE_TARGET_SAME_FORMAT,
|
||||
IMAGE_TARGET_SAME_DEPTH,
|
||||
};
|
||||
bool image_target(image_t const *src, image_t *dst, ...);
|
||||
|
||||
#define image_target(src, dst, ...) \
|
||||
image_target(src, dst, image_target_arg1(__VA_ARGS__ __VA_OPT__(,) NONE))
|
||||
#define image_target_arg1(c, ...) \
|
||||
IMAGE_TARGET_ ## c __VA_OPT__(, image_target_arg2(__VA_ARGS__))
|
||||
#define image_target_arg2(c, ...) \
|
||||
IMAGE_TARGET_ ## c __VA_OPT__(, image_target_arg3(__VA_ARGS__))
|
||||
#define image_target_arg3(c, ...) \
|
||||
IMAGE_TARGET_ ## c __VA_OPT__(, image_target_arg4(__VA_ARGS__))
|
||||
#define image_target_arg4(c, ...) \
|
||||
IMAGE_TARGET_ ## c __VA_OPT__(, image_target_arg5(__VA_ARGS__))
|
||||
#define image_target_arg5(c, ...) \
|
||||
IMAGE_TARGET_ ## c __VA_OPT__(, image_target_arg6(__VA_ARGS__))
|
||||
#define image_target_arg6(c, ...) \
|
||||
IMAGE_TARGET_ ## c __VA_OPT__(, image_target_too_many_args(__VA_ARGS__))
|
||||
|
||||
/* image_alpha_2(): Conditional alpha */
|
||||
#define image_alpha_2(fmt, copy_alpha) \
|
||||
((copy_alpha) ? 0x10000 : image_alpha(fmt))
|
||||
|
||||
#endif /* GINT_RENDER_RGB */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_IMAGE */
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_INTC
|
||||
#define GINT_INTC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/defs/call.h>
|
||||
|
||||
|
@ -37,6 +41,8 @@ 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,
|
||||
|
@ -126,9 +132,18 @@ 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. */
|
||||
bool intc_handler_function(int event_code, gint_call_t function);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_INTC */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_KEYBOARD
|
||||
#define GINT_KEYBOARD
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Keyboard, key events, keydown() and getkey()
|
||||
|
||||
gint's keyboard driver regularly scans the keyboard matrix and produces *key
|
||||
|
@ -56,6 +60,24 @@
|
|||
|
||||
* 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
|
||||
|
@ -94,13 +116,13 @@ typedef struct
|
|||
{
|
||||
uint time :16; /* Time of event, unique over short periods */
|
||||
|
||||
uint :3; /* Reserved for future use */
|
||||
uint :2; /* 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 :2; /* Type of key event */
|
||||
uint type :3; /* Type of key event */
|
||||
uint key :8; /* Hit key */
|
||||
|
||||
} GPACKED(4) key_event_t;
|
||||
|
@ -108,10 +130,11 @@ 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_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 */
|
||||
};
|
||||
|
||||
/* Keyboard frequency analysis is a runtime setting since gint 2.4. This macro
|
||||
|
@ -158,6 +181,12 @@ 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
|
||||
//---
|
||||
|
@ -177,6 +206,16 @@ 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
|
||||
//---
|
||||
|
@ -201,30 +240,32 @@ key_event_t getkey(void);
|
|||
/* The following are the option bits for getkey_opt(). */
|
||||
enum {
|
||||
/* Enable modifiers keys */
|
||||
GETKEY_MOD_SHIFT = 0x01,
|
||||
GETKEY_MOD_ALPHA = 0x02,
|
||||
/* SHIFT + OPTN toggles backlight (requires GETKEY_MOD_SHIFT) */
|
||||
GETKEY_BACKLIGHT = 0x04,
|
||||
GETKEY_MOD_SHIFT = 0x0001,
|
||||
GETKEY_MOD_ALPHA = 0x0002,
|
||||
/* SHIFT + OPTN (requires GETKEY_MOD_SHIFT) or LIGHT toggles backlight */
|
||||
GETKEY_BACKLIGHT = 0x0004,
|
||||
/* MENU triggers a task switch and displays the main menu */
|
||||
GETKEY_MENU = 0x08,
|
||||
GETKEY_MENU = 0x0008,
|
||||
/* Repeat arrow keys, or even all keys */
|
||||
GETKEY_REP_ARROWS = 0x10,
|
||||
GETKEY_REP_ALL = 0x20,
|
||||
GETKEY_REP_ARROWS = 0x0010,
|
||||
GETKEY_REP_ALL = 0x0020,
|
||||
/* Enable custom repeat profiles; see getkey_set_repeat_profile() */
|
||||
GETKEY_REP_PROFILE = 0x40,
|
||||
GETKEY_REP_PROFILE = 0x0040,
|
||||
/* Enable application shortcuts; see getkey_set_feature_function() */
|
||||
GETKEY_FEATURES = 0x80,
|
||||
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,
|
||||
|
||||
/* No modifiers */
|
||||
GETKEY_NONE = 0x00,
|
||||
GETKEY_NONE = 0x0000,
|
||||
/* Default settings of getkey() */
|
||||
GETKEY_DEFAULT = 0xdf,
|
||||
GETKEY_DEFAULT = 0x05df,
|
||||
};
|
||||
|
||||
/* getkey_profile_t: Custom repeat profile function
|
||||
See getkey_set_repeat_profile() for details. */
|
||||
typedef int (*getkey_profile_t)(int key, int duration, int count);
|
||||
|
||||
/* getkey_feature_t: Custom feature function
|
||||
See getkey_set_feature_function() for details. */
|
||||
typedef bool (*getkey_feature_t)(key_event_t event);
|
||||
|
@ -242,58 +283,20 @@ typedef bool (*getkey_feature_t)(key_event_t event);
|
|||
value whenever you want to interrupt the call; using a timer with
|
||||
[timer_timeout] as callback is suitable. See <gint/timer.h>.
|
||||
|
||||
Event transforms in getkey_opt() (SHIFT, ALPHA and repetitions) are handled
|
||||
by changing the transform settings on the keyboard device. These settings
|
||||
are restored when getkey_opt() returns, so if they are originally disabled
|
||||
(which they are unless set manually) then the status of the SHIFT and ALPHA
|
||||
keys is lost between calls (this has an effect it getkey_opt() is
|
||||
interrupted by timeout). Therefore, in order to use modifiers across several
|
||||
calls to getkey_opt(), make sure to enable the transforms on the keyboard
|
||||
device; see <gint/drivers/keydev.h> for details.
|
||||
|
||||
@options An or-combination of values from the GETKEY_* enumeration
|
||||
@timeout Optional pointer to a timeout value
|
||||
Returns a key event of type KEYEV_DOWN or KEYEV_HOLD with [mod=1]. */
|
||||
key_event_t getkey_opt(int options, volatile int *timeout);
|
||||
|
||||
/* getkey_repeat(): Set repeat delays for getkey()
|
||||
|
||||
This function updates the repeat delays of getkey() and getkey_opt(). The
|
||||
unit of the argument is in milliseconds, but the granularity of the delay is
|
||||
dependent on the keyboard scan frequency.
|
||||
|
||||
In the default setting (128 Hz scans), the possible repeat delays are
|
||||
approximately 8 ms, 16 ms, 23 ms, 31 ms... the provided arguments will be
|
||||
rounded to the closest feasible delays to ensure that repetitions are
|
||||
perfectly regular, rather than approximating the requested frequency.
|
||||
|
||||
The system default is (500 ms, 125 ms). With the 128 Hz setting, this
|
||||
default is reached exactly without approximation. gint's default is (400 ms,
|
||||
40 ms) for more reactivity.
|
||||
|
||||
@first Delay between key press and first repeat (no more than one hour)
|
||||
@next Delay between subsequent repeats (no more than one hour) */
|
||||
void getkey_repeat(int first, int next);
|
||||
|
||||
/* getkey_repeat_profile(): Get the current repeat profile function */
|
||||
getkey_profile_t getkey_repeat_profile(void);
|
||||
|
||||
/* getkey_set_repeat_profile(): Set the repeat profile function
|
||||
|
||||
The repeat profile is called by getkey() and getkey_opt() when a key is
|
||||
pressed or held, and getkey() is planning to repeat it. The profile decides
|
||||
whether such repetition is allowed, and if so, how long it shoud take. The
|
||||
profile has access to the following information:
|
||||
|
||||
@key Key for which a repetition is being considered
|
||||
@duration Duration since the key was first pressed (us)
|
||||
@count Number of previous repeats (0 on the first call)
|
||||
|
||||
The profile function must either return a positive number of microseconds to
|
||||
wait until the next repeat, or 0 to block the repeat indefinitely. Note that
|
||||
the keyboard device typically updates every 7-8 ms, timings are tracked in
|
||||
microseconds only to limit deviations.
|
||||
|
||||
Setting a repeat profile overrides GETKEY_REP_ARROWS, GETKEY_REP_ALL, and
|
||||
the repeat delays. Calling with profile=NULL restores this behavior.
|
||||
|
||||
This mechanism replaces a "repeat filter" that existed until gint 2.4. The
|
||||
main difference is that the repeat filter was called when the repeat event
|
||||
arrived, whereas the repeat profile is called one repeat earlier to schedule
|
||||
the repeat exactly when needed. */
|
||||
void getkey_set_repeat_profile(getkey_profile_t profile);
|
||||
|
||||
/* getkey_feature_function(): Get the current feature function */
|
||||
getkey_feature_t getkey_feature_function(void);
|
||||
|
||||
|
@ -329,4 +332,36 @@ int keycode_function(int keycode);
|
|||
returns 7 for KEY_7) and -1 for other keys. */
|
||||
int keycode_digit(int keycode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
//---
|
||||
// Deprecated functions for repeat control
|
||||
//
|
||||
// The following types and functions have been deprecated. The handling of
|
||||
// repeats is done inside the keyboard device (see <gint/drivers/keydev.h>).
|
||||
// Until gint 2.9, the device had repeats disabled by default and getkey()
|
||||
// enabled them. The problem is that repeats usually occur while getkey() is
|
||||
// not running, so repeats wouldn't work as expected.
|
||||
//
|
||||
// Thus, getkey()-specific APIs related to repeat settings are now deprecated
|
||||
// in favor of the ones provided by <gint/drivers/keydev.h>, which apply
|
||||
// globally instead of just when getkey() is being run.
|
||||
//---
|
||||
|
||||
typedef void *getkey_profile_t;
|
||||
|
||||
__attribute__((deprecated(
|
||||
"Use keydev_set_standard_repeats(), which is permanent, instead")))
|
||||
void getkey_repeat(int first, int next);
|
||||
|
||||
__attribute__((deprecated(
|
||||
"Use keydev_transform(keydev_std()).repeater instead")))
|
||||
getkey_profile_t getkey_repeat_profile(void);
|
||||
|
||||
__attribute__((deprecated(
|
||||
"Set the [repeater] attribute with keydev_set_transform() instead")))
|
||||
void getkey_set_repeat_profile(getkey_profile_t profile);
|
||||
|
||||
#endif /* GINT_KEYBOARD */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_KEYCODES
|
||||
#define GINT_KEYCODES
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Raw matrix codes */
|
||||
enum {
|
||||
KEY_F1 = 0x91,
|
||||
|
@ -71,6 +75,18 @@ enum {
|
|||
of the matrix one could use a ghosting effect to boot the calc. */
|
||||
KEY_ACON = 0x07,
|
||||
|
||||
/* Virtual key codes */
|
||||
KEY_HELP = 0x20, /* fx-9860G Slim: 0x75 */
|
||||
KEY_LIGHT = 0x10, /* fx-9860G Slim: 0x76 */
|
||||
|
||||
/* Key codes for the CP-400 */
|
||||
KEY_KBD = 0xa1,
|
||||
KEY_X = 0xa2,
|
||||
KEY_Y = 0xa3,
|
||||
KEY_Z = 0xa4,
|
||||
KEY_EQUALS = 0xa5,
|
||||
KEY_CLEAR = KEY_EXIT,
|
||||
|
||||
/* Key aliases (handle with care =D) */
|
||||
KEY_X2 = KEY_SQUARE,
|
||||
KEY_CARET = KEY_POWER,
|
||||
|
@ -83,4 +99,8 @@ enum {
|
|||
KEY_MINUS = KEY_SUB,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_KEYCODES */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_KMALLOC
|
||||
#define GINT_KMALLOC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/config.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
|
@ -35,6 +39,20 @@ void *krealloc(void *ptr, size_t size);
|
|||
/* kfree(): Free memory allocated with kalloc() */
|
||||
void kfree(void *ptr);
|
||||
|
||||
/* kmalloc_max(): Allocate the largest block available in an arena
|
||||
|
||||
This function is like kmalloc(), but it find the largest block in the arena
|
||||
and returns it whole after setting its size in *size. This is useful if you
|
||||
need memory to manage with another allocator, or you don't yet know the size
|
||||
of the data to be generated. The block can later be shrunk with realloc().
|
||||
|
||||
Currently only gint-managed arenas support this operation.
|
||||
|
||||
@size Will be set to size of returned block (if there is one)
|
||||
@arean_name Name of arena to allocate in (*cannot* be NULL)
|
||||
Returns the address of the largest block available, NULL on error. */
|
||||
void *kmalloc_max(size_t *size, char const *arena_name);
|
||||
|
||||
//---
|
||||
// Extension API for new areas and statistics
|
||||
//---
|
||||
|
@ -49,6 +67,8 @@ typedef struct {
|
|||
void * (*realloc)(void *ptr, size_t newsize, void *data);
|
||||
/* kfree() handles ptr == NULL*/
|
||||
void (*free)(void *ptr, void *data);
|
||||
/* kmalloc_max() backend */
|
||||
void * (*malloc_max)(size_t *size, void *data);
|
||||
|
||||
/* Name, should be unique; gint reserves names starting with "_" */
|
||||
char const *name;
|
||||
|
@ -88,6 +108,11 @@ 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
|
||||
//---
|
||||
|
@ -164,4 +189,8 @@ int kmallocdbg_sequence_length(kmalloc_arena_t *a);
|
|||
|
||||
#endif /* GINT_KMALLOC_DEBUG */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_KMALLOC */
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
//---
|
||||
// gint:kprint - gint's printf(3)-like formatted printer
|
||||
//---
|
||||
|
||||
#ifndef GINT_KPRINT
|
||||
#define GINT_KPRINT
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
//---
|
||||
// Formatted printing
|
||||
//---
|
||||
|
||||
/* kvsprint(): Formatted print to string
|
||||
This function is similar to vsnprintf(3), except that variadic arguments are
|
||||
passed as a pointer to va_list. For standard functions like vsnprintf(3),
|
||||
see <stdio.h>. */
|
||||
size_t kvsprint(char *output, size_t len, char const *format, va_list *args);
|
||||
|
||||
/* kprint_enable_fp(): Enable and load floating-point formats
|
||||
Loads floating-point formats %e, %E, %f, %F, %g and %G. By default these
|
||||
formats are not enabled because the formatting code takes a large amount of
|
||||
space. Calling this function pulls the floating-point formatter from the
|
||||
gint library at link time. */
|
||||
void kprint_enable_fp(void);
|
||||
|
||||
//---
|
||||
// Printer extensions
|
||||
//---
|
||||
|
||||
/* Arguments passed to formatters */
|
||||
#define KFORMAT_ARGS \
|
||||
GUNUSED int spec, /* Specifier letter */ \
|
||||
GUNUSED kprint_options_t *opt, /* Other options in format */ \
|
||||
va_list *args /* Vararg list to read from */
|
||||
|
||||
/* kprint_options_t: Standard format options */
|
||||
typedef struct {
|
||||
/* Minimal length of formatted string (padding can be added) */
|
||||
uint16_t length;
|
||||
/* How much significant characters of data, meaning varies */
|
||||
int16_t precision;
|
||||
|
||||
/* Size specifier for integers (%o, %x, %i, %d, %u), may be one of:
|
||||
(0) char (8-bit)
|
||||
(1) short (16-bit)
|
||||
(2) int (32-bit)
|
||||
(3) long (32-bit)
|
||||
(4) long long (64-bit) */
|
||||
uint8_t size;
|
||||
|
||||
/* (#) Alternative form: base prefixes, decimal point */
|
||||
uint alternative :1;
|
||||
/* ( ) Add a blank sign before nonnegative numbers */
|
||||
uint blank_sign :1;
|
||||
/* (+) Always add a sign before a number (overrides ' ') */
|
||||
uint force_sign :1;
|
||||
|
||||
/* Alignment options: each option overrides all others before itself
|
||||
NUL By default, align right
|
||||
(0) Left-pad numerical values with zeros
|
||||
(-) Align left by adding space on the right, dropping zeros */
|
||||
uint8_t alignment;
|
||||
|
||||
} GPACKED(2) kprint_options_t;
|
||||
|
||||
/* kprint_formatter_t: Type of format function */
|
||||
typedef void (*kprint_formatter_t)(KFORMAT_ARGS);
|
||||
|
||||
/* kprint_register(): Register a formatter
|
||||
|
||||
The formatter designated by the specified lowercase letter (eg 'q') is
|
||||
registered. It will handle formats for both the lowercase and uppercase
|
||||
formats (eg "%q" and "%Q").
|
||||
|
||||
Default formatters can be overridden (although not advised), but formatters
|
||||
for "h" and "l" and "z" cannot be set because these letters are used as size
|
||||
specifiers (eg in "%hd" or "%zu").
|
||||
|
||||
A formatter can be removed or disabled by registering NULL.
|
||||
|
||||
@spec Specifier to use, should be a lowercase letter
|
||||
@kformat Format function */
|
||||
void kprint_register(int spec, kprint_formatter_t kformat);
|
||||
|
||||
/* kprint_out(): Output a single character to the kprint buffer */
|
||||
void kprint_out(int byte);
|
||||
|
||||
/* kprint_outn(): Output the same character <n> times */
|
||||
void kprint_outn(int byte, int n);
|
||||
|
||||
/* kprint_outstr(): Output a string to the kprint buffer */
|
||||
void kprint_outstr(char const *str, int n);
|
||||
|
||||
//---
|
||||
// Helper functions for formatters
|
||||
//---
|
||||
|
||||
/* kprint_geometry_t: General geometry for a format
|
||||
This helper defines the structure of a format as follows:
|
||||
|
||||
sign v |< zeros >| |< content >|
|
||||
_ _ _ _ _ _ _ _ _ + 0 x 0 0 0 0 0 0 8 a c 7 . 3 c _ _ _ _ _ _ _ _ _ _
|
||||
|< left_spaces >| ^^^ prefix |< right_spaces >|
|
||||
|
||||
The sign character is absent if sign=0, the prefix is specified by length
|
||||
and is also absent if prefix=0. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t left_spaces; /* Spaces before content */
|
||||
uint8_t sign; /* Sign character (NUL, ' ', '+' or '-') */
|
||||
uint8_t prefix; /* Base prefix ('0', '0x', etc) length */
|
||||
uint16_t zeros; /* For integer displays, number of zeros */
|
||||
uint16_t content; /* Content length in bytes */
|
||||
uint16_t right_spaces; /* Spaces after content */
|
||||
|
||||
/* Style of display:
|
||||
KPRINT_GENERIC Sign ignored, 0-padding ignored
|
||||
KPRINT_INTEGER .precision causes 0-padding
|
||||
KPRINT_NUMERIC No effect */
|
||||
enum { KPRINT_GENERIC = 0, KPRINT_INTEGER, KPRINT_NUMERIC } style;
|
||||
|
||||
} GPACKED(2) kprint_geometry_t;
|
||||
|
||||
/* kformat_geometry(): Calculate the geometry of a format
|
||||
|
||||
The caller provides as input:
|
||||
* opt, as passed by the main kprint() routine
|
||||
* g->prefix, the length of the desired prefix (if unused, 0)
|
||||
* g->content, the natural content length for the provided data
|
||||
* g->sign, the sign of the input ("+" or "-"); for KPRINT_GENERIC, 0
|
||||
* g->style, which affects the meaning of options
|
||||
|
||||
This function outputs:
|
||||
* g->sign, which will be changed to " " or NUL (0) depending on options
|
||||
* All fields of g that are not part of the input
|
||||
|
||||
The algorithm for laying out the format is as follows.
|
||||
1. For numerical and integer formats, turn a "+" sign into " " if
|
||||
opt->blank_sign is set, "+" if opt->force_sign is set, NUL otherwise.
|
||||
2. Compute the total amount of padding needed to reach opt->length.
|
||||
3. In integer style, if a precision is specified and more than content
|
||||
length plus sign and prefix, turn some padding into zeros.
|
||||
4. If numerical and integer styles, if opt->alignment == '0' turn all the
|
||||
padding into zeros.
|
||||
5. Turn remaining padding into spaces at the left (if opt->alignment == NUL)
|
||||
or right (if opt->alignment == '-').
|
||||
|
||||
@opt Options provided by the main kprint() routine
|
||||
@g Format geometry (input/output) */
|
||||
void kformat_geometry(kprint_options_t *opt, kprint_geometry_t *g);
|
||||
|
||||
#endif /* GINT_KPRINT */
|
|
@ -5,7 +5,12 @@
|
|||
#ifndef GINT_MMU
|
||||
#define GINT_MMU
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/mpu/mmu.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
//---
|
||||
// Unified interface
|
||||
|
@ -36,6 +41,17 @@ void *mmu_uram(void);
|
|||
fx-9860G, and 512k on fx-CG 50. */
|
||||
uint32_t mmu_uram_size(void);
|
||||
|
||||
/* mmu_is_rom(): Determine if an address points to ROM
|
||||
|
||||
Checks whether the supplied pointer points to ROM or to a virtualized
|
||||
portion of ROM. For the sake of efficiency, this function uses heuristics
|
||||
about the structure of P0 rather than actually checking the TLB.
|
||||
|
||||
This is useful during filesystem accesses because only data outside of ROM
|
||||
can be written to files. Pointers for which this function returns true
|
||||
cannot be used as a source for BFile_Write(). */
|
||||
bool mmu_is_rom(void const *ptr);
|
||||
|
||||
//---
|
||||
// SH7705 TLB
|
||||
//---
|
||||
|
@ -73,7 +89,7 @@ uint32_t tlb_translate(uint32_t page, uint32_t *size);
|
|||
/* utlb_addr() - get the P4 address of a UTLB address entry
|
||||
@E Entry number (should be in range 0..63)
|
||||
Returns a pointer to the entry. */
|
||||
const utlb_addr_t *utlb_addr(uint E);
|
||||
utlb_addr_t const *utlb_addr(uint E);
|
||||
|
||||
/* utlb_data() - get the P4 address of a UTLB data entry
|
||||
@E Entry number (should be in range 0..63)
|
||||
|
@ -94,4 +110,18 @@ void utlb_mapped_memory(uint32_t *rom, uint32_t *ram);
|
|||
/* utlb_translate(): Get the physical address for a virtual page */
|
||||
uint32_t utlb_translate(uint32_t page, uint32_t *size);
|
||||
|
||||
/* itlb_addr(): Get the P4 address of an ITLB address entry
|
||||
@E Entry number (0..3)
|
||||
Returns a pointer to the entry. */
|
||||
itlb_addr_t const *itlb_addr(uint E);
|
||||
|
||||
/* itlb_data(): Get the P4 address of an ITLB data entry
|
||||
@E Entry number (0..3)
|
||||
Returns a pointer to the entry. */
|
||||
itlb_data_t const *itlb_data(uint E);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MMU */
|
||||
|
|
224
include/gint/mpu/bsc.h
Normal file
224
include/gint/mpu/bsc.h
Normal file
|
@ -0,0 +1,224 @@
|
|||
//---
|
||||
// gint:mpu:bsc - Bus State Controller
|
||||
//---
|
||||
|
||||
#ifndef GINT_MPU_BSC
|
||||
#define GINT_MPU_BSC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
//---
|
||||
// SH7705 But State Controller. Refer to:
|
||||
// Renesas SH7705 Group Hardware Manual
|
||||
// Section 7: Bus State Controller (BSC)
|
||||
//---
|
||||
|
||||
typedef volatile lword_union(sh7705_bsc_CSnBCR_t,
|
||||
uint32_t :2;
|
||||
uint32_t IWW :2; /* Wait cycles for Write-Read and Write-Write */
|
||||
uint32_t :1;
|
||||
uint32_t IWRWD :2; /* Wait cycles for other-space Read-Write */
|
||||
uint32_t :1;
|
||||
uint32_t IWRWS :2; /* Wait cycles for same-space Read-Write */
|
||||
uint32_t :1;
|
||||
uint32_t IWRRD :2; /* Wait cycles for other-space Read-Read */
|
||||
uint32_t :1;
|
||||
uint32_t IWRRS :2; /* Wait cycles for same-space Read-Read */
|
||||
uint32_t :1;
|
||||
uint32_t TYPE :3; /* Memory type */
|
||||
uint32_t :1;
|
||||
uint32_t BSZ :2; /* Data bus size */
|
||||
uint32_t :9;
|
||||
);
|
||||
|
||||
/* Warning: the layout of this register changes with n *and* with the memory
|
||||
type. This version is not exhaustive. Check the manual! */
|
||||
typedef volatile lword_union(sh7705_bsc_CSnWCR_t,
|
||||
uint32_t :13;
|
||||
uint32_t WW :3; /* Write access wait cycles */
|
||||
uint32_t :3;
|
||||
uint32_t SW :2; /* Wait from CSn/address to RD/WEn assertion */
|
||||
uint32_t WR :4; /* Access wait cycles */
|
||||
uint32_t WM :1; /* Whether to use external wait */
|
||||
uint32_t :4;
|
||||
uint32_t HW :2; /* Wait from RD/WEn to CSn/address negation */
|
||||
);
|
||||
|
||||
typedef volatile struct
|
||||
{
|
||||
lword_union(CMNCR,
|
||||
uint32_t :24;
|
||||
uint32_t DMAIW :2; /* DMA single-address wait states */
|
||||
uint32_t DMAIWA :1; /* DMAIW wait states insertion method */
|
||||
uint32_t :1;
|
||||
uint32_t const ENDIAN :1; /* Global CPU endianness flag */
|
||||
uint32_t :1;
|
||||
uint32_t HIZMEM :1; /* High-Z memory Control*/
|
||||
uint32_t HIZCNT :1; /* High-Z Control*/
|
||||
);
|
||||
|
||||
sh7705_bsc_CSnBCR_t CS0BCR;
|
||||
sh7705_bsc_CSnBCR_t CS2BCR;
|
||||
sh7705_bsc_CSnBCR_t CS3BCR;
|
||||
sh7705_bsc_CSnBCR_t CS4BCR;
|
||||
sh7705_bsc_CSnBCR_t CS5ABCR;
|
||||
sh7705_bsc_CSnBCR_t CS5BBCR;
|
||||
sh7705_bsc_CSnBCR_t CS6ABCR;
|
||||
sh7705_bsc_CSnBCR_t CS6BBCR;
|
||||
|
||||
sh7705_bsc_CSnWCR_t CS0WCR;
|
||||
sh7705_bsc_CSnWCR_t CS2WCR;
|
||||
sh7705_bsc_CSnWCR_t CS3WCR;
|
||||
sh7705_bsc_CSnWCR_t CS4WCR;
|
||||
sh7705_bsc_CSnWCR_t CS5AWCR;
|
||||
sh7705_bsc_CSnWCR_t CS5BWCR;
|
||||
sh7705_bsc_CSnWCR_t CS6AWCR;
|
||||
sh7705_bsc_CSnWCR_t CS6BWCR;
|
||||
|
||||
/* TODO: There are more registers (not involved in overclocking). */
|
||||
} GPACKED(4) sh7705_bsc_t;
|
||||
|
||||
#define SH7705_BSC (*(sh7705_bsc_t *)0xa4fd0000)
|
||||
|
||||
|
||||
//---
|
||||
// SH7305 But State Controller. Refer to:
|
||||
// Renesas SH7730 Group Hardware Manual
|
||||
// Section 11: Bus State Controller (BSC)
|
||||
//---
|
||||
|
||||
typedef volatile lword_union(sh7305_bsc_CSnBCR_t,
|
||||
uint32_t :1;
|
||||
uint32_t IWW :3;
|
||||
uint32_t IWRWD :3;
|
||||
uint32_t IWRWS :3;
|
||||
uint32_t IWRRD :3;
|
||||
uint32_t IWRRS :3;
|
||||
uint32_t TYPE :4;
|
||||
uint32_t :1;
|
||||
uint32_t BSZ :2;
|
||||
uint32_t :9;
|
||||
);
|
||||
|
||||
typedef volatile lword_union(sh7305_bsc_CSnWCR_06A6B_t,
|
||||
uint32_t :11;
|
||||
uint32_t BAS :1;
|
||||
uint32_t :1;
|
||||
uint32_t WW :3;
|
||||
uint32_t ADRSFIX:1;
|
||||
uint32_t :2;
|
||||
uint32_t SW :2;
|
||||
uint32_t WR :4;
|
||||
uint32_t WM :1;
|
||||
uint32_t :4;
|
||||
uint32_t HW :2;
|
||||
);
|
||||
|
||||
typedef volatile lword_union(sh7305_bsc_CSnWCR_45A5B_t,
|
||||
uint32_t :11;
|
||||
uint32_t BAS :1;
|
||||
uint32_t :1;
|
||||
uint32_t WW :3;
|
||||
uint32_t :3;
|
||||
uint32_t SW :2;
|
||||
uint32_t WR :4;
|
||||
uint32_t WM :1;
|
||||
uint32_t :4;
|
||||
uint32_t HW :2;
|
||||
);
|
||||
|
||||
typedef volatile struct
|
||||
{
|
||||
lword_union(CMNCR,
|
||||
uint32_t :6;
|
||||
uint32_t CKOSTP :1;
|
||||
uint32_t CKODRV :1;
|
||||
uint32_t :7;
|
||||
uint32_t DMSTP :1;
|
||||
uint32_t :1;
|
||||
uint32_t BSD :1;
|
||||
uint32_t MAP :2;
|
||||
uint32_t BLOCK :1;
|
||||
uint32_t :7;
|
||||
uint32_t ENDIAN :1;
|
||||
uint32_t :1;
|
||||
uint32_t HIZMEM :1;
|
||||
uint32_t HIZCNT :1;
|
||||
);
|
||||
|
||||
sh7305_bsc_CSnBCR_t CS0BCR;
|
||||
sh7305_bsc_CSnBCR_t CS2BCR;
|
||||
sh7305_bsc_CSnBCR_t CS3BCR;
|
||||
sh7305_bsc_CSnBCR_t CS4BCR;
|
||||
sh7305_bsc_CSnBCR_t CS5ABCR;
|
||||
sh7305_bsc_CSnBCR_t CS5BBCR;
|
||||
sh7305_bsc_CSnBCR_t CS6ABCR;
|
||||
sh7305_bsc_CSnBCR_t CS6BBCR;
|
||||
|
||||
sh7305_bsc_CSnWCR_06A6B_t CS0WCR;
|
||||
lword_union(CS2WCR,
|
||||
uint32_t :8;
|
||||
uint32_t BW :2;
|
||||
uint32_t PMD :1;
|
||||
uint32_t BAS :1;
|
||||
uint32_t :1;
|
||||
uint32_t WW :3;
|
||||
uint32_t :3;
|
||||
uint32_t SW :2;
|
||||
uint32_t WR :4;
|
||||
uint32_t WM :1;
|
||||
uint32_t :4;
|
||||
uint32_t HW :2;
|
||||
);
|
||||
lword_union(CS3WCR,
|
||||
uint32_t :17;
|
||||
uint32_t TRP :2;
|
||||
uint32_t :1;
|
||||
uint32_t TRCD :2;
|
||||
uint32_t :1;
|
||||
uint32_t A3CL :2;
|
||||
uint32_t :2;
|
||||
uint32_t TRWL :2;
|
||||
uint32_t :1;
|
||||
uint32_t TRC :2;
|
||||
);
|
||||
sh7305_bsc_CSnWCR_45A5B_t CS4WCR;
|
||||
sh7305_bsc_CSnWCR_45A5B_t CS5AWCR;
|
||||
sh7305_bsc_CSnWCR_45A5B_t CS5BWCR;
|
||||
sh7305_bsc_CSnWCR_06A6B_t CS6AWCR;
|
||||
sh7305_bsc_CSnWCR_06A6B_t CS6BWCR;
|
||||
|
||||
lword_union(SDCR,
|
||||
uint32_t :11;
|
||||
uint32_t A2ROW :2;
|
||||
uint32_t :1;
|
||||
uint32_t A2COL :2;
|
||||
uint32_t :4;
|
||||
uint32_t RFSH :1;
|
||||
uint32_t RMODE :1;
|
||||
uint32_t PDOWN :1;
|
||||
uint32_t BACTV :1;
|
||||
uint32_t :3;
|
||||
uint32_t A3ROW :2;
|
||||
uint32_t :1;
|
||||
uint32_t A3COL :2;
|
||||
);
|
||||
|
||||
uint32_t RTCSR;
|
||||
uint32_t RTCNT;
|
||||
uint32_t RTCOR;
|
||||
|
||||
} GPACKED(4) sh7305_bsc_t;
|
||||
|
||||
#define SH7305_BSC (*(sh7305_bsc_t *)0xfec10000)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_BSC */
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_MPU_CPG
|
||||
#define GINT_MPU_CPG
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
|
@ -28,6 +32,12 @@ typedef volatile struct
|
|||
uint16_t PFC :2; /* Peripheral clock divider */
|
||||
);
|
||||
|
||||
byte_union(UCLKCR,
|
||||
uint8_t USSCS :2; /* Source Clock Selection Bit */
|
||||
uint8_t USBEN :1; /* USB On-Chip Oscillator Enable */
|
||||
uint8_t :5;
|
||||
);
|
||||
|
||||
} GPACKED(4) sh7705_cpg_t;
|
||||
|
||||
#define SH7705_CPG (*((sh7705_cpg_t *)0xffffff80))
|
||||
|
@ -43,7 +53,7 @@ typedef volatile struct
|
|||
documentation. */
|
||||
typedef volatile struct
|
||||
{
|
||||
lword_union(FRQCRA,
|
||||
lword_union(FRQCR,
|
||||
uint32_t KICK :1; /* Flush FRQCRA modifications */
|
||||
uint32_t :1;
|
||||
uint32_t STC :6; /* PLL multiplication [*] */
|
||||
|
@ -64,7 +74,15 @@ typedef volatile struct
|
|||
uint32_t SRC :2; /* Clock source select */
|
||||
uint32_t DIVA :6; /* Division ratio for port A */
|
||||
);
|
||||
pad(0x08);
|
||||
pad(0x04);
|
||||
|
||||
lword_union(DDCLKCR,
|
||||
uint32_t :23;
|
||||
uint32_t CLKSTP :1; /* Clock Stop */
|
||||
uint32_t _ :1; /* Unknown */
|
||||
uint32_t :1;
|
||||
uint32_t DIV :6;
|
||||
);
|
||||
|
||||
lword_union(USBCLKCR,
|
||||
uint32_t :23;
|
||||
|
@ -82,7 +100,9 @@ typedef volatile struct
|
|||
uint32_t CKOFF :1; /* CKO Output Stop */
|
||||
uint32_t :1;
|
||||
);
|
||||
pad(0x14);
|
||||
|
||||
uint32_t PLL2CR;
|
||||
pad(0x10);
|
||||
|
||||
lword_union(SPUCLKCR,
|
||||
uint32_t :23;
|
||||
|
@ -105,9 +125,16 @@ typedef volatile struct
|
|||
uint32_t :3;
|
||||
uint32_t FLF :11; /* FLL Multiplication Ratio */
|
||||
);
|
||||
pad(0x0c);
|
||||
|
||||
uint32_t LSTATS;
|
||||
|
||||
} GPACKED(4) sh7305_cpg_t;
|
||||
|
||||
#define SH7305_CPG (*((sh7305_cpg_t *)0xa4150000))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_CPG */
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#ifndef GINT_MPU_DMA
|
||||
#define GINT_MPU_DMA
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
//---
|
||||
|
@ -86,4 +90,8 @@ typedef volatile struct
|
|||
|
||||
#define SH7305_DMA (*((sh7305_dma_t *)0xfe008020))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_DMA */
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
#ifndef GINT_MPU_INTC
|
||||
#define GINT_MPU_INTC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
//---
|
||||
|
@ -294,7 +298,11 @@ typedef struct
|
|||
//---
|
||||
|
||||
/* Provided by intc/intc.c */
|
||||
extern sh7705_intc_t SH7705_INTC;
|
||||
extern sh7305_intc_t SH7305_INTC;
|
||||
extern sh7705_intc_t const SH7705_INTC;
|
||||
extern sh7305_intc_t const SH7305_INTC;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_INTC */
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#ifndef GINT_MPU_MMU
|
||||
#define GINT_MPU_MMU
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
|
@ -45,12 +49,10 @@ typedef struct
|
|||
} GPACKED(4) tlb_data_t;
|
||||
|
||||
//---
|
||||
// SH7305 TLB. Refer to:
|
||||
// "Renesas SH7724 User's Manual: Hardware"
|
||||
// Section 7: "Memory Management Unit (MMU)"
|
||||
// SH7305 TLB. Refer to SH4AL-DSP manual, section 7 (MMU)
|
||||
//---
|
||||
|
||||
/* utlb_addr_t - address part of a UTLB entry */
|
||||
/* utlb_addr_t: Address part of a UTLB entry */
|
||||
typedef struct
|
||||
{
|
||||
uint VPN :22;
|
||||
|
@ -60,7 +62,7 @@ typedef struct
|
|||
|
||||
} GPACKED(4) utlb_addr_t;
|
||||
|
||||
/* utlb_data_t - data part of a UTLB entry */
|
||||
/* utlb_data_t: Data part of a UTLB entry */
|
||||
typedef struct
|
||||
{
|
||||
uint :3;
|
||||
|
@ -77,6 +79,34 @@ typedef struct
|
|||
|
||||
} GPACKED(4) utlb_data_t;
|
||||
|
||||
/* itlb_addr_t: Address part of an ITLB entry */
|
||||
typedef struct
|
||||
{
|
||||
uint VPN :22;
|
||||
uint :1;
|
||||
uint V :1;
|
||||
uint ASID :8;
|
||||
|
||||
} GPACKED(4) itlb_addr_t;
|
||||
|
||||
/* itlb_data_t: Data part of an ITLB entry */
|
||||
typedef struct
|
||||
{
|
||||
uint :3;
|
||||
uint PPN :19;
|
||||
uint :1;
|
||||
uint V :1;
|
||||
uint SZ1 :1;
|
||||
uint PR :1;
|
||||
uint :1;
|
||||
uint SZ0 :1;
|
||||
uint C :1;
|
||||
uint :1;
|
||||
uint SH :1;
|
||||
uint :1;
|
||||
|
||||
} GPACKED(4) itlb_data_t;
|
||||
|
||||
typedef volatile struct
|
||||
{
|
||||
lword_union(PTEH,
|
||||
|
@ -152,4 +182,8 @@ typedef volatile struct
|
|||
|
||||
#define SH7305_MMU (*(sh7305_mmu_t *)0xff000000)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_MMU */
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#ifndef GINT_MPU_PFC
|
||||
#define GINT_MPU_PFC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
|
@ -72,7 +76,164 @@ typedef volatile struct
|
|||
#define SH7705_PFC (*((sh7705_pfc_t *)0xa4000100))
|
||||
|
||||
//---
|
||||
// TODO: Document the SH7305 Pin Function Controller
|
||||
// SH7305 Pin Function Controller.
|
||||
// This is somewhat reminiscent of the SH7724, but there are many differences.
|
||||
// The official emulator is the basis for this module.
|
||||
//---
|
||||
|
||||
/* All port control registers (PCRx) have 2-bit entries specifying 4 pin modes:
|
||||
00: Special functions
|
||||
01: Output
|
||||
10: Input (pull-up ON)
|
||||
11: Input (pull-up OFF)
|
||||
|
||||
Some pins do not accept all settings. The SH7724 has these exceptions:
|
||||
- PGCR (all pins): Input now allowed (00 and 01 only)
|
||||
- PJCR.P5MD/P6MD/P7MD: Input not allowed (00 and 01 only)
|
||||
|
||||
Also, some entries are not configurable or are not mapped to actual pins.
|
||||
Again the SH7724 has these exceptions:
|
||||
- PGCR.P6MD/P7MD: No setting
|
||||
- PJCR.P4MD: No setting
|
||||
- PSCR.P7MD: No setting */
|
||||
typedef volatile word_union(sh7305_pfc_control_t,
|
||||
uint16_t P7MD :2;
|
||||
uint16_t P6MD :2;
|
||||
uint16_t P5MD :2;
|
||||
uint16_t P4MD :2;
|
||||
uint16_t P3MD :2;
|
||||
uint16_t P2MD :2;
|
||||
uint16_t P1MD :2;
|
||||
uint16_t P0MD :2;
|
||||
);
|
||||
|
||||
/* Data register; a plain 8-bit value. Each bit can be either read or written
|
||||
depending on the mode of the corresponding pin. */
|
||||
typedef volatile byte_union(sh7305_pfc_data_t,
|
||||
uint8_t P7DT :1;
|
||||
uint8_t P6DT :1;
|
||||
uint8_t P5DT :1;
|
||||
uint8_t P4DT :1;
|
||||
uint8_t P3DT :1;
|
||||
uint8_t P2DT :1;
|
||||
uint8_t P1DT :1;
|
||||
uint8_t P0DT :1;
|
||||
);
|
||||
|
||||
typedef volatile struct
|
||||
{
|
||||
sh7305_pfc_control_t
|
||||
PACR, PBCR, PCCR, PDCR, PECR, PFCR, PGCR, PHCR,
|
||||
PJCR, PKCR, PLCR, PMCR, PNCR, PQCR, PRCR, PSCR;
|
||||
|
||||
sh7305_pfc_data_t PADR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PBDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PCDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PDDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PEDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PFDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PGDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PHDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PJDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PKDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PLDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PMDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PNDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PQDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PRDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PSDR;
|
||||
pad(1);
|
||||
|
||||
sh7305_pfc_control_t PTCR;
|
||||
sh7305_pfc_control_t PUCR;
|
||||
sh7305_pfc_control_t PVCR;
|
||||
pad(6);
|
||||
sh7305_pfc_control_t PPCR;
|
||||
|
||||
/* PSEM*: Multiplexing pin settings. These are highly MPU-dependent and
|
||||
the assignment is basically unknown.
|
||||
HIZCR*: High-impedance settings for pins' I/O buffers. */
|
||||
uint16_t PSELA;
|
||||
uint16_t PSELB;
|
||||
uint16_t PSELC;
|
||||
uint16_t PSELD;
|
||||
uint16_t PSELE;
|
||||
uint16_t HIZCRA;
|
||||
uint16_t HIZCRB;
|
||||
uint16_t HIZCRC;
|
||||
uint16_t PSELF;
|
||||
|
||||
sh7305_pfc_data_t PTDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PUDR;
|
||||
pad(1);
|
||||
sh7305_pfc_data_t PVDR;
|
||||
pad(5);
|
||||
sh7305_pfc_data_t PPDR;
|
||||
pad(0x15);
|
||||
|
||||
/* Module function selection registers.
|
||||
WARNING: These are the SH7724 bits, not necessarily the SH7305! */
|
||||
word_union(MSELCRA,
|
||||
uint16_t :8;
|
||||
uint16_t UNKNOWN_USB :2;
|
||||
uint16_t :6;
|
||||
);
|
||||
word_union(MSELCRB,
|
||||
uint16_t XTAL_USB :2;
|
||||
uint16_t :6;
|
||||
uint16_t SCIF2_PORT :1;
|
||||
uint16_t :1;
|
||||
uint16_t SCIF3_PORT :1;
|
||||
uint16_t :3;
|
||||
uint16_t LDC_VSYNC_DIR :1;
|
||||
uint16_t :1;
|
||||
);
|
||||
|
||||
// TODO: Doc
|
||||
uint16_t DRVCRD, DRVCRA, DRVCRB, DRVCRC;
|
||||
pad(4);
|
||||
|
||||
/* Pull-up control registers. Not sure what these are since that's
|
||||
normally handled in the modes for P*CR? */
|
||||
uint8_t PULCRA, PULCRB, PULCRC, PULCRD, PULCRE, PULCRF, PULCRG,
|
||||
PULCRH, PULCRJ, PULCRK, PULCRL, PULCRM, PULCRN, PULCRQ,
|
||||
PULCRR, PULCRS;
|
||||
pad(0x20);
|
||||
uint8_t PULCRT;
|
||||
uint8_t PULCRU;
|
||||
uint8_t PULCRV;
|
||||
uint8_t PULCRBSC;
|
||||
pad(1);
|
||||
uint8_t PULCRTRST;
|
||||
uint8_t PULCRP;
|
||||
pad(1);
|
||||
|
||||
uint16_t PSELG;
|
||||
pad(12);
|
||||
uint16_t PSELH;
|
||||
|
||||
} sh7305_pfc_t;
|
||||
|
||||
#define SH7305_PFC (*((sh7305_pfc_t *)0xa4050100))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_PFC */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_MPU_POWER
|
||||
#define GINT_MPU_POWER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
//---
|
||||
|
@ -103,4 +107,8 @@ typedef volatile struct
|
|||
|
||||
#define SH7305_POWER (*((sh7305_power_t *)0xa4150020))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_POWER */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_MPU_RTC
|
||||
#define GINT_MPU_RTC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/attributes.h>
|
||||
|
||||
//---
|
||||
|
@ -75,4 +79,8 @@ typedef volatile struct
|
|||
#define SH7705_RTC (*((rtc_t *)0xfffffec0))
|
||||
#define SH7305_RTC (*((rtc_t *)0xa413fec0))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_RTC */
|
||||
|
|
218
include/gint/mpu/scif.h
Normal file
218
include/gint/mpu/scif.h
Normal file
|
@ -0,0 +1,218 @@
|
|||
//---
|
||||
// gint:mpu:scif - Serial Communication Interface with FIFO (SCIF)
|
||||
//---
|
||||
|
||||
#ifndef GINT_MPU_SCIF
|
||||
#define GINT_MPU_SCIF
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
//---
|
||||
// SH7705 SCIF (from: SH7705 manual, section 16)
|
||||
//---
|
||||
|
||||
typedef volatile struct
|
||||
{
|
||||
/* Serial Mode Register */
|
||||
word_union(SCSMR,
|
||||
uint16_t :5;
|
||||
uint16_t SRC :3; /* Sampling Control */
|
||||
uint16_t CA :1; /* Communication Mode */
|
||||
uint16_t CHR :1; /* Character Length */
|
||||
uint16_t PE :1; /* Parity Enable */
|
||||
uint16_t OE :1; /* Parity Mode */
|
||||
uint16_t STOP :1; /* Stop Bit Length */
|
||||
uint16_t :1;
|
||||
uint16_t CKS :2; /* Clock Select */
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
/* Bit Rate Register */
|
||||
uint8_t SCBRR;
|
||||
pad(0x3);
|
||||
|
||||
/* Serial Control Register */
|
||||
word_union(SCSCR,
|
||||
uint16_t :4;
|
||||
uint16_t TSIE :1; /* Transmit Data Stop Interrupt Enable */
|
||||
uint16_t ERIE :1; /* Receive Error Interrupt Enable */
|
||||
uint16_t BRIE :1; /* Break Interrupt Enable */
|
||||
uint16_t DRIE :1; /* Receive Data Ready Interrupt Enable */
|
||||
uint16_t TIE :1; /* Transmit Interrupt Enable */
|
||||
uint16_t RIE :1; /* Receive Interrupt Enable */
|
||||
uint16_t TE :1; /* Transmit Enable */
|
||||
uint16_t RE :1; /* Receive Mode */
|
||||
uint16_t :2;
|
||||
uint16_t CKE :2; /* Clock Enable */
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
/* Transmit Data Stop Register */
|
||||
uint8_t SCTDSR;
|
||||
pad(0x3);
|
||||
|
||||
/* FIFO Error Count Register */
|
||||
word_union(SCFER,
|
||||
uint16_t :2;
|
||||
uint16_t PER :6; /* Parity Error Count */
|
||||
uint16_t :2;
|
||||
uint16_t FER :6; /* Framing Error Count */
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
/* Serial Status Register */
|
||||
word_union(SCSSR,
|
||||
uint16_t :6;
|
||||
uint16_t ORER :1; /* Overrun Error */
|
||||
uint16_t TSF :1; /* Transmit Data Stop */
|
||||
uint16_t ER :1; /* Receive Error */
|
||||
uint16_t TEND :1; /* Transmit End */
|
||||
uint16_t TDFE :1; /* Transmit FIFO Data Empty */
|
||||
uint16_t BRK :1; /* Break Detect */
|
||||
uint16_t FER :1; /* Framing Error */
|
||||
uint16_t PER :1; /* Parity Error */
|
||||
uint16_t RDF :1; /* Receive FIFO Data Full */
|
||||
uint16_t DR :1; /* Receive Data Ready */
|
||||
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
/* FIFO Control Register */
|
||||
word_union(SCFCR,
|
||||
uint16_t TSE :1; /* Transmit Data Stop Enable */
|
||||
uint16_t TCRST :1; /* Transmit Count Reset */
|
||||
uint16_t :3;
|
||||
uint16_t RSTRG :3; /* RTS Output Active Trigger */
|
||||
uint16_t RTRG :2; /* Receive FIFO Data Number Trigger */
|
||||
uint16_t TTRG :2; /* Transmit FIFO Data Number Trigger */
|
||||
uint16_t MCE :1; /* Modem Control Enable */
|
||||
uint16_t TFRST :1; /* Transmit FIFO Data Register Reset */
|
||||
uint16_t RFRST :1; /* Receive FIFO Data Register Reset */
|
||||
uint16_t LOOP :1; /* Loopback Test */
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
/* FIFO Data Count Register */
|
||||
word_union(SCFDR,
|
||||
uint16_t :1;
|
||||
uint16_t T :7; /* Pending bytes in transmit FIFO */
|
||||
uint16_t :1;
|
||||
uint16_t R :7; /* Received bytes in receive FIFO */
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
/* Serial FIFO Transmit Data Register (64 bytes rolling register) */
|
||||
uint8_t SCFTDR;
|
||||
pad(0x3);
|
||||
|
||||
/* Serial FIFO Receive Data Register (64 bytes rolling register) */
|
||||
uint8_t SCFRDR;
|
||||
|
||||
} GPACKED(4) sh7705_scif_t;
|
||||
|
||||
#define SH7705_SCIF (*((sh7705_scif_t *)0xa4410000))
|
||||
|
||||
//---
|
||||
// SH7305 SCIF (from: SH7305 emulator and SH7730 SCIF)
|
||||
// The module is very close to the SH7724 but it has a couple extra bits in
|
||||
// SCFCR, which shows that it is closer to the SH7730 SCIF.
|
||||
//---
|
||||
|
||||
typedef volatile struct
|
||||
{
|
||||
/* Serial Mode Register */
|
||||
word_union(SCSMR,
|
||||
uint16_t :8;
|
||||
uint16_t CA :1; /* Communication Mode */
|
||||
uint16_t CHR :1; /* Character Length */
|
||||
uint16_t PE :1; /* Parity Enable */
|
||||
uint16_t OE :1; /* Parity Mode */
|
||||
uint16_t STOP :1; /* Stop Bit Length */
|
||||
uint16_t :1;
|
||||
uint16_t CKS :2; /* Clock Select */
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
/* Serial Bit Rate Register */
|
||||
uint8_t SCBRR;
|
||||
pad(0x3);
|
||||
|
||||
/* Serial Control Register */
|
||||
word_union(SCSCR,
|
||||
uint16_t :8;
|
||||
uint16_t TIE :1; /* Transmit Interrupt Enable */
|
||||
uint16_t RIE :1; /* Receive Interrupt Enable */
|
||||
uint16_t TE :1; /* Transmit Enable */
|
||||
uint16_t RE :1; /* Receive Mode */
|
||||
uint16_t REIE :1; /* Receive Error Interrupt Enable */
|
||||
uint16_t :1;
|
||||
uint16_t CKE :2; /* Clock Enable */
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
/* Serial FIFO Transmit Data Register */
|
||||
uint8_t SCFTDR;
|
||||
pad(0x3);
|
||||
|
||||
/* Serial FIFO Status Register */
|
||||
word_union(SCFSR,
|
||||
uint16_t const PERC :4; /* Number of Parity Errors */
|
||||
uint16_t const FERC :4; /* Number of Framing Errors */
|
||||
uint16_t ER :1; /* Receive Error */
|
||||
uint16_t TEND :1; /* Transmit End */
|
||||
uint16_t TDFE :1; /* Transmit FIFO Data Empty */
|
||||
uint16_t BRK :1; /* Break Detection */
|
||||
uint16_t const FER :1; /* Framing Error */
|
||||
uint16_t const PER :1; /* Parity Error */
|
||||
uint16_t RDF :1; /* Receive FIFO Data Full */
|
||||
uint16_t DR :1; /* Data Ready */
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
/* Serial FIFO Receive Data Register */
|
||||
uint8_t SCFRDR;
|
||||
pad(0x3);
|
||||
|
||||
/* Serial FIFO Control Register */
|
||||
word_union(SCFCR,
|
||||
uint16_t :5;
|
||||
uint16_t RSTRG :3; /* RTS Output Active Trigger */
|
||||
uint16_t RTRG :2; /* Receive FIFO Data Trigger */
|
||||
uint16_t TTRG :2; /* Transmit FIFO Data Trigger */
|
||||
uint16_t MCE :1; /* Model Control Enable */
|
||||
uint16_t TFRST :1; /* Transmit FIFO Data Register Reset */
|
||||
uint16_t RFRST :1; /* Receive FIFO Data Register Reset */
|
||||
uint16_t LOOP :1; /* Loopback Test */
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
/* Serial FIFO Data Count Register */
|
||||
word_union(SCFDR,
|
||||
uint16_t :3;
|
||||
uint16_t TFDC :5; /* Number of Data Bytes in Transmit FIFO */
|
||||
uint16_t :3;
|
||||
uint16_t RFDC :5; /* Number of Data Bytes in Receive FIFO */
|
||||
);
|
||||
pad(0x6);
|
||||
|
||||
/* Serial Line Status */
|
||||
word_union(SCLSR,
|
||||
uint16_t :15;
|
||||
uint16_t ORER :1; /* Overrun Error */
|
||||
);
|
||||
pad(0x2);
|
||||
|
||||
} GPACKED(4) sh7305_scif_t;
|
||||
|
||||
#define SH7305_SCIF (*((sh7305_scif_t *)0xa4410000))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_SCIF */
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_MPU_SPU
|
||||
#define GINT_MPU_SPU
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
typedef volatile struct
|
||||
|
@ -94,4 +98,8 @@ typedef volatile struct
|
|||
#define SH7305_DSP0 (*(spu_dsp_t *)0xfe2ffd00)
|
||||
#define SH7305_DSP1 (*(spu_dsp_t *)0xfe3ffd00)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_SPU */
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#ifndef GINT_MPU_TMU
|
||||
#define GINT_MPU_TMU
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
//---
|
||||
|
@ -101,4 +105,8 @@ typedef volatile struct
|
|||
typedef volatile etmu_t sh7305_etmu_t[6];
|
||||
#define SH7305_ETMU (*(sh7305_etmu_t *)0xa44d0030)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_TMU */
|
||||
|
|
90
include/gint/mpu/ubc.h
Normal file
90
include/gint/mpu/ubc.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
//---
|
||||
// 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 */
|
|
@ -5,8 +5,25 @@
|
|||
#ifndef GINT_MPU_USB
|
||||
#define GINT_MPU_USB
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
word_union(TRE,
|
||||
uint16_t :6;
|
||||
uint16_t TRENB :1; /* Transaction Counter Enable */
|
||||
uint16_t TRCLR :1; /* Transaction Counter Clear */
|
||||
uint16_t :8;
|
||||
);
|
||||
word_union(TRN,
|
||||
uint16_t TRCNT :16; /* Transaction Counter */
|
||||
);
|
||||
} sh7305_usb_pipetr;
|
||||
|
||||
typedef volatile struct
|
||||
{
|
||||
/* System Configuration Control Register */
|
||||
|
@ -24,12 +41,16 @@ typedef volatile struct
|
|||
|
||||
/* CPU Bus Wait Setting Register */
|
||||
word_union(BUSWAIT,
|
||||
uint16_t :12;
|
||||
uint16_t :8;
|
||||
uint16_t _1 :1; /* Unknown role; can be set */
|
||||
uint16_t :1;
|
||||
uint16_t _2 :1; /* Unknown role; can be set */
|
||||
uint16_t :1;
|
||||
uint16_t BWAIT :4; /* Bus Wait */
|
||||
);
|
||||
|
||||
/* System Configuration Status Register */
|
||||
word_union(SYSSTS,
|
||||
const word_union(SYSSTS,
|
||||
uint16_t :14;
|
||||
uint16_t LNST :2; /* Line Status */
|
||||
);
|
||||
|
@ -37,7 +58,9 @@ typedef volatile struct
|
|||
|
||||
/* Device State Control Register */
|
||||
word_union(DVSTCTR,
|
||||
uint16_t :7;
|
||||
uint16_t _1 :1; /* Unknown role; can be set */
|
||||
uint16_t :2;
|
||||
uint16_t _2 :4; /* Unknown role; can be set */
|
||||
uint16_t WKUP :1; /* Wakeup Output */
|
||||
uint16_t RWUPE :1; /* Wakeup Detection Enable */
|
||||
uint16_t USBRT :1; /* USB Reset Output */
|
||||
|
@ -88,8 +111,9 @@ typedef volatile struct
|
|||
uint16_t DREQE :1; /* DMA Transfert Request Enable */
|
||||
uint16_t MBW :2; /* Access Bits Width */
|
||||
uint16_t :1;
|
||||
uint16_t BIGEND :1; /* Endiant Control */
|
||||
uint16_t :4;
|
||||
uint16_t BIGEND :1; /* Endian Control */
|
||||
uint16_t _1 :1; /* Unknown role; can be set */
|
||||
uint16_t :3;
|
||||
uint16_t CURPIPE:4; /* Port Access Pipe Specification */
|
||||
);
|
||||
word_union(D0FIFOCTR,
|
||||
|
@ -107,7 +131,8 @@ typedef volatile struct
|
|||
uint16_t MBW :2; /* Access Bits Width */
|
||||
uint16_t :1;
|
||||
uint16_t BIGEND :1; /* Endian Control */
|
||||
uint16_t :4;
|
||||
uint16_t _1 :1; /* Unknown role; can be set */
|
||||
uint16_t :3;
|
||||
uint16_t CURPIPE:4; /* Port Access Pipe Specification */
|
||||
);
|
||||
word_union(D1FIFOCTR,
|
||||
|
@ -130,50 +155,26 @@ typedef volatile struct
|
|||
uint16_t BRDYE :1; /* Buffer Ready */
|
||||
uint16_t :8;
|
||||
);
|
||||
pad(4);
|
||||
word_union(INTENB1,
|
||||
uint16_t _1 :1; /* Unknown role; can be set */
|
||||
uint16_t BCHGE :1; /* Bus Change */
|
||||
uint16_t :1;
|
||||
uint16_t DTCHE :1; /* Disconnection Detection */
|
||||
uint16_t ATTCHE :1; /* Connection Detection */
|
||||
uint16_t :4;
|
||||
uint16_t EOFERRE:1; /* EOF Error Detection */
|
||||
uint16_t SIGNE :1; /* Setup Transaction Error */
|
||||
uint16_t SACKE :1; /* Setup Transaction Normal Response */
|
||||
uint16_t :4;
|
||||
);
|
||||
pad(2);
|
||||
|
||||
/* BRDY Interrupt Enable Register */
|
||||
word_union(BRDYENB,
|
||||
uint16_t :6;
|
||||
uint16_t PIPE9BRDYE :1;
|
||||
uint16_t PIPE8BRDYE :1;
|
||||
uint16_t PIPE6BRDYE :1;
|
||||
uint16_t PIPE7BRDYE :1;
|
||||
uint16_t PIPE5BRDYE :1;
|
||||
uint16_t PIPE3BRDYE :1;
|
||||
uint16_t PIPE4BRDYE :1;
|
||||
uint16_t PIPE2BRDYE :1;
|
||||
uint16_t PIPE1BRDYE :1;
|
||||
uint16_t PIPE0BRDYE :1;
|
||||
);
|
||||
uint16_t BRDYENB;
|
||||
/* NRDY Interrupt Enable Register */
|
||||
word_union(NRDYENB,
|
||||
uint16_t :6;
|
||||
uint16_t PIPE9NRDYE :1;
|
||||
uint16_t PIPE8NRDYE :1;
|
||||
uint16_t PIPE6NRDYE :1;
|
||||
uint16_t PIPE7NRDYE :1;
|
||||
uint16_t PIPE5NRDYE :1;
|
||||
uint16_t PIPE3NRDYE :1;
|
||||
uint16_t PIPE4NRDYE :1;
|
||||
uint16_t PIPE2NRDYE :1;
|
||||
uint16_t PIPE1NRDYE :1;
|
||||
uint16_t PIPE0NRDYE :1;
|
||||
);
|
||||
uint16_t NRDYENB;
|
||||
/* BEMP Interrupt Enable Register */
|
||||
word_union(BEMPENB,
|
||||
uint16_t :6;
|
||||
uint16_t PIPE9BEMPE :1;
|
||||
uint16_t PIPE8BEMPE :1;
|
||||
uint16_t PIPE6BEMPE :1;
|
||||
uint16_t PIPE7BEMPE :1;
|
||||
uint16_t PIPE5BEMPE :1;
|
||||
uint16_t PIPE3BEMPE :1;
|
||||
uint16_t PIPE4BEMPE :1;
|
||||
uint16_t PIPE2BEMPE :1;
|
||||
uint16_t PIPE1BEMPE :1;
|
||||
uint16_t PIPE0BEMPE :1;
|
||||
);
|
||||
uint16_t BEMPENB;
|
||||
|
||||
/* SOF Control Register */
|
||||
word_union(SOFCFG,
|
||||
|
@ -182,7 +183,10 @@ typedef volatile struct
|
|||
uint16_t :1;
|
||||
uint16_t BRDYM :1; /* BRDY Status Clear Timing */
|
||||
uint16_t enable :1; /* SHOULD BE SET TO 1 MANUALLY */
|
||||
uint16_t :5;
|
||||
uint16_t :1;
|
||||
uint16_t _1 :1; /* Unknown role; can be set */
|
||||
uint16_t _2 :1; /* Unknown role; can be set */
|
||||
uint16_t :2;
|
||||
);
|
||||
pad(2);
|
||||
|
||||
|
@ -201,56 +205,32 @@ typedef volatile struct
|
|||
uint16_t VALID :1; /* USB Request Reception */
|
||||
uint16_t CTSQ :3; /* Control Transfer Stage */
|
||||
);
|
||||
pad(4);
|
||||
word_union(INTSTS1,
|
||||
uint16_t _1 :1; /* Unknown role */
|
||||
uint16_t BCHG :1; /* Bus Change */
|
||||
uint16_t :1;
|
||||
uint16_t DTCH :1; /* Disconnection Detection */
|
||||
uint16_t ATTCH :1; /* Connection Detection */
|
||||
uint16_t :4;
|
||||
uint16_t EOFERR :1; /* EOF Error Detection */
|
||||
uint16_t SIGN :1; /* Setup Transaction Error */
|
||||
uint16_t SACK :1; /* Setup Transaction Normal Response */
|
||||
uint16_t :4;
|
||||
);
|
||||
pad(2);
|
||||
|
||||
/* BRDY Interrupt Status Register */
|
||||
word_union(BRDYSTS,
|
||||
uint16_t :6;
|
||||
uint16_t PIPE9BRDY :1;
|
||||
uint16_t PIPE8BRDY :1;
|
||||
uint16_t PIPE6BRDY :1;
|
||||
uint16_t PIPE7BRDY :1;
|
||||
uint16_t PIPE5BRDY :1;
|
||||
uint16_t PIPE3BRDY :1;
|
||||
uint16_t PIPE4BRDY :1;
|
||||
uint16_t PIPE2BRDY :1;
|
||||
uint16_t PIPE1BRDY :1;
|
||||
uint16_t PIPE0BRDY :1;
|
||||
);
|
||||
uint16_t BRDYSTS;
|
||||
/* NRDY Interrupt Status Register */
|
||||
word_union(NRDYSTS,
|
||||
uint16_t :6;
|
||||
uint16_t PIPE9NRDY :1;
|
||||
uint16_t PIPE8NRDY :1;
|
||||
uint16_t PIPE6NRDY :1;
|
||||
uint16_t PIPE7NRDY :1;
|
||||
uint16_t PIPE5NRDY :1;
|
||||
uint16_t PIPE3NRDY :1;
|
||||
uint16_t PIPE4NRDY :1;
|
||||
uint16_t PIPE2NRDY :1;
|
||||
uint16_t PIPE1NRDY :1;
|
||||
uint16_t PIPE0NRDY :1;
|
||||
);
|
||||
uint16_t NRDYSTS;
|
||||
/* BEMP Interrupt Status Register */
|
||||
word_union(BEMPSTS,
|
||||
uint16_t :6;
|
||||
uint16_t PIPE9BEMP :1;
|
||||
uint16_t PIPE8BEMP :1;
|
||||
uint16_t PIPE6BEMP :1;
|
||||
uint16_t PIPE7BEMP :1;
|
||||
uint16_t PIPE5BEMP :1;
|
||||
uint16_t PIPE3BEMP :1;
|
||||
uint16_t PIPE4BEMP :1;
|
||||
uint16_t PIPE2BEMP :1;
|
||||
uint16_t PIPE1BEMP :1;
|
||||
uint16_t PIPE0BEMP :1;
|
||||
);
|
||||
uint16_t BEMPSTS;
|
||||
|
||||
/* Frame Number Registers */
|
||||
word_union(FRMNUM,
|
||||
uint16_t OVRN :1; /* Overrun/Underrun Detection Status */
|
||||
uint16_t CRCE :1; /* Receive Data Error */
|
||||
uint16_t cons :3;
|
||||
uint16_t const :3;
|
||||
uint16_t FRNM :11; /* Frame Number */
|
||||
);
|
||||
word_union(UFRMNUM,
|
||||
|
@ -285,7 +265,10 @@ typedef volatile struct
|
|||
|
||||
/* DCP Configuration Register */
|
||||
word_union(DCPCFG,
|
||||
uint16_t :11;
|
||||
uint16_t :7;
|
||||
uint16_t _1 :1; /* Unknown role; can be set */
|
||||
uint16_t _2 :1; /* Unknown role; can be set */
|
||||
uint16_t :2;
|
||||
uint16_t DIR :1; /* Transfer Direction */
|
||||
uint16_t :4;
|
||||
);
|
||||
|
@ -337,7 +320,7 @@ typedef volatile struct
|
|||
/* Pipe Buffer Setting Register */
|
||||
word_union(PIPEBUF,
|
||||
uint16_t :1;
|
||||
uint16_t BUFSIZE : 5; /* Buffer Size */
|
||||
uint16_t BUFSIZE:5; /* Buffer Size */
|
||||
uint16_t :2;
|
||||
uint16_t BUFNMB :8; /* Buffer Number */
|
||||
);
|
||||
|
@ -375,56 +358,20 @@ typedef volatile struct
|
|||
);
|
||||
pad(14);
|
||||
|
||||
/* PIPEn Transaction Counter Enable Registers and */
|
||||
/* PIPEn Transaction Counter Registers */
|
||||
word_union(PIPE1TRE,
|
||||
uint16_t :6;
|
||||
uint16_t TRENB :1; /* Transaction Counter Enable */
|
||||
uint16_t TRCLR :1; /* Transaction Counter Clear */
|
||||
uint16_t :8;
|
||||
);
|
||||
word_union(PIPE1TRN,
|
||||
uint16_t TRCNT :16; /* Transaction Counter */
|
||||
);
|
||||
word_union(PIPE2TRE,
|
||||
uint16_t :6;
|
||||
uint16_t TRENB :1; /* Transaction Counter Enable */
|
||||
uint16_t TRCLR :1; /* Transaction Counter Clear */
|
||||
uint16_t :8;
|
||||
);
|
||||
word_union(PIPE2TRN,
|
||||
uint16_t TRCNT :16; /* Transaction Counter */
|
||||
);
|
||||
word_union(PIPE3TRE,
|
||||
uint16_t :6;
|
||||
uint16_t TRENB :1; /* Transaction Counter Enable */
|
||||
uint16_t TRCLR :1; /* Transaction Counter Clear */
|
||||
uint16_t :8;
|
||||
);
|
||||
word_union(PIPE3TRN,
|
||||
uint16_t TRCNT :16; /* Transaction Counter */
|
||||
);
|
||||
word_union(PIPE4TRE,
|
||||
uint16_t :6;
|
||||
uint16_t TRENB :1; /* Transaction Counter Enable */
|
||||
uint16_t TRCLR :1; /* Transaction Counter Clear */
|
||||
uint16_t :8;
|
||||
);
|
||||
word_union(PIPE4TRN,
|
||||
uint16_t TRCNT :16; /* Transaction Counter */
|
||||
);
|
||||
word_union(PIPE5TRE,
|
||||
uint16_t :6;
|
||||
uint16_t TRENB :1; /* Transaction Counter Enable */
|
||||
uint16_t TRCLR :1; /* Transaction Counter Clear */
|
||||
uint16_t :8;
|
||||
);
|
||||
word_union(PIPE5TRN,
|
||||
uint16_t TRCNT :16; /* Transaction Counter */
|
||||
);
|
||||
/* Transaction Counter Registers (PIPE1..PIPE5 only) */
|
||||
sh7305_usb_pipetr PIPETR[5];
|
||||
pad(0x1e);
|
||||
|
||||
uint16_t REG_C2;
|
||||
pad(12);
|
||||
|
||||
word_union(DEVADD[11],
|
||||
uint16_t :1;
|
||||
uint16_t UPPHUB :4; /* Address of target's hub */
|
||||
uint16_t HUBPORT:3; /* Hub port where target connects */
|
||||
uint16_t USBSPD :2; /* Transfer speed / Target present */
|
||||
uint16_t :6;
|
||||
);
|
||||
|
||||
} GPACKED(4) sh7305_usb_t;
|
||||
|
||||
|
@ -437,4 +384,8 @@ typedef volatile word_union(sh7305_usb_uponcr_t,
|
|||
#define SH7305_USB (*(sh7305_usb_t *)0xa4d80000)
|
||||
#define SH7305_USB_UPONCR (*(sh7305_usb_uponcr_t *)0xa40501d4)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_USB */
|
||||
|
|
52
include/gint/mpu/wdt.h
Normal file
52
include/gint/mpu/wdt.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
//---
|
||||
// gint:mpu:wdt - Watchdog Timer
|
||||
//---
|
||||
|
||||
#ifndef GINT_MPU_WDT
|
||||
#define GINT_MPU_WDT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
//---
|
||||
// SH7705 WatchDog Timer. Refer to:
|
||||
// "Renesas SH7705 Group Hardware Manual"
|
||||
// Section 10: "WatchDog Timer (WDT)"
|
||||
//---
|
||||
|
||||
/* sh7705_wdt_t - Watch Dog Timer */
|
||||
typedef volatile struct
|
||||
{
|
||||
/* WDT registers are unique in access size; reads are performed with
|
||||
8-bit accesses, but writes are performed with 16-bit accesses. */
|
||||
|
||||
union {
|
||||
uint8_t READ;
|
||||
uint16_t WRITE;
|
||||
} WTCNT;
|
||||
|
||||
union {
|
||||
byte_union(READ,
|
||||
uint8_t TME :1; /* Timer Enable */
|
||||
uint8_t WTIT :1; /* Watchdog/Interval Select */
|
||||
uint8_t RSTS :1; /* Watchdog Reset Select */
|
||||
uint8_t WOVF :1; /* Watchdog Overflow Flag */
|
||||
uint8_t IOVF :1; /* Interval Overflow Flag */
|
||||
uint8_t CKS :3; /* Clock Select */
|
||||
);
|
||||
uint16_t WRITE;
|
||||
} WTCSR;
|
||||
|
||||
} sh7705_wdt_t;
|
||||
|
||||
#define SH7705_WDT (*((sh7705_wdt_t *)0xffffff84))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_MPU_WDT */
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_RTC
|
||||
#define GINT_RTC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/defs/call.h>
|
||||
#include <gint/timer.h>
|
||||
|
@ -13,7 +17,11 @@
|
|||
// Time management
|
||||
//---
|
||||
|
||||
/* rtc_time_t: A point in time, representable in the RTC registers */
|
||||
/* rtc_time_t: A point in time, representable in the RTC registers
|
||||
|
||||
WARNING: A copy of this definition is used in fxlibc, make sure to keep it
|
||||
in sync. (We don't install kernel headers before compiling the fxlibc, it's
|
||||
kind of a nightmare for the modest build system.) */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t year; /* Years (exact value, e.g. 2018) */
|
||||
|
@ -96,4 +104,8 @@ int rtc_start_timer(int frequency, timer_callback_t callback, ...);
|
|||
__attribute__((deprecated("Use rtc_periodic_disable() instead")))
|
||||
void rtc_stop_timer(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_RTC */
|
||||
|
|
64
include/gint/serial.h
Normal file
64
include/gint/serial.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
//---
|
||||
// gint:serial - Serial communication
|
||||
//---
|
||||
|
||||
// TODO: This is a template for a future implementation.
|
||||
|
||||
#ifndef GINT_SERIAL
|
||||
#define GINT_SERIAL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/defs/call.h>
|
||||
|
||||
typedef enum {
|
||||
SERIAL_PARITY_NONE,
|
||||
SERIAL_PARITY_EVEN,
|
||||
SERIAL_PARITY_ODD,
|
||||
|
||||
} GPACKEDENUM serial_parity_t;
|
||||
|
||||
typedef struct {
|
||||
/* Baud rate (valid options are 300, 600, 1200, 2400, 4800, 9600,
|
||||
19200, 38400, 57600 and 115200) */
|
||||
int baudrate;
|
||||
/* Parity */
|
||||
serial_parity_t parity;
|
||||
/* Data width (valid options are 7 and 8) */
|
||||
uint8_t data_width;
|
||||
/* Stop bits (valid options are 1 and 2) */
|
||||
uint8_t stop_bits;
|
||||
|
||||
} serial_config_t;
|
||||
|
||||
// TODO: Error management...
|
||||
|
||||
int serial_open(serial_config_t const *config);
|
||||
|
||||
bool serial_is_open(void);
|
||||
|
||||
void serial_write_async(void const *data, size_t size, gint_call_t callback);
|
||||
|
||||
void serial_write_sync(void const *data, size_t size);
|
||||
|
||||
void serial_read_async(void const *data, size_t size, gint_call_t callback);
|
||||
|
||||
void serial_read_sync(void const *data, size_t size);
|
||||
|
||||
// Waits for communications to finish
|
||||
void serial_wait(void);
|
||||
|
||||
// Calls serial_wait() automatically
|
||||
void serial_close(void);
|
||||
|
||||
// TODO: Info on how much data is pending in each buffer?
|
||||
// Ultimately we'll bind this to a file descriptor so we can't really know.
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_SERIAL */
|
|
@ -1,28 +1,2 @@
|
|||
//---
|
||||
// gint:std:endian - Endianness conversion
|
||||
//---
|
||||
|
||||
#ifndef GINT_STD_ENDIAN
|
||||
#define GINT_STD_ENDIAN
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/defs/attributes.h>
|
||||
|
||||
/* CASIO calculators are configured as big-endian. */
|
||||
|
||||
#define htobe16(x) (x)
|
||||
#define htole16(x) (__builtin_bswap16(x))
|
||||
#define be16toh(x) (x)
|
||||
#define le16toh(x) (__builtin_bswap16(x))
|
||||
|
||||
#define htobe32(x) (x)
|
||||
#define htole32(x) (__builtin_bswap32(x))
|
||||
#define be32toh(x) (x)
|
||||
#define le32toh(x) (__builtin_bswap32(x))
|
||||
|
||||
#define htobe64(x) (x)
|
||||
#define htole64(x) (__builtin_bswap64(x))
|
||||
#define be64toh(x) (x)
|
||||
#define le64toh(x) (__builtin_bswap64(x))
|
||||
|
||||
#endif /* GINT_STD_ENDIAN */
|
||||
/* Now provided by fxlibc. */
|
||||
#include <endian.h>
|
||||
|
|
|
@ -1,49 +1,2 @@
|
|||
//---
|
||||
// gint:std:stdio - a few <stdio.h> functions provided by gint
|
||||
//---
|
||||
|
||||
#ifndef GINT_STD_STDIO
|
||||
#define GINT_STD_STDIO
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Formatted printing functions
|
||||
|
||||
These functions implement most of printf(3)'s features, including:
|
||||
* Signed and unsigned integer formats (%d, %i, %o, %u, %x, %X)
|
||||
* Character, string and pointer formats (%c, %s, %p)
|
||||
* Format options (0, #, -, (space), length, precision)
|
||||
* Parameter length (hh, h, l, ll, z)
|
||||
* Limiting the size of the output and still returning the whole length
|
||||
* If kprint_enable_fp() from <gint/kprint.h> is called: floating-point
|
||||
formats (%e, %E, %f, %F, %g, %G) (disabled by default to save space)
|
||||
|
||||
They do not support:
|
||||
* Hexadecimal floating-point (%a, %A)
|
||||
* The strerror() shorthand, since there is no errno (%m)
|
||||
* Some size modifiers: long double (L), intmax_t (j), ptrdiff_t (t), and the
|
||||
nonstandard synonyms q (ll) and Z (z)
|
||||
* Dynamic length field (*)
|
||||
* Thousands separators (') and locale-aware digits (I)
|
||||
* Nonstandard synonyms %C (%lc) and %S (%ls)
|
||||
|
||||
A new fixed-point format %j has been added; it behaves like %d but includes
|
||||
a decimal point. The number of decimal places is specified by the precision
|
||||
field. For instance %.3j with 12345 prints "123.45". This can be used for
|
||||
decimal fixed-point values. */
|
||||
|
||||
/* Print to string from var args */
|
||||
int sprintf(char *str, char const *format, ...);
|
||||
/* Print to string from va_list */
|
||||
int vsprintf(char *str, char const *format, va_list args);
|
||||
/* Print to string with limited size from var args */
|
||||
int snprintf(char *str, size_t n, char const *format, ...);
|
||||
/* Print to string with limited size from va_list */
|
||||
int vsnprintf(char *str, size_t n, char const *format, va_list args);
|
||||
/* Print to auto-allocated string */
|
||||
int asprintf(char **strp, char const *format, ...);
|
||||
/* Print to auto-allocated string from va_list */
|
||||
int vasprintf(char **strp, char const *format, va_list args);
|
||||
|
||||
#endif /* GINT_STD_STDIO */
|
||||
/* Now provided by fxlibc. */
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -1,30 +1,2 @@
|
|||
//---
|
||||
// gint:std:stdlib - a few <stdlib.h> functions provided by gint
|
||||
//---
|
||||
|
||||
#ifndef GINT_STD_STDLIB
|
||||
#define GINT_STD_STDLIB
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* malloc(): Allocate dynamic memory */
|
||||
void *malloc(size_t size);
|
||||
|
||||
/* free(): Free dynamic memory */
|
||||
void free(void *ptr);
|
||||
|
||||
/* calloc(): Allocate and initialize dynamic memory */
|
||||
void *calloc(size_t nmemb, size_t size);
|
||||
|
||||
/* realloc(): Reallocate dynamic memory */
|
||||
void *realloc(void *ptr, size_t size);
|
||||
|
||||
#define RAND_MAX 0x7fffffff
|
||||
|
||||
/* srand(): Seed the PRNG */
|
||||
void srand(unsigned int seed);
|
||||
|
||||
/* rand(): Generate a pseudo-random number between 0 and RAND_MAX */
|
||||
int rand(void);
|
||||
|
||||
#endif /* GINT_STD_STDLIB */
|
||||
/* Now provided by fxlibc. */
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -1,43 +1,2 @@
|
|||
//---
|
||||
// gint:std:string - a few <string.h> functions provided by gint
|
||||
//---
|
||||
|
||||
#ifndef GINT_STD_STRING
|
||||
#define GINT_STD_STRING
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* memcpy(): Copy a chunk of memory to a non-overlapping destination */
|
||||
void *memcpy(void * __restrict dest, void const * __restrict src, size_t n);
|
||||
|
||||
/* memset(): Fill a chunk of memory with a single byte */
|
||||
void *memset(void *dest, int byte, size_t n);
|
||||
|
||||
/* memcmp(): Compare two chunks of memory */
|
||||
int memcmp(void const *s1, void const *s2, size_t n);
|
||||
|
||||
/* memmove(): Copy a chunk of memory to a possibly overlapping destination */
|
||||
void *memmove(void *dest, void const *src, size_t n);
|
||||
|
||||
/* strlen(): Length of a NUL-terminated string */
|
||||
size_t strlen(char const *str);
|
||||
|
||||
/* strncpy(): Copy a string with a size limit */
|
||||
char *strncpy(char *dst, char const *src, size_t n);
|
||||
|
||||
/* strcat(): Concatenation a string to a pre-allocated space */
|
||||
char *strcat(char *dest, const char *src);
|
||||
|
||||
/* strcmp(): Compare NUL-terminated strings */
|
||||
int strcmp(char const *s1, char const *s2);
|
||||
|
||||
/* strchr(): Find the first occurrence of a character in a string */
|
||||
char *strchr(char const *s, int c);
|
||||
|
||||
/* strrchr(): Find the last occurrence of a character in a string */
|
||||
char *strrchr(char const *s, int c);
|
||||
|
||||
/* strchrnul(): Like strchr(), but returns end-of-string instead of NUL */
|
||||
char *strchrnul(char const *s, int c);
|
||||
|
||||
#endif /* GINT_STD_STRING */
|
||||
/* Now provided by fxlibc. */
|
||||
#include <string.h>
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#ifndef GINT_TIMER
|
||||
#define GINT_TIMER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/mpu/tmu.h>
|
||||
#include <gint/hardware.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
@ -158,10 +162,11 @@ void timer_stop(int timer);
|
|||
it may have only paused. If the timer never stops, you're in trouble. */
|
||||
void timer_wait(int timer);
|
||||
|
||||
/* timer_spinwait(): Actively wait for a timer to raise UNF
|
||||
/* timer_spinwait(): Start a timer and actively wait for UNF
|
||||
Waits until the timer raises UNF, without sleeping. This is useful for
|
||||
delays in driver code that is run when interrupts are disabled. This relies
|
||||
neither on the interrupt signal nor on the UNIE flag. */
|
||||
delays in driver code that is run when interrupts are disabled. UNIE is
|
||||
disabled before starting the timer and waiting, so the callback is never
|
||||
called. */
|
||||
void timer_spinwait(int timer);
|
||||
|
||||
//---
|
||||
|
@ -236,4 +241,8 @@ int timer_setup(int timer, uint64_t delay_us, timer_callback_t callback, ...);
|
|||
Use GINT_CALL_SET_STOP() with timer_configure() instead. */
|
||||
int timer_timeout(volatile void *arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_TIMER */
|
||||
|
|
58
include/gint/ubc.h
Normal file
58
include/gint/ubc.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
//---
|
||||
// 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 */
|
|
@ -1,24 +1,125 @@
|
|||
//---
|
||||
// gint:usb-ff-bulk - A trivial bulk-based transfer class
|
||||
// gint:usb-ff-bulk - A bulk-based transfer class using the fxlink protocol
|
||||
//
|
||||
// This interface (class code 0xff/0x77) implements a simple bidirectional
|
||||
// communication channel running the fxlink protocol. It basically talks to
|
||||
// fxlink's interactive mode on the host, and can broadly be used for 4 things:
|
||||
//
|
||||
// 1. Sending standard messages to fxlink (screenshots, logs...). Convenient
|
||||
// functions are provided in this header to minimize the overhead. fxlink
|
||||
// running in interactive mode (fxlink -t) will handle these messages in a
|
||||
// suitable way automatically (eg. save screenshots as PNG).
|
||||
//
|
||||
// 2. Sending custom messages to fxlink (bench results, memory dumps, crash
|
||||
// reports...). fxlink running in interactive mode will forward the data to
|
||||
// appropriate user-provided external programs to handle the messages.
|
||||
//
|
||||
// 3. Applications based around on data streams coming from the host (screen
|
||||
// projector, web browser...). This can be achieved by modifying fxlink or
|
||||
// using it as a library.
|
||||
//
|
||||
// 4. Remote control from the fxlink interactive mode (fxlink -t). This is
|
||||
// based on fxlink's 'command' and 'keyboard' protocols. This module will
|
||||
// automatically handle commands and respond to them as long as the message
|
||||
// handling function is called regularly.
|
||||
//---
|
||||
|
||||
#ifndef GINT_USB_FF_BULK
|
||||
#define GINT_USB_FF_BULK
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/usb.h>
|
||||
#include <gint/config.h>
|
||||
struct usb_fxlink_header;
|
||||
|
||||
/* The bulk transfer interface with class code 0xff provides a very simple
|
||||
communication channel between the calculator and a host. There is
|
||||
(currently) a single IN pipe that sends data from the calculator to the
|
||||
host, at high-speed (USB 2.0).
|
||||
|
||||
The class code of this interface is 0xff, which means that the protocol is
|
||||
custom and requires a custom program on the host to receive the data (unlike
|
||||
for instance LINK on a Graph 90+E which behaves as a USB stick and can be
|
||||
used with the file browser). fxlink can be used to the effect. */
|
||||
|
||||
/* This bulk transfer interface with class code 0xff/0x77 implements a simple
|
||||
bidirectional communication channel between the calculator and a host,
|
||||
running at high-speed USB 2.0 and using the fxlink protocol. You can use it
|
||||
to communicate with fxlink's interactive mode on the host. */
|
||||
extern usb_interface_t const usb_ff_bulk;
|
||||
|
||||
//---
|
||||
// Sending standard messages
|
||||
//---
|
||||
|
||||
/* usb_fxlink_text(): Send raw text
|
||||
Send a string; fxlink will display it in the terminal. This can be used to
|
||||
back stdout/stderr. Sending lots of small messages can be slow; if that's a
|
||||
problem, fill in message manually. If size is 0, uses strlen(text). */
|
||||
void usb_fxlink_text(char const *text, int size);
|
||||
|
||||
/* usb_fxlink_screenshot(): Take a screenshot
|
||||
|
||||
This function sends a copy of the VRAM to fxlink. This is best used just
|
||||
before dupdate() since this ensures the image sent by USB is identical to
|
||||
the one displayed on screen.
|
||||
|
||||
If `onscreen` is set and there are two VRAMs (on fx-CG or when using the
|
||||
gray engine on fx-9860G), sends a copy of the other VRAM. This is a bit more
|
||||
intuitive when taking a screenshot of the last shown image as a result of a
|
||||
key press. Note that this function never reads pixels directly from the
|
||||
display (it's usually slow and currently not even implemented). */
|
||||
void usb_fxlink_screenshot(bool onscreen);
|
||||
|
||||
/* usb_fxlink_videocapture(): Send a frame for a video recording
|
||||
|
||||
This function is essentially the same as usb_fxlink_screenshot(). It sends a
|
||||
capture of the VRAM to fxlink but uses the "video" type, which fxlink
|
||||
displays in real-time or saves as a video file. The meaning of the onscreen
|
||||
setting is identical to usb_fxlink_screenshot().
|
||||
|
||||
This function can be called with onscreen=false as a dupdate() hook to
|
||||
automatically send new frames to fxlink. */
|
||||
void usb_fxlink_videocapture(bool onscreen);
|
||||
|
||||
#if GINT_RENDER_MONO
|
||||
/* Similar to usb_fxlink_screenshot(), but takes a gray screenshot if the gray
|
||||
engine is currently running. */
|
||||
void usb_fxlink_screenshot_gray(bool onscreen);
|
||||
|
||||
/* Like usb_fxlink_videocapture(), but uses VRAM data from the gray engine. */
|
||||
void usb_fxlink_videocapture_gray(bool onscreen);
|
||||
#endif
|
||||
|
||||
//---
|
||||
// Receiving messages
|
||||
//---
|
||||
|
||||
/* usb_fxlink_handle_messages(): Process and return incoming messages
|
||||
|
||||
This function processes incoming messages. It handles some types of messages
|
||||
internally (eg. fxlink commands) and returns the others to the caller by
|
||||
loading the provided header structure and returning true.
|
||||
|
||||
When this function returns true, the caller should read the message contents
|
||||
on the interface's input pipe. Usually every read will return just a portion
|
||||
of the message (eg. 2048 bytes) so the contents should be read with a loop.
|
||||
|
||||
As long as this function returns true it should be called againt to process
|
||||
any other messages. When there is no more messages to process, this function
|
||||
returns false. It is important to call this function regularly from the main
|
||||
thread when quick responses are expected. */
|
||||
bool usb_fxlink_handle_messages(struct usb_fxlink_header *header);
|
||||
|
||||
/* usb_fxlink_drop_transaction(): Drop incoming data until end of transaction
|
||||
|
||||
When a message arrives on the USB port incoming data *must* be processed in
|
||||
order for the pipe to accept any further data in the future. This function
|
||||
can be used in error situations to drop data until the end of the
|
||||
transaction (which is usually the end of the message, at least with the
|
||||
fxSDK's implementation of fxlink). */
|
||||
void usb_fxlink_drop_transaction(void);
|
||||
|
||||
/* usb_fxlink_set_notifier(): Set up a notification for incoming messages
|
||||
|
||||
Registers the provided function to be called when data arrives on the fxlink
|
||||
input pipe. This signals that usb_fxlink_handle_messages() should be called
|
||||
later from the main thread. Pass NULL to disable the notification. */
|
||||
void usb_fxlink_set_notifier(void (*notifier_function)(void));
|
||||
|
||||
//---
|
||||
// Direct bulk access
|
||||
//
|
||||
|
@ -27,48 +128,36 @@ extern usb_interface_t const usb_ff_bulk;
|
|||
// functions.
|
||||
//---
|
||||
|
||||
/* usb_ff_bulk_output(): Pipe for calculator -> host communication */
|
||||
/* usb_ff_bulk_output(): Pipe number for calculator -> host communication */
|
||||
int usb_ff_bulk_output(void);
|
||||
|
||||
/* usb_ff_bulk_input(): Pipe number for host -> calculator communication */
|
||||
int usb_ff_bulk_input(void);
|
||||
|
||||
//---
|
||||
// fxlink protocol
|
||||
// Construction and analysis of fxlink protocol messages
|
||||
//
|
||||
// fxlink is a bulk-based communication tool in the fxSDK that can be used to
|
||||
// conveniently transfer or manipulate information during the execution of an
|
||||
// add-in. For instance, screenshots can be saved, files can be transferred,
|
||||
// and text can be logged.
|
||||
// fxlink messages consist of a simple header followed by message contents
|
||||
// (sometimes with a subheader). In addition to the functions above, it is
|
||||
// possible to craft custom fxlink messages and send them manually.
|
||||
//
|
||||
// Each communication with fxlink is a message that consists of:
|
||||
// * A first write with a message header;
|
||||
// * One or more writes with message data (of a size announced in the header);
|
||||
// * A commit on the USB pipe (to ensure that everything is sent).
|
||||
//
|
||||
// There are two ways to use the fxlink protocol in this header; you can either
|
||||
// use one of the convenience functions like usb_fxlink_screenshot() that do
|
||||
// all the steps for you, or you can perform the writes and commits yourself to
|
||||
// send custom messages.
|
||||
// To send a message manually, simple write an fxlink header to the output
|
||||
// pipe, followed by the contents. The message can be built from any number of
|
||||
// writes to the pipe. After the last write, commit the pipe.
|
||||
//---
|
||||
|
||||
/* usb_fxlink_header_t: Message header for fxlink
|
||||
|
||||
fxlink supports a minimalistic protocol to receive data sent from the
|
||||
calculator and automatically process it (such as save it to file, convert
|
||||
to an image, etc). It is designed as a convenience feature, and it can be
|
||||
extended with custom types rather easily.
|
||||
Messages are categorized with an (application, type) pair; both are UTF-8
|
||||
strings of up to 16 bytes (NUL not required). The application name "fxlink"
|
||||
is reserved for built-in types of messages. Other names can be used freely,
|
||||
and fxlink's interactive mode on the host side will forward messages to
|
||||
external programs based on the application name.
|
||||
|
||||
A message is categorized with an (application, type) pair; both are UTF-8
|
||||
strings of up to 16 characters. The application name "fxlink" is reserved
|
||||
for built-in types supported by fxlink; any other custom application name
|
||||
can be set (in which case fxlink will call a user-provided program to handle
|
||||
the message).
|
||||
|
||||
The size of the data to be transferred must be specified in order of the
|
||||
transfer to proceed correctly, as it cannot reliably be guessed on the other
|
||||
side (and guessing wrong means all further messages will be in trouble).
|
||||
|
||||
As with the rest of the USB protocol, all the multi-byte integer fields in
|
||||
this header are encoded as *little-endian*. */
|
||||
typedef struct
|
||||
The size of the data to be transferred must be specified upfront, but this
|
||||
restriction might be lifted in the future. As with the rest of the USB
|
||||
protocol, all the integer are encoded as *little-endian*. */
|
||||
typedef struct usb_fxlink_header
|
||||
{
|
||||
/* Protocol version = 0x00000100 */
|
||||
uint32_t version;
|
||||
|
@ -76,33 +165,24 @@ typedef struct
|
|||
uint32_t size;
|
||||
/* Size of individual transfers (related to the size of the FIFO) */
|
||||
uint32_t transfer_size;
|
||||
/* Application name, UTF-8 (might not be zero-terminated) */
|
||||
/* Application name and message type, UTF-8 (need not be zero-terminated) */
|
||||
char application[16];
|
||||
/* Message type */
|
||||
char type[16];
|
||||
|
||||
} usb_fxlink_header_t;
|
||||
|
||||
/* usb_fxlink_fill_header(): Fill an fxlink message header
|
||||
|
||||
This function will fill the specified fxlink header. You need to specify the
|
||||
exact amount of data that the fxlink message will contain; if you cannot
|
||||
determine it, consider splitting the message into several messages each with
|
||||
their own header, and use the application-specific script on the host to
|
||||
recombine them.
|
||||
|
||||
Returns false if the parameters are invalid or don't fit, in this case the
|
||||
contents of the header are unchanged. */
|
||||
bool usb_fxlink_fill_header(usb_fxlink_header_t *header, char *application,
|
||||
char *type, uint32_t data_size);
|
||||
|
||||
//---
|
||||
// Short functions for fxlink built-in types
|
||||
//---
|
||||
Fills an fxlink header's fields with the provided. You need to specify the
|
||||
exact amount of data that the fxlink message will contain. Returns false if
|
||||
parameters are invalid or don't fit the fields. */
|
||||
bool usb_fxlink_fill_header(usb_fxlink_header_t *header,
|
||||
char const *application, char const *type, uint32_t data_size);
|
||||
|
||||
/* Subheader for the fxlink built-in "image" type */
|
||||
typedef struct
|
||||
{
|
||||
/* Image size; storage is row-major */
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
/* Pixel format, see below */
|
||||
|
@ -111,57 +191,17 @@ typedef struct
|
|||
} usb_fxlink_image_t;
|
||||
|
||||
/* Pixel formats */
|
||||
typedef enum
|
||||
{
|
||||
enum {
|
||||
/* Image is an array of *big-endian* uint16_t with RGB565 format */
|
||||
USB_FXLINK_IMAGE_RGB565 = 0,
|
||||
/* Image is an array of bits in mono format */
|
||||
USB_FXLINK_IMAGE_MONO,
|
||||
/* Image is two consecutive mono arrays, one for light, one for dark */
|
||||
USB_FXLINK_IMAGE_GRAY,
|
||||
};
|
||||
|
||||
} usb_fxlink_image_format_t;
|
||||
|
||||
/* usb_fxlink_screenshot(): Take a screenshot
|
||||
|
||||
This function takes a screenshot. If (onscreen = false), it sends the
|
||||
contents of the VRAM. This mode is best used just before dupdate(), since
|
||||
the VRAM contents are exactly as they will appear on screen a moment later.
|
||||
However, this is somewhat unintuitive for interactive GUI as the user has to
|
||||
press a button after the option is present on-screen, therefore the contents
|
||||
of the *next* frame are captured.
|
||||
|
||||
If (onscreen = true), this function tries to send the pixels that are
|
||||
currently visible on-screen, with the following heuristic:
|
||||
|
||||
* If there is only one VRAM, the VRAM contents are used in the hope they
|
||||
haven't changed since the last frame was presented with dupdate().
|
||||
* If there are two VRAMs (on fx-CG 50 or using the gray engine) the contents
|
||||
of the VRAM not currently being draw to are sent.
|
||||
|
||||
This function does not read pixels directly from the display, as this is
|
||||
usually slow and currently not even implemented. */
|
||||
void usb_fxlink_screenshot(bool onscreen);
|
||||
|
||||
#ifdef FX9860G
|
||||
/* usb_fxlink_screenshot_gray(): Take a gray screenshot on fx-9860G
|
||||
|
||||
This function is similar to usb_fxlink_screenshot(), but it takes a gray
|
||||
screenshot. It depends on the gray engine so if you use your add-in will
|
||||
automatically have the gray engine, that's why it's separate. */
|
||||
void usb_fxlink_screenshot_gray(bool onscreen);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* usb_fxlink_text(): Send raw text
|
||||
|
||||
This function sends a string with the "text" type, which fxlink prints on
|
||||
the terminal. It will send a full fxlink message (with a commit), which is
|
||||
inefficient if there is a lot of text to send. For better speed, send the
|
||||
message manually by filling the header and doing the writes and commit
|
||||
manually.
|
||||
|
||||
This function sends the text by blocks of 4 bytes or 2 bytes when alignment
|
||||
and size allow, and 1 byte otherwise. If size is 0, strlen(text) is used. */
|
||||
void usb_fxlink_text(char const *text, int size);
|
||||
|
||||
#endif /* GINT_USB_FF_BULK */
|
||||
|
|
|
@ -5,10 +5,16 @@
|
|||
#ifndef GINT_USB
|
||||
#define GINT_USB
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/std/endian.h>
|
||||
#include <gint/defs/timeout.h>
|
||||
#include <gint/gint.h>
|
||||
#include <gint/config.h>
|
||||
#include <stdarg.h>
|
||||
#include <endian.h>
|
||||
|
||||
/* See "Interfaces to communicate with USB transfers" below for details */
|
||||
typedef struct usb_interface usb_interface_t;
|
||||
|
@ -23,26 +29,35 @@ enum {
|
|||
/* There are no interfaces */
|
||||
USB_OPEN_NO_INTERFACE = 1,
|
||||
/* There are more interfaces than supported (16) */
|
||||
USB_OPEN_TOO_MANY_INTERFACES,
|
||||
USB_OPEN_TOO_MANY_INTERFACES = -2,
|
||||
/* There are not enough endpoint numbers for every interface, or there
|
||||
are not enough pipes to set them up */
|
||||
USB_OPEN_TOO_MANY_ENDPOINTS,
|
||||
USB_OPEN_TOO_MANY_ENDPOINTS = -3,
|
||||
/* There is not enough FIFO memory to use the requested buffer sizes */
|
||||
USB_OPEN_NOT_ENOUGH_MEMORY,
|
||||
USB_OPEN_NOT_ENOUGH_MEMORY = -4,
|
||||
/* Information is missing, such as buffer size for some endpoints */
|
||||
USB_OPEN_MISSING_DATA,
|
||||
USB_OPEN_MISSING_DATA = -5,
|
||||
/* Invalid parameters: bad endpoint numbers, bad buffer sizes... */
|
||||
USB_OPEN_INVALID_PARAMS,
|
||||
USB_OPEN_INVALID_PARAMS = -6,
|
||||
/* USB interfaces are already opened */
|
||||
USB_OPEN_ALREADY_OPEN = -7,
|
||||
|
||||
/* This pipe is busy (returned by usb_write_async()) */
|
||||
USB_WRITE_BUSY,
|
||||
/* Both FIFO controlles are busy, none is available to transfer */
|
||||
USB_WRITE_NOFIFO,
|
||||
/* General timeout for a sync_timeout call */
|
||||
USB_TIMEOUT = -8,
|
||||
/* This pipe is busy with another call */
|
||||
USB_BUSY = -9,
|
||||
|
||||
/* This pipe is busy (returned by usb_commit_async()) */
|
||||
USB_COMMIT_BUSY,
|
||||
/* Both FIFO controllers are busy, none is available to transfer */
|
||||
USB_WRITE_NOFIFO = -10,
|
||||
/* This pipe has no ongoing transfer to commit */
|
||||
USB_COMMIT_INACTIVE,
|
||||
USB_COMMIT_INACTIVE = -11,
|
||||
/* This pipe is currently not receiving any data */
|
||||
USB_READ_IDLE = -12,
|
||||
/* No FIFO controller is available */
|
||||
USB_READ_NOFIFO = -13,
|
||||
|
||||
/* (Internal codes) */
|
||||
USB_ERROR_ZERO_LENGTH = -100,
|
||||
};
|
||||
|
||||
/* usb_open(): Open the USB link
|
||||
|
@ -75,6 +90,9 @@ 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
|
||||
|
@ -125,8 +143,12 @@ struct usb_interface {
|
|||
/* Answer class-specific SETUP requests */
|
||||
/* TODO */
|
||||
|
||||
/* Receive data from an endpoint */
|
||||
/* TODO */
|
||||
/* Notification that an endpoint has data to be read. This function is
|
||||
called frequently when data is being transmitted; the particular
|
||||
timings depend on low-level details. The notification should be
|
||||
passed down to cause the main thread to read later. Do not read in
|
||||
the notification function! */
|
||||
void (*notify_read)(int endpoint);
|
||||
};
|
||||
|
||||
/* usb_interface_endpoint_t: Parameters for an interface endpoint
|
||||
|
@ -165,23 +187,22 @@ int usb_interface_pipe(usb_interface_t const *interface, int endpoint);
|
|||
|
||||
/* usb_write_sync(): Synchronously write to a USB pipe
|
||||
|
||||
This functions writes (size) bytes of (data) into the specified pipe, by
|
||||
units of (unit_size) bytes. The unit size must be 1, 2 or 4, and both (data)
|
||||
and (size) must be multiples of the unit size. In general, you should try to
|
||||
use the largest possible unit size, as it will be much faster. In a sequence
|
||||
of writes that concludes with a commit, all the writes must use the same
|
||||
unit size.
|
||||
This functions writes (size) bytes of (data) into the specified pipe. If the
|
||||
data fits into the pipe, this function returns right away, and the data is
|
||||
*not* transmitted. Otherwise, data is written until the pipe is full, at
|
||||
which point it is automatically transmitted. After the transfer, this
|
||||
function resumes writing, returning only once everything is written. Even
|
||||
then the last bytes will still not have been transmitted, to allow for other
|
||||
writes to follow. After the last write in a sequence, use usb_commit_sync()
|
||||
or usb_commit_async() to transmit the last bytes.
|
||||
|
||||
If the data fits into the pipe, this function returns right away, and the
|
||||
data is *not* transmitted. Otherwise, data is written until the pipe is
|
||||
full, at which point it is automatically transmitted. After the transfer,
|
||||
this function resumes writing, returning only once everything is written.
|
||||
Even then the last bytes will still not have been transmitted, to allow for
|
||||
other writes to follow. After the last write in a sequence, use
|
||||
usb_commit_sync() or usb_commit_async() to transmit the last bytes.
|
||||
|
||||
If (use_dma=true), the write is performed with the DMA instead of the CPU,
|
||||
which is generally faster.
|
||||
If (use_dma=true), the write is performed with the DMA instead of the CPU.
|
||||
This requires at least 4-byte alignment on:
|
||||
1. The input data;
|
||||
2. The size of this write;
|
||||
3. The amount of data previously written to the pipe not yet committed.
|
||||
This is because using the DMA does not allow any insertion of CPU logic to
|
||||
handle unaligned stuff.
|
||||
|
||||
This function will use a FIFO controller to access the pipe. The FIFO
|
||||
controller will be reserved for further writes until the contents of the
|
||||
|
@ -194,13 +215,15 @@ int usb_interface_pipe(usb_interface_t const *interface, int endpoint);
|
|||
waits for the ressources to become available then proceeds normally.
|
||||
|
||||
@pipe Pipe to write into
|
||||
@data Source data (unit_size-aligned)
|
||||
@size Size of source (multiple of unit_size)
|
||||
@unit_size FIFO access size (must be 1, 2, or 4)
|
||||
@data Source data
|
||||
@size Size of source
|
||||
@dma Whether to use the DMA to perform the write
|
||||
-> Returns an error code (0 on success). */
|
||||
int usb_write_sync(int pipe, void const *data, int size, int unit_size,
|
||||
bool use_dma);
|
||||
int usb_write_sync(int pipe, void const *data, int size, bool use_dma);
|
||||
|
||||
/* usb_write_sync_timeout(): Synchronously write, with a timeout */
|
||||
int usb_write_sync_timeout(int pipe, void const *data, int size,
|
||||
bool use_dma, timeout_t const *timeout);
|
||||
|
||||
/* usb_write_async(): Asynchronously write to a USB pipe
|
||||
|
||||
|
@ -222,14 +245,13 @@ int usb_write_sync(int pipe, void const *data, int size, int unit_size,
|
|||
is idle and USB_WRITE_BUSY otherwise.
|
||||
|
||||
@pipe Pipe to write into
|
||||
@data Source data (unit_size-aligned)
|
||||
@size Size of source (multiple of unit_size)
|
||||
@unit_size FIFO access size (must be 1, 2, or 4)
|
||||
@data Source data
|
||||
@size Size of source
|
||||
@dma Whether to use the DMA to perform the write
|
||||
@callback Optional callback to invoke when the write completes
|
||||
-> Returns an error code (0 on success). */
|
||||
int usb_write_async(int pipe, void const *data, int size, int unit_size,
|
||||
bool use_dma, gint_call_t callback);
|
||||
int usb_write_async(int pipe, void const *data, int size, bool use_dma,
|
||||
gint_call_t callback);
|
||||
|
||||
/* usb_commit_sync(): Synchronously commit a write
|
||||
|
||||
|
@ -237,6 +259,9 @@ int usb_write_async(int pipe, void const *data, int size, int unit_size,
|
|||
transfers whatever data is left, and returns when the transfer completes. */
|
||||
void usb_commit_sync(int pipe);
|
||||
|
||||
/* usb_commit_sync_timeout(): Synchronously commit a write, with timeout */
|
||||
int usb_commit_sync_timeout(int pipe, timeout_t const *timeout);
|
||||
|
||||
/* usb_commit_async(): Asynchronously commit a write
|
||||
|
||||
This function commits the specified pipe, causing the pipe to transfer
|
||||
|
@ -251,23 +276,142 @@ void usb_commit_sync(int pipe);
|
|||
of the remaining data completes. */
|
||||
int usb_commit_async(int pipe, gint_call_t callback);
|
||||
|
||||
/* usb_read_sync(): Synchronously read from a USB pipe
|
||||
|
||||
This function waits for data to become available on the specified `pipe`,
|
||||
and then reads up to `size` bytes into `data`. It is "synchronized" with USB
|
||||
transactions on the pipe in the following ways:
|
||||
|
||||
1. If there is no active transaction, it waits for one to arrive.
|
||||
2. If the active transaction has no data left to read, it is skipped.
|
||||
3. If the transaction's data is completely read, the transaction is closed
|
||||
even if `data` is full. (See usb_read_async() for the alternative.)
|
||||
|
||||
Basically usb_read_sync() returns the next `size` bytes of data that the
|
||||
calculator receives on the pipe, with a single exception: it doesn't read
|
||||
across transactions, so if the active transaction has 100 bytes left and you
|
||||
request 200, you will only get 100. usb_read_sync() only ever returns 0
|
||||
bytes if there is an empty transaction, which is rare.
|
||||
|
||||
Because this is a blocking function, a call to usb_read_sync() will *FREEZE*
|
||||
if there is no data to read on the pipe and the host doesn't send any. In
|
||||
addition, it's not possible to detect how much data is left to read with
|
||||
usb_read_sync()'s interface. If you want to avoid or debug a freeze, use
|
||||
use usb_read_async() or set a timeout with usb_read_sync_timeout(). If you
|
||||
want to read a transaction until the end without knowing its size in
|
||||
advance, use usb_read_async().
|
||||
|
||||
If `use_dma=true`, uses the DMA for transfers. This requires 4-byte
|
||||
alignment on the buffer, size, and number of bytes previously read in the
|
||||
current transaction.
|
||||
|
||||
Returns the number of bytes read or a negative error code. */
|
||||
int usb_read_sync(int pipe, void *data, int size, bool use_dma);
|
||||
|
||||
/* usb_read_sync_timeout(): Synchronous read with a timeout */
|
||||
int usb_read_sync_timeout(int pipe, void *data, int size, bool use_dma,
|
||||
timeout_t const *timeout);
|
||||
|
||||
/* Flags for usb_read_async(), see below. */
|
||||
enum {
|
||||
/* Use the DMA for data transfer (requires full 4-byte alignment). */
|
||||
USB_READ_USE_DMA = 0x01,
|
||||
/* Ignore reads of 0 bytes from exhausted transactions. */
|
||||
USB_READ_IGNORE_ZEROS = 0x02,
|
||||
/* Close transactions when exhausted even by non-partial reads. */
|
||||
USB_READ_AUTOCLOSE = 0x04,
|
||||
/* Wait for the read to finish before returning. */
|
||||
USB_READ_WAIT = 0x08,
|
||||
/* Block for a new transaction if none is currenty active. */
|
||||
USB_READ_BLOCK = 0x10,
|
||||
};
|
||||
|
||||
/* usb_read_async(): Asynchronously read from a USB pipe
|
||||
|
||||
This function is similar to usb_read_sync() but it is asynchronous, ie. it
|
||||
returns after starting the read and then runs in the background. Without
|
||||
options, usb_read_async() is guaranteed to return quickly without waiting
|
||||
for communications. The read itself also never blocks unless there is a
|
||||
disagreement with the host on the size of transactions.
|
||||
|
||||
usb_read_async() is also slightly lower-level than usb_read_sync(). In
|
||||
particular, it only closes transactions when the data is fully read *and*
|
||||
the user buffer is not full. If the user requests exactly the number of
|
||||
bytes left in the transaction, the entire contents will be read but the
|
||||
transaction will be left in an "active with 0 bytes left" state. Only on the
|
||||
next read will the transaction be closed.
|
||||
|
||||
This behavior is designed so that a read closes a transaction if and only if
|
||||
it returns fewer bytes than requested, which is useful for detecting the end
|
||||
of transfers when their size isn't known in advance.
|
||||
|
||||
This function returns a preliminary error code. If it is zero, then the
|
||||
callback will be invoked later with *rc set to the final return value of the
|
||||
read, which is itself either an error (< 0) or the number of bytes read.
|
||||
|
||||
Due to its low-level nature, raw usb_read_async() is a bit impractical to
|
||||
use and almost always requires repeated calls and callback waits. The
|
||||
following flags are provided to make it more convenient by incorporating
|
||||
features of usb_read_sync():
|
||||
|
||||
* USB_READ_IGNORE_ZEROS causes usb_read_async() to ignore reads of 0 bytes
|
||||
from transactions that were exhausted but not closed.
|
||||
* USB_READ_AUTOCLOSE causes usb_read_async() to always close transactions
|
||||
when exhausted even if the read is not partial. This is useful when the
|
||||
size of the transaction is in fact known in advance.
|
||||
* USB_READ_WAIT causes usb_read_async() to wait for the end of the transfer
|
||||
before returning. Unless there is a driver bug or USB_READ_BLOCK is also
|
||||
set, this cannot cause the function to freeze since the read will always
|
||||
complete in finite time (returning USB_READ_IDLE if no transaction is
|
||||
active). When USB_READ_WAIT it set, `callback` and `rc` are ignored; the
|
||||
callback is not invoked, and the status of the entire read is returned.
|
||||
* USB_READ_BLOCK causes usb_read_async() to wait for a transaction if none
|
||||
is active. This can stall the transfer indefinitely if the host doesn't
|
||||
transmit any data, and freeze the call entirely if USB_READ_WAIT is set.
|
||||
This option really makes usb_read_async() a synchronous function.
|
||||
* A timeout is supported (pass NULL to ignore).
|
||||
|
||||
With all options enabled, usb_read_async() becomes functionally identical to
|
||||
usb_read_sync_timeout(). */
|
||||
int usb_read_async(int pipe, void *data, int size, int flags, int *rc,
|
||||
timeout_t const *timeout, gint_call_t callback);
|
||||
|
||||
/* usb_read_cancel(): Cancel an asynchronous read
|
||||
|
||||
Once started, an async read will run in the background and keep writing to
|
||||
the provided buffer. This function cancels the operation so that no further
|
||||
writes to the buffer are made and the associated memory can be safely
|
||||
deallocated. */
|
||||
void usb_read_cancel(int pipe);
|
||||
|
||||
//---
|
||||
// USB debugging log
|
||||
// USB debugging functions
|
||||
//---
|
||||
|
||||
/* usb_set_log(): Set the logging function for the USB driver
|
||||
|
||||
The USB driver can produce logs, which are mostly useful to troubleshoot
|
||||
problems and add new protocols. The logging is disabled by default but can
|
||||
be enabled by specifying this function.
|
||||
|
||||
It is up to you whether to store that in a buffer, rotate logs, send them to
|
||||
storage memory or a console on the PC. */
|
||||
/* usb_set_log(): Set the logging function for the USB driver */
|
||||
void usb_set_log(void (*logger)(char const *format, va_list args));
|
||||
|
||||
/* usb_get_log(): Get the logging function */
|
||||
void (*usb_get_log(void))(char const *format, va_list args);
|
||||
/* usb_log(): Send a message to the USB log */
|
||||
void usb_log(char const *format, ...);
|
||||
|
||||
/* usb_set_trace(): Set the tracing function for the USB driver
|
||||
The function is called atomically, thus cannot be interrupted, therefore it
|
||||
is safe to call usb_trace() in interrupt handlers. */
|
||||
void usb_set_trace(void (*tracer)(char const *message));
|
||||
/* usb_get_trace(): Get the tracing function */
|
||||
void (*usb_get_trace(void))(char const *message);
|
||||
/* usb_trace(): Trace the current state of the driver */
|
||||
void usb_trace(char const *message);
|
||||
|
||||
#ifdef GINT_USB_DEBUG
|
||||
#define USB_LOG(...) usb_log(__VA_ARGS__)
|
||||
#define USB_TRACE(...) usb_trace(__VA_ARGS__)
|
||||
#else
|
||||
#define USB_LOG(...) do {} while(0)
|
||||
#define USB_TRACE(...) do {} while(0)
|
||||
#endif
|
||||
|
||||
//---
|
||||
// Standard descriptors
|
||||
//---
|
||||
|
@ -376,4 +520,16 @@ 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
|
||||
|
||||
#endif /* GINT_USB */
|
||||
|
|
93
include/gint/video.h
Normal file
93
include/gint/video.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
//---
|
||||
// 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_NONE 0x00
|
||||
#define VIDEO_UPDATE_ENABLE_DMA 0x01
|
||||
#define VIDEO_UPDATE_ATOMIC 0x02
|
||||
#define VIDEO_UPDATE_FOREIGN_WORLD 0x04
|
||||
|
||||
/* 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 */
|
22
src/3rdparty/grisu2b_59_56/LICENSE
vendored
22
src/3rdparty/grisu2b_59_56/LICENSE
vendored
|
@ -1,22 +0,0 @@
|
|||
Copyright (c) 2009 Florian Loitsch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
14
src/3rdparty/grisu2b_59_56/README
vendored
14
src/3rdparty/grisu2b_59_56/README
vendored
|
@ -1,14 +0,0 @@
|
|||
Grisu is an algorithm by Florian Loitsch to print the decimal representation of
|
||||
floating-point numbers.
|
||||
|
||||
The original code from which this folder is extracted can be found at
|
||||
<https://drive.google.com/open?id=0BwvYOx00EwKmejFIMjRORTFLcTA>.
|
||||
|
||||
Only a minimal variation, the Grisu2 rounding algorithm with α=-59 and γ=-56,
|
||||
is present here. The code has been adapted to fit the limited runtime as well
|
||||
as the use of OpenLibm.
|
||||
|
||||
See the original paper at <https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf>
|
||||
and Florian Loitsch's home page at <https://florian.loitsch.com/publications>.
|
||||
|
||||
The files are licensed under the permissive conditions of the attached LICENSE.
|
58
src/3rdparty/grisu2b_59_56/diy_fp.h
vendored
58
src/3rdparty/grisu2b_59_56/diy_fp.h
vendored
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009 Florian Loitsch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct diy_fp_t {
|
||||
uint64_t f;
|
||||
int e;
|
||||
} diy_fp_t;
|
||||
|
||||
static diy_fp_t minus(diy_fp_t x, diy_fp_t y) {
|
||||
diy_fp_t r = {.f = x.f - y.f, .e = x.e};
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
static diy_fp_t minus(diy_fp_t x, diy_fp_t y) {
|
||||
assert(x.e == y.e);
|
||||
assert(x.f >= y.f);
|
||||
diy_fp_t r = {.f = x.f - y.f, .e = x.e};
|
||||
return r;
|
||||
}
|
||||
*/
|
||||
|
||||
static diy_fp_t multiply(diy_fp_t x, diy_fp_t y) {
|
||||
uint64_t a,b,c,d,ac,bc,ad,bd,tmp,h;
|
||||
diy_fp_t r; uint64_t M32 = 0xFFFFFFFF;
|
||||
a = x.f >> 32; b = x.f & M32;
|
||||
c = y.f >> 32; d = y.f & M32;
|
||||
ac = a*c; bc = b*c; ad = a*d; bd = b*d;
|
||||
tmp = (bd>>32) + (ad&M32) + (bc&M32);
|
||||
tmp += 1U << 31; /// mult_round
|
||||
r.f = ac+(ad>>32)+(bc>>32)+(tmp >>32);
|
||||
r.e = x.e + y.e + 64;
|
||||
return r;
|
||||
}
|
110
src/3rdparty/grisu2b_59_56/double.h
vendored
110
src/3rdparty/grisu2b_59_56/double.h
vendored
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009 Florian Loitsch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "diy_fp.h"
|
||||
#include "powers.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef union {
|
||||
double d;
|
||||
uint64_t n;
|
||||
} converter_t;
|
||||
|
||||
static uint64_t double_to_uint64(double d) { converter_t tmp; tmp.d = d; return tmp.n; }
|
||||
static double uint64_to_double(uint64_t d64) { converter_t tmp; tmp.n = d64; return tmp.d; }
|
||||
|
||||
#define DP_SIGNIFICAND_SIZE 52
|
||||
#define DP_EXPONENT_BIAS (0x3FF + DP_SIGNIFICAND_SIZE)
|
||||
#define DP_MIN_EXPONENT (-DP_EXPONENT_BIAS)
|
||||
#define DP_EXPONENT_MASK 0x7FF0000000000000
|
||||
#define DP_SIGNIFICAND_MASK 0x000FFFFFFFFFFFFF
|
||||
#define DP_HIDDEN_BIT 0x0010000000000000
|
||||
|
||||
static diy_fp_t normalize_diy_fp(diy_fp_t in) {
|
||||
diy_fp_t res = in;
|
||||
/* Normalize now */
|
||||
/* the original number could have been a denormal. */
|
||||
while (! (res.f & DP_HIDDEN_BIT))
|
||||
{
|
||||
res.f <<= 1;
|
||||
res.e--;
|
||||
}
|
||||
/* do the final shifts in one go. Don't forget the hidden bit (the '-1') */
|
||||
res.f <<= (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 1);
|
||||
res.e = res.e - (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
static diy_fp_t double2diy_fp(double d) {
|
||||
uint64_t d64 = double_to_uint64(d);
|
||||
int biased_e = (d64 & DP_EXPONENT_MASK) >> DP_SIGNIFICAND_SIZE;
|
||||
uint64_t significand = (d64 & DP_SIGNIFICAND_MASK);
|
||||
diy_fp_t res;
|
||||
if (biased_e != 0)
|
||||
{
|
||||
res.f = significand + DP_HIDDEN_BIT;
|
||||
res.e = biased_e - DP_EXPONENT_BIAS;
|
||||
} else {
|
||||
res.f = significand;
|
||||
res.e = DP_MIN_EXPONENT + 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static diy_fp_t normalize_boundary(diy_fp_t in) {
|
||||
diy_fp_t res = in;
|
||||
/* Normalize now */
|
||||
/* the original number could have been a denormal. */
|
||||
while (! (res.f & (DP_HIDDEN_BIT << 1)))
|
||||
{
|
||||
res.f <<= 1;
|
||||
res.e--;
|
||||
}
|
||||
/* do the final shifts in one go. Don't forget the hidden bit (the '-1') */
|
||||
res.f <<= (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 2);
|
||||
res.e = res.e - (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 2);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void normalized_boundaries(double d, diy_fp_t* out_m_minus, diy_fp_t* out_m_plus) {
|
||||
diy_fp_t v = double2diy_fp(d);
|
||||
diy_fp_t pl, mi;
|
||||
bool significand_is_zero = v.f == DP_HIDDEN_BIT;
|
||||
pl.f = (v.f << 1) + 1; pl.e = v.e - 1;
|
||||
pl = normalize_boundary(pl);
|
||||
if (significand_is_zero)
|
||||
{
|
||||
mi.f = (v.f << 2) - 1;
|
||||
mi.e = v.e - 2;
|
||||
} else {
|
||||
mi.f = (v.f << 1) - 1;
|
||||
mi.e = v.e - 1;
|
||||
}
|
||||
mi.f <<= mi.e - pl.e;
|
||||
mi.e = pl.e;
|
||||
*out_m_plus = pl;
|
||||
*out_m_minus = mi;
|
||||
}
|
27
src/3rdparty/grisu2b_59_56/grisu2.h
vendored
27
src/3rdparty/grisu2b_59_56/grisu2.h
vendored
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009 Florian Loitsch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
void grisu2(double v, char* buffer, int* length, int* K);
|
95
src/3rdparty/grisu2b_59_56/grisu2b_59_56.c
vendored
95
src/3rdparty/grisu2b_59_56/grisu2b_59_56.c
vendored
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009 Florian Loitsch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "diy_fp.h"
|
||||
#include "k_comp.h"
|
||||
#include "double.h"
|
||||
#include "powers.h"
|
||||
#include <stdbool.h>
|
||||
#include "grisu2.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define TEN9 1000000000
|
||||
|
||||
void grisu_round(char* buffer, int len,
|
||||
uint64_t delta, uint64_t rest,
|
||||
uint64_t ten_kappa, uint64_t wp_w) {
|
||||
while (rest < wp_w &&
|
||||
delta - rest >= ten_kappa &&
|
||||
(rest + ten_kappa < wp_w || /// closer
|
||||
wp_w - rest > rest+ten_kappa - wp_w))
|
||||
{
|
||||
buffer[len-1]--; rest += ten_kappa;
|
||||
}
|
||||
}
|
||||
|
||||
void digit_gen(diy_fp_t W, diy_fp_t Mp, diy_fp_t delta,
|
||||
char* buffer, int* len, int* K) {
|
||||
uint32_t div; int d,kappa; diy_fp_t one, wp_w;
|
||||
wp_w = minus(Mp, W);
|
||||
one.f = ((uint64_t) 1) << -Mp.e; one.e = Mp.e;
|
||||
uint32_t p1 = Mp.f >> -one.e; /// Mp_cut
|
||||
uint64_t p2 = Mp.f & (one.f - 1);
|
||||
*len = 0; kappa = 10; div = TEN9;
|
||||
while (kappa > 0) {
|
||||
d = p1 / div;
|
||||
if (d || *len) buffer[(*len)++] = '0' + d; /// Mp_inv1
|
||||
p1 %= div; kappa--;
|
||||
uint64_t tmp = (((uint64_t)p1)<<-one.e)+p2;
|
||||
if (tmp <= delta.f) { /// Mp_delta
|
||||
*K += kappa;
|
||||
grisu_round(buffer, *len, delta.f, tmp, ((uint64_t)div) << -one.e, wp_w.f);
|
||||
return;
|
||||
}
|
||||
div /= 10;
|
||||
}
|
||||
uint64_t unit = 1;
|
||||
while (1) {
|
||||
p2 *= 10; delta.f *= 10; unit *= 10;
|
||||
d = p2 >> -one.e;
|
||||
if (d || *len) buffer[(*len)++] = '0' + d;
|
||||
p2 &= one.f - 1; kappa--;
|
||||
if (p2 < delta.f) {
|
||||
*K += kappa;
|
||||
grisu_round(buffer, *len, delta.f, p2, one.f, wp_w.f*unit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void grisu2(double v, char* buffer, int* length, int* K) {
|
||||
diy_fp_t w_m, w_p;
|
||||
int q = 64, alpha = -59, gamma = -56; int pos;
|
||||
normalized_boundaries(v, &w_m, &w_p);
|
||||
diy_fp_t w = normalize_diy_fp(double2diy_fp(v));
|
||||
int mk = k_comp(w_p.e + q, alpha, gamma);
|
||||
diy_fp_t c_mk = cached_power(mk);
|
||||
diy_fp_t W = multiply(w, c_mk);
|
||||
diy_fp_t Wp = multiply(w_p, c_mk);
|
||||
diy_fp_t Wm = multiply(w_m, c_mk);
|
||||
Wm.f++; Wp.f--;
|
||||
diy_fp_t delta = minus(Wp, Wm);
|
||||
*K = -mk;
|
||||
digit_gen(W, Wp, delta, buffer, length, K);
|
||||
}
|
32
src/3rdparty/grisu2b_59_56/k_comp.h
vendored
32
src/3rdparty/grisu2b_59_56/k_comp.h
vendored
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009 Florian Loitsch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <openlibm.h>
|
||||
|
||||
#define D_1_LOG2_10 0.30102999566398114 // 1 / lg(10)
|
||||
|
||||
static int k_comp(int e, int alpha, int gamma) {
|
||||
return ceil((alpha-e+63) * D_1_LOG2_10);
|
||||
}
|
27
src/3rdparty/grisu2b_59_56/powers.h
vendored
27
src/3rdparty/grisu2b_59_56/powers.h
vendored
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009 Florian Loitsch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
#include "diy_fp.h"
|
||||
#include "powers_ten_round64.h"
|
36
src/3rdparty/grisu2b_59_56/powers_ten_round64.h
vendored
36
src/3rdparty/grisu2b_59_56/powers_ten_round64.h
vendored
File diff suppressed because one or more lines are too long
29
src/3rdparty/tinymt32/LICENSE.txt
vendored
29
src/3rdparty/tinymt32/LICENSE.txt
vendored
|
@ -1,29 +0,0 @@
|
|||
Copyright (c) 2011 Mutsuo Saito, Makoto Matsumoto, Hiroshima
|
||||
University and The University of Tokyo. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of the Hiroshima University nor the names of
|
||||
its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
14
src/3rdparty/tinymt32/rand.c
vendored
14
src/3rdparty/tinymt32/rand.c
vendored
|
@ -1,14 +0,0 @@
|
|||
#include <gint/std/stdlib.h>
|
||||
#include "tinymt32.h"
|
||||
|
||||
static tinymt32_t random;
|
||||
|
||||
void srand(unsigned int seed)
|
||||
{
|
||||
tinymt32_init(&random, seed);
|
||||
}
|
||||
|
||||
int rand(void)
|
||||
{
|
||||
return tinymt32_generate_uint32(&random) & 0x7fffffff;
|
||||
}
|
121
src/3rdparty/tinymt32/tinymt32.c
vendored
121
src/3rdparty/tinymt32/tinymt32.c
vendored
|
@ -1,121 +0,0 @@
|
|||
/**
|
||||
* @file tinymt32.c
|
||||
*
|
||||
* @brief Tiny Mersenne Twister only 127 bit internal state
|
||||
*
|
||||
* @author Mutsuo Saito (Hiroshima University)
|
||||
* @author Makoto Matsumoto (The University of Tokyo)
|
||||
*
|
||||
* Copyright (C) 2011 Mutsuo Saito, Makoto Matsumoto,
|
||||
* Hiroshima University and The University of Tokyo.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The 3-clause BSD License is applied to this software, see
|
||||
* LICENSE.txt
|
||||
*/
|
||||
|
||||
/* Note: this is a stripped-down version of TinyMT that only includes the
|
||||
32-bit integer generator. For the full version, please see
|
||||
<https://github.com/MersenneTwister-Lab/TinyMT>. */
|
||||
|
||||
#include "tinymt32.h"
|
||||
|
||||
#define TINYMT32_SH0 1
|
||||
#define TINYMT32_SH1 10
|
||||
#define TINYMT32_SH8 8
|
||||
#define TINYMT32_MASK 0x7fffffff
|
||||
|
||||
/**
|
||||
* This function changes internal state of tinymt32.
|
||||
* Users should not call this function directly.
|
||||
* @param random tinymt internal status
|
||||
*/
|
||||
static void tinymt32_next_state(tinymt32_t * random) {
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
|
||||
y = random->status[3];
|
||||
x = (random->status[0] & TINYMT32_MASK)
|
||||
^ random->status[1]
|
||||
^ random->status[2];
|
||||
x ^= (x << TINYMT32_SH0);
|
||||
y ^= (y >> TINYMT32_SH0) ^ x;
|
||||
random->status[0] = random->status[1];
|
||||
random->status[1] = random->status[2];
|
||||
random->status[2] = x ^ (y << TINYMT32_SH1);
|
||||
random->status[3] = y;
|
||||
random->status[1] ^= -((int32_t)(y & 1)) & random->mat1;
|
||||
random->status[2] ^= -((int32_t)(y & 1)) & random->mat2;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function outputs 32-bit unsigned integer from internal state.
|
||||
* Users should not call this function directly.
|
||||
* @param random tinymt internal status
|
||||
* @return 32-bit unsigned pseudorandom number
|
||||
*/
|
||||
static uint32_t tinymt32_temper(tinymt32_t * random) {
|
||||
uint32_t t0, t1;
|
||||
t0 = random->status[3];
|
||||
#if defined(LINEARITY_CHECK)
|
||||
t1 = random->status[0]
|
||||
^ (random->status[2] >> TINYMT32_SH8);
|
||||
#else
|
||||
t1 = random->status[0]
|
||||
+ (random->status[2] >> TINYMT32_SH8);
|
||||
#endif
|
||||
t0 ^= t1;
|
||||
t0 ^= -((int32_t)(t1 & 1)) & random->tmat;
|
||||
return t0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function outputs 32-bit unsigned integer from internal state.
|
||||
* @param random tinymt internal status
|
||||
* @return 32-bit unsigned integer r (0 <= r < 2^32)
|
||||
*/
|
||||
uint32_t tinymt32_generate_uint32(tinymt32_t * random) {
|
||||
tinymt32_next_state(random);
|
||||
return tinymt32_temper(random);
|
||||
}
|
||||
|
||||
#define MIN_LOOP 8
|
||||
#define PRE_LOOP 8
|
||||
|
||||
/**
|
||||
* This function certificate the period of 2^127-1.
|
||||
* @param random tinymt state vector.
|
||||
*/
|
||||
static void period_certification(tinymt32_t * random) {
|
||||
if ((random->status[0] & TINYMT32_MASK) == 0 &&
|
||||
random->status[1] == 0 &&
|
||||
random->status[2] == 0 &&
|
||||
random->status[3] == 0) {
|
||||
random->status[0] = 'T';
|
||||
random->status[1] = 'I';
|
||||
random->status[2] = 'N';
|
||||
random->status[3] = 'Y';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function initializes the internal state array with a 32-bit
|
||||
* unsigned integer seed.
|
||||
* @param random tinymt state vector.
|
||||
* @param seed a 32-bit unsigned integer used as a seed.
|
||||
*/
|
||||
void tinymt32_init(tinymt32_t * random, uint32_t seed) {
|
||||
random->status[0] = seed;
|
||||
random->status[1] = random->mat1;
|
||||
random->status[2] = random->mat2;
|
||||
random->status[3] = random->tmat;
|
||||
for (int i = 1; i < MIN_LOOP; i++) {
|
||||
random->status[i & 3] ^= i + UINT32_C(1812433253)
|
||||
* (random->status[(i - 1) & 3]
|
||||
^ (random->status[(i - 1) & 3] >> 30));
|
||||
}
|
||||
period_certification(random);
|
||||
for (int i = 0; i < PRE_LOOP; i++) {
|
||||
tinymt32_next_state(random);
|
||||
}
|
||||
}
|
40
src/3rdparty/tinymt32/tinymt32.h
vendored
40
src/3rdparty/tinymt32/tinymt32.h
vendored
|
@ -1,40 +0,0 @@
|
|||
#ifndef TINYMT32_H
|
||||
#define TINYMT32_H
|
||||
/**
|
||||
* @file tinymt32.h
|
||||
*
|
||||
* @brief Tiny Mersenne Twister only 127 bit internal state
|
||||
*
|
||||
* @author Mutsuo Saito (Hiroshima University)
|
||||
* @author Makoto Matsumoto (University of Tokyo)
|
||||
*
|
||||
* Copyright (C) 2011 Mutsuo Saito, Makoto Matsumoto,
|
||||
* Hiroshima University and The University of Tokyo.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The 3-clause BSD License is applied to this software, see
|
||||
* LICENSE.txt
|
||||
*/
|
||||
|
||||
/* Note: this is a stripped-down version of TinyMT that only includes the
|
||||
32-bit integer generator. For the full version, please see
|
||||
<https://github.com/MersenneTwister-Lab/TinyMT>. */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* tinymt32 internal state vector and parameters
|
||||
*/
|
||||
struct TINYMT32_T {
|
||||
uint32_t status[4];
|
||||
uint32_t mat1;
|
||||
uint32_t mat2;
|
||||
uint32_t tmat;
|
||||
};
|
||||
|
||||
typedef struct TINYMT32_T tinymt32_t;
|
||||
|
||||
uint32_t tinymt32_generate_uint32(tinymt32_t *random);
|
||||
void tinymt32_init(tinymt32_t *random, uint32_t seed);
|
||||
|
||||
#endif
|
|
@ -5,6 +5,7 @@
|
|||
#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>
|
||||
|
@ -26,10 +27,9 @@ const clock_frequency_t *clock_freq(void)
|
|||
// SH7705 Clock signals
|
||||
//---
|
||||
|
||||
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
|
||||
#define CPG SH7705_CPG
|
||||
#if GINT_HW_FX
|
||||
|
||||
static void sh7705_probe(void)
|
||||
void sh7705_probe(void)
|
||||
{
|
||||
/* According to Sentaro21 in the sources of Ftune 1.0.1, the clock mode
|
||||
is thought to be 5, which means that:
|
||||
|
@ -41,36 +41,24 @@ static void sh7705_probe(void)
|
|||
int ckio = xtal * pll2;
|
||||
|
||||
/* This signal is multiplied by the PLL1 circuit */
|
||||
int pll1 = CPG.FRQCR.STC + 1;
|
||||
int pll1 = SH7705_CPG.FRQCR.STC + 1;
|
||||
|
||||
/* Iphi and Pphi have dividers (Bphi is always equal to CKIO) */
|
||||
int idiv = CPG.FRQCR.IFC;
|
||||
int pdiv = CPG.FRQCR.PFC;
|
||||
|
||||
/* Fill in the setting structure */
|
||||
/* Fill in the setting structure. Iϕ and Pϕ have dividers, while Bϕ is
|
||||
always equal to CKIO. */
|
||||
freq.PLL1 = pll1;
|
||||
freq.PLL2 = pll2;
|
||||
freq.Bphi_div = 1;
|
||||
freq.Iphi_div = idiv + 1;
|
||||
freq.Pphi_div = pdiv + 1;
|
||||
|
||||
/* Deduce the frequency of the main clocks. This value is ckio/3 */
|
||||
int ckio_3 = 9830400;
|
||||
|
||||
/* Exchange the setting values 2 and 3 (corresponding to /3 and /4)
|
||||
This means that /1, /2, /4 are now 0, 1, 2, which is perfect for a
|
||||
quick bit shift */
|
||||
idiv = idiv ^ (idiv >> 1);
|
||||
pdiv = pdiv ^ (pdiv >> 1);
|
||||
freq.Iphi_div = SH7705_CPG.FRQCR.IFC + 1;
|
||||
freq.Pphi_div = SH7705_CPG.FRQCR.PFC + 1;
|
||||
|
||||
/* Deduce the frequency of the main clocks */
|
||||
freq.CKIO_f = ckio;
|
||||
freq.Bphi_f = ckio;
|
||||
freq.Iphi_f = (idiv == 3) ? ckio_3 : ckio >> idiv;
|
||||
freq.Pphi_f = (pdiv == 3) ? ckio_3 : ckio >> pdiv;
|
||||
freq.Iphi_f = (ckio * pll1) / freq.Iphi_div;
|
||||
freq.Pphi_f = (ckio * pll1) / freq.Pphi_div;
|
||||
}
|
||||
|
||||
#undef CPG
|
||||
#endif /* FX9860G and platform-agnostic */
|
||||
#endif
|
||||
|
||||
//---
|
||||
// SH7305 clock signals
|
||||
|
@ -82,7 +70,7 @@ static void sh7305_probe(void)
|
|||
{
|
||||
/* The meaning of the PLL setting on SH7305 differs from the
|
||||
documentation of SH7224; the value must not be doubled. */
|
||||
int pll = CPG.FRQCRA.STC + 1;
|
||||
int pll = CPG.FRQCR.STC + 1;
|
||||
freq.PLL = pll;
|
||||
|
||||
/* The FLL ratio is the value of the setting, halved if SELXM=1 */
|
||||
|
@ -93,9 +81,9 @@ static void sh7305_probe(void)
|
|||
/* On SH7724, the divider ratio is given by 1 / (setting + 1), but on
|
||||
the SH7305 it is 1 / (2^setting + 1). */
|
||||
|
||||
int divb = CPG.FRQCRA.BFC;
|
||||
int divi = CPG.FRQCRA.IFC;
|
||||
int divp = CPG.FRQCRA.P1FC;
|
||||
int divb = CPG.FRQCR.BFC;
|
||||
int divi = CPG.FRQCR.IFC;
|
||||
int divp = CPG.FRQCR.P1FC;
|
||||
|
||||
freq.Bphi_div = 1 << (divb + 1);
|
||||
freq.Iphi_div = 1 << (divi + 1);
|
||||
|
@ -115,24 +103,28 @@ static void sh7305_probe(void)
|
|||
|
||||
#undef CPG
|
||||
|
||||
|
||||
//---
|
||||
// Initialization
|
||||
//---
|
||||
|
||||
void cpg_compute_freq(void)
|
||||
{
|
||||
/* This avoids warnings about sh7705_probe() being undefined when
|
||||
building for fxcg50 */
|
||||
#if GINT_HW_FX
|
||||
isSH3() ? sh7705_probe() :
|
||||
#endif
|
||||
sh7305_probe();
|
||||
}
|
||||
|
||||
static void configure(void)
|
||||
{
|
||||
/* Disable spread spectrum in SSGSCR */
|
||||
if(isSH4())
|
||||
{
|
||||
SH7305_CPG.SSCGCR.SSEN = 0;
|
||||
}
|
||||
|
||||
/* This avoids warnings about sh7705_probe() being undefined when
|
||||
building for fxcg50 */
|
||||
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
|
||||
isSH3() ? sh7705_probe() :
|
||||
#endif
|
||||
sh7305_probe();
|
||||
cpg_compute_freq();
|
||||
}
|
||||
|
||||
//---
|
||||
|
@ -141,12 +133,16 @@ static void configure(void)
|
|||
|
||||
static void hsave(cpg_state_t *s)
|
||||
{
|
||||
if(isSH4()) s->SSCGCR = SH7305_CPG.SSCGCR.lword;
|
||||
if(isSH4())
|
||||
s->SSCGCR = SH7305_CPG.SSCGCR.lword;
|
||||
cpg_get_overclock_setting(&s->speed);
|
||||
}
|
||||
|
||||
static void hrestore(cpg_state_t const *s)
|
||||
{
|
||||
if(isSH4()) SH7305_CPG.SSCGCR.lword = s->SSCGCR;
|
||||
if(isSH4())
|
||||
SH7305_CPG.SSCGCR.lword = s->SSCGCR;
|
||||
cpg_set_overclock_setting(&s->speed);
|
||||
}
|
||||
|
||||
gint_driver_t drv_cpg = {
|
||||
|
|
514
src/cpg/overclock.c
Normal file
514
src/cpg/overclock.c
Normal file
|
@ -0,0 +1,514 @@
|
|||
//---
|
||||
// gint:cpg:overclock - Clock speed control
|
||||
//
|
||||
// Most of the data in this file has been reused from Sentaro21's Ftune and
|
||||
// Ptune utilities, which have long been the standard for overclocking CASIO
|
||||
// calculators.
|
||||
// See: http://pm.matrix.jp/ftune2e.html
|
||||
//
|
||||
// SlyVTT also contributed early testing on both the fx-CG 10/20 and fx-CG 50.
|
||||
//---
|
||||
|
||||
#include <gint/clock.h>
|
||||
#include <gint/gint.h>
|
||||
#include <gint/hardware.h>
|
||||
#include <gint/mpu/cpg.h>
|
||||
#include <gint/mpu/bsc.h>
|
||||
#include <gint/mpu/wdt.h>
|
||||
|
||||
//---
|
||||
// Low-level clock speed access
|
||||
//---
|
||||
|
||||
#define SH7305_SDMR3_CL2 ((volatile uint8_t *)0xFEC15040)
|
||||
#define SH7305_SDMR3_CL3 ((volatile uint8_t *)0xFEC15060)
|
||||
|
||||
//---
|
||||
// Predefined clock speeds
|
||||
//---
|
||||
|
||||
/* SH7305 CPG */
|
||||
#define SH4_PLL_32x 0b011111
|
||||
#define SH4_PLL_26x 0b011001
|
||||
#define SH4_PLL_16x 0b001111
|
||||
#define SH4_DIV_2 0
|
||||
#define SH4_DIV_4 1
|
||||
#define SH4_DIV_8 2
|
||||
#define SH4_DIV_16 3
|
||||
#define SH4_DIV_32 4
|
||||
|
||||
/* SH7705-like CPG */
|
||||
#define SH3_PLL_1x 0
|
||||
#define SH3_PLL_2x 1
|
||||
#define SH3_PLL_3x 2
|
||||
#define SH3_PLL_4x 3
|
||||
#define SH3_DIV_1 0
|
||||
#define SH3_DIV_2 1
|
||||
#define SH3_DIV_3 2
|
||||
#define SH3_DIV_4 3
|
||||
|
||||
void cpg_get_overclock_setting(struct cpg_overclock_setting *s)
|
||||
{
|
||||
if(isSH3()) {
|
||||
s->FLLFRQ = -1;
|
||||
s->FRQCR = SH7705_CPG.FRQCR.word;
|
||||
|
||||
s->CS0BCR = SH7705_BSC.CS0BCR.lword;
|
||||
s->CS0WCR = SH7705_BSC.CS0WCR.lword;
|
||||
s->CS2BCR = SH7705_BSC.CS2BCR.lword;
|
||||
s->CS2WCR = SH7705_BSC.CS2WCR.lword;
|
||||
s->CS3BCR = SH7705_BSC.CS3BCR.lword;
|
||||
s->CS3WCR = SH7705_BSC.CS3WCR.lword;
|
||||
s->CS5aBCR = SH7705_BSC.CS5ABCR.lword;
|
||||
s->CS5aWCR = SH7705_BSC.CS5AWCR.lword;
|
||||
}
|
||||
else {
|
||||
s->FLLFRQ = SH7305_CPG.FLLFRQ.lword;
|
||||
s->FRQCR = SH7305_CPG.FRQCR.lword;
|
||||
|
||||
s->CS0BCR = SH7305_BSC.CS0BCR.lword;
|
||||
s->CS0WCR = SH7305_BSC.CS0WCR.lword;
|
||||
s->CS2BCR = SH7305_BSC.CS2BCR.lword;
|
||||
s->CS2WCR = SH7305_BSC.CS2WCR.lword;
|
||||
s->CS3BCR = SH7305_BSC.CS3BCR.lword;
|
||||
s->CS3WCR = SH7305_BSC.CS3WCR.lword;
|
||||
s->CS5aBCR = SH7305_BSC.CS5ABCR.lword;
|
||||
s->CS5aWCR = SH7305_BSC.CS5AWCR.lword;
|
||||
}
|
||||
}
|
||||
|
||||
static void cpg_low_level_set_setting(struct cpg_overclock_setting const *s)
|
||||
{
|
||||
if(isSH3()) {
|
||||
SH7705_WDT.WTCNT.WRITE = 0;
|
||||
SH7705_WDT.WTCSR.WRITE = 0x65;
|
||||
SH7705_CPG.FRQCR.word = s->FRQCR | 0x1000;
|
||||
SH7705_BSC.CS0BCR.lword = s->CS0BCR;
|
||||
SH7705_BSC.CS0WCR.lword = s->CS0WCR;
|
||||
SH7705_BSC.CS2BCR.lword = s->CS2BCR;
|
||||
SH7705_BSC.CS2WCR.lword = s->CS2WCR;
|
||||
SH7705_BSC.CS3BCR.lword = s->CS3BCR;
|
||||
SH7705_BSC.CS3WCR.lword = s->CS3WCR;
|
||||
SH7705_BSC.CS5ABCR.lword = s->CS5aBCR;
|
||||
SH7705_BSC.CS5AWCR.lword = s->CS5aWCR;
|
||||
}
|
||||
else {
|
||||
SH7305_BSC.CS0WCR.WR = 11; /* 18 cycles */
|
||||
|
||||
SH7305_CPG.FLLFRQ.lword = s->FLLFRQ;
|
||||
SH7305_CPG.FRQCR.lword = s->FRQCR;
|
||||
SH7305_CPG.FRQCR.KICK = 1;
|
||||
while(SH7305_CPG.LSTATS != 0) {}
|
||||
|
||||
SH7305_BSC.CS0BCR.lword = s->CS0BCR;
|
||||
SH7305_BSC.CS0WCR.lword = s->CS0WCR;
|
||||
SH7305_BSC.CS2BCR.lword = s->CS2BCR;
|
||||
SH7305_BSC.CS2WCR.lword = s->CS2WCR;
|
||||
SH7305_BSC.CS3BCR.lword = s->CS3BCR;
|
||||
SH7305_BSC.CS3WCR.lword = s->CS3WCR;
|
||||
|
||||
if(SH7305_BSC.CS3WCR.A3CL == 1)
|
||||
*SH7305_SDMR3_CL2 = 0;
|
||||
else
|
||||
*SH7305_SDMR3_CL3 = 0;
|
||||
|
||||
SH7305_BSC.CS5ABCR.lword = s->CS5aBCR;
|
||||
SH7305_BSC.CS5AWCR.lword = s->CS5aWCR;
|
||||
}
|
||||
}
|
||||
|
||||
void cpg_set_overclock_setting(struct cpg_overclock_setting const *s)
|
||||
{
|
||||
uint32_t old_Pphi = clock_freq()->Pphi_f;
|
||||
|
||||
/* Wait for asynchronous tasks to complete */
|
||||
gint_world_sync();
|
||||
|
||||
/* Disable interrupts during the change */
|
||||
cpu_atomic_start();
|
||||
|
||||
/* Load the clock settings */
|
||||
cpg_low_level_set_setting(s);
|
||||
|
||||
/* Determine the change in frequency for Pϕ and recompute CPG data */
|
||||
cpg_compute_freq();
|
||||
uint32_t new_Pphi = clock_freq()->Pphi_f;
|
||||
|
||||
/* Update timers' TCNT and TCOR to match the new clock speed */
|
||||
void timer_rescale(uint32_t old_Pphi, uint32_t new_Pphi);
|
||||
timer_rescale(old_Pphi, new_Pphi);
|
||||
|
||||
cpu_atomic_end();
|
||||
}
|
||||
|
||||
#if GINT_HW_FX
|
||||
|
||||
static struct cpg_overclock_setting const settings_fx9860g_sh3[5] = {
|
||||
/* CLOCK_SPEED_F1 */
|
||||
{ .FRQCR = 0x1001,
|
||||
.CS0BCR = 0x02480400,
|
||||
.CS2BCR = 0x02483400,
|
||||
.CS3BCR = 0x36DB0600,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x00000140,
|
||||
.CS2WCR = 0x00000140,
|
||||
.CS3WCR = 0x00000500,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
/* CLOCK_SPEED_F2 */
|
||||
{ .FRQCR = (SH3_PLL_2x<<8)+(SH3_DIV_1<<4)+SH3_DIV_2,
|
||||
.CS0BCR = 0x02480400,
|
||||
.CS2BCR = 0x02483400,
|
||||
.CS3BCR = 0x36DB0600,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x00000140,
|
||||
.CS2WCR = 0x00000140,
|
||||
.CS3WCR = 0x00000500,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
/* CLOCK_SPEED_F3 */
|
||||
{ .FRQCR = (SH3_PLL_3x<<8)+(SH3_DIV_1<<4)+SH3_DIV_3,
|
||||
.CS0BCR = 0x02480400,
|
||||
.CS2BCR = 0x02483400,
|
||||
.CS3BCR = 0x36DB0600,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x00000140,
|
||||
.CS2WCR = 0x00000140,
|
||||
.CS3WCR = 0x00000500,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
/* CLOCK_SPEED_F4 */
|
||||
{ .FRQCR = (SH3_PLL_4x<<8)+(SH3_DIV_1<<4)+SH3_DIV_4,
|
||||
.CS0BCR = 0x02480400,
|
||||
.CS2BCR = 0x02483400,
|
||||
.CS3BCR = 0x36DB0600,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x00000140,
|
||||
.CS2WCR = 0x00000140,
|
||||
.CS3WCR = 0x00000500,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
/* CLOCK_SPEED_F5 */
|
||||
{ .FRQCR = (SH3_PLL_4x<<8)+(SH3_DIV_1<<4)+SH3_DIV_4,
|
||||
.CS0BCR = 0x02480400,
|
||||
.CS2BCR = 0x02483400,
|
||||
.CS3BCR = 0x36DB0600,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x000000C0,
|
||||
.CS2WCR = 0x000100C0,
|
||||
.CS3WCR = 0x00000500,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
};
|
||||
|
||||
static struct cpg_overclock_setting const settings_fx9860g_sh4[5] = {
|
||||
/* CLOCK_SPEED_F1 */
|
||||
{ .FLLFRQ = 0x00004384,
|
||||
.FRQCR = 0x0F202203,
|
||||
.CS0BCR = 0x24920400,
|
||||
.CS2BCR = 0x24923400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x000005C0,
|
||||
.CS2WCR = 0x00000140,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
/* CLOCK_SPEED_F2 */
|
||||
{ .FLLFRQ = 0x00004384,
|
||||
.FRQCR = (SH4_PLL_16x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16,
|
||||
.CS0BCR = 0x24920400,
|
||||
.CS2BCR = 0x24923400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x000001C0,
|
||||
.CS2WCR = 0x00000140,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
/* CLOCK_SPEED_F3 */
|
||||
{ .FLLFRQ = 0x00004384,
|
||||
.FRQCR = (SH4_PLL_16x<<24)+(SH4_DIV_8<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16,
|
||||
.CS0BCR = 0x04900400,
|
||||
.CS2BCR = 0x04903400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x24920200,
|
||||
.CS0WCR = 0x00000140,
|
||||
.CS2WCR = 0x00000140,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
/* CLOCK_SPEED_F4 */
|
||||
{ .FLLFRQ = 0x00004384,
|
||||
.FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16,
|
||||
.CS0BCR = 0x04900400,
|
||||
.CS2BCR = 0x04903400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x000001C0,
|
||||
.CS2WCR = 0x00020140,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
/* CLOCK_SPEED_F5 */
|
||||
{ .FLLFRQ = 0x00004384,
|
||||
.FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_2<<20)+(SH4_DIV_4<<12)+(SH4_DIV_4<<8)+SH4_DIV_16,
|
||||
.CS0BCR = 0x14900400,
|
||||
.CS2BCR = 0x04903400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x000003C0,
|
||||
.CS2WCR = 0x000302C0,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
};
|
||||
|
||||
static struct cpg_overclock_setting const settings_g35pe2[5] = {
|
||||
/* CLOCK_SPEED_F1 */
|
||||
{ .FLLFRQ = 0x00004384,
|
||||
.FRQCR = 0x0F112213,
|
||||
.CS0BCR = 0x24920400,
|
||||
.CS2BCR = 0x24923400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x000001C0,
|
||||
.CS2WCR = 0x000001C0,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00031340 },
|
||||
/* CLOCK_SPEED_F2 */
|
||||
{ .FLLFRQ = 0x00004384,
|
||||
.FRQCR = (SH4_PLL_16x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16,
|
||||
.CS0BCR = 0x24920400,
|
||||
.CS2BCR = 0x24923400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x000001C0,
|
||||
.CS2WCR = 0x00000140,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
/* CLOCK_SPEED_F3 */
|
||||
{ .FLLFRQ = 0x00004384,
|
||||
.FRQCR = (SH4_PLL_16x<<24)+(SH4_DIV_8<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16,
|
||||
.CS0BCR = 0x04900400,
|
||||
.CS2BCR = 0x04903400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x24920200,
|
||||
.CS0WCR = 0x00000140,
|
||||
.CS2WCR = 0x00000140,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00000D41 },
|
||||
/* CLOCK_SPEED_F4 */
|
||||
{ .FLLFRQ = 0x00004384,
|
||||
.FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16,
|
||||
.CS0BCR = 0x04900400,
|
||||
.CS2BCR = 0x04903400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x000001C0,
|
||||
.CS2WCR = 0x00020140,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00031B40 },
|
||||
/* CLOCK_SPEED_F5 */
|
||||
{ .FLLFRQ = 0x00004384,
|
||||
.FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_2<<20)+(SH4_DIV_4<<12)+(SH4_DIV_8<<8)+SH4_DIV_16,
|
||||
.CS0BCR = 0x14900400,
|
||||
.CS2BCR = 0x04903400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x224A0200,
|
||||
.CS0WCR = 0x000001C0,
|
||||
.CS2WCR = 0x00020140,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00031B40 },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if GINT_HW_CG
|
||||
|
||||
static struct cpg_overclock_setting const settings_prizm[5] = {
|
||||
/* CLOCK_SPEED_F1 */
|
||||
{ .FLLFRQ = 0x00004000 + 900,
|
||||
.FRQCR = 0x0F102203,
|
||||
.CS0BCR = 0x24920400,
|
||||
.CS2BCR = 0x24923400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x15140400,
|
||||
.CS0WCR = 0x000001C0,
|
||||
.CS2WCR = 0x00000140,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00010240 },
|
||||
/* CLOCK_SPEED_F2 */
|
||||
{ .FLLFRQ = 0x00004000 + 900,
|
||||
.FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_8<<20)+(SH4_DIV_16<<12)+(SH4_DIV_16<<8)+SH4_DIV_32,
|
||||
.CS0BCR = 0x04900400,
|
||||
.CS2BCR = 0x04903400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x15140400,
|
||||
.CS0WCR = 0x00000140,
|
||||
.CS2WCR = 0x000100C0,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00010240 },
|
||||
/* CLOCK_SPEED_F3 */
|
||||
{ .FLLFRQ = 0x00004000 + 900,
|
||||
.FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_32,
|
||||
.CS0BCR = 0x24900400,
|
||||
.CS2BCR = 0x04903400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x15140400,
|
||||
.CS0WCR = 0x000002C0,
|
||||
.CS2WCR = 0x000201C0,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00010240 },
|
||||
/* CLOCK_SPEED_F4 */
|
||||
{ .FLLFRQ = 0x00004000 + 900,
|
||||
.FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_4<<12)+(SH4_DIV_4<<8)+SH4_DIV_32,
|
||||
.CS0BCR = 0x44900400,
|
||||
.CS2BCR = 0x04903400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x15140400,
|
||||
.CS0WCR = 0x00000440,
|
||||
.CS2WCR = 0x00040340,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00010240 },
|
||||
/* CLOCK_SPEED_F5 */
|
||||
{ .FLLFRQ = 0x00004000 + 900,
|
||||
.FRQCR = (SH4_PLL_26x<<24)+(SH4_DIV_2<<20)+(SH4_DIV_4<<12)+(SH4_DIV_4<<8)+SH4_DIV_16,
|
||||
.CS0BCR = 0x34900400,
|
||||
.CS2BCR = 0x04903400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x15140400,
|
||||
.CS0WCR = 0x000003C0,
|
||||
.CS2WCR = 0x000402C0,
|
||||
.CS3WCR = 0x000024D0,
|
||||
.CS5aWCR = 0x00010240 },
|
||||
};
|
||||
|
||||
static struct cpg_overclock_setting const settings_fxcg50[5] = {
|
||||
/* CLOCK_SPEED_F1 */
|
||||
{ .FLLFRQ = 0x00004000 + 900,
|
||||
.FRQCR = 0x0F011112,
|
||||
.CS0BCR = 0x36DA0400,
|
||||
.CS2BCR = 0x36DA3400,
|
||||
.CS3BCR = 0x36DB4400,
|
||||
.CS5aBCR = 0x17DF0400,
|
||||
.CS0WCR = 0x000003C0,
|
||||
.CS2WCR = 0x000003C0,
|
||||
.CS3WCR = 0x000024D1,
|
||||
.CS5aWCR = 0x000203C1 },
|
||||
/* CLOCK_SPEED_F2 */
|
||||
{ .FLLFRQ = 0x00004000 + 900,
|
||||
.FRQCR = (SH4_PLL_16x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_8,
|
||||
.CS0BCR = 0x24920400,
|
||||
.CS2BCR = 0x24923400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x17DF0400,
|
||||
.CS0WCR = 0x00000340,
|
||||
.CS2WCR = 0x000003C0,
|
||||
.CS3WCR = 0x000024D1,
|
||||
.CS5aWCR = 0x000203C1 },
|
||||
/* CLOCK_SPEED_F3 */
|
||||
{ .FLLFRQ = 0x00004000 + 900,
|
||||
.FRQCR = (SH4_PLL_26x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_8,
|
||||
.CS0BCR = 0x24920400,
|
||||
.CS2BCR = 0x24923400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x17DF0400,
|
||||
.CS0WCR = 0x00000240,
|
||||
.CS2WCR = 0x000003C0,
|
||||
.CS3WCR = 0x000024D1,
|
||||
.CS5aWCR = 0x000203C1 },
|
||||
/* CLOCK_SPEED_F4 */
|
||||
{ .FLLFRQ = 0x00004000 + 900,
|
||||
.FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_2<<20)+(SH4_DIV_4<<12)+(SH4_DIV_8<<8)+SH4_DIV_16,
|
||||
.CS0BCR = 0x24920400,
|
||||
.CS2BCR = 0x24923400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x17DF0400,
|
||||
.CS0WCR = 0x000002C0,
|
||||
.CS2WCR = 0x000003C0,
|
||||
.CS3WCR = 0x000024D1,
|
||||
.CS5aWCR = 0x000203C1 },
|
||||
/* CLOCK_SPEED_F5 */
|
||||
{ .FLLFRQ = 0x00004000 + 900,
|
||||
.FRQCR = (SH4_PLL_26x<<24)+(SH4_DIV_2<<20)+(SH4_DIV_4<<12)+(SH4_DIV_4<<8)+SH4_DIV_8,
|
||||
.CS0BCR = 0x24920400,
|
||||
.CS2BCR = 0x24923400,
|
||||
.CS3BCR = 0x24924400,
|
||||
.CS5aBCR = 0x17DF0400,
|
||||
.CS0WCR = 0x00000440,
|
||||
.CS2WCR = 0x000003C0,
|
||||
.CS3WCR = 0x000024D1,
|
||||
.CS5aWCR = 0x000203C1 },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static struct cpg_overclock_setting const *get_settings(void)
|
||||
{
|
||||
#if GINT_HW_FX
|
||||
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
|
||||
|
||||
#if GINT_HW_CG
|
||||
if(gint[HWCALC] == HWCALC_PRIZM)
|
||||
return settings_prizm;
|
||||
if(gint[HWCALC] == HWCALC_FXCG50)
|
||||
return settings_fxcg50;
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int clock_get_speed(void)
|
||||
{
|
||||
struct cpg_overclock_setting const *settings = get_settings();
|
||||
if(!settings)
|
||||
return CLOCK_SPEED_UNKNOWN;
|
||||
|
||||
if(isSH3()) {
|
||||
for(int i = 0; i < 5; i++) {
|
||||
struct cpg_overclock_setting const *s = &settings[i];
|
||||
|
||||
if(SH7705_CPG.FRQCR.word == (s->FRQCR | 0x1000)
|
||||
&& SH7705_BSC.CS0BCR.lword == s->CS0BCR
|
||||
&& SH7705_BSC.CS2BCR.lword == s->CS2BCR
|
||||
&& SH7705_BSC.CS3BCR.lword == s->CS3BCR
|
||||
&& SH7705_BSC.CS5ABCR.lword == s->CS5aBCR
|
||||
&& SH7705_BSC.CS0WCR.lword == s->CS0WCR
|
||||
&& SH7705_BSC.CS2WCR.lword == s->CS2WCR
|
||||
&& SH7705_BSC.CS3WCR.lword == s->CS3WCR
|
||||
&& SH7705_BSC.CS5AWCR.lword == s->CS5aWCR)
|
||||
return CLOCK_SPEED_F1 + i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(int i = 0; i < 5; i++) {
|
||||
struct cpg_overclock_setting const *s = &settings[i];
|
||||
|
||||
if(SH7305_CPG.FLLFRQ.lword == s->FLLFRQ
|
||||
&& SH7305_CPG.FRQCR.lword == s->FRQCR
|
||||
&& SH7305_BSC.CS0BCR.lword == s->CS0BCR
|
||||
&& SH7305_BSC.CS2BCR.lword == s->CS2BCR
|
||||
&& SH7305_BSC.CS3BCR.lword == s->CS3BCR
|
||||
&& SH7305_BSC.CS5ABCR.lword == s->CS5aBCR
|
||||
&& SH7305_BSC.CS0WCR.lword == s->CS0WCR
|
||||
&& SH7305_BSC.CS2WCR.lword == s->CS2WCR
|
||||
&& SH7305_BSC.CS3WCR.lword == s->CS3WCR
|
||||
&& SH7305_BSC.CS5AWCR.lword == s->CS5aWCR)
|
||||
return CLOCK_SPEED_F1 + i;
|
||||
}
|
||||
}
|
||||
|
||||
return CLOCK_SPEED_UNKNOWN;
|
||||
}
|
||||
|
||||
void clock_set_speed(int level)
|
||||
{
|
||||
if(level < CLOCK_SPEED_F1 || level > CLOCK_SPEED_F5)
|
||||
return;
|
||||
if(clock_get_speed() == level)
|
||||
return;
|
||||
|
||||
struct cpg_overclock_setting const *settings = get_settings();
|
||||
if(!settings)
|
||||
return;
|
||||
|
||||
struct cpg_overclock_setting const *s = &settings[level - CLOCK_SPEED_F1];
|
||||
cpg_set_overclock_setting(s);
|
||||
}
|
|
@ -45,6 +45,15 @@ static void hsave(cpu_state_t *s)
|
|||
s->CPUOPM = cpu_getCPUOPM();
|
||||
s->SR = cpu_getSR().lword;
|
||||
}
|
||||
|
||||
__asm__("stc r0_bank, %0" : "=r"(s->rN_bank[0]));
|
||||
__asm__("stc r1_bank, %0" : "=r"(s->rN_bank[1]));
|
||||
__asm__("stc r2_bank, %0" : "=r"(s->rN_bank[2]));
|
||||
__asm__("stc r3_bank, %0" : "=r"(s->rN_bank[3]));
|
||||
__asm__("stc r4_bank, %0" : "=r"(s->rN_bank[4]));
|
||||
__asm__("stc r5_bank, %0" : "=r"(s->rN_bank[5]));
|
||||
__asm__("stc r6_bank, %0" : "=r"(s->rN_bank[6]));
|
||||
__asm__("stc r7_bank, %0" : "=r"(s->rN_bank[7]));
|
||||
}
|
||||
|
||||
static void hrestore(cpu_state_t const *s)
|
||||
|
@ -55,6 +64,15 @@ static void hrestore(cpu_state_t const *s)
|
|||
cpu_setCPUOPM(s->CPUOPM);
|
||||
cpu_setSR((cpu_sr_t)s->SR);
|
||||
}
|
||||
|
||||
__asm__("ldc %0, r0_bank" :: "r"(s->rN_bank[0]));
|
||||
__asm__("ldc %0, r1_bank" :: "r"(s->rN_bank[1]));
|
||||
__asm__("ldc %0, r2_bank" :: "r"(s->rN_bank[2]));
|
||||
__asm__("ldc %0, r3_bank" :: "r"(s->rN_bank[3]));
|
||||
__asm__("ldc %0, r4_bank" :: "r"(s->rN_bank[4]));
|
||||
__asm__("ldc %0, r5_bank" :: "r"(s->rN_bank[5]));
|
||||
__asm__("ldc %0, r6_bank" :: "r"(s->rN_bank[6]));
|
||||
__asm__("ldc %0, r7_bank" :: "r"(s->rN_bank[7]));
|
||||
}
|
||||
|
||||
gint_driver_t drv_cpu = {
|
||||
|
|
64
src/cpu/ics.s
Normal file
64
src/cpu/ics.s
Normal file
|
@ -0,0 +1,64 @@
|
|||
.global _cpu_csleep_init
|
||||
.global _cpu_csleep
|
||||
.global _cpu_csleep_cancel
|
||||
|
||||
_cpu_csleep_init:
|
||||
mov.l .memcpy, r1
|
||||
mova sleep, r0
|
||||
mov r0, r5
|
||||
jmp @r1
|
||||
mov #(sleep_end - sleep), r6
|
||||
|
||||
.align 4
|
||||
.memcpy:
|
||||
.long _memcpy
|
||||
|
||||
_cpu_csleep:
|
||||
mov.l r8, @-r15
|
||||
sts.l pr, @-r15
|
||||
mov r4, r8
|
||||
|
||||
/* Check if the sleep instruction is still there */
|
||||
1: mov.w @(8, r8), r0
|
||||
extu.w r0, r0
|
||||
cmp/eq #0x001b, r0
|
||||
bf 2f
|
||||
|
||||
/* Invalidate the cache in case of previous ICS being cached */
|
||||
mov r8, r0
|
||||
icbi @r0
|
||||
add #18, r0
|
||||
icbi @r0
|
||||
|
||||
/* Execute the sleep, and loop */
|
||||
jsr @r8
|
||||
nop
|
||||
bra 1b
|
||||
nop
|
||||
|
||||
2: lds.l @r15+, pr
|
||||
rts
|
||||
mov.l @r15+, r8
|
||||
|
||||
_cpu_csleep_cancel:
|
||||
mov #0x0009, r0
|
||||
add #8, r4
|
||||
mov.w r0, @r4
|
||||
icbi @r4
|
||||
rts
|
||||
nop
|
||||
|
||||
.align 4
|
||||
|
||||
/* This is identical in functionality to the CPU driver's sleep() function */
|
||||
sleep:
|
||||
mov.l 2f, r0
|
||||
mov.l @r0, r0
|
||||
cmp/pl r0
|
||||
bt 1f
|
||||
sleep
|
||||
1: rts
|
||||
nop
|
||||
nop
|
||||
2: .long _cpu_sleep_block_counter
|
||||
sleep_end:
|
|
@ -8,6 +8,7 @@
|
|||
#include <gint/drivers/states.h>
|
||||
#include <gint/clock.h>
|
||||
#include <gint/exc.h>
|
||||
#include <gint/cpu.h>
|
||||
|
||||
#define DMA SH7305_DMA
|
||||
#define POWER SH7305_POWER
|
||||
|
@ -18,6 +19,8 @@ typedef volatile sh7305_dma_channel_t channel_t;
|
|||
static gint_call_t dma_callbacks[6] = { 0 };
|
||||
/* Sleep blocking flags for all channels */
|
||||
static bool dma_sleep_blocking[6] = { 0 };
|
||||
/* ICS for dma_channel_wait() for all channels */
|
||||
static cpu_csleep_t *dma_wait_ics[6] = { 0 };
|
||||
|
||||
/* dma_channel(): Get address of a DMA channel */
|
||||
static channel_t *dma_channel(int channel)
|
||||
|
@ -113,6 +116,11 @@ static int dma_setup(int channel, dma_size_t size, uint blocks,
|
|||
if(ch->DAR >= 0xe5007000 && ch->DAR <= 0xe5204000)
|
||||
dma_sleep_blocking[channel] = true;
|
||||
|
||||
if(ch->SAR >= 0xfe200000 && ch->SAR <= 0xfe3fffff)
|
||||
dma_sleep_blocking[channel] = true;
|
||||
if(ch->DAR >= 0xfe200000 && ch->DAR <= 0xfe3fffff)
|
||||
dma_sleep_blocking[channel] = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -138,6 +146,7 @@ bool dma_transfer_async(int channel, dma_size_t size, uint blocks,
|
|||
static void dma_interrupt_transfer_ended(int channel)
|
||||
{
|
||||
channel_t *ch = dma_channel(channel);
|
||||
ch->CHCR.IE = 0;
|
||||
ch->CHCR.DE = 0;
|
||||
ch->CHCR.TE = 0;
|
||||
|
||||
|
@ -147,31 +156,60 @@ static void dma_interrupt_transfer_ended(int channel)
|
|||
if(dma_sleep_blocking[channel])
|
||||
sleep_unblock();
|
||||
|
||||
if(dma_callbacks[channel].function)
|
||||
/* Cancel any sleep operation that is synchronized with this interrupt */
|
||||
if(dma_wait_ics[channel])
|
||||
cpu_csleep_cancel(dma_wait_ics[channel]);
|
||||
|
||||
gint_call(dma_callbacks[channel]);
|
||||
dma_callbacks[channel] = GINT_CALL_NULL;
|
||||
}
|
||||
|
||||
/* dma_channel_wait(): Wait for a particular channel's transfer to finish
|
||||
|
||||
This function is used both during normal gint operation and during foreign
|
||||
unbinds of the DMA driver. The waiting method varies with interrupt settings
|
||||
and device ownership. */
|
||||
static void dma_channel_wait(int channel, bool foreign)
|
||||
{
|
||||
channel_t *ch = dma_channel(channel);
|
||||
if(!ch) return;
|
||||
|
||||
/* If interrupts are disabled or we don't own the device, spin-wait by
|
||||
checking either for TE to be set (Transfer Ended) or DE to be gone
|
||||
(channel disabled).
|
||||
|
||||
There are definitely race conditions if the DMA is restarted between
|
||||
our checks; only the context of the calls guarantee soundness.
|
||||
|
||||
* If interrupts are disabled, we assume there is no one that could
|
||||
start the DMA again, since we are the only thread of execution.
|
||||
* If the device is owned by another kernel, then we're transitioning
|
||||
so we have to wait for *all* tasks to complete anyway. The risk is
|
||||
rather to stop too early. */
|
||||
if(!ch->CHCR.IE || foreign)
|
||||
{
|
||||
gint_call(dma_callbacks[channel]);
|
||||
dma_callbacks[channel] = GINT_CALL_NULL;
|
||||
while(ch->CHCR.DE && !ch->CHCR.TE) {}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize an interrupt-cancellable sleep, to ensure
|
||||
synchronization */
|
||||
cpu_csleep_t ics;
|
||||
cpu_csleep_init(&ics);
|
||||
dma_wait_ics[channel] = &ics;
|
||||
|
||||
/* Now the ICS is set; if the interrupt has not occurred yet then the
|
||||
handler is guaranteed to cancel the sleep at some point */
|
||||
if(ch->CHCR.DE && !ch->CHCR.TE) cpu_csleep(&ics);
|
||||
|
||||
/* Clear the ICS pointer for next time */
|
||||
dma_wait_ics[channel] = NULL;
|
||||
}
|
||||
|
||||
/* dma_transfer_wait(): Wait for a transfer to finish */
|
||||
void dma_transfer_wait(int channel)
|
||||
{
|
||||
if(channel < 0)
|
||||
{
|
||||
for(int channel = 0; channel < 6; channel++)
|
||||
dma_transfer_wait(channel);
|
||||
return;
|
||||
}
|
||||
|
||||
channel_t *ch = dma_channel(channel);
|
||||
if(!ch) return;
|
||||
|
||||
while(ch->CHCR.DE && !ch->CHCR.TE)
|
||||
{
|
||||
/* Sleep only if the interrupt is enabled to wake us up */
|
||||
if(ch->CHCR.IE) sleep();
|
||||
}
|
||||
dma_channel_wait(channel, false);
|
||||
}
|
||||
|
||||
bool dma_transfer_sync(int channel, dma_size_t size, uint length,
|
||||
|
@ -258,10 +296,18 @@ static void configure(void)
|
|||
DMA.OR.DME = 1;
|
||||
}
|
||||
|
||||
static void universal_unbind(void)
|
||||
static void funbind(void)
|
||||
{
|
||||
/* Make sure any DMA transfer is finished before leaving the app */
|
||||
dma_transfer_wait(-1);
|
||||
/* Wait for all OS transfers to finish before taking over */
|
||||
for(int channel = 0; channel < 6; channel++)
|
||||
dma_channel_wait(channel, true);
|
||||
}
|
||||
|
||||
static void unbind(void)
|
||||
{
|
||||
/* Make sure all DMA transfers are finished before leaving gint */
|
||||
for(int channel = 0; channel < 6; channel++)
|
||||
dma_channel_wait(channel, false);
|
||||
}
|
||||
|
||||
static bool hpowered(void)
|
||||
|
@ -322,8 +368,8 @@ static void hrestore(dma_state_t const *s)
|
|||
gint_driver_t drv_dma0 = {
|
||||
.name = "DMA",
|
||||
.configure = configure,
|
||||
.funbind = universal_unbind,
|
||||
.unbind = universal_unbind,
|
||||
.funbind = funbind,
|
||||
.unbind = unbind,
|
||||
.hpowered = hpowered,
|
||||
.hpoweron = hpoweron,
|
||||
.hpoweroff = hpoweroff,
|
||||
|
|
|
@ -4,6 +4,18 @@
|
|||
void *dma_memcpy(void * __restrict dst, const void * __restrict src,
|
||||
size_t size)
|
||||
{
|
||||
dma_transfer_sync(1, DMA_32B, size >> 5, src, DMA_INC, dst, DMA_INC);
|
||||
int block_size = DMA_32B;
|
||||
int block_count = size >> 5;
|
||||
|
||||
/* Use 4-byte transfers to access SPU memory */
|
||||
if(((uint32_t)src >= 0xfe200000 && (uint32_t)src < 0xfe400000) ||
|
||||
((uint32_t)dst >= 0xfe200000 && (uint32_t)dst < 0xfe400000))
|
||||
{
|
||||
block_size = DMA_4B;
|
||||
block_count = size >> 2;
|
||||
}
|
||||
|
||||
dma_transfer_sync(1, block_size, block_count, src, DMA_INC, dst,
|
||||
DMA_INC);
|
||||
return dst;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,17 @@ void *dma_memset(void *dst, uint32_t l, size_t size)
|
|||
different memory regions, making the DMA faster than the CPU. */
|
||||
for(int i = 0; i < 8; i++) ILbuf[i] = l;
|
||||
|
||||
dma_transfer_sync(1, DMA_32B, size>>5, ILbuf, DMA_FIXED, dst, DMA_INC);
|
||||
int block_size = DMA_32B;
|
||||
int block_count = size >> 5;
|
||||
|
||||
/* Use 4-byte transfers to access SPU memory */
|
||||
if((uint32_t)dst >= 0xfe200000 && (uint32_t)dst < 0xfe400000)
|
||||
{
|
||||
block_size = DMA_4B;
|
||||
block_count = size >> 2;
|
||||
}
|
||||
|
||||
dma_transfer_sync(1, block_size, block_count, ILbuf, DMA_FIXED, dst,
|
||||
DMA_INC);
|
||||
return dst;
|
||||
}
|
||||
|
|
19
src/fs/close.c
Normal file
19
src/fs/close.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include <unistd.h>
|
||||
#include <gint/fs.h>
|
||||
#include <errno.h>
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
fs_descriptor_t const *d = fs_get_descriptor(fd);
|
||||
if(!d) {
|
||||
errno = EBADF;
|
||||
return (ssize_t)-1;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
if(d->type->close)
|
||||
rc = d->type->close(d->data);
|
||||
|
||||
fs_free_descriptor(fd);
|
||||
return rc;
|
||||
}
|
10
src/fs/closedir.c
Normal file
10
src/fs/closedir.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int closedir(DIR *dp)
|
||||
{
|
||||
int rc = close(dp->fd);
|
||||
free(dp);
|
||||
return rc;
|
||||
}
|
6
src/fs/creat.c
Normal file
6
src/fs/creat.c
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
int creat(char const *path, mode_t mode)
|
||||
{
|
||||
return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
|
||||
}
|
27
src/fs/fdopendir.c
Normal file
27
src/fs/fdopendir.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <gint/fs.h>
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "fugue/fugue.h"
|
||||
|
||||
DIR *fdopendir(int fd)
|
||||
{
|
||||
fs_descriptor_t const *desc = fs_get_descriptor(fd);
|
||||
if(desc == NULL) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
if(desc->type != &fugue_dir_descriptor_type) {
|
||||
errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DIR *dp = malloc(sizeof *dp);
|
||||
if(!dp) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dp->fd = fd;
|
||||
return dp;
|
||||
}
|
103
src/fs/fs.c
Normal file
103
src/fs/fs.c
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include <gint/fs.h>
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* File descriptor table */
|
||||
static fs_descriptor_t *fdtable;
|
||||
|
||||
fs_descriptor_t const *fs_get_descriptor(int fd)
|
||||
{
|
||||
if(!fdtable || (unsigned)fd >= FS_FD_MAX)
|
||||
return NULL;
|
||||
if(fdtable[fd].type == NULL)
|
||||
return NULL;
|
||||
|
||||
return &fdtable[fd];
|
||||
}
|
||||
|
||||
int fs_create_descriptor(fs_descriptor_t const *data)
|
||||
{
|
||||
if(!fdtable || data->type == NULL)
|
||||
return -1;
|
||||
|
||||
/* Leave 0/1/2 for stdin, stdout and stderr */
|
||||
for(int i = 3; i < FS_FD_MAX; i++) {
|
||||
if(fdtable[i].type == NULL) {
|
||||
fdtable[i] = *data;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void fs_free_descriptor(int fd)
|
||||
{
|
||||
if(!fdtable || (unsigned)fd >= FS_FD_MAX)
|
||||
return;
|
||||
|
||||
fdtable[fd].type = NULL;
|
||||
fdtable[fd].data = NULL;
|
||||
}
|
||||
|
||||
int open_generic(fs_descriptor_type_t const *type, void *data, int fd)
|
||||
{
|
||||
if(!fdtable) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
if(!type) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
fs_descriptor_t d = {
|
||||
.type = type,
|
||||
.data = data
|
||||
};
|
||||
|
||||
/* Re-use file descriptor mode */
|
||||
if(fd >= 0) {
|
||||
if(fd >= FS_FD_MAX) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
if(fdtable[fd].type) {
|
||||
errno = ENFILE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdtable[fd] = d;
|
||||
return fd;
|
||||
}
|
||||
/* Normal allocation mode */
|
||||
else {
|
||||
return fs_create_descriptor(&d);
|
||||
}
|
||||
}
|
||||
|
||||
/* Standard streams */
|
||||
|
||||
static fs_descriptor_type_t const devnull = {
|
||||
.read = NULL,
|
||||
.write = NULL,
|
||||
.lseek = NULL,
|
||||
.close = NULL,
|
||||
};
|
||||
|
||||
GCONSTRUCTOR static void init_fs(void)
|
||||
{
|
||||
fdtable = calloc(FS_FD_MAX, sizeof *fdtable);
|
||||
if(!fdtable)
|
||||
return;
|
||||
|
||||
fdtable[STDIN_FILENO].type = &devnull;
|
||||
fdtable[STDIN_FILENO].data = NULL;
|
||||
|
||||
fdtable[STDOUT_FILENO].type = &devnull;
|
||||
fdtable[STDOUT_FILENO].data = NULL;
|
||||
|
||||
fdtable[STDERR_FILENO].type = &devnull;
|
||||
fdtable[STDERR_FILENO].data = NULL;
|
||||
}
|
24
src/fs/fugue/BFile_Ext_Stat.c
Normal file
24
src/fs/fugue/BFile_Ext_Stat.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include <gint/bfile.h>
|
||||
#include "util.h"
|
||||
|
||||
int BFile_Ext_Stat(uint16_t const *path, int *type, int *size)
|
||||
{
|
||||
int search_handle, rc;
|
||||
uint16_t found_file[256];
|
||||
struct BFile_FileInfo fileinfo;
|
||||
|
||||
rc = BFile_FindFirst(path, &search_handle, found_file, &fileinfo);
|
||||
if(rc < 0) {
|
||||
if(type) *type = -1;
|
||||
if(size) *size = -1;
|
||||
rc = -1;
|
||||
}
|
||||
else {
|
||||
if(type) *type = fileinfo.type;
|
||||
if(size) *size = fileinfo.file_size;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
BFile_FindClose(search_handle);
|
||||
return rc;
|
||||
}
|
145
src/fs/fugue/fugue.c
Normal file
145
src/fs/fugue/fugue.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
#include <gint/fs.h>
|
||||
#include <gint/hardware.h>
|
||||
#include <gint/bfile.h>
|
||||
#include <gint/mmu.h>
|
||||
#include <gint/defs/util.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "fugue.h"
|
||||
#include "util.h"
|
||||
|
||||
ssize_t fugue_read(void *data0, void *buf, size_t size)
|
||||
{
|
||||
fugue_fd_t *data = data0;
|
||||
int fugue_fd = data->fd;
|
||||
|
||||
/* Fugue allows to read past EOF up to the end of the sector */
|
||||
int filesize = BFile_Size(fugue_fd);
|
||||
if(data->pos + (int)size > filesize)
|
||||
size = filesize - data->pos;
|
||||
|
||||
int rc = BFile_Read(fugue_fd, buf, size, -1);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
return -1;
|
||||
}
|
||||
data->pos += rc;
|
||||
return size;
|
||||
}
|
||||
|
||||
static void *temp_ram(size_t total_size, size_t *block_size)
|
||||
{
|
||||
for(size_t candidate = 16384; candidate >= 64; candidate >>= 1) {
|
||||
if(candidate > 64 && candidate >= 2 * total_size)
|
||||
continue;
|
||||
|
||||
size_t size = min(candidate, total_size);
|
||||
void *ram = malloc(size);
|
||||
if(ram) {
|
||||
*block_size = size;
|
||||
return ram;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t fugue_write(void *data0, const void *buf, size_t size)
|
||||
{
|
||||
fugue_fd_t *data = data0;
|
||||
int fugue_fd = data->fd;
|
||||
|
||||
/* The main concern of this function is that we cannot write from ROM.
|
||||
If [buf] is in ROM then we have to copy it to RAM, preferably within
|
||||
the limits of available heap memory. */
|
||||
if(mmu_is_rom(buf)) {
|
||||
size_t alloc_size, written=0;
|
||||
|
||||
void *ram = temp_ram(size, &alloc_size);
|
||||
if(!ram) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(written < size) {
|
||||
size_t block_size = min(size - written, alloc_size);
|
||||
memcpy(ram, buf + written, block_size);
|
||||
|
||||
int rc = BFile_Write(fugue_fd, ram, block_size);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
written = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
written += rc;
|
||||
data->pos += rc;
|
||||
|
||||
/* Partial write */
|
||||
if(rc < (int)block_size) break;
|
||||
}
|
||||
|
||||
free(ram);
|
||||
return written;
|
||||
}
|
||||
/* Otherwise, we can write normally */
|
||||
else {
|
||||
int rc = BFile_Write(fugue_fd, buf, size);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
return -1;
|
||||
}
|
||||
data->pos += rc;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
off_t fugue_lseek(void *data0, off_t offset, int whence)
|
||||
{
|
||||
fugue_fd_t *data = data0;
|
||||
int fugue_fd = data->fd;
|
||||
|
||||
int filesize = BFile_Size(fugue_fd);
|
||||
|
||||
if(whence == SEEK_CUR)
|
||||
offset += data->pos;
|
||||
else if(whence == SEEK_END)
|
||||
offset += filesize;
|
||||
|
||||
/* BFile_Seek() clamps to the file size, but still returns the argument
|
||||
when it does... */
|
||||
offset = min(offset, filesize);
|
||||
|
||||
int rc = BFile_Seek(fugue_fd, offset);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
return -1;
|
||||
}
|
||||
data->pos = offset;
|
||||
|
||||
/* rc is the amount of space left in the file (including pre-allocated
|
||||
space), so instead just return offset directly */
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fugue_close(void *data0)
|
||||
{
|
||||
fugue_fd_t *data = data0;
|
||||
int fugue_fd = data->fd;
|
||||
|
||||
int rc = BFile_Close(fugue_fd);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
return -1;
|
||||
}
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const fs_descriptor_type_t fugue_descriptor_type = {
|
||||
.read = fugue_read,
|
||||
.write = fugue_write,
|
||||
.lseek = fugue_lseek,
|
||||
.close = fugue_close,
|
||||
};
|
40
src/fs/fugue/fugue.h
Normal file
40
src/fs/fugue/fugue.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#ifndef FS_FUGUE_FUGUE_H
|
||||
#define FS_FUGUE_FUGUE_H
|
||||
|
||||
#include <gint/fs.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* File descriptor type */
|
||||
extern const fs_descriptor_type_t fugue_descriptor_type;
|
||||
/* Directory descriptor type */
|
||||
extern const fs_descriptor_type_t fugue_dir_descriptor_type;
|
||||
|
||||
/* Since on Graph 35+E II / fx-9860G III there is no (known) syscall to update
|
||||
the file position, we need to track it ourselves, hopefully faithfully. */
|
||||
typedef struct {
|
||||
int fd;
|
||||
int pos;
|
||||
} fugue_fd_t;
|
||||
|
||||
/* Specific implementations of some standard functions */
|
||||
|
||||
int fugue_open(char const *path, int flags, mode_t mode);
|
||||
|
||||
int fugue_unlink(char const *path);
|
||||
|
||||
int fugue_rename(char const *oldpath, char const *newpath);
|
||||
|
||||
int fugue_mkdir(char const *path, mode_t mode);
|
||||
|
||||
int fugue_rmdir(char const *path);
|
||||
|
||||
int fugue_stat(char const * restrict path, struct stat * restrict statbuf);
|
||||
|
||||
/* Other functions */
|
||||
|
||||
void *fugue_dir_explore(char const *path);
|
||||
|
||||
#endif /* FS_FUGUE_FUGUE_H */
|
161
src/fs/fugue/fugue_dir.c
Normal file
161
src/fs/fugue/fugue_dir.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
#include <gint/fs.h>
|
||||
#include <gint/hardware.h>
|
||||
#include <gint/bfile.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
#include "fugue.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Number of entries */
|
||||
int count;
|
||||
/* All entries */
|
||||
struct dirent **entries;
|
||||
/* Current position in directory */
|
||||
off_t pos;
|
||||
|
||||
} dir_t;
|
||||
|
||||
/* There is no well-standardized API for reading from directory descriptors.
|
||||
getdents(2) is a thing, but it's mostly Linux-specific and has no glibc
|
||||
wrapper, so no userspace application is using it directly. We define our
|
||||
directory descriptor interface to mimic opendir(3) for efficiency. */
|
||||
|
||||
ssize_t fugue_dir_read(void *data, void *buf, GUNUSED size_t size)
|
||||
{
|
||||
struct dirent **dirent_ptr = buf;
|
||||
if(size < sizeof *dirent_ptr)
|
||||
return 0;
|
||||
|
||||
dir_t *dp = data;
|
||||
if(dp->pos >= dp->count)
|
||||
*dirent_ptr = NULL;
|
||||
else
|
||||
*dirent_ptr = dp->entries[dp->pos++];
|
||||
|
||||
return sizeof *dirent_ptr;
|
||||
}
|
||||
|
||||
ssize_t fugue_dir_write(GUNUSED void *data, GUNUSED const void *buf,
|
||||
GUNUSED size_t size)
|
||||
{
|
||||
errno = EISDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
off_t fugue_dir_lseek(void *data, off_t offset, int whence)
|
||||
{
|
||||
dir_t *dp = data;
|
||||
|
||||
if(whence == SEEK_CUR)
|
||||
offset += dp->pos;
|
||||
if(whence == SEEK_END)
|
||||
offset += dp->count;
|
||||
|
||||
/* dp->count, being at the end of the enumeration, is a valid offset */
|
||||
if(offset < 0 || offset >= dp->count + 1) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dp->pos = offset;
|
||||
return dp->pos;
|
||||
}
|
||||
|
||||
int fugue_dir_close(void *data)
|
||||
{
|
||||
dir_t *dp = data;
|
||||
|
||||
if(dp && dp->entries) {
|
||||
for(int i = 0; i < dp->count; i++)
|
||||
free(dp->entries[i]);
|
||||
free(dp->entries);
|
||||
}
|
||||
free(dp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const fs_descriptor_type_t fugue_dir_descriptor_type = {
|
||||
.read = fugue_dir_read,
|
||||
.write = fugue_dir_write,
|
||||
.lseek = fugue_dir_lseek,
|
||||
.close = fugue_dir_close,
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
dp->count = 0;
|
||||
dp->entries = NULL;
|
||||
dp->pos = 0;
|
||||
|
||||
fc_path = malloc(512 * sizeof *fc_path);
|
||||
if(!fc_path) goto alloc_failure;
|
||||
|
||||
wildcard = malloc(strlen(path) + 3);
|
||||
if(!wildcard) goto alloc_failure;
|
||||
strcpy(wildcard, path);
|
||||
strcat(wildcard, "/*");
|
||||
|
||||
search = fs_path_normalize_fc(wildcard);
|
||||
if(!search) goto alloc_failure;
|
||||
|
||||
rc = BFile_FindFirst(search, &sd, fc_path, &info);
|
||||
if(rc < 0) {
|
||||
if(rc != BFile_EntryNotFound)
|
||||
errno = bfile_error_to_errno(rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
do {
|
||||
if(dp->count+1 > allocated) {
|
||||
struct dirent **new_entries = realloc(dp->entries,
|
||||
(allocated + 8) * sizeof *dp->entries);
|
||||
if(!new_entries)
|
||||
goto alloc_failure;
|
||||
dp->entries = new_entries;
|
||||
allocated += 8;
|
||||
}
|
||||
|
||||
size_t name_length = fc_len(fc_path);
|
||||
size_t s = sizeof(struct dirent) + name_length + 1;
|
||||
struct dirent *ent = malloc(s);
|
||||
if(!ent) goto alloc_failure;
|
||||
|
||||
ent->d_ino = 0;
|
||||
ent->d_type = bfile_type_to_dirent(info.type);
|
||||
fc_to_utf8(ent->d_name, fc_path, name_length + 1);
|
||||
dp->entries[dp->count++] = ent;
|
||||
|
||||
rc = BFile_FindNext(sd, fc_path, &info);
|
||||
}
|
||||
while(rc >= 0);
|
||||
goto end;
|
||||
|
||||
alloc_failure:
|
||||
errno = ENOMEM;
|
||||
error:
|
||||
fugue_dir_close(dp);
|
||||
dp = NULL;
|
||||
end:
|
||||
free(wildcard);
|
||||
free(search);
|
||||
free(fc_path);
|
||||
if(sd >= 0)
|
||||
BFile_FindClose(sd);
|
||||
return dp;
|
||||
}
|
26
src/fs/fugue/fugue_mkdir.c
Normal file
26
src/fs/fugue/fugue_mkdir.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <gint/hardware.h>
|
||||
#include <gint/bfile.h>
|
||||
#include <gint/fs.h>
|
||||
#include <errno.h>
|
||||
#include "util.h"
|
||||
|
||||
int fugue_mkdir(char const *path, GUNUSED mode_t mode)
|
||||
{
|
||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||
|
||||
uint16_t *fcpath = fs_path_normalize_fc(path);
|
||||
if(!fcpath) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rc = BFile_Create(fcpath, BFile_Folder, NULL);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
free(fcpath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(fcpath);
|
||||
return 0;
|
||||
}
|
147
src/fs/fugue/fugue_open.c
Normal file
147
src/fs/fugue/fugue_open.c
Normal file
|
@ -0,0 +1,147 @@
|
|||
#include <gint/fs.h>
|
||||
#include <gint/bfile.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
#include "fugue.h"
|
||||
|
||||
static int new_file_size;
|
||||
|
||||
int fugue_open(char const *path, int flags, GUNUSED mode_t mode)
|
||||
{
|
||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||
|
||||
uint16_t *fcpath = fs_path_normalize_fc(path);
|
||||
int fugue_fd, err, rc=-1, type, fd=-1;
|
||||
|
||||
if(!fcpath) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open mode */
|
||||
int bfile_mode = BFile_ReadOnly;
|
||||
if(flags & O_WRONLY)
|
||||
bfile_mode = BFile_WriteOnly;
|
||||
else if(flags & O_RDWR)
|
||||
bfile_mode = BFile_ReadWrite;
|
||||
|
||||
/* Exclusive open means no sense unless creation is also requested */
|
||||
bool excl = (flags & O_EXCL) && (flags & O_CREAT);
|
||||
/* Truncation requires the file to be removed/recreated */
|
||||
bool trunc = (flags & O_TRUNC) && (flags & O_CREAT);
|
||||
|
||||
/* Stat the entry. A special case is needed for the root, which doesn't
|
||||
respond well. fs_path_normalize_fc() normalizes the path so we just
|
||||
have to check for the fixed string "\\fls0\". */
|
||||
bool exists;
|
||||
if(!memcmp(fcpath, u"\\\\fls0\\", 16)) {
|
||||
exists = true;
|
||||
type = BFile_Type_Directory;
|
||||
}
|
||||
else {
|
||||
exists = (BFile_Ext_Stat(fcpath, &type, NULL) == 0);
|
||||
if(!exists) type = -1;
|
||||
}
|
||||
|
||||
/* If the entry exists and O_EXCL was requested, fail. */
|
||||
if(exists && excl) {
|
||||
errno = EEXIST;
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* If the entry is not a directory but O_DIRECTORY is set, fail. If the
|
||||
directory doesn't exist, we fail regardless of O_CREAT. */
|
||||
if((flags & O_DIRECTORY) && type != BFile_Type_Directory) {
|
||||
errno = (exists ? ENOTDIR : ENOENT);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
};
|
||||
fd = fs_create_descriptor(&data);
|
||||
rc = fd;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Try and open the file normally, unless O_TRUNC is specified without
|
||||
O_EXCL, in which case we simply delete and recreate the file. */
|
||||
if(trunc)
|
||||
fugue_fd = BFile_EntryNotFound;
|
||||
else
|
||||
fugue_fd = BFile_Open(fcpath, bfile_mode);
|
||||
|
||||
/* If O_TRUNC is requested and either the file exists or we can create
|
||||
it, remove it. (If fugue_fd < 0 an opening error might still have
|
||||
occurred so we delete it just in case.) */
|
||||
if((flags & O_TRUNC) && (fugue_fd >= 0 || (flags & O_CREAT))) {
|
||||
if(fugue_fd >= 0)
|
||||
BFile_Close(fugue_fd);
|
||||
BFile_Remove(fcpath);
|
||||
fugue_fd = BFile_EntryNotFound;
|
||||
}
|
||||
|
||||
/* If the file does not exist and O_CREAT is set, create it */
|
||||
if((flags & O_CREAT) && ((flags & O_TRUNC) || fugue_fd < 0)) {
|
||||
new_file_size = 0;
|
||||
err = BFile_Create(fcpath, BFile_File, &new_file_size);
|
||||
if(err < 0) {
|
||||
errno = bfile_error_to_errno(err);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
fugue_fd = BFile_Open(fcpath, bfile_mode);
|
||||
}
|
||||
|
||||
if(fugue_fd < 0) {
|
||||
errno = bfile_error_to_errno(fugue_fd);
|
||||
rc = fugue_fd;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* If O_APPEND is set, move to the end of the file */
|
||||
// TODO: O_APPEND should move the cursor before *each* write
|
||||
int pos = 0;
|
||||
if((flags & O_APPEND)) {
|
||||
pos = BFile_Size(fugue_fd);
|
||||
BFile_Seek(fugue_fd, pos);
|
||||
}
|
||||
|
||||
/* Return the now-open file descriptor */
|
||||
fugue_fd_t *data = malloc(sizeof *data);
|
||||
if(!data) {
|
||||
BFile_Close(fugue_fd);
|
||||
goto end;
|
||||
}
|
||||
data->fd = fugue_fd;
|
||||
data->pos = pos;
|
||||
|
||||
fs_descriptor_t fd_data = {
|
||||
.type = &fugue_descriptor_type,
|
||||
.data = data,
|
||||
};
|
||||
rc = fd = fs_create_descriptor(&fd_data);
|
||||
|
||||
if(fd == -1) {
|
||||
BFile_Close(fugue_fd);
|
||||
free(data);
|
||||
errno = ENFILE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
free(fcpath);
|
||||
return rc;
|
||||
}
|
38
src/fs/fugue/fugue_rename.c
Normal file
38
src/fs/fugue/fugue_rename.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <gint/hardware.h>
|
||||
#include <gint/bfile.h>
|
||||
#include <gint/fs.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include "util.h"
|
||||
|
||||
int fugue_rename(char const *oldpath, char const *newpath)
|
||||
{
|
||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||
int rc = -1;
|
||||
|
||||
uint16_t *fcpath_1 = NULL;
|
||||
uint16_t *fcpath_2 = NULL;
|
||||
|
||||
fcpath_1 = fs_path_normalize_fc(oldpath);
|
||||
if(!fcpath_1) {
|
||||
errno = ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
fcpath_2 = fs_path_normalize_fc(newpath);
|
||||
if(!fcpath_2) {
|
||||
errno = ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = BFile_Rename(fcpath_1, fcpath_2);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
rc = -1;
|
||||
}
|
||||
else rc = 0;
|
||||
|
||||
end:
|
||||
free(fcpath_1);
|
||||
free(fcpath_2);
|
||||
return rc;
|
||||
}
|
51
src/fs/fugue/fugue_rmdir.c
Normal file
51
src/fs/fugue/fugue_rmdir.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include <gint/hardware.h>
|
||||
#include <gint/bfile.h>
|
||||
#include <gint/fs.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
#include "fugue.h"
|
||||
|
||||
int fugue_rmdir(char const *path)
|
||||
{
|
||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||
|
||||
/* Check if the folder is empty */
|
||||
DIR *dp = opendir(path);
|
||||
if(!dp) return -1;
|
||||
|
||||
bool empty = true;
|
||||
struct dirent *ent;
|
||||
|
||||
while((ent = readdir(dp))) {
|
||||
if(strcmp(ent->d_name, ".") != 0 &&
|
||||
strcmp(ent->d_name, "..") != 0) {
|
||||
empty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
|
||||
if(!empty) {
|
||||
errno = ENOTEMPTY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t *fcpath = fs_path_normalize_fc(path);
|
||||
if(!fcpath) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rc = BFile_Remove(fcpath);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
rc = -1;
|
||||
}
|
||||
else rc = 0;
|
||||
|
||||
free(fcpath);
|
||||
return rc;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue