Screen address change now handled entirely in C (handler_gpt0/
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user