refactor ram dsk driver a bit more, some work toward multiplexed interrupt

This commit is contained in:
Romain Dolbeau 2022-10-08 10:39:18 +02:00
parent fb0a291b70
commit 6040bca13a
7 changed files with 148 additions and 57 deletions

View File

@ -14,14 +14,20 @@ typedef void(*vblproto)(short);
*/
#pragma parameter __D0 fbIrq(__A1)
__attribute__ ((section (".text.fbdriver"))) short fbIrq(const long sqParameter) {
/* AuxDCEPtr dce = (AuxDCEPtr)sqParameter; */
/* NuBusFPGADriverGlobalsHdl dStoreHdl = (NuBusFPGADriverGlobalsHdl)dce->dCtlStorage; */
/* NuBusFPGADriverGlobalsPtr dStore = *dStoreHdl; */
vblproto myVbl = *(vblproto**)0x0d28;
/* write_reg(dce, GOBOFB_INTR_CLEAR, 0); */
*((volatile unsigned int*)(sqParameter+GOBOFB_BASE+GOBOFB_INTR_CLEAR)) = 0;
myVbl((sqParameter>>24)&0xf); // cleaner to use dStore->slot ? but require more code...
return 1;
register unsigned long p_D1 asm("d1"), p_D2 asm("d2");
unsigned int irq;
short ret;
asm volatile("" : "+d" (p_D1), "+d" (p_D2));
ret = 0;
irq = (*((volatile unsigned int*)(sqParameter+GOBOFB_BASE+GOBOFB_INTR_CLEAR)));
if (irq) {
vblproto myVbl = *(vblproto**)0x0d28;
*((volatile unsigned int*)(sqParameter+GOBOFB_BASE+GOBOFB_INTR_CLEAR)) = 0;
myVbl((sqParameter>>24)&0xf); // cleaner to use dStore->slot ? but require more code...
ret = 1;
}
asm volatile("" : : "d" (p_D1), "d" (p_D2));
return ret;
}
#pragma parameter __D0 cNuBusFPGAOpen(__A0, __A1)

View File

