Compare commits

...

21 Commits

Author SHA1 Message Date
Yatis c923ad24b1 @add
* special fxcg50 dupdate_noint() which display the content of the VRM without using the DMA (usefull for debugging)

@update
* update the drivers interface to get some information about the current running drivers' context
* remove the old cpu_setVBR() function

@fix
* fix cpu_setVBR() returned value
* fix kquit() drivers restore atomic error
2021-03-13 17:59:03 +01:00
Yatis 6961a0feec Add dynamique world context management
* Update all drivers to add context's size information.
* Isolate the driver module from the kernel module.
* Isolate the CPU "driver" from the kernel module.
* Isolate the Gint "world switch" from the kernel module.
* Generate two worlds: Gint and Casio (see <src/kernel/kernel.c>).
* Add atomic (SR.IMASK=15) functions.
* Allow to overwrite the Gint "world switch" (gint_switch()).
2021-02-01 12:00:25 +01:00
Yatis 48709c72e4 Fix Makefile installation + add some common std functions + add size_t type 2021-02-01 11:52:06 +01:00
Yatis 01f5f883e7 Update BFile information + add some common std functions 2021-02-01 11:49:31 +01:00
Lephe 7a68070bac
show version in header for static version resolution
This change moves the gint version declaration from a symbol in a
compile-time generated object file to a preprocessed header installed in
the library tree.

This makes it possible to determine the gint version statically from the
headers, which is much more robust in complex build systems that use
version information such as CMake's find_package().
2020-12-30 18:35:06 +01:00
Lephe ad6c108dfc
kernel: always pull the INTC driver
Some very trivial applications might not require its symbols explicitly,
thus the need to force a dependency (otherwise OS interrupts such as the
KEYSC are not disabled and crash the handler very quickly).
2020-10-28 10:01:55 +01:00
Lephe 2c2d1513f9
spu: more complete initialization 2020-10-24 17:40:05 +02:00
Lephe 3694f20d56
spu: starter driver, supporting direct CPU access to SPU memory 2020-10-21 18:29:04 +02:00
Lephe 8ff7d89d33
cpg, tmu: add spin waiting and spin delay functions for drivers
This change adds a new TMU function timer_spinwait() which waits for a
timer to raise its UNF flag. This makes it possible to wait even when
interrupts are disabled.

This is used by the new CPG function sleep_us_spin() which waits for a
given delay without using interrupts. This is currently used in SPU
initialization.
2020-10-21 14:49:34 +02:00
Lephe 858ec8aa12
cpg, power: improve peripheral register descriptions
The POWER and CPG modules have been reverse-engineered by Yatis.
2020-10-21 14:48:04 +02:00
Lephe 19951ccf62
mmu: add MMU registers with a driver context for PASCR and IRMCR 2020-10-21 14:44:47 +02:00
Lephe 3a15340335
topti: improve text positioning
* Specify a line height for the default fx-CG 50 font so that the height
  returned by dsize() is correctly 9, not 11.
* Adjust vertical and horizontal alignment in dtext_opt() and
  dprint_opt() by a full pixel (DTEXT_BOTTOM, DTEXT_RIGHT) and half a
  pixel (DTEXT_MIDDLE, DTEXT_CENTER) to make sure that the specified
  position is within rendered text (as in DTEXT_LEFT and TEXT_TOP) and
  to improve centering of strings with odd width or odd height, for
  which there is only one valid position.
2020-10-21 11:49:12 +02:00
Lephe e63ff8351b
dsp: enable integrated DSP in SR at startup 2020-10-09 18:58:43 +02:00
Lephe bc575f1599
intc: update interrupt sources in IPR registers
As per new documentation reverse-engineered from CPU73050.DLL.
https://bible.planet-casio.com/lephenixnoir/sh7305/intc/interrupt-sources.html
2020-10-09 18:03:08 +02:00
Lephe 52d95e72ed
stdlib: force rand() to return a non-negative number
Negative numbers come with tricky modulus results and are excluded from
the return values of the standard rand().
2020-10-09 09:17:48 +02:00
Lephe 078edb50b2
small cleanup 2020-10-05 16:31:37 +02:00
Lephe 240f29f9d5
topti: custom character and word spacing (#13)
This commit introduces custom character spacing with a new fxconv
parameter "char-spacing". Word spacing is also tied to the width of the
space character (0x20). This removes the need for special semantics on
the space character, but requires that its size be specified with gray
pixels for proportional fonts.

This also fixes problems with the size of spaces in dsize() not being
correlated with their size during rendering, since on fx-9860G topti
already used the glyph's with as word spacing.

Since fxconv changes but gint's Makefile does not track updates to
external tools, a full rebuild of gint is required past this commit.
2020-10-05 16:14:12 +02:00
Lephe 2e8b1020cb
display-fx: protect vertical lines against clipping out of bounds 2020-10-05 15:13:38 +02:00
Lephe 9b462deca1
kernel: preload add-in to TLB on SH3 (UNSTABLE) (#12) 2020-09-28 14:09:03 +02:00
Lephe e66b9083b4
kernel: do not copy data to on-chip memory on SH3
Avoids a crash at startup, but the application needs to be smart enough
to not use the data.
2020-09-28 14:06:29 +02:00
Lephe 744d243265
kernel: do SH3 initialization before context saves
This should be obvious and breaks ctx_save() for the RTC and TMU. Which
apparently never came up during testing.
2020-09-28 14:01:32 +02:00
51 changed files with 1386 additions and 474 deletions

1
TODO
View File

@ -1,4 +1,5 @@
Extensions on existing code:
* project: add license file
* kernel: group linker script symbols in a single header file
* kernel: be consistent about *tlb_mapped_memory() in hw_detect()
* bopti: try to display fullscreen images with TLB access + DMA on fxcg50

35
include/gint/atomic.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _SRC_KERNEL_ATOMIC_H__
# define _SRC_KERNEL_ATOMIC_H__
#include <stddef.h>
#include <stdint.h>
/* atomic_begin(): Start atomic operation
This function will block interruptions and exception until
"thread_atomic_stop()" is called. This is really useful when you need to
secure some tricky part of code (like driver kernel-level implementation).
But be carefull: your code executed after this function SHOULD be
EXCEPTION-SAFE ! Otherwise, a crash will occur and Gint can do nothing to
avoid it because is hardware specific. If you need to secure shared data,
use mutex instead.
This implementation is recursive-safe and will return:
* SR value when you enter in "atomic" operation (first call)
* 0 if you are already in a "atomic" operation (x call)
To return to the "normal" operation, you should call "thread_atomic_stop()"
as many time as you have involved with "thread_atomic_start()". */
extern void *atomic_begin(void);
/* atomic_end(): Stop atomic opration
This function will try to return to the "normal" mode and will return:
* negative value If error occur
* 0 If you are alwayrs in "atomic" mode
* the restored SR value If you are returned to the "clasic" mode */
extern void *atomic_end(void);
#endif /*_SRC_KERNEL_ATOMIC_H__*/

View File

@ -105,6 +105,21 @@ 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,
struct BFile_FileInfo *fileinfo);

View File

@ -67,6 +67,11 @@ const clock_frequency_t *clock_freq(void);
function selects a timer with timer_setup() called with TIMER_ANY. */
void sleep_us(uint64_t delay_us);
/* sleep_us_spin(): Actively sleep for a fixed duration in microseconds
Like sleep_us(), but uses timer_spinwait() and does not rely on interrupts
being enabled. Useful in timer code running without interrupts. */
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)

19
include/gint/config.h.in Normal file
View File

@ -0,0 +1,19 @@
//---
// config - Compile-time generate configuration
//---
#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 */
#define GINT_VERSION @GINT_VERSION@
/* GINT_HASH: Commit hash with 7 digits
0x03f7c0a0 = Commit 3f7c0a0 */
#define GINT_HASH @GINT_HASH@
#endif /* GINT_CONFIG */

View File

@ -7,6 +7,7 @@
#include <gint/defs/types.h>
#if 0
/* cpu_setVBR(): Change VBR address
Blocks interrupts then changes the VBR address and calls the provided INTC
@ -23,6 +24,7 @@
Returns the previous VBR address. */
extern uint32_t (*cpu_setVBR)(uint32_t vbr, void (*conf_intc)(int arg),
int arg);
#endif
/* cpu_setCPUOPM(): Change the CPU Operation Mode register
@ -36,4 +38,35 @@ void cpu_setCPUOPM(uint32_t CPUOPM);
/* cpu_getCPUOPM(): Get the CPU OperatioN Mode register */
uint32_t cpu_getCPUOPM(void);
//---
// Status Register
//---
/* Status Register bits */
typedef lword_union(sr_t,
uint32_t :1;
uint32_t MD :1;
uint32_t RB :1;
uint32_t BL :1;
uint32_t RC :12;
uint32_t :3;
uint32_t DSP :1;
uint32_t DMY :1;
uint32_t DMX :1;
uint32_t M :1;
uint32_t Q :1;
uint32_t IMASK :4;
uint32_t RF :2;
uint32_t S :1;
uint32_t T :1;
);
/* Get and set sr through the sr_t type */
extern sr_t cpu_getSR(void);
extern void cpu_setSR(sr_t sr);
/* Get and set vbr register */
extern void *cpu_setVBR(void *vbr);
extern void *cpu_getVBR();
#endif /* GINT_CORE_CPU */

View File

@ -16,7 +16,8 @@
typedef unsigned int uint;
/* Signed size_t */
typedef signed int ssize_t;
/* Offset */
typedef unsigned int off_t;
//---
// Structure elements
//----

View File

@ -122,6 +122,8 @@ void dsetvram(uint16_t *main, uint16_t *secondary);
Returns the VRAM buffer addresses used to render on fx-CG 50. */
void dgetvram(uint16_t **main, uint16_t **secondary);
/* vdupdate_noint(): Push the VRAM to the display driver without DMA */
extern void dupdate_noint(void);
#endif /* FXCG50 */
#endif /* GINT_DISPLAY_CG */

View File

