From a99bffe7f454d3c69fcfd039ea0db860c4078100 Mon Sep 17 00:00:00 2001 From: Lephe Date: Wed, 8 Jul 2020 20:01:58 +0200 Subject: [PATCH] iokbd keysc: space optimizations for SH3 * Reduce the keyboard queue size from 64 to 32, which is more than enough even for real-time games with multiple key presses. * Pack the driver_event_t structure of the keyboard driver to make it 4 bytes rather than 6 bytes. Combined with the previous item, this saves 256 bytes off the BSS section (which is 3% of the SH3's static RAM). * As part of a debugging attempt, updated the watchdog delay code in iokbd_delay() to make it usable in the current version of gint. * Restored port registers more aggressively in iokbd_row(). --- include/gint/keyboard.h | 4 ++-- src/core/mmu.c | 4 ++-- src/keysc/iokbd.c | 47 +++++++++++++++++++++++------------------ src/keysc/keysc.c | 8 +++---- 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/include/gint/keyboard.h b/include/gint/keyboard.h index e2426ec..48aaef6 100644 --- a/include/gint/keyboard.h +++ b/include/gint/keyboard.h @@ -117,12 +117,12 @@ enum /* Size of the buffer event queue, can be customized using gint's configure script before compiling the library. Better be a power of 2. */ #ifndef KEYBOARD_QUEUE_SIZE -#define KEYBOARD_QUEUE_SIZE 64 +#define KEYBOARD_QUEUE_SIZE 32 #endif /* Keyboard frequency analysis, must be at least 64 for the keyboard to work, and at most 32768 for the extra timer to support it. Better if a power of 2. - TODO: Add a configure or runtime setting for KEYBOARD_SCAN_FREQUENCY */ + TODO: Add a runtime setting for KEYBOARD_SCAN_FREQUENCY */ #ifndef KEYBOARD_SCAN_FREQUENCY #define KEYBOARD_SCAN_FREQUENCY 128 #endif diff --git a/src/core/mmu.c b/src/core/mmu.c index 289bf58..733861d 100644 --- a/src/core/mmu.c +++ b/src/core/mmu.c @@ -21,11 +21,11 @@ GINLINE const tlb_addr_t *tlb_addr(uint way, uint E) /* tlb_data() - get the P4 address of a TLB data entry */ GINLINE const tlb_data_t *tlb_data(uint way, uint E) { - uint32_t addr = 0xf3000000 | (E << 12) | (way << 8); + uint32_t addr = 0xf3000000 | (E << 12) | (way << 8); return (void *)addr; } -/* tlb_mapped_memort() - count amount of mapped memory */ +/* tlb_mapped_memory() - count amount of mapped memory */ void tlb_mapped_memory(uint32_t *p_rom, uint32_t *p_ram) { uint32_t rom = 0, ram = 0; diff --git a/src/keysc/iokbd.c b/src/keysc/iokbd.c index 3455fa5..fbadb4c 100644 --- a/src/keysc/iokbd.c +++ b/src/keysc/iokbd.c @@ -21,26 +21,30 @@ static void iokbd_delay(void) ); #if 0 - /* Watchdog delay version */ + uint8_t volatile *WTCSRr = (void *)0xffffff86; + uint16_t volatile *WTCSRw = (void *)0xffffff86; + uint16_t volatile *WTCNTw = (void *)0xffffff84; + + /* Watchdog delay version, each of the values between this and 0xff + account for 256 clock cycles on Pphi. This is roughly equivalent to + 2048 nop, lasting ~70 µs */ const int delay = 0xf4; /* Disable the watchdog timer interrupt and reset configuration */ - INTC.IPRB.BIT._WDT = 0; - WDT.WTCSR.WRITE = 0xa500; + *WTCSRw = 0xa500; /* Set the delay, input on Pphi / 256 and start counting */ - WDT.WTCNT.WRITE = 0x5a00 | (delay & 0xff); - WDT.WTCSR.WRITE = 0xa505; - WDT.WTCSR.WRITE = 0xa585; + *WTCNTw = 0x5a00 | (delay & 0xff); + *WTCSRw = 0xa505; + *WTCSRw = 0xa585; /* Actively wait for overflow, then clear the interrupt flag */ - while((WDT.WTCSR.READ.BYTE & 0x08) == 0); - WDT.WTCSR.WRITE = 0xa500 | (WDT.WTCSR.READ.BYTE & 0xf7); + while((*WTCSRr & 0x08) == 0); + *WTCSRw = 0xa500 | (*WTCSRr & 0xf7); /* Reset configuration, counter, and re-enabled interrupt */ - WDT.WTCSR.WRITE = 0xa500; - WDT.WTCSR.WRITE = 0x5a00; - INTC.IPRB.BIT._WDT = GINT_INTP_WDT; + *WTCSRw = 0xa500; + *WTCNTw = 0x5a00; #endif } @@ -52,6 +56,11 @@ uint8_t iokbd_row(int row) if((unsigned)row > 9) return 0x00; row ^= 1; + int orig_PBCR = PFC.PBCR; + int orig_PMCR = PFC.PMCR; + int orig_PBDR = PFC.PBDR; + int orig_PMDR = PFC.PMDR; + /* This will enable output (01) on @row, input (10) everywhere else */ uint16_t ctrl_mask = 0x0003 << ((row & 7) * 2); /* Enable output (0) on @row, input (1) everywhere else */ @@ -81,25 +90,23 @@ uint8_t iokbd_row(int row) /* Set @row to 0, everything else to 1 */ PFC.PBDR = 0xff; PFC.PMDR = PFC.PMDR & data_mask; + iokbd_delay(); } /* Now read the input data from the keyboard! */ uint8_t input = ~PFC.PADR; iokbd_delay(); - /* Reset the port configuration. I don't know why the intermediate step - is necessary; refer to SimLo's documentation. */ - PFC.PBCR = 0xaaaa; - PFC.PMCR = (PFC.PMCR & 0xff00) | 0x00aa; - iokbd_delay(); - PFC.PBCR = 0x5555; - PFC.PMCR = (PFC.PMCR & 0xff00) | 0x0055; + /* Reset the port configuration */ + PFC.PBCR = orig_PBCR; + PFC.PMCR = orig_PMCR; iokbd_delay(); /* Now also reset the data registers. This was forgotten from SimLo's CheckKeyRow() and blows up everything. */ - PFC.PBDR = 0x00; - PFC.PMDR = PFC.PMDR & 0xf0; + PFC.PBDR = orig_PBDR; + PFC.PMDR = orig_PMDR; + iokbd_delay(); return input; } diff --git a/src/keysc/keysc.c b/src/keysc/keysc.c index 8e8a678..2802a2a 100644 --- a/src/keysc/keysc.c +++ b/src/keysc/keysc.c @@ -38,9 +38,9 @@ GDATA static uint8_t current[12] = { 0 }; typedef struct { uint16_t time; /* Locally unique time identifier */ - uint8_t row; /* Row number */ uint8_t changed; /* Keys that changed state */ - uint8_t kind; /* Type of change, either KEYEV_DOWN or KEYEV_UP */ + uint8_t row :4; /* Row number */ + uint8_t kind :4; /* Type of change, either KEYEV_DOWN or KEYEV_UP */ } driver_event_t; @@ -103,7 +103,7 @@ static void keysc_frame(void) if(!diff) continue; /* Update internal status if the event could be pushed */ - driver_event_t ev = { time, row, diff, KEYEV_UP }; + driver_event_t ev = { time, diff, row, KEYEV_UP }; if(!buffer_push(ev)) state[row] &= scan[row]; } for(int row = 0; row < 12; row++) @@ -111,7 +111,7 @@ static void keysc_frame(void) int diff = scan[row] & ~state[row]; if(!diff) continue; - driver_event_t ev = { time, row, diff, KEYEV_DOWN }; + driver_event_t ev = { time, diff, row, KEYEV_DOWN }; if(!buffer_push(ev)) state[row] |= scan[row]; } }