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.
This commit is contained in:
Lephe 2024-04-16 15:53:10 +02:00
parent 5c3dc3220a
commit 789ba7caa5
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
26 changed files with 657 additions and 38 deletions

View file

@ -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}")

26
TODO
View file

@ -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

View file

@ -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()

189
fxcp_hh2.ld.c Normal file
View file

@ -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)
}
}

View file

@ -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 */

View file

@ -25,8 +25,13 @@ extern "C" {
#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

View 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 */

View file

@ -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

View file

@ -29,8 +29,10 @@ typedef struct {
} 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 {

View file

@ -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()");

View file

@ -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

View file

@ -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);

View file

@ -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)

18
src/kernel/start.S Normal file
View file

@ -0,0 +1,18 @@
#include <gint/config.h>
#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

View file

@ -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 */
#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();

View file

@ -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 */

View file

@ -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

View file

@ -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
}

183
src/r61523/r61523.c Normal file
View file

@ -0,0 +1,183 @@
// Renesas R61523 driver-
#include <gint/defs/types.h>
#include <gint/defs/util.h>
// #include <gint/hardware.h>
#include <gint/drivers.h>
// #include <gint/dma.h>
#include <gint/drivers/r61523.h>
#include <gint/video.h>
#include <gint/image.h>
#include <gint/config.h>
#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 */

View file

@ -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

View file

@ -1,9 +1,20 @@
#include <gint/display.h>
#include <gint/drivers/r61523.h>
#include <gint/drivers/r61524.h>
#include "render-cg.h"
#include <gint/config.h>
#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 */

View file

@ -1,8 +1,37 @@
#include <gint/display.h>
#include <gint/kmalloc.h>
#include <gint/video.h>
#include <gint/image.h>
#include <gint/config.h>
#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 */

View file

@ -1,5 +1,11 @@
#include <gint/config.h>
#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

View file

@ -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;

View file

@ -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-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];

View file

@ -2,10 +2,10 @@
#include <gint/config.h>
// 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)
{