@ -189,6 +189,11 @@ typedef struct
/* Number of total glyphs */
uint32_t glyph_count;
/* Character spacing (usually 1) */
uint8_t char_spacing;
uint :24;
struct {
/* Unicode point of first character in block */
uint start :20;

View File

@ -70,14 +70,17 @@ typedef struct
is used for instance to wait for DMA transfers. May be NULL. */
void (*wait)(void);
/* Return the context size */
size_t (*ctx_size)(void);
/* System's context and gint's context. These should point to enough
memory to store a full driver state each. Used when switching from
the system to gint and back to the main menu. If they don't need to
be initialized, put them in gint's uninitialized BSS section using
the GBSS macro of <gint/defs/attributes.h>. May be NULL only if both
ctx_save() and ctx_restore() are NULL. */
void *sys_ctx;
void *gint_ctx;
//void *sys_ctx;
//void *gint_ctx;
/* Must save the state of as much driver-controlled hardware as
possible (memory-mapped MPU registers, port state, etc). This
@ -113,4 +116,22 @@ typedef struct
#define GINT_DRIVER_SH3(name) name
#endif
//---
// Driver interface
//---
extern void *drivers_context_create(void);
extern void drivers_context_destroy(void **buffctx);
extern void drivers_wait(void);
extern void *drivers_switch(void *buffctx);
extern void *drivers_restore(void *buffctx);
extern int drivers_save_and_init(void *buffctx);
extern int drivers_save(void *buffctx);
extern int drivers_context_duplicate(void **dst, void *src);
extern void *drivers_init(void *buffctx);
extern void *drivers_get_current(void);
// default world
extern void *kernel_env_casio;
extern void *kernel_env_gint;
#endif /* GINT_DRIVERS */

View File

@ -6,15 +6,7 @@
#define GINT_GINT
#include <gint/defs/types.h>
/* GINT_VERSION - the library version number
gint is versioned from its repository commits on the master branch. The
GINT_VERSION integer contains the short commit hash with 7 digits.
For instance, 0x03f7c0a0 means commit 3f7c0a0. */
extern char GINT_VERSION;
#define GINT_VERSION ((uint32_t)&GINT_VERSION)
#include <gint/config.h>
/* gint_switch(): Switch out of gint to execute a function
@ -137,4 +129,14 @@ void *gint_inthandler(int event_code, void const *handler, size_t size);
Returns the return value of the callback. */
extern int (*gint_inth_callback)(int (*function)(void *arg), void *arg);
//---
// Yatis, custom
//---
extern void gint_switch_to_casio(void);
extern void gint_switch_to_gint(void);
#endif /* GINT_GINT */

View File

@ -38,6 +38,9 @@ enum {
INTC_RTC_ATI,
INTC_RTC_PRI,
INTC_RTC_CUI,
/* SPU; interrupts from the DSPs and the SPU-bound DMA */
INTC_SPU_DSP0,
INTC_SPU_DSP1,
};
//---

View File

@ -248,10 +248,10 @@ void getkey_repeat(int first, int next);
/* getkey_repeat_filter(): Set the repeat filter function
This function is called by getkey() and getkey_opt() every time a repeat
event occurs when GETKEY_REPEAT_FILTER. The function can decide whether to
keep, delay it or drop it entirely. It can also change the repeat delays
with getkey_repeat() for fully custom repeat delay curves.
The repeat filter is called by getkey() and getkey_opt() every time a repeat
event occurs when GETKEY_REP_FILTER is set. The filter can decide whether to
keep, delay or drop the event. It can also change the repeat delays with
getkey_repeat() for fully custom repeat delay curves.
The time elapsed since the last accepted repeat is passed to the filter
function; this time must be larger than the repeat time set with

View File

@ -54,7 +54,17 @@ typedef volatile struct
uint32_t :4;
uint32_t P1FC :4; /* Pphi divider 1 [*] */
);
pad(0x20);
pad(0x4);
lword_union(FSICLKCR,
uint32_t :16;
uint32_t DIVB :6; /* Division ratio for port B */
uint32_t :1;
uint32_t CLKSTP :1; /* Clock Stop */
uint32_t SRC :2; /* Clock source select */
uint32_t DIVA :6; /* Division ratio for port A */
);
pad(0x18);
lword_union(PLLCR,
uint32_t :17;
@ -65,8 +75,17 @@ typedef volatile struct
uint32_t CKOFF :1; /* CKO Output Stop */
uint32_t :1;
);
pad(0x14);
lword_union(SPUCLKCR,
uint32_t :23;
uint32_t CLKSTP :1; /* Clock Stop */
uint32_t _ :1; /* Unknown */
uint32_t :1;
uint32_t DIV :6; /* Division ratio */
);
pad(0x4);
pad(0x1c);
lword_union(SSCGCR,
uint32_t SSEN :1; /* Spread Spectrum Enable */
uint32_t :31;

View File

@ -119,6 +119,7 @@ typedef struct
// SH7305 Interrupt Controller. Refer to:
// "Renesas SH7724 User's Manual: Hardware"
// Section 13: "Interrupt Controller (INTC)"
// Also CPU73050.dll was disassembled to find out the bits.
//---
/* sh7305_intc_ipc_t - Interrupt Priority Controller
@ -131,29 +132,29 @@ typedef volatile struct
uint16_t TMU0_0 :4; /* TMU0 Channel 0 */
uint16_t TMU0_1 :4; /* TMU0 Channel 1 */
uint16_t TMU0_2 :4; /* TMU0 Channel 2 */
uint16_t IrDA :4; /* Infrared Communication */
uint16_t :4;
);
pad(2);
word_union(IPRB,
uint16_t :4;
uint16_t LCDC :4; /* LCD Controller */
uint16_t DMAC1A :4; /* Direct Memory Access Controller 1 */
uint16_t _ :4; /* Unknown (TODO) */
uint16_t _LCDC :4; /* SH7724: LCD Controller */
uint16_t _DMAC1A:4; /* SH7724: DMAC1 channels 0..3 */
uint16_t :4;
);
pad(2);
word_union(IPRC,
uint16_t TMU1_0 :4; /* TMU1 Channel 0 */
uint16_t TMU1_1 :4; /* TMU1 Channel 1 */
uint16_t TMU1_2 :4; /* TMU1 Channel 2 */
uint16_t :4;
uint16_t :4;
uint16_t :4;
uint16_t SPU :4; /* SPU's DSP0 and DSP1 */
);
pad(2);
word_union(IPRD,
uint16_t :4;
uint16_t MMCIF :4; /* MultiMedia Card Interface */
uint16_t _MMCIF :4; /* SH7724: MultiMedia Card Interface */
uint16_t :4;
uint16_t :4;
);
@ -171,12 +172,12 @@ typedef volatile struct
uint16_t KEYSC :4; /* Key Scan Interface */
uint16_t DMACOB :4; /* DMAC0 transfer/error info */
uint16_t USB0_1 :4; /* USB controller */
uint16_t CMT :4; /* Compare Match Timer */
uint16_t _CMT :4; /* SH7724: Compare Match Timer */
);
pad(2);
word_union(IPRG,
uint16_t SCIF0 :4; /* SCIF0 transfer/error info */
uint16_t _SCIF0 :4; /* SH7724: SCIF0 transfer/error info */
uint16_t ETMU1 :4; /* Extra TMU 1 */
uint16_t ETMU2 :4; /* Extra TMU 2 */
uint16_t :4;
@ -184,26 +185,26 @@ typedef volatile struct
pad(2);
word_union(IPRH,
uint16_t MSIOF0 :4; /* Clock-synchronized SCIF channel 0 */
uint16_t MSIOF1 :4; /* Clock-synchronized SCIF channel 1 */
uint16_t :4;
uint16_t :4;
uint16_t _MSIOF0:4; /* SH7724: Sync SCIF channel 0 */
uint16_t _MSIOF1:4; /* SH7724: Sync SCIF channel 1 */
uint16_t _1 :4; /* Unknown (TODO) */
uint16_t _2 :4; /* Unknown (TODO) */
);
pad(2);
word_union(IPRI,
uint16_t ETMU4 :4; /* Extra TMU 4 */
uint16_t :4;
uint16_t :4;
uint16_t _ :4; /* Unknown (TODO) */
uint16_t :4;
);
pad(2);
word_union(IPRJ,
uint16_t ETMU0 :4; /* Extra TMU 0 */
uint16_t :4;
uint16_t _ :4; /* Unknown (TODO) */
uint16_t FSI :4; /* FIFO-Buffered Serial Interface */
uint16_t SDHI1 :4; /* SD Card Host Interface channel 1 */
uint16_t _SDHI1 :4; /* SH7724: SD Card Host Interface 1 */
);
pad(2);
@ -211,14 +212,14 @@ typedef volatile struct
uint16_t RTC :4; /* Real-Time Clock */
uint16_t DMAC1B :4; /* DMAC1 transfer/error info */
uint16_t :4;
uint16_t SDHI0 :4; /* SD Card Host Interface channel 0 */
uint16_t :4;
);
pad(2);
word_union(IPRL,
uint16_t ETMU5 :4; /* Extra TMU 5 */
uint16_t _ :4; /* Unknown (TODO) */
uint16_t :4;
uint16_t TPU :4; /* Timer-Pulse Unit */
uint16_t :4;
);
pad(2);
@ -292,7 +293,7 @@ typedef struct
// Forward definitions
//---
/* Provided by core/gint.c */
/* Provided by intc/intc.c */
extern sh7705_intc_t SH7705_INTC;
extern sh7305_intc_t SH7305_INTC;

View File

