kernel: compact VBR even more on SH3

This change moves interrupt handler from VBR + 0x640 to VBR + 0x200, in
the gap between the exception and TLB miss handlers.

This new scheme is not limited to VBR+0x200 .. VBR+0x400 as new large
block numbers can be used to jump over the TLB miss handler and the
interrupt handler entry points.
This commit is contained in:
Lephe 2020-07-10 13:07:12 +02:00
parent 2b1f408cb4
commit 0aceb6f93e
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
4 changed files with 35 additions and 23 deletions

1
TODO
View file

@ -6,6 +6,7 @@ Issues:
* #10 support fx-CG 20 * #10 support fx-CG 20
Extensions on existing code: Extensions on existing code:
* tmu: make interrupt handlers more elegant
* bopti: try to display fullscreen images with TLB access + DMA on fxcg50 * bopti: try to display fullscreen images with TLB access + DMA on fxcg50
* gray: double-buffer gray settings and unify d* with g* * gray: double-buffer gray settings and unify d* with g*
* topti: support unicode fonts * topti: support unicode fonts

View file

@ -20,9 +20,12 @@
The .gint.blocks section consists of blocks of 32 bytes intended for mapping The .gint.blocks section consists of blocks of 32 bytes intended for mapping
into the VBR space (exception, TLB miss, and interrupt handlers). Each event into the VBR space (exception, TLB miss, and interrupt handlers). Each event
gate is linearly associated with a block number: gate is linearly associated with a block number on SH4:
block_id = (event_code - 0x380) / 0x20 block_id = (event_code - 0x3c0) / 0x20
and associated with a compact block number on SH3 through a table (to ensure
that blocks are consecutive in memory).
This file provides entry points; drivers may provide their own interrupt This file provides entry points; drivers may provide their own interrupt
handlers, and store them in the .gint.blocks section for consistency. They handlers, and store them in the .gint.blocks section for consistency. They
@ -32,8 +35,8 @@
- It is possible to map MPU-specific blocks at runtime, to avoid checking - It is possible to map MPU-specific blocks at runtime, to avoid checking
the MPU each time an interrupt is handled; the MPU each time an interrupt is handled;
- However, the blocks can only rely on relative displacements or cross- - However, the blocks can only rely on relative displacements or cross-
references if their relative order is known and heeded for. A good example references if their relative order is known and heeded for both on SH4 and
of this is the timer driver. Please be careful. */ SH3. A good example of this is the timer driver. Please be careful. */
/* SH7305-TYPE DEBUG INTERRUPT HANDLER - 26 BYTES */ /* SH7305-TYPE DEBUG INTERRUPT HANDLER - 26 BYTES */
@ -76,10 +79,11 @@ _gint_inth_7305:
sub r1, r0 sub r1, r0
/* Add the distance to the first entry and jump as a subroutine */ /* Add the distance to the first entry and jump as a subroutine */
add #40, r0 add #(.first_entry - .jump_over), r0
bsrf r0 bsrf r0
nop nop
.jump_over:
/* Restore caller-saved registers */ /* Restore caller-saved registers */
lds.l @r15+, macl lds.l @r15+, macl
lds.l @r15+, mach lds.l @r15+, mach
@ -91,10 +95,11 @@ _gint_inth_7305:
.zero 24 .zero 24
1: .long 0xff000028 1: .long 0xff000028
.first_entry:
#ifdef FX9860G #ifdef FX9860G
/* SH7705-TYPE INTERRUT HANDLER ENTRY - 52 BYTES */ /* SH7705-TYPE INTERRUT HANDLER ENTRY - 56 BYTES */
_gint_inth_7705: _gint_inth_7705:
/* Save caller-saved registers as before */ /* Save caller-saved registers as before */
@ -107,18 +112,22 @@ _gint_inth_7705:
mov.l 1f, r0 mov.l 1f, r0
mov.l @r0, r0 /* r0 = old_code */ mov.l @r0, r0 /* r0 = old_code */
/* Translate the event code to SH4 format */ /* Translate the event code to compact format. The compact format is
laid out in a way that leaves no gap in the VBR space. Additionally,
gates are installed starting at VBR + 0x200 to save space. */
mov.l 2f, r2 mov.l 2f, r2
mov #-5, r3 mov #-5, r3
shld r3, r0 /* r0 = old_code >> 5 */ shld r3, r0 /* r0 = old_code >> 5 */
add #-32, r0 /* r0 = (old_code - 0x400) >> 5 */ add #-32, r0 /* r0 = (old_code - 0x400) >> 5 */
mov.b @(r0, r2), r0 /* r0 = (new_code - 0x400) >> 5 */ mov.b @(r0, r2), r0 /* r0 = gate_number */
add #16, r0 /* r0 = (0x200 + gate_number * 0x20) >> 5 */
mov #5, r3 mov #5, r3
shld r3, r0 /* r0 = new_code - 0x400 */ shld r3, r0 /* r0 = 0x200 + gate_number * 0x20 */
/* Add the distance between nop and the first entry, and jump */ /* Start at VBR + 0x200 and jump! */
add #32, r0 stc vbr, r1
bsrf r0 add r1, r0
jsr @r0
nop nop
/* Restore saved registers */ /* Restore saved registers */
@ -130,7 +139,7 @@ _gint_inth_7705:
rte rte
nop nop
.zero 12 .zero 8
1: .long 0xa4000000 /* INTEVT2 register */ 1: .long 0xa4000000 /* INTEVT2 register */
2: .long _inth_remap 2: .long _inth_remap
@ -148,13 +157,15 @@ _gint_inth_7705:
VBR offset SH3 events Description VBR offset SH3 events Description
---------------------------------------------------------------- ----------------------------------------------------------------
0x200 400 420 440 --- TMU0, TMU1, TMU2 and a helper
0x280 f00 --- --- --- ETMU0, ETMU1, ETMU2 and a helper
0x300 4a0 --- RTC Periodic Interrupt and a helper
----------------------------------------------------------------
0x600 --- --- Entry gate 0x600 --- --- Entry gate
0x640 400 420 440 --- TMU0, TMU1, TMU2 and a helper
0x6c0 f00 --- --- --- ETMU0, ETMU1, ETMU2 and a helper
0x740 4a0 --- RTC Periodic Interrupt and a helper
---------------------------------------------------------------- ----------------------------------------------------------------
This represents 12 gates so the VBR space ends at VBR + 0x780. */ There is space for 16 gates at VBR + 0x200 so the VBR currently ends after
the interrupt entry gate at VBR + 0x640. */
_inth_remap: _inth_remap:
.byte 0, 1, 2, 0xff, 0xff, 8, 0xff, 0xff .byte 0, 1, 2, 0xff, 0xff, 8, 0xff, 0xff

