display: add a dupdate_noint() for exceptions handlers

This commit is contained in:
lephe 2019-07-04 11:46:26 -04:00
parent b0ede1d15d
commit f8d69dd56a
6 changed files with 93 additions and 17 deletions

View File

@ -152,7 +152,7 @@ typedef struct
gint's default font is used.
On fx9860g, the default font is a 5x7 font very close to the system's.
On fxcg50, the default font is an original 10x12 font.
On fxcg50, the default font is an original 8x9 font.
@font Font to use for subsequent text rendering calls */
void dfont(font_t const * font);
@ -192,10 +192,22 @@ void dsize(const char *str, font_t const * font, int *w, int *h);
@str String to display
@fg Text color
fx9860g: white, black, none, invert
fxcg50: Any R5G6B6 color, or [color_none]
fxcg50: Any R5G6B6 color, or C_NONE
@bg Background color
fx9860g: white, black, none, invert
fxcg50: Any R5G6B5 color, or [color_none] */
fxcg50: Any R5G6B5 color, or C_NONE */
void dtext(int x, int y, const char *str, int fg, int bg);
//---
// Advanced functions
//---
/* dupdate_noint() - Push VRAM to the display without interrupts
This function does exactly as dupdate(), but does not use interrupts and
always returns when the transfer is finished. It actively waits for the end
of the transfer and is thus bad for any general-purpose use. In fact, it is
only needed to display panic messages in exception handlers. Don't use it
unless you know precisely why you're doing it. */
void dupdate_noint(void);
#endif /* GINT_DISPLAY */

View File

@ -42,7 +42,6 @@ typedef enum
} dma_address_t;
/* dma_transfer() - Start a data transfer on channel 0
This function returns just when the transfer starts. The transfer will end
later on and the DMA will be stopped by an interrupt. Call
dma_transfer_wait() if you need to wait for the transfer to finish. Don't
@ -59,11 +58,21 @@ void dma_transfer(dma_size_t size, uint length,
void *dst, dma_address_t dst_mode);
/* dma_transfer_wait() - Wait for a transfer on channel 0 to finish
You should call this function when you need to transfer to be complete
before continuing execution. If you are sure that the transfer is finished,
this is not necessary (the only way to know is to look at the DMA registers
or record interrupts). */
void dma_transfer_wait(void);
/* dma_transfer_noint() - Perform a data transfer without interrupts
This function performs a transfer much like dma_transfer(), but doesn't use
interrupts and *actively waits* for the transfer to finish, returning when
it's finished. Don't call dma_transfer_wait() after using this function.
Not using interrupts is a bad design idea for a majority of programs, and is
only ever needed to display panic messages inside exception handlers. */
void dma_transfer_noint(dma_size_t size, uint blocks,
void *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode);
#endif /* GINT_DMA */

View File

@ -15,13 +15,17 @@
// Driver interface
//---
/* dma_transfer() - Perform a data transfer */
void dma_transfer(dma_size_t size, uint blocks,
/* dma_setup() - Setup the DMA in interrupt or no-interrupt mode.
The first parameters are as for dma_transfer() and dma_transfer_noint(). The
last parameter indicates whether interrupts should be used.
Returns non-zero if the DMA is busy or a configuration error occurs. */
static int dma_setup(dma_size_t size, uint blocks,
void *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode)
void *dst, dma_address_t dst_mode,
int interrupts)
{
/* Safety guard: only start a transfer if there's not one running */
if(DMA.DMA0.CHCR.DE) return;
if(DMA.DMA0.CHCR.DE) return 1;
/* Disable DMA0 and disable the master DMA switch */
DMA.DMA0.CHCR.DE = 0;
@ -41,7 +45,7 @@ void dma_transfer(dma_size_t size, uint blocks,
DMA.DMA0.CHCR.TS_10 = (size & 3);
DMA.DMA0.CHCR.DM = dst_mode;
DMA.DMA0.CHCR.SM = src_mode;
DMA.DMA0.CHCR.IE = 1;
DMA.DMA0.CHCR.IE = !!interrupts;
/* Prepare DMAOR by enabling the master switch and clearing the
blocking flags. */
@ -49,6 +53,16 @@ void dma_transfer(dma_size_t size, uint blocks,
DMA.OR.AE = 0;
DMA.OR.NMIF = 0;
return 0;
}
/* dma_transfer() - Perform a data transfer */
void dma_transfer(dma_size_t size, uint blocks,
void *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode)
{
if(dma_setup(size, blocks, src, src_mode, dst, dst_mode, 1)) return;
/* Enable channel 0, starting the DMA transfer. */
DMA.DMA0.CHCR.DE = 1;
}
@ -60,6 +74,30 @@ void dma_transfer_wait(void)
while(DMA.OR.DME) sleep();
}
/* dma_transfer_noint() - Perform a data transfer without interruptions */
void dma_transfer_noint(dma_size_t size, uint blocks,
void *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode)
{
if(dma_setup(size, blocks, src, src_mode, dst, dst_mode, 0)) return;
/* Enable channel 0, starting the DMA transfer. */
DMA.DMA0.CHCR.DE = 1;
/* Actively wait until the transfer is finished */
while(!DMA.DMA0.CHCR.TE);
/* Disable the channel and clear the TE flag. Disable the channel first
as clearing the TE flag will allow the transfer to restart */
DMA.DMA0.CHCR.DE = 0;
DMA.DMA0.CHCR.TE = 0;
/* Clear the AE and NMIF status flags and cut the master switch */
DMA.OR.DME = 0;
DMA.OR.AE = 0;
DMA.OR.NMIF = 0;
}
//---
// Initialization
//---

View File

@ -202,9 +202,8 @@ void r61524_win_set(uint16_t HSA, uint16_t HEA, uint16_t VSA, uint16_t VEA)
/* TODO: r61524: update, backlight, brightness, gamma */
void r61524_display(uint16_t *vram, int start, int height)
void r61524_display(uint16_t *vram, int start, int height, int interrupts)
{
/* Move the window to the desired region, then select address 0 */
r61524_win_set(0, 395, start, start + height - 1);
select(ram_address_horizontal);
@ -224,9 +223,15 @@ void r61524_display(uint16_t *vram, int start, int height)
int blocks = 99 * (height >> 2);
/* Now roll! */
dma_transfer(DMA_32B, blocks, src, DMA_INC, dst, DMA_FIXED);
/* Wait for any previous DMA transfer to finish */
dma_transfer_wait();
if(interrupts)
{
/* Usa a normal, interrupt-based transfer */
dma_transfer(DMA_32B, blocks, src, DMA_INC, dst, DMA_FIXED);
/* Wait for it to finish */
/* TODO: Allow r61524_display() to return early */
dma_transfer_wait();
}
else dma_transfer_noint(DMA_32B, blocks, src, DMA_INC, dst, DMA_FIXED);
}
//---

View File

@ -2,8 +2,14 @@
#include <gint/display.h>
//#include <gint/drivers/r61524.h>
/* dupdate() - push the video RAM to the display driver */
/* dupdate() - Push the video RAM to the display driver */
void dupdate(void)
{
r61524_display(vram, 0, 224);
r61524_display(vram, 0, 224, 1);
}
/* dupdate_noint() - Push VRAM to the display without interrupts */
void dupdate_noint(void)
{
r61524_display(vram, 0, 224, 0);
}

View File

@ -13,3 +13,9 @@ void dupdate(void)
{
t6k11_display(vram, 0, 64, 16);
}
/* dupdate_noint() - Push VRAM to the display without interrupts */
void dupdate_noint(void)
{
dupdate();
}