@ -12,6 +12,17 @@
#include "NuBusFPGADrvr.h"
#ifdef ENABLE_DMA
typedef struct {
unsigned long blk_todo;
unsigned long blk_done;
unsigned long blk_offset;
unsigned long blk_doing;
void *ioBuffer;
int write;
} ram_dsk_op;
#endif
struct RAMDrvContext {
DrvSts2 drvsts;
char slot;
@ -21,6 +32,9 @@ struct RAMDrvContext {
unsigned int dma_blk_size_shift;
unsigned long dma_blk_base;
unsigned long dma_mem_size;
SlotIntQElement *siqel;
ram_dsk_op op;
char irqen;
#endif
};
@ -32,7 +46,7 @@ struct RAMDrvContext {
#define DMA_BLK_SIZE (0x00100800 | 0x00)
#define DMA_BLK_BASE (0x00100800 | 0x04)
#define DMA_MEM_SIZE (0x00100800 | 0x08)
//#define DMA_IRQ_CTL (0x00a00800 | 0x0c) // IRQ not connected
#define DMA_IRQ_CTL (0x00100800 | 0x0c)
#define DMA_BLK_ADDR (0x00100800 | 0x10)
#define DMA_DMA_ADDR (0x00100800 | 0x14)
#define DMA_BLK_CNT (0x00100800 | 0x18)
@ -40,8 +54,12 @@ struct RAMDrvContext {
#define DMA_STATUS (0x00100800 | 0x2c)
#define DMA_STATUS_CHECK_BITS (0x01F)
#define DMA_IRQSTATUS (0x00100800 | 0x34)
#endif
/* ctrl */
OSErr changeRAMdskIRQ(AuxDCEPtr dce, char en, OSErr err) __attribute__ ((section (".text.dskdriver")));
OSErr cNuBusFPGARAMDskCtl(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.dskdriver")));
/* open, close */
OSErr cNuBusFPGARAMDskOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.dskdriver")));

View File

@ -1,5 +1,31 @@
#include "NuBusFPGARAMDskDrvr.h"
OSErr changeRAMDskIRQ(AuxDCEPtr dce, char en, OSErr err) {
struct RAMDrvContext *ctx = *(struct RAMDrvContext**)dce->dCtlStorage;
if (en != ctx->irqen) {
/* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0005); */
/* write_reg(dce, GOBOFB_DEBUG, en); */
if (en) {
if (SIntInstall(ctx->siqel, dce->dCtlSlot)) {
return err;
}
} else {
if (SIntRemove(ctx->siqel, dce->dCtlSlot)) {
return err;
}
}
write_reg(dce, DMA_IRQ_CTL, en ? 0x3 : 0x2); // 0x2: always clear pending interrupt
ctx->irqen = en;
}
return noErr;
}
#pragma parameter __D0 cNuBusFPGARAMDskCtl(__A0, __A1)
OSErr cNuBusFPGARAMDskCtl(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
{

View File

@ -14,6 +14,32 @@ __attribute__ ((section (".text.dskdriver"))) static inline int dupAddDrive(unsi
return num; // should cost nothing, num is already in D0
}
/* see the comment for the FB irq */
#pragma parameter __D0 dskIrq(__A1)
__attribute__ ((section (".text.dskdriver"))) short dskIrq(const long sqParameter) {
register unsigned long p_D1 asm("d1"), p_D2 asm("d2");
AuxDCEPtr dce;
struct RAMDrvContext *ctx;
unsigned int irq;
short ret;
asm volatile("" : "+d" (p_D1), "+d" (p_D2));
dce = (AuxDCEPtr)sqParameter;
ctx = *(struct RAMDrvContext**)dce->dCtlStorage;
ret = 0;
irq = revb(*((volatile unsigned int*)(sqParameter+GOBOFB_BASE+DMA_IRQSTATUS)));
*((volatile unsigned int*)(sqParameter+GOBOFB_BASE+GOBOFB_DEBUG)) = 0x11111111;
*((volatile unsigned int*)(sqParameter+GOBOFB_BASE+GOBOFB_DEBUG)) = irq;
if (irq & 1) {
unsigned int irqctrl = revb(*((volatile unsigned int*)(sqParameter+GOBOFB_BASE+DMA_IRQ_CTL)));
irqctrl |= 0x2; // irq clear
*((volatile unsigned int*)(sqParameter+GOBOFB_BASE+DMA_IRQ_CTL)) = revb(irqctrl);
ret = 1;
}
asm volatile("" : : "d" (p_D1), "d" (p_D2));
return ret;
}
#include <ROMDefs.h>
#pragma parameter __D0 cNuBusFPGARAMDskOpen(__A0, __A1)
@ -123,6 +149,26 @@ OSErr cNuBusFPGARAMDskOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
/* write_reg(dce, GOBOFB_DEBUG, ctx->dma_blk_size_shift); */
/* write_reg(dce, GOBOFB_DEBUG, ctx->dma_blk_base); */
/* write_reg(dce, GOBOFB_DEBUG, ctx->dma_mem_size); */
if (1) {
SlotIntQElement *siqel = (SlotIntQElement *)NewPtrSysClear(sizeof(SlotIntQElement));
if (siqel == NULL) {
return openErr;
}
// disable IRQ for now
write_reg(dce, DMA_IRQ_CTL, 0x2); // 0x1 would enable irq, 0x2 is auto-clear so we make sure there's no spurious IRQ pending
siqel->sqType = sIQType;
siqel->sqPrio = 7;
siqel->sqAddr = dskIrq;
siqel->sqParm = (long)dce;
ctx->siqel = siqel;
ctx->irqen = 0;
write_reg(dce, GOBOFB_DEBUG, siqel);
write_reg(dce, GOBOFB_DEBUG, ctx);
}
#endif
// auto-mount
@ -131,8 +177,6 @@ OSErr cNuBusFPGARAMDskOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
pbr.volumeParam.ioVRefNum = dsptr->dQDrive;
ret = PBMountVol(&pbr);
}
}
SwapMMUMode ( &busMode );
@ -145,13 +189,14 @@ OSErr cNuBusFPGARAMDskOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
OSErr cNuBusFPGARAMDskClose(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
{
OSErr ret = noErr;
//RAMDrvContext *ctx = *(RAMDrvContext**)dce->dCtlStorage;
struct RAMDrvContext *ctx = *(struct RAMDrvContext**)dce->dCtlStorage;
/* dce->dCtlDevBase = 0xfc000000; */
/* write_reg(dce, GOBOFB_DEBUG, 0xDEAD0001); */
if (dce->dCtlStorage) {
//DisposePtr((Ptr)ctx->siqel);
/* HUnlock(dce->dCtlStorage); */ /* not needed before DisposeHandle */
DisposeHandle(dce->dCtlStorage);
dce->dCtlStorage = NULL;

View File

@ -9,36 +9,27 @@ __attribute__ ((section (".text.dskdriver"))) static inline void waitSome(unsign
}
}
typedef struct {
unsigned long blk_todo;
unsigned long blk_done;
unsigned long blk_offset;
unsigned long blk_doing;
void *ioBuffer;
int write;
} ram_dsk_op;
__attribute__ ((section (".text.dskdriver"))) static void startOneOp(const struct RAMDrvContext *ctx, const AuxDCEPtr dce, ram_dsk_op *op) {
if (op->blk_todo > 0) {
op->blk_doing = op->blk_todo;
if (op->blk_doing > 65535) { // fixme: read HW max
op->blk_doing = 32768; // nice Po2
__attribute__ ((section (".text.dskdriver"))) static void startOneOp(struct RAMDrvContext *ctx, const AuxDCEPtr dce) {
if (ctx->op.blk_todo > 0) {
ctx->op.blk_doing = ctx->op.blk_todo;
if (ctx->op.blk_doing > 65535) { // fixme: read HW max
ctx->op.blk_doing = 32768; // nice Po2
}
write_reg(dce, DMA_BLK_ADDR, revb(ctx->dma_blk_base + op->blk_offset));
write_reg(dce, DMA_DMA_ADDR, revb(op->ioBuffer + (op->blk_done << ctx->dma_blk_size_shift)));
write_reg(dce, DMA_BLK_CNT, revb((op->write ? 0x80000000ul : 0x00000000ul) | op->blk_doing));
op->blk_done += op->blk_doing;
op->blk_todo -= op->blk_doing;
op->blk_offset += op->blk_doing;
write_reg(dce, DMA_BLK_ADDR, revb(ctx->dma_blk_base + ctx->op.blk_offset));
write_reg(dce, DMA_DMA_ADDR, revb(ctx->op.ioBuffer + (ctx->op.blk_done << ctx->dma_blk_size_shift)));
write_reg(dce, DMA_BLK_CNT, revb((ctx->op.write ? 0x80000000ul : 0x00000000ul) | ctx->op.blk_doing));
ctx->op.blk_done += ctx->op.blk_doing;
ctx->op.blk_todo -= ctx->op.blk_doing;
ctx->op.blk_offset += ctx->op.blk_doing;
}
}
__attribute__ ((section (".text.dskdriver"))) static OSErr waitForHW(const struct RAMDrvContext *ctx, const AuxDCEPtr dce, ram_dsk_op *op) {
__attribute__ ((section (".text.dskdriver"))) static OSErr waitForHW(struct RAMDrvContext *ctx, const AuxDCEPtr dce) {
unsigned long count, max_count, delay;
unsigned long blk_cnt, status;
OSErr ret = noErr;
max_count = 32 * op->blk_doing;
delay = (op->blk_doing >> 4);
max_count = 32 * ctx->op.blk_doing;
delay = (ctx->op.blk_doing >> 4);
if (delay > 65536)
delay = 65536;
waitSome(delay);
@ -54,7 +45,7 @@ __attribute__ ((section (".text.dskdriver"))) static OSErr waitForHW(const struc
if (status) status = revb(read_reg(dce, DMA_STATUS)) & DMA_STATUS_CHECK_BITS;
}
if (blk_cnt || status) {
ret = op->write ? writErr : readErr;
ret = ctx->op.write ? writErr : readErr;
}
return ret;
}
@ -103,19 +94,18 @@ OSErr cNuBusFPGARAMDskPrime(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
if ((((unsigned long)pb->ioBuffer & ctx->dma_blk_size_mask) == 0) &&
(((unsigned long)pb->ioReqCount & ctx->dma_blk_size_mask) == 0) &&
(((unsigned long)abs_offset & ctx->dma_blk_size_mask) == 0)) {
ram_dsk_op op;
unsigned long blk_cnt, status;
blk_cnt = revb(read_reg(dce, DMA_BLK_CNT)) & 0xFFFF;
status = revb(read_reg(dce, DMA_STATUS)) & DMA_STATUS_CHECK_BITS;
if ((blk_cnt == 0) && (status == 0)) {
op.blk_todo = pb->ioReqCount >> ctx->dma_blk_size_shift;
op.blk_done = 0;
op.blk_offset = abs_offset >> ctx->dma_blk_size_shift;
op.ioBuffer = pb->ioBuffer;
op.write = 0;
while (op.blk_todo > 0) {
startOneOp(ctx, dce, &op);
ret = waitForHW(ctx, dce, &op);
ctx->op.blk_todo = pb->ioReqCount >> ctx->dma_blk_size_shift;
ctx->op.blk_done = 0;
ctx->op.blk_offset = abs_offset >> ctx->dma_blk_size_shift;
ctx->op.ioBuffer = pb->ioBuffer;
ctx->op.write = 0;
while (ctx->op.blk_todo > 0) {
startOneOp(ctx, dce);
ret = waitForHW(ctx, dce);
if (ret != noErr)
goto done;
}
@ -141,19 +131,18 @@ OSErr cNuBusFPGARAMDskPrime(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
if ((((unsigned long)pb->ioBuffer & ctx->dma_blk_size_mask) == 0) &&
(((unsigned long)pb->ioReqCount & ctx->dma_blk_size_mask) == 0) &&
(((unsigned long)abs_offset & ctx->dma_blk_size_mask) == 0)) {
ram_dsk_op op;
unsigned long blk_cnt, status;
blk_cnt = revb(read_reg(dce, DMA_BLK_CNT)) & 0xFFFF;
status = revb(read_reg(dce, DMA_STATUS)) & DMA_STATUS_CHECK_BITS;
if ((blk_cnt == 0) && (status == 0)) {
op.blk_todo = pb->ioReqCount >> ctx->dma_blk_size_shift;
op.blk_done = 0;
op.blk_offset = abs_offset >> ctx->dma_blk_size_shift;
op.ioBuffer = pb->ioBuffer;
op.write = 1;
while (op.blk_todo > 0) {
startOneOp(ctx, dce, &op);
ret = waitForHW(ctx, dce, &op);
ctx->op.blk_todo = pb->ioReqCount >> ctx->dma_blk_size_shift;
ctx->op.blk_done = 0;
ctx->op.blk_offset = abs_offset >> ctx->dma_blk_size_shift;
ctx->op.ioBuffer = pb->ioBuffer;
ctx->op.write = 1;
while (ctx->op.blk_todo > 0) {
startOneOp(ctx, dce);
ret = waitForHW(ctx, dce);
if (ret != noErr)
goto done;
}

View File

@ -557,6 +557,7 @@ class goblin(Module, AutoCSR):
# bt_addr
0x0: [ NextValue(bus.dat_r[low_byte], bt_mode), ],
0x2: [ NextValue(bus.dat_r[low_byte], videoctrl), ],
0x3: [ NextValue(bus.dat_r[low_byte], vbl_signal), ],
"default": [ NextValue(bus.dat_r, 0xDEADBEEF)],
0x10: [ NextValue(bus.dat_r, hres), ], # hres (r/o) # FIXME: endianess
0x11: [ NextValue(bus.dat_r, vres), ], # vres (r/o) # FIXME: endianess

View File

@ -349,6 +349,11 @@ class NuBusFPGA(SoCCore):
self.submodules.tosbus_fifo = ClockDomainsRenamer({"read": "nubus", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(self.tosbus_layout), depth=1024//data_width))
self.submodules.fromsbus_fifo = ClockDomainsRenamer({"write": "nubus", "read": "sys"})(AsyncFIFOBuffered(width=layout_len(self.fromsbus_layout), depth=512//data_width))
self.submodules.fromsbus_req_fifo = ClockDomainsRenamer({"read": "nubus", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(self.fromsbus_req_layout), depth=512//data_width))
irq_line = self.platform.request("nmrq_3v3_n")
fb_irq = Signal()
dma_irq = Signal()
self.comb += irq_line.eq(fb_irq | dma_irq)
self.submodules.exchange_with_mem = ExchangeWithMem(soc=self,
platform=platform,
@ -362,6 +367,8 @@ class NuBusFPGA(SoCCore):
do_checksum = False,
clock_domain="nubus")
self.comb += dma_irq.eq(self.exchange_with_mem.irq)
if (sampling):
self.submodules.nubus = nubus_full_sampling.NuBus(soc=self,
burst_size=burst_size,
@ -388,15 +395,14 @@ class NuBusFPGA(SoCCore):
self.submodules.stat = nubus_stat.NuBusStat(nubus=self.nubus, platform=platform)
self.bus.add_slave("Stat", self.stat.bus_slv, SoCRegion(origin=self.mem_map.get("stat", None), size=0x1000, cached=False))
if (goblin):
if (not hdmi):
self.submodules.videophy = VideoVGAPHY(platform.request("vga"), clock_domain="vga")
self.submodules.goblin = goblin_fb.goblin(soc=self, phy=self.videophy, timings=goblin_res, clock_domain="vga", irq_line=self.platform.request("nmrq_3v3_n"), endian="little", hwcursor=False, truecolor=True) # clock_domain for the VGA side, goblin is running in cd_sys
self.submodules.goblin = goblin_fb.goblin(soc=self, phy=self.videophy, timings=goblin_res, clock_domain="vga", irq_line=fb_irq, endian="little", hwcursor=False, truecolor=True) # clock_domain for the VGA side, goblin is running in cd_sys
else:
self.submodules.videophy = VideoS7HDMIPHY(platform.request("hdmi"), clock_domain="hdmi")
self.submodules.goblin = goblin_fb.goblin(soc=self, phy=self.videophy, timings=goblin_res, clock_domain="hdmi", irq_line=self.platform.request("nmrq_3v3_n"), endian="little", hwcursor=False, truecolor=True) # clock_domain for the HDMI side, goblin is running in cd_sys
self.submodules.goblin = goblin_fb.goblin(soc=self, phy=self.videophy, timings=goblin_res, clock_domain="hdmi", irq_line=fb_irq, endian="little", hwcursor=False, truecolor=True) # clock_domain for the HDMI side, goblin is running in cd_sys
self.bus.add_slave("goblin_bt", self.goblin.bus, SoCRegion(origin=self.mem_map.get("goblin_bt", None), size=0x1000, cached=False))
#pad_user_led_0 = platform.request("user_led", 0)
#pad_user_led_1 = platform.request("user_led", 1)