mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23:36 +01:00
exc: add exception handlers, use them in the DMA
This change introduces exception handlers that default to a fatal error with an on-screen description of the exception and some debugging information. It also adds the dprint() function as a definitely-needed helper and removes bootlog_unmapped() by using the exception handler for the fatal error display. (Also printf() is now required in all gint add-ins; this is sad, but space is not as much of a constraint as debugging.) Finally, the exception handler is used to handle an interrupt which is an exception in practice, the DMA address error. On fx-CG 50, additional DMA-related information is displayed on the screen. This is left out on fx-9860G as there is not enough space.
This commit is contained in:
parent
6d54a5fe0a
commit
e1aca8d89b
18 changed files with 226 additions and 76 deletions
7
TODO
7
TODO
|
@ -1,7 +1,7 @@
|
|||
Crucial, missing things.
|
||||
! core: the four basic memory functions
|
||||
! core: build an exception handler and a TLB miss handler
|
||||
! core: gint_switch() (driver contexts on stack; arbitrary code?)
|
||||
! core: gint_switch() with driver contexts on stack and arbitrary code
|
||||
! core: use gint_switch() to handle TLB misses
|
||||
! bopti: fxcg50 version
|
||||
! syscalls: fxcg50 BFile calls
|
||||
|
||||
|
@ -10,10 +10,11 @@ Tests to run.
|
|||
* topti: all charsets
|
||||
|
||||
Complementary elements on existing code.
|
||||
* gray: find good values for more models than the Graph 35+E II
|
||||
* render: get rid of GINT_NEED_VRAM and #define vram gint_vram if you need
|
||||
* dma: dma_memcpy() and dma_memset(), possibly requiring alignment
|
||||
* core: use topti in the error message for missing mappings
|
||||
* core: find the #ifdef FX9860G|FXCG50 that have a cross-platform def
|
||||
* core: try to leave add-in without reset in case of fatal exception
|
||||
* topti: support Unicode fonts
|
||||
* hardware: fill in the HWMEM_FITTLB flag
|
||||
* keyboard: think of extended functions
|
||||
|
|
|
@ -55,6 +55,10 @@ SECTIONS
|
|||
} > rom
|
||||
|
||||
.text : {
|
||||
_gint_exch_tlbh_start = . ;
|
||||
*(.gint.exch_tlbh);
|
||||
_gint_exch_tlbh_size = ABSOLUTE(. - _gint_exch_tlbh_start);
|
||||
|
||||
*(.text .text.*)
|
||||
*(C P)
|
||||
} > rom
|
||||
|
|
|
@ -49,6 +49,10 @@ SECTIONS
|
|||
*(.dtors .dtors.*)
|
||||
_etors = . ;
|
||||
|
||||
_gint_exch_tlbh_start = . ;
|
||||
*(.gint.exch_tlbh);
|
||||
_gint_exch_tlbh_size = ABSOLUTE(. - _gint_exch_tlbh_start);
|
||||
|
||||
*(.text .text.*)
|
||||
} > rom
|
||||
|
||||
|
|
|
@ -11,12 +11,6 @@
|
|||
Called when RAM sections have been wiped and copied */
|
||||
void bootlog_loaded(void);
|
||||
|
||||
/* bootlog_unmapped() - ROM mapping stage failed
|
||||
Called if not enough ROM pages have been mapped.
|
||||
@rom Amount of mapped ROM, in bytes
|
||||
@size Minimum mapping required */
|
||||
void bootlog_unmapped(int rom, int size);
|
||||
|
||||
/* bootlog_mapped() - ROM mapping stage
|
||||
Called after all ROM pages have been traversed. All of them may not have
|
||||
been mapped.
|
||||
|
@ -37,7 +31,6 @@ void bootlog_driver_summary(void);
|
|||
/* All these functions are enabled only if GINT_BOOT_LOG is defined */
|
||||
#ifndef GINT_BOOT_LOG
|
||||
#define bootlog_loaded(...)
|
||||
#define bootlog_unmapped(...)
|
||||
#define bootlog_mapped(...)
|
||||
#define bootlog_kernel(...)
|
||||
#define bootlog_driver(...)
|
||||
|
|
|
@ -20,4 +20,12 @@
|
|||
Returns the previous VBR address. */
|
||||
uint32_t gint_setvbr(uint32_t vbr, void (*configure)(void));
|
||||
|
||||
/* gint_exch_tlbh(): Exception and TLB miss handler */
|
||||
void gint_exch_tlbh(void);
|
||||
|
||||
/* gint_inth_7705(): SH7705 exception handler */
|
||||
void gint_inth_7705(void);
|
||||
/* gint_inth_7305(): SH7305 exception handler */
|
||||
void gint_inth_7305(void);
|
||||
|
||||
#endif /* GINT_CORE_SETUP */
|
||||
|
|
|
@ -199,6 +199,11 @@ void dsize(const char *str, font_t const * font, int *w, int *h);
|
|||
fxcg50: Any R5G6B5 color, or C_NONE */
|
||||
void dtext(int x, int y, const char *str, int fg, int bg);
|
||||
|
||||
/* dprint(): Display a formatted string
|
||||
Much like dtext(), but accepts printf-like formats with arguments. See
|
||||
<gint/std/stdio.h> for a detailed view of what this format supports. */
|
||||
void dprint(int x, int y, int fg, int bg, char const *format, ...);
|
||||
|
||||
//---
|
||||
// Image rendering (bopti)
|
||||
//---
|
||||
|
|
|
@ -79,4 +79,19 @@ void dma_transfer_noint(int channel, dma_size_t size, uint blocks,
|
|||
void const *src, dma_address_t src_mode,
|
||||
void *dst, dma_address_t dst_mode);
|
||||
|
||||
//---
|
||||
// DMA-based memory manipulation functions
|
||||
//---
|
||||
|
||||
/* dma_memset(): Fast 32-aligned memset
|
||||
This function is your typical memset, except that the destination and size
|
||||
must be 32-aligned, and that the pattern is 4 bytes instead of one. It is
|
||||
replicated to 32 bytes then used to fill the destination area. This 4-byte
|
||||
fixed size may be lifted in future versions.
|
||||
|
||||
@dst Destination address (32-aligned)
|
||||
@pattern 4-byte pattern to fill @dst
|
||||
@size Sie of destination area (32-aligned) */
|
||||
void *dma_memset(void *dst, uint32_t pattern, size_t size);
|
||||
|
||||
#endif /* GINT_DMA */
|
||||
|
|
21
include/gint/exc.h
Normal file
21
include/gint/exc.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
//---
|
||||
// gint:exc - Exception handling
|
||||
//
|
||||
// This small module is used to display exceptions and configure when the
|
||||
// exception handler displays these messages. This is for advanced users
|
||||
// only!
|
||||
//---
|
||||
|
||||
#ifndef GINT_EXC
|
||||
#define GINT_EXC
|
||||
|
||||
/* gint_exc(): Exception handler fatal error message
|
||||
Displays a full-screen fatal error message from an exception event code.
|
||||
Some custom event codes are also used for library failure. This function is
|
||||
typically called by exception handlers and returns after a dupdate_noint().
|
||||
You probably want to soft-lock or quit the add-in after calling it. */
|
||||
void gint_exc(uint32_t code);
|
||||
|
||||
/* TODO: Add functions to disable fatal errors for some exceptions */
|
||||
|
||||
#endif /* GINT_EXC */
|
|
@ -117,14 +117,6 @@ void bootlog_mapped(int rom, GUNUSED int ram)
|
|||
dupdate();
|
||||
}
|
||||
|
||||
/* bootlog_unmapped() - ROM mapping stage failure */
|
||||
void bootlog_unmapped(int rom, int size)
|
||||
{
|
||||
print(1, 6, "MMU: add-in too large");
|
||||
print(1, 7, "%8x < %8x", rom, size);
|
||||
dupdate();
|
||||
}
|
||||
|
||||
/* bootlog_kernel() - gint loading stage */
|
||||
void bootlog_kernel(void)
|
||||
{
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
** gint:core:exch - Exception handlers
|
||||
*/
|
||||
|
||||
.global _exch_entry_7305
|
||||
|
||||
#ifdef FX9860G
|
||||
.global _exch_entry_7705
|
||||
#endif
|
||||
|
||||
.section .gint.blocks, "ax"
|
||||
.align 4
|
||||
|
||||
/* SH7305-TYPE DEBUG EXCEPTION HANDLER */
|
||||
|
||||
_exch_entry_7705:
|
||||
_exch_entry_7305:
|
||||
mov.l 1f, r0
|
||||
mov.l @r0, r4
|
||||
|
||||
rte
|
||||
nop
|
||||
|
||||
.zero 20
|
||||
|
||||
1: .long 0xff000024
|
98
src/core/exch.c
Normal file
98
src/core/exch.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
#define GINT_NEED_VRAM
|
||||
#include <gint/display.h>
|
||||
#include <gint/exc.h>
|
||||
#include <gint/defs/attributes.h>
|
||||
|
||||
#define dprint(x, y, ...) dprint(x, y, C_BLACK, C_NONE, __VA_ARGS__)
|
||||
#define dtext(x, y, str) dtext (x, y, str, C_BLACK, C_NONE)
|
||||
|
||||
/* gint_exc(): Exception handler fatal error message */
|
||||
void gint_exc(GUNUSED uint32_t code)
|
||||
{
|
||||
uint32_t TEA = *(volatile uint32_t *)0xff00000c;
|
||||
uint32_t TRA = *(volatile uint32_t *)0xff000020 >> 2;
|
||||
|
||||
uint32_t PC;
|
||||
__asm__("stc spc, %0" : "=r"(PC));
|
||||
|
||||
dfont(NULL);
|
||||
dclear(C_WHITE);
|
||||
|
||||
#ifdef FX9860G
|
||||
dtext(1, 0, "Exception! (SysERROR)");
|
||||
for(int i = 0; i < 32; i++) vram[i] = ~vram[i];
|
||||
|
||||
char const *name = "";
|
||||
if(code == 0x040) name = "TLB miss read";
|
||||
if(code == 0x060) name = "TLB miss write";
|
||||
if(code == 0x0e0) name = "Read address error";
|
||||
if(code == 0x100) name = "Write address error";
|
||||
if(code == 0x160) name = "Unconditional trap";
|
||||
if(code == 0x180) name = "Illegal instruction";
|
||||
if(code == 0x1a0) name = "Illegal delay slot";
|
||||
|
||||
/* Custom gint codes for convenience */
|
||||
if(code == 0x1020) name = "DMA address error";
|
||||
if(code == 0x1040) name = "Add-in too large";
|
||||
|
||||
if(name[0]) dtext(1, 9, name);
|
||||
else dprint(1, 9, "%03x", code);
|
||||
|
||||
dprint(1, 17, " PC :%08x", PC);
|
||||
dprint(1, 25, "TEA :%08x", TEA);
|
||||
dprint(1, 33, "TRA :%08x", TRA);
|
||||
|
||||
dtext(1, 49, "The add-in crashed.");
|
||||
dtext(1, 57, "Please reset the calc");
|
||||
#endif
|
||||
|
||||
#ifdef FXCG50
|
||||
dtext(6, 3, "An exception occured! (System ERROR)");
|
||||
|
||||
uint32_t *long_vram = (void *)vram;
|
||||
for(int i = 0; i < 198 * 16; i++) long_vram[i] = ~long_vram[i];
|
||||
|
||||
char const *name = "";
|
||||
if(code == 0x040) name = "TLB miss (nonexisting address) on read";
|
||||
if(code == 0x060) name = "TLB miss (nonexisting address) on write";
|
||||
if(code == 0x0e0) name = "Read address error (probably alignment)";
|
||||
if(code == 0x100) name = "Write address error (probably alignment)";
|
||||
if(code == 0x160) name = "Unconditional trap";
|
||||
if(code == 0x180) name = "Illegal instruction";
|
||||
if(code == 0x1a0) name = "Illegal delay slot instruction";
|
||||
|
||||
/* Custom gint codes for convenience */
|
||||
if(code == 0x1020) name = "DMA address error";
|
||||
if(code == 0x1040) name = "Add-in not fully mapped (too large)";
|
||||
|
||||
dprint(6, 25, "%03x %s", code, name);
|
||||
|
||||
dtext(6, 45, "PC");
|
||||
dprint(38, 45, "= %08x", PC);
|
||||
dtext(261, 45, "(Error location)");
|
||||
|
||||
dtext(6, 60, "TEA");
|
||||
dprint(38, 60, "= %08x", TEA);
|
||||
dtext(234, 60, "(Offending address)");
|
||||
|
||||
dtext(6, 75, "TRA");
|
||||
dprint(38, 75, "= %#x", TRA);
|
||||
dtext(281, 75, "(Trap number)");
|
||||
|
||||
dtext(6, 95, "An unrecoverable error ocurred in the add-in.");
|
||||
dtext(6, 108, "Please press the RESET button to restart the");
|
||||
dtext(6, 121, "calculator.");
|
||||
#endif
|
||||
|
||||
dupdate_noint();
|
||||
}
|
||||
|
||||
/* gint_exch_tlbh(): Exception and TLB miss handler */
|
||||
__attribute__((interrupt_handler)) GSECTION(".gint.exch_tlbh") GALIGNED(4)
|
||||
void gint_exch_tlbh(void)
|
||||
{
|
||||
uint32_t EXPEVT = *(volatile uint32_t *)0xff000024;
|
||||
|
||||
gint_exc(EXPEVT);
|
||||
while(1);
|
||||
}
|
|
@ -5,10 +5,10 @@
|
|||
** blocks depending on its configuration.
|
||||
*/
|
||||
|
||||
.global _inth_entry_7305
|
||||
.global _gint_inth_7305
|
||||
|
||||
#ifdef FX9860G
|
||||
.global _inth_entry_7705
|
||||
.global _gint_inth_7705
|
||||
#endif
|
||||
|
||||
.section .gint.blocks, "ax"
|
||||
|
@ -36,7 +36,7 @@
|
|||
/* SH7305-TYPE DEBUG INTERRUPT HANDLER - 26 BYTES */
|
||||
|
||||
#if 0
|
||||
_inth_entry_7305:
|
||||
_gint_inth_7305:
|
||||
mov.l 1f, r0
|
||||
mov.l @r0, r4
|
||||
|
||||
|
@ -56,7 +56,7 @@ _inth_entry_7305:
|
|||
|
||||
/* SH7305-TYPE INTERRUPT HANDLER ENTRY - 20 BYTES */
|
||||
|
||||
_inth_entry_7305:
|
||||
_gint_inth_7305:
|
||||
/* Get the event code from the INTEVT register */
|
||||
mov.l 1f, r0
|
||||
mov.l @r0, r0
|
||||
|
@ -78,7 +78,7 @@ _inth_entry_7305:
|
|||
|
||||
/* SH7705-TYPE INTERRUT HANDLER ENTRY - 32 BYTES */
|
||||
|
||||
_inth_entry_7705:
|
||||
_gint_inth_7705:
|
||||
/* Get the event code from the INTEVT2 register */
|
||||
mov.l 1f, r0
|
||||
mov.l @r0, r0 /* r0 = old_code */
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
extern char gint_vbr;
|
||||
/* System's VBR address */
|
||||
GBSS static uint32_t system_vbr;
|
||||
/* Size of exception and TLB handler */
|
||||
extern char gint_exch_tlbh_size;
|
||||
/* Driver table */
|
||||
extern gint_driver_t bdrv, edrv;
|
||||
|
||||
|
@ -67,11 +69,13 @@ static void lock(void)
|
|||
void gint_install(void)
|
||||
{
|
||||
/* VBR address, provided by the linker script */
|
||||
uint32_t vbr = (uint32_t)&gint_vbr;
|
||||
void *vbr = (void *)&gint_vbr;
|
||||
|
||||
/* Event handler entry points */
|
||||
void *exch_entry;
|
||||
void *inth_entry;
|
||||
void *inth_entry = isSH3() ? gint_inth_7705 : gint_inth_7305;
|
||||
|
||||
/* Size of the exception and TLB handlers */
|
||||
uint32_t exch_tlbh_size = (uint32_t)&gint_exch_tlbh_size;
|
||||
|
||||
/* First save the hardware configuration. This step is crucial because
|
||||
we don't want the system to find out about us directly manipulating
|
||||
|
@ -79,28 +83,12 @@ void gint_install(void)
|
|||
gint_ctx_save(&sys_ctx);
|
||||
|
||||
/* Load the event handler entry points into memory */
|
||||
/* TODO: Load an exception handler and a TLB miss handler */
|
||||
|
||||
if(isSH3())
|
||||
{
|
||||
extern void exch_entry_7705(void);
|
||||
extern void inth_entry_7705(void);
|
||||
exch_entry = exch_entry_7705;
|
||||
inth_entry = inth_entry_7705;
|
||||
}
|
||||
else
|
||||
{
|
||||
extern void exch_entry_7305(void);
|
||||
extern void inth_entry_7305(void);
|
||||
exch_entry = exch_entry_7305;
|
||||
inth_entry = inth_entry_7305;
|
||||
}
|
||||
|
||||
memcpy((void *)(vbr + 0x100), exch_entry, 32);
|
||||
memcpy((void *)(vbr + 0x600), inth_entry, 32);
|
||||
memcpy(vbr + 0x100, gint_exch_tlbh, exch_tlbh_size);
|
||||
memcpy(vbr + 0x400, gint_exch_tlbh, exch_tlbh_size);
|
||||
memcpy(vbr + 0x600, inth_entry, 32);
|
||||
|
||||
/* Time to switch VBR and roll! */
|
||||
system_vbr = gint_setvbr(vbr, lock);
|
||||
system_vbr = gint_setvbr((uint32_t)vbr, lock);
|
||||
}
|
||||
|
||||
/* unlock() - unlock interrupts, restoring system settings */
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <gint/drivers.h>
|
||||
#include <gint/gint.h>
|
||||
#include <gint/hardware.h>
|
||||
#include <gint/exc.h>
|
||||
|
||||
/* Symbols provided by the linker script. For sections:
|
||||
- l* represents the load address (source address in ROM)
|
||||
|
@ -135,7 +136,7 @@ int start(int isappli, int optnum)
|
|||
/* Cancel add-in execution if not all pages are mapped */
|
||||
if(rom < (uint32_t)&srom)
|
||||
{
|
||||
bootlog_unmapped(rom, (uint32_t)&srom);
|
||||
gint_exc(0x1040);
|
||||
while(1);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <gint/dma.h>
|
||||
#include <gint/drivers.h>
|
||||
#include <gint/clock.h>
|
||||
#include <gint/display.h>
|
||||
#include <gint/exc.h>
|
||||
|
||||
#define DMA SH7305_DMA
|
||||
#define INTC SH7305_INTC
|
||||
|
@ -150,6 +152,34 @@ void dma_transfer_noint(int channel, dma_size_t size, uint blocks,
|
|||
DMA.OR.NMIF = 0;
|
||||
}
|
||||
|
||||
//---
|
||||
// Address error handler
|
||||
//---
|
||||
|
||||
/* gint_dma_ae(): DMA Address Error handler */
|
||||
void gint_dma_ae(void)
|
||||
{
|
||||
gint_exc(0x1020);
|
||||
|
||||
#ifdef FXCG50
|
||||
dprint(6, 141, C_BLACK, C_NONE,
|
||||
"SAR0: %08x DAR0: %08x TCR0: %08x",
|
||||
DMA.DMA0.SAR, DMA.DMA0.DAR, DMA.DMA0.TCR);
|
||||
dprint(6, 154, C_BLACK, C_NONE,
|
||||
"CHCR0: %08x", DMA.DMA0.CHCR);
|
||||
dprint(6, 167, C_BLACK, C_NONE,
|
||||
"SAR1: %08x DAR1: %08x TCR1: %08x",
|
||||
DMA.DMA1.SAR, DMA.DMA1.DAR, DMA.DMA1.TCR);
|
||||
dprint(6, 180, C_BLACK, C_NONE,
|
||||
"CHCR1: %08x", DMA.DMA1.CHCR);
|
||||
dprint(6, 193, C_BLACK, C_NONE,
|
||||
"DMAOR: %04x", DMA.OR);
|
||||
dupdate_noint();
|
||||
#endif
|
||||
|
||||
while(1);
|
||||
}
|
||||
|
||||
//---
|
||||
// Initialization
|
||||
//---
|
||||
|
|
|
@ -46,4 +46,4 @@ _inth_dma_ae:
|
|||
|
||||
.zero 14
|
||||
|
||||
1: .long _dma_address_error
|
||||
1: .long _gint_dma_ae
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include <gint/dma.h>
|
||||
|
||||
/* dma_memset(): Fast memset for highly-aligned addresses */
|
||||
void dma_memset(void *dst, uint32_t l, size_t size)
|
||||
/* dma_memset(): Fast 32-aligned memset */
|
||||
void *dma_memset(void *dst, uint32_t l, size_t size)
|
||||
{
|
||||
/* TODO: Use a proper IL memory allocation scheme */
|
||||
uint32_t *IL = (void *)0xe5200000;
|
||||
for(int i = 0; i < 8; i++) IL[i] = l;
|
||||
|
||||
dma_transfer_noint(1, DMA_32B, size >> 5, IL, DMA_FIXED, dst, DMA_INC);
|
||||
return dst;
|
||||
}
|
||||
|
|
15
src/render/dprint.c
Normal file
15
src/render/dprint.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <gint/display.h>
|
||||
#include <gint/std/stdio.h>
|
||||
|
||||
/* dprint(): Display a formatted string */
|
||||
void dprint(int x, int y, int fg, int bg, char const *format, ...)
|
||||
{
|
||||
char str[256];
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(str, 256, format, args);
|
||||
va_end(args);
|
||||
|
||||
dtext(x, y, str, fg, bg);
|
||||
}
|
Loading…
Reference in a new issue