diff --git a/TODO b/TODO index 95da967..506b871 100644 --- a/TODO +++ b/TODO @@ -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 diff --git a/src/core/inth.S b/src/core/inth.S index 9f9bd0d..4df2410 100644 --- a/src/core/inth.S +++ b/src/core/inth.S @@ -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 diff --git a/src/core/kernel.c b/src/core/kernel.c index b4014c5..43b85bf 100644 --- a/src/core/kernel.c +++ b/src/core/kernel.c @@ -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); } diff --git a/src/tmu/tmu.c b/src/tmu/tmu.c index 24c2d41..0de8ad4 100644 --- a/src/tmu/tmu.c +++ b/src/tmu/tmu.c @@ -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;