View file

@ -162,7 +162,7 @@ static const uint16_t sh3_vbr_map[] = {
/* gint_inthandler(): Install interrupt handlers */ /* gint_inthandler(): Install interrupt handlers */
void *gint_inthandler(int event_code, const void *handler, size_t size) void *gint_inthandler(int event_code, const void *handler, size_t size)
{ {
int offset; void *dest;
/* Normalize the event code */ /* Normalize the event code */
if(event_code < 0x400) return NULL; if(event_code < 0x400) return NULL;
@ -183,16 +183,16 @@ void *gint_inthandler(int event_code, const void *handler, size_t size)
ie. the compact VBR scheme does not support this code */ ie. the compact VBR scheme does not support this code */
if(!sh3_vbr_map[index]) return NULL; if(!sh3_vbr_map[index]) return NULL;
offset = index * 0x20; /* 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 */ /* On SH4, just use the code as offset */
else else
{ {
offset = event_code - 0x400; /* 0x40 is the size of the entry gate */
dest = (void *)gint_ctx.VBR + 0x640 + (event_code - 0x400);
} }
/* 0x40 is the size of the entry gate */
void *dest = (void *)gint_ctx.VBR + 0x600 + 0x40 + offset;
return memcpy(dest, handler, size); return memcpy(dest, handler, size);
} }

View file

@ -378,7 +378,7 @@ static void init(void)
/* On SH3, the ETMU handler is not at an offset of 0x840 (event /* On SH3, the ETMU handler is not at an offset of 0x840 (event
code 0xc40) but at an offset of 0xc0 */ code 0xc40) but at an offset of 0xc0 */
uint32_t *etmu_offset = h + 16; uint32_t *etmu_offset = h + 16;
if(isSH3()) *etmu_offset = *etmu_offset - 0x840 + 0xc0; if(isSH3()) *etmu_offset = *etmu_offset - 0xe80 + 0x2c0;
uint32_t *data_id = h + 20; uint32_t *data_id = h + 20;
*data_id = i; *data_id = i;