From 789ba7caa5af724313fbbb8adb55c47386a374ff Mon Sep 17 00:00:00 2001 From: Lephe Date: Tue, 16 Apr 2024 15:53:10 +0200 Subject: [PATCH] gint: basic support for fx-CP 400 programs with HollyHock 2 loading Features will come in slowly while I restructure for gint 3. With this third big target for gint, the legacy aspects of gint 2's structure and API are getting felt, so a major revision will be in order. See the TODO file at this commit for info on what works and not. --- CMakeLists.txt | 13 +++ TODO | 26 ++++- cmake/FindGint.cmake | 4 + fxcp_hh2.ld.c | 189 ++++++++++++++++++++++++++++++++++ include/gint/config.h.in | 14 ++- include/gint/display-cg.h | 5 + include/gint/drivers/r61523.h | 26 +++++ include/gint/hardware.h | 4 +- include/gint/video.h | 6 +- src/kernel/exch.c | 13 ++- src/kernel/hardware.c | 19 ++++ src/kernel/kernel.c | 18 +++- src/kernel/osmenu.c | 9 ++ src/kernel/start.S | 18 ++++ src/kernel/start.c | 6 +- src/kernel/syscalls.S | 35 ++++++- src/kernel/tlbh.S | 11 +- src/kernel/world.c | 5 +- src/r61523/r61523.c | 183 ++++++++++++++++++++++++++++++++ src/render-cg/dclear.c | 6 ++ src/render-cg/dupdate.c | 16 ++- src/render-cg/dvram.c | 36 ++++++- src/render-cg/topti-asm.S | 14 ++- src/usb/classes/ff-bulk.c | 3 +- src/usb/setup.c | 10 +- src/video/video.c | 6 +- 26 files changed, 657 insertions(+), 38 deletions(-) create mode 100644 fxcp_hh2.ld.c create mode 100644 include/gint/drivers/r61523.h create mode 100644 src/kernel/start.S create mode 100644 src/r61523/r61523.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 16ff731..75b118e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,7 @@ set(SOURCES 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 @@ -144,6 +145,8 @@ set(SOURCES src/kmalloc/kmalloc.c # MMU driver src/mmu/mmu.c + # R61523 display driver + src/r61523/r61523.c # R61524 display driver src/r61524/r61524.c # Format-agnostic rendering @@ -250,6 +253,7 @@ set(SOURCES 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( @@ -283,6 +287,14 @@ if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G_G3A) 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 linker scripts @@ -296,6 +308,7 @@ 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_LIB}") diff --git a/TODO b/TODO index 5e9ac98..a0fa6ef 100644 --- a/TODO +++ b/TODO @@ -25,9 +25,6 @@ Future directions: * Make fx9860g projects work out of the box on fxcg50 * Base for Yatis' threads library -TODO: -* SPLIT CONFIG HEADER IN VARIANTS SO THEY DON'T CLASH WHEN INSTALLED - Bits that need to abstract out into APIs: - display: Toggle backlight (or set level) -> Have a backlight property with min/max values @@ -61,6 +58,25 @@ enum { /* Indexed 2-bit: white, light gray, dark gray, black. Represented as a pair of I1MSB buffers, the first being bit #0, the second bit #1. */ IMAGE_FORMAT_2I1MSB, - /* 16-bit RGB565. Row-major, left-to-right. */ - IMAGE_FORMAT_RGB565, }; + +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 diff --git a/cmake/FindGint.cmake b/cmake/FindGint.cmake index 207f632..edd6005 100644 --- a/cmake/FindGint.cmake +++ b/cmake/FindGint.cmake @@ -11,6 +11,10 @@ elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G_G3A) set(PC fxg3a) set(INTF_DEFN FX9860G_G3A) set(INTF_LINK "-T;fxcg50.ld") +elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCP) + set(PC cp) + set(INTF_DEFN FXCP) + set(INTF_LINK "-T;fxcp_hh2.ld") else() message(FATAL_ERROR "gint: unknown fxSDK platform '${FXSDK_PLATFORM}'") endif() diff --git a/fxcp_hh2.ld.c b/fxcp_hh2.ld.c new file mode 100644 index 0000000..25a9edd --- /dev/null +++ b/fxcp_hh2.ld.c @@ -0,0 +1,189 @@ +/* + Linker script for fxCP add-ins linking with HollyHock2. +*/ + +OUTPUT_ARCH(sh4) +OUTPUT_FORMAT(elf32-sh) +ENTRY(_start_header) + +MEMORY +{ + /* Everything mixed together loaded as one */ + ram (rwx): o = 0x8cff0000, l = 61184 /* 64k - 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 +} + +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) */ + .text : { + *(.text.header) + *(.hh2info) + *(.text.entry) + + _bctors = . ; + *(.ctors .ctors.*) + _ectors = . ; + + _bdtors = . ; + *(.dtors .dtors.*) + _edtors = . ; + + _gint_exch_start = . ; + *(.gint.exch) + _gint_exch_size = ABSOLUTE(. - _gint_exch_start); + + _gint_tlbh_start = . ; + *(.gint.tlbh) + _gint_tlbh_size = ABSOLUTE(. - _gint_tlbh_start); + + *(.text .text.*) + } > ram + + /* 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 : { + KEEP(*(.gint.blocks)); + } > ram + + /* 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 : { + _gint_drivers = . ; + KEEP(*(SORT_BY_NAME(.gint.drivers.*))); + _gint_drivers_end = . ; + } > ram + + /* 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 : SUBALIGN(4) { + /* Put these first, they need to be 4-aligned */ + *(.rodata.4) + + *(.rodata .rodata.*) + } > ram + + + + /* + ** RAM sections + */ + + . = ALIGN(16); /* No effect? */ + + /* 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 + + /* Read-write data sub-aligned to 4 bytes (mainly from fxconv) */ + .data.4 : SUBALIGN(4) { + *(.data.4) + . = ALIGN(16); + } > ram + + _sdata = SIZEOF(.data) + SIZEOF(.data.4); + + /* On-chip memory sections: IL, X and Y memory */ + + . = ORIGIN(ilram); + .ilram ALIGN(4) : ALIGN(4) { + _lilram = LOADADDR(.ilram); + _rilram = . ; + + *(.ilram) + + . = ALIGN(16); + } > ilram AT> ram + + . = ORIGIN(xyram); + .xyram ALIGN(4) : ALIGN(4) { + _lxyram = LOADADDR(.xyram); + _rxyram = . ; + + *(.xram .yram .xyram) + + . = ALIGN(16); + } > xyram AT> ram + + _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) + } +} diff --git a/include/gint/config.h.in b/include/gint/config.h.in index 00fc5be..0f5af29 100644 --- a/include/gint/config.h.in +++ b/include/gint/config.h.in @@ -18,11 +18,18 @@ #if defined(FX9860G) # define GINT_HW_FX 1 # define GINT_HW_CG 0 -# define GINT_HW_SWITCH(FX,CG) (FX) +# 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_SWITCH(FX,CG) (CG) +# 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. */ @@ -36,6 +43,7 @@ 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 @@ -70,6 +78,6 @@ /* GINT_RENDER_{MONO,RGB}: Enable the mono/rgb rendering API. Currently these are exclusive. */ #define GINT_RENDER_MONO (GINT_HW_FX || GINT_FX9860G_G3A) -#define GINT_RENDER_RGB (GINT_HW_CG && !GINT_FX9860G_G3A) +#define GINT_RENDER_RGB ((GINT_HW_CG || GINT_HW_CP) && !GINT_FX9860G_G3A) #endif /* GINT_CONFIG */ diff --git a/include/gint/display-cg.h b/include/gint/display-cg.h index ebbdf38..48f4412 100644 --- a/include/gint/display-cg.h +++ b/include/gint/display-cg.h @@ -25,8 +25,13 @@ extern "C" { #include /* 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 diff --git a/include/gint/drivers/r61523.h b/include/gint/drivers/r61523.h new file mode 100644 index 0000000..c4b5b3c --- /dev/null +++ b/include/gint/drivers/r61523.h @@ -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 + +/* 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 */ diff --git a/include/gint/hardware.h b/include/gint/hardware.h index f2e2545..6044ec8 100644 --- a/include/gint/hardware.h +++ b/include/gint/hardware.h @@ -46,7 +46,7 @@ void hw_detect(void); # define isSH3() (gint[HWMPU] & 1) # define isSH4() (!isSH3()) # define isSlim() (gint[HWCALC] == HWCALC_FX9860G_SLIM) -#elif GINT_HW_CG +#elif GINT_HW_CG || GINT_HW_CP # define isSH3() 0 # define isSH4() 1 # define isSlim() 0 @@ -109,6 +109,8 @@ void hw_detect(void); #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 diff --git a/include/gint/video.h b/include/gint/video.h index 6edf0b6..1ba3fe7 100644 --- a/include/gint/video.h +++ b/include/gint/video.h @@ -29,8 +29,10 @@ typedef struct { } video_mode_t; /* Flags for the update function of the interface. */ -#define VIDEO_UPDATE_ENABLE_DMA 0x01 -#define VIDEO_UPDATE_ATOMIC 0x02 +#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 { diff --git a/src/kernel/exch.c b/src/kernel/exch.c index ee8d3f2..b1c11e9 100644 --- a/src/kernel/exch.c +++ b/src/kernel/exch.c @@ -104,7 +104,7 @@ GNORETURN static void gint_default_panic(GUNUSED uint32_t code) dtext(6, 3, "An exception occured! (System ERROR)"); uint32_t *long_vram = (void *)gint_vram; - for(int i = 0; i < 198 * 16; i++) long_vram[i] = ~long_vram[i]; + for(int i = 0; i < (DWIDTH/2) * 16; i++) long_vram[i] = ~long_vram[i]; char const *name = ""; if(code == 0x040) name = "TLB miss (nonexisting address) on read"; @@ -126,20 +126,25 @@ GNORETURN static void gint_default_panic(GUNUSED uint32_t code) dtext(6, 45, "PC"); dprint(38, 45, "= %08x", PC); - dtext(261, 45, "(Error location)"); + dtext(DWIDTH-135, 45, "(Error location)"); dtext(6, 60, "TEA"); dprint(38, 60, "= %08x", TEA); - dtext(234, 60, "(Offending address)"); + dtext(DWIDTH-162, 60, "(Offending address)"); dtext(6, 75, "TRA"); dprint(38, 75, "= %#x", TRA); - dtext(281, 75, "(Trap number)"); + dtext(DWIDTH-115, 75, "(Trap number)"); dtext(6, 95, "The add-in crashed!"); if(kd == NULL) { +#if GINT_HW_CG dtext(6, 108, "Please press the RESET button to restart the"); dtext(6, 121, "calculator."); +#else + dtext(6, 108, "Please press the RESET button to"); + dtext(6, 121, "restart the calculator."); +#endif } else { dtext(6, 121, "[EXIT]: Exit the program with abort()"); diff --git a/src/kernel/hardware.c b/src/kernel/hardware.c index 5b4f834..793c39e 100644 --- a/src/kernel/hardware.c +++ b/src/kernel/hardware.c @@ -145,6 +145,25 @@ void hw_detect(void) utlb_mapped_memory(NULL, NULL); } +#elif GINT_HW_CP + +/* hw_detect(): Basic hardware detection */ +void hw_detect(void) +{ + gint[HWMPU] = HWMPU_SH7305; + gint[HWCPUVR] = PVR; + gint[HWCPUPR] = PRR; + gint[HWCALC] = HWCALC_FXCP400; + // TODO: What filesystem implementation on the fx-CP 400? + gint[HWFS] = HWFS_NONE; + gint[HWRAM] = 16 << 20; + // TOOD: How much ROM on the fx-CP 400? + gint[HWROM] = 0; + + /* There is no userspace so not MMU being used */ + gint[HWURAM] = 0; +} + #else #error unknown hardware type for hw_detect #endif diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index feed797..eec13fb 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -40,8 +40,6 @@ void *gint_stack_top = NULL; /* kinit(): Install and start gint */ void kinit(void) { - uint32_t VBR = 0; - #if GINT_HW_FX /* On fx-9860G, VBR is loaded at the end of the user RAM. On SH4, the end of the user RAM hosts the stack, for which we leave 12 kB @@ -59,7 +57,7 @@ void kinit(void) /* VBR is advanced 0x100 bytes because of an unused gap */ uram_end -= (isSH3() ? 0x600 : 0x1100); - VBR = uram_end - 0x100; + uint32_t VBR = uram_end - 0x100; #endif #if GINT_HW_CG @@ -67,11 +65,16 @@ void kinit(void) script leaves 5 kB (0x1400 bytes) before the start of the data segment. The stack is again placed at the end of the region, and we leave 16 kB. */ - VBR = (uint32_t)mmu_uram(); + uint32_t VBR = (uint32_t)mmu_uram(); uint32_t uram_end = (uint32_t)mmu_uram() + mmu_uram_size() - 0x4000; gint_stack_top = (void *)uram_end; #endif + #if GINT_HW_CP + extern char gint_region_vbr; + uint32_t VBR = (uint32_t)&gint_region_vbr - 0x100; + #endif + /* Event handler entry points */ void *inth_entry = isSH3() ? gint_inth_7705 : gint_inth_7305; uint32_t exch_size = (uint32_t)&gint_exch_size; @@ -85,6 +88,7 @@ void kinit(void) /* Initialize memory allocators */ kmalloc_init(); + #if !GINT_HW_CP /* Create an allocation arena with unused static RAM */ static kmalloc_arena_t static_ram = { 0 }; extern uint32_t euram; @@ -94,6 +98,7 @@ void kinit(void) static_ram.end = (void *)uram_end; kmalloc_init_arena(&static_ram, true); kmalloc_add_arena(&static_ram); + #endif /* Create an arena in the OS stack as well, for VRAM and more data */ #if GINT_HW_CG && !defined(GINT_NO_OS_STACK) @@ -143,6 +148,11 @@ void kquit(void) { gint_world_switch_out(gint_world_addin, gint_world_os); +#if !GINT_OS_FX + extern void dvram_quit(void); + dvram_quit(); +#endif + gint_world_free(gint_world_os); gint_world_free(gint_world_addin); free(gint_driver_flags); diff --git a/src/kernel/osmenu.c b/src/kernel/osmenu.c index 55a5472..ea503cd 100644 --- a/src/kernel/osmenu.c +++ b/src/kernel/osmenu.c @@ -16,6 +16,7 @@ void __ClearKeyBuffer(void); /* ? */ void __ConfigureStatusArea(int mode); void __SetQuitHandler(void (*callback)(void)); +#if !GINT_OS_CP static int __osmenu_id; static void __osmenu_handler(void) @@ -28,6 +29,7 @@ static void __osmenu_handler(void) __Timer_Stop(__osmenu_id); __Timer_Deinstall(__osmenu_id); } +#endif #if GINT_OS_CG typedef void (os_menu_function_t)(void); @@ -94,6 +96,8 @@ static os_menu_function_t *find_os_menu_function(void) void gint_osmenu_native(void) { +// TODO: OS menu on fx-CP +#if !GINT_OS_CP __ClearKeyBuffer(); gint_copy_vram(); @@ -134,6 +138,7 @@ void gint_osmenu_native(void) 1 /* Delay in seconds */, 0 /* Enable return to main menu */, &keycode); +#endif } /* gint_osmenu() - switch out of gint and call the calculator's main menu */ @@ -157,7 +162,11 @@ static void __handler() static void __sethandler() { + (void)__handler; +// TODO: Quit handler on fx-CP +#if !GINT_OS_CP __SetQuitHandler((void *)__handler); +#endif } void gint_set_quit_handler(gint_call_t gcall, bool do_world_switch) diff --git a/src/kernel/start.S b/src/kernel/start.S new file mode 100644 index 0000000..69eeb4e --- /dev/null +++ b/src/kernel/start.S @@ -0,0 +1,18 @@ +#include +#if GINT_OS_CP + +.section .text.header +.global _start_header + +_start_header: + mov.l .start, r0 + jmp @r0 + nop + +.align 2 +.start: + .long _start +.load_addr: + .long _start_header + +#endif diff --git a/src/kernel/start.c b/src/kernel/start.c index ca33608..6c83e3d 100644 --- a/src/kernel/start.c +++ b/src/kernel/start.c @@ -151,11 +151,14 @@ static int start2(int isappli, int optnum) /* Load data sections and wipe the bss section. This has to be done first for static and global variables to be initialized */ - regcpy(&ldata, &sdata, &rdata); + #if !GINT_OS_CP + regcpy(&ldata, &sdata, &rdata); + #endif regclr(&rbss, &sbss); gint_load_onchip_sections(); + #if !GINT_OS_CP /* Copy permanently-mapped code to start of user RAM (this section is only used on fx-9860G; on fx-CG 50 it's fixed in ILRAM) */ void *rgmapped = mmu_uram(); @@ -167,6 +170,7 @@ static int start2(int isappli, int optnum) { fixups[i] += (uint32_t)rgmapped; } + #endif /* Install gint, switch VBR and initialize drivers */ kinit(); diff --git a/src/kernel/syscalls.S b/src/kernel/syscalls.S index 7f43a88..387e18f 100644 --- a/src/kernel/syscalls.S +++ b/src/kernel/syscalls.S @@ -45,6 +45,9 @@ .global ___GetVRAMAddress .global ___ConfigureStatusArea .global ___SetQuitHandler +/* VRAM backup on fx-CP */ +.global ___VRAMBackup +.global ___VRAMRestore /* Reset */ .global ___PowerOff @@ -55,11 +58,18 @@ mov.l 1f, r0 ;\ jmp @r2 ;\ nop ;\ -.align 4 ;\ +.balign 4 ;\ 1: .long id #define syscall(id) syscall_(id, syscall_table) +#define fixed(address) \ + mov.l 1f, r0 ;\ + jmp @r0 ;\ + nop ;\ +.balign 4 ;\ +1: .long address + #if GINT_OS_FX /* Dynamic allocation */ @@ -212,3 +222,26 @@ syscall_table: .long 0x80020070 #endif /* GINT_OS_CG */ + +#if GINT_OS_CP + +___malloc: + fixed(0x800cfb00) +___realloc: + // TODO: realloc for fx-CP? + rts + mov #0, r0 +___free: + fixed(0x800a76fc) + +___GetVRAMAddress: + fixed(0x8002e154) +___VRAMBackup: + fixed(0x8002d3fa) +___VRAMRestore: + fixed(0x8002d41a) + +___Reset: + fixed(0xa0000000) + +#endif /* GINT_OS_CP */ diff --git a/src/kernel/tlbh.S b/src/kernel/tlbh.S index 71c022b..fff5ce9 100644 --- a/src/kernel/tlbh.S +++ b/src/kernel/tlbh.S @@ -10,11 +10,14 @@ #elif GINT_OS_CG # define SYSCALL_TABLE 0x80020070 # define SYSCALL_TLBH 12 +#elif GINT_OS_CP +# define NOMMU 1 #else # error Unknown HW for tlbh.S! #endif _gint_tlbh: +#if ! NOMMU sts.l pr, @-r15 stc.l gbr, @-r15 sts.l mach, @-r15 @@ -50,10 +53,12 @@ map: lds.l @r15+, pr rte nop +#endif panic: - /* Otherwise, panic by defaulting to the exception handler (the TLB - miss may still be resolved by a panic handler) */ + /* Otherwise, or if there is no MMU, panic by defaulting to the + exception handler (the TLB miss may still be resolved by a panic + handler) */ lds.l @r15+, macl lds.l @r15+, mach ldc.l @r15+, gbr @@ -66,6 +71,7 @@ panic: jmp @r0 nop +#if ! NOMMU .align 4 .gint: @@ -80,3 +86,4 @@ panic: .long 0x00300000 + _srom .syscall: .long SYSCALL_TABLE +#endif diff --git a/src/kernel/world.c b/src/kernel/world.c index 301510f..6a39d27 100644 --- a/src/kernel/world.c +++ b/src/kernel/world.c @@ -244,9 +244,12 @@ void gint_copy_vram(void) #endif } -void gint_poweroff(bool show_logo) +void gint_poweroff(GUNUSED bool show_logo) { +// TODO: Power off on fx-CP +#if !GINT_OS_CP void __PowerOff(int show_logo); gint_copy_vram(); gint_world_switch(GINT_CALL(__PowerOff, (int)show_logo)); +#endif } diff --git a/src/r61523/r61523.c b/src/r61523/r61523.c new file mode 100644 index 0000000..598d236 --- /dev/null +++ b/src/r61523/r61523.c @@ -0,0 +1,183 @@ +// Renesas R61523 driver- + +#include +#include +// #include +#include +// #include +#include +#include +#include +#include + +#if GINT_HW_CP + +/* Registers */ +#define REG_HRANGE 0x2a +#define REG_VRANGE 0x2b +#define REG_DATA 0x2c +#define REG_DEVICE_CODE_READ 0xbf + +/* Interface with the controller */ +static volatile uint16_t *DISPLAY = (void *)0xb4000000; +/* Bit 4 of Port R controls the RS bit of the display driver */ +static volatile uint8_t *PRDR = (void *)0xa405013c; + +/* Select a register */ +GINLINE static void select(uint16_t reg) +{ + /* Clear RS and write the register number */ + *PRDR &= ~0x10; + synco(); + *DISPLAY = reg; + synco(); + /* Set RS=1 to allow consecutive reads/writes after a select() */ + *PRDR |= 0x10; + synco(); +} + +GINLINE static void write(uint16_t data) +{ + *DISPLAY = data; +} + +GINLINE static uint16_t read(void) +{ + return *DISPLAY; +} + +static void read_Nu16(uint16_t *array, int N) +{ + for(int i = 0; i < N; i++) + array[i] = *DISPLAY; +} + +//--- +// Generic functions +//--- + +void r61523_identify(uint32_t *manufacturerCode, uint16_t *deviceCode) +{ + select(REG_DEVICE_CODE_READ); + uint16_t packets[5]; + read_Nu16(packets, 5); + + if(manufacturerCode) + *manufacturerCode = (packets[1] << 16) | packets[2]; + if(deviceCode) + *deviceCode = (packets[3] << 16) | packets[4]; +} + +//--- +// Window management +//--- + +void r61523_win_set(int x1, int x2, int y1, int y2) +{ + /* R61523 has a 360x640 area; the CP-400 uses the top-right corner for its + 320x528 display, so skip over the first 40 columns */ + x1 += 40; + x2 += 40; + + uint16_t volatile *DISPLAY = (void *)0xb4000000; + + select(REG_HRANGE); + + /* Upper half has 2 bits (total 10 bits = 1024) */ + *DISPLAY = (x1 >> 8) & 3; + synco(); + *DISPLAY = x1 & 0xff; + + *DISPLAY = (x2 >> 8) & 3; + synco(); + *DISPLAY = x2 & 0xff; + synco(); + + select(REG_VRANGE); + + *DISPLAY = (y1 >> 8) & 3; + synco(); + *DISPLAY = y1 & 0xff; + synco(); + + *DISPLAY = (y2 >> 8) & 3; + synco(); + *DISPLAY = y2 & 0xff; + synco(); +} + +void r61523_display(uint16_t *vram) +{ + r61523_win_set(0, 319, 0, 527); + + select(44); + + int row_offset = 0; + uint16_t volatile *DISPLAY = (void *)0xb4000000; + + for(int y = 0; y < 528; y++) { + uint16_t *r5 = (void *)vram + row_offset; + + for(int x = 0; x < 320; x++) + *DISPLAY = *r5++; + + row_offset += 2 * 320; + } +} + +static bool r61523_update(int x, int y, image_t const *fb, int flags) +{ + if(fb->format != IMAGE_RGB565) + return false; + + // TODO: r61523_update: DMA support + // unless VIDEO_UPDATE_FOREIGN_WORLD is set + (void)flags; + uint w = fb->width; + uint h = fb->height; + + // TODO: r61523_update: sub-rectangle support + if(x != 0 || y != 0 || w != 320 || h != 528) + return false; + + // TODO: r61523_update: stride support! + if(fb->stride != 320 * 2) + return false; + + r61523_display(fb->data); + return true; +} + +//--- +// Driver metadata +//--- + +/* As far as I can tell there's no way to read the current window from the + controller so this driver is completely stateless for now. */ +gint_driver_t drv_r61523 = { + .name = "R61523", +}; +GINT_DECLARE_DRIVER(26, drv_r61523); + +//--- +// Video driver interface +//--- + +static video_mode_t r61523_modes[] = { + /* Standard full-screen full-color mode */ + { 320, 528, IMAGE_RGB565, -1 }, + { 0 } +}; + +video_interface_t r61523_video = { + .driver = &drv_r61523, + .modes = r61523_modes, + .mode_get = NULL, // TODO + .mode_set = NULL, // TODO + .brightness_min = 0, // TODO + .brightness_max = 0, // TODO + .brightness_set = NULL, + .update = r61523_update, +}; + +#endif /* GINT_HW_CP */ diff --git a/src/render-cg/dclear.c b/src/render-cg/dclear.c index e5c15a4..4871b98 100644 --- a/src/render-cg/dclear.c +++ b/src/render-cg/dclear.c @@ -5,6 +5,11 @@ void dclear(uint16_t color) { + // TODO: CP: DMA support for dclear() +#if GINT_HW_CP + for(int i = 0; i < DWIDTH * DHEIGHT; i++) + gint_vram[i] = color; +#else bool full_width = (dwindow.left == 0 && dwindow.right == DWIDTH); bool dma_aligned = !(dwindow.top & 3) && !(dwindow.bottom & 3); @@ -17,6 +22,7 @@ void dclear(uint16_t color) drect(dwindow.left, dwindow.top, dwindow.right - 1, dwindow.bottom - 1, color); } +#endif } #endif diff --git a/src/render-cg/dupdate.c b/src/render-cg/dupdate.c index d6480c9..3aed3e6 100644 --- a/src/render-cg/dupdate.c +++ b/src/render-cg/dupdate.c @@ -1,9 +1,20 @@ #include +#include #include #include "render-cg.h" #include #if GINT_RENDER_RGB +#if GINT_HW_CP + +void dupdate(void) +{ + r61523_display(gint_vram); + gint_call(dupdate_get_hook()); +} + +#elif GINT_HW_CG + /* dupdate(): Push the video RAM to the display driver */ void dupdate(void) { @@ -19,7 +30,10 @@ void dupdate(void) /* Switch buffers if triple buffering is enabled */ dvram_switch(); } + +#endif + __attribute__((alias("dupdate"))) void _WEAK_dupdate(void); -#endif +#endif /* GINT_RENDER_RGB */ diff --git a/src/render-cg/dvram.c b/src/render-cg/dvram.c index 88b1d57..c4307ff 100644 --- a/src/render-cg/dvram.c +++ b/src/render-cg/dvram.c @@ -1,8 +1,37 @@ #include #include +#include +#include #include #if GINT_RENDER_RGB +#if GINT_OS_CP + +extern void *__GetVRAMAddress(void); +extern void __VRAMBackup(void); +extern void __VRAMRestore(void); + +uint16_t *gint_vram = NULL; + +bool dvram_init(void) +{ + __VRAMBackup(); + gint_vram = __GetVRAMAddress(); + return true; +} + +void dvram_quit(void) +{ + __VRAMRestore(); + // TODO: CP dvram_quit: use global framebuffer image + image_t *img = image_create_vram(); + video_update(0, 0, img, VIDEO_UPDATE_FOREIGN_WORLD); + image_free(img); +} + +#elif GINT_OS_CG +// TODO[3]: CG: Remove triple buffering + /* Up to two VRAM pointers can be set, for triple buffering. */ static uint16_t *vram_1 = NULL, *vram_2 = NULL; /* Current VRAM pointer, always equal to either vram_1 or vram_2. */ @@ -69,4 +98,9 @@ void dvram_switch(void) gint_vram = (gint_vram == vram_1) ? vram_2 : vram_1; } -#endif +void dvram_quit(void) +{ +} + +#endif /* OS type */ +#endif /* GINT_RENDER_RGB */ diff --git a/src/render-cg/topti-asm.S b/src/render-cg/topti-asm.S index b1aaf30..ff09fc3 100644 --- a/src/render-cg/topti-asm.S +++ b/src/render-cg/topti-asm.S @@ -1,5 +1,11 @@ #include #if GINT_RENDER_RGB +// TODO: topti-asm: avoid duplicating DWIDTH here +#if GINT_HW_CG +# define DWIDTH 396 +#elif GINT_HW_CP +# define DWIDTH 320 +#endif .global _topti_glyph_fg_bg .global _topti_glyph_fg @@ -39,7 +45,7 @@ _topti_glyph_fg_bg: - # Compute VRAM stride 2 * (396-width) + # Compute VRAM stride 2 * (DWIDTH-width) mov.l r8, @-r15 mov.l 1f, r8 mov.l @(4, r15), r3 @@ -96,7 +102,7 @@ _topti_glyph_fg_bg: _topti_glyph_fg: - # Compute VRAM stride 2 * (396-width) + # Compute VRAM stride 2 * (DWIDTH-width) mov.l r8, @-r15 mov.l 1f, r8 mov.l @(4, r15), r3 @@ -149,7 +155,7 @@ _topti_glyph_fg: _topti_glyph_bg: - # Compute VRAM stride 2 * (396-width) + # Compute VRAM stride 2 * (DWIDTH-width) mov.l r8, @-r15 mov.l 1f, r8 mov.l @(4, r15), r3 @@ -202,6 +208,6 @@ _topti_glyph_bg: .align 4 -1: .long 396*2 +1: .long DWIDTH*2 #endif diff --git a/src/usb/classes/ff-bulk.c b/src/usb/classes/ff-bulk.c index a94aea7..6254bd8 100644 --- a/src/usb/classes/ff-bulk.c +++ b/src/usb/classes/ff-bulk.c @@ -178,6 +178,7 @@ static char const * const str_CALC[] = { [HWCALC_FXCG50] = "fx-CG 50/Graph 90+E", [HWCALC_FXCG_MANAGER] = "fx-CG Manager", [HWCALC_FX9860G_SLIM] = "fx-9860G Slim", + [HWCALC_FXCP400] = "fx-CP 400", }; static void execute_command(char const *cmd) @@ -191,7 +192,7 @@ static void execute_command(char const *cmd) char const *serial_number = (void *)0x8000ffd0; char const *OS_version = (void *)0x80010020; char const *BC_version = (void *)0x8000ffb0; -#elif GINT_OS_CG +#elif GINT_OS_CG || GINT_OS_CP char const *serial_number = (void *)0x8001ffd0; char const *OS_version = (void *)0x80020020; char const *BC_version = (void *)0x8001ffb0; diff --git a/src/usb/setup.c b/src/usb/setup.c index 55d9e42..82ac80e 100644 --- a/src/usb/setup.c +++ b/src/usb/setup.c @@ -17,10 +17,11 @@ /* 0x6101: fx-9860G II, Protocol 7.00, etc. 0x6102: fx-CP 400, fx-CG 50, Mass Storage, etc. */ -#define ID_PRODUCT GINT_HW_SWITCH(0x6101, 0x6102) +#define ID_PRODUCT GINT_HW_SWITCH(0x6101, 0x6102, 0x6102) #define DESC_PRODUCT GINT_HW_SWITCH( \ - u"CASIO fx-9860G family on gint", \ - u"CASIO fx-CG family on gint") + u"CASIO fx-9860G family on gint", \ + u"CASIO fx-CG family on gint", \ + u"CASIO fx-CP family on gint") static usb_dc_device_t dc_device = { .bLength = sizeof(usb_dc_device_t), @@ -56,7 +57,8 @@ static usb_dc_string_t dc_string0 = { GCONSTRUCTOR static void set_strings(void) { - char const *serial_base = (void *)GINT_OS_SWITCH(0x8000ffd0, 0x8001ffd0); + char const *serial_base = + (void *)GINT_OS_SWITCH(0x8000ffd0, 0x8001ffd0, 0x8001ffd0); /* Convert the serial number to UTF-16 */ uint16_t serial[8]; diff --git a/src/video/video.c b/src/video/video.c index b458147..b3f76e0 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -2,10 +2,10 @@ #include // TODO: video: Have interface set by gint pre-main call instead -extern video_interface_t t6k11_video, r61524_video; +extern video_interface_t t6k11_video, r61524_video, r61523_video; static video_interface_t const *current_intf = - GINT_HW_SWITCH(NULL, &r61524_video); -static int current_mode_index = GINT_HW_SWITCH(-1, 0); + GINT_HW_SWITCH(NULL, &r61524_video, &r61523_video); +static int current_mode_index = GINT_HW_SWITCH(-1, 0, 0); video_interface_t const *video_get_current_interface(void) {