mirror of
https://github.com/rdolbeau/NuBusFPGA.git
synced 2024-12-22 10:29:53 +00:00
426 lines
11 KiB
C
426 lines
11 KiB
C
#include "A4Stuff.h"
|
|
#include "SetupA4.h"
|
|
#include <OSUtils.h>
|
|
#include <Types.h>
|
|
#include <QuickDraw.h>
|
|
#include <Slots.h>
|
|
#include <ROMDefs.h>
|
|
|
|
#include "NuBusFPGA_HW.h"
|
|
|
|
#include "ShowInitIcon.h"
|
|
|
|
#define kINITid 0
|
|
|
|
#define _BitBlt 0xAB00
|
|
|
|
// #define QEMU
|
|
|
|
|
|
int hwblit(char* stack, char* p_fb_base, /* short dstshift, */ short mode, Pattern* pat, PixMapPtr dstpix, PixMapPtr srcpix, Rect *dstrect, Rect *srcrect);
|
|
pascal asm void myBitBlt(BitMap *srcBits, BitMap *maskBits, BitMap *dstBits, Rect *srcRect, Rect *maskRect, Rect *dstRect, short mode, Pattern *pat, RgnHandle rgnA, RgnHandle rgnB, RgnHandle rgnC, short multColor);
|
|
short check_slots(char list[6]);
|
|
|
|
typedef pascal void (*BitBltProc)(BitMap *srcBits, BitMap *maskBits, BitMap *dstBits, Rect *srcRect, Rect *maskRect, Rect *dstRect, short mode, Pattern *pat, RgnHandle rgnA, RgnHandle rgnB, RgnHandle rgnC, short multColor);
|
|
static BitBltProc oldBitBlt;
|
|
|
|
void* fb_base;
|
|
void* bt_base;
|
|
void* accel_base;
|
|
|
|
static inline unsigned long brev(const unsigned long r) {
|
|
return (((r&0xFF000000)>>24) | ((r&0xFF0000)>>8) | ((r&0xFF00)<<8) | ((r&0xFF)<<24));
|
|
}
|
|
|
|
#define WAIT_FOR_HW(accel) \
|
|
while (accel->reg_status & brev(1<<WORK_IN_PROGRESS_BIT))
|
|
|
|
#define WAIT_FOR_HW_LE(accel_le) \
|
|
while (accel_le->reg_status & (1<<WORK_IN_PROGRESS_BIT))
|
|
|
|
#define uint8_t unsigned char
|
|
#define uint16_t unsigned short
|
|
#define uint32_t unsigned long
|
|
|
|
#include "NuBusFPGA_QD.h"
|
|
|
|
#ifdef QEMU
|
|
#define DLOG(x) bt->debug = (x);
|
|
#else
|
|
#define DLOG(X)
|
|
#endif
|
|
|
|
int hwblit(char* stack, char* p_fb_base, /* short dstshift, */ short mode, Pattern* pat, PixMapPtr dstpix, PixMapPtr srcpix, Rect *dstrect, Rect *srcrect) {
|
|
struct goblin_bt_regs* bt = (struct goblin_bt_regs*)(p_fb_base + GOBLIN_BT_OFFSET);
|
|
struct goblin_accel_regs* accel_le = (struct goblin_accel_regs*)(p_fb_base + GOBLIN_ACCEL_OFFSET_LE);
|
|
struct qdstuff* qdstack = (struct qdstuff*)(stack - sizeof(struct qdstuff));
|
|
short height = qdstack->MINRECT.bottom - qdstack->MINRECT.top;
|
|
short dstshift = qdstack->DSTSHIFT;
|
|
short srcshift = qdstack->SRCSHIFT;
|
|
short expat_size = 0;
|
|
short expat_const = 0;
|
|
|
|
if ((mode != 0) && (mode != 8)) { // only copy handled for now
|
|
#if 0
|
|
DLOG(-2L)
|
|
DLOG(mode)
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
if (mode == 8) {
|
|
register int i, n;
|
|
register unsigned long expat0 = qdstack->EXPAT[0];
|
|
if (qdstack->PATROW != 0) {
|
|
expat_size = (qdstack->PATVMASK+1) >> 2;
|
|
#if 0
|
|
DLOG(-6L)
|
|
DLOG((unsigned long)qdstack->EXPAT)
|
|
DLOG(expat_size)
|
|
for (i = 0 ; i < expat_size ; i++) {
|
|
DLOG(qdstack->EXPAT[i])
|
|
}
|
|
// PATROW is the stride between lines (bytes)
|
|
DLOG(qdstack->PATROW)
|
|
// PATVMASK has the number of bytes-1 in the pattern?
|
|
DLOG(qdstack->PATVMASK)
|
|
// PATHMASK has ???
|
|
DLOG(qdstack->PATHMASK)
|
|
DLOG(qdstack->PATVPOS)
|
|
DLOG(qdstack->PATHPOS)
|
|
#endif
|
|
if (expat_size > 512)
|
|
return 0;
|
|
|
|
expat_const = 0;
|
|
} else {
|
|
expat_const = 1;
|
|
if ((expat0 & 0xFFFF) != ((expat0 >> 16) & 0xFFFF))
|
|
expat_const = 0;
|
|
if ((expat0 & 0xFF) != ((expat0 >> 8) & 0xFF))
|
|
expat_const = 0;
|
|
for (i = 1 ; expat_const && i < 16 ; i++)
|
|
if (expat0 != qdstack->EXPAT[i])
|
|
expat_const = 0;
|
|
|
|
#ifdef QEMU
|
|
if (!expat_const) {
|
|
DLOG(-7L)
|
|
// PATROW is the stride between lines (bytes)
|
|
DLOG(qdstack->PATROW)
|
|
// PATVMASK has the number of bytes-1 in the pattern?
|
|
DLOG(qdstack->PATVMASK)
|
|
// PATHMASK has ???
|
|
DLOG(qdstack->PATHMASK)
|
|
DLOG(qdstack->PATVPOS)
|
|
DLOG(qdstack->PATHPOS)
|
|
for (i = 0 ; i < 16 ; i++)
|
|
DLOG(qdstack->EXPAT[i])
|
|
//return 0;
|
|
}
|
|
#endif
|
|
expat_size = 16;
|
|
}
|
|
}
|
|
|
|
if (srcshift != dstshift) {
|
|
DLOG(-9L)
|
|
DLOG(srcshift)
|
|
DLOG(dstshift)
|
|
return 0;
|
|
}
|
|
|
|
|
|
if (height < 0) { // no height
|
|
return 0;
|
|
}
|
|
|
|
if (dstpix->baseAddr != p_fb_base) { // we're not destination
|
|
#if 0//def QEMU
|
|
DLOG(-4L)
|
|
DLOG((unsigned long)dstpix->baseAddr)
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
if ((srcpix->baseAddr != p_fb_base)
|
|
// && ((unsigned long)srcpix->baseAddr >= 0x40000000) // and neither is main memory
|
|
){
|
|
#if 0//def QEMU
|
|
DLOG(-5L)
|
|
DLOG((unsigned long)srcpix->baseAddr)
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
{
|
|
Rect realrect, srcv, dstv;
|
|
short width = qdstack->MINRECT.right - qdstack->MINRECT.left;
|
|
short src_check = 0x07 >> srcshift;
|
|
short dst_check = 0x07 >> dstshift;
|
|
|
|
//*debug_ptr = -1L;
|
|
|
|
realrect.top = qdstack->MINRECT.top;
|
|
realrect.left = qdstack->MINRECT.left;
|
|
//realrect.bottom = qdstack->MINRECT.bottom;
|
|
//realrect.right = qdstack->MINRECT.right;
|
|
|
|
realrect.top += (srcrect->top - dstrect->top);
|
|
realrect.left += (srcrect->left - dstrect->left); /* A2 */
|
|
/* qdstack->MINRECT is A3 */
|
|
|
|
srcv.top = realrect.top - srcpix->bounds.top;
|
|
srcv.left = realrect.left - srcpix->bounds.left;
|
|
|
|
dstv.top = qdstack->MINRECT.top - dstpix->bounds.top;
|
|
dstv.left = qdstack->MINRECT.left - dstpix->bounds.left;
|
|
|
|
// must be byte-aligned for now
|
|
if (width & src_check) {
|
|
DLOG(-15);
|
|
DLOG(width);
|
|
return 0;
|
|
}
|
|
if (srcv.left & src_check) {
|
|
DLOG(-16);
|
|
DLOG(srcv.left);
|
|
return 0;
|
|
}
|
|
if (dstv.left & dst_check) {
|
|
DLOG(-17);
|
|
DLOG(dstv.left);
|
|
return 0;
|
|
}
|
|
if (width < 4)
|
|
return 0;
|
|
|
|
/* if .baseAddr of both pix are different, no overlap */
|
|
/*
|
|
// the HW can handle that for us
|
|
if (dstpix->baseAddr == srcpix->baseAddr) {
|
|
|
|
}
|
|
*/
|
|
#ifdef QEMU
|
|
#if 1
|
|
DLOG(-1L)
|
|
|
|
DLOG(srcpix->rowBytes)
|
|
DLOG(dstpix->rowBytes)
|
|
|
|
DLOG(srcv.top)
|
|
DLOG(srcv.left)
|
|
|
|
DLOG(height)
|
|
DLOG(width)
|
|
|
|
DLOG(dstv.top)
|
|
DLOG(dstv.left)
|
|
|
|
DLOG((long)dstpix->baseAddr)
|
|
DLOG((long)srcpix->baseAddr)
|
|
#endif
|
|
|
|
return 0;
|
|
#else
|
|
WAIT_FOR_HW_LE(accel_le);
|
|
|
|
accel_le->reg_op = 0x3; // GXcopy
|
|
accel_le->reg_depth = 0; // current
|
|
|
|
accel_le->reg_width = (width); // pixels
|
|
accel_le->reg_height = (height);
|
|
accel_le->reg_bitblt_dst_x = (dstv.left); // pixels
|
|
accel_le->reg_bitblt_dst_y = (dstv.top);
|
|
if (dstpix->baseAddr != p_fb_base)
|
|
accel_le->reg_dst_ptr = (unsigned long)(dstpix->baseAddr);
|
|
else
|
|
accel_le->reg_dst_ptr = 0; // let the HW pick its internal address
|
|
accel_le->reg_dst_stride = (dstpix->rowBytes); // bytes // we should strip the high-order bit, but the HW ignore that for us anyway
|
|
|
|
if (mode == 0) {
|
|
accel_le->reg_bitblt_src_x = (srcv.left); // pixels
|
|
accel_le->reg_bitblt_src_y = (srcv.top);
|
|
if (srcpix->baseAddr != p_fb_base)
|
|
accel_le->reg_src_ptr = (unsigned long)(srcpix->baseAddr);
|
|
else
|
|
accel_le->reg_src_ptr = 0; // let the HW pick its internal address
|
|
accel_le->reg_src_stride = (srcpix->rowBytes); // bytes // we should strip the high-order bit, but the HW ignore that for us anyway
|
|
accel_le->reg_cmd = (1<<DO_BLIT_BIT);
|
|
} else if (mode == 8) {
|
|
register unsigned short i;
|
|
if (expat_const) {
|
|
accel_le->reg_fgcolor = qdstack->EXPAT[0];
|
|
accel_le->reg_cmd = (1<<DO_FILL_BIT);
|
|
} else {
|
|
if (qdstack->PATROW == 0) { // same as 4 ?
|
|
accel_le->reg_bitblt_src_x = 0x3;
|
|
accel_le->reg_bitblt_src_y = 0xf;
|
|
accel_le->reg_src_stride = 4;
|
|
expat_size = 16;
|
|
} else {
|
|
accel_le->reg_bitblt_src_x = qdstack->PATROW - 1;
|
|
accel_le->reg_bitblt_src_y = ((qdstack->PATVMASK+1)/qdstack->PATROW)-1;
|
|
accel_le->reg_src_stride = qdstack->PATROW;
|
|
}
|
|
for (i = 0 ; i < expat_size ; i++) {
|
|
((unsigned long*)(p_fb_base + GOBLIN_PATTERN_OFFSET))[i] = qdstack->EXPAT[i];
|
|
}
|
|
accel_le->reg_cmd = (1<<DO_PATT_BIT);
|
|
}
|
|
}
|
|
WAIT_FOR_HW_LE(accel_le);
|
|
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
pascal asm void myBitBlt(BitMap *srcBits, BitMap *maskBits, BitMap *dstBits, Rect *srcRect, Rect *maskRect, Rect *dstRect, short mode, Pattern *pat, RgnHandle rgnA, RgnHandle rgnB, RgnHandle rgnC, short multColor) {
|
|
// a2: srcrect
|
|
// a3: dstrect
|
|
// a4: srcpix
|
|
// a5: dstpix
|
|
// d3: srcshift (not used)
|
|
// d4: dstshift
|
|
// d7: invert flag
|
|
|
|
link a6,#-4
|
|
//moveq #-1,d0
|
|
//move.l d0,0xfc90001c
|
|
jsr SetCurrentA4
|
|
move.l d0,-4(a6)
|
|
jsr RememberA4
|
|
////movea.l 0(a4), a0
|
|
movea.l oldBitBlt, a0
|
|
movea.l fb_base, a1
|
|
//move.l a0,0xfc90001c
|
|
move.l -4(a6), d0
|
|
//move.l d0,0xfc90001c
|
|
exg d0,a4
|
|
unlk a6
|
|
|
|
//move.l #0xF00FF00F,d0
|
|
//move.l a0,0xfc90001c
|
|
//move.l d0,0xfc90001c
|
|
move.l a0,-(sp) // save oldBitBlt, not a parameter
|
|
|
|
move.l a2,-(sp) // srcrect*
|
|
move.l a3,-(sp) // dstrect*
|
|
move.l a4,-(sp) // srcpix*
|
|
move.l a5,-(sp) // dstpix*
|
|
move.l 22(a6),-(sp) // pat*
|
|
move.w 26(a6),-(sp) // mode
|
|
//move.w d4,-(sp) // dstshift
|
|
move.l a1,-(sp) // fb_base
|
|
move.l a6,-(sp) // top of stack
|
|
jsr hwblit
|
|
add #0x1e,sp
|
|
|
|
move.l (sp)+,a0 // restore oldBitBlt
|
|
//move.l a0,0xfc90001c
|
|
cmpi #1,d0 // if hwblit returned 1, it did the copy
|
|
beq finish
|
|
jmp (a0)
|
|
finish:
|
|
rts
|
|
}
|
|
|
|
void main(void)
|
|
{
|
|
long oldA4;
|
|
short cnt;
|
|
char list[6];
|
|
char slot;
|
|
Handle h;
|
|
struct goblin_bt_regs* bt;
|
|
|
|
//volatile unsigned long * const debug_ptr = (unsigned long*)0xFC90001c;
|
|
//*debug_ptr = 0xDEADBEEF;
|
|
|
|
oldA4 = SetCurrentA4();
|
|
RememberA4();
|
|
|
|
cnt = check_slots(list);
|
|
|
|
if (!cnt)
|
|
goto finish;
|
|
|
|
slot = list[0]; // FIXME: what if more than one ???
|
|
|
|
//fb_base = (void*)GOBLIN_FB_BASE; // FIXME !!!
|
|
fb_base = (void*)(0xF0000000ul | (((unsigned long)slot) << 24));
|
|
bt_base = ((char*)fb_base + GOBLIN_BT_OFFSET);
|
|
accel_base = ((char*)fb_base + GOBLIN_ACCEL_OFFSET);
|
|
|
|
bt = (struct goblin_bt_regs*)bt_base;
|
|
DLOG(0xDEADBEEF)
|
|
DLOG((unsigned long)fb_base)
|
|
DLOG((unsigned long)bt_base)
|
|
DLOG((unsigned long)accel_base)
|
|
|
|
h = Get1Resource('INIT', kINITid);
|
|
if (h) {
|
|
DetachResource(h);
|
|
} else {
|
|
DebugStr("\pargh");
|
|
}
|
|
|
|
oldBitBlt = (BitBltProc)GetToolTrapAddress(_BitBlt);
|
|
//*debug_ptr = (unsigned long)oldBitBlt;
|
|
SetToolTrapAddress((UniversalProcPtr)myBitBlt, _BitBlt);
|
|
|
|
ShowInitIcon(121 + slot, true);
|
|
|
|
finish:
|
|
/* restore the a4 world */
|
|
SetA4(oldA4);
|
|
// *debug_ptr = 0xBEEFDEAD;
|
|
}
|
|
|
|
short check_slots(char list[6]) {
|
|
int i;
|
|
short cnt;
|
|
OSErr err;
|
|
SpBlock mySpBlock;
|
|
SInfoRecord mySInfoRecord;
|
|
cnt = 0;
|
|
// check all slots
|
|
for (i = 0x9 ; i < 0xf ; i++) {
|
|
// check if there's something there
|
|
mySpBlock.spResult = (long)&mySInfoRecord;
|
|
mySpBlock.spSlot = i;
|
|
mySpBlock.spSize = 0; // unused by SReadInfo, can be altered
|
|
err = SReadInfo(&mySpBlock);
|
|
if (!err) {
|
|
if (mySInfoRecord.siInitStatusA == smEmptySlot) {
|
|
// oups ?
|
|
} else {
|
|
// check for what exactly is here
|
|
mySpBlock.spSlot = i;
|
|
mySpBlock.spID = 0;
|
|
mySpBlock.spExtDev = 0;
|
|
mySpBlock.spCategory = catDisplay;
|
|
mySpBlock.spCType = typeVideo;
|
|
mySpBlock.spDrvrSW = drSwApple;
|
|
mySpBlock.spDrvrHW = 0xbeef; // DrHwNuBusFPGA
|
|
mySpBlock.spTBMask = 0;
|
|
err = SNextTypeSRsrc(&mySpBlock);
|
|
if (!err) {
|
|
if ((mySpBlock.spCategory == catDisplay) &&
|
|
(mySpBlock.spCType == typeVideo) &&
|
|
(mySpBlock.spDrvrSW == drSwApple) &&
|
|
(mySpBlock.spDrvrHW == 0xbeef) &&
|
|
(mySpBlock.spSlot == i)) {
|
|
list[cnt] = i;
|
|
cnt ++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return cnt;
|
|
} |