@ -77,4 +77,79 @@ typedef struct
} GPACKED(4) utlb_data_t;
typedef volatile struct
{
lword_union(PTEH,
uint32_t VPN :22; /* Virtual Page Number */
uint32_t :2;
uint32_t ASID :8; /* Address Space Identifier */
);
lword_union(PTEL,
uint32_t :3;
uint32_t PPN :19; /* Phusical Page Number */
uint32_t :1;
uint32_t V :1; /* Valid */
uint32_t SZ1 :1; /* Size (bit 1) */
uint32_t PR :2; /* Protection */
uint32_t SZ0 :1; /* Size (bit 0) */
uint32_t C :1; /* Cacheable */
uint32_t D :1; /* Dirty */
uint32_t SH :1; /* Shared */
uint32_t WT :1; /* Write-through */
);
uint32_t TTB;
uint32_t TEA;
lword_union(MMUCR,
uint32_t LRUI :6; /* Least-Recently Used ITLB */
uint32_t :2;
uint32_t URB :6; /* UTLB Replace Boundary */
uint32_t :2;
uint32_t URC :6; /* UTLB Replace Counter */
uint32_t SQMD :1; /* Store Queue Mode */
uint32_t SV :1; /* Single Virtual Memory Mode */
uint32_t ME :1; /* TLB Extended Mode */
uint32_t :4;
uint32_t TI :1; /* TLB Invalidate */
uint32_t :1;
uint32_t AT :1; /* Address Translation */
);
pad(0x20);
lword_union(PTEA,
uint32_t :18;
uint32_t EPR :6;
uint32_t ESZ :4;
uint32_t :4;
);
pad(0x38);
lword_union(PASCR,
uint32_t :24;
uint32_t UBC :1; /* Control register area */
uint32_t UB6 :1; /* Area 6 */
uint32_t UB5 :1; /* Area 5 */
uint32_t UB4 :1; /* Area 4 */
uint32_t UB3 :1; /* Area 3 */
uint32_t UB2 :1; /* Area 2 */
uint32_t UB1 :1; /* Area 1 */
uint32_t UB0 :1; /* Area 0 */
);
pad(4);
lword_union(IRMCR,
uint32_t :27;
uint32_t R2 :1; /* Re-fetch after Register 2 change */
uint32_t R1 :1; /* Re-fetch after Register 1 change */
uint32_t LT :1; /* Re-fetch after LDTLB */
uint32_t MT :1; /* Re-fetch after writing TLB */
uint32_t MC :1; /* Re-fetch after writing insn cache */
);
} GPACKED(4) sh7305_mmu_t;
#define SH7305_MMU (*(sh7305_mmu_t *)0xff000000)
#endif /* GINT_MPU_MMU */

View File

@ -37,8 +37,8 @@ typedef volatile struct
uint32_t RS :1;
uint32_t IL :1;
uint32_t SndCache :1;
uint32_t _unknown1 :1;
uint32_t :1;
uint32_t FPU :1;
uint32_t :1;
uint32_t INTC :1;
@ -53,41 +53,44 @@ typedef volatile struct
uint32_t CMT :1;
uint32_t RWDT :1;
uint32_t DMAC1 :1;
uint32_t :1;
uint32_t TMU1 :1;
uint32_t SCIF0 :1;
uint32_t SCIF1 :1;
uint32_t :4;
uint32_t SCIF2 :1;
uint32_t SCIF3 :1;
uint32_t SCIF4 :1;
uint32_t SCIF5 :1;
uint32_t :1;
uint32_t SCIF :1;
uint32_t KEYSC :1;
uint32_t RTC :1;
uint32_t :2;
uint32_t MSIOF0 :1;
uint32_t MSIOF1 :1;
uint32_t :1;
);
/* Module Stop Control Register 1 */
lword_union(MSTPCR1,
uint32_t :19;
uint32_t KEYSC :1;
uint32_t RTC :1;
uint32_t :1;
uint32_t I2C0 :1;
uint32_t I2C1 :1;
uint32_t :8;
);
/* Module Stop Control Register 2
I stripped down this one to remove any fancy modules from the SH7724
that are unlikely to even be present in the SH7305. */
The list was established by Yatis. See <https://bible.planet-casio.
com/yatis/hardware/sh7305/power.html>. */
lword_union(MSTPCR2,
uint32_t :2;
uint32_t MMC :1;
uint32_t :1;
uint32_t ADC :1;
uint32_t :6;
uint32_t TPU :1;
uint32_t :4;
uint32_t USB0 :1;
uint32_t :20;
uint32_t :2;
uint32_t SDC :1;
uint32_t :2;
uint32_t FLCTL :1;
uint32_t ECC :1;
uint32_t :1;
uint32_t I2C :1;
uint32_t :1;
uint32_t FSI_SPU :1;
uint32_t _unknown2 :1;
uint32_t :1;
uint32_t LCDC :1;
uint32_t _unknown3 :1;
uint32_t Cmod :1;
uint32_t :1;
uint32_t Cmod2A :1;
uint32_t :2;
);
pad(4);

97
include/gint/mpu/spu.h Normal file
View File

@ -0,0 +1,97 @@
//---
// gint:mpu:spu - Sound Processing Unit and its DSPs
//---
#ifndef GINT_MPU_SPU
#define GINT_MPU_SPU
#include <gint/defs/types.h>
typedef volatile struct
{
uint32_t PBANKC0; /* Program Bank Control 0 */
uint32_t PBANKC1; /* Program Bank Control 1 */
pad(0x8);
uint32_t XBANKC0; /* X Bank Control 0 */
uint32_t XBANKC1; /* X Bank Control 1 */
pad(0x10);
lword_union(SPUSRST, /* SPU Software Reset */
uint32_t :24;
uint32_t DB3 :1; /* DMABUF 3 */
uint32_t DB2 :1; /* DMABUF 2 */
uint32_t DB1 :1; /* DMABUF 1 */
uint32_t DB0 :1; /* DMABUF 0 */
uint32_t :3;
uint32_t RST :1; /* Reset */
);
uint32_t const SPUADR; /* SPU address */
uint32_t const ENDIAN; /* SuperHyway endian */
pad(0x10);
uint32_t GCOM[8]; /* Global Common */
pad(0x20);
uint32_t const DMABUF[4]; /* Inter-DSP Communication Buffer */
} GPACKED(4) spu_t;
typedef volatile struct
{
uint32_t SBAR; /* Source base address */
uint32_t SAR; /* Source address */
uint32_t DBAR; /* Destination base address */
uint32_t DAR; /* Destination address */
uint32_t TCR; /* Transfer count */
uint32_t SHPRI; /* SHway priority */
uint32_t CHCR; /* Channel control */
pad(0x4);
} GPACKED(4) spu_dsp_dma_t;
typedef volatile struct {
uint32_t LSA; /* Loop start address */
uint32_t LEA; /* Loop end address */
pad(0x8);
} GPACKED(4) spu_dsp_loop_t;
typedef volatile struct
{
uint32_t DSPRST; /* DSP full reset */
uint32_t DSPCORERST; /* DSP core reset */
uint32_t const DSPHOLD; /* DSP hold */
uint32_t DSPRESTART; /* DSP restart */
pad(0x8);
uint32_t IEMASKC; /* CPU interrupt source mask */
uint32_t IMASKC; /* CPU interrupt signal mask */
uint32_t IEVENTC; /* CPU interrupt source */
uint32_t IEMASKD; /* DSP interrupt source mask */
uint32_t IMASKD; /* DSP interrupt signal mask */
uint32_t IESETD; /* DSP interrupt set */
uint32_t IECLRD; /* DSP interrupt clear */
uint32_t OR; /* DMAC operation */
uint32_t COM[8]; /* CPU-DSP communication */
uint32_t BTADRU; /* Bus-through address high */
uint32_t BTADRL; /* Bus-through address low */
uint32_t WDATU; /* Bus-through write data high */
uint32_t WDATL; /* Bus-through write data low */
uint32_t RDATU; /* Bus-through read data high */
uint32_t RDATL; /* Bus-through read data low */
uint32_t BTCTRL; /* Bus-through mode control */
uint32_t SPUSTS; /* SPU status */
pad(0x88);
spu_dsp_dma_t DMA[3];
pad(0x20);
spu_dsp_loop_t LP[3];
} GPACKED(4) spu_dsp_t;
#define SH7305_SPU (*(spu_t *)0xfe2ffc00)
#define SH7305_DSP0 (*(spu_dsp_t *)0xfe2ffd00)
#define SH7305_DSP1 (*(spu_dsp_t *)0xfe3ffd00)
#endif /* GINT_MPU_SPU */

View File

@ -19,10 +19,15 @@ 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 */
/* rand(): Generate a pseudo-random number between 0 and RAND_MAX */
int rand(void);
/* atoi(): Convert string into decimal */
extern int atoi(const char *restrict s);
#endif /* GINT_STD_STDLIB */

View File

@ -31,4 +31,13 @@ char *strcat(char *dest, const char *src);
/* strcmp(): Compare NUL-terminated strings */
int strcmp(char const *s1, char const *s2);
/* strchr(): returns a pointer to the first occurrence of the character c */
extern char *strchr(const char *s1, int c);
/* strchrnull(): returns a pointer to the first occurrence of the character c*/
extern char *strchrnull(const char *s1, int c);
/* strchr(): returns a pointer to the first occurrence of the character c */
extern char *strrchr(const char *s1, int c);
#endif /* GINT_STD_STRING */

View File

@ -41,7 +41,7 @@
* Set a specific ID in timer_setup(), in which case the delay is no longer
interpreter as count of µs, but as a TCOR value.
* If this ID is a TMU, you can further add (with + or |) a prescaler
specification, one of TIMER_Po_{4,16,64,256}.
specification, one of TIMER_Pphi_{4,16,64,256}.
* Regardless of how the timer was obtained, you can use timer_reload() to
replace the value of TCOR.
* Also note that TMU0, TMU1, TMU2 and the ETMU have respective interrupt
@ -59,7 +59,7 @@
Standard TMU can count at different speeds. A fast speed offers more
precision but a slower speed offers longer delays. gint automatically
selects suitable speed by default.
selects suitable speeds by default.
If you want something very particular, you can add (with + or |) a prescaler
value to a chosen ID in timer_setup() to request that specific value. The
@ -186,6 +186,12 @@ 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
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. */
void timer_spinwait(int timer);
//---
// Low-level functions
//---

View File

