Screen address change now handled entirely in C (handler_gpt0/

This commit is contained in:
Markus Fröschle
2014-09-19 17:41:00 +00:00
parent d5359c4b95
commit 44acce1258
3 changed files with 609 additions and 552 deletions

View File

@@ -39,7 +39,7 @@
#error "unknown machine!"
#endif /* MACHINE_FIREBEE */
//#define DBG_DMA
#define DBG_DMA
#ifdef DBG_DMA
#define dbg(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0)
#else

View File

@@ -766,102 +766,21 @@ irq7:
* the FPGA and triggers everytime vbasehi is written to, i.e.
* when the video base address gets changed
*/
handler_gpt0:
move #0x2700,sr // disable interrupts
.extern _gpt0_interrupt_handler
lea -7 * 4(sp),sp // save registers
movem.l d0-d4/a0-a1,(sp)
mvz.b vbasehi,d0 // screen base address high
cmp.w #2,d0 // screen base lower than 0x20000?
blt video_chg_end // yes, do nothing
cmp.w #0xd0,d0 // lower than 0xd00000? - normal Falcon video area, mapped
// to 60d00000 (FPGA video memory)
blt sca_other //
move.w #0x2700,sr // disable interrupts
link a6,#-4 * 4 // make room for
movem.l d0-d1/a0-a1,(sp) // gcc scratch registers and save them,
// other registers will be handled by gcc itself
lea MCF_SLT0_SCNT,a0
move.l (a0),_video_sbt // save time
// FIXME: don't we need to get out here?
// bra video_chg_end
sca_other:
lsl.l #8,d0 // build new screen start address from Atari register contents
move.b 0xffff8203,d0 // mid byte
lsl.l #8,d0
move.b 0xffff820d,d0 // low byte
move.l d0,d3 // d0 and d3 now contain the video memory start address
video_chg_1page:
moveq #20,d4
move.l d0,d2
lsr.l d4,d2 // shift right by 20 bit -> page number (MB pages)
move.l _video_tlb,d4 // save to video pages bitmask
bset.l d2,d4 // set as newly set
bne video_chg_2page // was it set already?
move.l d4,_video_tlb
// jsr _flush_and_invalidate_caches FIXME: why should we need that?
video_copy_data:
move.l d4,_video_tlb
and.l #0x00f00000,d0
move.l d0,a0
move.l a0,a1
add.l #0x60000000,a1
move.l #0x10000,d4 // 16 bytes per copy -> 1 MB
video_copy_data_loop:
move.l (a0)+,(a1)+ // copy video page contents to FPGA memory
move.l (a0)+,(a1)+
move.l (a0)+,(a1)+
move.l (a0)+,(a1)+
subq.l #1,d4
bne video_copy_data_loop
// eintrag suchen
move.l d0,MCF_MMU_MMUAR // address
move.l #0x106,d4
move.l d4,MCF_MMU_MMUOR // search -> new one will be offered if not found
nop
move.l MCF_MMU_MMUOR,d4
clr.w d4
swap d4
move.l d4,MCF_MMU_MMUAR
move.l d0,d1
add.l #MCF_MMU_MMUTR_ID(sca_page_ID)|std_mmutr,d0
add.l #0x60000000|writethrough_mmudr /* |MCF_MMU_MMUDR_LK */,d1
mvz.w #0x10b,d2 // MMU update
move.l d0,MCF_MMU_MMUTR
move.l d1,MCF_MMU_MMUDR
move.l d2,MCF_MMU_MMUOR // setzen vidoe maped to 60xxx only data
nop
video_chg_2page:
// calculate screen memory size
move.l d3,d0
mvz.w 0xffff8210,d4 // VWRAP: words per scanline
mvz.w 0xffff82aa,d2 // VDE: vertical display end
mvz.w 0xffff82a8,d1 // VDB: vertical display begin
sub.l d1,d2 // number of lines
mulu d2,d4 // times number of words per line
add.l d4,d0 // calculate end address
cmp.l #__STRAM_END,d0 // > end of STRAM?
bge video_chg_end // yes - we're finished
moveq #20,d4 // shift right by 20 bit -> page number (MB pages)
move.l d0,d2
lsr.l d4,d2 // calculate page number
move.l _video_tlb,d4
bset.l d2,d4 // set as changed
beq video_copy_data // was not set yet, copy
jsr _flush_and_invalidate_caches
video_chg_end:
lea MCF_GPT0_GMS,a0 // disable and reenable trigger
bclr.b #0,3(a0)
nop
bset.b #0,3(a0)
movem.l (sp),d0-d4/a0-a1 // restore saved registers
lea 7 * 4(sp),sp
move.w 4(a6),d0 // fetch vector number from stack
move.l d0,-(sp) // push it
jsr _gpt0_interrupt_handler // call C handler
addq.l #4,sp // adjust stack
unlk a6
rte
#endif /* MACHINE_FIREBEE */

View File

@@ -34,11 +34,12 @@
#include "startcf.h"
#include "cache.h"
#include "util.h"
#include "dma.h"
extern void (*rt_vbr[])(void);
#define VBR rt_vbr
//#define IRQ_DEBUG
#define IRQ_DEBUG
#if defined(IRQ_DEBUG)
#define dbg(format, arg...) do { xprintf("DEBUG %s(): " format, __FUNCTION__, ##arg); } while (0)
#else
@@ -208,6 +209,9 @@ bool isr_execute_handler(int vector)
/*
* PIC interrupt handler for Firebee
*
* Handles PIC requests that come in from PSC3 serial interface. Currently, that
* is RTC/NVRAM requests only
*/
int pic_interrupt_handler(void *arg1, void *arg2)
{
@@ -401,3 +405,137 @@ bool irq6_interrupt_handler(uint32_t sf1, uint32_t sf2)
return handled;
}
#if defined(MACHINE_FIREBEE)
#define vbasehi (* (volatile uint8_t *) 0xffff8201)
#define vbasemid (* (volatile uint8_t *) 0xffff8203)
#define vbaselow (* (volatile uint8_t *) 0xffff820d)
#define vwrap (* (volatile uint16_t *) 0xffff8210)
#define vde (* (volatile uint16_t *) 0xffff82aa)
#define vdb (* (volatile uint16_t *) 0xffff82a8)
/*
* this is the higlevel interrupt service routine for gpt0 timer interrupts.
*
* It is called from handler_gpt0 in exceptions.S
*
* The gpt0 timer is not used as a timer, but as interrupt trigger by the FPGA which fires
* everytime the video base address high byte (0xffff8201) gets written by user code (i.e.
* everytime the video base address is set).
* The interrupt service routine checks if that page was already set as a video page (in that
* case it does nothing), if not (if we have a newly set page), it sets up an MMU mapping for
* that page (effectively rerouting any further access to Falcon video RAM to Firebee FPGA
* video RAM starting at 0x60000000) and copies SDRAM contents of that page to the video
* RAM page.
*/
void gpt0_interrupt_handler(void)
{
uint32_t video_address;
uint32_t video_end_address;
int page_number;
bool already_set;
extern uint32_t _STRAM_END;
dbg("screen base = 0x%x\r\n", vbasehi);
if (vbasehi < 2) /* screen base lower than 0x20000? */
{
goto rearm_trigger; /* do nothing */
}
else if (vbasehi >= 0xd0) /* higher than 0xd00000 (normal Falcon address)? */
{
video_sbt = MCF_SLT0_SCNT; /* FIXME: no idea why we need to save the time here */
}
video_address = (vbasehi << 16) | (vbasemid << 8) | vbaselow;
page_number = video_address >> 20; /* calculate a page number */
already_set = (video_tlb & (1 << page_number)); /* already in bitset? */
video_tlb |= page_number; /* set it */
if (! already_set) /* newly set page, need to copy contents */
{
flush_and_invalidate_caches();
dma_memcpy((uint8_t *) video_address + 0x60000000, (uint8_t *) video_address, 0x100000);
/*
* create an MMU TLB entry for the new video page
*/
/*
* first search for an existing entry with our address. If none is found,
* the MMU will propose a new one
*/
MCF_MMU_MMUAR = video_address;
MCF_MMU_MMUOR = 0x106;
NOP();
/*
* take this MMU TLB entry and set it to our video address and page mapping
*/
MCF_MMU_MMUAR = (MCF_MMU_MMUOR >> 16) & 0xffff; /* set TLB id */
MCF_MMU_MMUTR = video_address |
MCF_MMU_MMUTR_ID(sca_page_ID) | /* set video page ID */
MCF_MMU_MMUTR_SG | /* shared global */
MCF_MMU_MMUTR_V; /* valid */
MCF_MMU_MMUDR = (video_address + 0x60000000) | /* physical address */
MCF_MMU_MMUDR_SZ(0) | /* 1 MB page size */
MCF_MMU_MMUDR_CM(0) | /* writethrough */
MCF_MMU_MMUDR_R | /* readable */
MCF_MMU_MMUDR_W | /* writeable */
MCF_MMU_MMUDR_X; /* executable */
MCF_MMU_MMUOR = 0x10b; /* update TLB entry */
}
/*
* Calculate the effective screen memory size to see if we need to map another page
* in case the new screen spans more than one single page
*/
video_end_address = video_address + (vde - vdb) * vwrap;
if (video_end_address < _STRAM_END)
{
page_number = video_end_address >> 20; /* calculate a page number */
already_set = (video_tlb & (1 << page_number)); /* already in bitset? */
video_tlb |= page_number; /* set it */
if (! already_set) /* newly set page, need to copy contents */
{
flush_and_invalidate_caches();
dma_memcpy((uint8_t *) video_end_address + 0x60000000, (uint8_t *) video_end_address, 0x100000);
/*
* create an MMU TLB entry for the new video page
*/
/*
* first search for an existing entry with our address. If none is found,
* the MMU will propose a new one
*/
MCF_MMU_MMUAR = video_end_address;
MCF_MMU_MMUOR = 0x106;
NOP();
/*
* take this MMU TLB entry and set it to our video address and page mapping
*/
MCF_MMU_MMUAR = (MCF_MMU_MMUOR >> 16) & 0xffff; /* set TLB id */
MCF_MMU_MMUTR = video_end_address |
MCF_MMU_MMUTR_ID(sca_page_ID) | /* set video page ID */
MCF_MMU_MMUTR_SG | /* shared global */
MCF_MMU_MMUTR_V; /* valid */
MCF_MMU_MMUDR = (video_end_address + 0x60000000) | /* physical address */
MCF_MMU_MMUDR_SZ(0) | /* 1 MB page size */
MCF_MMU_MMUDR_CM(0) | /* writethrough */
MCF_MMU_MMUDR_R | /* readable */
MCF_MMU_MMUDR_W | /* writeable */
MCF_MMU_MMUDR_X; /* executable */
MCF_MMU_MMUOR = 0x10b; /* update TLB entry */
}
}
rearm_trigger:
MCF_GPT0_GMS &= ~1; /* rearm trigger */
NOP();
MCF_GPT0_GMS |= 1;
}
#endif /* MACHINE_FIREBEE */