mirror of
https://github.com/rdolbeau/NuBusFPGA.git
synced 2025-01-21 23:30:32 +00:00
Update memory map ; preliminary accel stuff to test (CW project missing, code resource INIT id 0 with the sysheap flag)
This commit is contained in:
parent
f867f02c83
commit
d53a70ba9e
300
nubus-to-ztex-gateware/NuBusFPGAInit/NuBusFPGAInit.c
Normal file
300
nubus-to-ztex-gateware/NuBusFPGAInit/NuBusFPGAInit.c
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
#include "A4Stuff.h"
|
||||||
|
#include "SetupA4.h"
|
||||||
|
#include <OSUtils.h>
|
||||||
|
#include <Types.h>
|
||||||
|
#include <QuickDraw.h>
|
||||||
|
|
||||||
|
#include "NuBusFPGA_HW.h"
|
||||||
|
|
||||||
|
#define kINITid 0
|
||||||
|
|
||||||
|
#define _BitBlt 0xAB00
|
||||||
|
|
||||||
|
//extern pascal void CopyBits(const BitMap *srcBits, const BitMap *dstBits, const Rect *srcRect, const Rect *dstRect, short mode, RgnHandle maskRgn) ONEWORDINLINE(0xA8EC);
|
||||||
|
//extern pascal void StdBits(const BitMap *srcBits, const Rect *srcRect, const Rect *dstRect, short mode, RgnHandle maskRgn) ONEWORDINLINE(0xA8EB);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
typedef pascal void (*StdBitsProc)(BitMap *srcBits, Rect *srcRect, Rect *dstRect, short mode, RgnHandle maskRgn);
|
||||||
|
StdBitsProc oldStdBits;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
pascal void myStdBits(BitMap *srcBits, Rect *srcRect, Rect *dstRect, short mode, RgnHandle maskRgn){
|
||||||
|
long oldA4;
|
||||||
|
volatile unsigned long * const debug_ptr = (unsigned long*)0xFC90001c;
|
||||||
|
*debug_ptr = 0xC0FFEE00;
|
||||||
|
|
||||||
|
oldA4 = SetCurrentA4();
|
||||||
|
RememberA4();
|
||||||
|
|
||||||
|
oldStdBits(srcBits, srcRect, dstRect, mode, maskRgn);
|
||||||
|
|
||||||
|
SetA4(oldA4);
|
||||||
|
}
|
||||||
|
|
||||||
|
pascal void myBitBltX(BitMap *srcBits, BitMap *maskBits, BitMap *dstBits, Rect *srcRect, Rect *maskRect, Rect *dstRect, short mode, Pattern *pat, RgnHandle rgnA, RgnHandle rgnB, RgnHandle rgnC, short multColor){
|
||||||
|
register BitBltProc loldBitBlt;
|
||||||
|
register long oldA4;
|
||||||
|
volatile unsigned long * const debug_ptr = (unsigned long*)0xFC90001c;
|
||||||
|
*debug_ptr = 0xC0FFEE00;
|
||||||
|
|
||||||
|
oldA4 = SetCurrentA4();
|
||||||
|
RememberA4();
|
||||||
|
|
||||||
|
//oldBitBlt(srcBits, maskBits, dstBits, srcRect, maskRect, dstRect, mode, pat, rgnA, rgnB, rgnC, multColor);
|
||||||
|
loldBitBlt = oldBitBlt;
|
||||||
|
|
||||||
|
SetA4(oldA4);
|
||||||
|
|
||||||
|
loldBitBlt(srcBits, maskBits, dstBits, srcRect, maskRect, dstRect, mode, pat, rgnA, rgnB, rgnC, multColor);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
int hwblit(char* p_fb_base, short dstshift, short mode, PixMapPtr dstpix, PixMapPtr srcpix, Rect *dstrect, Rect *srcrect, Rect minrect) {
|
||||||
|
//volatile unsigned long * const debug_ptr = (unsigned long*)0xFC90001c;
|
||||||
|
struct goblin_bt_regs* bt = (struct goblin_bt_regs*)(p_fb_base + GOBLIN_BT_OFFSET);
|
||||||
|
struct goblin_accel_regs* accel = (struct goblin_accel_regs*)(p_fb_base + GOBLIN_ACCEL_OFFSET);
|
||||||
|
short height = minrect.bottom - minrect.top;
|
||||||
|
//*debug_ptr = 0xC0FFEE00;
|
||||||
|
//*debug_ptr = (unsigned long)p_fb_base;
|
||||||
|
|
||||||
|
if (mode != 0) { // only copy for now
|
||||||
|
//*debug_ptr = -2L;
|
||||||
|
//*debug_ptr = mode;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (dstshift < 3) { // only 8/16/32 bits for now
|
||||||
|
//*debug_ptr = -3L;
|
||||||
|
//*debug_ptr = dstshift;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dstshift -= 3;
|
||||||
|
if (height < 0) { // no height
|
||||||
|
//*debug_ptr = -4L;
|
||||||
|
//*debug_ptr = height;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dstpix->baseAddr != p_fb_base) { // we're not destination
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (srcpix->baseAddr != p_fb_base) { // we're not source
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((minrect.top == 0x0) & (minrect.bottom == 0x14) &
|
||||||
|
(minrect.left == 0x5c9) & (minrect.right == 0x5f6)) { // ignore that one until later
|
||||||
|
//*debug_ptr = -5L;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Rect realrect, srcv, dstv;
|
||||||
|
short width = minrect.right - minrect.left;
|
||||||
|
|
||||||
|
//*debug_ptr = -1L;
|
||||||
|
|
||||||
|
realrect.top = minrect.top;
|
||||||
|
realrect.left = minrect.left;
|
||||||
|
//realrect.bottom = minrect.bottom;
|
||||||
|
//realrect.right = minrect.right;
|
||||||
|
|
||||||
|
realrect.top += (srcrect->top - dstrect->top);
|
||||||
|
realrect.left += (srcrect->left - dstrect->left); /* A2 */
|
||||||
|
/* minrect is A3 */
|
||||||
|
|
||||||
|
srcv.top = realrect.top - srcpix->bounds.top;
|
||||||
|
srcv.left = realrect.left - srcpix->bounds.left;
|
||||||
|
|
||||||
|
dstv.top = minrect.top - dstpix->bounds.top;
|
||||||
|
dstv.left = minrect.left - dstpix->bounds.left;
|
||||||
|
|
||||||
|
/* if .baseAddr of both pix are different, no overlap */
|
||||||
|
/*
|
||||||
|
// the HW can handle that for us
|
||||||
|
if (dstpix->baseAddr == srcpix->baseAddr) {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
bt->debug = srcv.top;
|
||||||
|
bt->debug = srcv.left;
|
||||||
|
|
||||||
|
bt->debug = dstv.top;
|
||||||
|
bt->debug = dstv.left;
|
||||||
|
|
||||||
|
bt->debug = (long)dstpix->baseAddr;
|
||||||
|
bt->debug = (long)srcpix->baseAddr;
|
||||||
|
|
||||||
|
bt->debug = height;
|
||||||
|
bt->debug = width;
|
||||||
|
|
||||||
|
WAIT_FOR_HW(accel);
|
||||||
|
|
||||||
|
accel->reg_width = brev(width);
|
||||||
|
accel->reg_height = brev(height);
|
||||||
|
accel->reg_bitblt_src_x = brev(srcv.left << dstshift);
|
||||||
|
accel->reg_bitblt_src_y = brev(srcv.top);
|
||||||
|
accel->reg_bitblt_dst_x = brev(dstv.left << dstshift);
|
||||||
|
accel->reg_bitblt_dst_y = brev(dstv.top);
|
||||||
|
|
||||||
|
accel->reg_cmd = brev(1<<DO_BLIT_BIT);
|
||||||
|
|
||||||
|
WAIT_FOR_HW(accel);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *debug_ptr = a;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
*debug_ptr = dstshift;
|
||||||
|
*debug_ptr = mode;
|
||||||
|
|
||||||
|
*debug_ptr = dstrect->top;
|
||||||
|
*debug_ptr = dstrect->left;
|
||||||
|
*debug_ptr = dstrect->bottom;
|
||||||
|
*debug_ptr = dstrect->right;
|
||||||
|
|
||||||
|
*debug_ptr = srcrect->top;
|
||||||
|
*debug_ptr = srcrect->left;
|
||||||
|
*debug_ptr = srcrect->bottom;
|
||||||
|
*debug_ptr = srcrect->right;
|
||||||
|
|
||||||
|
*debug_ptr = minrect.top;
|
||||||
|
*debug_ptr = minrect.left;
|
||||||
|
*debug_ptr = minrect.bottom;
|
||||||
|
*debug_ptr = minrect.right;
|
||||||
|
#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
|
||||||
|
// MINRECT
|
||||||
|
move.l -112(a6),-(sp) // parameter (last first)
|
||||||
|
move.l -116(a6),-(sp) // parameter (last first)
|
||||||
|
move.l a2,-(sp) // srcrect*
|
||||||
|
move.l a3,-(sp) // dstrect*
|
||||||
|
move.l a4,-(sp) // srcpix*
|
||||||
|
move.l a5,-(sp) // dstpix*
|
||||||
|
move.w 26(a6),-(sp) // mode
|
||||||
|
move.w d4,-(sp) // dstshift
|
||||||
|
move.l a1,-(sp) // fb_base
|
||||||
|
jsr hwblit
|
||||||
|
add #0x20,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
|
||||||
|
}
|
||||||
|
//616 610
|
||||||
|
#if 0
|
||||||
|
CQDProcs customCProcs;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
long oldA4;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
GrafPtr currPort;
|
||||||
|
#endif
|
||||||
|
Handle h;
|
||||||
|
struct goblin_bt_regs* bt;
|
||||||
|
|
||||||
|
//volatile unsigned long * const debug_ptr = (unsigned long*)0xFC90001c;
|
||||||
|
//*debug_ptr = 0xDEADBEEF;
|
||||||
|
|
||||||
|
oldA4 = SetCurrentA4();
|
||||||
|
RememberA4();
|
||||||
|
|
||||||
|
fb_base = (void*)GOBLIN_FB_BASE; // FIXME !!!
|
||||||
|
bt_base = ((char*)fb_base + GOBLIN_BT_OFFSET);
|
||||||
|
accel_base = ((char*)fb_base + GOBLIN_ACCEL_OFFSET);
|
||||||
|
|
||||||
|
bt = (struct goblin_bt_regs*)bt_base;
|
||||||
|
bt->debug = 0xDEADBEEF;
|
||||||
|
bt->debug = (unsigned long)fb_base;
|
||||||
|
bt->debug = (unsigned long)bt_base;
|
||||||
|
bt->debug = (unsigned long)accel_base;
|
||||||
|
|
||||||
|
h = Get1Resource('INIT', kINITid);
|
||||||
|
if (h) {
|
||||||
|
DetachResource(h);
|
||||||
|
} else {
|
||||||
|
DebugStr("\pargh");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
GetPort(&currPort);
|
||||||
|
if (currPort->portBits.rowBytes < 0) /* color port */ {
|
||||||
|
SetStdCProcs(&customCProcs);
|
||||||
|
customCProcs.bitsProc = myStdBits;
|
||||||
|
currPort->grafProcs = (QDProcs*)&customCProcs;
|
||||||
|
*debug_ptr = 0;
|
||||||
|
} else {
|
||||||
|
*debug_ptr = 0xF00FF00F;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
oldStdBits = (StdBitsProc)GetToolTrapAddress(_StdBits);
|
||||||
|
*debug_ptr = (unsigned long)oldStdBits;
|
||||||
|
SetToolTrapAddress((UniversalProcPtr)myStdBits, _StdBits);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
oldBitBlt = (BitBltProc)GetToolTrapAddress(_BitBlt);
|
||||||
|
//*debug_ptr = (unsigned long)oldBitBlt;
|
||||||
|
SetToolTrapAddress((UniversalProcPtr)myBitBlt, _BitBlt);
|
||||||
|
|
||||||
|
/* restore the a4 world */
|
||||||
|
SetA4(oldA4);
|
||||||
|
// *debug_ptr = 0xBEEFDEAD;
|
||||||
|
}
|
||||||
|
|
48
nubus-to-ztex-gateware/NuBusFPGAInit/NuBusFPGA_HW.h
Normal file
48
nubus-to-ztex-gateware/NuBusFPGAInit/NuBusFPGA_HW.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef __NUBUSFPGA_HW_H__
|
||||||
|
#define __NUBUSFPGA_HW_H__
|
||||||
|
|
||||||
|
#define GOBLIN_FB_BASE 0xFC000000 // FIXME !!!!
|
||||||
|
|
||||||
|
#define GOBLIN_BT_OFFSET 0x00900000
|
||||||
|
#define GOBLIN_ACCEL_OFFSET 0x00901000
|
||||||
|
|
||||||
|
#define u_int32_t volatile unsigned long
|
||||||
|
|
||||||
|
// status
|
||||||
|
#define WORK_IN_PROGRESS_BIT 0
|
||||||
|
|
||||||
|
// cmd
|
||||||
|
#define DO_BLIT_BIT 0 // hardwired in goblin_accel.py
|
||||||
|
|
||||||
|
|
||||||
|
#define FUN_DONE_BIT 31
|
||||||
|
|
||||||
|
struct goblin_bt_regs {
|
||||||
|
u_int32_t mode;
|
||||||
|
u_int32_t vblmask;
|
||||||
|
u_int32_t videoctrl;
|
||||||
|
u_int32_t intrclear;
|
||||||
|
u_int32_t reset;
|
||||||
|
u_int32_t lutaddr;
|
||||||
|
u_int32_t lut;
|
||||||
|
u_int32_t debug;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct goblin_accel_regs {
|
||||||
|
u_int32_t reg_status;
|
||||||
|
u_int32_t reg_cmd;
|
||||||
|
u_int32_t reg_r5_cmd;
|
||||||
|
u_int32_t resv0;
|
||||||
|
u_int32_t reg_width;
|
||||||
|
u_int32_t reg_height;
|
||||||
|
u_int32_t resv1;
|
||||||
|
u_int32_t resv2;
|
||||||
|
u_int32_t reg_bitblt_src_x;
|
||||||
|
u_int32_t reg_bitblt_src_y;
|
||||||
|
u_int32_t reg_bitblt_dst_x;
|
||||||
|
u_int32_t reg_bitblt_dst_y;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __NUBUSFPGA_HW_H__
|
5279
nubus-to-ztex-gateware/VexRiscv_FbAccel.v
Normal file
5279
nubus-to-ztex-gateware/VexRiscv_FbAccel.v
Normal file
File diff suppressed because it is too large
Load Diff
698
nubus-to-ztex-gateware/blit.c
Normal file
698
nubus-to-ztex-gateware/blit.c
Normal file
@ -0,0 +1,698 @@
|
|||||||
|
/*
|
||||||
|
~/LITEX/riscv64-unknown-elf-gcc-10.1.0-2020.08.2-x86_64-linux-ubuntu14/bin/riscv64-unknown-elf-gcc -Os -S blit.c -march=rv32ib -mabi=ilp32 -mstrict-align -fno-builtin-memset -nostdlib -ffreestanding -nostartfiles
|
||||||
|
~/LITEX/riscv64-unknown-elf-gcc-10.1.0-2020.08.2-x86_64-linux-ubuntu14/bin/riscv64-unknown-elf-gcc -Os -o blit -march=rv32ib -mabi=ilp32 -T blit.lds -nostartfiles blit.s
|
||||||
|
~/LITEX/riscv64-unknown-elf-gcc-10.1.0-2020.08.2-x86_64-linux-ubuntu14/bin/riscv64-unknown-elf-objcopy -O binary -j .text blit blit.raw
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HRES
|
||||||
|
#define HRES 1920
|
||||||
|
#warning "Using default HRES"
|
||||||
|
#endif
|
||||||
|
#ifndef VRES
|
||||||
|
#define VRES 1080
|
||||||
|
#warning "Using default VRES"
|
||||||
|
#endif
|
||||||
|
#ifndef BASE_FB
|
||||||
|
#define BASE_FB 0x8F800000 // FIXME : should be generated ; 2+ MiB of SDRAM as framebuffer
|
||||||
|
#warning "Using default BASE_FB"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BASE_ROM 0xF0910000 // FIXME : should be generated ; 4-64 KiB of Wishbone ROM ? ; also in the LDS file ; also in the Vex config
|
||||||
|
|
||||||
|
#define BASE_RAM 0xF0902000 // FIXME : should be generated : 4-64 KiB of Wishbone SRAM ? ; also in _start
|
||||||
|
#define BASE_RAM_SIZE 0x00001000 // FIXME : should be generated : 4-64 KiB of Wishbone SRAM ? ; also in _start
|
||||||
|
|
||||||
|
#define BASE_ACCEL_REGS 0xF0901000
|
||||||
|
|
||||||
|
#define mul_HRES(a) ((a) * HRES)
|
||||||
|
|
||||||
|
//typedef void (*boot_t)(void);
|
||||||
|
//typedef void (*start_t)(unsigned short, unsigned short, unsigned short, unsigned short, unsigned short, unsigned short, unsigned short, unsigned short);
|
||||||
|
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef volatile unsigned int u_int32_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
struct control_blitter {
|
||||||
|
volatile unsigned int fun;
|
||||||
|
volatile unsigned int done;
|
||||||
|
volatile unsigned short arg[8];
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FUN_BLIT_BIT 0 // hardwired in goblin_accel.py
|
||||||
|
#define FUN_DONE_BIT 31
|
||||||
|
#define FUN_BLIT (1<<FUN_BLIT_BIT)
|
||||||
|
#define FUN_DONE (1<<FUN_DONE_BIT)
|
||||||
|
|
||||||
|
struct goblin_accel_regs {
|
||||||
|
u_int32_t reg_status;
|
||||||
|
u_int32_t reg_cmd;
|
||||||
|
u_int32_t reg_r5_cmd;
|
||||||
|
u_int32_t resv0;
|
||||||
|
u_int32_t reg_width;
|
||||||
|
u_int32_t reg_height;
|
||||||
|
u_int32_t resv1;
|
||||||
|
u_int32_t resv2;
|
||||||
|
u_int32_t reg_bitblt_src_x;
|
||||||
|
u_int32_t reg_bitblt_src_y;
|
||||||
|
u_int32_t reg_bitblt_dst_x;
|
||||||
|
u_int32_t reg_bitblt_dst_y;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//#include "./rvintrin.h"
|
||||||
|
|
||||||
|
void from_reset(void) __attribute__ ((noreturn)); // nothrow,
|
||||||
|
|
||||||
|
static inline void flush_cache(void) {
|
||||||
|
asm volatile(".word 0x0000500F\n"); // flush the Dcache so that we get updated data
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef unsigned int unsigned_param_type;
|
||||||
|
|
||||||
|
static void rectfill(const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type color
|
||||||
|
);
|
||||||
|
static void rectfill_pm(const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type color,
|
||||||
|
const unsigned char pm
|
||||||
|
);
|
||||||
|
static void xorrectfill(const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type color
|
||||||
|
);
|
||||||
|
static void xorrectfill_pm(const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type color,
|
||||||
|
const unsigned char pm
|
||||||
|
);
|
||||||
|
static void invert(const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re
|
||||||
|
);
|
||||||
|
static void bitblit(const unsigned_param_type xs,
|
||||||
|
const unsigned_param_type ys,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned char pm,
|
||||||
|
const unsigned char gxop
|
||||||
|
);
|
||||||
|
|
||||||
|
static void print_hexword(unsigned int v, unsigned int bx, unsigned int by);
|
||||||
|
static void show_status_on_screen(void);
|
||||||
|
|
||||||
|
asm(".global _start\n"
|
||||||
|
"_start:\n"
|
||||||
|
// ".word 0x0000500F\n" // flush cache ; should not be needed after reset
|
||||||
|
//"addi sp,zero,66\n" // 0x0042
|
||||||
|
//"slli sp,sp,16\n" // 0x00420000, BASE_RAM
|
||||||
|
//"addi a0,zero,1\n" // 0x0001
|
||||||
|
//"slli a0,a0,12\n" // 0x00001000, BASE_RAM_SIZE
|
||||||
|
//"add sp,sp,a0\n" // SP at the end of the SRAM
|
||||||
|
"nop\n"
|
||||||
|
"li sp, 0xF0902ffc\n" // SP at the end of the SRAM
|
||||||
|
//"li a0, 0x00700968\n" // @ of r5_cmd
|
||||||
|
//"li a1, 0x00C0FFEE\n"
|
||||||
|
//"sw a1, 0(a0)\n"
|
||||||
|
"call from_reset\n"
|
||||||
|
".size _start, .-_start\n"
|
||||||
|
".align 4\n"
|
||||||
|
".globl _start\n"
|
||||||
|
".type _start, @function\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
#define imax(a,b) (((a)>(b))?(a):(b))
|
||||||
|
#define imin(a,b) (((a)<(b))?(a):(b))
|
||||||
|
|
||||||
|
#define DEBUG
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define SHOW_FUN(a) /* fbc->fbc_r5_status[0] = a */
|
||||||
|
#define SHOW_PC() /* SHOW_FUN(cmd); do { u_int32_t rd; asm volatile("auipc %[rd], 0" : [rd]"=r"(rd) ) ; fbc->fbc_r5_status[1] = rd; } while (0) */
|
||||||
|
#define SHOW_PC_2VAL(a, b) /* SHOW_PC(); fbc->fbc_r5_status[2] = a; fbc->fbc_r5_status[3] = b */
|
||||||
|
#else
|
||||||
|
#define SHOW_FUN(a)
|
||||||
|
#define SHOW_PC()
|
||||||
|
#define SHOW_PC_2VAL(a, b)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* need some way to have identifiable proc# and multiple struct control_blitter for //ism */
|
||||||
|
/* First need to set up essential C stuff like the stack */
|
||||||
|
/* maybe pass core-id as the first parameter (in a0) to everyone */
|
||||||
|
/* also need to figure out the non-coherent caches ... */
|
||||||
|
void from_reset(void) {
|
||||||
|
struct goblin_accel_regs* fbc = (struct goblin_accel_regs*)BASE_ACCEL_REGS;
|
||||||
|
unsigned int cmd = fbc->reg_r5_cmd;
|
||||||
|
|
||||||
|
switch (cmd & 0xF) {
|
||||||
|
case FUN_BLIT: {
|
||||||
|
bitblit(fbc->reg_bitblt_src_x, fbc->reg_bitblt_src_y,
|
||||||
|
fbc->reg_width, fbc->reg_height,
|
||||||
|
fbc->reg_bitblt_dst_x, fbc->reg_bitblt_dst_y,
|
||||||
|
0xFF, 0x3); // GXcopy
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
finish:
|
||||||
|
|
||||||
|
// make sure we have nothing left in the cache
|
||||||
|
flush_cache();
|
||||||
|
|
||||||
|
fbc->reg_r5_cmd = 0xFFFFFFFF; //FUN_DONE;
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* wait for reset */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define bitblit_proto_int(a, b, suf) \
|
||||||
|
static void bitblit##a##b##suf(const unsigned_param_type xs, \
|
||||||
|
const unsigned_param_type ys, \
|
||||||
|
const unsigned_param_type wi, \
|
||||||
|
const unsigned_param_type re, \
|
||||||
|
const unsigned_param_type xd, \
|
||||||
|
const unsigned_param_type yd, \
|
||||||
|
const unsigned char pm \
|
||||||
|
)
|
||||||
|
#define bitblit_proto(suf) \
|
||||||
|
bitblit_proto_int(_fwd, _fwd, suf); \
|
||||||
|
bitblit_proto_int(_bwd, _fwd, suf); \
|
||||||
|
bitblit_proto_int(_fwd, _bwd, suf)
|
||||||
|
// bitblit_proto_int(_bwd, _bwd, suf);
|
||||||
|
|
||||||
|
bitblit_proto(_copy);
|
||||||
|
bitblit_proto(_xor);
|
||||||
|
bitblit_proto(_copy_pm);
|
||||||
|
bitblit_proto(_xor_pm);
|
||||||
|
|
||||||
|
|
||||||
|
#define ROUTE_BITBLIT_PM(pm, bb) \
|
||||||
|
if (pm == 0xFF) bb(xs, ys, wi, re, xd, yd, pm); \
|
||||||
|
else bb##_pm(xs, ys, wi, re, xd, yd, pm)
|
||||||
|
|
||||||
|
static void bitblit(const unsigned_param_type xs,
|
||||||
|
const unsigned_param_type ys,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned char pm,
|
||||||
|
const unsigned char gxop
|
||||||
|
) {
|
||||||
|
struct goblin_accel_regs* fbc = (struct goblin_accel_regs*)BASE_ACCEL_REGS;
|
||||||
|
|
||||||
|
if (ys > yd) {
|
||||||
|
switch(gxop) {
|
||||||
|
case 0x3: // GXcopy
|
||||||
|
ROUTE_BITBLIT_PM(pm, bitblit_fwd_fwd_copy);
|
||||||
|
break;
|
||||||
|
case 0x6: // GXxor
|
||||||
|
ROUTE_BITBLIT_PM(pm, bitblit_fwd_fwd_xor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (ys < yd) {
|
||||||
|
switch(gxop) {
|
||||||
|
case 0x3: // GXcopy
|
||||||
|
ROUTE_BITBLIT_PM(pm, bitblit_bwd_fwd_copy);
|
||||||
|
break;
|
||||||
|
case 0x6: // GXxor
|
||||||
|
ROUTE_BITBLIT_PM(pm, bitblit_bwd_fwd_xor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else { // ys == yd
|
||||||
|
if (xs > xd) {
|
||||||
|
switch(gxop) {
|
||||||
|
case 0x3: // GXcopy
|
||||||
|
ROUTE_BITBLIT_PM(pm, bitblit_fwd_fwd_copy);
|
||||||
|
break;
|
||||||
|
case 0x6: // GXxor
|
||||||
|
ROUTE_BITBLIT_PM(pm, bitblit_fwd_fwd_xor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (xs < xd) {
|
||||||
|
switch(gxop) {
|
||||||
|
case 0x3: // GXcopy
|
||||||
|
ROUTE_BITBLIT_PM(pm, bitblit_fwd_bwd_copy);
|
||||||
|
break;
|
||||||
|
case 0x6: // GXxor
|
||||||
|
ROUTE_BITBLIT_PM(pm, bitblit_fwd_bwd_xor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else { // xs == xd
|
||||||
|
switch(gxop) {
|
||||||
|
case 0x3: // GXcopy
|
||||||
|
/* don't bother */
|
||||||
|
break;
|
||||||
|
case 0x6: // GXxor
|
||||||
|
rectfill_pm(xd, yd, wi, re, 0, pm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void rectfill(const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type color
|
||||||
|
) {
|
||||||
|
struct goblin_accel_regs* fbc = (struct goblin_accel_regs*)BASE_ACCEL_REGS;
|
||||||
|
unsigned int i, j;
|
||||||
|
unsigned char *dptr = (((unsigned char *)BASE_FB) + mul_HRES(yd) + xd);
|
||||||
|
unsigned char *dptr_line = dptr;
|
||||||
|
unsigned char u8color = color & 0xFF;
|
||||||
|
|
||||||
|
for (j = 0 ; j < re ; j++) {
|
||||||
|
unsigned char *dptr_elt = dptr_line;
|
||||||
|
i = 0;
|
||||||
|
for ( ; i < wi && ((unsigned int)dptr_elt&0x3)!=0; i++) {
|
||||||
|
*dptr_elt = u8color;
|
||||||
|
dptr_elt ++;
|
||||||
|
}
|
||||||
|
if (wi > 3) {
|
||||||
|
unsigned int u32color = (unsigned int)u8color | ((unsigned int)u8color)<<8 | ((unsigned int)u8color)<<16 | ((unsigned int)u8color)<<24;
|
||||||
|
for ( ; i < (wi-3) ; i+=4) {
|
||||||
|
*(unsigned int*)dptr_elt = u32color;
|
||||||
|
dptr_elt +=4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( ; i < wi ; i++) {
|
||||||
|
*dptr_elt = u8color;
|
||||||
|
dptr_elt ++;
|
||||||
|
}
|
||||||
|
dptr_line += HRES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rectfill_pm(const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type color,
|
||||||
|
const unsigned char pm
|
||||||
|
) {
|
||||||
|
struct goblin_accel_regs* fbc = (struct goblin_accel_regs*)BASE_ACCEL_REGS;
|
||||||
|
unsigned int i, j;
|
||||||
|
unsigned char *dptr = (((unsigned char *)BASE_FB) + mul_HRES(yd) + xd);
|
||||||
|
unsigned char *dptr_line = dptr;
|
||||||
|
unsigned char u8color = color;
|
||||||
|
|
||||||
|
for (j = 0 ; j < re ; j++) {
|
||||||
|
unsigned char *dptr_elt = dptr_line;
|
||||||
|
i = 0;
|
||||||
|
for ( ; i < wi && ((unsigned int)dptr_elt&0x3)!=0; i++) {
|
||||||
|
*dptr_elt = (u8color & pm) | (*dptr_elt & ~pm);
|
||||||
|
dptr_elt ++;
|
||||||
|
}
|
||||||
|
if (wi > 3) {
|
||||||
|
unsigned int u32color = (unsigned int)u8color | ((unsigned int)u8color)<<8 | ((unsigned int)u8color)<<16 | ((unsigned int)u8color)<<24;
|
||||||
|
unsigned int u32pm = (unsigned int)pm | ((unsigned int)pm)<<8 | ((unsigned int)pm)<<16 | ((unsigned int)pm)<<24;
|
||||||
|
for ( ; i < (wi-3) ; i+=4) {
|
||||||
|
*(unsigned int*)dptr_elt = (u32color & u32pm) | (*(unsigned int*)dptr_elt & ~u32pm);
|
||||||
|
dptr_elt +=4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( ; i < wi ; i++) {
|
||||||
|
*dptr_elt = (u8color & pm) | (*dptr_elt & ~pm);
|
||||||
|
dptr_elt ++;
|
||||||
|
}
|
||||||
|
dptr_line += HRES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void xorrectfill(const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type color
|
||||||
|
) {
|
||||||
|
struct goblin_accel_regs* fbc = (struct goblin_accel_regs*)BASE_ACCEL_REGS;
|
||||||
|
unsigned int i, j;
|
||||||
|
unsigned char *dptr = (((unsigned char *)BASE_FB) + mul_HRES(yd) + xd);
|
||||||
|
unsigned char *dptr_line = dptr;
|
||||||
|
unsigned char u8color = color & 0xFF;
|
||||||
|
|
||||||
|
for (j = 0 ; j < re ; j++) {
|
||||||
|
unsigned char *dptr_elt = dptr_line;
|
||||||
|
i = 0;
|
||||||
|
for ( ; i < wi && ((unsigned int)dptr_elt&0x3)!=0; i++) {
|
||||||
|
*dptr_elt ^= u8color;
|
||||||
|
dptr_elt ++;
|
||||||
|
}
|
||||||
|
if (wi > 3) {
|
||||||
|
unsigned int u32color = (unsigned int)u8color | ((unsigned int)u8color)<<8 | ((unsigned int)u8color)<<16 | ((unsigned int)u8color)<<24;
|
||||||
|
for ( ; i < (wi-3) ; i+=4) {
|
||||||
|
*(unsigned int*)dptr_elt ^= u32color;
|
||||||
|
dptr_elt +=4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( ; i < wi ; i++) {
|
||||||
|
*dptr_elt ^= u8color;
|
||||||
|
dptr_elt ++;
|
||||||
|
}
|
||||||
|
dptr_line += HRES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void xorrectfill_pm(const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type color,
|
||||||
|
const unsigned char pm
|
||||||
|
) {
|
||||||
|
struct goblin_accel_regs* fbc = (struct goblin_accel_regs*)BASE_ACCEL_REGS;
|
||||||
|
unsigned int i, j;
|
||||||
|
unsigned char *dptr = (((unsigned char *)BASE_FB) + mul_HRES(yd) + xd);
|
||||||
|
unsigned char *dptr_line = dptr;
|
||||||
|
unsigned char u8color = color;
|
||||||
|
|
||||||
|
for (j = 0 ; j < re ; j++) {
|
||||||
|
unsigned char *dptr_elt = dptr_line;
|
||||||
|
i = 0;
|
||||||
|
for ( ; i < wi && ((unsigned int)dptr_elt&0x3)!=0; i++) {
|
||||||
|
*dptr_elt ^= (u8color & pm);
|
||||||
|
dptr_elt ++;
|
||||||
|
}
|
||||||
|
if (wi > 3) {
|
||||||
|
unsigned int u32color = (unsigned int)u8color | ((unsigned int)u8color)<<8 | ((unsigned int)u8color)<<16 | ((unsigned int)u8color)<<24;
|
||||||
|
unsigned int u32pm = (unsigned int)pm | ((unsigned int)pm)<<8 | ((unsigned int)pm)<<16 | ((unsigned int)pm)<<24;
|
||||||
|
for ( ; i < (wi-3) ; i+=4) {
|
||||||
|
*(unsigned int*)dptr_elt ^= (u32color & u32pm);
|
||||||
|
dptr_elt +=4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( ; i < wi ; i++) {
|
||||||
|
*dptr_elt ^= (u8color & pm);
|
||||||
|
dptr_elt ++;
|
||||||
|
}
|
||||||
|
dptr_line += HRES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void invert(const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re
|
||||||
|
) {
|
||||||
|
struct goblin_accel_regs* fbc = (struct goblin_accel_regs*)BASE_ACCEL_REGS;
|
||||||
|
unsigned int i, j;
|
||||||
|
unsigned char *dptr = (((unsigned char *)BASE_FB) + mul_HRES(yd) + xd);
|
||||||
|
unsigned char *dptr_line = dptr;
|
||||||
|
|
||||||
|
for (j = 0 ; j < re ; j++) {
|
||||||
|
unsigned char *dptr_elt = dptr_line;
|
||||||
|
i = 0;
|
||||||
|
for ( ; i < wi && ((unsigned int)dptr_elt&0x3)!=0; i++) {
|
||||||
|
*dptr_elt = ~(*dptr_elt);
|
||||||
|
dptr_elt ++;
|
||||||
|
}
|
||||||
|
if (wi > 3) {
|
||||||
|
for ( ; i < (wi-3) ; i+=4) {
|
||||||
|
*(unsigned int*)dptr_elt = ~(*(unsigned int*)dptr_elt);
|
||||||
|
dptr_elt +=4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( ; i < wi ; i++) {
|
||||||
|
*dptr_elt = ~(*dptr_elt);
|
||||||
|
dptr_elt ++;
|
||||||
|
}
|
||||||
|
dptr_line += HRES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOT using npm enables the use of 'cmix' in more cases
|
||||||
|
#define COPY(d,s,pm,npm) (d) = (s)
|
||||||
|
//#define COPY_PM(d,s,pm,npm) (d) = (((s) & (pm)) | ((d) & (npm)))
|
||||||
|
#define COPY_PM(d,s,pm,npm) (d) = (((s) & (pm)) | ((d) & (~pm)))
|
||||||
|
#define XOR(d,s,pm,npm) (d) = ((s) ^ (d))
|
||||||
|
//#define XOR_PM(d,s,pm,npm) (d) = ((((s) ^ (d)) & (pm)) | ((d) & (npm)))
|
||||||
|
#define XOR_PM(d,s,pm,npm) (d) = ((((s) ^ (d)) & (pm)) | ((d) & (~pm)))
|
||||||
|
|
||||||
|
#define BLIT_FWD_FWD(NAME, OP) \
|
||||||
|
static void bitblit_fwd_fwd_##NAME(const unsigned_param_type xs, \
|
||||||
|
const unsigned_param_type ys, \
|
||||||
|
const unsigned_param_type wi, \
|
||||||
|
const unsigned_param_type re, \
|
||||||
|
const unsigned_param_type xd, \
|
||||||
|
const unsigned_param_type yd, \
|
||||||
|
const unsigned char pm) { \
|
||||||
|
unsigned int i, j; \
|
||||||
|
unsigned char *sptr = (((unsigned char *)BASE_FB) + mul_HRES(ys) + xs); \
|
||||||
|
unsigned char *dptr = (((unsigned char *)BASE_FB) + mul_HRES(yd) + xd); \
|
||||||
|
unsigned char *sptr_line = sptr; \
|
||||||
|
unsigned char *dptr_line = dptr; \
|
||||||
|
/*const unsigned char npm = ~pm;*/ \
|
||||||
|
\
|
||||||
|
for (j = 0 ; j < re ; j++) { \
|
||||||
|
unsigned char *sptr_elt = sptr_line; \
|
||||||
|
unsigned char *dptr_elt = dptr_line; \
|
||||||
|
i = 0; \
|
||||||
|
if (wi>3) { \
|
||||||
|
if ((xs & 0x3) || (xd & 0x3)) { \
|
||||||
|
for ( ; i < wi && ((unsigned int)dptr_elt&0x3)!=0; i++) { \
|
||||||
|
OP(*dptr_elt, *sptr_elt, pm, npm); \
|
||||||
|
dptr_elt ++; \
|
||||||
|
sptr_elt ++; \
|
||||||
|
} \
|
||||||
|
unsigned char *sptr_elt_al = (unsigned char*)((unsigned int)sptr_elt & ~0x3); \
|
||||||
|
unsigned int fsr_cst = 8*((unsigned int)sptr_elt & 0x3); \
|
||||||
|
unsigned int src0 = ((unsigned int*)sptr_elt_al)[0]; \
|
||||||
|
unsigned int u32pm = (unsigned int)pm | ((unsigned int)pm)<<8 | ((unsigned int)pm)<<16 | ((unsigned int)pm)<<24; \
|
||||||
|
for ( ; i < (wi-3) ; i+=4) { \
|
||||||
|
unsigned int src1 = ((unsigned int*)sptr_elt_al)[1]; \
|
||||||
|
unsigned int val; \
|
||||||
|
asm("fsr %0, %1, %2, %3\n" : "=r"(val) : "r"(src0), "r"(src1), "r"(fsr_cst)); \
|
||||||
|
OP(*(unsigned int*)dptr_elt, val, u32pm, u32npm); \
|
||||||
|
src0 = src1; \
|
||||||
|
dptr_elt += 4; \
|
||||||
|
sptr_elt_al += 4; \
|
||||||
|
} \
|
||||||
|
sptr_elt = sptr_elt_al + ((unsigned int)sptr_elt & 0x3); \
|
||||||
|
} else { \
|
||||||
|
const unsigned int u32pm = (unsigned int)pm | ((unsigned int)pm)<<8 | ((unsigned int)pm)<<16 | ((unsigned int)pm)<<24; \
|
||||||
|
/*const unsigned int u32npm = (unsigned int)npm | ((unsigned int)npm)<<8 | ((unsigned int)npm)<<16 | ((unsigned int)npm)<<24;*/ \
|
||||||
|
if (((xs & 0xf) == 0) && ((xd & 0xf) == 0)) { \
|
||||||
|
for ( ; i < (wi&(~0xf)) ; i+= 16) { \
|
||||||
|
OP(((unsigned int*)dptr_elt)[0], ((unsigned int*)sptr_elt)[0], u32pm, u32npm); \
|
||||||
|
OP(((unsigned int*)dptr_elt)[1], ((unsigned int*)sptr_elt)[1], u32pm, u32npm); \
|
||||||
|
OP(((unsigned int*)dptr_elt)[2], ((unsigned int*)sptr_elt)[2], u32pm, u32npm); \
|
||||||
|
OP(((unsigned int*)dptr_elt)[3], ((unsigned int*)sptr_elt)[3], u32pm, u32npm); \
|
||||||
|
dptr_elt += 16; \
|
||||||
|
sptr_elt += 16; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
for ( ; i < (wi&(~3)) ; i+= 4) { \
|
||||||
|
OP(((unsigned int*)dptr_elt)[0], ((unsigned int*)sptr_elt)[0], u32pm, u32npm); \
|
||||||
|
dptr_elt += 4; \
|
||||||
|
sptr_elt += 4; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
for ( ; i < wi ; i++) { \
|
||||||
|
OP(*dptr_elt, *sptr_elt, pm, npm); \
|
||||||
|
dptr_elt ++; \
|
||||||
|
sptr_elt ++; \
|
||||||
|
} \
|
||||||
|
sptr_line += HRES; \
|
||||||
|
dptr_line += HRES; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BLIT_FWD_BWD(NAME, OP) \
|
||||||
|
static void bitblit_fwd_bwd_##NAME(const unsigned_param_type xs, \
|
||||||
|
const unsigned_param_type ys, \
|
||||||
|
const unsigned_param_type wi, \
|
||||||
|
const unsigned_param_type re, \
|
||||||
|
const unsigned_param_type xd, \
|
||||||
|
const unsigned_param_type yd, \
|
||||||
|
const unsigned char pm) { \
|
||||||
|
unsigned int i, j; \
|
||||||
|
unsigned char *sptr = (((unsigned char *)BASE_FB) + mul_HRES(ys) + xs); \
|
||||||
|
unsigned char *dptr = (((unsigned char *)BASE_FB) + mul_HRES(yd) + xd); \
|
||||||
|
unsigned char *sptr_line = sptr + wi - 1; \
|
||||||
|
unsigned char *dptr_line = dptr + wi - 1; \
|
||||||
|
const unsigned char npm = ~pm; \
|
||||||
|
\
|
||||||
|
for (j = 0 ; j < re ; j++) { \
|
||||||
|
unsigned char *sptr_elt = sptr_line; \
|
||||||
|
unsigned char *dptr_elt = dptr_line; \
|
||||||
|
for (i = 0 ; i < wi ; i++) { \
|
||||||
|
OP(*dptr_elt, *sptr_elt, pm, npm); \
|
||||||
|
dptr_elt --; \
|
||||||
|
sptr_elt --; \
|
||||||
|
} \
|
||||||
|
sptr_line += HRES; \
|
||||||
|
dptr_line += HRES; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BLIT_BWD_FWD(NAME, OP) \
|
||||||
|
static void bitblit_bwd_fwd_##NAME(const unsigned_param_type xs, \
|
||||||
|
const unsigned_param_type ys, \
|
||||||
|
const unsigned_param_type wi, \
|
||||||
|
const unsigned_param_type re, \
|
||||||
|
const unsigned_param_type xd, \
|
||||||
|
const unsigned_param_type yd, \
|
||||||
|
const unsigned char pm) { \
|
||||||
|
unsigned int i, j; \
|
||||||
|
unsigned char *sptr = (((unsigned char *)BASE_FB) + mul_HRES(ys) + xs); \
|
||||||
|
unsigned char *dptr = (((unsigned char *)BASE_FB) + mul_HRES(yd) + xd); \
|
||||||
|
unsigned char *sptr_line = sptr + mul_HRES(re-1); \
|
||||||
|
unsigned char *dptr_line = dptr + mul_HRES(re-1); \
|
||||||
|
const unsigned char npm = ~pm; \
|
||||||
|
\
|
||||||
|
for (j = 0 ; j < re ; j++) { \
|
||||||
|
unsigned char *sptr_elt = sptr_line; \
|
||||||
|
unsigned char *dptr_elt = dptr_line; \
|
||||||
|
i = 0; \
|
||||||
|
if (wi>3) { \
|
||||||
|
if ((xs & 0x3) || (xd & 0x3)) { \
|
||||||
|
for ( ; i < wi && ((unsigned int)dptr_elt&0x3)!=0; i++) { \
|
||||||
|
OP(*dptr_elt, *sptr_elt, pm, npm); \
|
||||||
|
dptr_elt ++; \
|
||||||
|
sptr_elt ++; \
|
||||||
|
} \
|
||||||
|
unsigned char *sptr_elt_al = (unsigned char*)((unsigned int)sptr_elt & ~0x3); \
|
||||||
|
unsigned int fsr_cst = 8*((unsigned int)sptr_elt & 0x3); \
|
||||||
|
unsigned int src0 = ((unsigned int*)sptr_elt_al)[0]; \
|
||||||
|
unsigned int u32pm = (unsigned int)pm | ((unsigned int)pm)<<8 | ((unsigned int)pm)<<16 | ((unsigned int)pm)<<24; \
|
||||||
|
for ( ; i < (wi-3) ; i+=4) { \
|
||||||
|
unsigned int src1 = ((unsigned int*)sptr_elt_al)[1]; \
|
||||||
|
unsigned int val; \
|
||||||
|
asm("fsr %0, %1, %2, %3\n" : "=r"(val) : "r"(src0), "r"(src1), "r"(fsr_cst)); \
|
||||||
|
OP(*(unsigned int*)dptr_elt, val, u32pm, u32npm); \
|
||||||
|
src0 = src1; \
|
||||||
|
dptr_elt += 4; \
|
||||||
|
sptr_elt_al += 4; \
|
||||||
|
} \
|
||||||
|
sptr_elt = sptr_elt_al + ((unsigned int)sptr_elt & 0x3); \
|
||||||
|
} else { \
|
||||||
|
if (((xs & 0xf) == 0) && ((xd & 0xf) == 0)) { \
|
||||||
|
for ( ; i < (wi&(~0xf)) ; i+= 16) { \
|
||||||
|
const unsigned int u32pm = (unsigned int)pm | ((unsigned int)pm)<<8 | ((unsigned int)pm)<<16 | ((unsigned int)pm)<<24; \
|
||||||
|
/*const unsigned int u32npm = (unsigned int)npm | ((unsigned int)npm)<<8 | ((unsigned int)npm)<<16 | ((unsigned int)npm)<<24;*/ \
|
||||||
|
OP(((unsigned int*)dptr_elt)[0], ((unsigned int*)sptr_elt)[0], u32pm, u32npm); \
|
||||||
|
OP(((unsigned int*)dptr_elt)[1], ((unsigned int*)sptr_elt)[1], u32pm, u32npm); \
|
||||||
|
OP(((unsigned int*)dptr_elt)[2], ((unsigned int*)sptr_elt)[2], u32pm, u32npm); \
|
||||||
|
OP(((unsigned int*)dptr_elt)[3], ((unsigned int*)sptr_elt)[3], u32pm, u32npm); \
|
||||||
|
dptr_elt += 16; \
|
||||||
|
sptr_elt += 16; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
if (((xs & 0x3) == 0) && ((xd & 0x3) == 0)) { \
|
||||||
|
for ( ; i < (wi&(~3)) ; i+= 4) { \
|
||||||
|
const unsigned int u32pm = (unsigned int)pm | ((unsigned int)pm)<<8 | ((unsigned int)pm)<<16 | ((unsigned int)pm)<<24; \
|
||||||
|
/*const unsigned int u32npm = (unsigned int)npm | ((unsigned int)npm)<<8 | ((unsigned int)npm)<<16 | ((unsigned int)npm)<<24;*/ \
|
||||||
|
OP(((unsigned int*)dptr_elt)[0], ((unsigned int*)sptr_elt)[0], u32pm, u32npm); \
|
||||||
|
dptr_elt += 4; \
|
||||||
|
sptr_elt += 4; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
for ( ; i < wi ; i++) { \
|
||||||
|
OP(*dptr_elt, *sptr_elt, pm, npm); \
|
||||||
|
dptr_elt ++; \
|
||||||
|
sptr_elt ++; \
|
||||||
|
} \
|
||||||
|
sptr_line -= HRES; \
|
||||||
|
dptr_line -= HRES; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define BLIT_ALLDIR(NAME, OP) \
|
||||||
|
BLIT_FWD_FWD(NAME, OP) \
|
||||||
|
BLIT_FWD_BWD(NAME, OP) \
|
||||||
|
BLIT_BWD_FWD(NAME, OP) \
|
||||||
|
|
||||||
|
|
||||||
|
BLIT_ALLDIR(copy, COPY)
|
||||||
|
BLIT_ALLDIR(xor, XOR)
|
||||||
|
BLIT_ALLDIR(copy_pm, COPY_PM)
|
||||||
|
BLIT_ALLDIR(xor_pm, XOR_PM)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
else if ((xd & 0xf) == 0) {
|
||||||
|
unsigned int fsr_cst = xs & 0x3;
|
||||||
|
unsigned char* sptr_elt_al = sptr_elt - fsr_cst;
|
||||||
|
unsigned int src0 = ((unsigned int*)sptr_elt_al)[0];
|
||||||
|
for ( ; i < (wi&(~0xf)) ; i+= 16) {
|
||||||
|
unsigned int src1, val;
|
||||||
|
|
||||||
|
src1 = ((unsigned int*)sptr_elt_al)[1];
|
||||||
|
val = _rv32_fsr(src0, src1, fsr_cst);
|
||||||
|
((unsigned int*)dptr_elt)[0] = val;
|
||||||
|
src0 = src1;
|
||||||
|
|
||||||
|
src1 = ((unsigned int*)sptr_elt_al)[2];
|
||||||
|
val = _rv32_fsr(src0, src1, fsr_cst);
|
||||||
|
((unsigned int*)dptr_elt)[1] = val;
|
||||||
|
src0 = src1;
|
||||||
|
|
||||||
|
src1 = ((unsigned int*)sptr_elt_al)[3];
|
||||||
|
val = _rv32_fsr(src0, src1, fsr_cst);
|
||||||
|
((unsigned int*)dptr_elt)[2] = val;
|
||||||
|
src0 = src1;
|
||||||
|
|
||||||
|
src1 = ((unsigned int*)sptr_elt_al)[4];
|
||||||
|
val = _rv32_fsr(src0, src1, fsr_cst);
|
||||||
|
((unsigned int*)dptr_elt)[3] = val;
|
||||||
|
src0 = src1;
|
||||||
|
|
||||||
|
dptr_elt += 16;
|
||||||
|
sptr_elt_al += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void bitblit_bwd_bwd_copy(const unsigned_param_type xs,
|
||||||
|
const unsigned_param_type ys,
|
||||||
|
const unsigned_param_type wi,
|
||||||
|
const unsigned_param_type re,
|
||||||
|
const unsigned_param_type xd,
|
||||||
|
const unsigned_param_type yd,
|
||||||
|
const unsigned char pm
|
||||||
|
) {
|
||||||
|
unsigned int i, j;
|
||||||
|
unsigned char *sptr = (((unsigned char *)BASE_FB) + mul_HRES(ys) + xs);
|
||||||
|
unsigned char *dptr = (((unsigned char *)BASE_FB) + mul_HRES(yd) + xd);
|
||||||
|
unsigned char *sptr_line = sptr + mul_HRES(re-1);
|
||||||
|
unsigned char *dptr_line = dptr + mul_HRES(re-1);
|
||||||
|
|
||||||
|
// flush_cache(); // handled in boot()
|
||||||
|
|
||||||
|
for (j = 0 ; j < re ; j++) {
|
||||||
|
unsigned char *sptr_elt = sptr_line + wi - 1;
|
||||||
|
unsigned char *dptr_elt = dptr_line + wi - 1;
|
||||||
|
for (i = 0 ; i < wi ; i++) {
|
||||||
|
*dptr_elt = *sptr_elt;
|
||||||
|
dptr_elt --;
|
||||||
|
sptr_elt --;
|
||||||
|
}
|
||||||
|
sptr_line -= HRES;
|
||||||
|
dptr_line -= HRES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
6
nubus-to-ztex-gateware/blit.lds
Normal file
6
nubus-to-ztex-gateware/blit.lds
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
OUTPUT_ARCH( "riscv" )
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0xF0910000;
|
||||||
|
.text : { *(.text) }
|
||||||
|
}
|
30
nubus-to-ztex-gateware/blit.sh
Executable file
30
nubus-to-ztex-gateware/blit.sh
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash -x
|
||||||
|
|
||||||
|
HRES=${1:-1920}
|
||||||
|
VRES=${2:-1080}
|
||||||
|
BASE_FB=${3:-0x8F800000}
|
||||||
|
|
||||||
|
GCCDIR=~/LITEX/riscv64-unknown-elf-gcc-10.1.0-2020.08.2-x86_64-linux-ubuntu14
|
||||||
|
GCCPFX=riscv64-unknown-elf-
|
||||||
|
GCCLINK=${GCCDIR}/bin/${GCCPFX}gcc
|
||||||
|
|
||||||
|
#GCCDIR=/opt/rv32bk
|
||||||
|
#GCCPFX=riscv32-buildroot-linux-gnu-
|
||||||
|
|
||||||
|
GCCDIR=~dolbeau2/LITEX/buildroot-rv32/output/host
|
||||||
|
GCCPFX=riscv32-buildroot-linux-gnu-
|
||||||
|
|
||||||
|
GCC=${GCCDIR}/bin/${GCCPFX}gcc
|
||||||
|
OBJCOPY=${GCCDIR}/bin/${GCCPFX}objcopy
|
||||||
|
|
||||||
|
OPT=-Os #-fno-inline
|
||||||
|
ARCH=rv32i_zba_zbb_zbt
|
||||||
|
|
||||||
|
PARAM="-DHRES=${HRES} -DVRES=${VRES} -DBASE_FB=${BASE_FB}"
|
||||||
|
|
||||||
|
if test "x$1" != "xASM"; then
|
||||||
|
$GCC $OPT -S -o blit.s $PARAM -march=$ARCH -mabi=ilp32 -mstrict-align -fno-builtin-memset -nostdlib -ffreestanding -nostartfiles blit.c
|
||||||
|
fi
|
||||||
|
$GCC $OPT -c -o blit.o $PARAM -march=$ARCH -mabi=ilp32 -mstrict-align -fno-builtin-memset -nostdlib -ffreestanding -nostartfiles blit.s &&
|
||||||
|
$GCCLINK $OPT -o blit $PARAM -march=$ARCH -mabi=ilp32 -T blit.lds -nostartfiles blit.o &&
|
||||||
|
$OBJCOPY -O binary -j .text -j .rodata blit blit.raw
|
145
nubus-to-ztex-gateware/goblin_accel.py
Normal file
145
nubus-to-ztex-gateware/goblin_accel.py
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
from migen import *
|
||||||
|
from migen.genlib.fifo import *
|
||||||
|
|
||||||
|
from litex.soc.interconnect.csr import *
|
||||||
|
|
||||||
|
from litex.soc.interconnect import wishbone
|
||||||
|
|
||||||
|
class GoblinAccel(Module): # AutoCSR ?
|
||||||
|
def __init__(self, soc):
|
||||||
|
platform = soc.platform
|
||||||
|
|
||||||
|
# reg access
|
||||||
|
self.bus = bus = wishbone.Interface()
|
||||||
|
|
||||||
|
self.COORD_BITS = COORD_BITS = 12 #
|
||||||
|
|
||||||
|
reg_status = Signal(32) # 0
|
||||||
|
reg_cmd = Signal(32) # 1
|
||||||
|
reg_r5_cmd = Signal(32) # 2, to communicate with Vex
|
||||||
|
# 3 resv0
|
||||||
|
reg_width = Signal(COORD_BITS)
|
||||||
|
reg_height = Signal(COORD_BITS)
|
||||||
|
# 6 resv1
|
||||||
|
# 7 resv2
|
||||||
|
reg_bitblt_src_x = Signal(COORD_BITS) # 8
|
||||||
|
reg_bitblt_src_y = Signal(COORD_BITS) # 9
|
||||||
|
reg_bitblt_dst_x = Signal(COORD_BITS) # 10
|
||||||
|
reg_bitblt_dst_y = Signal(COORD_BITS) # 11
|
||||||
|
|
||||||
|
# do-some-work flags
|
||||||
|
do_blit = Signal()
|
||||||
|
|
||||||
|
# cmd register reg_cmd
|
||||||
|
DO_BLIT_BIT = 0
|
||||||
|
|
||||||
|
# global status register reg_status
|
||||||
|
WORK_IN_PROGRESS_BIT = 0
|
||||||
|
|
||||||
|
self.submodules.wishbone_fsm = wishbone_fsm = FSM(reset_state = "Reset")
|
||||||
|
wishbone_fsm.act("Reset",
|
||||||
|
NextValue(bus.ack, 0),
|
||||||
|
NextState("Idle"))
|
||||||
|
wishbone_fsm.act("Idle",
|
||||||
|
If(bus.cyc & bus.stb & bus.we & ~bus.ack, #write
|
||||||
|
Case(bus.adr[0:10], { #
|
||||||
|
"default": [ ],
|
||||||
|
# 0: reg_status R/O
|
||||||
|
0: [ NextValue(reg_status, bus.dat_w) ], # debug, remove me
|
||||||
|
1: [ NextValue(reg_cmd, bus.dat_w),
|
||||||
|
NextValue(do_blit, bus.dat_w[DO_BLIT_BIT] & ~reg_status[WORK_IN_PROGRESS_BIT]),
|
||||||
|
],
|
||||||
|
2: [ NextValue(reg_r5_cmd, bus.dat_w) ],
|
||||||
|
# 3
|
||||||
|
4: [ NextValue(reg_width, bus.dat_w) ],
|
||||||
|
5: [ NextValue(reg_height, bus.dat_w) ],
|
||||||
|
# 6,7
|
||||||
|
8: [ NextValue(reg_bitblt_src_x, bus.dat_w) ],
|
||||||
|
9: [ NextValue(reg_bitblt_src_y, bus.dat_w) ],
|
||||||
|
10: [ NextValue(reg_bitblt_dst_x, bus.dat_w) ],
|
||||||
|
11: [ NextValue(reg_bitblt_dst_y, bus.dat_w) ],
|
||||||
|
}),
|
||||||
|
NextValue(bus.ack, 1),
|
||||||
|
).Elif(bus.cyc & bus.stb & ~bus.we & ~bus.ack, #read
|
||||||
|
Case(bus.adr[0:10], {
|
||||||
|
"default": [ NextValue(bus.dat_r, 0xDEADBEEF) ],
|
||||||
|
0: [ NextValue(bus.dat_r, reg_status) ],
|
||||||
|
1: [ NextValue(bus.dat_r, reg_cmd) ],
|
||||||
|
2: [ NextValue(bus.dat_r, reg_r5_cmd) ],
|
||||||
|
# 3
|
||||||
|
4: [ NextValue(bus.dat_r, reg_width) ],
|
||||||
|
5: [ NextValue(bus.dat_r, reg_height) ],
|
||||||
|
# 6, 7
|
||||||
|
8: [ NextValue(bus.dat_r, reg_bitblt_src_x) ],
|
||||||
|
9: [ NextValue(bus.dat_r, reg_bitblt_src_y) ],
|
||||||
|
10: [ NextValue(bus.dat_r, reg_bitblt_dst_x) ],
|
||||||
|
11: [ NextValue(bus.dat_r, reg_bitblt_dst_y) ],
|
||||||
|
}),
|
||||||
|
NextValue(bus.ack, 1),
|
||||||
|
).Else(
|
||||||
|
NextValue(bus.ack, 0),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# also in blit.c, for r5-cmd
|
||||||
|
FUN_DONE_BIT = 31
|
||||||
|
FUN_BLIT_BIT = 0
|
||||||
|
# to hold the Vex in reset
|
||||||
|
local_reset = Signal(reset = 1)
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
If(reg_r5_cmd[FUN_DONE_BIT],
|
||||||
|
reg_r5_cmd.eq(0),
|
||||||
|
reg_status[WORK_IN_PROGRESS_BIT].eq(0),
|
||||||
|
local_reset.eq(1),
|
||||||
|
#timeout.eq(timeout_rst),
|
||||||
|
).Elif(do_blit & ~reg_status[WORK_IN_PROGRESS_BIT],
|
||||||
|
do_blit.eq(0),
|
||||||
|
reg_r5_cmd[FUN_BLIT_BIT].eq(1),
|
||||||
|
reg_status[WORK_IN_PROGRESS_BIT].eq(1),
|
||||||
|
local_reset.eq(0),
|
||||||
|
#timeout.eq(timeout_rst),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
led0 = platform.request("user_led", 0)
|
||||||
|
self.comb += led0.eq(~local_reset)
|
||||||
|
|
||||||
|
self.ibus = ibus = wishbone.Interface()
|
||||||
|
self.dbus = dbus = wishbone.Interface()
|
||||||
|
vex_reset = Signal()
|
||||||
|
|
||||||
|
self.comb += vex_reset.eq(ResetSignal("sys") | local_reset)
|
||||||
|
self.specials += Instance(self.get_netlist_name(),
|
||||||
|
i_clk = ClockSignal("sys"),
|
||||||
|
i_reset = vex_reset,
|
||||||
|
o_iBusWishbone_CYC = ibus.cyc,
|
||||||
|
o_iBusWishbone_STB = ibus.stb,
|
||||||
|
i_iBusWishbone_ACK = ibus.ack,
|
||||||
|
o_iBusWishbone_WE = ibus.we,
|
||||||
|
o_iBusWishbone_ADR = ibus.adr,
|
||||||
|
i_iBusWishbone_DAT_MISO = ibus.dat_r,
|
||||||
|
o_iBusWishbone_DAT_MOSI = ibus.dat_w,
|
||||||
|
o_iBusWishbone_SEL = ibus.sel,
|
||||||
|
i_iBusWishbone_ERR = ibus.err,
|
||||||
|
o_iBusWishbone_CTI = ibus.cti,
|
||||||
|
o_iBusWishbone_BTE = ibus.bte,
|
||||||
|
o_dBusWishbone_CYC = dbus.cyc,
|
||||||
|
o_dBusWishbone_STB = dbus.stb,
|
||||||
|
i_dBusWishbone_ACK = dbus.ack,
|
||||||
|
o_dBusWishbone_WE = dbus.we,
|
||||||
|
o_dBusWishbone_ADR = dbus.adr,
|
||||||
|
i_dBusWishbone_DAT_MISO = dbus.dat_r,
|
||||||
|
o_dBusWishbone_DAT_MOSI = dbus.dat_w,
|
||||||
|
o_dBusWishbone_SEL = dbus.sel,
|
||||||
|
i_dBusWishbone_ERR = dbus.err,
|
||||||
|
o_dBusWishbone_CTI = dbus.cti,
|
||||||
|
o_dBusWishbone_BTE = dbus.bte,)
|
||||||
|
|
||||||
|
self.add_sources(platform)
|
||||||
|
|
||||||
|
def get_netlist_name(self):
|
||||||
|
return "VexRiscv"
|
||||||
|
|
||||||
|
def add_sources(self, platform):
|
||||||
|
platform.add_source("/home/dolbeau/NuBusFPGA/nubus-to-ztex-gateware/VexRiscv_FbAccel.v", "verilog")
|
@ -175,11 +175,11 @@ class VideoFrameBufferMultiDepth(Module, AutoCSR):
|
|||||||
0x0: [ data_buf_direct[0].eq(self.conv32.source.data[24:32]),
|
0x0: [ data_buf_direct[0].eq(self.conv32.source.data[24:32]),
|
||||||
data_buf_direct[1].eq(self.conv32.source.data[16:24]),
|
data_buf_direct[1].eq(self.conv32.source.data[16:24]),
|
||||||
data_buf_direct[2].eq(self.conv32.source.data[8:16]), ],
|
data_buf_direct[2].eq(self.conv32.source.data[8:16]), ],
|
||||||
0x1: [ data_buf_direct[0].eq(Cat(Signal(3, reset = 0), self.conv16.source.data[11:16])), # fixme: 16-bits in X11 ???
|
0x1: [ data_buf_direct[0].eq(Cat(Signal(3, reset = 0), self.conv16.source.data[0:5])), # fixme: 16-bits in X11 ??? (this is QD32)
|
||||||
data_buf_direct[1].eq(Cat(Signal(3, reset = 0), self.conv16.source.data[6:11])),
|
data_buf_direct[1].eq(Cat(Signal(3, reset = 0), self.conv16.source.data[5:10])),
|
||||||
data_buf_direct[2].eq(Cat(Signal(3, reset = 0), self.conv16.source.data[1:6])), ]
|
data_buf_direct[2].eq(Cat(Signal(3, reset = 0), self.conv16.source.data[10:15])), ]
|
||||||
})]
|
})]
|
||||||
else:
|
else: # and little "i'm in the NuBusFPGA" ...
|
||||||
handle_truecolor_databuf =[ Case(self.indexed_mode, {
|
handle_truecolor_databuf =[ Case(self.indexed_mode, {
|
||||||
0x0: [ data_buf_direct[2].eq(self.conv32.source.data[24:32]),
|
0x0: [ data_buf_direct[2].eq(self.conv32.source.data[24:32]),
|
||||||
data_buf_direct[1].eq(self.conv32.source.data[16:24]),
|
data_buf_direct[1].eq(self.conv32.source.data[16:24]),
|
||||||
|
@ -38,6 +38,17 @@ class NuBus(Module):
|
|||||||
self.mem_local = Signal()
|
self.mem_local = Signal()
|
||||||
|
|
||||||
self.add_sources(platform)
|
self.add_sources(platform)
|
||||||
|
|
||||||
|
#arbcy_n = platform.request("arbcy_n")
|
||||||
|
#grant = platform.request("grant")
|
||||||
|
#pad_user_led_0 = platform.request("user_led", 0)
|
||||||
|
#pad_user_led_1 = platform.request("user_led", 1)
|
||||||
|
#arbcy_n_mem = Signal()
|
||||||
|
#grant_mem = Signal()
|
||||||
|
#self.sync.nubus += [ arbcy_n_mem.eq(~arbcy_n | arbcy_n_mem) ]
|
||||||
|
#self.sync.nubus += [ grant_mem.eq(grant | grant_mem) ]
|
||||||
|
#self.comb += pad_user_led_0.eq(arbcy_n_mem)
|
||||||
|
#self.comb += pad_user_led_1.eq(grant_mem)
|
||||||
|
|
||||||
#fixme: parameters
|
#fixme: parameters
|
||||||
self.specials += Instance(self.get_netlist_name(),
|
self.specials += Instance(self.get_netlist_name(),
|
||||||
|
@ -20,8 +20,15 @@ class Wishbone2NuBus(Module):
|
|||||||
#input cpu_eclr,
|
#input cpu_eclr,
|
||||||
#output [3:0] cpu_errors,
|
#output [3:0] cpu_errors,
|
||||||
|
|
||||||
|
#wb_adr_rev = Signal(32)
|
||||||
|
#self.comb += [ wb_adr_rev[ 0: 8].eq(wb.adr[22:30]),
|
||||||
|
# wb_adr_rev[ 8:16].eq(wb.adr[14:22]),
|
||||||
|
# wb_adr_rev[16:24].eq(wb.adr[ 6:14]),
|
||||||
|
# wb_adr_rev[24:32].eq(Cat(Signal(2, reset = 0),wb.adr[ 0: 6])), ]
|
||||||
|
|
||||||
self.comb += nubus.cpu_valid.eq(wb.cyc & wb.stb)
|
self.comb += nubus.cpu_valid.eq(wb.cyc & wb.stb)
|
||||||
self.comb += nubus.cpu_addr.eq(Cat(Signal(2, reset = 0), wb.adr))
|
self.comb += nubus.cpu_addr.eq(Cat(Signal(2, reset = 0), wb.adr))
|
||||||
|
#self.comb += nubus.cpu_addr.eq(wb_adr_rev)
|
||||||
self.comb += nubus.cpu_wdata.eq(wb.dat_w)
|
self.comb += nubus.cpu_wdata.eq(wb.dat_w)
|
||||||
self.comb += If(wb.we == 1,
|
self.comb += If(wb.we == 1,
|
||||||
nubus.cpu_write.eq(wb.sel)).Else(
|
nubus.cpu_write.eq(wb.sel)).Else(
|
||||||
@ -30,3 +37,11 @@ class Wishbone2NuBus(Module):
|
|||||||
self.comb += wb.dat_r.eq(nubus.cpu_rdata)
|
self.comb += wb.dat_r.eq(nubus.cpu_rdata)
|
||||||
self.comb += nubus.cpu_lock.eq(0) # FIXME: TODO: ???
|
self.comb += nubus.cpu_lock.eq(0) # FIXME: TODO: ???
|
||||||
self.comb += nubus.cpu_eclr.eq(0) # FIXME: TODO: ???
|
self.comb += nubus.cpu_eclr.eq(0) # FIXME: TODO: ???
|
||||||
|
|
||||||
|
#pad_user_led_0 = platform.request("user_led", 0)
|
||||||
|
#pad_user_led_1 = platform.request("user_led", 1)
|
||||||
|
#self.comb += pad_user_led_0.eq(nubus.cpu_valid)
|
||||||
|
#cpu_valid_ex = Signal(reset = 0)
|
||||||
|
#self.sync += cpu_valid_ex.eq(nubus.cpu_valid | cpu_valid_ex)
|
||||||
|
#self.comb += pad_user_led_1.eq(cpu_valid_ex)
|
||||||
|
|
||||||
|
@ -12,6 +12,12 @@ class PingMaster(Module):
|
|||||||
valu_reg = Signal(32)
|
valu_reg = Signal(32)
|
||||||
addr_reg = Signal(32)
|
addr_reg = Signal(32)
|
||||||
writ_del = Signal(6)
|
writ_del = Signal(6)
|
||||||
|
addr_reg_rev = Signal(32)
|
||||||
|
|
||||||
|
self.comb += [ addr_reg_rev[ 0: 8].eq(addr_reg[24:32]),
|
||||||
|
addr_reg_rev[ 8:16].eq(addr_reg[16:24]),
|
||||||
|
addr_reg_rev[16:24].eq(addr_reg[ 8:16]),
|
||||||
|
addr_reg_rev[24:32].eq(addr_reg[ 0: 8]), ]
|
||||||
|
|
||||||
self.sync += If(writ_del != 0,
|
self.sync += If(writ_del != 0,
|
||||||
writ_del.eq(writ_del - 1))
|
writ_del.eq(writ_del - 1))
|
||||||
@ -26,7 +32,7 @@ class PingMaster(Module):
|
|||||||
Case(bus_slv.adr[0:1], {
|
Case(bus_slv.adr[0:1], {
|
||||||
0x0: [ NextValue(valu_reg, bus_slv.dat_w[0:32]), ],
|
0x0: [ NextValue(valu_reg, bus_slv.dat_w[0:32]), ],
|
||||||
0x1: [ NextValue(addr_reg, bus_slv.dat_w[0:32]),
|
0x1: [ NextValue(addr_reg, bus_slv.dat_w[0:32]),
|
||||||
NextValue(writ_del, 63), ],
|
NextValue(writ_del, 3), ],
|
||||||
}),
|
}),
|
||||||
NextValue(bus_slv.ack, 1),
|
NextValue(bus_slv.ack, 1),
|
||||||
).Elif(bus_slv.cyc & bus_slv.stb & ~bus_slv.we & ~bus_slv.ack, #read
|
).Elif(bus_slv.cyc & bus_slv.stb & ~bus_slv.we & ~bus_slv.ack, #read
|
||||||
|
@ -19,9 +19,6 @@ class NuBus2Wishbone(Module):
|
|||||||
#nubus.mem_error
|
#nubus.mem_error
|
||||||
#nubus.mem_tryagain
|
#nubus.mem_tryagain
|
||||||
|
|
||||||
#nubus_mem_addr_revb = Signal(32)
|
|
||||||
#self.comb += nubus_mem_addr_revb.eq(Cat(nubus.mem_addr[24:32], nubus.mem_addr[16:24], nubus.mem_addr[8:16], nubus.mem_addr[0:8]))
|
|
||||||
|
|
||||||
self.comb += wb.cyc.eq(nubus.mem_valid)
|
self.comb += wb.cyc.eq(nubus.mem_valid)
|
||||||
self.comb += wb.stb.eq(nubus.mem_valid)
|
self.comb += wb.stb.eq(nubus.mem_valid)
|
||||||
self.comb += If(nubus.mem_write == 0,
|
self.comb += If(nubus.mem_write == 0,
|
||||||
@ -33,14 +30,12 @@ class NuBus2Wishbone(Module):
|
|||||||
If(~nubus.mem_addr[23], # first 8 MiB of slot space: remap to last 8 Mib of SDRAM
|
If(~nubus.mem_addr[23], # first 8 MiB of slot space: remap to last 8 Mib of SDRAM
|
||||||
wb.adr.eq(Cat(nubus.mem_addr[2:23], Signal(1, reset=1), Signal(8, reset = 0x8f))), # 0x8f8...
|
wb.adr.eq(Cat(nubus.mem_addr[2:23], Signal(1, reset=1), Signal(8, reset = 0x8f))), # 0x8f8...
|
||||||
).Else( # second 8 MiB: direct access
|
).Else( # second 8 MiB: direct access
|
||||||
wb.adr.eq(Cat(nubus.mem_addr[2:24], Signal(8, reset = 0)))), # 24 bits, a.k.a 22 bits of words
|
wb.adr.eq(Cat(nubus.mem_addr[2:24], Signal(8, reset = 0xf0)))), # 24 bits, a.k.a 22 bits of words
|
||||||
]
|
]
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
wb.dat_w.eq(nubus.mem_wdata),
|
wb.dat_w.eq(nubus.mem_wdata),
|
||||||
nubus.mem_rdata.eq(wb.dat_r),
|
nubus.mem_rdata.eq(wb.dat_r),
|
||||||
#wb.dat_w.eq(Cat(nubus.mem_wdata[24:32], nubus.mem_wdata[16:24], nubus.mem_wdata[8:16], nubus.mem_wdata[0:8])),
|
|
||||||
#nubus.mem_rdata.eq(Cat(wb.dat_r[24:32], wb.dat_r[16:24], wb.dat_r[8:16], wb.dat_r[0:8])),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
self.comb += nubus.mem_ready.eq(wb.ack)
|
self.comb += nubus.mem_ready.eq(wb.ack)
|
||||||
|
@ -30,6 +30,7 @@ from litex.soc.cores.video import VideoS7HDMIPHY
|
|||||||
from litex.soc.cores.video import VideoVGAPHY
|
from litex.soc.cores.video import VideoVGAPHY
|
||||||
from litex.soc.cores.video import video_timings
|
from litex.soc.cores.video import video_timings
|
||||||
import goblin_fb
|
import goblin_fb
|
||||||
|
import goblin_accel
|
||||||
|
|
||||||
# Wishbone stuff
|
# Wishbone stuff
|
||||||
from sbus_wb import WishboneDomainCrossingMaster
|
from sbus_wb import WishboneDomainCrossingMaster
|
||||||
@ -241,17 +242,22 @@ class NuBusFPGA(SoCCore):
|
|||||||
# they are translated: '$s0 0000-$sF FFFF' to '$Fs00 0000-$Fs0F FFFF' (for s in range $9 through $E)
|
# they are translated: '$s0 0000-$sF FFFF' to '$Fs00 0000-$Fs0F FFFF' (for s in range $9 through $E)
|
||||||
# let's assume we have 32-bits mode, this can be requested in the DeclROM apparently
|
# let's assume we have 32-bits mode, this can be requested in the DeclROM apparently
|
||||||
self.wb_mem_map = wb_mem_map = {
|
self.wb_mem_map = wb_mem_map = {
|
||||||
"goblin_mem": 0x00000000, # up to 8 MiB of FB memory
|
# master to map the NuBus access to RAM
|
||||||
#"END OF FIRST MB" : 0x000FFFFF,
|
"master": 0x00000000, # to 0x3FFFFFFF
|
||||||
#"END OF 8 MB": 0x007FFFFF,
|
|
||||||
"goblin_bt" : 0x00900000, # BT for goblin
|
|
||||||
"csr" : 0x00a00000, # CSR
|
|
||||||
"pingmaster": 0x00b00000,
|
|
||||||
"rom": 0x00FF8000, # ROM at the end (32 KiB of it ATM)
|
|
||||||
#"END OF SLOT SPACE": 0x00FFFFFF,
|
|
||||||
"main_ram": 0x80000000, # not directly reachable from NuBus
|
"main_ram": 0x80000000, # not directly reachable from NuBus
|
||||||
"video_framebuffer": 0x80000000 + 0x10000000 - goblin_fb_size, # Updated later
|
"video_framebuffer": 0x80000000 + 0x10000000 - goblin_fb_size, # Updated later
|
||||||
"fixme_master": 0xF0000000,
|
# map everything in slot 0, remapped from the real slot in NuBus2Wishbone
|
||||||
|
"goblin_mem": 0xF0000000, # up to 8 MiB of FB memory
|
||||||
|
#"END OF FIRST MB" : 0xF00FFFFF,
|
||||||
|
#"END OF 8 MB": 0xF07FFFFF,
|
||||||
|
"goblin_bt" : 0xF0900000, # BT for goblin (regs)
|
||||||
|
"goblin_accel" : 0xF0901000, # accel for goblin (regs)
|
||||||
|
"goblin_accel_ram" : 0xF0902000, # accel for goblin (scratch ram)
|
||||||
|
"goblin_accel_rom" : 0xF0910000, # accel for goblin (rom)
|
||||||
|
"csr" : 0xF0a00000, # CSR
|
||||||
|
"pingmaster": 0xF0b00000,
|
||||||
|
"rom": 0xF0FF8000, # ROM at the end (32 KiB of it ATM)
|
||||||
|
#"END OF SLOT SPACE": 0xF0FFFFFF,
|
||||||
}
|
}
|
||||||
self.mem_map.update(wb_mem_map)
|
self.mem_map.update(wb_mem_map)
|
||||||
self.submodules.crg = _CRG(platform=platform, sys_clk_freq=sys_clk_freq, goblin=goblin, hdmi=hdmi, pix_clk=litex.soc.cores.video.video_timings[goblin_res]["pix_clk"])
|
self.submodules.crg = _CRG(platform=platform, sys_clk_freq=sys_clk_freq, goblin=goblin, hdmi=hdmi, pix_clk=litex.soc.cores.video.video_timings[goblin_res]["pix_clk"])
|
||||||
@ -302,7 +308,7 @@ class NuBusFPGA(SoCCore):
|
|||||||
self.bus.add_master(name="DDR3Init", master=self.sdram_init.bus)
|
self.bus.add_master(name="DDR3Init", master=self.sdram_init.bus)
|
||||||
else:
|
else:
|
||||||
avail_sdram = 256 * 1024 * 1024
|
avail_sdram = 256 * 1024 * 1024
|
||||||
self.add_ram("ram", origin=self.mem_map["goblin_mem"], size=2**16, mode="rw")
|
self.add_ram("ram", origin=0x8f800000, size=2**16, mode="rw")
|
||||||
|
|
||||||
#self.submodules.leds = ClockDomainsRenamer("nubus")(LedChaser(
|
#self.submodules.leds = ClockDomainsRenamer("nubus")(LedChaser(
|
||||||
# pads = platform.request_all("user_led"),
|
# pads = platform.request_all("user_led"),
|
||||||
@ -349,8 +355,7 @@ class NuBusFPGA(SoCCore):
|
|||||||
wishbone_slave_nubus = wishbone.Interface(data_width=self.bus.data_width)
|
wishbone_slave_nubus = wishbone.Interface(data_width=self.bus.data_width)
|
||||||
self.submodules.wishbone2nubus = ClockDomainsRenamer("nubus")(Wishbone2NuBus(nubus=self.nubus,wb=wishbone_slave_nubus))
|
self.submodules.wishbone2nubus = ClockDomainsRenamer("nubus")(Wishbone2NuBus(nubus=self.nubus,wb=wishbone_slave_nubus))
|
||||||
self.submodules.wishbone_slave_sys = WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_slave_nubus, cd_master="sys", cd_slave="nubus")
|
self.submodules.wishbone_slave_sys = WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_slave_nubus, cd_master="sys", cd_slave="nubus")
|
||||||
self.bus.add_slave("DMA", self.wishbone_slave_sys, SoCRegion(origin=self.mem_map.get("fixme_master", None), size=0x0fffffff, cached=False))
|
self.bus.add_slave("DMA", self.wishbone_slave_sys, SoCRegion(origin=self.mem_map.get("master", None), size=0x40000000, cached=False))
|
||||||
|
|
||||||
|
|
||||||
if (goblin):
|
if (goblin):
|
||||||
if (not hdmi):
|
if (not hdmi):
|
||||||
@ -364,13 +369,25 @@ class NuBusFPGA(SoCCore):
|
|||||||
#pad_user_led_1 = platform.request("user_led", 1)
|
#pad_user_led_1 = platform.request("user_led", 1)
|
||||||
#self.comb += pad_user_led_0.eq(self.goblin.video_framebuffer.underflow)
|
#self.comb += pad_user_led_0.eq(self.goblin.video_framebuffer.underflow)
|
||||||
#self.comb += pad_user_led_1.eq(self.goblin.video_framebuffer.fb_dma.enable)
|
#self.comb += pad_user_led_1.eq(self.goblin.video_framebuffer.fb_dma.enable)
|
||||||
|
if (True):
|
||||||
|
self.submodules.goblin_accel = goblin_accel.GoblinAccel(soc = self)
|
||||||
|
self.bus.add_slave("goblin_accel", self.goblin_accel.bus, SoCRegion(origin=self.mem_map.get("goblin_accel", None), size=0x1000, cached=False))
|
||||||
|
self.bus.add_master(name="goblin_accel_r5_i", master=self.goblin_accel.ibus)
|
||||||
|
self.bus.add_master(name="goblin_accel_r5_d", master=self.goblin_accel.dbus)
|
||||||
|
goblin_rom_file = "blit.raw"
|
||||||
|
goblin_rom_data = soc_core.get_mem_data(goblin_rom_file, "little")
|
||||||
|
goblin_rom_len = 4*len(goblin_rom_data);
|
||||||
|
rounded_goblin_rom_len = 2**log2_int(goblin_rom_len, False)
|
||||||
|
print(f"GOBLIN ROM is {goblin_rom_len} bytes, using {rounded_goblin_rom_len}")
|
||||||
|
assert(rounded_goblin_rom_len <= 2**16)
|
||||||
|
self.add_ram("goblin_accel_rom", origin=self.mem_map["goblin_accel_rom"], size=rounded_goblin_rom_len, contents=goblin_rom_data, mode="r")
|
||||||
|
self.add_ram("goblin_accel_ram", origin=self.mem_map["goblin_accel_ram"], size=2**12, mode="rw")
|
||||||
|
|
||||||
# for testing
|
# for testing
|
||||||
#from nubus_master_tst import PingMaster
|
#from nubus_master_tst import PingMaster
|
||||||
#self.submodules.pingmaster = PingMaster()
|
#self.submodules.pingmaster = PingMaster()
|
||||||
#self.bus.add_slave("pingmaster_slv", self.pingmaster.bus_slv, SoCRegion(origin=self.mem_map.get("pingmaster", None), size=0x010, cached=False))
|
#self.bus.add_slave("pingmaster_slv", self.pingmaster.bus_slv, SoCRegion(origin=self.mem_map.get("pingmaster", None), size=0x010, cached=False))
|
||||||
#self.bus.add_master(name="pingmaster_mst", master=self.pingmaster.bus_mst)
|
#self.bus.add_master(name="pingmaster_mst", master=self.pingmaster.bus_mst)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="SbusFPGA")
|
parser = argparse.ArgumentParser(description="SbusFPGA")
|
||||||
|
@ -18,7 +18,7 @@ dfii_command_wrdata = 0x10
|
|||||||
dfii_command_rddata = 0x20
|
dfii_command_rddata = 0x20
|
||||||
|
|
||||||
# /!\ keep up to date with csr /!\
|
# /!\ keep up to date with csr /!\
|
||||||
sdram_dfii_base = 0x00a01000
|
sdram_dfii_base = 0xf0a01000
|
||||||
sdram_dfii_control = sdram_dfii_base + 0x000
|
sdram_dfii_control = sdram_dfii_base + 0x000
|
||||||
sdram_dfii_pi0_command = sdram_dfii_base + 0x004
|
sdram_dfii_pi0_command = sdram_dfii_base + 0x004
|
||||||
sdram_dfii_pi0_command_issue = sdram_dfii_base + 0x008
|
sdram_dfii_pi0_command_issue = sdram_dfii_base + 0x008
|
||||||
@ -26,7 +26,7 @@ sdram_dfii_pi0_address = sdram_dfii_base + 0x00c
|
|||||||
sdram_dfii_pi0_baddress = sdram_dfii_base + 0x010
|
sdram_dfii_pi0_baddress = sdram_dfii_base + 0x010
|
||||||
|
|
||||||
# /!\ keep up to date with csr /!\
|
# /!\ keep up to date with csr /!\
|
||||||
ddrphy_base = 0x00a00000
|
ddrphy_base = 0xf0a00000
|
||||||
ddrphy_rst = ddrphy_base + 0x000
|
ddrphy_rst = ddrphy_base + 0x000
|
||||||
ddrphy_dly_sel = ddrphy_base + 0x010
|
ddrphy_dly_sel = ddrphy_base + 0x010
|
||||||
ddrphy_rdly_dq_rst = ddrphy_base + 0x014
|
ddrphy_rdly_dq_rst = ddrphy_base + 0x014
|
||||||
|
@ -324,9 +324,9 @@ module nubus_slave_tb ();
|
|||||||
|
|
||||||
// check PingMaster
|
// check PingMaster
|
||||||
$display ("PING ---------------------------");
|
$display ("PING ---------------------------");
|
||||||
write_word(TMADN_WR_WORD, PING_ADDR+0, 'hC0FFEE00);
|
write_word(TMADN_WR_WORD, PING_ADDR+0, 'h00C0FFEE);
|
||||||
read_word (TMADN_RD_WORD, PING_ADDR+0);
|
read_word (TMADN_RD_WORD, PING_ADDR+0);
|
||||||
write_word(TMADN_WR_WORD, PING_ADDR+4, 'hF0F0F0F0);
|
write_word(TMADN_WR_WORD, PING_ADDR+4, 'h00096240);
|
||||||
|
|
||||||
mastermode_start <= 1;
|
mastermode_start <= 1;
|
||||||
mastermode_tmack <= 0;
|
mastermode_tmack <= 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user