forked from Lephenixnoir/gint
Compare commits
21 Commits
master
...
dyn_driver
Author | SHA1 | Date |
---|---|---|
Yatis | c923ad24b1 | |
Yatis | 6961a0feec | |
Yatis | 48709c72e4 | |
Yatis | 01f5f883e7 | |
Lephe | 7a68070bac | |
Lephe | ad6c108dfc | |
Lephe | 2c2d1513f9 | |
Lephe | 3694f20d56 | |
Lephe | 8ff7d89d33 | |
Lephe | 858ec8aa12 | |
Lephe | 19951ccf62 | |
Lephe | 3a15340335 | |
Lephe | e63ff8351b | |
Lephe | bc575f1599 | |
Lephe | 52d95e72ed | |
Lephe | 078edb50b2 | |
Lephe | 240f29f9d5 | |
Lephe | 2e8b1020cb | |
Lephe | 9b462deca1 | |
Lephe | e66b9083b4 | |
Lephe | 744d243265 |
1
TODO
1
TODO
|
@ -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
|
||||
|
|
|
@ -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__*/
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -16,7 +16,8 @@
|
|||
typedef unsigned int uint;
|
||||
/* Signed size_t */
|
||||
typedef signed int ssize_t;
|
||||
|
||||
/* Offset */
|
||||
typedef unsigned int off_t;
|
||||
//---
|
||||
// Structure elements
|
||||
//----
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
//---
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
//---
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
|
@ -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
|
|
@ -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);
|
||||
|
|
BIN
src/font8x9.png
BIN
src/font8x9.png
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -10,5 +10,5 @@ void srand(unsigned int seed)
|
|||
|
||||
int rand(void)
|
||||
{
|
||||
return tinymt32_generate_uint32(&random);
|
||||
return tinymt32_generate_uint32(&random) & 0x7fffffff;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue