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:
lephe 2019-09-03 22:15:00 +02:00
parent 6d54a5fe0a
commit e1aca8d89b
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
18 changed files with 226 additions and 76 deletions

7
TODO
View file

@ -1,7 +1,7 @@
Crucial, missing things. Crucial, missing things.
! core: the four basic memory functions ! core: the four basic memory functions
! core: build an exception handler and a TLB miss handler ! core: gint_switch() with driver contexts on stack and arbitrary code
! core: gint_switch() (driver contexts on stack; arbitrary code?) ! core: use gint_switch() to handle TLB misses
! bopti: fxcg50 version ! bopti: fxcg50 version
! syscalls: fxcg50 BFile calls ! syscalls: fxcg50 BFile calls
@ -10,10 +10,11 @@ Tests to run.
* topti: all charsets * topti: all charsets
Complementary elements on existing code. 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 * render: get rid of GINT_NEED_VRAM and #define vram gint_vram if you need
* dma: dma_memcpy() and dma_memset(), possibly requiring alignment * 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: 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 * topti: support Unicode fonts
* hardware: fill in the HWMEM_FITTLB flag * hardware: fill in the HWMEM_FITTLB flag
* keyboard: think of extended functions * keyboard: think of extended functions

View file

@ -55,6 +55,10 @@ SECTIONS
} > rom } > rom
.text : { .text : {
_gint_exch_tlbh_start = . ;
*(.gint.exch_tlbh);
_gint_exch_tlbh_size = ABSOLUTE(. - _gint_exch_tlbh_start);
*(.text .text.*) *(.text .text.*)
*(C P) *(C P)
} > rom } > rom

View file

@ -49,6 +49,10 @@ SECTIONS
*(.dtors .dtors.*) *(.dtors .dtors.*)
_etors = . ; _etors = . ;
_gint_exch_tlbh_start = . ;
*(.gint.exch_tlbh);
_gint_exch_tlbh_size = ABSOLUTE(. - _gint_exch_tlbh_start);
*(.text .text.*) *(.text .text.*)
} > rom } > rom

View file

@ -11,12 +11,6 @@
Called when RAM sections have been wiped and copied */ Called when RAM sections have been wiped and copied */
void bootlog_loaded(void); 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 /* bootlog_mapped() - ROM mapping stage
Called after all ROM pages have been traversed. All of them may not have Called after all ROM pages have been traversed. All of them may not have
been mapped. been mapped.
@ -37,7 +31,6 @@ void bootlog_driver_summary(void);
/* All these functions are enabled only if GINT_BOOT_LOG is defined */ /* All these functions are enabled only if GINT_BOOT_LOG is defined */
#ifndef GINT_BOOT_LOG #ifndef GINT_BOOT_LOG
#define bootlog_loaded(...) #define bootlog_loaded(...)
#define bootlog_unmapped(...)
#define bootlog_mapped(...) #define bootlog_mapped(...)
#define bootlog_kernel(...) #define bootlog_kernel(...)
#define bootlog_driver(...) #define bootlog_driver(...)

View file

@ -20,4 +20,12 @@
Returns the previous VBR address. */ Returns the previous VBR address. */
uint32_t gint_setvbr(uint32_t vbr, void (*configure)(void)); 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 */ #endif /* GINT_CORE_SETUP */

View file

@ -199,6 +199,11 @@ void dsize(const char *str, font_t const * font, int *w, int *h);
fxcg50: Any R5G6B5 color, or C_NONE */ fxcg50: Any R5G6B5 color, or C_NONE */
void dtext(int x, int y, const char *str, int fg, int bg); 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) // Image rendering (bopti)
//--- //---

View file

@ -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 const *src, dma_address_t src_mode,
void *dst, dma_address_t dst_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 */ #endif /* GINT_DMA */

21
include/gint/exc.h Normal file
View 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 */

View file

@ -117,14 +117,6 @@ void bootlog_mapped(int rom, GUNUSED int ram)
dupdate(); 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 */ /* bootlog_kernel() - gint loading stage */
void bootlog_kernel(void) void bootlog_kernel(void)
{ {

View file

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

View file

@ -5,10 +5,10 @@
** blocks depending on its configuration. ** blocks depending on its configuration.
*/ */
.global _inth_entry_7305 .global _gint_inth_7305
#ifdef FX9860G #ifdef FX9860G
.global _inth_entry_7705 .global _gint_inth_7705
#endif #endif
.section .gint.blocks, "ax" .section .gint.blocks, "ax"
@ -36,7 +36,7 @@
/* SH7305-TYPE DEBUG INTERRUPT HANDLER - 26 BYTES */ /* SH7305-TYPE DEBUG INTERRUPT HANDLER - 26 BYTES */
#if 0 #if 0
_inth_entry_7305: _gint_inth_7305:
mov.l 1f, r0 mov.l 1f, r0
mov.l @r0, r4 mov.l @r0, r4
@ -56,7 +56,7 @@ _inth_entry_7305:
/* SH7305-TYPE INTERRUPT HANDLER ENTRY - 20 BYTES */ /* SH7305-TYPE INTERRUPT HANDLER ENTRY - 20 BYTES */
_inth_entry_7305: _gint_inth_7305:
/* Get the event code from the INTEVT register */ /* Get the event code from the INTEVT register */
mov.l 1f, r0 mov.l 1f, r0
mov.l @r0, r0 mov.l @r0, r0
@ -78,7 +78,7 @@ _inth_entry_7305:
/* SH7705-TYPE INTERRUT HANDLER ENTRY - 32 BYTES */ /* SH7705-TYPE INTERRUT HANDLER ENTRY - 32 BYTES */
_inth_entry_7705: _gint_inth_7705:
/* Get the event code from the INTEVT2 register */ /* Get the event code from the INTEVT2 register */
mov.l 1f, r0 mov.l 1f, r0
mov.l @r0, r0 /* r0 = old_code */ mov.l @r0, r0 /* r0 = old_code */

View file

@ -13,6 +13,8 @@
extern char gint_vbr; extern char gint_vbr;
/* System's VBR address */ /* System's VBR address */
GBSS static uint32_t system_vbr; GBSS static uint32_t system_vbr;
/* Size of exception and TLB handler */
extern char gint_exch_tlbh_size;
/* Driver table */ /* Driver table */
extern gint_driver_t bdrv, edrv; extern gint_driver_t bdrv, edrv;
@ -67,11 +69,13 @@ static void lock(void)
void gint_install(void) void gint_install(void)
{ {
/* VBR address, provided by the linker script */ /* VBR address, provided by the linker script */
uint32_t vbr = (uint32_t)&gint_vbr; void *vbr = (void *)&gint_vbr;
/* Event handler entry points */ /* Event handler entry points */
void *exch_entry; void *inth_entry = isSH3() ? gint_inth_7705 : gint_inth_7305;
void *inth_entry;
/* 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 /* First save the hardware configuration. This step is crucial because
we don't want the system to find out about us directly manipulating 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); gint_ctx_save(&sys_ctx);
/* Load the event handler entry points into memory */ /* Load the event handler entry points into memory */
/* TODO: Load an exception handler and a TLB miss handler */ memcpy(vbr + 0x100, gint_exch_tlbh, exch_tlbh_size);
memcpy(vbr + 0x400, gint_exch_tlbh, exch_tlbh_size);
if(isSH3()) memcpy(vbr + 0x600, inth_entry, 32);
{
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);
/* Time to switch VBR and roll! */ /* 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 */ /* unlock() - unlock interrupts, restoring system settings */

View file

@ -9,6 +9,7 @@
#include <gint/drivers.h> #include <gint/drivers.h>
#include <gint/gint.h> #include <gint/gint.h>
#include <gint/hardware.h> #include <gint/hardware.h>
#include <gint/exc.h>
/* Symbols provided by the linker script. For sections: /* Symbols provided by the linker script. For sections:
- l* represents the load address (source address in ROM) - 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 */ /* Cancel add-in execution if not all pages are mapped */
if(rom < (uint32_t)&srom) if(rom < (uint32_t)&srom)
{ {
bootlog_unmapped(rom, (uint32_t)&srom); gint_exc(0x1040);
while(1); while(1);
return 1; return 1;
} }

View file

@ -6,6 +6,8 @@
#include <gint/dma.h> #include <gint/dma.h>
#include <gint/drivers.h> #include <gint/drivers.h>
#include <gint/clock.h> #include <gint/clock.h>
#include <gint/display.h>
#include <gint/exc.h>
#define DMA SH7305_DMA #define DMA SH7305_DMA
#define INTC SH7305_INTC #define INTC SH7305_INTC
@ -150,6 +152,34 @@ void dma_transfer_noint(int channel, dma_size_t size, uint blocks,
DMA.OR.NMIF = 0; 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 // Initialization
//--- //---

View file

@ -46,4 +46,4 @@ _inth_dma_ae:
.zero 14 .zero 14
1: .long _dma_address_error 1: .long _gint_dma_ae

View file

@ -1,11 +1,12 @@
#include <gint/dma.h> #include <gint/dma.h>
/* dma_memset(): Fast memset for highly-aligned addresses */ /* dma_memset(): Fast 32-aligned memset */
void dma_memset(void *dst, uint32_t l, size_t size) void *dma_memset(void *dst, uint32_t l, size_t size)
{ {
/* TODO: Use a proper IL memory allocation scheme */ /* TODO: Use a proper IL memory allocation scheme */
uint32_t *IL = (void *)0xe5200000; uint32_t *IL = (void *)0xe5200000;
for(int i = 0; i < 8; i++) IL[i] = l; for(int i = 0; i < 8; i++) IL[i] = l;
dma_transfer_noint(1, DMA_32B, size >> 5, IL, DMA_FIXED, dst, DMA_INC); dma_transfer_noint(1, DMA_32B, size >> 5, IL, DMA_FIXED, dst, DMA_INC);
return dst;
} }

15
src/render/dprint.c Normal file
View 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);
}