Compare commits

...

11 Commits

17 changed files with 584 additions and 22 deletions

View File

@ -241,8 +241,47 @@ set(SOURCES_CG
src/render-cg/image/image_p4_dye.c
)
set(ASSETS_FX src/font5x7.png)
set(ASSETS_CG src/font8x9.png)
set(SOURCES_FXASCG
# Gray engine
src/gray/gclear.c
src/gray/ggetpixel.c
src/gray/gint_gline.c
src/gray/gpixel.c
src/gray/grect.c
src/gray/gsubimage.c
src/gray/gtext.c
# Rendering
src/render-fx/bopti-asm-gray-scsp.s
src/render-fx/bopti-asm-gray.s
src/render-fx/bopti-asm-mono-scsp.s
src/render-fx/bopti-asm.s
src/render-fx/bopti.c
src/render-fx/dclear.c
src/render-fx/dgetpixel.c
src/render-fx/dpixel.c
src/render-fx/drect.c
src/render-fx/dsubimage.c
src/render-fx/gint_dline.c
src/render-fx/masks.c
src/render-fx/topti-asm.s
src/render-fx/topti.c
#special dupdate functions to treat a FX VRAM and convert to a CG VRAM
src/render-fxascg/dupdate.c
src/render-fxascg/engine_fxascg.c
# R61524 driver as we are working with a CG50
src/r61524/r61524.c
src/usb/classes/ff-bulk-gray.c
)
set(ASSETS_FX
src/font5x7.png
)
set(ASSETS_CG
src/font8x9.png
)
fxconv_declare_assets(${ASSETS_FX} ${ASSETS_CG})
include_directories(
@ -269,6 +308,17 @@ if("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
${LINKER_SCRIPTS})
endif()
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G_AS_CG)
add_compile_options(-DFXCG50)
add_compile_definitions(FX9860G_AS_CG)
set(NAME "gint-fxascg")
set(LINKER_SCRIPTS
"${CMAKE_CURRENT_BINARY_DIR}/fxcg50.ld"
"${CMAKE_CURRENT_BINARY_DIR}/fxcg50_fastload.ld")
add_library(gint-fxascg STATIC ${SOURCES_COMMON} ${SOURCES_FXASCG} ${ASSETS_FX}
${LINKER_SCRIPTS})
endif()
set_target_properties("${NAME}" PROPERTIES OUTPUT_NAME "${NAME}")
# Generate linker scripts

View File

@ -105,6 +105,22 @@ The available options are:
% fxsdk build-cg install
```
**"Cross-Building" a fx-9860G II project for fx-CG 50**
fx-9860G II sources can be automatically converted to run on fx-CG 50, provided no
low level function/specific hardware manipulation/or syscall is used by the program.
The command is very similar to fx-9860G II one, except it is `fxsdk build-fx-as-cg`
instead of `fxsdk build-fx`.
The available options are:
```
% fxsdk build-fx-as-cg
% fxsdk build-fx-as-cg install
```
## Using in CMake-based add-ins
Find the `Gint` module and link against `Gint::Gint`. gint declares the include
@ -125,6 +141,10 @@ using the fxSDK, you will need to:
* 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.
Manually building a fx-9860G project to run on a fx-CG50 can be done :
* Build with `-m4-nofpu -mb -DFXCG50 -DFX9860G_AS_CG`;
* Link with `-T fxcg50.ld -lgint-fxascg -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

View File

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

View File

@ -5,14 +5,17 @@
configure:
@ fxsdk build-fx -c $(GINT_CMAKE_OPTIONS)
@ fxsdk build-cg -c $(GINT_CMAKE_OPTIONS)
@ fxsdk build-fx-as-cg -c $(GINT_CMAKE_OPTIONS)
build:
@ fxsdk build-fx
@ fxsdk build-cg
@ fxsdk build-fx-as-cg
install:
@ fxsdk build-fx install
@ fxsdk build-cg install
@ fxsdk build-fx-as-cg 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-fx-as-cg/install_manifest.txt ]; then \
xargs rm -f < build-fxascg/install_manifest.txt; \
fi
.PHONY: configure build install uninstall

