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
Extensions on existing code:
* tmu: make interrupt handlers more elegant
* bopti: try to display fullscreen images with TLB access + DMA on fxcg50
* gray: double-buffer gray settings and unify d* with g*
* topti: support unicode fonts

View file

@ -20,9 +20,12 @@
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
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
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
the MPU each time an interrupt is handled;
- However, the blocks can only rely on relative displacements or cross-
references if their relative order is known and heeded for. A good example
of this is the timer driver. Please be careful. */
references if their relative order is known and heeded for both on SH4 and
SH3. A good example of this is the timer driver. Please be careful. */
/* SH7305-TYPE DEBUG INTERRUPT HANDLER - 26 BYTES */
@ -76,10 +79,11 @@ _gint_inth_7305:
sub r1, r0
/* Add the distance to the first entry and jump as a subroutine */
add #40, r0
add #(.first_entry - .jump_over), r0
bsrf r0
nop
.jump_over:
/* Restore caller-saved registers */
lds.l @r15+, macl
lds.l @r15+, mach
@ -91,10 +95,11 @@ _gint_inth_7305:
.zero 24
1: .long 0xff000028
.first_entry:
#ifdef FX9860G
/* SH7705-TYPE INTERRUT HANDLER ENTRY - 52 BYTES */
/* SH7705-TYPE INTERRUT HANDLER ENTRY - 56 BYTES */
_gint_inth_7705:
/* Save caller-saved registers as before */
@ -107,18 +112,22 @@ _gint_inth_7705:
mov.l 1f, r0
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 #-5, r3
shld r3, r0 /* r0 = old_code >> 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
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 */
add #32, r0
bsrf r0
/* Start at VBR + 0x200 and jump! */
stc vbr, r1
add r1, r0
jsr @r0
nop
/* Restore saved registers */
@ -130,7 +139,7 @@ _gint_inth_7705:
rte
nop
.zero 12
.zero 8
1: .long 0xa4000000 /* INTEVT2 register */
2: .long _inth_remap
@ -148,13 +157,15 @@ _gint_inth_7705:
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
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:
.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 */
void *gint_inthandler(int event_code, const void *handler, size_t size)
{
int offset;
void *dest;
/* Normalize the event code */
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 */
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 */
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);
}

View file

@ -378,7 +378,7 @@ static void init(void)
/* On SH3, the ETMU handler is not at an offset of 0x840 (event
code 0xc40) but at an offset of 0xc0 */
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;
*data_id = i;