@ -26,7 +26,7 @@ machine ?= -m4-nofpu -mb
endif
# Compiler flags, assembler flags, dependency generation, archiving
inc := -I ../include
inc := -I ../include -I include
cflags := $(machine) -ffreestanding -nostdlib -Wall -Wextra -std=c11 -Os \
-fstrict-volatile-bitfields $(inc) $(CONFIG.MACROS) \
$(CONFIG.CFLAGS)
@ -64,7 +64,7 @@ src_obj := $(foreach s,$(src),$(call src2obj,$s))
# Files with special handling
spe-fx := ../src/font5x7.png
spe-cg := ../src/font8x9.png
spe_obj := version.o $(foreach s,$(spe-$(CONFIG.TARGET)),$(call src2obj,$s))
spe_obj := $(foreach s,$(spe-$(CONFIG.TARGET)),$(call src2obj,$s))
# All object files
obj := $(src_obj) $(spe_obj)
@ -87,6 +87,8 @@ objcopy = $(CONFIG.TOOLCHAIN)-objcopy
# Version symbol is obtained by using the last commit hash on 7 nibbles
version_hash = 0x0$(shell git rev-parse --short HEAD)
# Version number: closest tag, with additional commits
version_number = $(shell git describe --tag --always | cut -d- -f1-2)
#
@ -95,7 +97,7 @@ version_hash = 0x0$(shell git rev-parse --short HEAD)
all: $(target)
$(target): $(obj)
$(target): include/gint/config.h $(obj)
@ rm -f $@
$(call cmd_l,ar,$@) $(ar) rcs $(arflags) $@ $^
@ -113,6 +115,11 @@ src/%.c.o: ../src/%.c src/%.c.d
$(call cmd_b,gcc,$*.c) $(gcc) -c $< -o $@ $(dflags) $(cflags)
# Special files
include/gint/config.h: ../include/gint/config.h.in $(gitfile)
@ mkdir -p $(dir $@)
$(call cmd_m,sed,$@) cp $< $@
@ sed -i'' 's/@GINT_VERSION@/"$(version_number)"/' $@
@ sed -i'' 's/@GINT_HASH@/$(version_hash)/' $@
$(call src2obj,../src/font5x7.png): ../src/font5x7.png
@ mkdir -p $(dir $@)
$(call cmd_m,fxconv,font5x7.png) fxconv -f $< -o $@ \
@ -123,21 +130,14 @@ $(call src2obj,../src/font8x9.png): ../src/font8x9.png
$(call cmd_m,fxconv,font8x9.png) fxconv -f $< -o $@ \
--cg --toolchain=$(CONFIG.TOOLCHAIN) name:gint_font8x9 \
charset:print grid.size:8x11 grid.padding:1 grid.border:0 \
proportional:true
# Version symbol. ld generates a .stack section for unknown reasons; I remove
# it in the linker script.
version.o: $(gitfile)
@ mkdir -p $(dir $@)
@ echo "_GINT_VERSION = $(version_hash);" > $@.txt
$(call cmd_b,ld,$@) $(ld) -r -R $@.txt -o $@
proportional:true height:9
#
# Cleaning
#
clean:
@ rm -rf src version.o{,txt}
@ rm -rf src include
distclean: clean
@ rm -rf Makefile $(CONFIG) $(target)
@ -156,7 +156,8 @@ install: $(target)
install -d $(PREFIX)
install $(target) $(m644) $(PREFIX)
install ../$(CONFIG.TARGET.LONG).ld $(m644) $(PREFIX)
cp -r ../include/gint $(PREFIX)/include
install -d $(PREFIX)/include/gint
cp -r ../include/gint/* $(PREFIX)/include/gint/
uninstall:
rm -f $(PREFIX)/$(target)

View File

@ -56,7 +56,9 @@ static void sh7705_probe(void)
/* Deduce the frequency of the main clocks. This value is ckio/3 */
int ckio_3 = 9830400;
/* Exchange the setting values 2 and 3 */
/* 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);
@ -87,8 +89,8 @@ static void sh7305_probe(void)
if(CPG.FLLFRQ.SELXM == 1) fll >>= 1;
freq.FLL = fll;
/* On SH7724, the divider ratio is given by 1 / (setting + 1), but
SH7305 behaves as 1 / (2^setting + 1). */
/* 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;
@ -116,11 +118,11 @@ static void sh7305_probe(void)
// Initialization, contexts and driver metadata
//---
/* init: Initialize thre driver */
static void init(void)
{
/* Disable spread spectrum in SSGSCR */
if(isSH4())
{
if(isSH4()) {
SH7305_CPG.SSCGCR.SSEN = 0;
}
@ -132,31 +134,41 @@ static void init(void)
sh7305_probe();
}
/* CPG context */
typedef struct {
uint32_t SSCGCR;
} ctx_t;
static ctx_t sys_ctx, gint_ctx;
/* ctx_save(): save the driver's context */
static void ctx_save(void *ctx)
{
ctx_t *c = ctx;
if(isSH4()) c->SSCGCR = SH7305_CPG.SSCGCR.lword;
if(isSH4())
c->SSCGCR = SH7305_CPG.SSCGCR.lword;
}
/* ctx_restore(): restore the driver's context */
static void ctx_restore(void *ctx)
{
ctx_t *c = ctx;
if(isSH4()) SH7305_CPG.SSCGCR.lword = c->SSCGCR;
if(isSH4())
SH7305_CPG.SSCGCR.lword = c->SSCGCR;
}
/* ctx_size(): return the context size */
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
/* create the driver object */
gint_driver_t drv_cpg = {
.name = "CPG",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
/* register the driver */
GINT_DECLARE_DRIVER(1, drv_cpg);

179
src/cpu/cpu.c Normal file
View File

@ -0,0 +1,179 @@
//---
// gint:kernel:cpu - CPU "driver"
//---
#include <gint/hardware.h>
#include <gint/drivers.h>
#include <gint/mmu.h>
#include <gint/std/string.h>
#include <gint/cpu.h>
/* The kernel's interrupt and exception handlers' entry points */
extern void gint_exch(void);
extern void gint_tlbh(void);
extern void gint_inth_7705(void);
extern void gint_inth_7305(void);
/* Size of exception and TLB handlers */
extern char gint_exch_size;
extern char gint_tlbh_size;
/* VBR information (generated by the kernel module) */
extern void *gint_vbr;
//---
// Context management
//---
/* CPU context */
typedef struct
{
sr_t SR;
uint32_t VBR;
uint32_t CPUOPM;
} ctx_t;
/* ctx_save(): save the CPU context */
static void ctx_save(ctx_t *ctx)
{
ctx->VBR = (uint32_t)(uintptr_t)cpu_getVBR();
if(isSH4()) {
ctx->CPUOPM = cpu_getCPUOPM();
ctx->SR = cpu_getSR();
}
}
/* ctx_restore(): Restore the CPU context */
static void ctx_restore(ctx_t *ctx)
{
cpu_setVBR((void*)(uintptr_t)ctx->VBR);
if(isSH4()) {
cpu_setCPUOPM(ctx->CPUOPM);
cpu_setSR(ctx->SR);
}
}
/* ctx_size(): return the context size */
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver manipulation
//---
/* init(): Initialize the CPU */
static void init(void)
{
/* Event handler entry points */
uint32_t exch_size = (uintptr_t)&gint_exch_size;
uint32_t tlbh_size = (uintptr_t)&gint_tlbh_size;
void *inth_entry = gint_inth_7305;
if (isSH3())
inth_entry = gint_inth_7705;
/* Load the event handler entry points into memory */
memcpy(gint_vbr + 0x100, gint_exch, exch_size);
memcpy(gint_vbr + 0x400, gint_tlbh, tlbh_size);
memcpy(gint_vbr + 0x600, inth_entry, 64);
/* enable some feature on SH4 */
if(isSH4()) {
cpu_setCPUOPM(cpu_getCPUOPM() | 0x00000008);
/* Enable DSP mode on the CPU */
sr_t SR = cpu_getSR();
SR.DSP = 1;
cpu_setSR(SR);
}
/* switch the VBR */
cpu_setVBR(gint_vbr);
}
/* Due to dire space restrictions on SH3, event codes that are translated to
SH4 are further remapped into the VBR space to eliminate gaps and save
space. Each entry in this table represents a 32-byte block after the
interrupt handler's entry gate. It shows the SH4 event code whose gate is
placed on that block (some of gint's SH4 event codes are invented to host
helper blocks).
For instance, the 5th block after the entry gate hosts the interrupt handler
for SH4 event 0x9e0, which is ETMU0 underflow.
The _inth_remap table in src/core/inth.S combines the SH3-SH4 translation
with the compact translation, hence its entry for 0xf00 (the SH3 event code
for ETMU0 underflow) is the offset in this table where 0x9e0 is stored,
which is 4. */
static const uint16_t sh3_vbr_map[] = {
0x400, /* TMU0 underflow */
0x420, /* TMU1 underflow */
0x440, /* TMU2 underflow */
0x460, /* (gint custom: TMU helper) */
0x9e0, /* ETMU0 underflow */
0xd00, /* ETMU4 underflow (used as helper on SH3) */
0xd20, /* (gint custom: ETMU helper) */
0xd40, /* (gint custom: ETMU helper) */
0xaa0, /* RTC Periodic Interrupt */
1, /* (Filler to maintain the gap between 0xaa0 and 0xae0) */
0xae0, /* (gint custom: RTC helper) */
0
};
/* gint_inthandler(): Install interrupt handlers */
/* Yatis note:
** Due to the hypervisor hack, we assume that the VBR is already mapped.
** FIXME
*/
void *gint_inthandler(int event_code, const void *handler, size_t size)
{
void *dest;
/* Normalize the event code */
if(event_code < 0x400)
return NULL;
event_code &= ~0x1f;
/* On SH3, make VBR compact. Use this offset specified in the VBR map
above to avoid gaps */
if(isSH3())
{
int index = 0;
while(sh3_vbr_map[index])
{
if((int)sh3_vbr_map[index] == event_code) break;
index++;
}
/* This happens if the event has not beed added to the table,
ie. the compact VBR scheme does not support this code */
if(!sh3_vbr_map[index]) return NULL;
/* Gates are placed starting at VBR + 0x200 to save space */
dest = (void *)(gint_vbr + 0x200 + index * 0x20);
}
/* On SH4, just use the code as offset */
else
{
/* 0x40 is the size of the entry gate */
dest = (void *)(gint_vbr + 0x640 + (event_code - 0x400));
}
return memcpy(dest, handler, size);
}
//---
// Driver definition
//---
/* create the driver object */
gint_driver_t drv_cpu = {
.name = "CPU",
.init = init,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)ctx_restore,
};
/* register the driver */
GINT_DECLARE_DRIVER(0, drv_cpu);

View File

@ -2,46 +2,14 @@
** gint:core:vbr - Assembler-level VBR management
*/
.global _cpu_setVBR
.text
.global _cpu_setCPUOPM
.global _cpu_getCPUOPM
.global _cpu_getSR
.global _cpu_setSR
.global _cpu_setVBR
.global _cpu_getVBR
/* cpu_setVBR(): Change VBR address */
.section .gint.mapped, "ax"
_cpu_setVBR_reloc:
mov.l r8, @-r15
sts.l pr, @-r15
stc.l sr, @-r15
/* Block all interrupts by setting IMASK=15 */
mov #0xf, r1
shll2 r1
shll2 r1
stc sr, r0
or r1, r0
ldc r0, sr
/* Set the new VBR address */
stc vbr, r8
ldc r4, vbr
/* Call the configuration function */
jsr @r5
mov r6, r4
/* Enable interrupts again by restoring the status register */
ldc.l @r15+, sr
lds.l @r15+, pr
mov r8, r0
rts
mov.l @r15+, r8
.section .gint.mappedrel, "aw"
_cpu_setVBR:
.long _cpu_setVBR_reloc
.text
/* cpu_setCPUOPM(): Change the CPU Operation Mode register */
_cpu_setCPUOPM:
@ -68,5 +36,41 @@ _cpu_getCPUOPM:
mov.l @r0, r0
.align 4
1: .long 0xff2f0000
/* cpu_getSR(): Get status register */
_cpu_getSR:
stc sr, r0
rts
nop
/* cpu_setSR(): Set status register */
_cpu_setSR:
ldc r4, sr
rts
nop
/* cpu_setVBR(): Set the VBR */
_cpu_setVBR:
/* Block all interrupts by setting IMASK=15 */
mov #0xf, r1
shll2 r1
shll2 r1
stc sr, r2
or r2, r1
ldc r1, sr
/* switch VBR */
stc vbr, r0
ldc r4, vbr
/* resotre old SR */
ldc r2, sr
rts
nop
/* cpu_getVBR: Get the VBR */
_cpu_getVBR:
stc vbr, r0
rts
nop

View File

@ -29,7 +29,7 @@ static channel_t *dma_channel(int channel)
/* dma_translate(): Translate virtual address to DMA-suitable form */
static uint32_t dma_translate(void const *address)
{
uint32_t a = (uint32_t)address;
uint32_t a = (uintptr_t)address;
/* Preserve RS addresses (as of SH7724 Reference, 11.2.2) */
if(a >= 0xfd800000 && a < 0xfd800800)
@ -173,7 +173,7 @@ void dma_transfer_noint(int channel, dma_size_t size, uint blocks,
//---
// Initialization
//---
/* init: Initialize the hardware */
static void init(void)
{
/* This driver is not implemented on SH3 */
@ -215,16 +215,20 @@ static void init(void)
DMA.OR.DME = 1;
}
/* wait(): Wait all transfers' end */
static void wait(void)
{
/* Make sure any DMA transfer is finished before leaving the app */
dma_transfer_wait(-1);
}
//---
// Context system for this driver
//---
/* define the driver context */
typedef struct
{
channel_t ch[6];
@ -233,9 +237,7 @@ typedef struct
} GPACKED(4) ctx_t;
/* One buffer for the system state will go in gint's .bss section */
GBSS static ctx_t sys_ctx, gint_ctx;
/* ctx_save(): save the current driver's context */
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -255,6 +257,7 @@ static void ctx_save(void *buf)
ctx->clock = POWER.MSTPCR0.DMAC0;
}
/* ctx_restore(): restore the driver's context */
static void ctx_restore(void *buf)
{
ctx_t *ctx = buf;
@ -279,18 +282,24 @@ static void ctx_restore(void *buf)
DMA.OR.word = ctx->OR;
}
/* ctx_size(): return the context size */
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver structure definition
//---
/* define the driver object */
gint_driver_t drv_dma0 = {
.name = "DMA0",
.init = init,
.wait = wait,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
/* register the driver */
GINT_DECLARE_DRIVER(2, drv_dma0);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -56,6 +56,9 @@ static struct info {
{ IPRK, 0xf000, IMR10, 0x04, IPRA, 0x000f },
{ IPRK, 0xf000, IMR10, 0x02, IPRA, 0x000f },
{ IPRK, 0xf000, IMR10, 0x01, IPRA, 0x000f },
/* SPU */
{ IPRC, 0x000f, IMR3, 0x04, _ /* Not supported on SH3! */ },
{ IPRC, 0x000f, IMR4, 0x08, _ },
};
@ -110,15 +113,14 @@ static void init(void)
//---
// Driver context
//---
/* define the driver's context */
typedef struct
{
uint16_t IPR[12];
uint8_t MSK[13];
} ctx_t;
GBSS static ctx_t sys_ctx, gint_ctx;
/* ctx_save(): save the current driver's context */
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -127,9 +129,7 @@ static void ctx_save(void *buf)
{
for(int i = 0; i < 8; i++)
ctx->IPR[i] = *(SH7705_INTC.IPR[i]);
}
else
{
} else {
for(int i = 0; i < 12; i++)
ctx->IPR[i] = SH7305_INTC.IPR[2 * i];
@ -139,42 +139,44 @@ static void ctx_save(void *buf)
}
}
/* ctx_restore(): restore the driver's context */
static void ctx_restore(void *buf)
{
ctx_t *ctx = buf;
if(isSH3())
{
if(isSH3()) {
for(int i = 0; i < 8; i++)
*(SH7705_INTC.IPR[i]) = ctx->IPR[i];
}
else
{
} else {
for(int i = 0; i < 12; i++)
SH7305_INTC.IPR[2 * i] = ctx->IPR[i];
/* Setting masks it a bit more involved than reading them */
uint8_t *IMCR = (void *)SH7305_INTC.MSKCLR;
uint8_t *IMR = (void *)SH7305_INTC.MSK;
for(int i = 0; i < 13; i++, IMR += 4, IMCR += 4)
{
for(int i = 0; i < 13; i++, IMR += 4, IMCR += 4) {
*IMCR = 0xff;
*IMR = ctx->MSK[i];
}
}
}
/* ctx_size(): return the context size */
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver structure definition
//---
/* create the driver object */
gint_driver_t drv_intc = {
.name = "INTC",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)ctx_save,
.ctx_restore = (void*)ctx_restore,
};
/* register the driver */
GINT_DECLARE_DRIVER(0, drv_intc);

87
src/kernel/atomic.S Normal file
View File

@ -0,0 +1,87 @@
/*
** gint:thread:atomic - Thread atomic helper
*/
.text
.align 2
.global _atomic_begin
.type _atomic_begin, @function
/* thread_atomic_begin(): Mask interrupts and exceptions */
_atomic_begin:
/* Check if the user is currently into an atomic state and update
atomic counter. */
mov.l atomic_counter, r1
mov.l @r1, r2
tst r2, r2
add #1, r2
mov.l r2, @r1
bf/s atomic_begin_exit
mov #-1, r0
/* Block all interrupts by setting IMASK=15 */
mov #0xf, r1
shll2 r1
shll2 r1
stc sr, r0
or r0, r1
ldc r1, sr
/* Save "old" SR register. */
mov.l atomic_sr_save, r1
mov.l r0, @r1
atomic_begin_exit:
rts
nop
.global _atomic_end
.type _atomic_end, @function
/* atomic_end(): Unmask (if possible) interrupts / exceptions signals */
_atomic_end:
/* Check if the device is currently into an atomic operation, then
update the counter and, if needed, restore the SR register. */
mov.l atomic_counter, r1
mov.l @r1, r0
tst r0, r0
bt atomic_end_error
cmp/eq #1, r0
add #-1, r0
mov.l r0, @r1
bf/s atomic_end_exit
mov #0, r0
/* Restore saved SR register data. */
mov.l atomic_sr_save, r1
mov.l @r1, r0
ldc r0, sr
bra atomic_end_exit
nop
atomic_end_error:
mov #-1, r0
atomic_end_exit:
rts
nop
.align 4
atomic_counter: .long _atomic_counter
atomic_sr_save: .long _atomic_sr_save
/*
** Global symbols
*/
.global _atomic_sr_save
.type _atomic_sr_save, @object
.global _atomic_counter
.type _atomic_counter, @object
.align 4
_atomic_sr_save: .long 0x00000000
_atomic_counter: .long 0x00000000

166
src/kernel/drivers.c Normal file
View File

@ -0,0 +1,166 @@
//---
// gint:core:drivers - Drivers manager
//---
#include <gint/drivers.h>
#include <gint/hardware.h>
#include <gint/atomic.h>
#include <gint/std/string.h>
#include <gint/std/stdlib.h>
#include "drivers.h"
/* external driver information */
extern gint_driver_t bdrv;
extern gint_driver_t edrv;
//---
// Context interface
//---
/* drivers_context_get_size(): Return the buffctx size */
size_t drivers_context_get_size(void)
{
size_t size = 0;
for driver_asc(drv) {
if (drv->ctx_size != NULL)
size += (drv->ctx_size() + 3) & ~3;
}
return (size);
}
/* drivers_create_cotext(): Generate buffer with can content all driver ctx */
void *drivers_context_create(void)
{
return (malloc(drivers_context_get_size()));
}
/* drivers_context_duplicate(): Duplicate an environment */
int drivers_context_duplicate(void **dst, void *src)
{
if (src == NULL)
return (-1);
size_t ctxsz = drivers_context_get_size();
*dst = realloc(*dst, ctxsz);
if (*dst == NULL)
return (-2);
atomic_begin();
memcpy(*dst, src, ctxsz);
atomic_end();
return (0);
}
/* drivers_context_destroy(): Destroy generated context */
void drivers_context_destroy(void **buffctx)
{
if (buffctx != NULL && *buffctx != NULL)
free(*buffctx);
*buffctx = NULL;
}
//---
// Drivers interface
//---
/* current env drivers information */
void *kernel_env_current = NULL;
/* driver_wait(): Wait until all driver have finished */
void drivers_wait(void)
{
for driver_asc(drv) {
if (drv->wait != NULL)
drv->wait();
}
}
/* drivers_save(): save the current drivers' context */
int drivers_save(void *buffctx)
{
if (buffctx == NULL)
return (-1);
/* we need to wait until all transction has been done */
drivers_wait();
/* save the current drivers state into the given env */
atomic_begin();
buffctx += drivers_context_get_size();
for driver_dsc(drv) {
if (drv->ctx_size != NULL)
buffctx -= (drv->ctx_size() + 3) & ~3;
if (drv->ctx_save != NULL)
drv->ctx_save(buffctx);
}
atomic_end();
return (0);
}
/* drivers_restore(): restore entier drivers' context */
void *drivers_restore(void *buffctx)
{
void *tmp;
if (buffctx == NULL)
return (NULL);
/* we need to wait until all transction has been done */
drivers_wait();
/* switch current env then restore the saved drivers' env */
atomic_begin();
tmp = kernel_env_current;
kernel_env_current = buffctx;
for driver_asc(drv) {
if (drv->ctx_restore != NULL)
drv->ctx_restore(buffctx);
if (drv->ctx_size != NULL)
buffctx += (drv->ctx_size() + 3) & ~3;
}
atomic_end();
/* return the previous env */
return (tmp);
}
/* drivers_save_and_exit(): save the current context and init the next */
void *drivers_init(void *buffctx)
{
void *tmp;
if (buffctx == NULL)
return (NULL);
/* switch the current env then initialize it */
atomic_begin();
tmp = kernel_env_current;
kernel_env_current = buffctx;
for driver_asc(drv) {
if (isSH3() && drv->driver_sh3 != NULL)
drv->driver_sh3();
if (drv->init != NULL)
drv->init();
}
atomic_end();
/* return the previous env */
return (tmp);
}
//---
// abstraction
//---
/* drivers_switch(): Switch between two world */
void *drivers_switch(void *buffctx)
{
drivers_save(kernel_env_current);
return (drivers_restore(buffctx));
}
/* drivers_get_current(): return the current context information */
void *drivers_get_current(void)
{
return (kernel_env_current);
}

32
src/kernel/hypervisor.c Normal file
View File

@ -0,0 +1,32 @@
//---
// gint:kernel:hypervisor - small hypervisor that perform world switch
//---
#include <gint/gint.h>
#include <gint/atomic.h>
#include <gint/defs/attributes.h>
#include <gint/drivers.h>
/* external symbols */
extern void *kernel_env_casio;
extern void *kernel_env_gint;
#if 0
/* gint_switch(): Temporarily switch out of gint */
GWEAK void gint_switch(void (*function)(void))
{
void *buffctx;
/* check useless switch */
if(function == NULL)
return;
/* Switch from gint to the OS after a short wait */
buffctx = drivers_switch(kernel_env_casio);
/* involve function */
function();
/* Then switch back to gint once the OS finishes working */
drivers_switch(buffctx);
}
#endif

View File

@ -2,222 +2,46 @@
// gint:core:kernel - Installing and unloading the library
//---
#include <gint/gint.h>
#include <gint/drivers.h>
#include <gint/std/string.h>
#include <gint/hardware.h>
#include <gint/mmu.h>
#include <gint/mpu/intc.h>
#include <gint/drivers.h>
#include <gint/atomic.h>
#include "cpu.h"
#include "vbr.h"
#include "drivers.h"
#include "kernel.h"
/* internal global witch content Casio and Gint environment */
void *kernel_env_casio;
void *kernel_env_gint;
static void kinit_cpu(void);
//---
// Context for the CPU and registers not directly managed by a driver
//---
typedef struct
{
uint32_t VBR;
uint32_t CPUOPM;
} ctx_t;
/* System context and gint context for the CPU and VBR */
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(ctx_t *ctx)
{
if(isSH4()) ctx->CPUOPM = cpu_getCPUOPM();
}
static void ctx_restore(ctx_t *ctx)
{
if(isSH4()) cpu_setCPUOPM(ctx->CPUOPM);
}
//---
// Driver control
//---
static void drivers_wait(void)
{
for driver_asc(d)
{
if(d->wait) d->wait();
}
}
static void drivers_save_and_init(GUNUSED int zero)
{
/* Initialize the CPU, which is done here instead of in a driver */
ctx_save(&sys_ctx);
kinit_cpu();
for driver_asc(d)
{
if(d->ctx_save) d->ctx_save(d->sys_ctx);
if(isSH3() && d->driver_sh3) d->driver_sh3();
if(d->init) d->init();
}
}
static void drivers_restore(int who)
{
for driver_dsc(d)
{
if(d->ctx_restore) d->ctx_restore(who?d->gint_ctx:d->sys_ctx);
}
ctx_restore(who ? &gint_ctx : &sys_ctx);
}
static void drivers_switch(int who)
{
/* Save all drivers in reverse order */
for driver_dsc(d)
{
if(!d->ctx_save || !d->ctx_restore) continue;
d->ctx_save(who ? d->gint_ctx : d->sys_ctx);
}
ctx_save(who ? &gint_ctx : &sys_ctx);
/* Restore the other context */
ctx_restore(who ? &sys_ctx : &gint_ctx);
for driver_asc(d)
{
if(!d->ctx_save || !d->ctx_restore) continue;
d->ctx_restore(who ? d->sys_ctx : d->gint_ctx);
}
}
//---
// Initialization and unloading
//---
static void kinit_cpu(void)
{
if(isSH4()) cpu_setCPUOPM(cpu_getCPUOPM() | 0x00000008);
}
/* global information ( workaround >_< ) */
void *gint_vbr = NULL;
/* kinit(): Install and start gint */
void kinit(void)
{
/* generate the VBR address */
#ifdef FX9860G
/* VBR is loaded 0x600 bytes before end of the user RAM (0x100 bytes at
the start of the VBR space are unused) */
gint_ctx.VBR = (uint32_t)mmu_uram() + 0x1a00 - 0x100;
gint_vbr = (void*)(uintptr_t)mmu_uram() + 0x1a00 - 0x100;
#endif
#ifdef FXCG50
/* VBR is loaded at the start of the user RAM */
gint_ctx.VBR = (uint32_t)mmu_uram();
gint_vbr = (void*)(uintptr_t)mmu_uram();
#endif
/* Event handler entry points */
void *inth_entry = isSH3() ? gint_inth_7705 : gint_inth_7305;
uint32_t exch_size = (uint32_t)&gint_exch_size;
uint32_t tlbh_size = (uint32_t)&gint_tlbh_size;
/* Load the event handler entry points into memory */
void *vbr = (void *)gint_ctx.VBR;
memcpy(vbr + 0x100, gint_exch, exch_size);
memcpy(vbr + 0x400, gint_tlbh, tlbh_size);
memcpy(vbr + 0x600, inth_entry, 64);
/* Take control of the VBR and roll! */
drivers_wait();
sys_ctx.VBR = (*cpu_setVBR)(gint_ctx.VBR, drivers_save_and_init, 0);
}
/* Due to dire space restrictions on SH3, event codes that are translated to
SH4 are further remapped into the VBR space to eliminate gaps and save
space. Each entry in this table represents a 32-byte block after the
interrupt handler's entry gate. It shows the SH4 event code whose gate is
placed on that block (some of gint's SH4 event codes are invented to host
helper blocks).
For instance, the 5th block after the entry gate hosts the interrupt handler
for SH4 event 0x9e0, which is ETMU0 underflow.
The _inth_remap table in src/core/inth.S combines the SH3-SH4 translation
with the compact translation, hence its entry for 0xf00 (the SH3 event code
for ETMU0 underflow) is the offset in this table where 0x9e0 is stored,
which is 4. */
static const uint16_t sh3_vbr_map[] = {
0x400, /* TMU0 underflow */
0x420, /* TMU1 underflow */
0x440, /* TMU2 underflow */
0x460, /* (gint custom: TMU helper) */
0x9e0, /* ETMU0 underflow */
0xd00, /* ETMU4 underflow (used as helper on SH3) */
0xd20, /* (gint custom: ETMU helper) */
0xd40, /* (gint custom: ETMU helper) */
0xaa0, /* RTC Periodic Interrupt */
1, /* (Filler to maintain the gap between 0xaa0 and 0xae0) */
0xae0, /* (gint custom: RTC helper) */
0
};
/* gint_inthandler(): Install interrupt handlers */
void *gint_inthandler(int event_code, const void *handler, size_t size)
{
void *dest;
/* Normalize the event code */
if(event_code < 0x400) return NULL;
event_code &= ~0x1f;
/* On SH3, make VBR compact. Use this offset specified in the VBR map
above to avoid gaps */
if(isSH3())
{
int index = 0;
while(sh3_vbr_map[index])
{
if((int)sh3_vbr_map[index] == event_code) break;
index++;
}
/* This happens if the event has not beed added to the table,
ie. the compact VBR scheme does not support this code */
if(!sh3_vbr_map[index]) return NULL;
/* Gates are placed starting at VBR + 0x200 to save space */
dest = (void *)gint_ctx.VBR + 0x200 + index * 0x20;
}
/* On SH4, just use the code as offset */
else
{
/* 0x40 is the size of the entry gate */
dest = (void *)gint_ctx.VBR + 0x640 + (event_code - 0x400);
}
return memcpy(dest, handler, size);
}
/* gint_switch(): Temporarily switch out of gint */
void gint_switch(void (*function)(void))
{
/* Switch from gint to the OS after a short wait */
drivers_wait();
(*cpu_setVBR)(sys_ctx.VBR, drivers_switch, 1);
if(function) function();
/* Then switch back to gint once the OS finishes working */
drivers_wait();
(*cpu_setVBR)(gint_ctx.VBR, drivers_switch, 0);
/* create Casio's context, switch to Gint and save Gint context */
kernel_env_gint = drivers_context_create();
kernel_env_casio = drivers_context_create();
drivers_save(kernel_env_casio);
drivers_init(kernel_env_gint);
drivers_save(kernel_env_gint);
}
/* kquit(): Quit gint and give back control to the system */
void kquit(void)
{
/* Wait for hardware tasks then restore all of the drivers' state and
return the VBR space to the OS */
drivers_wait();
(*cpu_setVBR)(sys_ctx.VBR, drivers_restore, 0);
drivers_restore(kernel_env_casio);
atomic_begin();
drivers_context_destroy(&kernel_env_casio);
drivers_context_destroy(&kernel_env_gint);
atomic_end();
}

View File

@ -6,9 +6,9 @@
#define GINT_CORE_KERNEL
/* kinit(): Install and start gint */
void kinit(void);
extern void kinit(void);
/* kquit(): Quit gint and give back control to the system */
void kquit(void);
extern void kquit(void);
#endif /* GINT_CORE_KERNEL */

View File

@ -113,16 +113,42 @@ int start(int isappli, int optnum)
/* Detect hardware; this will mainly tell SH3 from SH4 on fx-9860G */
hw_detect();
/* The dynamic TLB mechanism for old SH3-based fx-9860G (basically OS
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(isSH3())
{
/* Try to map every ROM address up to _srom */
volatile uint8_t *x = (void *)0x00300000;
uint32_t loaded = 0;
while(loaded < (uint32_t)&srom)
{
GUNUSED volatile uint8_t y = *x;
loaded += 1024;
x += 1024;
}
}
#endif
/* 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);
regcpy(&lilram, &silram, &rilram);
regcpy(&lxram, &sxram, &rxram);
regcpy(&lyram, &syram, &ryram);
regclr(&rbss, &sbss);
/* Do not load data to ILRAM, XRAM or YRAM on SH3 - the areas don't
exist. If you use them, you're responsible! */
if(!isSH3())
{
regcpy(&lilram, &silram, &rilram);
regcpy(&lxram, &sxram, &rxram);
regcpy(&lyram, &syram, &ryram);
}
#ifdef FX9860G
/* Copy permanentely-mapped code to start of user RAM (on fx-CG 50 it
/* Copy permanently-mapped code to start of user RAM (on fx-CG 50 it
is loaded along ILRAM contents) */
void *rgmapped = mmu_uram();
regcpy(&lgmapped, &sgmapped, rgmapped);
@ -158,6 +184,7 @@ int start(int isappli, int optnum)
}
callarray(&bdtors, &edtors);
/* Before leaving the application, we need to clean everything we
changed to hardware settings and peripheral modules. The OS is bound
to be confused (and hang, or crash, or any other kind of giving up)

View File

@ -1,8 +1,9 @@
//---
// gint:core:mmu - MMU-related definitions
// gint:mmu:mmu - MMU driver definition and context management
//---
#include <gint/mmu.h>
#include <gint/drivers.h>
#include <gint/hardware.h>
//---
@ -148,3 +149,56 @@ uint32_t utlb_translate(uint32_t page)
}
return -1;
}
//---
// Initialization
//---
static void init(void)
{
/* Make writes to the control register area synchronous; this is needed
for the SPU to operate properly */
if(isSH4()) SH7305_MMU.PASCR.UBC = 1;
}
//---
// Context management
//---
typedef struct {
uint32_t PASCR;
uint32_t IRMCR;
} ctx_t;
static void ctx_save(void *buf)
{
if(isSH3()) return;
ctx_t *ctx = buf;
ctx->PASCR = SH7305_MMU.PASCR.lword;
ctx->IRMCR = SH7305_MMU.IRMCR.lword;
}
static void ctx_restore(void *buf)
{
if(isSH3()) return;
ctx_t *ctx = buf;
SH7305_MMU.PASCR.lword = ctx->PASCR;
SH7305_MMU.IRMCR.lword = ctx->IRMCR;
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
gint_driver_t drv_mmu = {
.name = "MMU",
.init = init,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
GINT_DECLARE_DRIVER(1, drv_mmu);

View File

@ -253,9 +253,6 @@ typedef struct
} GPACKED(2) ctx_t;
/* Allocate one buffer in gint's storage section */
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -268,10 +265,15 @@ static void ctx_restore(void *buf)
r61524_win_set(ctx->HSA, ctx->HEA, ctx->VSA, ctx->VEA);
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver initialization
//---
/* init(): Initialize the hardware */
static void init(void)
{
select(device_code_read);
@ -284,14 +286,14 @@ static void init(void)
//---
// Driver structure definition
//---
/* define the driver object */
gint_driver_t drv_r61524 = {
.name = "R61524",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
/* register the driver */
GINT_DECLARE_DRIVER(5, drv_r61524);

View File

@ -11,3 +11,9 @@ void dupdate(void)
overwriting the data which is about to be sent. */
dvram_switch();
}
/* dupdate_noint(): Push the video RAM to the display driver without DMA */
void dupdate_noint(void)
{
r61524_display(gint_vram, 0, 224, R61524_CPU);
}

View File

@ -61,9 +61,8 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
/* Move to top row */
uint16_t *target = gint_vram + 396 * y;
/* Character spacing and space waiting to be drawn */
int space = 1;
int active_space = 0;
/* Character spacing waiting to be drawn, in pixels */
int space = 0;
/* Read each character from the input string */
while(1)
@ -74,29 +73,23 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
int glyph = topti_glyph_index(f, code_point);
if(glyph < 0) continue;
/* Draw the space if background is opaque */
int prop_space = (code_point == ' ' && f->prop) ? 5 : 0;
if(active_space || prop_space)
{
active_space += prop_space;
if(bg >= 0) drect(x, y, x + active_space - 1,
y + height - 1, bg);
}
x += active_space;
if(prop_space) { active_space = space; continue; }
int dataw = f->prop ? f->glyph_width[glyph] : f->width;
/* Draw character spacing if background is opaque */
if(space && bg >= 0) drect(x, y, x+space-1, y+height-1, bg);
x += space;
if(x >= 396) break;
int index = topti_offset(f, glyph);
/* Compute horizontal intersection between glyph and screen */
int dataw = f->prop ? f->glyph_width[glyph] : f->width;
int width = dataw, left = 0;
if(x + dataw <= 0)
{
x += dataw;
active_space = space;
space = f->char_spacing;
continue;
}
if(x < 0) left = -x, width += x;
@ -108,7 +101,7 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
dataw, fg, bg);
x += dataw;
active_space = space;
space = f->char_spacing;
}
}
@ -121,10 +114,10 @@ void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
int w, h;
dsize(str, topti_font, &w, &h);
if(halign == DTEXT_RIGHT) x -= w;
if(halign == DTEXT_CENTER) x -= ((w+1) >> 1);
if(valign == DTEXT_BOTTOM) y -= h;
if(valign == DTEXT_MIDDLE) y -= ((h+1) >> 1);
if(halign == DTEXT_RIGHT) x -= w - 1;
if(halign == DTEXT_CENTER) x -= (w >> 1);
if(valign == DTEXT_BOTTOM) y -= h - 1;
if(valign == DTEXT_MIDDLE) y -= (h >> 1);
}
topti_render(x, y, str, topti_font, fg, bg);

