Skip to content

Commit

Permalink
Optimise the drive-select ISR. It was too slow on a Vampire-accelerat…
Browse files Browse the repository at this point in the history
…ed Amiga.

1. Optimise the ISR functions at level -Ofast
2. Restructuire the main C routine a little
3. Provide a faster methoid for detecting dma_rd->state == DMA_active

Refs #650
  • Loading branch information
keirf committed May 27, 2022
1 parent ea44c1d commit 328f642
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 17 deletions.
3 changes: 3 additions & 0 deletions src/floppy_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ struct exti_irq {

#if defined(QUICKDISK)
#include "gotek/quickdisk.c"
#define dma_rd_set_active(x) ((void)(x))
#else
#include "gotek/floppy.c"
#endif
Expand Down Expand Up @@ -432,6 +433,7 @@ static void rdata_stop(void)

/* Ok we're now stopping DMA activity. */
dma_rd->state = DMA_stopping;
dma_rd_set_active(FALSE);

/* If DMA was not yet active, don't need to touch peripherals. */
if (prev_state != DMA_active)
Expand Down Expand Up @@ -460,6 +462,7 @@ static void rdata_start(void)
goto out;

dma_rd->state = DMA_active;
dma_rd_set_active(TRUE);

/* Start timer. */
tim_rdata->egr = TIM_EGR_UG;
Expand Down
47 changes: 30 additions & 17 deletions src/gotek/floppy.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,18 @@ static const struct exti_irq exti_irqs[] = {
/* Subset of output pins which are active (O_TRUE). */
extern uint32_t gpio_out_active;

/* Abuse gpio_out_active:PA11 to indicate that read DMA is active. This is
* safe because PA11 is configured for USB, so GPIO level has no effect.
* This saves some memory loads in the critical SELA IRQ handler. */
#define GPIO_OUT_DMA_RD_ACTIVE (16+11)

/* GPIO register to either assert or deassert active output pins. */
extern uint32_t gpiob_setreset;

/* This bitband address is used to atomically update GPIO_OUT_DMA_RD_ACTIVE */
static volatile uint32_t *p_dma_rd_active;
#define dma_rd_set_active(x) (*p_dma_rd_active = (x))

bool_t floppy_ribbon_is_reversed(void)
{
time_t t_start = time_now();
Expand All @@ -86,8 +95,16 @@ bool_t floppy_ribbon_is_reversed(void)
return FALSE;
}

static uint32_t *get_bitband(void *ram_addr, unsigned int bit)
{
uint32_t byte = (uint32_t)ram_addr - 0x20000000u;
return (uint32_t *)(0x22000000u + (byte * 32) + (bit * 4));
}

static void board_floppy_init(void)
{
p_dma_rd_active = get_bitband(&gpio_out_active, GPIO_OUT_DMA_RD_ACTIVE);

#if MCU == STM32F105

#define change_pin_mode(gpio, pin, mode) \
Expand Down Expand Up @@ -183,9 +200,11 @@ void IRQ_SELA_changed(void) {
}

static void Amiga_HD_ID(uint32_t _gpio_out_active, uint32_t _gpiob_setreset)
__attribute__((used)) __attribute__((section(".ramfuncs")));
__attribute__((used)) __attribute__((section(".ramfuncs")))
__attribute__((optimize("Ofast")));
static void _IRQ_SELA_changed(uint32_t _gpio_out_active)
__attribute__((used)) __attribute__((section(".ramfuncs")));
__attribute__((used)) __attribute__((section(".ramfuncs")))
__attribute__((optimize("Ofast")));

/* Intermediate SELA-changed handler for generating the Amiga HD RDY signal. */
static void Amiga_HD_ID(uint32_t _gpio_out_active, uint32_t _gpiob_setreset)
Expand All @@ -203,36 +222,30 @@ static void Amiga_HD_ID(uint32_t _gpio_out_active, uint32_t _gpiob_setreset)
* speculative entry point for the next interrupt. */
static void _IRQ_SELA_changed(uint32_t _gpio_out_active)
{
/* Clear SELA-changed flag. */
/* Latch SELA. */
exti->pr = m(pin_sel0);
drive.sel = !(gpioa->idr & m(pin_sel0));

if (!(gpioa->idr & m(pin_sel0))) {
if (drive.sel) {
/* SELA is asserted (this drive is selected).
* Immediately re-enable all our asserted outputs. */
gpiob->brr = _gpio_out_active & 0xffff;
gpioa->brr = _gpio_out_active >> 16;
/* Set pin_rdata as timer output (AFO_bus). */
if (dma_rd && (dma_rd->state == DMA_active))
if (_gpio_out_active & m(GPIO_OUT_DMA_RD_ACTIVE))
change_pin_mode(gpio_data, pin_rdata, AFO_bus);
/* Let main code know it can drive the bus until further notice. */
drive.sel = 1;
/* Speculate that, on next interrupt, SELA is deasserted. */
*(uint8_t *)&gpiob_setreset = (uint8_t)(uint32_t)&gpiob->bsrr;
} else {
/* SELA is deasserted (this drive is not selected).
* Relinquish the bus by disabling all our asserted outputs. */
gpiob->bsrr = _gpio_out_active & 0xffff;
gpioa->bsrr = _gpio_out_active >> 16;
/* Set pin_rdata as quiescent (GPO_bus). */
if (dma_rd && (dma_rd->state == DMA_active))
change_pin_mode(gpio_data, pin_rdata, GPO_bus);
/* Tell main code to leave the bus alone. */
drive.sel = 0;
}

/* Set up the speculative fast path for the next interrupt. */
if (drive.sel)
*(uint8_t *)&gpiob_setreset = (uint8_t)(uint32_t)&gpiob->bsrr;
else
change_pin_mode(gpio_data, pin_rdata, GPO_bus);
/* Speculate that, on next interrupt, SELA is asserted. */
*(uint8_t *)&gpiob_setreset = (uint8_t)(uint32_t)&gpiob->brr;
}
}

/* Update the SELA handler. Used for switching in the Amiga HD-ID "magic".
Expand Down

0 comments on commit 328f642

Please sign in to comment.