View File

@ -15,7 +15,7 @@
#ifndef GINT_DISPLAY_CG
#define GINT_DISPLAY_CG
#ifdef FXCG50
#if defined(FXCG50) && !defined(FX9860G_AS_CG)
#ifdef __cplusplus
extern "C" {

View File

@ -9,7 +9,7 @@
#ifndef GINT_DISPLAY_FX
#define GINT_DISPLAY_FX
#ifdef FX9860G
#if defined(FX9860G) || defined(FX9860G_AS_CG)
#ifdef __cplusplus
extern "C" {

View File

@ -19,11 +19,11 @@ extern "C" {
/* Platform-specific functions include VRAM management and the definition of
the color_t type. */
#ifdef FX9860G
#if defined(FX9860G) || defined(FX9860G_AS_CG)
#include <gint/display-fx.h>
#endif
#ifdef FXCG50
#if defined(FXCG50) && ! defined(FX9860G_AS_CG)
#include <gint/display-cg.h>
#endif

View File

@ -147,7 +147,7 @@ typedef enum
usually slow and currently not even implemented. */
void usb_fxlink_screenshot(bool onscreen);
#ifdef FX9860G
#if defined(FX9860G) || defined(FX9860G_AS_CG)
/* usb_fxlink_screenshot_gray(): Take a gray screenshot on fx-9860G
This function is similar to usb_fxlink_screenshot(), but it takes a gray
@ -179,7 +179,7 @@ void usb_fxlink_text(char const *text, int size);
automatically send new frames to fxlink. */
void usb_fxlink_videocapture(bool onscreen);
#ifdef FX9860G
#if defined(FX9860G) || defined(FX9860G_AS_CG)
/* usb_fxlink_videocapture_gray(): Send a gray frame for a video recording
Like usb_fxlink_videocapture(), but uses VRAM data from the gray engine. */
void usb_fxlink_videocapture_gray(bool onscreen);

View File

@ -11,7 +11,6 @@
//---
// Interrupt controllers
//---
GRODATA3 sh7705_intc_t const SH7705_INTC = {
.IPR = {
(void *)0xfffffee2, (void *)0xfffffee4,

View File

@ -25,7 +25,7 @@ extern uint32_t
lilram, silram, rilram, /* IL memory section */
lxyram, sxyram, rxyram, /* X and Y memory section */
sbss, rbss; /* User's BSS section */
#ifdef FX9860G
#if defined(FX9860G) && !defined(FX9860G_AS_CG)
extern uint32_t
lgmapped, sgmapped, /* Permanently mapped functions */
lreloc, sreloc; /* Relocatable references */
@ -120,7 +120,7 @@ static int start2(int isappli, int optnum)
1.00 and the fx-9860G emulator) is not clear yet, so gint can't load
pages dynamically. Load everything preventively (works only if the
add-in is small enough) */
#ifdef FX9860G
#if defined(FX9860G) && !defined(FX9860G_AS_CG)
if(isSH3())
{
/* Try to map every ROM address up to _srom */
@ -149,7 +149,7 @@ static int start2(int isappli, int optnum)
regcpy(&lxyram, &sxyram, &rxyram);
}
#ifdef FX9860G
#if defined(FX9860G) && !defined(FX9860G_AS_CG)
/* Copy permanently-mapped code to start of user RAM (on fx-CG 50 it
is loaded along ILRAM contents) */
void *rgmapped = mmu_uram();

View File

@ -9,9 +9,16 @@
#include "topti-asm.h"
/* Default font */
extern font_t gint_font8x9;
font_t const * gint_default_font = &gint_font8x9;
font_t const * topti_font = &gint_font8x9;
#if(FX9860G_AS_CG)
extern font_t gint_font5x7;
font_t const * gint_default_font = &gint_font5x7;
font_t const * topti_font = &gint_font5x7;
#else
extern font_t gint_font8x9;
font_t const * gint_default_font = &gint_font8x9;
font_t const * topti_font = &gint_font8x9;
#endif
/* topti_glyph(): Render a glyph on the VRAM
Prints a glyph naively using word accesses, because for most fonts with a

View File

@ -100,5 +100,4 @@ void gsubimage(bopti_image_t const *image, struct rbox *r, int flags);
if(dmode && dmode->func) { \
return dmode->func(__VA_ARGS__); \
}
#endif /* RENDER_FX */

137
src/render-fxascg/dupdate.c Normal file
View File

@ -0,0 +1,137 @@
#include <gint/display.h>
#include <gint/kmalloc.h>
#include <gint/config.h>
#include <gint/drivers/r61524.h>
#include "../render-fx/render-fx.h"
/* The destination VRAM for upscaling + centering + conversion B&W --> 16bits RGB565 */
uint16_t *cg_vram; // set to 0 at initialisation
/* Standard video RAM for fx9860g is 1 bit per pixel */
GALIGNED(32) static uint32_t fx_vram[256];
/* Here is the definition of the VRAM pointer, exposed in <gint/display.h> */
uint32_t *gint_vram = fx_vram;
/* The current rendering mode */
struct rendering_mode const *dmode = NULL;
bool dvram_init( void )
{
int const MARGIN = 32;
/* Leave MARGIN bytes on each side of the region; this enables some
important optimizations in the image renderer. We also add another
32 bytes so we can manually 32-align the region */
uint32_t region = (uint32_t)kmalloc(DWIDTH*DHEIGHT*2 + MARGIN*2 + 32,
#if !defined(GINT_NO_OS_STACK)
"_ostk"
#else
NULL
#endif
);
if(region == 0)
return false;
/* 32-align the region */
region = (region + 31) & -32;
/* Skip a MARGIN */
region += MARGIN;
/* Use an uncached address */
region = (region & 0x1fffffff) | 0xa0000000;
/* Don't enable triple buffering by default */
cg_vram = (void *)region;
return true;
}
void dgetvram(uint16_t **ptr_vram_1, uint16_t **ptr_vram_2)
{
if(ptr_vram_1) *ptr_vram_1 = &cg_vram;
if(ptr_vram_2) *ptr_vram_2 = &cg_vram;
}
inline drawupscale( int x, int y, int color )
{
int u=y*396*3;
int v=x*3;
uint16_t colorcg;
if (color==C_WHITE) colorcg=0xFFFF;
else colorcg=0x0000;
int baseindex = (396*16+6+v+u); // 16 lines on top/bottom remain black and 6 columns on left/right remain black
cg_vram[baseindex] = colorcg;
cg_vram[baseindex+1] = colorcg;
cg_vram[baseindex+2] = colorcg;
baseindex+=396;
cg_vram[baseindex] = colorcg;
cg_vram[baseindex+1] = colorcg;
cg_vram[baseindex+2] = colorcg;
baseindex+=396;
cg_vram[baseindex] = colorcg;
cg_vram[baseindex+1] = colorcg;
cg_vram[baseindex+2] = colorcg;
}
/* dupdate(): Push the video RAM to the display driver */
void dupdate(void)
{
bool run_default = true;
if(dmode && dmode->dupdate)
{
/* Call the overridden dupdate(), but continue if it returns
non-zero (this is used when stopping the gray engine) */
int rc = dmode->dupdate();
run_default = (rc != 0);
}
if(run_default)
{
for( int j=0; j<DHEIGHT; j++ ) // 64 lines
{
for( int i=0; i<DWIDTH; i++ ) // 128 column
{
drawupscale( i, j, dgetpixel(i,j) ); // really not optimised; just to check if OK
}
}
//draw a black layer around the screen
int base1 = 0;
int base2 = (64*3+16)*396;
for(int u = 0; u<16; u++)
{
for(int v = 0; v<396; v++)
{
cg_vram[base1+v] = 0;
cg_vram[base2+v] = 0;
}
base1+=396;
base2+=396;
}
base1 = 16*396;
base2 = 16*396+6+128*3;
for(int u = 0; u<64*3; u++)
{
for(int v = 0; v<6; v++)
{
cg_vram[base1+v] = 0;
cg_vram[base2+v] = 0;
}
base1+=396;
base2+=396;
}
r61524_display(cg_vram, 0, 224, R61524_DMA_WAIT );
}
gint_call(dupdate_get_hook());
}
__attribute__((alias("dupdate")))
void _WEAK_dupdate(void);

View File

@ -0,0 +1,340 @@
//---
// gint:gray:engine - Core gray engine
//---
#include <gint/defs/types.h>
#include <gint/drivers/r61524.h>
#include <gint/gray.h>
#include <gint/display.h>
#include <stdlib.h>
#include "../render-fx/render-fx.h"
/* Three additional video RAMS, allocated statically if --static-gray was set
at configure time, or with malloc() otherwise. */
#ifdef GINT_STATIC_GRAY
GBSS static uint32_t gvrams[1][256];
#endif
uint16_t *cg_vram_gray;
/* two VRAMs: two to draw and two to display */
static uint32_t *vrams[2] = { NULL, NULL };
/* Whether the engine is scheduled to run at the next frame */
static int runs = 0;
extern struct rendering_mode const *dmode;
/* The alternate rendering mode structure used to override d*() */
static struct rendering_mode const gray_mode = {
.dupdate = gupdate,
.dclear = gclear,
.drect = grect,
.dpixel = gpixel,
.dgetpixel = ggetpixel,
.gint_dhline = gint_ghline,
.gint_dvline = gint_gvline,
.dtext_opt = gtext_opt,
.dsubimage = gsubimage,
};
static struct rendering_mode const gray_exit_mode = {
.dupdate = gupdate,
.dclear = NULL,
.drect = NULL,
.dpixel = NULL,
.dgetpixel = NULL,
.gint_dhline = NULL,
.gint_dvline = NULL,
.dtext_opt = NULL,
.dsubimage = NULL,
};
//---
// Engine control (init/quit and start/stop)
//---
//static int gray_int(void);
static void gray_quit(void);
/* gray_isinit(): Check whether the engine is initialized and ready to run */
static int gray_isinit(void)
{
//return (vrams[0] && vrams[1] && vrams[2] && vrams[3] && timer >= 0);
return (vrams[0] && vrams[1] >= 0);
}
bool dvram_init_gray( void )
{
int const MARGIN = 32;
/* Leave MARGIN bytes on each side of the region; this enables some
important optimizations in the image renderer. We also add another
32 bytes so we can manually 32-align the region */
uint32_t region = (uint32_t)kmalloc(DWIDTH*DHEIGHT*2 + MARGIN*2 + 32,
#if !defined(GINT_NO_OS_STACK)
"_ostk"
#else
NULL
#endif
);
if(region == 0)
return false;
/* 32-align the region */
region = (region + 31) & -32;
/* Skip a MARGIN */
region += MARGIN;
/* Use an uncached address */
region = (region & 0x1fffffff) | 0xa0000000;
/* Don't enable triple buffering by default */
cg_vram_gray = (void *)region;
return true;
}
/* gray_init(): Initialize the engine
This is done at startup so that memory can be reserved very early from the
heap (because not having enough memory is unrecoverable for the engine). */
GCONSTRUCTOR static void gray_init(void)
{
/* We need four VRAMs. First use the standard monochrome one */
vrams[0] = gint_vram;
#ifdef GINT_STATIC_GRAY
vrams[1] = gvrams[0];
#else
vrams[1] = malloc(1024);
#endif /* GINT_STATIC_GRAY */
dvram_init_gray();
/* On failure, release the resources that we obtained */
if(!gray_isinit()) gray_quit();
}
/* gray_quit(): Free engine resources */
GDESTRUCTOR static void gray_quit(void)
{
#ifndef GINT_STATIC_GRAY
if(vrams[1]) free(vrams[1]);
vrams[1] = NULL;
#endif /* GINT_STATIC_GRAY */
}
/* gray_start(): Start the gray engine */
static void gray_start(void)
{
runs = 1;
}
/* gray_stop(): Stop the gray engine */
static void gray_stop(void)
{
runs = 0;
}
//---
// Dynamic udpate and rendering mode
//---
/* dgray(): Start or stop the gray engine at the next dupdate() */
int dgray(int mode)
{
/* Stack of states for the push modes */
static uint8_t states[32] = { 0 };
static uint8_t current = 0;
if(mode == DGRAY_ON)
{
if(!gray_isinit()) return 1;
/* Set the display module's alternate rendering mode to
override rendering functions to use their g*() variant */
if(!dgray_enabled()) dmode = &gray_mode;
}
else if(mode == DGRAY_OFF)
{
/* Set the mode to a temporary one that only overrides
dupdate() so that we can stop the engine next frame */
if(dgray_enabled()) dmode = &gray_exit_mode;
}
else if(mode == DGRAY_PUSH_ON)
{
if(current >= 32) return 1;
states[current++] = dgray_enabled() ? DGRAY_ON : DGRAY_OFF;
return dgray(DGRAY_ON);
}
else if(mode == DGRAY_PUSH_OFF)
{
if(current >= 32) return 1;
states[current++] = dgray_enabled() ? DGRAY_ON : DGRAY_OFF;
return dgray(DGRAY_OFF);
}
else if(mode == DGRAY_POP)
{
/* Stay at 0 if the user's push/pop logic is broken */
if(current > 0) current--;
/* Switch to previous state */
return dgray(states[current]);
}
else return 1;
return 0;
}
/* convert the gray scale into RGB565 and draw in the virutal VRAMthe 3x3 pixels upscaled and centered */
inline gdrawupscale( int x, int y, int color_fx )
{
int u=y*396*3;
int v=x*3;
uint16_t color_cg;
if (color_fx==C_WHITE) color_cg=0xFFFF;
else if (color_fx==C_LIGHT) color_cg=0xAD55;
else if (color_fx==C_DARK) color_cg=0x528A;
else color_cg=0x0000;
int baseindex = (396*16+6+v+u); // 16 lines on top/bottom remain black and 6 columns on left/right remain black
cg_vram_gray[baseindex] = color_cg; // draw 3 pixels side by side
cg_vram_gray[baseindex+1] = color_cg;
cg_vram_gray[baseindex+2] = color_cg;
baseindex+=396; // same for the line below (line #2)
cg_vram_gray[baseindex] = color_cg;
cg_vram_gray[baseindex+1] = color_cg;
cg_vram_gray[baseindex+2] = color_cg;
baseindex+=396; // same for the line below (line #3)
cg_vram_gray[baseindex] = color_cg;
cg_vram_gray[baseindex+1] = color_cg;
cg_vram_gray[baseindex+2] = color_cg;
}
/* gray_int(): Interrupt handler */
//int gray_int(void)
//{
// //t6k11_display(vrams[st ^ 2], 0, 64, 16);
// timer_reload(GRAY_TIMER, delays[(st ^ 3) & 1]);
//
// st ^= 1;
//
// return TIMER_CONTINUE;
//}
/* gupdate(): Push the current VRAMs to the screen */
int gupdate(void)
{
/* At the first gupdate(), start the engine */
if(dmode == &gray_mode && !runs)
{
gray_start();
}
/* At the last gupdate(), stop the engine */
else if(dmode == &gray_exit_mode)
{
gray_stop();
dmode = NULL;
return 1;
}
uint32_t *light, *dark;
dgray_getscreen(&light, &dark);
for( int j=0; j<DHEIGHT; j++ ) // 64 lines
{
for( int i=0; i<DWIDTH; i++ ) // 128 column
{
int offset = (j << 2) + (i >> 5);
uint32_t mask = 1 << (~i & 31);
int l = (light[offset] & mask) !=0 ? 1 : 0;
int d = (dark [offset] & mask) !=0 ? 1 : 0;
int color_fx = (d << 1) | l;
gdrawupscale( i, j, color_fx ); // really not optimised; just to check if OK
}
}
//draw a black layer around the screen
int base1 = 0;
int base2 = (64*3+16)*396;
for(int u = 0; u<16; u++)
{
for(int v = 0; v<396; v++)
{
cg_vram_gray[base1+v] = 0;
cg_vram_gray[base2+v] = 0;
}
base1+=396;
base2+=396;
}
base1 = 16*396;
base2 = 16*396+6+128*3;
for(int u = 0; u<64*3; u++)
{
for(int v = 0; v<6; v++)
{
cg_vram_gray[base1+v] = 0;
cg_vram_gray[base2+v] = 0;
}
base1+=396;
base2+=396;
}
r61524_display(cg_vram_gray, 0, 224, R61524_DMA_WAIT );
/* When the engine is running, swap frames */
return 0;
}
//---
// Query and configuration functions
//---
/* dgray_enabled(): Check whether gray mode is enabled */
int dgray_enabled(void)
{
return (dmode == &gray_mode);
}
/* dgray_setdelays(): Set the gray engine delays */
void dgray_setdelays(uint32_t light, uint32_t dark)
{
// delays[0] = light;
// delays[1] = dark;
}
/* dgray_getdelays(): Get the gray engine delays */
void dgray_getdelays(uint32_t *light, uint32_t *dark)
{
// if(light) *light = delays[0];
// if(dark) *dark = delays[1];
}
/* dgray_getvram(): Get the current VRAM pointers */
void dgray_getvram(uint32_t **light, uint32_t **dark)
{
if(light) *light = vrams[0];
if(dark) *dark = vrams[1];
}
/* dgray_getscreen(): Get the current screen pointers */
void dgray_getscreen(uint32_t **light, uint32_t **dark)
{
if(light) *light = vrams[0];
if(dark) *dark = vrams[1];
}

View File

@ -2,7 +2,7 @@
#include <gint/defs/util.h>
#include "../render/render.h"
#ifdef FX9860G
#if defined(FX9860G) || defined(FX9860G_AS_CG)
#include "../render-fx/render-fx.h"
#endif
@ -18,7 +18,7 @@ void dline(int x1, int y1, int x2, int y2, int color)
/* Possible optimizations */
if(y1 == y2)
{
#ifdef FX9860G
#if defined(FX9860G) || defined(FX9860G_AS_CG)
DMODE_OVERRIDE(gint_dhline, x1, x2, y1, color);
#endif
@ -27,7 +27,7 @@ void dline(int x1, int y1, int x2, int y2, int color)
}
if(x1 == x2)
{
#ifdef FX9860G
#if defined(FX9860G) || defined(FX9860G_AS_CG)
DMODE_OVERRIDE(gint_dvline, y1, y2, x1, color);
#endif

View File

@ -1,4 +1,4 @@
#ifdef FX9860G
#if defined(FX9860G) || defined(FX9860G_AS_CG)
#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>

View File

@ -101,12 +101,12 @@ static void capture_vram(GUNUSED bool onscreen, char const *type)
void *source = gint_vram;
int size, format;
#ifdef FX9860G
#if defined(FX9860G) || defined(FX9860G_AS_CG)
size = 1024;
format = USB_FXLINK_IMAGE_MONO;
#endif
#ifdef FXCG50
#if defined(FXCG50) && !defined(FX9860G_AS_CG)
if(onscreen) {
uint16_t *main, *secondary;
dgetvram(&main, &secondary);