View File

@ -291,24 +291,3 @@ int bopti_clip(bopti_image_t const *img, struct rbox *r)
/* Return non-zero if the result is empty */
return (width <= 0 || height <= 0);
}
void bopti_render_noclip(bopti_image_t const *img, struct rbox *r,
uint32_t *v1, uint32_t *v2)
{
int left = r->left;
/* Start column and end column (both included) */
r->left >>= 5;
if(r->columns == 1 && (r->visual_x & 31) + r->width <= 32)
{
r->x = (left & 31) - (r->visual_x & 31);
bopti_render_scsp(img, r, v1, v2);
}
else
{
/* x-coordinate of the first pixel of the first column */
r->x = r->visual_x - (left & 31);
bopti_render(img, r, v1, v2);
}
}

View File

@ -44,6 +44,8 @@ void gint_dvline(int y1, int y2, int x, int color)
if((uint)x >= 128) return;
if(y1 > y2) swap(y1, y2);
if(y1 >= 64 || y2 < 0) return;
if(y1 < 0) y1 = 0;
if(y2 >= 64) y2 = 63;
uint32_t *base = gint_vram + (y1 << 2) + (x >> 5);
uint32_t *lword = base + ((y2 - y1 + 1) << 2);

View File

@ -30,18 +30,24 @@ void masks(int x1, int x2, uint32_t *masks);
@rbox Rendering box */
int bopti_clip(bopti_image_t const *img, struct rbox *rbox);
/* bopti_render_noclip(): Render a bopti image without clipping
This function is only ever slightly faster than bopti_render_clip(),
eliminating two types of coordinate checks:
1. The bounding box does not overflow from the image
2. The final rendering does not overflow from the screen
/* bopti_render(): Render a bopti image
Copies an image into the VRAM. This function does not perform clipping;
use bopti_clip() on the rbox before calling it if needed.
@x @y Location of the top-left corner
@img Image encoded by [fxconv]
@left @top @w @h Bounding box to render
@v1 @v2 VRAMs (gray rendering is used if v2 != NULL) */
void bopti_render_noclip(bopti_image_t const *img, struct rbox *rbox,
uint32_t *v1, uint32_t *v2);
@img Image encoded by [fxconv]
@rbox Rendering box (may or may not be clipped)
@v1 @v2 VRAMs (gray rendering is used if v2 != NULL) */
void bopti_render(bopti_image_t const *img, struct rbox *rbox, uint32_t *v1,
uint32_t *v2);
/* bopti_render_scsp(): Single-column single-position image renderer
This function is a specialized version of bopti_render() that can be used
when only a single column of the source image is used (all pixels to be
rendered are in a single 32-aligned 32-wide pixel column of the source) and
a single position of the VRAM is used (all pixels to be rendered end up in a
single 32-aligned 32-wide pixel column of the VRAM). */
void bopti_render_scsp(bopti_image_t const *img, struct rbox *rbox,
uint32_t *v1, uint32_t *v2);
//---
// Alternate rendering modes

View File

@ -133,7 +133,7 @@ void topti_render(int x, int y, char const *str_char, font_t const *f,
free = topti_split(data+index, width, height, free, operators);
/* Potential space after the glyph */
int space = (*str != 0);
int space = (*str != 0) ? f->char_spacing : 0;
free -= space;
if(free > 0) continue;
@ -186,10 +186,10 @@ void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
int w, h;
dsize(str, topti_font, &w, &h);
if(halign == DTEXT_RIGHT) x -= w;
if(halign == DTEXT_CENTER) x -= ((w+1) >> 1);
if(valign == DTEXT_BOTTOM) y -= h;
if(valign == DTEXT_MIDDLE) y -= ((h+1) >> 1);
if(halign == DTEXT_RIGHT) x -= w - 1;
if(halign == DTEXT_CENTER) x -= (w >> 1);
if(valign == DTEXT_BOTTOM) y -= h - 1;
if(valign == DTEXT_MIDDLE) y -= (h >> 1);
}
topti_render(x, y, str, topti_font, topti_asm_text[fg],

View File

@ -3,10 +3,6 @@
#include "../render/render.h"
/* TODO: These parameters will eventually be specified by the font */
#define CHAR_SPACING 1
#define PROP_SPACING 5
/* dfont(): Set the default font for text rendering */
font_t const *dfont(font_t const * font)
{
@ -105,39 +101,34 @@ uint32_t topti_utf8_next(uint8_t const **str_pointer)
void dsize(char const *str_char, font_t const * f, int *w, int *h)
{
uint8_t const *str = (void *)str_char;
uint32_t code_point;
if(!f) f = topti_font;
if(h) *h = f->line_height;
if(!w) return;
/* Width for monospaced fonts is easy, unfortunately we still need to
compute the length of [str]. Critical applications might do the
product themselves to avoid this cost. */
compute the length and group bytes into Unicode code points. */
if(!f->prop)
{
int length = 0;
while(*str++) length++;
*w = (f->width + CHAR_SPACING) * length - CHAR_SPACING;
while((code_point = topti_utf8_next(&str))) length++;
*w = (f->width + f->char_spacing) * length - f->char_spacing;
return;
}
/* For proportional fonts, fetch the width of each individual glyphs */
int width = 0;
uint32_t code_point;
while(1)
{
code_point = topti_utf8_next(&str);
if(!code_point) break;
if(code_point == ' ')
{
width += PROP_SPACING + CHAR_SPACING;
continue;
}
int glyph = topti_glyph_index(f, code_point);
if(glyph >= 0) width += f->glyph_width[glyph] + CHAR_SPACING;
if(glyph < 0) continue;
width += f->glyph_width[glyph] + f->char_spacing;
}
*w = width - CHAR_SPACING;
*w = width - f->char_spacing;
}

View File

@ -180,8 +180,6 @@ typedef struct
uint8_t RCR2;
} ctx_t;
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -197,6 +195,11 @@ static void ctx_restore(void *buf)
RTC->RCR2.byte = ctx->RCR2 & 0x7f;
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver structure definition
//---
@ -205,10 +208,9 @@ gint_driver_t drv_rtc = {
.name = "RTC",
.driver_sh3 = GINT_DRIVER_SH3(driver_sh3),
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
GINT_DECLARE_DRIVER(2, drv_rtc);

100
src/spu/spu.c Normal file
View File

@ -0,0 +1,100 @@
#include <gint/mpu/spu.h>
#include <gint/mpu/cpg.h>
#include <gint/mpu/power.h>
#include <gint/drivers.h>
#include <gint/clock.h>
#include <gint/intc.h>
#define SPU SH7305_SPU
#define DSP0 SH7305_DSP0
#define DSP1 SH7305_DSP1
#define CPG SH7305_CPG
#define POWER SH7305_POWER
static void init(void)
{
/* Block SPU interrupts from DSP0, DSP1, and their DMA */
intc_priority(INTC_SPU_DSP0, 0);
intc_priority(INTC_SPU_DSP1, 0);
/* Stop both the SPU and FSI clocks */
CPG.FSICLKCR.lword = 0x00000103;
CPG.SPUCLKCR.lword = 0x00000100;
/* Enable the FSI clock, then the SPU/SPURAM clock */
CPG.FSICLKCR.CLKSTP = 0;
CPG.SPUCLKCR.CLKSTP = 0;
/* Power the clocks through MSTPCR2 */
POWER.MSTPCR2.FSI_SPU = 0;
/* Reset the SPU */
SPU.SPUSRST.RST = 0;
sleep_us_spin(1000);
SPU.SPUSRST.RST = 1;
sleep_us_spin(1000);
/* Initially give all P memory and X memory to DSP0 */
SPU.PBANKC0 = 0x1f;
SPU.PBANKC1 = 0x00;
SPU.XBANKC0 = 0x7f;
SPU.XBANKC1 = 0x00;
/* Perform full DSP resets */
DSP0.DSPCORERST = 1;
DSP1.DSPCORERST = 1;
DSP0.DSPRST = 0;
DSP1.DSPRST = 0;
sleep_us_spin(1000);
}
int spu_zero(void)
{
return 0;
}
//---
// Hardware context
//---
typedef struct
{
uint32_t PBANKC0, PBANKC1;
uint32_t XBANKC0, XBANKC1;
} ctx_t;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
ctx->PBANKC0 = SPU.PBANKC0;
ctx->PBANKC1 = SPU.PBANKC1;
ctx->XBANKC0 = SPU.XBANKC0;
ctx->XBANKC1 = SPU.XBANKC1;
}
static void ctx_restore(void *buf)
{
ctx_t *ctx = buf;
SPU.PBANKC0 = ctx->PBANKC0;
SPU.PBANKC1 = ctx->PBANKC1;
SPU.XBANKC0 = ctx->XBANKC0;
SPU.XBANKC1 = ctx->XBANKC1;
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver structure definition
//---
gint_driver_t drv_spu = {
.name = "SPU",
.init = init,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
GINT_DECLARE_DRIVER(3, drv_spu);

16
src/std/stdlib.c Normal file
View File

@ -0,0 +1,16 @@
#include <gint/defs/types.h>
#include <gint/defs/attributes.h>
GWEAK int atoi(const char *restrict s)
{
if (s == NULL)
return (0);
int nb = 0;
for (int i = 0; s[i] != '\0'; ++i) {
if (s[i] < '0' || s[i] > '9')
return (nb);
nb = (nb * 10) + (s[i] - '0');
}
return (nb);
}

View File

@ -33,3 +33,35 @@ GWEAK int strcmp(char const *s1, char const *s2)
while(*s1 && *s1 == *s2) s1++, s2++;
return *s1 - *s2;
}
GWEAK char *strchr(const char *s1, int c)
{
void *ret;
int i;
i = -1;
while (s1[++i] != '\0' && s1[i] != c);
ret = NULL;
if (s1[i] != '\0')
ret = (void *)&s1[i];
return (ret);
}
GWEAK char *strchrnul(const char *s1, int c)
{
int i = -1;
while (s1[++i] != '\0' && s1[i] != c) ;
return ((void *)&s1[i]);
}
GWEAK char *strrchr(const char *s1, int c)
{
void *saved;
saved = NULL;
for (int i = 0; s1[i] != '\0'; i++) {
if (s1[i] == c)
saved = (void *)&s1[i];
}
return (saved);
}

View File

@ -10,5 +10,5 @@ void srand(unsigned int seed)
int rand(void)
{
return tinymt32_generate_uint32(&random);
return tinymt32_generate_uint32(&random) & 0x7fffffff;
}

View File

@ -195,9 +195,6 @@ typedef struct
} GPACKED(1) ctx_t;
/* Pre-allocate a context in gint's uninitialized section */
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
if(gint[HWCALC] == HWCALC_G35PE2) return;
@ -221,6 +218,11 @@ static void ctx_restore(void *buf)
command(reg_counter, cnt);
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver initialization
//---
@ -239,10 +241,9 @@ static void init(void)
gint_driver_t drv_t6k11 = {
.name = "T6K11",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
GINT_DECLARE_DRIVER(5, drv_t6k11);

View File

@ -5,8 +5,7 @@
#include <gint/clock.h>
#include <gint/timer.h>
/* sleep_us(): Sleep for a fixed duration in microseconds */
void sleep_us(uint64_t delay_us)
static void do_sleep(uint64_t delay_us, int spin)
{
volatile int flag = 0;
@ -14,5 +13,18 @@ void sleep_us(uint64_t delay_us)
if(timer < 0) return;
timer_start(timer);
timer_wait(timer);
if(spin) timer_spinwait(timer);
else timer_wait(timer);
}
/* sleep_us(): Sleep for a fixed duration in microseconds */
void sleep_us(uint64_t delay_us)
{
do_sleep(delay_us, 0);
}
/* sleep_us_spin(): Actively sleep for a fixed duration in microseconds */
void sleep_us_spin(uint64_t delay_us)
{
do_sleep(delay_us, 1);
}

View File

@ -261,13 +261,13 @@ void timer_stop(int id)
}
}
/* timer_wait() - wait until a timer is stopped */
/* timer_wait(): Wait for a timer to stop */
void timer_wait(int id)
{
if(id < 3)
{
tmu_t *T = &TMU[id];
/* Sleep if an interruption will wake us up */
/* Sleep only if an interrupt will be there to wake us up */
while(*TSTR & (1 << id)) if(T->TCR.UNIE) sleep();
}
else
@ -277,6 +277,21 @@ void timer_wait(int id)
}
}
/* timer_spinwait(): Actively wait for a timer to raise UNF */
void timer_spinwait(int id)
{
if(id < 3)
{
tmu_t *T = &TMU[id];
while(!T->TCR.UNF) {}
}
else
{
etmu_t *T = &ETMU[id-3];
while(!T->TCR.UNF) {}
}
}
//---
// Predefined timer callbacks
//---
@ -421,9 +436,6 @@ typedef struct
uint8_t TSTR;
} ctx_t;
/* Allocate a system buffer in gint's BSS area */
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -483,6 +495,11 @@ static void ctx_restore(void *buf)
*TSTR = ctx->TSTR;
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver structure definition
//---
@ -491,10 +508,9 @@ gint_driver_t drv_tmu = {
.name = "TMU",
.driver_sh3 = GINT_DRIVER_SH3(driver_sh3),
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
GINT_DECLARE_DRIVER(2, drv_tmu);