From 08bbcc21a1b7d1c8b828a39f7318b6d04c78937f Mon Sep 17 00:00:00 2001 From: Romain Dolbeau Date: Sat, 23 Sep 2023 15:46:31 +0200 Subject: [PATCH] move DeclRom from NuBusFPGA to common --- .gitmodules | 3 + DeclROM/.gitignore | 11 + DeclROM/DepVideo.inc | 56 ++ DeclROM/Makefile | 89 +++ DeclROM/NuBusFPGADrvr.h | 157 ++++ DeclROM/NuBusFPGADrvr.s | 23 + DeclROM/NuBusFPGADrvr_Ctrl.c | 513 ++++++++++++ DeclROM/NuBusFPGADrvr_OpenClose.c | 208 +++++ DeclROM/NuBusFPGADrvr_Status.c | 406 ++++++++++ DeclROM/NuBusFPGAPrimaryInit_Primary.c | 157 ++++ DeclROM/NuBusFPGAPrimaryInit_RamInit.c | 660 ++++++++++++++++ DeclROM/NuBusFPGARAMDskDrvr.h | 74 ++ DeclROM/NuBusFPGARAMDskDrvr.s | 23 + DeclROM/NuBusFPGARAMDskDrvr_Ctrl.c | 59 ++ DeclROM/NuBusFPGARAMDskDrvr_OpenClose.c | 185 +++++ DeclROM/NuBusFPGARAMDskDrvr_Prime.c | 350 ++++++++ DeclROM/NuBusFPGARAMDskDrvr_Status.c | 30 + DeclROM/NuBusFPGASDCardDrvr.h | 137 ++++ DeclROM/NuBusFPGASDCardDrvr.s | 23 + DeclROM/NuBusFPGASDCardDrvr_Ctrl.c | 59 ++ DeclROM/NuBusFPGASDCardDrvr_OpenClose.c | 878 +++++++++++++++++++++ DeclROM/NuBusFPGASDCardDrvr_Prime.c | 111 +++ DeclROM/NuBusFPGASDCardDrvr_Status.c | 30 + DeclROM/NuBusFPGASecondaryInit_Secondary.c | 93 +++ DeclROM/ROMDefs.inc | 197 +++++ DeclROM/Video.inc | 358 +++++++++ DeclROM/dump.cpr | Bin 0 -> 2920 bytes DeclROM/gen_mode.c | 288 +++++++ DeclROM/linker.ld | 50 ++ DeclROM/myrle.c | 151 ++++ DeclROM/ns816-declrom | 1 + DeclROM/nubusfpga_csr_common.h | 214 +++++ DeclROM/vid_decl_rom.s | 228 ++++++ 33 files changed, 5822 insertions(+) create mode 100644 .gitmodules create mode 100644 DeclROM/.gitignore create mode 100644 DeclROM/DepVideo.inc create mode 100644 DeclROM/Makefile create mode 100644 DeclROM/NuBusFPGADrvr.h create mode 100644 DeclROM/NuBusFPGADrvr.s create mode 100644 DeclROM/NuBusFPGADrvr_Ctrl.c create mode 100644 DeclROM/NuBusFPGADrvr_OpenClose.c create mode 100644 DeclROM/NuBusFPGADrvr_Status.c create mode 100644 DeclROM/NuBusFPGAPrimaryInit_Primary.c create mode 100644 DeclROM/NuBusFPGAPrimaryInit_RamInit.c create mode 100644 DeclROM/NuBusFPGARAMDskDrvr.h create mode 100644 DeclROM/NuBusFPGARAMDskDrvr.s create mode 100644 DeclROM/NuBusFPGARAMDskDrvr_Ctrl.c create mode 100644 DeclROM/NuBusFPGARAMDskDrvr_OpenClose.c create mode 100644 DeclROM/NuBusFPGARAMDskDrvr_Prime.c create mode 100644 DeclROM/NuBusFPGARAMDskDrvr_Status.c create mode 100644 DeclROM/NuBusFPGASDCardDrvr.h create mode 100644 DeclROM/NuBusFPGASDCardDrvr.s create mode 100644 DeclROM/NuBusFPGASDCardDrvr_Ctrl.c create mode 100644 DeclROM/NuBusFPGASDCardDrvr_OpenClose.c create mode 100644 DeclROM/NuBusFPGASDCardDrvr_Prime.c create mode 100644 DeclROM/NuBusFPGASDCardDrvr_Status.c create mode 100644 DeclROM/NuBusFPGASecondaryInit_Secondary.c create mode 100644 DeclROM/ROMDefs.inc create mode 100644 DeclROM/Video.inc create mode 100755 DeclROM/dump.cpr create mode 100644 DeclROM/gen_mode.c create mode 100644 DeclROM/linker.ld create mode 100644 DeclROM/myrle.c create mode 160000 DeclROM/ns816-declrom create mode 100644 DeclROM/nubusfpga_csr_common.h create mode 100644 DeclROM/vid_decl_rom.s diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1d528de --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "DeclROM/ns816-declrom"] + path = DeclROM/ns816-declrom + url = https://github.com/jaoswald/ns816-declrom diff --git a/DeclROM/.gitignore b/DeclROM/.gitignore new file mode 100644 index 0000000..6581f3f --- /dev/null +++ b/DeclROM/.gitignore @@ -0,0 +1,11 @@ +vid_decl_rom.bin +vid_decl_rom.dir +vid_decl_rom.l +vid_decl_rom.o +vid_decl_rom.raw +vid_decl_rom.srec +*.bin +VidRom* +NuBusFPGADrvr*.s +NuBusFPGARAMDskDrvr*.s +*.o diff --git a/DeclROM/DepVideo.inc b/DeclROM/DepVideo.inc new file mode 100644 index 0000000..9e2a584 --- /dev/null +++ b/DeclROM/DepVideo.inc @@ -0,0 +1,56 @@ +.include "res.inc" + +NuBusFPGAID = 0xC0 + +defMinorBase = 0 /* beginning */ +defMinorLength = 0x800000 /* 8192 KiB */ + +Pages8s = 1 +Pages4s = 1 +Pages2s = 1 +Pages1s = 1 +Pages15s = 1 +Pages24s = 1 + +defmBounds_Ls = 0 +defmBounds_Ts = 0 +defmBounds_Rs = HRES +defmBounds_Bs = VRES + +defScrnRow = HRES + +/* row bytes */ +RB8s = HRES +RB4s = HRES/2 +RB2s = HRES/4 +RB1s = HRES/8 +RB15s = HRES*2 +RB24s = HRES*4 + +DrHwNuBusFPGA = 0xBEEF /* placeholder for GoboFB */ +DrHwNuBusFPGADsk = 0xBEEE /* placeholder for RAM Dsk */ +DrHwNuBusFPGAAudio = 0xBEED /* placeholder for Audio */ +DrHwNuBusFPGASDCard = 0xBEEC /* placeholder for SD Card */ + +typeDrive = 0x1000 /* placeholder for RAM Dsk*/ +typeAudio = 0x1001 /* placeholder for Audio*/ + +defmBaseOffset = 0 /* beginning, placeholder */ + +devVersion = 0 /* placeholder */ + +defmHRes = 0x480000 /* Horizontal Pixels/inch */ +defmVRes = 0x480000 /* Vertical pixels/inch */ + +clutType = 0 +directType = 2 + +defmPlaneBytes = 0 /* Offset from one plane to the next. */ + +SGammaResID = 0 + + +ChunkyIndexed = 0 +ChunkyDirect = 16 + +defVersion = 0 /* Version = 0 */ diff --git a/DeclROM/Makefile b/DeclROM/Makefile new file mode 100644 index 0000000..55cfe01 --- /dev/null +++ b/DeclROM/Makefile @@ -0,0 +1,89 @@ +AS=/home/dolbeau/Retro68/build/toolchain/bin/m68k-apple-macos-as +CC=/home/dolbeau/Retro68/build/toolchain/bin/m68k-apple-macos-gcc +LD=/home/dolbeau/Retro68/build/toolchain/bin/m68k-apple-macos-ld +STRIP=/home/dolbeau/Retro68/build/toolchain/bin/m68k-apple-macos-strip +OBJCOPY=/home/dolbeau/Retro68/build/toolchain/bin/m68k-apple-macos-objcopy +HOSTCC=gcc +HOSTCFLAGS=-O2 + +ARCHFLAGS=-march=68020 -mcpu=68020 +CFLAGS=-O2 -mpcrel +FEATURES= + +TARGET=NUBUSFPGA + +ifeq (${TARGET},NUBUSFPGA) + FEATURES+=-DNUBUSFPGA -DENABLE_RAMDSK -DENABLE_SDCARD -DENABLE_HDMIAUDIO +endif +ifeq (${TARGET},IISIFPGA) + FEATURES+=--DIISIFPGA DENABLE_HDMIAUDIO +endif +ifeq (${TARGET},QUADRAFPGA) + FEATURES+=-DQUADRAFPGA -DENABLE_HDMIAUDIO +endif + +CFLAGS+=${FEATURES} + +NS816DECLROMDIR=./ns816-declrom +NUBUS_CHECKSUM=${NS816DECLROMDIR}/nubus_checksum +PROCESS_ROM=${NS816DECLROMDIR}/process_rom + +APPLEINCS=${NS816DECLROMDIR}/atrap.inc ${NS816DECLROMDIR}/declrom.inc ${NS816DECLROMDIR}/globals.inc + +HRES=1920 +VRES=1080 +QEMU=no +ifeq ($(QEMU),yes) + CFLAGS+=-DQEMU +endif + +CSRC_VIDEO=NuBusFPGADrvr_OpenClose.c NuBusFPGADrvr_Ctrl.c NuBusFPGADrvr_Status.c NuBusFPGAPrimaryInit_Primary.c NuBusFPGAPrimaryInit_RamInit.c NuBusFPGASecondaryInit_Secondary.c +CSRC_RAMDSK=NuBusFPGARAMDskDrvr_OpenClose.c NuBusFPGARAMDskDrvr_Ctrl.c NuBusFPGARAMDskDrvr_Prime.c NuBusFPGARAMDskDrvr_Status.c myrle.c +CSRC_SDCARD=NuBusFPGASDCardDrvr_OpenClose.c NuBusFPGASDCardDrvr_Ctrl.c NuBusFPGASDCardDrvr_Prime.c NuBusFPGASDCardDrvr_Status.c +CSRC=${CSRC_VIDEO} ${CSRC_RAMDSK} ${CSRC_SDCARD} +CSRC_ASM=${CSRC:.c=.s} + +GEN_ASM=VidRomDef.s VidRomDir.s VidRomName.s VidRomRes.s VidRomRsrcDir.s + +all: vid_decl_rom.bin + +gen_mode: gen_mode.c + $(HOSTCC) -Wall ${HOSTCFLAGS} $^ -o $@ + +${GEN_ASM}: gen_mode + ./gen_mode ${HRES} ${VRES} + +$(NUBUS_CHECKSUM): ${NS816DECLROMDIR}/nubus_checksum.cc ${NS816DECLROMDIR}/nubus_crc.cc + g++ -std=c++11 $^ -lglog -lgflags -labsl_strings -o $@ + +vid_decl_rom.o: vid_decl_rom.s NuBusFPGADrvr.s NuBusFPGARAMDskDrvr.s ${APPLEINCS} DepVideo.inc ${GEN_ASM} + rm -f res.inc + echo -e "HRES=${HRES}\nVRES=${VRES}\n" | tee res.inc + ${AS} ${ARCHFLAGS} -I${NS816DECLROMDIR} $< -o $@ -a > vid_decl_rom.l + +myrle.o: myrle.c + ${CC} ${ARCHFLAGS} ${CFLAGS} $< -c -o $@ -DSKIP_MAIN + +dump_cpr.s: dump_cpr.c + ${CC} ${ARCHFLAGS} ${CFLAGS} $< -S -o $@ -DSKIP_MAIN + sed -i -e 's/^\([^a-zA-Z0-9_]*\.globl.*\)/# --- \1/' $@ + sed -i -e 's/\.\(L[0-9][0-9]*\)/.dump_cpr_\1/g' $@ + +%.o: %.c NuBusFPGADrvr.h + ${CC} ${CFLAGS} $< -c -o $@ -DHRES=${HRES} -DVRES=${VRES} + +vid_decl_rom.elf: linker.ld vid_decl_rom.o ${CSRC:.c=.o} # linker script must be first + ${LD} -o $@ -T $^ + +vid_decl_rom.raw: vid_decl_rom.elf + ${OBJCOPY} $^ $@ --input-target=elf32-m68k --output-target=binary + +vid_decl_rom.bin: vid_decl_rom.raw $(NUBUS_CHECKSUM) + ${NUBUS_CHECKSUM} --input_file $< --output_file $@ --output_size 32768 + dd if=dump.cpr of=vid_decl_rom.bin bs=1 conv=notrunc + +clean: + rm -f res.inc ${CSRC_ASM} *.o vid_decl_rom.srec vid_decl_rom.raw vid_decl_rom.dir vid_decl_rom.l VidRom*.s + +append_romdir: append_romdir.c + ${HOSTCC} $< -o $@ diff --git a/DeclROM/NuBusFPGADrvr.h b/DeclROM/NuBusFPGADrvr.h new file mode 100644 index 0000000..fa5969f --- /dev/null +++ b/DeclROM/NuBusFPGADrvr.h @@ -0,0 +1,157 @@ +#ifndef __NUBUSFPGADRVR_H__ +#define __NUBUSFPGADRVR_H__ + +#include +#include +#include +#include +#include +#include + +#define GOBOFB_BASE 0x00900000 +#define GOBOFB_ACCEL 0x00901000 +#define GOBOFB_ACCEL_LE 0x00901800 + +//#define GOBOFB_REG_BASE 0x00900000 +//#define GOBOFB_MEM_BASE 0x00000000 /* remapped to 0x8f800000 by HW */ + +#define GOBOFB_MODE 0x0 +#define GOBOFB_VBL_MASK 0x4 +#define GOBOFB_VIDEOCTRL 0x8 +#define GOBOFB_INTR_CLEAR 0xc +#define GOBOFB_RESET 0x10 +#define GOBOFB_LUT_ADDR 0x14 +#define GOBOFB_LUT 0x18 +#define GOBOFB_DEBUG 0x1c +//#define GOBOFB_CURSOR_LUT 0x20 +//#define GOBOFB_CURSOR_XY 0x24 +#define GOBOFB_HRES 0x40 +#define GOBOFB_VRES 0x44 +#define GOBOFB_HRES_START 0x48 +#define GOBOFB_VRES_START 0x4C +#define GOBOFB_HRES_END 0x50 +#define GOBOFB_VRES_END 0x54 +//#define GOBOFB_MASK_BASE 0x80 +//#define GOBOFB_BITS_BASE 0x100 + +#define GOBOFB_INTR_VBL 0x1 + +// for GOBOFB_MODE +#define GOBOFB_MODE_1BIT 0x0 +#define GOBOFB_MODE_2BIT 0x1 +#define GOBOFB_MODE_4BIT 0x2 +#define GOBOFB_MODE_8BIT 0x3 +#define GOBOFB_MODE_24BIT 0x10 +#define GOBOFB_MODE_15BIT 0x11 + +#define u_int32_t volatile unsigned long +struct goblin_accel_regs { + u_int32_t reg_status; // 0 + u_int32_t reg_cmd; + u_int32_t reg_r5_cmd; + u_int32_t resv0; + u_int32_t reg_width; // 4 + u_int32_t reg_height; + u_int32_t reg_fgcolor; + u_int32_t resv2; + u_int32_t reg_bitblt_src_x; // 8 + u_int32_t reg_bitblt_src_y; + u_int32_t reg_bitblt_dst_x; + u_int32_t reg_bitblt_dst_y; + u_int32_t reg_src_stride; // 12 + u_int32_t reg_dst_stride; + u_int32_t reg_src_ptr; // 14 + u_int32_t reg_dst_ptr; +}; + +// status +#define WORK_IN_PROGRESS_BIT 0 + +// cmd +#define DO_BLIT_BIT 0 // hardwired in goblin_accel.py +#define DO_FILL_BIT 1 // hardwired in goblin_accel.py +#define DO_TEST_BIT 3 // hardwired in goblin_accel.py + +struct MyGammaTbl { + short gVersion; /*gamma version number*/ + short gType; /*gamma data type*/ + short gFormulaSize; /*Formula data size*/ + short gChanCnt; /*number of channels of data*/ + short gDataCnt; /*number of values/channel*/ + short gDataWidth; /*bits/corrected value (data packed to next larger byte size)*/ + char gFormulaData[3][256]; /*data for formulas followed by gamma values*/ +}; + +#define nativeVidMode ((unsigned char)0x80) +/* alternate resolution in 0x81...0x8f */ +#define diskResource ((unsigned char)0x90) + +struct NuBusFPGADriverGlobals { + AuxDCEPtr dce; // unused + SlotIntQElement *siqel; + //unsigned char shadowClut[768]; + unsigned short hres[16]; /* HW max in 0 */ + unsigned short vres[16]; /* HW max in 0 */ + unsigned short curPage; + unsigned char maxMode; + unsigned char curMode; /* mode ; this is resolution (which can't be changed in 7.1 except via reboot ?) */ + unsigned char curDepth; /* depth */ + char gray; + char irqen; + char slot; + struct MyGammaTbl gamma; +}; +typedef struct NuBusFPGADriverGlobals NuBusFPGADriverGlobals; +typedef struct NuBusFPGADriverGlobals *NuBusFPGADriverGlobalsPtr; +typedef struct NuBusFPGADriverGlobals **NuBusFPGADriverGlobalsHdl; + +typedef struct NuBusFPGAPramRecord { /* slot parameter RAM record, derived from SPRAMRecord */ + short boardID; /* Apple-defined card ID */ + char vendorUse1; /* reserved for vendor use */ /* DCDMF3 p210 says reserved for system ... */ + unsigned char mode; /* vendorUse2 */ + unsigned char depth; /* vendorUse3 */ + unsigned char page; /* vendorUse4 */ + char vendorUse5; /* reserved for vendor use */ + char vendorUse6; /* reserved for vendor use */ +} NuBusFPGAPramRecord; +typedef struct NuBusFPGAPramRecord *NuBusFPGAPramRecordPtr; + +static inline void write_reg(AuxDCEPtr dce, unsigned int reg, unsigned int val) { + *((volatile unsigned int*)(dce->dCtlDevBase+GOBOFB_BASE+reg)) = val; +} +static inline unsigned int read_reg(AuxDCEPtr dce, unsigned int reg) { + return *((volatile unsigned int*)(dce->dCtlDevBase+GOBOFB_BASE+reg));; +} + +/* ASM */ +extern SlotIntServiceProcPtr interruptRoutine; +/* ctrl */ +void linearGamma(NuBusFPGADriverGlobalsPtr dStore) __attribute__ ((section (".text.fbdriver"))); +OSErr changeIRQ(AuxDCEPtr dce, char en, OSErr err) __attribute__ ((section (".text.fbdriver"))); +OSErr cNuBusFPGACtl(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.fbdriver"))); +OSErr reconfHW(AuxDCEPtr dce, unsigned char mode, unsigned char depth, unsigned short page) __attribute__ ((section (".text.fbdriver"))); +OSErr updatePRAM(AuxDCEPtr dce, unsigned char mode, unsigned char depth, unsigned short page) __attribute__ ((section (".text.fbdriver"))); +/* status */ +OSErr cNuBusFPGAStatus(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.fbdriver"))); +/* open close */ +OSErr cNuBusFPGAOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.fbdriver"))); +OSErr cNuBusFPGAClose(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.fbdriver"))); + +/* primary init */ +UInt32 Primary(SEBlock* block) __attribute__ ((section (".text.primary"))); +int sdram_init(uint32_t a32) __attribute__ ((section (".text.primary"))); +/* secondary init */ +UInt32 Secondary(SEBlock* seblock) __attribute__ ((section (".text.secondary"))); + +#define Check32QDTrap 0xAB03 + +#if 0 +static inline UInt32 revb(UInt32 d) { + return ((d&0xFFul)<<24) | ((d&0xFF00ul)<<8) | ((d&0xFF0000ul)>>8) | ((d&0xFF000000ul)>>24); +} +#else +#define revb(a) __builtin_bswap32(a) +#endif + +#endif + diff --git a/DeclROM/NuBusFPGADrvr.s b/DeclROM/NuBusFPGADrvr.s new file mode 100644 index 0000000..b93afbe --- /dev/null +++ b/DeclROM/NuBusFPGADrvr.s @@ -0,0 +1,23 @@ +NuBusFPGADrvr: + .word 0x4c00 /* 0x4c00: ctl, status, needsLock [Devices.a] */ + .word 0 + .word 0 + .word 0 + /* Entry point offset table */ + /* we can directly call the C version if it has the right calling convention */ + .word cNuBusFPGAOpen-NuBusFPGADrvr /* open routine */ + .word NuBusFPGADrvr-NuBusFPGADrvr /* no prime */ + .word cNuBusFPGACtl-NuBusFPGADrvr /* control */ + .word cNuBusFPGAStatus-NuBusFPGADrvr /* status */ + .word cNuBusFPGAClose-NuBusFPGADrvr /* close */ + +_NuBusFPGATitle: + .byte _NuBusFPGATitle_StringEnd-.-1 /* pascal string length */ + .ascii ".NuBusFPGA_Drvr" +_NuBusFPGATitle_StringEnd: + .word 0 /* version number */ + + /* for entry points: */ + /* A0 pointer to driver parameter block */ + /* A1 pointer to driver device control entry */ + ALIGN 2 diff --git a/DeclROM/NuBusFPGADrvr_Ctrl.c b/DeclROM/NuBusFPGADrvr_Ctrl.c new file mode 100644 index 0000000..3b42e7c --- /dev/null +++ b/DeclROM/NuBusFPGADrvr_Ctrl.c @@ -0,0 +1,513 @@ +#include "NuBusFPGADrvr.h" + +void linearGamma(NuBusFPGADriverGlobalsPtr dStore) { + int i; + dStore->gamma.gVersion = 0; + dStore->gamma.gType = 0; + dStore->gamma.gFormulaSize = 0; + dStore->gamma.gChanCnt = 3; + dStore->gamma.gDataCnt = 256; + dStore->gamma.gDataWidth = 8; + for (i = 0 ; i < 256 ; i++) { + dStore->gamma.gFormulaData[0][i] = i; + dStore->gamma.gFormulaData[1][i] = i; + dStore->gamma.gFormulaData[2][i] = i; + } +} + +OSErr changeIRQ(AuxDCEPtr dce, char en, OSErr err) { + NuBusFPGADriverGlobalsHdl dStoreHdl = (NuBusFPGADriverGlobalsHdl)dce->dCtlStorage; + NuBusFPGADriverGlobalsPtr dStore = *dStoreHdl; + char busMode = 1; + if (en != dStore->irqen) { + /* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0005); */ + /* write_reg(dce, GOBOFB_DEBUG, en); */ + + if (en) { + if (SIntInstall(dStore->siqel, dce->dCtlSlot)) { + return err; + } + write_reg(dce, GOBOFB_DEBUG, 0x88888888); + write_reg(dce, GOBOFB_DEBUG, dStore->siqel); + write_reg(dce, GOBOFB_DEBUG, dStore->siqel->sqLink); + } else { + if (SIntRemove(dStore->siqel, dce->dCtlSlot)) { + return err; + } + } + + SwapMMUMode ( &busMode ); + write_reg(dce, GOBOFB_VBL_MASK, en ? GOBOFB_INTR_VBL : 0); + SwapMMUMode ( &busMode ); + dStore->irqen = en; + } + return noErr; +} + +/* + 7.1.1: + 11 Debug: 0x00000003 + 2 Debug: 0x00000004 + 1 Debug: 0x00000005 + 4 Debug: 0x00000006 + 1 �Debug: 0x00000002 + + 7.5.3: + 4 Debug: 0x00000002 + 12 Debug: 0x00000003 + 3 Debug: 0x00000004 + 5 Debug: 0x00000005 + 5 Debug: 0x00000006 + 5 Debug: 0x00000009 + 4 Debug: 0x0000000a + 5 Debug: 0x00000010 + 1 �Debug: 0x00000002 + + 8.1: + 5 Debug: 0x00000002 + 9 Debug: 0x00000003 + 1 Debug: 0x00000004 + 6 Debug: 0x00000005 + 6 Debug: 0x00000006 + 4 Debug: 0x00000009 + 5 Debug: 0x0000000a + 4 Debug: 0x00000010 + 1 �Debug: 0x00000002 +*/ + +#pragma parameter __D0 cNuBusFPGACtl(__A0, __A1) +OSErr cNuBusFPGACtl(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + NuBusFPGADriverGlobalsHdl dStoreHdl = (NuBusFPGADriverGlobalsHdl)dce->dCtlStorage; + NuBusFPGADriverGlobalsPtr dStore = *dStoreHdl; + + short ret = -1; + char busMode = 1; + + /* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0001); */ + /* write_reg(dce, GOBOFB_DEBUG, pb->csCode); */ + + switch (pb->csCode) + { + case -1: + asm volatile(".word 0xfe16\n"); + break; + case cscReset: /* 0x0 */ + { + VDPageInfo *vPInfo = (VDPageInfo *)*(long *)pb->csParam; + dStore->curMode = nativeVidMode; + dStore->curDepth = kDepthMode1; /* 8-bit */ + vPInfo->csMode = nativeVidMode; + vPInfo->csPage = 0; + vPInfo->csBaseAddr = 0; + ret = noErr; + } + break; + case cscKillIO: /* 0x1 */ + asm volatile(".word 0xfe16\n"); + ret = noErr; + break; + case cscSetMode: /* 0x2 */ + { + VDPageInfo *vPInfo = (VDPageInfo *)*(long *)pb->csParam; + + ret = reconfHW(dce, dStore->curMode, vPInfo->csMode, vPInfo->csPage); + + if (ret == noErr) + vPInfo->csBaseAddr = (void*)(vPInfo->csPage * 1024 * 1024 * 4); + } + break; + case cscSetEntries: /* 0x3 */ + if (1) { + VDSetEntryRecord **vdentry = (VDSetEntryRecord **)(long *)pb->csParam; + int csCount = (*vdentry)->csCount; + int csStart = (*vdentry)->csStart; + int i; + if (csCount <= 0) { + ret = noErr; + goto cscSetMode_done; + } + SwapMMUMode ( &busMode ); + if (csStart < 0) { + for (i = 0 ; i <= csCount ; i++) { + unsigned char idx = ((*vdentry)->csTable[i].value & 0x0FF); + /* dStore->shadowClut[idx*3+0] = (*vdentry)->csTable[i].rgb.red; */ + /* dStore->shadowClut[idx*3+1] = (*vdentry)->csTable[i].rgb.green; */ + /* dStore->shadowClut[idx*3+2] = (*vdentry)->csTable[i].rgb.blue; */ + + write_reg(dce, GOBOFB_LUT_ADDR, 3 * idx); + write_reg(dce, GOBOFB_LUT, dStore->gamma.gFormulaData[0][(*vdentry)->csTable[i].rgb.red>>8 & 0xFF]); + write_reg(dce, GOBOFB_LUT, dStore->gamma.gFormulaData[1][(*vdentry)->csTable[i].rgb.green>>8 & 0xFF]); + write_reg(dce, GOBOFB_LUT, dStore->gamma.gFormulaData[2][(*vdentry)->csTable[i].rgb.blue>>8 & 0xFF]); + /* write_reg(dce, GOBOFB_LUT, (*vdentry)->csTable[i].rgb.red); */ + /* write_reg(dce, GOBOFB_LUT, (*vdentry)->csTable[i].rgb.green); */ + /* write_reg(dce, GOBOFB_LUT, (*vdentry)->csTable[i].rgb.blue); */ + } + } else { + write_reg(dce, GOBOFB_LUT_ADDR, 3 * (csStart & 0xFF)); + for (i = 0 ; i <= csCount ; i++) { + /* dStore->shadowClut[(i+csStart)*3+0] = (*vdentry)->csTable[i].rgb.red; */ + /* dStore->shadowClut[(i+csStart)*3+1] = (*vdentry)->csTable[i].rgb.green; */ + /* dStore->shadowClut[(i+csStart)*3+2] = (*vdentry)->csTable[i].rgb.blue; */ + + write_reg(dce, GOBOFB_LUT, dStore->gamma.gFormulaData[0][(*vdentry)->csTable[i].rgb.red>>8 & 0xFF]); + write_reg(dce, GOBOFB_LUT, dStore->gamma.gFormulaData[1][(*vdentry)->csTable[i].rgb.green>>8 & 0xFF]); + write_reg(dce, GOBOFB_LUT, dStore->gamma.gFormulaData[2][(*vdentry)->csTable[i].rgb.blue>>8 & 0xFF]); + /* write_reg(dce, GOBOFB_LUT, (*vdentry)->csTable[i].rgb.red); */ + /* write_reg(dce, GOBOFB_LUT, (*vdentry)->csTable[i].rgb.green); */ + /* write_reg(dce, GOBOFB_LUT, (*vdentry)->csTable[i].rgb.blue); */ + } + } + SwapMMUMode ( &busMode ); + ret = noErr; + } else { + ret = noErr; + } + cscSetMode_done: + break; + case cscSetGamma: /* 0x4 */ + { + VDGammaRecord *vdgamma = (VDGammaRecord *)*(long *)pb->csParam; + GammaTbl *gammaTbl = (GammaTbl*)vdgamma->csGTable; + int i; + if (gammaTbl == NULL) { + linearGamma(dStore); + } else { + ret = noErr; + if (gammaTbl->gDataWidth != 8) + ret = paramErr; + if (gammaTbl->gDataCnt != 256) // 8-bits + ret = paramErr; + if ((gammaTbl->gChanCnt != 1) && (gammaTbl->gChanCnt != 3)) + ret = paramErr; + if ((gammaTbl->gType != 0) && (gammaTbl->gType != 0xFFFFBEEF)) + ret = paramErr; + if (gammaTbl->gFormulaSize != 0) + ret = paramErr; + if (ret != noErr) + goto done; + + dStore->gamma.gVersion = gammaTbl->gVersion; + dStore->gamma.gType = gammaTbl->gType; + dStore->gamma.gFormulaSize = gammaTbl->gFormulaSize; + dStore->gamma.gChanCnt = gammaTbl->gChanCnt; + dStore->gamma.gDataCnt = gammaTbl->gDataCnt; + dStore->gamma.gDataWidth = gammaTbl->gDataWidth; + + int og, ob; + if (gammaTbl->gChanCnt == 1) + og = ob = 0; + else { + og = 256; + ob = 512; + } + for (i = 0 ; i < gammaTbl->gDataCnt ; i++) { + dStore->gamma.gFormulaData[0][i] = ((unsigned char*)gammaTbl->gFormulaData)[i + 0]; + dStore->gamma.gFormulaData[1][i] = ((unsigned char*)gammaTbl->gFormulaData)[i + og]; + dStore->gamma.gFormulaData[2][i] = ((unsigned char*)gammaTbl->gFormulaData)[i + ob]; + } + } + ret = noErr; + } + break; + case cscGrayPage: /* 0x5 == cscGrayScreen */ + { + VDPageInfo *vPInfo = (VDPageInfo *)*(long *)pb->csParam; + const uint8_t idx = dStore->curMode % 4; // checkme + UInt32 a32 = dce->dCtlDevBase; + UInt32 a32_l0, a32_l1; + UInt32 a32_4p0, a32_4p1; + const uint32_t wb = dStore->hres[0] >> idx; + unsigned short j, i; + short npage = (vPInfo->csMode == kDepthMode5) ? 1 : 2; + if (vPInfo->csPage >= npage) { + return paramErr; + goto done; + } + + a32 += vPInfo->csPage * 1024 * 1024 * 4; /* fixme */ + + SwapMMUMode ( &busMode ); +#if 0 + if ((dStore->curMode != kDepthMode5) && (dStore->curMode != kDepthMode6)) { + /* grey the screen */ + a32_l0 = a32; + a32_l1 = a32 + wb; + for (j = 0 ; j < dStore->vres[0] ; j+= 2) { + a32_4p0 = a32_l0; + a32_4p1 = a32_l1; + for (i = 0 ; i < wb ; i += 4) { + *((UInt32*)a32_4p0) = 0xFF00FF00; + *((UInt32*)a32_4p1) = 0x00FF00FF; + a32_4p0 += 4; + a32_4p1 += 4; + } + a32_l0 += 2*wb; + a32_l1 += 2*wb; + } + } else { + /* testing */ + a32_l0 = a32; + a32_l1 = a32 + dStore->hres[0]*4; + for (j = 0 ; j < dStore->vres[0] ; j+= 2) { + a32_4p0 = a32_l0; + a32_4p1 = a32_l1; + for (i = 0 ; i < dStore->hres[0] ; i ++ ) { + *((UInt32*)a32_4p0) = (i&0xFF);//(i&0xFF) | (i&0xFF)<<8 | (i&0xff)<<24; + *((UInt32*)a32_4p1) = (i&0xFF)<<16;//(i&0xFF) | (i&0xFF)<<8 | (i&0xff)<<24; + a32_4p0 += 4; + a32_4p1 += 4; + } + a32_l0 += 2*dStore->hres[0]*4; + a32_l1 += 2*dStore->hres[0]*4; + } + } +#else + +#define WAIT_FOR_HW_LE(accel_le) \ + while (accel_le->reg_status & (1<dCtlDevBase+GOBOFB_ACCEL_LE); + WAIT_FOR_HW_LE(accel_le); + accel_le->reg_width = dStore->hres[dStore->curMode - nativeVidMode]; // pixels + accel_le->reg_height = dStore->vres[dStore->curMode - nativeVidMode]; + accel_le->reg_bitblt_dst_x = 0; // pixels + accel_le->reg_bitblt_dst_y = 0; + accel_le->reg_dst_ptr = 0; + accel_le->reg_fgcolor = fgcolor; + accel_le->reg_cmd = (1<csParam; + dStore->gray = vGInfo->csMode; + ret = noErr; + } + break; + + case cscSetInterrupt: /* 0x7 */ + { + VDFlagRecord *vdflag = (VDFlagRecord *)*(long *)pb->csParam; + ret = changeIRQ(dce, 1 - vdflag->csMode, controlErr); + } + break; + + case cscDirectSetEntries: /* 0x8 */ + asm volatile(".word 0xfe16\n"); + ret = controlErr; + break; + + case cscSetDefaultMode: /* 0x9 */ + { + VDDefMode *vddefm = (VDDefMode *)*(long *)pb->csParam; + + ret = updatePRAM(dce, vddefm->csID, dStore->curDepth, 0); + } + break; + + case cscSwitchMode: /* 0xa */ + { + VDSwitchInfoRec *vdswitch = *(VDSwitchInfoRec **)(long *)pb->csParam; + + ret = reconfHW(dce, vdswitch->csData, vdswitch->csMode, vdswitch->csPage); + + if (ret == noErr) + vdswitch->csBaseAddr = (void*)(vdswitch->csPage * 1024 * 1024 * 4); + } + break; + + /* cscSetSync */ /* 0xb */ + /* 0xc ... 0xf : undefined */ + + case cscSavePreferredConfiguration: /* 0x10 */ + { + VDSwitchInfoRec *vdswitch = *(VDSwitchInfoRec **)(long *)pb->csParam; + + ret = updatePRAM(dce, vdswitch->csData, vdswitch->csMode, 0); + } + break; + + /* 0x11 .. 0x15 : undefined */ + + /* cscSetHardwareCursor */ /* 0x16 */ + /* cscDrawHardwareCursor */ /* 0x17 */ + /* cscSetConvolution */ /* 0x18 */ + /* cscSetPowerState */ /* 0x19 */ + /* cscPrivateControlCall */ /* 0x1a */ + /* 0x1b : undefined */ + /* cscSetMultiConnect */ /* 0x1c */ + /* cscSetClutBehavior */ /* 0x1d */ + /* 0x1e : undefined */ + /* cscSetDetailedTiming */ /* 0x1f */ + /* 0x20 : undefined */ + /* cscDoCommunication */ /* 0x21 */ + /* cscProbeConnection */ /* 0x22 */ + + default: /* always return controlErr for unknown csCode */ + asm volatile(".word 0xfe16\n"); + ret = controlErr; + break; + } + + done: + if (!(pb->ioTrap & (1<dCtlStorage; + NuBusFPGADriverGlobalsPtr dStore = *dStoreHdl; + const short npage = (depth == kDepthMode5) ? 1 : 2; + OSErr err = noErr; + char busMode = 1; + + /* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0031); */ + /* write_reg(dce, GOBOFB_DEBUG, mode); */ + /* write_reg(dce, GOBOFB_DEBUG, depth); */ + /* write_reg(dce, GOBOFB_DEBUG, page); */ + + if ((mode == dStore->curMode) && + (depth == dStore->curDepth) && + (page == dStore->curPage)) { + return noErr; + } + + if (page >= npage) + return paramErr; + + if ((mode < nativeVidMode) || + (mode > dStore->maxMode)) + return paramErr; + + switch (depth) { + case kDepthMode1: + break; + case kDepthMode2: + break; + case kDepthMode3: + break; + case kDepthMode4: + break; + case kDepthMode5: + break; + case kDepthMode6: + break; + default: + return paramErr; + } + + SwapMMUMode ( &busMode ); + if (mode != dStore->curMode) { + unsigned short i; + for (i = nativeVidMode ; i <= dStore->maxMode ; i++) { + // disable spurious resources, enable only the right one + SpBlock spb; + spb.spParamData = (i != mode ? 1 : 0); /* disable/enable */ + spb.spSlot = dStore->slot; + spb.spID = i; + spb.spExtDev = 0; + SetSRsrcState(&spb); + } + dce->dCtlSlotId = mode; // where is that explained ? cscSwitchMode is not in DCDMF3, and you should'nt do that anymore says PDCD... + + UInt8 id = mode - nativeVidMode; + unsigned int ho = ((dStore->hres[0] - dStore->hres[id]) / 2); + unsigned int vo = ((dStore->vres[0] - dStore->vres[id]) / 2); + /* write_reg(dce, GOBOFB_VIDEOCTRL, 0); */ + write_reg(dce, GOBOFB_HRES_START, __builtin_bswap32(ho)); + write_reg(dce, GOBOFB_VRES_START, __builtin_bswap32(vo)); + write_reg(dce, GOBOFB_HRES_END, __builtin_bswap32(ho + dStore->hres[id])); + write_reg(dce, GOBOFB_VRES_END, __builtin_bswap32(vo + dStore->vres[id])); + /* write_reg(dce, GOBOFB_VIDEOCTRL, 1); */ + } + if (depth != dStore->curDepth) { + switch (depth) { + case kDepthMode1: + write_reg(dce, GOBOFB_MODE, GOBOFB_MODE_8BIT); + break; + case kDepthMode2: + write_reg(dce, GOBOFB_MODE, GOBOFB_MODE_4BIT); + break; + case kDepthMode3: + write_reg(dce, GOBOFB_MODE, GOBOFB_MODE_2BIT); + break; + case kDepthMode4: + write_reg(dce, GOBOFB_MODE, GOBOFB_MODE_1BIT); + break; + case kDepthMode5: + write_reg(dce, GOBOFB_MODE, GOBOFB_MODE_24BIT); + break; + case kDepthMode6: + write_reg(dce, GOBOFB_MODE, GOBOFB_MODE_15BIT); + break; + default: + SwapMMUMode ( &busMode ); + return paramErr; + } + } + dStore->curMode = mode; + dStore->curDepth = depth; + dStore->curPage = page; /* FIXME: HW */ + + SwapMMUMode ( &busMode ); + + return err; +} + +OSErr updatePRAM(AuxDCEPtr dce, unsigned char mode, unsigned char depth, unsigned short page) { + NuBusFPGADriverGlobalsHdl dStoreHdl = (NuBusFPGADriverGlobalsHdl)dce->dCtlStorage; + NuBusFPGADriverGlobalsPtr dStore = *dStoreHdl; + const short npage = (depth == kDepthMode5) ? 1 : 2; + SpBlock spb; + NuBusFPGAPramRecord pram; + OSErr err; + + if (page >= npage) + return paramErr; + + if ((mode < nativeVidMode) || + (mode > dStore->maxMode)) + return paramErr; + + switch (depth) { + case kDepthMode1: + break; + case kDepthMode2: + break; + case kDepthMode3: + break; + case kDepthMode4: + break; + case kDepthMode5: + break; + case kDepthMode6: + break; + default: + return paramErr; + } + + spb.spSlot = dce->dCtlSlot; + spb.spResult = (UInt32)&pram; + err = SReadPRAMRec(&spb); + if (err == noErr) { + pram.mode = mode; + pram.depth = depth; + pram.page = page; + spb.spSlot = dce->dCtlSlot; + spb.spsPointer = &pram; + err = SPutPRAMRec(&spb); + } + return err; +} diff --git a/DeclROM/NuBusFPGADrvr_OpenClose.c b/DeclROM/NuBusFPGADrvr_OpenClose.c new file mode 100644 index 0000000..6ad3db1 --- /dev/null +++ b/DeclROM/NuBusFPGADrvr_OpenClose.c @@ -0,0 +1,208 @@ +#include "NuBusFPGADrvr.h" + +#include "ROMDefs.h" + +typedef void(*vblproto)(short); + +/* how do I tell it to only modify D0 & A1 ? */ +/* the ABI allows to modify D0-D2 & A0-A1 (caller save) */ +/* currently this is clobbering A0 yet seems to work ... */ +/* 'Devices' p1-37 says of interrupt handler "preserving all registers other than D0 through D3 and A0 through A3" + * but that for NuBus you see SIntInstall which says (2-70) + * "routine must preserve the contents of all registers except A1 and D0" + * yet the interrupt handler for the video card driver example in DCDMF3 p589 clobbers A0 + */ +#pragma parameter __D0 fbIrq(__A1) +__attribute__ ((section (".text.fbdriver"))) short fbIrq(const long sqParameter) { + 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 & 1) { + 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) +OSErr cNuBusFPGAOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + OSErr ret = noErr; + /* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0000); */ + /* write_reg(dce, GOBOFB_DEBUG, (unsigned long)dce->dCtlDevBase); */ + + if (dce->dCtlStorage == nil) + { + int i; + /* set up flags in the device control entry */ + /* dce->dCtlFlags |= (dCtlEnableMask | dStatEnableMask | dWritEnableMask | + dReadEnableMask | dNeedLockMask | dRAMBasedMask ); */ + + /* initialize dCtlStorage */ + ReserveMemSys(sizeof(NuBusFPGADriverGlobals)); + dce->dCtlStorage = NewHandleSysClear(sizeof(NuBusFPGADriverGlobals)); + if (dce->dCtlStorage == nil) + return(openErr); + HLock(dce->dCtlStorage); + NuBusFPGADriverGlobalsHdl dStoreHdl = (NuBusFPGADriverGlobalsHdl)dce->dCtlStorage; + NuBusFPGADriverGlobalsPtr dStore = *dStoreHdl; + /* (*dStore)->dce = dce; */ + + /* for (i = 0 ; i < 256 ; i++) { */ + /* dStore->shadowClut[i*3+0] = i; */ + /* dStore->shadowClut[i*3+1] = i; */ + /* dStore->shadowClut[i*3+2] = i; */ + /* } */ + + dStore->gray = 0; + dStore->irqen = 0; + dStore->slot = dce->dCtlSlot; + + /* initialize DRAM controller */ + //sdram_init(0xF0000000 | (((unsigned long)dStore->slot) << 24)); + + /* Get the HW setting for native resolution */ + dStore->hres[0] = __builtin_bswap32((unsigned int)read_reg(dce, GOBOFB_HRES)); // fixme: endianness + dStore->vres[0] = __builtin_bswap32((unsigned int)read_reg(dce, GOBOFB_VRES)); // fixme: endianness + + SlotIntQElement *siqel = (SlotIntQElement *)NewPtrSysClear(sizeof(SlotIntQElement)); + if (siqel == NULL) { + return openErr; + } + siqel->sqType = sIQType; + siqel->sqPrio = 8; + //siqel->sqAddr = interruptRoutine; + /* not sure how to get the proper result in C... */ + /* SlotIntServiceProcPtr sqAddr; */ + /* asm("lea %%pc@(interruptRoutine),%0\n" : "=a"(sqAddr)); */ + /* siqel->sqAddr = sqAddr; */ + /* siqel->sqParm = (long)dce->dCtlDevBase; */ + + /* not sure how to get the proper result in C... */ + /* ... from ~mac68k, you need option "-mpcrel", and it works */ + /* SlotIntServiceProcPtr sqAddr; */ + /* asm("lea %%pc@(fbIrq),%0\n" : "=a"(sqAddr)); */ + siqel->sqAddr = fbIrq; + /* siqel->sqParm = (long)dce; */ + siqel->sqParm = (long)dce->dCtlDevBase; + dStore->siqel = siqel; + + dStore->curPage = 0; + dStore->curMode = nativeVidMode; + dStore->curDepth = kDepthMode1; + + { + OSErr err = noErr; + SpBlock spb; + UInt8 max = nativeVidMode; + + spb.spParamData = 1<dCtlSlot; + spb.spID = nativeVidMode; + spb.spExtDev = 0; + err = SGetTypeSRsrc(&spb); + while ((err == noErr) && + (spb.spSlot == dce->dCtlSlot) && + (((UInt8)spb.spID) > (UInt8)0x80) && + (((UInt8)spb.spID) < (UInt8)0x90)) { + /* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0020); */ + /* write_reg(dce, GOBOFB_DEBUG, spb.spID); */ + /* write_reg(dce, GOBOFB_DEBUG, err); */ + + if (((UInt8)spb.spID) == max) // should not happen + err = smNoMoresRsrcs; + if (((UInt8)spb.spID) > max) + max = spb.spID; + err = SGetTypeSRsrc(&spb); + } + dStore->maxMode = max; + } + /* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0000); */ + /* write_reg(dce, GOBOFB_DEBUG, dStore->maxMode); */ + { + OSErr err = noErr; + SpBlock spb; + /* check for resolution */ + UInt8 id; + for (id = nativeVidMode; id <= dStore->maxMode ; id ++) { + /* try every resource, enabled or not */ + spb.spParamData = 1<dCtlSlot; + spb.spID = id; + spb.spExtDev = 0; + err = SGetSRsrc(&spb); + + if (err == noErr) { + spb.spID = kDepthMode1; + err = SFindStruct(&spb); /* that will give us the Parms block ... */ + + if (err == noErr) { + /* take the Parms pointer, add the offset to the Modes block and then skip the block size at the beginning to get the structure pointer ... */ + const unsigned long offset = *(unsigned long*)spb.spsPointer & 0x00FFFFFF; + VPBlockPtr vpblock = (VPBlockPtr)(spb.spsPointer + offset + sizeof(long)); + UInt8 idx = id - nativeVidMode; + dStore->hres[idx] = vpblock->vpBounds.right; + dStore->vres[idx] = vpblock->vpBounds.bottom; + } + } + } + + } + + linearGamma(dStore); + + /* now check the content of PRAM */ + if (0) { + SpBlock spb; + NuBusFPGAPramRecord pram; + OSErr err; + spb.spSlot = dce->dCtlSlot; + spb.spResult = (UInt32)&pram; + err = SReadPRAMRec(&spb); + if (err == noErr) { + err = reconfHW(dce, pram.mode, pram.depth, pram.page); + } + } + + write_reg(dce, GOBOFB_VIDEOCTRL, 1); + + ret = changeIRQ(dce, 1, openErr); + } + + return noErr; +} + +#pragma parameter __D0 cNuBusFPGAClose(__A0, __A1) +OSErr cNuBusFPGAClose(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + OSErr ret = noErr; + /* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0003); */ + /* write_reg(dce, GOBOFB_DEBUG, 0x0000DEAD); */ + asm(".word 0xfe16\n"); + if (dce->dCtlStorage != nil) + { + ret = changeIRQ(dce, 0, openErr); + write_reg(dce, GOBOFB_VIDEOCTRL, 0); + DisposePtr((Ptr)(*(NuBusFPGADriverGlobalsHdl)dce->dCtlStorage)->siqel); + DisposeHandle(dce->dCtlStorage); + dce->dCtlStorage = nil; + } + return ret; +} + diff --git a/DeclROM/NuBusFPGADrvr_Status.c b/DeclROM/NuBusFPGADrvr_Status.c new file mode 100644 index 0000000..9a56f1b --- /dev/null +++ b/DeclROM/NuBusFPGADrvr_Status.c @@ -0,0 +1,406 @@ +#include "NuBusFPGADrvr.h" + +/* + 7.1: + 2 Debug: 0x00000009 + 1 �Debug: 0x00000009 + + + 7.5.3: + 6 Debug: 0x00000008 + 112 Debug: 0x0000000a + 32 Debug: 0x0000000c + 14 Debug: 0x0000000d + 3 Debug: 0x0000000e + 4 Debug: 0x00000010 + 2 Debug: 0x00000011 + 78 Debug: 0x00000012 + 1 Debug: 0x00000014 + 1 �Debug: 0x0000000a + + 8.1: + 9 Debug: 0x00000008 + 273 Debug: 0x0000000a + 156 Debug: 0x0000000c + 16 Debug: 0x0000000d + 3 Debug: 0x00000010 + 3 Debug: 0x00000011 + 157 Debug: 0x00000012 + 1 Debug: 0x00000014 + 2 Debug: 0x00000018 + 10 Debug: 0x0000001c + 1 �Debug: 0x0000000c +*/ + +#pragma parameter __D0 cNuBusFPGAStatus(__A0, __A1) +OSErr cNuBusFPGAStatus(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + NuBusFPGADriverGlobalsHdl dStoreHdl = (NuBusFPGADriverGlobalsHdl)dce->dCtlStorage; + NuBusFPGADriverGlobalsPtr dStore = *dStoreHdl; + short ret = -1; + + /* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0002); */ + /* write_reg(dce, GOBOFB_DEBUG, pb->csCode); */ + +#if 1 + switch (pb->csCode) + { + case -1: + asm volatile(".word 0xfe16\n"); + break; + case 0: + ret = statusErr; + break; + /* case 1: */ + /* break; */ + case cscGetMode: /* 2 */ + { + VDPageInfo *vPInfo = (VDPageInfo *)*(long *)pb->csParam; + vPInfo->csMode = dStore->curDepth; /* checkme: PCI says depth, 7.5+ doesn't call anyway? */ + vPInfo->csPage = dStore->curPage; + vPInfo->csBaseAddr = (Ptr)(dStore->curPage * 1024 * 1024 * 4); /* fixme */ + ret = noErr; + } + break; + case cscGetEntries: /* 3 */ + /* FIXME: TODO */ + /* never called in >= 7.1 ? */ + asm volatile(".word 0xfe16\n"); + ret = noErr; + break; + case cscGetPageCnt: /* 4 == cscGetPages */ + { + VDPageInfo *vPInfo = (VDPageInfo *)*(long *)pb->csParam; + if ((vPInfo->csMode != kDepthMode1) && + (vPInfo->csMode != kDepthMode2) && + (vPInfo->csMode != kDepthMode3) && + (vPInfo->csMode != kDepthMode4) && + (vPInfo->csMode != kDepthMode5) && + (vPInfo->csMode != kDepthMode6)) { + ret = paramErr; + goto done; + } + vPInfo->csPage = (vPInfo->csMode == kDepthMode5) ? 1 : 2; + ret = noErr; + } + break; + case cscGetPageBase: /* 5 == cscGetBaseAddr */ + { + VDPageInfo *vPInfo = (VDPageInfo *)*(long *)pb->csParam; + if ((vPInfo->csMode != kDepthMode1) && + (vPInfo->csMode != kDepthMode2) && + (vPInfo->csMode != kDepthMode3) && + (vPInfo->csMode != kDepthMode4) && + (vPInfo->csMode != kDepthMode5) && + (vPInfo->csMode != kDepthMode6)) { + ret = paramErr; + goto done; + } + short npage = (vPInfo->csMode == kDepthMode5) ? 1 : 2; + if (vPInfo->csPage >= npage) { + ret = paramErr; + goto done; + } + vPInfo->csBaseAddr = (Ptr)(vPInfo->csPage * 1024 * 1024 * 4); /* fixme for > 2 pages ? */ + ret = noErr; + } + asm volatile(".word 0xfe16\n"); + ret = noErr; + break; + case cscGetGray: /* 6 */ + { + VDGrayRecord *vGInfo = (VDGrayRecord *)*(long *)pb->csParam; + vGInfo->csMode = dStore->gray; + ret = noErr; + } + asm volatile(".word 0xfe16\n"); + break; + case cscGetInterrupt: /* 7 */ + asm volatile(".word 0xfe16\n"); + { + VDFlagRecord *vdflag = (VDFlagRecord *)*(long *)pb->csParam; + vdflag->csMode = 1 - dStore->irqen; + ret = noErr; + } + break; + case cscGetGamma: /* 8 */ + { + VDGammaRecord *vdgamma = (VDGammaRecord *)*(long *)pb->csParam; + vdgamma->csGTable = (Ptr)&dStore->gamma; + ret = noErr; + } + break; + case cscGetDefaultMode: /* 9 */ + { /* obsolete in PCI, not called >= 7.5 */ + VDDefMode *vddefm = (VDDefMode *)*(long *)pb->csParam; + SpBlock spb; + NuBusFPGAPramRecord pram; + OSErr err; + spb.spSlot = dce->dCtlSlot; + spb.spResult = (UInt32)&pram; + ret = SReadPRAMRec(&spb); + if (ret == noErr) { + vddefm->csID = pram.mode; + } + } + break; + + case cscGetCurMode: /* 0xa */ + { + VDSwitchInfoRec *vdswitch = *(VDSwitchInfoRec **)(long *)pb->csParam; + /* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0022); */ + /* write_reg(dce, GOBOFB_DEBUG, (unsigned int)dStore->curDepth); */ + /* write_reg(dce, GOBOFB_DEBUG, (unsigned int)dStore->curMode); */ + vdswitch->csMode = dStore->curDepth; + vdswitch->csData = dStore->curMode; + vdswitch->csPage = dStore->curPage; + vdswitch->csBaseAddr = (Ptr)(dStore->curPage * 1024 * 1024 * 4); /* fixme */ + ret = noErr; + } + break; + + case cscGetSync: /* 0xb */ + asm volatile(".word 0xfe16\n"); + ret = statusErr; + break; + + case cscGetConnection: /* 0xc */ + { + VDDisplayConnectInfoRec *vdconn = *(VDDisplayConnectInfoRec **)(long *)pb->csParam; + vdconn->csDisplayType = kGenericLCD; + vdconn->csConnectTaggedType = 0; + vdconn->csConnectTaggedData = 0; + vdconn->csConnectFlags = (1<csDisplayComponent = 0; + ret = noErr; + } + break; + + case cscGetModeTiming: /* 0xd */ + { + VDTimingInfoRec *vdtim = *(VDTimingInfoRec **)(long *)pb->csParam; + if (((((UInt8)vdtim->csTimingMode) < nativeVidMode) || + (((UInt8)vdtim->csTimingMode) > dStore->maxMode)) && + (vdtim->csTimingMode != kDisplayModeIDFindFirstResolution) && + (vdtim->csTimingMode != kDisplayModeIDCurrent)) { + ret = paramErr; + goto done; + } + unsigned int mode = vdtim->csTimingMode; + if (mode == kDisplayModeIDFindFirstResolution) + mode = nativeVidMode; + if (mode == kDisplayModeIDCurrent) + mode = dStore->curMode; + + switch (mode) { + case nativeVidMode: + vdtim->csTimingFormat = kDeclROMtables; + vdtim->csTimingData = 0; + vdtim->csTimingFlags = 1<csTimingFormat = kDeclROMtables;//kDetailedTimingFormat; + vdtim->csTimingData = 0; + vdtim->csTimingFlags = 1<csParam; + vdbase->csDevBase = 0; + ret = noErr; + } + ret = noErr; + break; + + /* cscGetScanProc */ /* 0xf*/ /* undocumented ? could be called according to #mac68k */ + + case cscGetPreferredConfiguration: /* 0x10 */ + { /* fixme: NVRAM */ + VDSwitchInfoRec *vdswitch = *(VDSwitchInfoRec **)(long *)pb->csParam; + vdswitch->csMode = kDepthMode1; //dStore->curDepth; /* fixme: prefered not current / default */ + vdswitch->csData = nativeVidMode; //dStore->curMode; + ret = noErr; + SpBlock spb; + NuBusFPGAPramRecord pram; + OSErr err; + spb.spSlot = dce->dCtlSlot; + spb.spResult = (UInt32)&pram; + ret = SReadPRAMRec(&spb); + if (ret == noErr) { + vdswitch->csMode = pram.depth; + vdswitch->csData = pram.mode; + } + } + break; + + case cscGetNextResolution: /* 0x11 */ + { + VDResolutionInfoRec *vdres = *(VDResolutionInfoRec **)(long *)pb->csParam; + switch (vdres->csPreviousDisplayModeID) + { + default: + if ((((UInt8)vdres->csPreviousDisplayModeID) < nativeVidMode) || + (((UInt8)vdres->csPreviousDisplayModeID) > dStore->maxMode)) { + ret = paramErr; + goto done; + } + if (((UInt8)vdres->csPreviousDisplayModeID) == dStore->maxMode) + vdres->csDisplayModeID = kDisplayModeIDNoMoreResolutions; + else + vdres->csDisplayModeID = ((UInt8)vdres->csPreviousDisplayModeID) + 1; + vdres->csHorizontalPixels = dStore->hres[((UInt8)vdres->csDisplayModeID) - nativeVidMode]; + vdres->csVerticalLines = dStore->vres[((UInt8)vdres->csDisplayModeID) - nativeVidMode]; + vdres->csRefreshRate = 60 << 16; /* Fixed(Point) 16+16 */ + vdres->csMaxDepthMode = kDepthMode6; + break; + case kDisplayModeIDFindFirstResolution: + vdres->csDisplayModeID = nativeVidMode; + vdres->csHorizontalPixels = dStore->hres[0]; + vdres->csVerticalLines = dStore->vres[0]; + vdres->csRefreshRate = 60 << 16; /* Fixed(Point) 16+16 */ + vdres->csMaxDepthMode = kDepthMode6; + break; + case kDisplayModeIDCurrent: + vdres->csDisplayModeID = dStore->curMode; + vdres->csHorizontalPixels = dStore->hres[dStore->curMode - nativeVidMode]; + vdres->csVerticalLines = dStore->vres[dStore->curMode - nativeVidMode]; + vdres->csRefreshRate = 60 << 16; /* Fixed(Point) 16+16 */ + vdres->csMaxDepthMode = kDepthMode6; + break; + } + ret = noErr; + } + break; + + case cscGetVideoParameters: /* 0x12 */ + { + VDVideoParametersInfoRec *vdparam = *(VDVideoParametersInfoRec **)(long *)pb->csParam; + if (((((UInt8)vdparam->csDisplayModeID) < nativeVidMode) || + (((UInt8)vdparam->csDisplayModeID) > dStore->maxMode)) && + (vdparam->csDisplayModeID != kDisplayModeIDFindFirstResolution) && + (vdparam->csDisplayModeID != kDisplayModeIDCurrent)) { + ret = paramErr; + goto done; + } + if ((vdparam->csDepthMode != kDepthMode1) && + (vdparam->csDepthMode != kDepthMode2) && + (vdparam->csDepthMode != kDepthMode3) && + (vdparam->csDepthMode != kDepthMode4) && + (vdparam->csDepthMode != kDepthMode5) && + (vdparam->csDepthMode != kDepthMode6)) { + ret = paramErr; + goto done; + } + /* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0022); */ + /* write_reg(dce, GOBOFB_DEBUG, (unsigned int)vdparam->csDisplayModeID); */ + /* write_reg(dce, GOBOFB_DEBUG, (unsigned int)vdparam->csDepthMode); */ + VPBlock* vpblock = vdparam->csVPBlockPtr; + unsigned char mode = vdparam->csDisplayModeID; + if (mode == kDisplayModeIDFindFirstResolution) + mode = nativeVidMode; + if (mode == kDisplayModeIDCurrent) + mode = dStore->curMode; + /* basically the same as the EBVParms ? */ + vdparam->csPageCount = (vdparam->csDepthMode == kDepthMode5) ? 1 : 2; + vpblock->vpBaseOffset = 0; + vpblock->vpBounds.left = 0; + vpblock->vpBounds.top = 0; + vpblock->vpBounds.right = dStore->hres[mode - nativeVidMode]; + vpblock->vpBounds.bottom = dStore->vres[mode - nativeVidMode]; + vpblock->vpVersion = 0; + vpblock->vpPackType = 0; + vpblock->vpPackSize = 0; + vpblock->vpHRes = 0x480000; + vpblock->vpVRes = 0x480000; + vpblock->vpPixelType = chunky; // checkme? + if (vdparam->csDepthMode == kDepthMode1) { + vpblock->vpRowBytes = vpblock->vpBounds.right; + vdparam->csDeviceType = clutType; + vpblock->vpPixelSize = 8; + vpblock->vpCmpCount = 1; + vpblock->vpCmpSize = 8; + } else if (vdparam->csDepthMode == kDepthMode2) { + vpblock->vpRowBytes = vpblock->vpBounds.right/2; + vdparam->csDeviceType = clutType; + vpblock->vpPixelSize = 4; + vpblock->vpCmpCount = 1; + vpblock->vpCmpSize = 4; + } else if (vdparam->csDepthMode == kDepthMode3) { + vpblock->vpRowBytes = vpblock->vpBounds.right/4; + vdparam->csDeviceType = clutType; + vpblock->vpPixelSize = 2; + vpblock->vpCmpCount = 1; + vpblock->vpCmpSize = 2; + } else if (vdparam->csDepthMode == kDepthMode4) { + vpblock->vpRowBytes = vpblock->vpBounds.right/8; + vdparam->csDeviceType = clutType; + vpblock->vpPixelSize = 1; + vpblock->vpCmpCount = 1; + vpblock->vpCmpSize = 1; + } else if (vdparam->csDepthMode == kDepthMode5) { + vpblock->vpRowBytes = vpblock->vpBounds.right*4; + vdparam->csDeviceType = directType; + vpblock->vpPixelSize = 32; + vpblock->vpCmpCount = 3; + vpblock->vpCmpSize = 8; + } else if (vdparam->csDepthMode == kDepthMode6) { + vpblock->vpRowBytes = vpblock->vpBounds.right*2; + vdparam->csDeviceType = directType; + vpblock->vpPixelSize = 16; + vpblock->vpCmpCount = 3; + vpblock->vpCmpSize = 5; + } + vpblock->vpPlaneBytes = 0; + ret = noErr; + } + break; + + /* 0x13 */ /* nothing */ + + case cscGetGammaInfoList: /* 0x14 */ + ret = statusErr; + break; + + case cscRetrieveGammaTable: /* 0x15 */ + asm volatile(".word 0xfe16\n"); + ret = statusErr; + break; + + /* cscSupportsHardwareCursor */ /* 0x16 */ /* never called, unfortunately */ + + /* cscGetHardwareCursorDrawState */ /* 0x17 */ /* never called, unfortunately */ + + case cscGetConvolution: /* 0x18 */ + ret = statusErr; + break; + + /* cscGetPowerState */ /* 0x19 */ + /* cscPrivateStatusCall */ /* 0x1a */ + /* cscGetDDCBlock */ /* 0x1b */ + + case cscGetMultiConnect: /* 0x1c */ + ret = statusErr; + break; + + /* cscGetClutBehavior */ /* 0x1d */ + /* cscGetTimingRanges */ /* 0x1e */ + /* cscGetDetailedTiming */ /* 0x1f */ + /* cscGetCommunicationInfo */ /* 0x20 */ + + default: /* always return statusErr for unknown csCode */ + asm volatile(".word 0xfe16\n"); + ret = statusErr; + break; + } +#endif + done: + if (!(pb->ioTrap & (1< +#include + +#define PRIM_WRITEREG(reg, val) \ + *((volatile UInt32*)(a32+GOBOFB_BASE+reg)) = (UInt32)val +#define PRIM_READREG(reg) \ + (*((volatile UInt32*)(a32+GOBOFB_BASE+reg))) + +#pragma parameter __D0 Primary(__A0) +UInt32 Primary(SEBlock* seblock) { + UInt32 a32 = 0xF0000000 | ((UInt32)seblock->seSlot << 24); + UInt32 a32_l0, a32_l1; + UInt32 a32_4p0, a32_4p1; + SpBlock spblock; + /* UInt8 pram[8]; */ + OSErr err; + UInt16 i,j, hres, vres; + char busMode; + UniversalProcPtr qd32ptr, unimpptr; + + busMode = 1; + SwapMMUMode ( &busMode ); // to32 // this likely won't work on older MacII ??? + + PRIM_WRITEREG(GOBOFB_VBL_MASK, 0);// disable interrupts on FB + PRIM_WRITEREG(DMA_IRQ_CTL, revb(0x2));// disable/clear interrupts on DSK + + /* PRIM_WRITEREG(GOBOFB_DEBUG, 0x87654321);// trace */ + /* PRIM_WRITEREG(GOBOFB_DEBUG, busMode);// trace */ + + hres = __builtin_bswap32((UInt32)PRIM_READREG(GOBOFB_HRES)); // fixme: endianness + vres = __builtin_bswap32((UInt32)PRIM_READREG(GOBOFB_VRES)); // fixme: endianness + + /* initialize DRAM controller */ +#ifndef QEMU + sdram_init(a32); +#endif + + /* grey the screen */ + /* should switch to HW ? */ + a32_l0 = a32; + a32_l1 = a32 + hres; + for (j = 0 ; j < vres ; j+= 2) { + a32_4p0 = a32_l0; + a32_4p1 = a32_l1; + for (i = 0 ; i < hres ; i += 4) { + *((UInt32*)a32_4p0) = 0xAAAAAAAA; + *((UInt32*)a32_4p1) = 0x55555555; + a32_4p0 += 4; + a32_4p1 += 4; + } + a32_l0 += 2*hres; + a32_l1 += 2*hres; + } + + SwapMMUMode ( &busMode ); // restore + + { // disable non-default entries + SpBlock spb; + err = noErr; + do { + spb.spParamData = 1<seSlot; + spb.spID = nativeVidMode; /* skip over the 'good' one; we can reset as SNextTypeSRsrc skips disabled */ + spb.spExtDev = 0; + err = SNextTypeSRsrc(&spb); + + if ((err == noErr) && + (spb.spSlot == seblock->seSlot) && + (((UInt8)spb.spID) > (UInt8)nativeVidMode) && + (((UInt8)spb.spID) < (UInt8)diskResource)) { + spb.spParamData = 1; /* disable */ + spb.spSlot = seblock->seSlot; + spb.spExtDev = 0; + SetSRsrcState(&spb); + /* PRIM_WRITEREG(GOBOFB_DEBUG, 0xBEEF000F); */ + /* PRIM_WRITEREG(GOBOFB_DEBUG, spb.spID); */ + } + } while (err == noErr); + } + +#if 0 + + /* call SVersion to figure out if we have a recent SlotManager */ + //spblock.spSlot = seblock->seSlot; + //spblock.spExtDev = 0; + err = SVersion(&spblock); + + busMode = 1; + SwapMMUMode ( &busMode ); // to32 + if (err) { + /* DCDMF3 p178: if error, old slot manager*/ + /* PRIM_WRITEREG(GOBOFB_DEBUG, 0xFFFFFFFF);*/ + /* PRIM_WRITEREG(GOBOFB_DEBUG, err);*/ + } else { + /* DCDMF3 p178: new slot manager */ + /* PRIM_WRITEREG(GOBOFB_DEBUG, 0);*/ + /* PRIM_WRITEREG(GOBOFB_DEBUG, spblock.spResult);*/ + } + SwapMMUMode ( &busMode ); // restore + + /* check for 32-bits QuickDraw */ + qd32ptr = GetTrapAddress(Check32QDTrap); + unimpptr = GetTrapAddress(_Unimplemented); + + busMode = 1; + SwapMMUMode ( &busMode ); // to32 + if (qd32ptr == unimpptr) { + /* no 32QD */ + PRIM_WRITEREG(GOBOFB_DEBUG, 0xFFFFFFFF); + PRIM_WRITEREG(GOBOFB_DEBUG, unimpptr); + } else { + /* yes 32QD */ + PRIM_WRITEREG(GOBOFB_DEBUG, 0x00C0FFEE); + } + SwapMMUMode ( &busMode ); // restore + + /* check the content of the PRAM */ + spblock.spSlot = seblock->seSlot; + spblock.spResult = (UInt32)pram; + err = SReadPRAMRec(&spblock); + +#if 0 + PRIM_WRITEREG(GOBOFB_DEBUG, 0x88888888); + for (j = 0 ; j < 8 ; j++) + PRIM_WRITEREG(GOBOFB_DEBUG, (uint32_t)pram[j]); + PRIM_WRITEREG(GOBOFB_DEBUG, 0x88888888); +#endif + + busMode = 1; + SwapMMUMode ( &busMode ); // to32 + if (err) { + /* PRIM_WRITEREG(GOBOFB_DEBUG, 0xFFFFFFFF);*/ + /* PRIM_WRITEREG(GOBOFB_DEBUG, err);*/ + } else { + /* PRIM_WRITEREG(GOBOFB_DEBUG, 0xC0FFEE00);*/ + /* for (i = 0 ; i < 8 ; i++) */ + /* PRIM_WRITEREG(GOBOFB_DEBUG, pram[i]);*/ + } + SwapMMUMode ( &busMode ); // restore + +#endif + + seblock->seStatus = 1; + + return 0; +} + +/* SDRAM INIT */ + diff --git a/DeclROM/NuBusFPGAPrimaryInit_RamInit.c b/DeclROM/NuBusFPGAPrimaryInit_RamInit.c new file mode 100644 index 0000000..82c61d0 --- /dev/null +++ b/DeclROM/NuBusFPGAPrimaryInit_RamInit.c @@ -0,0 +1,660 @@ +#include "NuBusFPGADrvr.h" + +#define CONFIG_CSR_DATA_WIDTH 32 + +#if defined(NUBUSFPGA) +#include "../nubusfpga_csr_ddrphy.h" +#include "../nubusfpga_csr_sdram.h" +#elif defined(IISIFPGA) +#include "../IIsifpga_csr_ddrphy.h" +#include "../IIsifpga_csr_sdram.h" +#elif defined(QUADRAFPGA) +#include "../quadrafpga_csr_ddrphy.h" +#include "../quadrafpga_csr_sdram.h" +#else +#error "no board defined" +#endif + +/* auto-generated sdram_phy.h + sc */ +#define DFII_CONTROL_SEL 0x01 +#define DFII_CONTROL_CKE 0x02 +#define DFII_CONTROL_ODT 0x04 +#define DFII_CONTROL_RESET_N 0x08 + +#define DFII_COMMAND_CS 0x01 +#define DFII_COMMAND_WE 0x02 +#define DFII_COMMAND_CAS 0x04 +#define DFII_COMMAND_RAS 0x08 +#define DFII_COMMAND_WRDATA 0x10 +#define DFII_COMMAND_RDDATA 0x20 + +#define SDRAM_PHY_A7DDRPHY +#define SDRAM_PHY_XDR 2 +#define SDRAM_PHY_DATABITS 16 +#define SDRAM_PHY_PHASES 4 +#define SDRAM_PHY_CL 6 +#define SDRAM_PHY_CWL 5 +#define SDRAM_PHY_CMD_LATENCY 0 +#define SDRAM_PHY_RDPHASE 2 +#define SDRAM_PHY_WRPHASE 3 +#define SDRAM_PHY_WRITE_LATENCY_CALIBRATION_CAPABLE +#define SDRAM_PHY_READ_LEVELING_CAPABLE +#define SDRAM_PHY_MODULES SDRAM_PHY_DATABITS/8 +#define SDRAM_PHY_DELAYS 32 +#define SDRAM_PHY_BITSLIPS 8 + +__attribute__ ((section (".text.primary"))) static void cdelay(int i); + +__attribute__ ((section (".text.primary"))) static void +sdram_read_leveling_rst_delay (uint32_t a32, int module); +__attribute__ ((section (".text.primary"))) static void +sdram_read_leveling_inc_delay (uint32_t a32, int module); + +__attribute__ ((section (".text.primary"))) static inline void command_p0(uint32_t a32, int cmd) +{ + sdram_dfii_pi0_command_write(a32, cmd); + sdram_dfii_pi0_command_issue_write(a32, 1); +} +__attribute__ ((section (".text.primary"))) static inline void command_p1(uint32_t a32, int cmd) +{ + sdram_dfii_pi1_command_write(a32, cmd); + sdram_dfii_pi1_command_issue_write(a32, 1); +} +__attribute__ ((section (".text.primary"))) static inline void command_p2(uint32_t a32, int cmd) +{ + sdram_dfii_pi2_command_write(a32, cmd); + sdram_dfii_pi2_command_issue_write(a32, 1); +} +__attribute__ ((section (".text.primary"))) static inline void command_p3(uint32_t a32, int cmd) +{ + sdram_dfii_pi3_command_write(a32, cmd); + sdram_dfii_pi3_command_issue_write(a32, 1); +} + +#define DFII_PIX_DATA_SIZE CSR_SDRAM_DFII_PI0_WRDATA_SIZE + +__attribute__ ((section (".text.primary"))) static inline unsigned long sdram_dfii_pix_wrdata_addr(int phase) +{ + switch (phase) { + case 0: return CSR_SDRAM_DFII_PI0_WRDATA_ADDR; + case 1: return CSR_SDRAM_DFII_PI1_WRDATA_ADDR; + case 2: return CSR_SDRAM_DFII_PI2_WRDATA_ADDR; + case 3: return CSR_SDRAM_DFII_PI3_WRDATA_ADDR; + default: return 0; + } +} + +__attribute__ ((section (".text.primary"))) static inline unsigned long sdram_dfii_pix_rddata_addr(int phase) +{ + switch (phase) { + case 0: return CSR_SDRAM_DFII_PI0_RDDATA_ADDR; + case 1: return CSR_SDRAM_DFII_PI1_RDDATA_ADDR; + case 2: return CSR_SDRAM_DFII_PI2_RDDATA_ADDR; + case 3: return CSR_SDRAM_DFII_PI3_RDDATA_ADDR; + default: return 0; + } +} + +#define DDRX_MR_WRLVL_ADDRESS 1 +#define DDRX_MR_WRLVL_RESET 6 +#define DDRX_MR_WRLVL_BIT 7 + +__attribute__ ((section (".text.primary"))) static inline void init_sequence(uint32_t a32) +{ + /* Release reset */ + sdram_dfii_pi0_address_write(a32, 0x0); + sdram_dfii_pi0_baddress_write(a32, 0); + sdram_dfii_control_write(a32, DFII_CONTROL_ODT|DFII_CONTROL_RESET_N); + cdelay(50000); + + /* Bring CKE high */ + sdram_dfii_pi0_address_write(a32, 0x0); + sdram_dfii_pi0_baddress_write(a32, 0); + sdram_dfii_control_write(a32, DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N); + cdelay(10000); + + /* Load Mode Register 2, CWL=5 */ + sdram_dfii_pi0_address_write(a32, 0x200); + sdram_dfii_pi0_baddress_write(a32, 2); + command_p0(a32, DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + + /* Load Mode Register 3 */ + sdram_dfii_pi0_address_write(a32, 0x0); + sdram_dfii_pi0_baddress_write(a32, 3); + command_p0(a32, DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + + /* Load Mode Register 1 */ + sdram_dfii_pi0_address_write(a32, 0x6); + sdram_dfii_pi0_baddress_write(a32, 1); + command_p0(a32, DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + + /* Load Mode Register 0, CL=6, BL=8 */ + sdram_dfii_pi0_address_write(a32, 0x920); + sdram_dfii_pi0_baddress_write(a32, 0); + command_p0(a32, DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + cdelay(200); + + /* ZQ Calibration */ + sdram_dfii_pi0_address_write(a32, 0x400); + sdram_dfii_pi0_baddress_write(a32, 0); + command_p0(a32, DFII_COMMAND_WE|DFII_COMMAND_CS); + cdelay(200); +} + +#include "nubusfpga_csr_common.h" + +/* sdram.c from liblitedram, preprocessed for our case, + sc */ + +__attribute__ ((section (".text.primary"))) static inline unsigned long +lfsr (unsigned long bits, unsigned long prev) +{ + /*static*/ const unsigned long long lfsr_taps[] = { + 0x0L, + 0x0L, + 0x3L, + 0x6L, + 0xcL, + 0x14L, + 0x30L, + 0x60L, + 0xb8L, + 0x110L, + 0x240L, + 0x500L, + 0x829L, + 0x100dL, + 0x2015L, + 0x6000L, + 0xd008L, + 0x12000L, + 0x20400L, + 0x40023L, + 0x90000L, + 0x140000L, + 0x300000L, + 0x420000L, + 0xe10000L, + 0x1200000L, + 0x2000023L, + 0x4000013L, + 0x9000000L, + 0x14000000L, + 0x20000029L, + 0x48000000L, + 0x80200003L, + 0x100080000L, + 0x204000003L, + 0x500000000L, + 0x801000000L, + 0x100000001fL, + 0x2000000031L, + 0x4400000000L, + 0xa000140000L, + 0x12000000000L, + 0x300000c0000L, + 0x63000000000L, + 0xc0000030000L, + 0x1b0000000000L, + 0x300003000000L, + 0x420000000000L, + 0xc00000180000L, + 0x1008000000000L, + 0x3000000c00000L, + 0x6000c00000000L, + 0x9000000000000L, + 0x18003000000000L, + 0x30000000030000L, + 0x40000040000000L, + 0xc0000600000000L, + 0x102000000000000L, + 0x200004000000000L, + 0x600003000000000L, + 0xc00000000000000L, + 0x1800300000000000L, + 0x3000000000000030L, + 0x6000000000000000L, + 0x800000000000000dL + }; + unsigned long lsb = prev & 1; + prev >>= 1; + prev ^= (-lsb) & lfsr_taps[bits]; + return prev; +} + +__attribute__ ((section (".text.primary"))) +static void cdelay (int i) +{ + //i >>= 2; + while (i > 0) { + __asm__ volatile (""); + i--; + } +} + +__attribute__ ((section (".text.primary"))) static unsigned char +sdram_dfii_get_rdphase(uint32_t a32) +{ + return ddrphy_rdphase_read(a32); +} +__attribute__ ((section (".text.primary"))) static unsigned char +sdram_dfii_get_wrphase(uint32_t a32) +{ + return ddrphy_wrphase_read(a32); +} +__attribute__ ((section (".text.primary"))) static void +sdram_dfii_pix_address_write(uint32_t a32, unsigned char phase, unsigned int value) +{ + switch (phase) { + case 3: + sdram_dfii_pi3_address_write(a32, value); + break; + case 2: + sdram_dfii_pi2_address_write(a32, value); + break; + case 1: + sdram_dfii_pi1_address_write(a32, value); + break; + default: + sdram_dfii_pi0_address_write(a32, value); + } +} +__attribute__ ((section (".text.primary"))) static void +sdram_dfii_pird_address_write(uint32_t a32, unsigned int value) +{ + unsigned char rdphase = sdram_dfii_get_rdphase(a32); + sdram_dfii_pix_address_write(a32, rdphase, value); +} +__attribute__ ((section (".text.primary"))) static void +sdram_dfii_piwr_address_write(uint32_t a32, unsigned int value) +{ + unsigned char wrphase = sdram_dfii_get_wrphase(a32); + sdram_dfii_pix_address_write(a32, wrphase, value); +} +__attribute__ ((section (".text.primary"))) static void +sdram_dfii_pix_baddress_write(uint32_t a32, unsigned char phase, unsigned int value) +{ + switch (phase) { + case 3: + sdram_dfii_pi3_baddress_write(a32, value); + break; + case 2: + sdram_dfii_pi2_baddress_write(a32, value); + break; + case 1: + sdram_dfii_pi1_baddress_write(a32, value); + break; + default: + sdram_dfii_pi0_baddress_write(a32, value); + } +} +__attribute__ ((section (".text.primary"))) static void +sdram_dfii_pird_baddress_write(uint32_t a32, unsigned int value) +{ + unsigned char rdphase = sdram_dfii_get_rdphase(a32); + sdram_dfii_pix_baddress_write(a32, rdphase, value); +} +__attribute__ ((section (".text.primary"))) static void +sdram_dfii_piwr_baddress_write(uint32_t a32, unsigned int value) +{ + unsigned char wrphase = sdram_dfii_get_wrphase(a32); + sdram_dfii_pix_baddress_write(a32, wrphase, value); +} +__attribute__ ((section (".text.primary"))) static void +command_px(uint32_t a32, unsigned char phase, unsigned int value) +{ + switch (phase) { + case 3: + command_p3(a32, value); + break; + case 2: + command_p2(a32, value); + break; + case 1: + command_p1(a32, value); + break; + default: + command_p0(a32, value); + } +} +__attribute__ ((section (".text.primary"))) static void +command_prd(uint32_t a32, unsigned int value) +{ + unsigned char rdphase = sdram_dfii_get_rdphase(a32); + command_px(a32, rdphase, value); +} +__attribute__ ((section (".text.primary"))) static void +command_pwr (uint32_t a32, unsigned int value) +{ + unsigned char wrphase = sdram_dfii_get_wrphase(a32); + command_px(a32, wrphase, value); +} +__attribute__ ((section (".text.primary"))) static void +sdram_software_control_on(uint32_t a32) +{ + unsigned int previous; + previous = sdram_dfii_control_read(a32); + if (previous != (0x02 | 0x04 | 0x08)) { + sdram_dfii_control_write(a32, (0x02 | 0x04 | 0x08)); + } +} +__attribute__ ((section (".text.primary"))) static void +sdram_software_control_off(uint32_t a32) +{ + unsigned int previous; + previous = sdram_dfii_control_read(a32); + if (previous != (0x01)) { + sdram_dfii_control_write(a32, (0x01)); + } +} +__attribute__ ((section (".text.primary"))) static void +sdram_mode_register_write(uint32_t a32, char reg, int value) +{ + sdram_dfii_pi0_address_write(a32, value); + sdram_dfii_pi0_baddress_write(a32, reg); + command_p0(a32, 0x08 | 0x04 | 0x02 | 0x01); +} + +//typedef void (*delay_callback) (uint32_t a32, int module); + +__attribute__ ((section (".text.primary"))) static void +sdram_activate_test_row(uint32_t a32) +{ + sdram_dfii_pi0_address_write(a32, 0); + sdram_dfii_pi0_baddress_write(a32, 0); + command_p0(a32, 0x08 | 0x01); + cdelay (15); +} +__attribute__ ((section (".text.primary"))) static void +sdram_precharge_test_row(uint32_t a32) +{ + sdram_dfii_pi0_address_write(a32, 0); + sdram_dfii_pi0_baddress_write(a32, 0); + command_p0(a32, 0x08 | 0x02 | 0x01); + cdelay (15); +} + +__attribute__ ((section (".text.primary"))) static unsigned int +popcount (unsigned int x) +{ + x -= ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x += (x >> 8); + x += (x >> 16); + return x & 0x0000003F; +} + +__attribute__ ((section (".text.primary"))) static unsigned int +sdram_write_read_check_test_pattern (uint32_t a32, int module, unsigned int seed) +{ + int p, i; + unsigned int errors; + unsigned int prv; + unsigned char tst[1 * 32 / 8]; + unsigned char prs[4][1 * 32 / 8]; + prv = seed; + for (p = 0; p < 4; p++) { + for (i = 0; i < 1 * 32 / 8; i++) { + prv = lfsr (32, prv); + prs[p][i] = prv; + } + } + sdram_activate_test_row(a32); + for (p = 0; p < 4; p++) + csr_wr_buf_uint8(a32, (sdram_dfii_pix_wrdata_addr (p)/* - CSR_SDRAM_BASE*/), prs[p], 1 * 32 / 8); /* cleanme */ + sdram_dfii_piwr_address_write(a32, 0); + sdram_dfii_piwr_baddress_write(a32, 0); + command_pwr(a32, 0x04 | 0x02 | 0x01 | 0x10); + cdelay (15); + sdram_dfii_pird_address_write(a32, 0); + sdram_dfii_pird_baddress_write(a32, 0); + command_prd(a32, 0x04 | 0x01 | 0x20); + cdelay (15); + sdram_precharge_test_row(a32); + errors = 0; + for (p = 0; p < 4; p++) { + csr_rd_buf_uint8(a32, (sdram_dfii_pix_rddata_addr (p)/* - CSR_SDRAM_BASE*/), tst, 1 * 32 / 8); /* cleanme */ + errors += + popcount (prs[p][16 / 8 - 1 - module] ^ tst[16 / 8 - 1 - module]); + errors += + popcount (prs[p][2 * 16 / 8 - 1 - module] ^ + tst[2 * 16 / 8 - 1 - module]); + } + return errors; +} +__attribute__ ((section (".text.primary"))) static void +sdram_leveling_center_module (uint32_t a32, int module, int show_short, int show_long) +/* , + delay_callback rst_delay, + delay_callback inc_delay) */ +{ + int i; + int show; + int working; + unsigned int errors; + int delay, delay_mid, delay_range; + int delay_min = -1, delay_max = -1; + + delay = 0; + //rst_delay(a32, module); + sdram_read_leveling_rst_delay(a32, module); + while (1) { + errors = sdram_write_read_check_test_pattern(a32, module, 42); + errors += sdram_write_read_check_test_pattern(a32, module, 84); + working = errors == 0; + show = show_long; + + if (working && delay_min < 0) { + delay_min = delay; + break; + } + delay++; + if (delay >= 32) + break; + //inc_delay(a32, module); + sdram_read_leveling_inc_delay(a32, module); + } + delay++; + //inc_delay(a32, module); + sdram_read_leveling_inc_delay(a32, module); + while (1) { + errors = sdram_write_read_check_test_pattern(a32, module, 42); + errors += sdram_write_read_check_test_pattern(a32, module, 84); + working = errors == 0; + show = show_long; + + if (!working && delay_max < 0) { + delay_max = delay; + } + delay++; + if (delay >= 32) + break; + //inc_delay(a32, module); + sdram_read_leveling_inc_delay(a32, module); + } + if (delay_max < 0) { + delay_max = delay; + } + + delay_mid = (delay_min + delay_max) / 2 % 32; + delay_range = (delay_max - delay_min) / 2; + +//delay_mid = 25; + + //rst_delay(a32, module); + sdram_read_leveling_rst_delay(a32, module); + cdelay (100); + for (i = 0; i < delay_mid; i++) { + //inc_delay(a32, module); + sdram_read_leveling_inc_delay(a32, module); + cdelay (100); + } +} + +//__attribute__ ((section (".data.primary"))) int _sdram_write_leveling_bitslips[16]; + +__attribute__ ((section (".text.primary"))) static void +sdram_read_leveling_rst_delay (uint32_t a32, int module) +{ + ddrphy_dly_sel_write(a32, 1 << module); + ddrphy_rdly_dq_rst_write(a32, 1); + ddrphy_dly_sel_write(a32, 0); +} +__attribute__ ((section (".text.primary"))) static void +sdram_read_leveling_inc_delay (uint32_t a32, int module) +{ + ddrphy_dly_sel_write(a32, 1 << module); + ddrphy_rdly_dq_inc_write(a32, 1); + ddrphy_dly_sel_write(a32, 0); +} +__attribute__ ((section (".text.primary"))) static void +sdram_read_leveling_rst_bitslip (uint32_t a32, char m) +{ + ddrphy_dly_sel_write(a32, 1 << m); + ddrphy_rdly_dq_bitslip_rst_write(a32, 1); + ddrphy_dly_sel_write(a32, 0); +} +__attribute__ ((section (".text.primary"))) static void +sdram_read_leveling_inc_bitslip (uint32_t a32, char m) +{ + ddrphy_dly_sel_write(a32, 1 << m); + ddrphy_rdly_dq_bitslip_write(a32, 1); + ddrphy_dly_sel_write(a32, 0); +} +__attribute__ ((section (".text.primary"))) static unsigned int +sdram_read_leveling_scan_module (uint32_t a32, int module, int bitslip, int show) +{ + const unsigned int max_errors = 2 * (4 * 2 * 32); + int i; + unsigned int score; + unsigned int errors; + score = 0; + + sdram_read_leveling_rst_delay(a32, module); + for (i = 0; i < 32; i++) { + int working; + int _show = show; + errors = sdram_write_read_check_test_pattern(a32, module, 42); + errors += sdram_write_read_check_test_pattern(a32, module, 84); + working = (errors == 0) ? 1 : 0; + score += (working * max_errors * 32) + (max_errors - errors); + + sdram_read_leveling_inc_delay(a32, module); + } + return score; +} +__attribute__ ((section (".text.primary"))) static void +sdram_read_leveling(uint32_t a32) +{ + int module; + int bitslip; + unsigned int score; + unsigned int best_score; + int best_bitslip; + for (module = 0; module < 16 / 8; module++) { + best_score = 0; + best_bitslip = 0; + sdram_read_leveling_rst_bitslip(a32, module); + for (bitslip = 0; bitslip < 8; bitslip++) { + score = sdram_read_leveling_scan_module(a32, module, bitslip, 1); + sdram_leveling_center_module(a32, module, 1, 0); + /*, + sdram_read_leveling_rst_delay, + sdram_read_leveling_inc_delay);*/ + if (score > best_score) { + best_bitslip = bitslip; + best_score = score; + } + if (bitslip == 8 - 1) + break; + sdram_read_leveling_inc_bitslip(a32, module); + } + +//best_bitslip = 1; + + sdram_read_leveling_rst_bitslip(a32, module); + for (bitslip = 0; bitslip < best_bitslip; bitslip++) + sdram_read_leveling_inc_bitslip(a32, module); + sdram_leveling_center_module(a32, module, 1, 0); + /*, + sdram_read_leveling_rst_delay, + sdram_read_leveling_inc_delay);*/ + } +} +__attribute__ ((section (".text.primary"))) static void +sdram_write_latency_calibration(uint32_t a32) +{ + int i; + int module; + int bitslip; + unsigned int score; + unsigned int subscore; + unsigned int best_score; + int best_bitslip; + int _sdram_write_leveling_bitslips[16] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; + for (module = 0; module < 16 / 8; module++) { + best_score = 0; + best_bitslip = -1; + for (bitslip = 0; bitslip < 8; bitslip += 2) { + score = 0; + ddrphy_dly_sel_write(a32, 1 << module); + ddrphy_wdly_dq_bitslip_rst_write(a32, 1); + for (i = 0; i < bitslip; i++) { + ddrphy_wdly_dq_bitslip_write(a32, 1); + } + ddrphy_dly_sel_write(a32, 0); + score = 0; + sdram_read_leveling_rst_bitslip(a32, module); + for (i = 0; i < 8; i++) { + subscore = sdram_read_leveling_scan_module(a32, module, i, 0); + score = subscore > score ? subscore : score; + sdram_read_leveling_inc_bitslip(a32, module); + } + if (score > best_score) { + best_bitslip = bitslip; + best_score = score; + } + } + if (_sdram_write_leveling_bitslips[module] < 0) + bitslip = best_bitslip; + else + bitslip = _sdram_write_leveling_bitslips[module]; +//bitslip = 0; + ddrphy_dly_sel_write(a32, 1 << module); + ddrphy_wdly_dq_bitslip_rst_write(a32, 1); + for (i = 0; i < bitslip; i++) { + ddrphy_wdly_dq_bitslip_write(a32, 1); + } + ddrphy_dly_sel_write(a32, 0); + } +} +__attribute__ ((section (".text.primary"))) static int +sdram_leveling(uint32_t a32) +{ + int module; + sdram_software_control_on(a32); + for (module = 0; module < 16 / 8; module++) { + sdram_read_leveling_rst_delay(a32, module); + sdram_read_leveling_rst_bitslip(a32, module); + } + sdram_write_latency_calibration(a32); + sdram_read_leveling(a32); + sdram_software_control_off(a32); + return 1; +} +int +sdram_init(uint32_t a32) // // attribute in header file +{ + ddrphy_rdphase_write(a32, 2); + ddrphy_wrphase_write(a32, 3); + sdram_software_control_on(a32); + ddrphy_rst_write(a32, 1); + cdelay (1000); + ddrphy_rst_write(a32, 0); + cdelay (1000); + init_sequence(a32); + sdram_leveling(a32); + sdram_software_control_off(a32); + return 1; +} diff --git a/DeclROM/NuBusFPGARAMDskDrvr.h b/DeclROM/NuBusFPGARAMDskDrvr.h new file mode 100644 index 0000000..18fe369 --- /dev/null +++ b/DeclROM/NuBusFPGARAMDskDrvr.h @@ -0,0 +1,74 @@ +#ifndef __NUBUSFPGARAMDSKDRVR_H__ +#define __NUBUSFPGARAMDSKDRVR_H__ + +#include +#include +#include +#include +#include +#include + +// noy yest supported on PDS variants +#if defined(NUBUSFPGA) +// #define ENABLE_DMA 1 +#endif + +#include "NuBusFPGADrvr.h" + +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; + +struct RAMDrvContext { + DrvSts2 drvsts; + ram_dsk_op op; + char slot; +#ifdef ENABLE_DMA + char irqen; + unsigned int dma_blk_size; + unsigned int dma_blk_size_mask; + unsigned int dma_blk_size_shift; + unsigned long dma_blk_base; + unsigned long dma_mem_size; + SlotIntQElement *siqel; +#endif +}; + +#define DRIVE_SIZE_BYTES ((256ul-8ul)*1024ul*1024ul) // FIXME: mem size minus fb size + +/* FIXME; should be auto-generated for CSR addresses... */ +/* WARNING: 0x00100800 is the offset to GOBOFB_BASE !! */ +#define DMA_BLK_SIZE (0x00100800 | 0x00) +#define DMA_BLK_BASE (0x00100800 | 0x04) +#define DMA_MEM_SIZE (0x00100800 | 0x08) +#define DMA_IRQ_CTL (0x00100800 | 0x0c) +#define DMA_BLK_ADDR (0x00100800 | 0x10) +#define DMA_DMA_ADDR (0x00100800 | 0x14) +#define DMA_BLK_CNT (0x00100800 | 0x18) + +#define DMA_STATUS (0x00100800 | 0x2c) +#define DMA_STATUS_CHECK_BITS (0x01F) + +#define DMA_IRQSTATUS (0x00100800 | 0x34) + + +/* 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"))); +OSErr cNuBusFPGARAMDskClose(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.dskdriver"))); +/* prime */ +short dskIrq(const long sqParameter) __attribute__ ((section (".text.dskdriver"))); +OSErr cNuBusFPGARAMDskPrime(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.dskdriver"))); +/* status */ +OSErr cNuBusFPGARAMDskStatus(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.dskdriver"))); + +uint32_t rledec(uint32_t* out, const uint32_t* in, const uint32_t len) __attribute__ ((section (".text.dskdriver")));; + +#endif diff --git a/DeclROM/NuBusFPGARAMDskDrvr.s b/DeclROM/NuBusFPGARAMDskDrvr.s new file mode 100644 index 0000000..91c56bb --- /dev/null +++ b/DeclROM/NuBusFPGARAMDskDrvr.s @@ -0,0 +1,23 @@ +NuBusFPGARAMDskDrvr: + .word 0x4f00 /* 0x4f00: ctl, status, read, write, needsLock [Devices.a] */ + .word 0 + .word 0 + .word 0 + /* Entry point offset table */ + /* we can directly call the C version if it has the right calling convention */ + .word cNuBusFPGARAMDskOpen - NuBusFPGARAMDskDrvr /* open routine */ + .word cNuBusFPGARAMDskPrime - NuBusFPGARAMDskDrvr /* prime */ + .word cNuBusFPGARAMDskCtl - NuBusFPGARAMDskDrvr /* control */ + .word cNuBusFPGARAMDskStatus- NuBusFPGARAMDskDrvr /* status */ + .word cNuBusFPGARAMDskClose - NuBusFPGARAMDskDrvr /* close */ + +_NuBusFPGARAMDskTitle: + .byte _NuBusFPGARAMDskTitle_StringEnd-.-1 /* pascal string length */ + .ascii ".NuBusFPGARAMDsk_Drvr" +_NuBusFPGARAMDskTitle_StringEnd: + .word 0 /* version number */ + + /* for entry points: */ + /* A0 pointer to driver parameter block */ + /* A1 pointer to driver device control entry */ + ALIGN 2 diff --git a/DeclROM/NuBusFPGARAMDskDrvr_Ctrl.c b/DeclROM/NuBusFPGARAMDskDrvr_Ctrl.c new file mode 100644 index 0000000..de2f4a6 --- /dev/null +++ b/DeclROM/NuBusFPGARAMDskDrvr_Ctrl.c @@ -0,0 +1,59 @@ +#include "NuBusFPGARAMDskDrvr.h" + +#ifdef ENABLE_DMA +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 ? revb(0x3) : revb(0x2)); // 0x2: always clear pending interrupt + ctx->irqen = en; + } + return noErr; +} +#endif + + +#pragma parameter __D0 cNuBusFPGARAMDskCtl(__A0, __A1) +OSErr cNuBusFPGARAMDskCtl(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + OSErr ret = noErr; + struct RAMDrvContext *ctx; + + /* write_reg(dce, GOBOFB_DEBUG, 0xDEAD0002); */ + /* write_reg(dce, GOBOFB_DEBUG, pb->csCode); */ + + ctx = *(struct RAMDrvContext**)dce->dCtlStorage; + + if (ctx) { + switch (pb->csCode) + { + case kFormat: + ret = noErr; + break; + default: + ret = controlErr; + break; + } + } else { + ret = offLinErr; /* r/w requested for an off-line drive */ + goto done; + } + + done: + if (!(pb->ioTrap & (1< + +/* FYI, missing in library with Retro68 */ +/* void AddDrive(short drvrRefNum, short drvNum, DrvQElPtr qEl); */ + +/* re-implement with Retro68 features */ +/* drVNum to high-order bits of num, drvrRefNum in low-order */ +/* not sure how to do "parameter" without output ? */ +#pragma parameter __D0 AddDrive(__D0, __A0) +__attribute__ ((section (".text.dskdriver"))) static inline int dupAddDrive(unsigned long num, DrvQElPtr qEl) { + asm volatile(".word 0xA04E" : : "d" (num), "a" (qEl)); + return num; // should cost nothing, num is already in D0 +} + +#include + +#pragma parameter __D0 cNuBusFPGARAMDskOpen(__A0, __A1) +OSErr cNuBusFPGARAMDskOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + DrvSts2 *dsptr; // pointer to the DrvSts2 in our context + int drvnum = 1; + struct RAMDrvContext *ctx; + OSErr ret = noErr; + char busMode; + char slot; + + busMode = 1; + SwapMMUMode ( &busMode ); // to32 // this likely won't work on older MacII ??? + + if (dce->dCtlDevBase == 0) { // for some unknown reason, we get an empty dCtlDevBase... + if ((dce->dCtlSlot > 0xE) || (dce->dCtlSlot < 0x9)) { // safety net + SpBlock mySpBlock; + SInfoRecord mySInfoRecord; + mySpBlock.spResult = (long)&mySInfoRecord; + + mySpBlock.spSlot = 0x9; // start at first + mySpBlock.spID = 0; + mySpBlock.spExtDev = 0; + mySpBlock.spCategory = catProto; + mySpBlock.spCType = 0x1000; // typeDrive; + mySpBlock.spDrvrSW = drSwApple; + mySpBlock.spDrvrHW = 0xbeee; // DrHwNuBusFPGADsk + mySpBlock.spTBMask = 0; + ret = SNextTypeSRsrc(&mySpBlock); + if (ret) + goto done; + slot = mySpBlock.spSlot; + } else { + slot = dce->dCtlSlot; + } + dce->dCtlDevBase = 0xF0000000ul | ((unsigned long)slot << 24); + } + + /* write_reg(dce, GOBOFB_DEBUG, 0xDEAD0000); */ + /* write_reg(dce, GOBOFB_DEBUG, dce->dCtlSlot); */ + + if (dce->dCtlStorage == nil) { + DrvQElPtr dq; + for(dq = (DrvQElPtr)(GetDrvQHdr())->qHead; dq; dq = (DrvQElPtr)dq->qLink) { + if (dq->dQDrive >= drvnum) + drvnum = dq->dQDrive+1; + } + + ReserveMemSys(sizeof(struct RAMDrvContext)); + dce->dCtlStorage = NewHandleSysClear(sizeof(struct RAMDrvContext)); + if (dce->dCtlStorage == nil) { + ret = openErr; + goto done; + } + + HLock(dce->dCtlStorage); + + ctx = *(struct RAMDrvContext **)dce->dCtlStorage; + ctx->slot = slot; + + // disable IRQ for now + write_reg(dce, DMA_IRQ_CTL, revb(0x2)); // 0x1 would enable irq, 0x2 is auto-clear so we make sure there's no spurious IRQ pending ; should be already done by Pirmary + + dsptr = &ctx->drvsts; + // dsptr->track /* current track */ + dsptr->writeProt = 0; /* bit 7 = 1 if volume is locked */ + dsptr->diskInPlace = 8; /* disk in drive */ + // dsptr->installed /* drive installed */ + // dsptr->sides /* -1 for 2-sided, 0 for 1-sided */ + // dsptr->QLink /* next queue entry */ + dsptr->qType = 1; /* 1 for HD20 */ /* Files 2-85 (p173) : 1 to enable S1 */ + dsptr->dQDrive = drvnum; /* drive number */ + dsptr->dQRefNum = dce->dCtlRefNum; /* driver reference number */ + // dsptr->dQFSID /* file system ID */ + dsptr->driveSize = ((DRIVE_SIZE_BYTES/512ul) & 0x0000FFFFul); /* (no comments in Disks.h) */ + dsptr->driveS1 = ((DRIVE_SIZE_BYTES/512ul) & 0xFFFF0000ul) >> 16; /* */ + // dsptr->driveType + // dsptr->driveManf + // dsptr->driveChar + // dsptr->driveMisc + + // MyAddDrive(dsptr->dQRefNum, drvnum, (DrvQElPtr)&dsptr->qLink); + + // write_reg(dce, GOBOFB_DEBUG, 0x0000DEAD); + + // initialize to our empty volume + { + unsigned long *superslot = (unsigned long*)(((unsigned long)ctx->slot) << 28ul); + unsigned long *compressed = (unsigned long*)(dce->dCtlDevBase + 0x00FF8000ul); + unsigned long res; + res = rledec(superslot, compressed, 730); // FIXME: 730 = 2920/4 (compressed size in words) + } + + // add the drive + //MyAddDrive(dsptr->dQRefNum, drvnum, (DrvQElPtr)&dsptr->qLink); + dupAddDrive((dsptr->dQRefNum & 0xFFFF) | (drvnum << 16), (DrvQElPtr)&dsptr->qLink); + +#ifdef ENABLE_DMA + ctx->dma_blk_size = revb( read_reg(dce, DMA_BLK_SIZE) ); + ctx->dma_blk_size_mask = ctx->dma_blk_size - 1; // size is Po2 + ctx->dma_blk_size_shift = 0; + while ((1 << ctx->dma_blk_size_shift) < ctx->dma_blk_size) // fixme + ctx->dma_blk_size_shift++; + ctx->dma_blk_base = revb( read_reg(dce, DMA_BLK_BASE) ); + ctx->dma_mem_size = revb( read_reg(dce, DMA_MEM_SIZE) ); + /* write_reg(dce, GOBOFB_DEBUG, 0xD1580002); */ + /* write_reg(dce, GOBOFB_DEBUG, ctx->dma_blk_size); */ + /* write_reg(dce, GOBOFB_DEBUG, ctx->dma_blk_size_mask); */ + /* 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); */ + + { + SlotIntQElement *siqel = (SlotIntQElement *)NewPtrSysClear(sizeof(SlotIntQElement)); + + if (siqel == NULL) { + return openErr; + } + + siqel->sqType = sIQType; + siqel->sqPrio = 7; + siqel->sqAddr = dskIrq; + siqel->sqParm = (long)dce; + ctx->siqel = siqel; + ctx->irqen = 0; + + ctx->op.blk_todo = 0; + ctx->op.blk_done = 0; + ctx->op.blk_offset = 0; + ctx->op.blk_doing = 0; + ctx->op.ioBuffer = 0; + ctx->op.write = 0; + } +#endif + + // auto-mount + { + ParamBlockRec pbr; + pbr.volumeParam.ioVRefNum = dsptr->dQDrive; + ret = PBMountVol(&pbr); + } + } + + SwapMMUMode ( &busMode ); + + done: + return ret; +} + +#pragma parameter __D0 cNuBusFPGARAMDskClose(__A0, __A1) +OSErr cNuBusFPGARAMDskClose(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + OSErr ret = noErr; + 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; + } + return ret; +} + diff --git a/DeclROM/NuBusFPGARAMDskDrvr_Prime.c b/DeclROM/NuBusFPGARAMDskDrvr_Prime.c new file mode 100644 index 0000000..0d22c2b --- /dev/null +++ b/DeclROM/NuBusFPGARAMDskDrvr_Prime.c @@ -0,0 +1,350 @@ +#include "NuBusFPGARAMDskDrvr.h" + +/* #include */ + +__attribute__ ((section (".text.dskdriver"))) static inline void waitSome(unsigned long bound) { + unsigned long i; + for (i = 0 ; i < bound ; i++) { + asm volatile("nop"); + } +} + +// CLEANME: use the proper CSR accessor from nubusfpga_csr_exchange_with_mem.h + +#ifdef ENABLE_DMA +__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 + ctx->op.blk_offset)); + write_reg(dce, DMA_DMA_ADDR, revb((uint32_t)(ctx->op.ioBuffer + (ctx->op.blk_done << ctx->dma_blk_size_shift)))); + ctx->op.blk_done += ctx->op.blk_doing; + ctx->op.blk_todo -= ctx->op.blk_doing; + ctx->op.blk_offset += ctx->op.blk_doing; + write_reg(dce, DMA_BLK_CNT, revb((ctx->op.write ? 0x80000000ul : 0x00000000ul) | ctx->op.blk_doing)); + } +} +#endif + +#ifdef ENABLE_DMA +__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 * ctx->op.blk_doing; + delay = (ctx->op.blk_doing >> 4); + if (delay > 65536) + delay = 65536; + waitSome(delay); + count = 0; + blk_cnt = revb(read_reg(dce, DMA_BLK_CNT)) & 0xFFFF; + status = revb(read_reg(dce, DMA_STATUS)) & DMA_STATUS_CHECK_BITS; + while (((blk_cnt != 0) || + (status != 0)) && + (count < max_count)) { + count ++; + waitSome(delay); + if (blk_cnt) blk_cnt = revb(read_reg(dce, DMA_BLK_CNT)) & 0xFFFF; + if (status) status = revb(read_reg(dce, DMA_STATUS)) & DMA_STATUS_CHECK_BITS; + } + if (blk_cnt || status) { + ret = ctx->op.write ? writErr : readErr; + } + return ret; +} +#endif + +#ifdef ENABLE_DMA +/* 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(read_reg(dce, DMA_IRQSTATUS)); + if (irq & 1) { + unsigned int irqctrl = revb(read_reg(dce, DMA_IRQ_CTL)); + irqctrl |= 0x2; // irq clear + write_reg(dce, DMA_IRQ_CTL, revb(irqctrl)); + if (ctx->op.blk_todo > 0) { + startOneOp(ctx, dce); + } else { + if (ctx->op.blk_doing > 0) { + ctx->op.blk_doing = 0; // reset just in case + IODone((DCtlPtr)dce, noErr); + } + } + ret = 1; + } + asm volatile("" : : "d" (p_D1), "d" (p_D2)); + return ret; +} +#endif + +#ifdef ENABLE_DMA +__attribute__ ((section (".text.dskdriver"))) static OSErr doAsync(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce, struct RAMDrvContext *ctx) { + OSErr ret = noErr; + + unsigned char* superslot = (unsigned char*)(((unsigned long)ctx->slot) << 28ul); + unsigned long abs_offset = 0; + /* IOParamPtr: Devices 1-53 (p73) */ + /* **** WHERE **** */ + switch(pb->ioPosMode & 0x000F) { // ignore rdVerify + case fsAtMark: + abs_offset = dce->dCtlPosition; + break; + case fsFromStart: + abs_offset = pb->ioPosOffset; + break; + case fsFromMark: + abs_offset = dce->dCtlPosition + pb->ioPosOffset; + break; + default: + break; + } + /* **** WHAT **** */ + /* Devices 1-33 (p53) */ + if ((pb->ioTrap & 0x00FF) == aRdCmd) { + if(!(pb->ioPosMode & 0x40)) { // rdVerify, let's ignore it for now + 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)) { + 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; + /* should we do it now ? */ + pb->ioActCount = pb->ioReqCount; + dce->dCtlPosition = abs_offset + pb->ioReqCount; + pb->ioPosOffset = dce->dCtlPosition; + if (ctx->op.blk_todo > 0) { + startOneOp(ctx, dce); + goto done; + } + } + if (blk_cnt || status) { + ret = readErr; + goto done; + } + } + } else if ((pb->ioTrap & 0x00FF) == aWrCmd) { + 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)) { + 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; + /* should we do it now ? */ + pb->ioActCount = pb->ioReqCount; + dce->dCtlPosition = abs_offset + pb->ioReqCount; + pb->ioPosOffset = dce->dCtlPosition; + if (ctx->op.blk_todo > 0) { + startOneOp(ctx, dce); + goto done; + } + } + if (blk_cnt || status) { + ret = writErr; + goto done; + } + } else { + ret = paramErr; + goto done; + } + + done: + return ret; +} +#endif // ENABLE_DMA + +__attribute__ ((section (".text.dskdriver"))) static OSErr doSync(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce, struct RAMDrvContext *ctx) { + OSErr ret = noErr; + + unsigned char* superslot = (unsigned char*)(((unsigned long)ctx->slot) << 28ul); + unsigned long abs_offset = 0; + /* IOParamPtr: Devices 1-53 (p73) */ + /* **** WHERE **** */ + switch(pb->ioPosMode & 0x000F) { // ignore rdVerify + case fsAtMark: + abs_offset = dce->dCtlPosition; + break; + case fsFromStart: + abs_offset = pb->ioPosOffset; + break; + case fsFromMark: + abs_offset = dce->dCtlPosition + pb->ioPosOffset; + break; + default: + break; + } + /* **** WHAT **** */ + /* Devices 1-33 (p53) */ + if ((pb->ioTrap & 0x00FF) == aRdCmd) { + if(!(pb->ioPosMode & 0x40)) { // rdVerify, let's ignore it for now +#ifdef ENABLE_DMA + /* write_reg(dce, GOBOFB_DEBUG, 0xD1580000); */ + /* write_reg(dce, GOBOFB_DEBUG, (unsigned long)pb->ioBuffer); */ + /* write_reg(dce, GOBOFB_DEBUG, pb->ioReqCount); */ + 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)) { + 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)) { + 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; + } + } + if (blk_cnt || status) { + ret = readErr; + goto done; + } + } else +#endif + { + BlockMoveData((superslot + abs_offset), pb->ioBuffer, pb->ioReqCount); + } + } + pb->ioActCount = pb->ioReqCount; + dce->dCtlPosition = abs_offset + pb->ioReqCount; + pb->ioPosOffset = dce->dCtlPosition; + } else if ((pb->ioTrap & 0x00FF) == aWrCmd) { +#ifdef ENABLE_DMA + /* write_reg(dce, GOBOFB_DEBUG, 0xD1580001); */ + /* write_reg(dce, GOBOFB_DEBUG, (unsigned long)pb->ioBuffer); */ + /* write_reg(dce, GOBOFB_DEBUG, pb->ioReqCount); */ + 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)) { + 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)) { + 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; + } + } + if (blk_cnt || status) { + ret = writErr; + goto done; + } + } else +#endif + { + BlockMoveData(pb->ioBuffer, (superslot + abs_offset), pb->ioReqCount); + } + pb->ioActCount = pb->ioReqCount; + dce->dCtlPosition = abs_offset + pb->ioReqCount; + pb->ioPosOffset = dce->dCtlPosition; + } else { + ret = paramErr; + goto done; + } + + done: + ctx->op.blk_doing = 0; + return ret; +} + +/* Devices 1-34 (p54) */ +#pragma parameter __D0 cNuBusFPGARAMDskPrime(__A0, __A1) +OSErr cNuBusFPGARAMDskPrime(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + OSErr ret = noErr; + struct RAMDrvContext *ctx; + unsigned long abs_offset = 0; + /* IOParamPtr: Devices 1-53 (p73) */ + /* **** WHERE **** */ + switch(pb->ioPosMode & 0x000F) { // ignore rdVerify + case fsAtMark: + abs_offset = dce->dCtlPosition; + break; + case fsFromStart: + abs_offset = pb->ioPosOffset; + break; + case fsFromMark: + abs_offset = dce->dCtlPosition + pb->ioPosOffset; + break; + default: + break; + } + + /* write_reg(dce, GOBOFB_DEBUG, 0xDEAD0003); */ + /* write_reg(dce, GOBOFB_DEBUG, pb->ioTrap); */ + /* write_reg(dce, GOBOFB_DEBUG, pb->ioPosMode); */ + /* write_reg(dce, GOBOFB_DEBUG, pb->ioReqCount); */ + /* write_reg(dce, GOBOFB_DEBUG, pb->ioPosOffset); */ + + ctx = *(struct RAMDrvContext**)dce->dCtlStorage; + + if (ctx) { +#ifdef ENABLE_DMA + 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) && + (!(pb->ioTrap & (1<ioTrap & 0x00FF) == aWrCmd ? writErr : readErr); + if (ret != noErr) { + IODone((DCtlPtr)dce, ret); + goto done; + } + // DMA-ifiable & queuable, go async + ret = doAsync(pb, dce, ctx); + // no IODone if ongoing, done at interrupt time + if (ret != noErr) + IODone((DCtlPtr)dce, ret); + goto done; + } else +#endif + { +#ifdef ENABLE_DMA + ret = changeRAMDskIRQ(dce, 0, (pb->ioTrap & 0x00FF) == aWrCmd ? writErr : readErr); +#endif + if (ret) + goto done; + ret = doSync(pb, dce, ctx); + if (!(pb->ioTrap & (1<ioTrap & (1<csCode); */ + + ctx = *(struct RAMDrvContext**)dce->dCtlStorage; + + if (ctx) { + switch (pb->csCode) + { + default: + ret = statusErr; + break; + } + } else { + ret = offLinErr; /* r/w requested for an off-line drive */ + goto done; + } + + done: + if (!(pb->ioTrap & (1< +#include +#include +#include +#include +#include + +#include "NuBusFPGADrvr.h" + +struct SDCardContext { + DrvSts2 drvsts; + unsigned int dma_blk_size; + unsigned int dma_blk_size_mask; + unsigned int dma_blk_size_shift; + unsigned int dma_blk_per_sdblk; + unsigned int dma_blk_per_sdblk_lshift; + char slot; + char toto; + unsigned int max_rd_blk_len; + SlotIntQElement *siqel; +}; + +#include "nubusfpga_csr_common.h" + +#if defined(NUBUSFPGA) +#include "../nubusfpga_csr_sdblock2mem.h" +#include "../nubusfpga_csr_sdcore.h" +//#include "../nubusfpga_csr_sdirq.h" +#include "../nubusfpga_csr_sdmem2block.h" +#include "../nubusfpga_csr_sdphy.h" +#include "../nubusfpga_csr_exchange_with_sd.h" +#elif defined(IISIFPGA) +#include "../IIsifpga_csr_sdblock2mem.h" +#include "../IIsifpga_csr_sdcore.h" +//#include "../IIsifpga_csr_sdirq.h" +#include "../IIsifpga_csr_sdmem2block.h" +#include "../IIsifpga_csr_sdphy.h" +#include "../IIsifpga_csr_exchange_with_sd.h" +#elif defined(QUADRAFPGA) +#include "../quadrafpga_csr_sdblock2mem.h" +#include "../quadrafpga_csr_sdcore.h" +//#include "../quadrafpga_csr_sdirq.h" +#include "../quadrafpga_csr_sdmem2block.h" +#include "../quadrafpga_csr_sdphy.h" +#include "../quadrafpga_csr_exchange_with_sd.h" +#else +#error "no board defined" +#endif + +/* basically Litex BIOS code */ + +#ifndef CONFIG_CLOCK_FREQUENCY +#define CONFIG_CLOCK_FREQUENCY 100000000 +#endif + + +#define CLKGEN_STATUS_BUSY 0x1 +#define CLKGEN_STATUS_PROGDONE 0x2 +#define CLKGEN_STATUS_LOCKED 0x4 + +#define SD_CMD_RESPONSE_SIZE 16 + +#define SD_OK 0 +#define SD_CRCERROR 1 +#define SD_TIMEOUT 2 +#define SD_WRITEERROR 3 + +#define SD_SWITCH_CHECK 0 +#define SD_SWITCH_SWITCH 1 + +#define SD_SPEED_SDR12 0 +#define SD_SPEED_SDR25 1 +#define SD_SPEED_SDR50 2 +#define SD_SPEED_SDR104 3 +#define SD_SPEED_DDR50 4 + +#define SD_DRIVER_STRENGTH_B 0 +#define SD_DRIVER_STRENGTH_A 1 +#define SD_DRIVER_STRENGTH_C 2 +#define SD_DRIVER_STRENGTH_D 3 + +#define SD_GROUP_ACCESSMODE 0 +#define SD_GROUP_COMMANDSYSTEM 1 +#define SD_GROUP_DRIVERSTRENGTH 2 +#define SD_GROUP_POWERLIMIT 3 + +#define SDCARD_STREAM_STATUS_OK 0b000 +#define SDCARD_STREAM_STATUS_TIMEOUT 0b001 +#define SDCARD_STREAM_STATUS_DATAACCEPTED 0b010 +#define SDCARD_STREAM_STATUS_CRCERROR 0b101 +#define SDCARD_STREAM_STATUS_WRITEERROR 0b110 + +#define SDCARD_CTRL_DATA_TRANSFER_NONE 0 +#define SDCARD_CTRL_DATA_TRANSFER_READ 1 +#define SDCARD_CTRL_DATA_TRANSFER_WRITE 2 + +#define SDCARD_CTRL_RESPONSE_NONE 0 +#define SDCARD_CTRL_RESPONSE_SHORT 1 +#define SDCARD_CTRL_RESPONSE_LONG 2 +#define SDCARD_CTRL_RESPONSE_SHORT_BUSY 3 + +//#define SDCARD_DEBUG +#define SDCARD_CMD23_SUPPORT /* SET_BLOCK_COUNT */ +#define SDCARD_CMD18_SUPPORT /* READ_MULTIPLE_BLOCK */ +#define SDCARD_CMD25_SUPPORT /* WRITE_MULTIPLE_BLOCK */ + +#ifndef SDCARD_CLK_FREQ_INIT +#define SDCARD_CLK_FREQ_INIT 400000 +#endif + +#ifndef SDCARD_CLK_FREQ +#define SDCARD_CLK_FREQ 25000000 +//#define SDCARD_CLK_FREQ 12500000 +#endif + + +/* ctrl */ +OSErr cNuBusFPGASDCardCtl(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.sddriver"))); +/* open, close */ +OSErr cNuBusFPGASDCardOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.sddriver"))); +OSErr cNuBusFPGASDCardClose(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.sddriver"))); +void busy_wait(int d) __attribute__ ((section (".text.sddriver"))); +void delay(int d) __attribute__ ((section (".text.sddriver"))); +int sdcard_read(uint32_t sc, struct SDCardContext *ctx, uint32_t block, uint32_t count, uint8_t* buf) __attribute__ ((section (".text.sddriver"))); +int sdcard_write(uint32_t sc, struct SDCardContext *ctx, uint32_t block, uint32_t count, uint8_t* buf) __attribute__ ((section (".text.sddriver"))); +/* prime */ +OSErr cNuBusFPGASDCardPrime(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.sddriver"))); +void waitSome(unsigned long bound) __attribute__ ((section (".text.sddriver"))); +/* status */ +OSErr cNuBusFPGASDCardStatus(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) __attribute__ ((section (".text.sddriver"))); + +uint32_t rledec(uint32_t* out, const uint32_t* in, const uint32_t len) __attribute__ ((section (".text.sddriver"))); + +#endif diff --git a/DeclROM/NuBusFPGASDCardDrvr.s b/DeclROM/NuBusFPGASDCardDrvr.s new file mode 100644 index 0000000..8481b34 --- /dev/null +++ b/DeclROM/NuBusFPGASDCardDrvr.s @@ -0,0 +1,23 @@ +NuBusFPGASDCardDrvr: + .word 0x4f00 /* 0x4f00: ctl, status, read, write, needsLock [Devices.a] */ + .word 0 + .word 0 + .word 0 + /* Entry point offset table */ + /* we can directly call the C version if it has the right calling convention */ + .word cNuBusFPGASDCardOpen - NuBusFPGASDCardDrvr /* open routine */ + .word cNuBusFPGASDCardPrime - NuBusFPGASDCardDrvr /* prime */ + .word cNuBusFPGASDCardCtl - NuBusFPGASDCardDrvr /* control */ + .word cNuBusFPGASDCardStatus- NuBusFPGASDCardDrvr /* status */ + .word cNuBusFPGASDCardClose - NuBusFPGASDCardDrvr /* close */ + +_NuBusFPGASDCardTitle: + .byte _NuBusFPGASDCardTitle_StringEnd-.-1 /* pascal string length */ + .ascii ".NuBusFPGASDCard_Drvr" +_NuBusFPGASDCardTitle_StringEnd: + .word 0 /* version number */ + + /* for entry points: */ + /* A0 pointer to driver parameter block */ + /* A1 pointer to driver device control entry */ + ALIGN 2 diff --git a/DeclROM/NuBusFPGASDCardDrvr_Ctrl.c b/DeclROM/NuBusFPGASDCardDrvr_Ctrl.c new file mode 100644 index 0000000..e992cfb --- /dev/null +++ b/DeclROM/NuBusFPGASDCardDrvr_Ctrl.c @@ -0,0 +1,59 @@ +#include "NuBusFPGASDCardDrvr.h" + +#if 0 +OSErr changeSDCardIRQ(AuxDCEPtr dce, char en, OSErr err) { + struct SDCardContext *ctx = *(struct SDCardContext**)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 ? revb(0x3) : revb(0x2)); // 0x2: always clear pending interrupt + ctx->irqen = en; + } + return noErr; +} +#endif + + +#pragma parameter __D0 cNuBusFPGASDCardCtl(__A0, __A1) +OSErr cNuBusFPGASDCardCtl(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + OSErr ret = noErr; + struct SDCardContext *ctx; + + /* write_reg(dce, GOBOFB_DEBUG, 0xDEAD0002); */ + /* write_reg(dce, GOBOFB_DEBUG, pb->csCode); */ + + ctx = *(struct SDCardContext**)dce->dCtlStorage; + + if (ctx) { + switch (pb->csCode) + { + case kFormat: + ret = noErr; + break; + default: + ret = controlErr; + break; + } + } else { + ret = offLinErr; /* r/w requested for an off-line drive */ + goto done; + } + + done: + if (!(pb->ioTrap & (1< + +/* FYI, missing in library with Retro68 */ +/* void AddDrive(short drvrRefNum, short drvNum, DrvQElPtr qEl); */ + +/* re-implement with Retro68 features */ +/* drVNum to high-order bits of num, drvrRefNum in low-order */ +/* not sure how to do "parameter" without output ? */ +#pragma parameter __D0 AddDrive(__D0, __A0) +__attribute__ ((section (".text.sddriver"))) static inline int dupAddDrive(unsigned long num, DrvQElPtr qEl) { + asm volatile(".word 0xA04E" : : "d" (num), "a" (qEl)); + return num; // should cost nothing, num is already in D0 +} + +static int sdcard_init(struct SDCardContext* sdcc, uint32_t sc) __attribute__ ((section (".text.sddriver"))); + +#include + +#pragma parameter __D0 cNuBusFPGASDCardOpen(__A0, __A1) +OSErr cNuBusFPGASDCardOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + DrvSts2 *dsptr; // pointer to the DrvSts2 in our context + int drvnum = 1; + struct SDCardContext *ctx; + OSErr ret = noErr; + char busMode; + char slot; + + busMode = 1; + SwapMMUMode ( &busMode ); // to32 // this likely won't work on older MacII ??? + + if (dce->dCtlDevBase == 0) { // for some unknown reason, we get an empty dCtlDevBase... + if ((dce->dCtlSlot > 0xE) || (dce->dCtlSlot < 0x9)) { // safety net + SpBlock mySpBlock; + SInfoRecord mySInfoRecord; + mySpBlock.spResult = (long)&mySInfoRecord; + + mySpBlock.spSlot = 0x9; // start at first + mySpBlock.spID = 0; + mySpBlock.spExtDev = 0; + mySpBlock.spCategory = catProto; + mySpBlock.spCType = 0x1000; // typeDrive; + mySpBlock.spDrvrSW = drSwApple; + mySpBlock.spDrvrHW = 0xbeec; // DrHwNuBusFPGADsk + mySpBlock.spTBMask = 0; + ret = SNextTypeSRsrc(&mySpBlock); + if (ret) + goto done; + slot = mySpBlock.spSlot; + } else { + slot = dce->dCtlSlot; + } + dce->dCtlDevBase = 0xF0000000ul | ((unsigned long)slot << 24); + } + + /* write_reg(dce, GOBOFB_DEBUG, 0xDEAD0000); */ + /* write_reg(dce, GOBOFB_DEBUG, dce->dCtlSlot); */ + + if (dce->dCtlStorage == nil) { + DrvQElPtr dq; + for(dq = (DrvQElPtr)(GetDrvQHdr())->qHead; dq; dq = (DrvQElPtr)dq->qLink) { + if (dq->dQDrive >= drvnum) + drvnum = dq->dQDrive+1; + } + + ReserveMemSys(sizeof(struct SDCardContext)); + dce->dCtlStorage = NewHandleSysClear(sizeof(struct SDCardContext)); + if (dce->dCtlStorage == nil) { + ret = openErr; + goto done; + } + + HLock(dce->dCtlStorage); + + ctx = *(struct SDCardContext **)dce->dCtlStorage; + ctx->slot = slot; + ctx->toto = 0; // removeme + + /* init the SDCard, this will also fill out dsptr->driveSize & dsptr->driveS1 */ + if (!sdcard_init(ctx, dce->dCtlDevBase)) { + ret = openErr; + HUnlock(dce->dCtlStorage); + DisposeHandle(dce->dCtlStorage); + dce->dCtlStorage = NULL; + goto done; + } + +#if 0 + ctx->dma_blk_size = exchange_with_sd_blk_size_read(dce->dCtlDevBase); + ctx->dma_blk_size_mask = ctx->dma_blk_size - 1; // size is Po2 + ctx->dma_blk_size_shift = 0; + while ((1 << ctx->dma_blk_size_shift) < ctx->dma_blk_size) // fixme + ctx->dma_blk_size_shift++; + ctx->dma_blk_per_sdblk_lshift = 9 - ctx->dma_blk_size_shift; + ctx->dma_blk_per_sdblk = 1 << ctx->dma_blk_per_sdblk_lshift; // 512 / ctx->dma_blk_size +#endif + + dsptr = &ctx->drvsts; + // dsptr->track /* current track */ + dsptr->writeProt = 0; /* bit 7 = 1 if volume is locked */ + dsptr->diskInPlace = 8; /* disk in drive */ + // dsptr->installed /* drive installed */ + // dsptr->sides /* -1 for 2-sided, 0 for 1-sided */ + // dsptr->QLink /* next queue entry */ + dsptr->qType = 1; /* 1 for HD20 */ /* Files 2-85 (p173) : 1 to enable S1 */ + dsptr->dQDrive = drvnum; /* drive number */ + dsptr->dQRefNum = dce->dCtlRefNum; /* driver reference number */ + // dsptr->dQFSID /* file system ID */ + /* driveSize & driveS1 filled by sdcard_init */ + //dsptr->driveSize = ((DRIVE_SIZE_BYTES/512ul) & 0x0000FFFFul); /* (no comments in Disks.h) */ + //dsptr->driveS1 = ((DRIVE_SIZE_BYTES/512ul) & 0xFFFF0000ul) >> 16; /* */ + // dsptr->driveType + // dsptr->driveManf + // dsptr->driveChar + // dsptr->driveMisc + + // MyAddDrive(dsptr->dQRefNum, drvnum, (DrvQElPtr)&dsptr->qLink); + + // write_reg(dce, GOBOFB_DEBUG, 0x0000DEAD); + + // add the drive + //MyAddDrive(dsptr->dQRefNum, drvnum, (DrvQElPtr)&dsptr->qLink); + dupAddDrive((dsptr->dQRefNum & 0xFFFF) | (drvnum << 16), (DrvQElPtr)&dsptr->qLink); + +#if 0 + ctx->dma_blk_size = revb( read_reg(dce, DMA_BLK_SIZE) ); + ctx->dma_blk_size_mask = ctx->dma_blk_size - 1; // size is Po2 + ctx->dma_blk_size_shift = 0; + while ((1 << ctx->dma_blk_size_shift) < ctx->dma_blk_size) // fixme + ctx->dma_blk_size_shift++; + ctx->dma_blk_base = revb( read_reg(dce, DMA_BLK_BASE) ); + ctx->dma_mem_size = revb( read_reg(dce, DMA_MEM_SIZE) ); + /* write_reg(dce, GOBOFB_DEBUG, 0xD1580002); */ + /* write_reg(dce, GOBOFB_DEBUG, ctx->dma_blk_size); */ + /* write_reg(dce, GOBOFB_DEBUG, ctx->dma_blk_size_mask); */ + /* 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); */ + + { + SlotIntQElement *siqel = (SlotIntQElement *)NewPtrSysClear(sizeof(SlotIntQElement)); + + if (siqel == NULL) { + return openErr; + } + + siqel->sqType = sIQType; + siqel->sqPrio = 7; + siqel->sqAddr = dskIrq; + siqel->sqParm = (long)dce; + ctx->siqel = siqel; + ctx->irqen = 0; + + ctx->op.blk_todo = 0; + ctx->op.blk_done = 0; + ctx->op.blk_offset = 0; + ctx->op.blk_doing = 0; + ctx->op.ioBuffer = 0; + ctx->op.write = 0; + } +#endif + + // auto-mount + if (0) { + ParamBlockRec pbr; + pbr.volumeParam.ioVRefNum = dsptr->dQDrive; + ret = PBMountVol(&pbr); + } + } + + SwapMMUMode ( &busMode ); + + done: + return ret; +} + +#pragma parameter __D0 cNuBusFPGASDCardClose(__A0, __A1) +OSErr cNuBusFPGASDCardClose(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) +{ + OSErr ret = noErr; + struct SDCardContext *ctx = *(struct SDCardContext**)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; + } + return ret; +} + +/*-----------------------------------------------------------------------*/ +/* Helpers */ +/*-----------------------------------------------------------------------*/ + +#define max(x, y) (((x) > (y)) ? (x) : (y)) +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +/* In MacOS + Delay(unsigned long numTicks, unsigned long * finalTicks) + has ticks in 1/60th of a second or 16.6666 ms +*/ + +/* in NetBSD/sparc busy_wait is 1ms * d */ +void busy_wait(int d) { + waitSome(d * 20000); // improveme + return; +} +/* in NetBSD/sparc delay is 1us * d */ +void delay(int d) { + waitSome(d * 20); // improveme + return; +} + +/*-----------------------------------------------------------------------*/ +/* SDCard command helpers */ +/*-----------------------------------------------------------------------*/ + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_wait_cmd_done(uint32_t sc) { + unsigned int event; +#ifdef SDCARD_DEBUG + uint32_t r[SD_CMD_RESPONSE_SIZE/4]; +#endif + for (;;) { + event = sdcore_cmd_event_read(sc); +#ifdef SDCARD_DEBUG + printf("cmdevt: %08x\n", event); +#endif + delay(10); + if (event & 0x1) + break; + } +#ifdef SDCARD_DEBUG + csr_rd_buf_uint32(sc, sc->sc_bhregs_sdcore + (CSR_SDCORE_CMD_RESPONSE_ADDR - CSR_SDCORE_BASE), r, SD_CMD_RESPONSE_SIZE/4); + printf("%08x %08x %08x %08x\n", r[0], r[1], r[2], r[3]); +#endif + if (event & 0x4) + return SD_TIMEOUT; + if (event & 0x8) + return SD_CRCERROR; + return SD_OK; +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_wait_data_done(uint32_t sc) { + unsigned int event; + for (;;) { + event = sdcore_data_event_read(sc); +#ifdef SDCARD_DEBUG + printf("dataevt: %08x\n", event); +#endif + if (event & 0x1) + break; + delay(10); + } + if (event & 0x4) + return SD_TIMEOUT; + else if (event & 0x8) + return SD_CRCERROR; + return SD_OK; +} + +/*-----------------------------------------------------------------------*/ +/* SDCard clocker functions */ +/*-----------------------------------------------------------------------*/ + +/* round up to closest power-of-two */ +__attribute__ ((section (".text.sddriver"))) static inline uint32_t pow2_round_up(uint32_t r) { + r--; + r |= r >> 1; + r |= r >> 2; + r |= r >> 4; + r |= r >> 8; + r |= r >> 16; + r++; + return r; +} + +__attribute__ ((section (".text.sddriver"))) static inline void sdcard_set_clk_freq(uint32_t sc, uint32_t clk_freq, int show) { + uint32_t divider; + divider = clk_freq ? CONFIG_CLOCK_FREQUENCY/clk_freq : 256; + divider = pow2_round_up(divider); + divider = min(max(divider, 2), 256); +#ifdef SDCARD_DEBUG + show = 1; +#endif + if (show) { + /* this is the *effective* new clk_freq */ + clk_freq = CONFIG_CLOCK_FREQUENCY/divider; + /* + printf("Setting SDCard clk freq to "); + if (clk_freq > 1000000) + printf("%d MHz\n", clk_freq/1000000); + else + printf("%d KHz\n", clk_freq/1000); + */ + } + sdphy_clocker_divider_write(sc, divider); +} + +/*-----------------------------------------------------------------------*/ +/* SDCard commands functions */ +/*-----------------------------------------------------------------------*/ + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_send_command(uint32_t sc, uint32_t arg, uint8_t cmd, uint8_t rsp) { + sdcore_cmd_argument_write(sc, arg); + sdcore_cmd_command_write(sc, (cmd << 8) | rsp); + sdcore_cmd_send_write(sc, 1); + return sdcard_wait_cmd_done(sc); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_go_idle(uint32_t sc) { +#ifdef SDCARD_DEBUG + printf("CMD0: GO_IDLE\n"); +#endif + return sdcard_send_command(sc, 0, 0, SDCARD_CTRL_RESPONSE_NONE); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_send_ext_csd(uint32_t sc) { + uint32_t arg = 0x000001aa; +#ifdef SDCARD_DEBUG + printf("CMD8: SEND_EXT_CSD, arg: 0x%08x\n", arg); +#endif + return sdcard_send_command(sc, arg, 8, SDCARD_CTRL_RESPONSE_SHORT); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_app_cmd(uint32_t sc, uint16_t rca) { +#ifdef SDCARD_DEBUG + printf("CMD55: APP_CMD\n"); +#endif + return sdcard_send_command(sc, rca << 16, 55, SDCARD_CTRL_RESPONSE_SHORT); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_app_send_op_cond(uint32_t sc, int hcs) { + uint32_t arg = 0x10ff8000; + if (hcs) + arg |= 0x60000000; +#ifdef SDCARD_DEBUG + printf("ACMD41: APP_SEND_OP_COND, arg: %08x\n", arg); +#endif + return sdcard_send_command(sc, arg, 41, SDCARD_CTRL_RESPONSE_SHORT_BUSY); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_all_send_cid(uint32_t sc) { +#ifdef SDCARD_DEBUG + printf("CMD2: ALL_SEND_CID\n"); +#endif + return sdcard_send_command(sc, 0, 2, SDCARD_CTRL_RESPONSE_LONG); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_set_relative_address(uint32_t sc) { +#ifdef SDCARD_DEBUG + printf("CMD3: SET_RELATIVE_ADDRESS\n"); +#endif + return sdcard_send_command(sc, 0, 3, SDCARD_CTRL_RESPONSE_SHORT); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_send_cid(uint32_t sc, uint16_t rca) { +#ifdef SDCARD_DEBUG + printf("CMD10: SEND_CID\n"); +#endif + return sdcard_send_command(sc, rca << 16, 10, SDCARD_CTRL_RESPONSE_LONG); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_send_csd(uint32_t sc, uint16_t rca) { +#ifdef SDCARD_DEBUG + printf("CMD9: SEND_CSD\n"); +#endif + return sdcard_send_command(sc, rca << 16, 9, SDCARD_CTRL_RESPONSE_LONG); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_select_card(uint32_t sc, uint16_t rca) { +#ifdef SDCARD_DEBUG + printf("CMD7: SELECT_CARD\n"); +#endif + return sdcard_send_command(sc, rca << 16, 7, SDCARD_CTRL_RESPONSE_SHORT_BUSY); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_app_set_bus_width(uint32_t sc) { +#ifdef SDCARD_DEBUG + printf("ACMD6: SET_BUS_WIDTH\n"); +#endif + return sdcard_send_command(sc, 2, 6, SDCARD_CTRL_RESPONSE_SHORT); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_switch(uint32_t sc, unsigned int mode, unsigned int group, unsigned int value) { + unsigned int arg; + arg = (mode << 31) | 0xffffff; + arg &= ~(0xf << (group * 4)); + arg |= value << (group * 4); + //device_printf(sc->dk.sc_dev, "switch arg is 0x%08x\n", arg); +#ifdef SDCARD_DEBUG + printf("CMD6: SWITCH_FUNC\n"); +#endif + sdcore_block_length_write(sc, 64); + sdcore_block_count_write(sc, 1); + while (sdcard_send_command(sc, arg, 6, + (SDCARD_CTRL_DATA_TRANSFER_READ << 5) | + SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); + return sdcard_wait_data_done(sc); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_app_send_scr(uint32_t sc) { +#ifdef SDCARD_DEBUG + printf("CMD51: APP_SEND_SCR\n"); +#endif + sdcore_block_length_write(sc, 8); + sdcore_block_count_write(sc, 1); + while (sdcard_send_command(sc, 0, 51, + (SDCARD_CTRL_DATA_TRANSFER_READ << 5) | + SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); + return sdcard_wait_data_done(sc); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_app_set_blocklen(uint32_t sc, unsigned int blocklen) { +#ifdef SDCARD_DEBUG + printf("CMD16: SET_BLOCKLEN\n"); +#endif + return sdcard_send_command(sc, blocklen, 16, SDCARD_CTRL_RESPONSE_SHORT); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_write_single_block(uint32_t sc, unsigned int blockaddr) { +#ifdef SDCARD_DEBUG + printf("CMD24: WRITE_SINGLE_BLOCK\n"); +#endif + sdcore_block_length_write(sc, 512); + sdcore_block_count_write(sc, 1); + while (sdcard_send_command(sc, blockaddr, 24, + (SDCARD_CTRL_DATA_TRANSFER_WRITE << 5) | + SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); + return SD_OK; +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_write_multiple_block(uint32_t sc, unsigned int blockaddr, unsigned int blockcnt) { +#ifdef SDCARD_DEBUG + printf("CMD25: WRITE_MULTIPLE_BLOCK\n"); +#endif + sdcore_block_length_write(sc, 512); + sdcore_block_count_write(sc, blockcnt); + while (sdcard_send_command(sc, blockaddr, 25, + (SDCARD_CTRL_DATA_TRANSFER_WRITE << 5) | + SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); + return SD_OK; +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_read_single_block(uint32_t sc, unsigned int blockaddr) { +#ifdef SDCARD_DEBUG + printf("CMD17: READ_SINGLE_BLOCK\n"); +#endif + sdcore_block_length_write(sc, 512); + sdcore_block_count_write(sc, 1); + while (sdcard_send_command(sc, blockaddr, 17, + (SDCARD_CTRL_DATA_TRANSFER_READ << 5) | + SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); + return sdcard_wait_data_done(sc); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_read_multiple_block(uint32_t sc, unsigned int blockaddr, unsigned int blockcnt) { +#ifdef SDCARD_DEBUG + printf("CMD18: READ_MULTIPLE_BLOCK\n"); +#endif + sdcore_block_length_write(sc, 512); + sdcore_block_count_write(sc, blockcnt); + while (sdcard_send_command(sc, blockaddr, 18, + (SDCARD_CTRL_DATA_TRANSFER_READ << 5) | + SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); + return sdcard_wait_data_done(sc); +} + +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_stop_transmission(uint32_t sc) { +#ifdef SDCARD_DEBUG + printf("CMD12: STOP_TRANSMISSION\n"); +#endif + return sdcard_send_command(sc, 0, 12, SDCARD_CTRL_RESPONSE_SHORT_BUSY); +} + +#if 0 +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_send_status(uint32_t sc, uint16_t rca) { +#ifdef SDCARD_DEBUG + printf("CMD13: SEND_STATUS\n"); +#endif + return sdcard_send_command(sc, rca << 16, 13, SDCARD_CTRL_RESPONSE_SHORT); +} +#endif + +#if 1 +__attribute__ ((section (".text.sddriver"))) static inline int sdcard_set_block_count(uint32_t sc, unsigned int blockcnt) { +#ifdef SDCARD_DEBUG + printf("CMD23: SET_BLOCK_COUNT\n"); +#endif + return sdcard_send_command(sc, blockcnt, 23, SDCARD_CTRL_RESPONSE_SHORT); +} +#endif + +__attribute__ ((section (".text.sddriver"))) static inline uint16_t sdcard_decode_rca(uint32_t sc) { + uint32_t r[SD_CMD_RESPONSE_SIZE/4]; + csr_rd_buf_uint32(sc, CSR_SDCORE_CMD_RESPONSE_ADDR, r, SD_CMD_RESPONSE_SIZE/4); + return (r[3] >> 16) & 0xffff; +} + +__attribute__ ((section (".text.sddriver"))) static inline void sdcard_decode_cid(uint32_t sc) { + uint32_t r[SD_CMD_RESPONSE_SIZE/4]; + csr_rd_buf_uint32(sc, CSR_SDCORE_CMD_RESPONSE_ADDR, r, SD_CMD_RESPONSE_SIZE/4); + /* aprint_normal_dev(sc->dk.sc_dev, */ + /* "CID Register: 0x%08x%08x%08x%08x " */ + /* "Manufacturer ID: 0x%x " */ + /* "Application ID 0x%x " */ + /* "Product name: %c%c%c%c%c " */ + /* "CRC: %02x " */ + /* "Production date(m/yy): %d/%d " */ + /* "PSN: %08x " */ + /* "OID: %c%c\n", */ + /* r[0], r[1], r[2], r[3], */ + /* (r[0] >> 16) & 0xffff, */ + /* r[0] & 0xffff, */ + /* (r[1] >> 24) & 0xff, (r[1] >> 16) & 0xff, */ + /* (r[1] >> 8) & 0xff, (r[1] >> 0) & 0xff, (r[2] >> 24) & 0xff, */ + /* r[3] & 0xff, */ + /* (r[3] >> 8) & 0x0f, (r[3] >> 12) & 0xff, */ + /* (r[3] >> 24) | (r[2] << 8), */ + /* (r[0] >> 16) & 0xff, (r[0] >> 8) & 0xff */ + /* ); */ +} + +__attribute__ ((section (".text.sddriver"))) static inline void sdcard_decode_csd(struct SDCardContext* sdcc, uint32_t sc) { + uint32_t r[SD_CMD_RESPONSE_SIZE/4]; + csr_rd_buf_uint32(sc, CSR_SDCORE_CMD_RESPONSE_ADDR, r, SD_CMD_RESPONSE_SIZE/4); + /* FIXME: only support CSR structure version 2.0 */ + //sc->max_rd_blk_len = (1 << ((r[1] >> 16) & 0xf)); + //sc->max_size_in_blk = ((r[2] >> 16) + ((r[1] & 0xff) << 16) + 1) * 512 * 2; + uint32_t max_size_in_blk = ((r[2] >> 16) + ((r[1] & 0xff) << 16) + 1) * 512 * 2; // weird spec in 512KiB unit + if (max_size_in_blk >= 4194304) // 2 GiB + max_size_in_blk = 4194303; // 2 GiB - 512 B + +#define MAX_DSK_SIZE_MB 80 + if (max_size_in_blk >= (MAX_DSK_SIZE_MB*(1048576/512))) // TEMPORARY FOR TESTING + max_size_in_blk = (MAX_DSK_SIZE_MB*(1048576/512)); // TEMPORARY FOR TESTING + + sdcc->drvsts.driveSize = max_size_in_blk & 0x0000FFFF; + sdcc->drvsts.driveS1 = (max_size_in_blk & 0xFFFF0000) >> 16; + sdcc->max_rd_blk_len = (1 << ((r[1] >> 16) & 0xf)); // READ_BL_LEN ? should always be 9 ? + /* aprint_normal_dev(sc->dk.sc_dev, */ + /* "CSD Register: 0x%08x%08x%08x%08x " */ + /* "Max data transfer rate: %d MB/s " */ + /* "Max read block length: %d bytes " */ + /* "Device size: %d GiB (%d blocks)\n", */ + /* r[0], r[1], r[2], r[3], */ + /* (r[0] >> 24) & 0xff, */ + /* sc->max_rd_blk_len, */ + /* ((r[2] >> 16) + ((r[1] & 0xff) << 16) + 1) * 512 / (1024 * 1024), */ + /* sc->max_size_in_blk */ + /* ); */ +} + +/*-----------------------------------------------------------------------*/ +/* SDCard user functions */ +/*-----------------------------------------------------------------------*/ +static int sdcard_init(struct SDCardContext* sdcc, uint32_t sc) { + uint16_t rca, timeout; + int res; + + /* Set SD clk freq to Initialization frequency */ + sdcard_set_clk_freq(sc, SDCARD_CLK_FREQ_INIT, 0); + busy_wait(1); + + for (timeout=1000; timeout>0; timeout--) { + /* Set SDCard in SPI Mode (generate 80 dummy clocks) */ + sdphy_init_initialize_write(sc, 1); + busy_wait(1); + + /* Set SDCard in Idle state */ + if (sdcard_go_idle(sc) == SD_OK) + break; + busy_wait(1); + } + if (timeout == 0) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard timeout (1)\n"); + return 0; + } + + /* Set SDCard voltages, only supported by ver2.00+ SDCards */ + if ((res = sdcard_send_ext_csd(sc)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_send_ext_csd failed\n"); + return 0; + } + + /* Set SD clk freq to Operational frequency */ + sdcard_set_clk_freq(sc, SDCARD_CLK_FREQ, 0); + busy_wait(1); + + /* Set SDCard in Operational state */ + for (timeout=1000; timeout>0; timeout--) { + sdcard_app_cmd(sc, 0); + if ((res = sdcard_app_send_op_cond(sc, 1)) != SD_OK) + break; + busy_wait(1); + } + if (timeout == 0) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard timeout (2)\n"); + return 0; + } + + /* Send identification */ + if ((res = sdcard_all_send_cid(sc)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_all_send_cid failed (%d)\n", res); + return 0; + } + sdcard_decode_cid(sc); + + /* Set Relative Card Address (RCA) */ + if ((res = sdcard_set_relative_address(sc)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_set_relative_address failed (%d)\n", res); + return 0; + } + rca = sdcard_decode_rca(sc); + //device_printf(sc->dk.sc_dev, "rca is 0x%08x\n", rca); + + /* Set CID */ + if ((res = sdcard_send_cid(sc, rca)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_send_cid failed (%d)\n", res); + return 0; + } +#ifdef SDCARD_DEBUG + /* FIXME: add cid decoding (optional) */ +#endif + + /* Set CSD */ + if ((res = sdcard_send_csd(sc, rca)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_send_csd failed (%d)\n", res); + return 0; + } + + sdcard_decode_csd(sdcc, sc); + + /* Select card */ + if ((res = sdcard_select_card(sc, rca)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_select_card failed (%d)\n", res); + return 0; + } + + /* Set bus width */ + if ((res = sdcard_app_cmd(sc, rca)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_app_cmd failed (%d)\n", res); + return 0; + } + if((res = sdcard_app_set_bus_width(sc)) != SD_OK){ + //aprint_error_dev(sc->dk.sc_dev, "sdcard_app_set_bus_width failed (%d)\n", res); + return 0; + } + + /* Switch speed */ + if ((res = sdcard_switch(sc, SD_SWITCH_SWITCH, SD_GROUP_ACCESSMODE, SD_SPEED_SDR25)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_switch failed (%d)\n", res); + return 0; + } + + /* Send SCR */ + /* FIXME: add scr decoding (optional) */ + if ((res = sdcard_app_cmd(sc, rca)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_app_cmd failed (%d)\n", res); + return 0; + } + if ((res = sdcard_app_send_scr(sc)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_app_send_scr failed (%d)\n", res); + return 0; + } + + /* Set block length */ + if ((res = sdcard_app_set_blocklen(sc, 512)) != SD_OK) { + //aprint_error_dev(sc->dk.sc_dev, "sdcard_app_set_blocklen failed (%d)\n", res); + return 0; + } + + return 1; +} + +#if 1 +__attribute__ ((section (".text.sddriver"))) static inline void do_copy_rev(uint32_t *src, uint32_t *dst, uint32_t size) { + uint32_t i; + for (i = 0 ; i < size/4 ; i++) { + dst[i] = revb(src[i]); + } +} +#endif + +__attribute__ ((section (".text.sddriver"))) static inline OSErr start_dma_read(uint32_t sc, struct SDCardContext *ctx, uint32_t count, uint8_t* buf) { + unsigned int dma_blk_cnt = count << ctx->dma_blk_per_sdblk_lshift; + + exchange_with_sd_blk_addr_write(sc, 0); + exchange_with_sd_dma_addr_write(sc, buf); + exchange_with_sd_blk_cnt_write(sc, dma_blk_cnt | 0x80000000); // MSb==1, read + return noErr; +} +__attribute__ ((section (".text.sddriver"))) static inline OSErr start_dma_write(uint32_t sc, struct SDCardContext *ctx, uint32_t count, uint8_t* buf) { + unsigned int dma_blk_cnt = count << ctx->dma_blk_per_sdblk_lshift; + + exchange_with_sd_blk_addr_write(sc, 0); + exchange_with_sd_dma_addr_write(sc, buf); + exchange_with_sd_blk_cnt_write(sc, dma_blk_cnt); // MSb==0, write + return noErr; +} +#if 0 +#define DMA_STATUS_CHECK_BITS (0x01F) +__attribute__ ((section (".text.sddriver"))) static inline OSErr wait_dma(uint32_t sc, uint32_t blk_count, OSErr err) { + unsigned long count, max_count, delay; + unsigned long blk_cnt, status; + OSErr ret = noErr; + max_count = 32 * blk_count; + delay = blk_count >> 2; + if (delay > 65536) + delay = 65536; + waitSome(delay); + count = 0; + blk_cnt = exchange_with_sd_blk_cnt_blk_cnt_read(sc); + status = exchange_with_sd_dma_status_read(sc) & DMA_STATUS_CHECK_BITS; + while (((blk_cnt != 0) || + (status != 0)) && + (count < max_count)) { + count ++; + waitSome(delay); + if (blk_cnt) blk_cnt = exchange_with_sd_blk_cnt_blk_cnt_read(sc); + if (status) status = exchange_with_sd_dma_status_read(sc) & DMA_STATUS_CHECK_BITS; + } + if (blk_cnt || status) { + ret = err; + } + return ret; +} +#endif + +int sdcard_read(uint32_t sc, struct SDCardContext *ctx, uint32_t block, uint32_t count, uint8_t* buf) { + while (count) { + uint32_t nblocks; + //uint64_t buf_hw_addr = ((uint64_t)((uint32_t)buf));// << 32; + uint32_t buf_hw_addr = (uint32_t)buf; // TEMPORARY FOR TESTING // VIRTUAL NEEDS TO GO THROUGH MemoryManager + uint32_t stage_addr_dma = 0x80000000; // DDR // TEMPORARY FOR TESTING + uint32_t stage_addr_cpu = sc << 4; // superslot // TEMPORARY FOR TESTING +#ifdef SDCARD_CMD18_SUPPORT + nblocks = count; + if (nblocks > 16) + nblocks = 16; +#else + nblocks = 1; +#endif + +#if 1 + /* Initialize DMA Writer */ + sdblock2mem_dma_enable_write(sc, 0); + /* sdblock2mem_dma_base_write takes an uint64_t */ + ////sdblock2mem_dma_base_write(sc, buf_hw_addr); + sdblock2mem_dma_base_write(sc, stage_addr_dma); + sdblock2mem_dma_length_write(sc, 512*nblocks); + sdblock2mem_dma_enable_write(sc, 1); +#else + start_dma_write(sc, ctx, nblocks, buf_hw_addr); // read from sdcard, write to memory +#endif + + /* Read Block(s) from SDCard */ +#ifdef SDCARD_CMD23_SUPPORT + sdcard_set_block_count(sc, nblocks); +#endif + if (nblocks > 1) + sdcard_read_multiple_block(sc, block, nblocks); + else + sdcard_read_single_block(sc, block); + +#if 1 + //int timeout = 64 * nblocks; + int timeout = 1024 * nblocks; + /* Wait for DMA Writer to complete */ + while (((sdblock2mem_dma_done_read(sc) & 0x1) == 0) && timeout) { + //delay(2); + delay(20); + timeout --; + } + if ((sdblock2mem_dma_done_read(sc) & 0x1) == 0) { + /* device_printf(sc->dk.sc_dev, "%s: SD card timeout\n", __PRETTY_FUNCTION__); */ + return 1; + } +#else + if (wait_dma(sc, nblocks, readErr) != noErr) + return 1; +#endif + + /* Stop transmission (Only for multiple block reads) */ + if (nblocks > 1) + sdcard_stop_transmission(sc); + + BlockMoveData((void*)stage_addr_cpu, (void*)buf_hw_addr, 512*nblocks); + //do_copy_rev((void*)stage_addr_cpu, (void*)buf_hw_addr, 512*nblocks); + + + /* Update Block/Buffer/Count */ + block += nblocks; + buf += 512*nblocks; + count -= nblocks; + } + + return 0; +} + +int sdcard_write(uint32_t sc, struct SDCardContext *ctx, uint32_t block, uint32_t count, uint8_t* buf) { + while (count) { + uint32_t nblocks; + //uint64_t buf_hw_addr = ((uint64_t)((uint32_t)buf));// << 32; + uint32_t buf_hw_addr = (uint32_t)buf; // TEMPORARY FOR TESTING + uint32_t stage_addr_dma = 0x80000000; // DDR // TEMPORARY FOR TESTING + uint32_t stage_addr_cpu = sc << 4; // superslot // TEMPORARY FOR TESTING +#ifdef SDCARD_CMD25_SUPPORT + nblocks = count; + if (nblocks > 16) + nblocks = 16; +#else + nblocks = 1; +#endif + + BlockMoveData((void*)buf_hw_addr, (void*)stage_addr_cpu, 512*nblocks); + //do_copy_rev((void*)buf_hw_addr, (void*)stage_addr_cpu, 512*nblocks); + +#if 1 + /* Initialize DMA Reader */ + sdmem2block_dma_enable_write(sc, 0); + /* sdblock2mem_dma_base_write takes an uint64_t */ + ////sdmem2block_dma_base_write(sc, buf_hw_addr); + sdmem2block_dma_base_write(sc, stage_addr_dma); + sdmem2block_dma_length_write(sc, 512*nblocks); + sdmem2block_dma_enable_write(sc, 1); +#else + start_dma_read(sc, ctx, nblocks, buf_hw_addr); // write to sdcard, read from memory +#endif + + /* Write Block(s) to SDCard */ +#ifdef SDCARD_CMD23_SUPPORT + sdcard_set_block_count(sc, nblocks); +#endif + if (nblocks > 1) + sdcard_write_multiple_block(sc, block, nblocks); + else + sdcard_write_single_block(sc, block); + + /* Stop transmission (Only for multiple block writes) */ + //if (nblocks > 1) + // sdcard_stop_transmission(sc); + +#if 1 + /* Wait for DMA Reader to complete */ + //int timeout = 64 * nblocks; + int timeout = 1024 * nblocks; + while (((sdmem2block_dma_done_read(sc) & 0x1) == 0) && timeout) { + //delay(2); + delay(20); + timeout --; + } + if ((sdmem2block_dma_done_read(sc) & 0x1) == 0) { + /* device_printf(sc->dk.sc_dev, "%s: SD card timeout\n", __PRETTY_FUNCTION__); */ + return 1; + } +#else + if (wait_dma(sc, nblocks, writErr) != noErr) + return 1; +#endif + + if (nblocks > 1) + sdcard_stop_transmission(sc); + + /* Update Block/Buffer/Count */ + block += nblocks; + buf += 512*nblocks; + count -= nblocks; + } + + return 0; +} diff --git a/DeclROM/NuBusFPGASDCardDrvr_Prime.c b/DeclROM/NuBusFPGASDCardDrvr_Prime.c new file mode 100644 index 0000000..3abba08 --- /dev/null +++ b/DeclROM/NuBusFPGASDCardDrvr_Prime.c @@ -0,0 +1,111 @@ +#include "NuBusFPGASDCardDrvr.h" + +/* #include */ + +inline void waitSome(unsigned long bound) { + unsigned long i; + for (i = 0 ; i < bound ; i++) { + asm volatile("nop"); + } +} + +__attribute__ ((section (".text.sddriver"))) static OSErr doSync(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce, struct SDCardContext *ctx) { + OSErr ret = noErr; + + unsigned char* superslot = (unsigned char*)(((unsigned long)ctx->slot) << 28ul); + unsigned long abs_offset = 0; + /* IOParamPtr: Devices 1-53 (p73) */ + /* **** WHERE **** */ + switch(pb->ioPosMode & 0x000F) { // ignore rdVerify + case fsAtMark: + abs_offset = dce->dCtlPosition; + break; + case fsFromStart: + abs_offset = pb->ioPosOffset; + break; + case fsFromMark: + abs_offset = dce->dCtlPosition + pb->ioPosOffset; + break; + default: + break; + } + /* **** WHAT **** */ + /* Devices 1-33 (p53) */ + if ((pb->ioTrap & 0x00FF) == aRdCmd) { + if(!(pb->ioPosMode & 0x40)) { // rdVerify, let's ignore it for now + if (abs_offset & 0x01FF) { + ret = paramErr; + *(uint32_t*)(dce->dCtlDevBase | 0x00902000 | 0x804) = abs_offset; + *(uint32_t*)(dce->dCtlDevBase | 0x00902000 | 0x808) = pb->ioReqCount; + goto done; + } + if (pb->ioReqCount & 0x01FF) { + ret = paramErr; + *(uint32_t*)(dce->dCtlDevBase | 0x00902000 | 0x804) = abs_offset; + *(uint32_t*)(dce->dCtlDevBase | 0x00902000 | 0x808) = pb->ioReqCount; + goto done; + } + if (sdcard_read(dce->dCtlDevBase, ctx, abs_offset >> 9, pb->ioReqCount >> 9, pb->ioBuffer)) { + ret = readErr; + goto done; + } + } + pb->ioActCount = pb->ioReqCount; + dce->dCtlPosition = abs_offset + pb->ioReqCount; + pb->ioPosOffset = dce->dCtlPosition; + } else if ((pb->ioTrap & 0x00FF) == aWrCmd) { + if (abs_offset & 0x01FF) { + ret = paramErr; + *(uint32_t*)(dce->dCtlDevBase | 0x00902000 | 0x804) = abs_offset; + *(uint32_t*)(dce->dCtlDevBase | 0x00902000 | 0x808) = pb->ioReqCount; + goto done; + } + if (pb->ioReqCount & 0x01FF) { + ret = paramErr; + *(uint32_t*)(dce->dCtlDevBase | 0x00902000 | 0x804) = abs_offset; + *(uint32_t*)(dce->dCtlDevBase | 0x00902000 | 0x808) = pb->ioReqCount; + goto done; + } + if (sdcard_write(dce->dCtlDevBase, ctx, abs_offset >> 9, pb->ioReqCount >> 9, pb->ioBuffer)) { + ret = writErr; + goto done; + } + pb->ioActCount = pb->ioReqCount; + dce->dCtlPosition = abs_offset + pb->ioReqCount; + pb->ioPosOffset = dce->dCtlPosition; + } else { + ret = paramErr; + goto done; + } + done: + if (ret != noErr) + *(uint32_t*)(dce->dCtlDevBase | 0x00902000 | 0x800) = ret | (((pb->ioTrap & 0x00FF) == aRdCmd) ? 0x11000000 : 0x22000000); + return ret; +} + +/* Devices 1-34 (p54) */ +#pragma parameter __D0 cNuBusFPGASDCardPrime(__A0, __A1) +OSErr cNuBusFPGASDCardPrime(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce) { + OSErr ret = noErr; + struct SDCardContext *ctx; + unsigned long abs_offset = 0; + + ctx = *(struct SDCardContext**)dce->dCtlStorage; + + if (ctx) { + ret = doSync(pb, dce, ctx); + if (!(pb->ioTrap & (1<ioTrap & (1<csCode); */ + + ctx = *(struct SDCardContext**)dce->dCtlStorage; + + if (ctx) { + switch (pb->csCode) + { + default: + ret = statusErr; + break; + } + } else { + ret = offLinErr; /* r/w requested for an off-line drive */ + goto done; + } + + done: + if (!(pb->ioTrap & (1< + +#define SECO_WRITEREG(reg, val) \ + *((volatile UInt32*)(a32+GOBOFB_BASE+reg)) = (UInt32)val; + +#pragma parameter __D0 Primary(__A0) +UInt32 Secondary(SEBlock* seblock) { + UInt32 a32 = 0xF0000000 | ((UInt32)seblock->seSlot << 24); + UInt32 a32_l0, a32_l1; + UInt32 a32_4p0, a32_4p1; + SpBlock spblock; + /* UInt8 pram[8]; */ + OSErr err; + UInt16 i,j; + char busMode; + UniversalProcPtr qd32ptr, unimpptr; + + busMode = 1; + + /* call SVersion to figure out if we have a recent SlotManager */ +#if 0 + //spblock.spSlot = seblock->seSlot; + //spblock.spExtDev = 0; + err = SVersion(&spblock); + + busMode = 1; + SwapMMUMode ( &busMode ); // to32 + if (err) { + /* DCDMF3 p178: if error, old slot manager*/ + /* SECO_WRITEREG(GOBOFB_DEBUG, 0xFFFFFFFF);*/ + /* SECO_WRITEREG(GOBOFB_DEBUG, err);*/ + } else { + /* DCDMF3 p178: new slot manager */ + /* SECO_WRITEREG(GOBOFB_DEBUG, 0);*/ + /* SECO_WRITEREG(GOBOFB_DEBUG, spblock.spResult);*/ + } + SwapMMUMode ( &busMode ); // restore +#endif + +#if 1 + /* check for 32-bits QuickDraw */ + qd32ptr = GetTrapAddress(Check32QDTrap); + unimpptr = GetTrapAddress(_Unimplemented); + + busMode = 1; + SwapMMUMode ( &busMode ); // to32 + if (qd32ptr == unimpptr) { + /* no 32QD */ + SECO_WRITEREG(GOBOFB_DEBUG, 0xFFFFFFFF); + SECO_WRITEREG(GOBOFB_DEBUG, unimpptr); + } else { + /* yes 32QD */ + SECO_WRITEREG(GOBOFB_DEBUG, 0x00C0FFEE); + } + SwapMMUMode ( &busMode ); // restore +#endif + + +#if 0 + /* check the content of the PRAM */ + spblock.spSlot = seblock->seSlot; + spblock.spResult = (UInt32)pram; + err = SReadPRAMRec(&spblock); + +#if 0 + SECO_WRITEREG(GOBOFB_DEBUG, 0x88888888); + for (j = 0 ; j < 8 ; j++) + SECO_WRITEREG(GOBOFB_DEBUG, (uint32_t)pram[j]); + SECO_WRITEREG(GOBOFB_DEBUG, 0x88888888); +#endif +#endif + +#if 0 + busMode = 1; + SwapMMUMode ( &busMode ); // to32 + if (err) { + /* SECO_WRITEREG(GOBOFB_DEBUG, 0xFFFFFFFF);*/ + /* SECO_WRITEREG(GOBOFB_DEBUG, err);*/ + } else { + /* SECO_WRITEREG(GOBOFB_DEBUG, 0xC0FFEE00);*/ + /* for (i = 0 ; i < 8 ; i++) */ + /* SECO_WRITEREG(GOBOFB_DEBUG, pram[i]);*/ + } + SwapMMUMode ( &busMode ); // restore +#endif + + seblock->seStatus = 1; + + return 0; +} + diff --git a/DeclROM/ROMDefs.inc b/DeclROM/ROMDefs.inc new file mode 100644 index 0000000..21be1ad --- /dev/null +++ b/DeclROM/ROMDefs.inc @@ -0,0 +1,197 @@ +appleFormat = 1 +romRevision = 1 +romRevRange = 9 +testPattern = 1519594439L +sCodeRev = 2 +sExec2 = 2 +sCPU68000 = 1 +sCPU68020 = 2 +sCPU68030 = 3 +sCPU68040 = 4 +sMacOS68000 = 1 +sMacOS68020 = 2 +sMacOS68030 = 3 +sMacOS68040 = 4 +board = 0 +displayVideoAppleTFB = 16843009L +displayVideoAppleGM = 16843010L +networkEtherNetApple3Com = 33620225L +testSimpleAppleAny = -2147417856L +endOfList = 255 +defaultTO = 100 +fOpenAtStart = 1 +f32BitMode = 2 +sRsrcType = 1 +sRsrcName = 2 +sRsrcIcon = 3 +sRsrcDrvrDir = 4 +sRsrcLoadDir = 5 +sRsrcBootRec = 6 +sRsrcFlags = 7 +sRsrcHWDevId = 8 +minorBaseOS = 10 +majorBaseOS = 12 +majorLength = 13 +sRsrcTest = 14 +sRsrccicn = 15 +sRsrcicl8 = 16 +sRsrcicl4 = 17 +sDRVRDir = 16 +sGammaDir = 64 +sRsrcVidNames = 65 +sRsrcDock = 80 +sDiagRec = 85 +sVidAuxParams = 123 +sDebugger = 124 +sVidAttributes = 125 +fLCDScreen = 0 +fBuiltInDisplay = 1 +fDefaultColor = 2 +fActiveBlack = 3 +fDimMinAt1 = 4 +fBuiltInDetach = 4 +sVidParmDir = 126 +sBkltParmDir = 140 +sSuperDir = 254 +/* = */ +/* = */ +catBoard = 0x0001 +catTest = 0x0002 +catDisplay = 0x0003 +catNetwork = 0x0004 +catScanner = 0x0008 +catCPU = 0x000A +catIntBus = 0x000C +catProto = 0x0011 +catDock = 0x0020 +typeBoard = 0x0000 +typeApple = 0x0001 +typeVideo = 0x0001 +typeEtherNet = 0x0001 +typeStation = 0x0001 +typeDesk = 0x0002 +typeTravel = 0x0003 +typeDSP = 0x0004 +typeXPT = 0x000B +typeSIM = 0x000C +typeDebugger = 0x0100 +type68000 = 0x0002 +type68020 = 0x0003 +type68030 = 0x0004 +type68040 = 0x0005 +type601 = 0x0025 +type603 = 0x002E +typeAppleII = 0x0015 +drSwMacCPU = 0 +drSwAppleIIe = 0x0001 +drSwApple = 1 +drSwMacsBug = 0x0104 +drSwDepewEngineering = 0x0101 +drHwTFB = 1 +drHw3Com = 1 +drHwBSC = 3 +drHwGemini = 1 +drHwDeskBar = 1 +drHwATT3210 = 0x0001 +drHwBootBug = 0x0100 +drHwMicroDock = 0x0100 +drHwSTB3 = 0x0002 +drHwSTB = drHwSTB3 +drHwRBV = 0x0018 +drHwElsie = 0x001A +drHwTim = 0x001B +drHwDAFB = 0x001C +drHwGSC = 0x001E +drHwDAFBPDS = 0x001F +drHWVSC = 0x0020 +drHwApollo = 0x0021 +drHwSonora = 0x0022 +drHwReserved2 = 0x0023 +drHwColumbia = 0x0024 +drHwCivic = 0x0025 +drHwBrazil = 0x0026 +drHWPBLCD = 0x0027 +drHWCSC = 0x0028 +drHwJET = 0x0029 +drHWMEMCjr = 0x002A +drHwHPV = 0x002C +drHwPlanaria = 0x002D +drHwValkyrie = 0x002E +drHwKeystone = 0x002F +drHWATI = 0x0055 +drHwGammaFormula = 0x0056 +drHwSonic = 0x0110 +drHwMace = 0x0114 +drHwDblExp = 0x0001 +MIIBoardId = 0x0010 +ciVidBoardID = 0x001F +CX16VidBoardID = 0x0020 +MIIxBoardId = 0x0021 +SE30BoardID = 0x0022 +MIIcxBoardId = 0x0023 +MIIfxBoardId = 0x0024 +EricksonBoardID = 0x0028 +ElsieBoardID = 0x0029 +TIMBoardID = 0x002A +EclipseBoardID = 0x002B +SpikeBoardID = 0x0033 +DBLiteBoardID = 0x0035 +ZydecoBrdID = 0x0036 +ApolloBoardID = 0x0038 +PDMBrdID = 0x0039 +VailBoardID = 0x003A +WombatBrdID = 0x003B +ColumbiaBrdID = 0x003C +CycloneBrdID = 0x003D +CompanionBrdID = 0x003E +DartanianBoardID = 0x0040 +DartExtVidBoardID = 0x0046 +HookBoardID = 0x0047 +EscherBoardID = 0x004A +POBoardID = 0x004D +TempestBrdID = 0x0050 +BlackBirdBdID = 0x0058 +BBExtVidBdID = 0x0059 +YeagerBoardID = 0x005A +BBEtherNetBdID = 0x005E +TELLBoardID = 0x0065 +MalcolmBoardID = 0x065E +AJBoardID = 0x065F +M2BoardID = 0x0660 +OmegaBoardID = 0x0661 +TNTBoardID = 0x0670 +HooperBoardID = 0x06CD +BoardIDDblExp = 0x002F +DAFBPDSBoardID = 0x0037 +MonetBoardID = 0x0048 +SacSONIC16BoardID = 0x004E +SacSONIC32BoardID = 0x004F +drHWMacII = 0x0001 +drHwMacIIx = 0x0002 +drHWSE30 = 0x0003 +drHwMacIIcx = 0x0004 +drHWMacIIfx = 0x0005 +drHWF19 = 0x0005 +sBlockTransferInfo = 20 +sMaxLockedTransferCount = 21 +boardId = 32 +pRAMInitData = 33 +primaryInit = 34 +timeOutConst = 35 +vendorInfo = 36 +boardFlags = 37 +secondaryInit = 38 +MajRAMSp = 129 +MinROMSp = 130 +vendorId = 1 +serialNum = 2 +revLevel = 3 +partNum = 4 +date = 5 +testByte = 32 +testWord = 33 +testLong = 34 +testString = 35 +mBlockTransferInfo = 5 +mMaxLockedTransferCount = 6 + diff --git a/DeclROM/Video.inc b/DeclROM/Video.inc new file mode 100644 index 0000000..2c8cc2e --- /dev/null +++ b/DeclROM/Video.inc @@ -0,0 +1,358 @@ +mBaseOffset = 1 /*IdofmBaseOffset.*/ +mRowBytes = 2 /*VideosResourceparameterId's*/ +mBounds = 3 /*VideosResourceparameterId's*/ +mVersion = 4 /*VideosResourceparameterId's*/ +mHRes = 5 /*VideosResourceparameterId's*/ +mVRes = 6 /*VideosResourceparameterId's*/ +mPixelType = 7 /*VideosResourceparameterId's*/ +mPixelSize = 8 /*VideosResourceparameterId's*/ +mCmpCount = 9 /*VideosResourceparameterId's*/ +mCmpSize = 10 /*VideosResourceparameterId's*/ +mPlaneBytes = 11 /*VideosResourceparameterId's*/ +mVertRefRate = 14 /*VideosResourceparameterId's*/ +mVidParams = 1 /*Videoparameterblockid.*/ +mTable = 2 /*Offsettothetable.*/ +mPageCnt = 3 /*Numberofpages*/ +mDevType = 4 /*DeviceType*/ +oneBitMode = 128 /*IdofOneBitModeParameterlist.*/ +twoBitMode = 129 /*IdofTwoBitModeParameterlist.*/ +fourBitMode = 130 /*IdofFourBitModeParameterlist.*/ +eightBitMode = 131/*IdofEightBitModeParameterlist.*/ +sixteenBitMode = 132 /*IdofSixteenBitModeParameterlist.*/ +thirtyTwoBitMode = 133 /*IdofThirtyTwoBitModeParameterlist.*/ +firstVidMode = 128 /*Thenew,betterwaytodotheabove.*/ +secondVidMode = 129 /*QuickDrawonlysupportssixvideo*/ +thirdVidMode = 130 /*atthistime.*/ +fourthVidMode = 131 +fifthVidMode = 132 +sixthVidMode = 133 +spGammaDir = 64 +spVidNamesDir = 65 +/* kDeclROMtables = FOUR_CHAR_CODE('decl') */ +/* kDetailedTimingFormat = FOUR_CHAR_CODE('arba') */ /*Timingisadetailedtiming*/ +kDDCBlockSize = 128 +kDDCBlockTypeEDID = 0/*EDIDblocktype.*/ +kDDCForceReadBit = 0 /*ForceanewreadoftheEDID.*/ +kDDCForceReadMask = (1<? +timingVESA_1600x1200_85hz = 289 /*1600x1200(85Hz)VESAtiming(pixelclockis229.5 +timingVESA_1792x1344_60hz = 296 /*1792x1344(60Hz)VESAtiming(204.75Mhzdotclock). +timingVESA_1792x1344_75hz = 298 /*1792x1344(75Hz)VESAtiming(261.75Mhzdotclock). +timingVESA_1856x1392_60hz = 300 /*1856x1392(60Hz)VESAtiming(218.25Mhzdotclock). +timingVESA_1856x1392_75hz = 302 /*1856x1392(75Hz)VESAtiming(288Mhzdotclock). +timingVESA_1920x1440_60hz = 304 /*1920x1440(60Hz)VESAtiming(234Mhzdotclock). +timingVESA_1920x1440_75hz = 306 /*1920x1440(75Hz)VESAtiming(297Mhzdotclock). +timingSMPTE240M_60hz = 400 /*60HzV,33.75KHzH,interlacedtiming,16:9aspect,typical +timingFilmRate_48hz = 410 /*48HzV,25.20KHzH,non-interlacedtiming,typicalresolutionof +timingSony_1600x1024_76hz = 500 /*1600x1024(76Hz)Sonytiming(pixelclockis170.447 +timingSony_1920x1080_60hz = 510 /*1920x1080(60Hz)Sonytiming(pixelclockis159.84 +timingSony_1920x1080_72hz = 520 /*1920x1080(72Hz)Sonytiming(pixelclockis216.023 +timingSony_1920x1200_76hz = 540 /*1900x1200(76Hz)Sonytiming(pixelclockis243.20 +timingApple_0x0_0hz_Offline = 550/*Indicatesthatthistimingwilltakethedisplayoff-line +timingApple12 = timingApple_512x384_60hz +timingApple12x = timingApple_560x384_60hz +timingApple13 = timingApple_640x480_67hz +timingApple13x = timingApple_640x400_67hz +timingAppleVGA = timingVESA_640x480_60hz +timingApple15 = timingApple_640x870_75hz +timingApple15x = timingApple_640x818_75hz +timingApple16 = timingApple_832x624_75hz +timingAppleSVGA = timingVESA_800x600_56hz +timingApple1Ka = timingVESA_1024x768_60hz +timingApple1Kb = timingVESA_1024x768_70hz +timingApple19 = timingApple_1024x768_75hz +timingApple21 = timingApple_1152x870_75hz +timingSony_1900x1200_74hz = 530 /*1900x1200(74Hz)Sonytiming(pixelclockis236.25 +timingSony_1900x1200_76hz = timingSony_1920x1200_76hz/*1900x1200(76Hz)Sonytiming(pixelclockis245.48 +kAllModesValid = 0 /*Allmodesnottrimmedbyprimaryinitaregood +kAllModesSafe = 1 /*Allmodesnottrimmedbyprimaryinitareknow +kReportsTagging = 2 /*Candetecttaggeddisplays(toidentifysmartmonitors)*/ +kHasDirectConnection = 3 /*Trueimpliesthatdrivercantalkdirectlytodevice +kUncertainConnection = 5 /*Theremaynotbeadisplay(nosenselines?). +kTaggingInfoNonStandard = 6 /*SetwhencsConnectTaggedType/csConnectTaggedDataarenon-standard(i.e.,nottheApple +kReportsDDCConnection = 7 /*Cardcandoddc(setkHasDirectConnect&&kHasDDCConnectif +kHasDDCConnection = 8 /*Cardhasddcconnectnow.*/ +kConnectionInactive = 9 /*SetwhentheconnectionisNOTcurrentlyactive(generally +kDependentConnection = 10 /*SetwhensomeascpectofTHISconnectiondependson +kBuiltInConnection = 11 /*SetwhenconnectionisKNOWNtobebuilt-in(this +kOverrideConnection = 12 /*Setwhenthereportedconnectionisnotthetrue +kFastCheckForDDC = 13 /*Setwhenall3aretrue:1)sensecodes +kReportsHotPlugging = 14/*Detectsandreportshotplugggingonconnector(viaVSL +kPanelConnect = 2 /*Forusewithfixed-in-placeLCDpanels.*/ +kPanelTFTConnect = 2 /*AliasforkPanelConnect*/ +kFixedModeCRTConnect = 3 /*Forusewithfixed-mode(i.e.,verylimitedrange)displays. +kMultiModeCRT1Connect = 4 /*320x200maybe,12"maybe,13"(default),16"certain,19" +kMultiModeCRT2Connect = 5 /*320x200maybe,12"maybe,13"certain,16"(default),19" +kMultiModeCRT3Connect = 6 /*320x200maybe,12"maybe,13"certain,16"certain,19" +kMultiModeCRT4Connect = 7 /*Expansiontolargemultimode(notyetused)*/ +kModelessConnect = 8 /*Expansiontomodelessmodel(notyetused)*/ +kFullPageConnect = 9 /*640x818(toget8bppin512Kcase)and640x870 +kVGAConnect = 10 /*640x480VGAdefault--questioneverythingelse*/ +kNTSCConnect = 11 /*NTSCST(default),FF,STconv,FFconv*/ +kPALConnect = 12 /*PALST(default),FF,STconv,FFconv*/ +kHRConnect = 13 /*Straight-6connect--640x480and640x400(toget8bpp +kMonoTwoPageConnect = 15 /*1152x870Applecolortwo-pagedisplay*/ +kColorTwoPageConnect = 16 /*1152x870AppleB&Wtwo-pagedisplay*/ +kColor16Connect = 17 /*832x624AppleB&Wtwo-pagedisplay*/ +kColor19Connect = 18 /*1024x768AppleB&Wtwo-pagedisplay*/ +kGenericCRT = 19 /*IndicatesnothingexceptthatconnectionisCRTinnature. +kGenericLCD = 20 /*IndicatesnothingexceptthatconnectionisLCDinnature. +kDDCConnect = 21 /*DDCconnection,alwayssetkHasDDCConnection*/ +kNoConnect = 22/*Nodisplayisconnected-loadsensingorsimilar +kModeValid = 0 /*SaysthatthismodeshouldNOTbetrimmed.*/ +kModeSafe = 1 /*Thismodedoesnotneedconfirmation*/ +kModeDefault = 2 /*Thisisthedefaultmodeforthistypeof +kModeShowNow = 3 /*Thismodeshouldalwaysbeshown(eventhoughit +kModeNotResize = 4 /*Thismodeshouldnotbeusedtoresizethe +kModeRequiresPan = 5 /*Thismodehasmorepixelsthanareactuallydisplayed +kModeInterlaced = 6 /*Thismodeisinterlaced(singlepixellineslookbad). +kModeShowNever = 7 /*Thismodeshouldnotbeshownintheuser +kModeSimulscan = 8 /*Indicatesthatmorethanonedisplayconnectioncanbe +kModeNotPreset = 9 /*Indicatesthatthetimingisnotafactorypreset +kModeBuiltIn = 10 /*Indicatesthatthedisplaymodeisforthebuilt-in +kModeStretched = 11/*Indicatesthatthedisplaymodewillbestretched/distortedto +kDepthDependent = 0/*Saysthatthisdepthmodemaycausedependentchanges +kResolutionHasMultipleDepthSizes = 0/*SaysthatthismodehasdifferentcsHorizontalPixels csVerticalLinesat +kAVPowerOff = 0 /*Powerfullyoff*/ +kAVPowerStandby = 1 +kAVPowerSuspend = 2 +kAVPowerOn = 3 +kHardwareSleep = 128 +kHardwareWake = 129 +kHardwareWakeFromSuspend = 130 +kHardwareWakeToDoze = 131 +kHardwareWakeToDozeFromSuspend = 132 +cscReset = 0 +cscKillIO = 1 +cscSetMode = 2 +cscSetEntries = 3 +cscSetGamma = 4 +cscGrayPage = 5 +cscGrayScreen = 5 +cscSetGray = 6 +cscSetInterrupt = 7 +cscDirectSetEntries = 8 +cscSetDefaultMode = 9 +cscSwitchMode = 10 /*TakesaVDSwitchInfoPtr*/ +cscSetSync = 11 /*TakesaVDSyncInfoPtr*/ +cscSavePreferredConfiguration = 16 /*TakesaVDSwitchInfoPtr*/ +cscSetHardwareCursor = 22 /*TakesaVDSetHardwareCursorPtr*/ +cscDrawHardwareCursor = 23 /*TakesaVDDrawHardwareCursorPtr*/ +cscSetConvolution = 24 /*TakesaVDConvolutionInfoPtr*/ +cscSetPowerState = 25 /*TakesaVDPowerStatePtr*/ +cscPrivateControlCall = 26 /*TakesaVDPrivateSelectorDataPtr*/ +cscSetMultiConnect = 28 /*TakesaVDMultiConnectInfoPtr*/ +cscSetClutBehavior = 29 /*TakesaVDClutBehavior*/ +cscSetDetailedTiming = 31 /*TakesaVDDetailedTimingPtr*/ +cscDoCommunication = 33 /*TakesaVDCommunicationPtr*/ +cscProbeConnection = 34 /*Takesnilpointer(maygenerateakFBConnectInterruptServiceTypeserviceinterrupt)*/ +cscUnusedCall = 127/*Thiscallusedtoexpendthescrnresource.Its +cscGetMode = 2 +cscGetEntries = 3 +cscGetPageCnt = 4 +cscGetPages = 4 /*ThisiswhatC&D2callsit.*/ +cscGetPageBase = 5 +cscGetBaseAddr = 5 /*ThisiswhatC&D2callsit.*/ +cscGetGray = 6 +cscGetInterrupt = 7 +cscGetGamma = 8 +cscGetDefaultMode = 9 +cscGetCurMode = 10 /*TakesaVDSwitchInfoPtr*/ +cscGetSync = 11 /*TakesaVDSyncInfoPtr*/ +cscGetConnection = 12 /*Returninformationabouttheconnectiontothedisplay*/ +cscGetModeTiming = 13 /*Returntiminginfoforamode*/ +cscGetModeBaseAddress = 14 /*Returnbaseaddressinformationaboutaparticularmode*/ +cscGetScanProc = 15 /*QuickTimescanchasingroutine*/ +cscGetPreferredConfiguration = 16 /*TakesaVDSwitchInfoPtr*/ +cscGetNextResolution = 17 /*TakesaVDResolutionInfoPtr*/ +cscGetVideoParameters = 18 /*TakesaVDVideoParametersInfoPtr*/ +cscGetGammaInfoList = 20 /*TakesaVDGetGammaListPtr*/ +cscRetrieveGammaTable = 21 /*TakesaVDRetrieveGammaPtr*/ +cscSupportsHardwareCursor = 22 /*TakesaVDSupportsHardwareCursorPtr*/ +cscGetHardwareCursorDrawState = 23 /*TakesaVDHardwareCursorDrawStatePtr*/ +cscGetConvolution = 24 /*TakesaVDConvolutionInfoPtr*/ +cscGetPowerState = 25 /*TakesaVDPowerStatePtr*/ +cscPrivateStatusCall = 26 /*TakesaVDPrivateSelectorDataPtr*/ +cscGetDDCBlock = 27 /*TakesaVDDDCBlockPtr*/ +cscGetMultiConnect = 28 /*TakesaVDMultiConnectInfoPtr*/ +cscGetClutBehavior = 29 /*TakesaVDClutBehaviorPtr*/ +cscGetTimingRanges = 30 /*TakesaVDDisplayTimingRangePtr*/ +cscGetDetailedTiming = 31 /*TakesaVDDetailedTimingPtr*/ +cscGetCommunicationInfo = 32/*TakesaVDCommunicationInfoPtr*/ +kDisableHorizontalSyncBit = 0 +kDisableVerticalSyncBit = 1 +kDisableCompositeSyncBit = 2 +kEnableSyncOnBlue = 3 +kEnableSyncOnGreen = 4 +kEnableSyncOnRed = 5 +kNoSeparateSyncControlBit = 6 +kTriStateSyncBit = 7 +kHorizontalSyncMask = 0x01 +kVerticalSyncMask = 0x02 +kCompositeSyncMask = 0x04 +kDPMSSyncMask = 0x07 +kTriStateSyncMask = 0x80 +kSyncOnBlueMask = 0x08 +kSyncOnGreenMask = 0x10 +kSyncOnRedMask = 0x20 +kSyncOnMask = 0x38 +kDPMSSyncOn = 0 +kDPMSSyncStandby = 1 +kDPMSSyncSuspend = 2 +kDPMSSyncOff = 7 +kConvolved = 0 +kLiveVideoPassThru = 1 +kConvolvedMask = 0x01 +kLiveVideoPassThruMask = 0x02 +kRSCZero = 0 +kRSCOne = 1 +kRSCTwo = 2 +kRSCThree = 3 +kRSCFour = 4 +kRSCFive = 5 +kRSCSix = 6 +kRSCSeven = 7 +kESCZero21Inch = 0x00 /*21"RGB*/ +kESCOnePortraitMono = 0x14 /*PortraitMonochrome*/ +kESCTwo12Inch = 0x21 /*12"RGB*/ +kESCThree21InchRadius = 0x31 /*21"RGB(Radius)*/ +kESCThree21InchMonoRadius = 0x34 /*21"Monochrome(Radius)*/ +kESCThree21InchMono = 0x35 /*21"Monochrome*/ +kESCFourNTSC = 0x0A /*NTSC*/ +kESCFivePortrait = 0x1E /*PortraitRGB*/ +kESCSixMSB1 = 0x03 /*MultiScanBand-1(12"thru1Six")*/ +kESCSixMSB2 = 0x0B /*MultiScanBand-2(13"thru19")*/ +kESCSixMSB3 = 0x23 /*MultiScanBand-3(13"thru21")*/ +kESCSixStandard = 0x2B /*13"/14"RGBor12"Monochrome*/ +kESCSevenPAL = 0x00 /*PAL*/ +kESCSevenNTSC = 0x14 /*NTSC*/ +kESCSevenVGA = 0x17 /*VGA*/ +kESCSeven16Inch = 0x2D /*16"RGB(GoldFish)*/ +kESCSevenPALAlternate = 0x30 /*PAL(Alternate)*/ +kESCSevenDDC = 0x3E /*DDCdisplay*/ +kESCSevenNoDisplay = 0x3F/*Nodisplayconnected*/ +kDepthMode1 = 128 +kDepthMode2 = 129 +kDepthMode3 = 130 +kDepthMode4 = 131 +kDepthMode5 = 132 +kDepthMode6 = 133 +kFirstDepthMode = 128 /*Theseconstantsareobsolete,andjustincluded*/ +kSecondDepthMode = 129 /*forclientsthathaveconvertedtotheabove*/ +kThirdDepthMode = 130 /*kDepthModeXXXconstants.*/ +kFourthDepthMode = 131 +kFifthDepthMode = 132 +kSixthDepthMode = 133 +kDisplayModeIDCurrent = 0x00 /*ReferencetheCurrentDisplayModeID*/ +kDisplayModeIDInvalid = 0xFFFFFFFF /*AbogusDisplayModeIDinallcases*/ +kDisplayModeIDFindFirstResolution = 0xFFFFFFFE /*UsedincscGetNextResolutiontoresetiterator*/ +kDisplayModeIDNoMoreResolutions = 0xFFFFFFFD /*UsedincscGetNextResolutiontoindicateEndOfList*/ +kDisplayModeIDFindFirstProgrammable = 0xFFFFFFFC /*UsedincscGetNextResolutiontofindunusedprogrammabletiming*/ +kDisplayModeIDBootProgrammable = 0xFFFFFFFB /*ThisistheIDgivenatboottimeby +kDisplayModeIDReservedBase = 0x80000000/*Lowest(unsigned)DisplayModeIDreservedbyApple*/ +kGammaTableIDFindFirst = 0xFFFFFFFE /*GetthefirstgammatableID*/ +kGammaTableIDNoMoreTables = 0xFFFFFFFD /*Usedtoindicateendoflist*/ +kGammaTableIDSpecific = 0x00/*Returntheinfoforthegiventableid*/ +kActivateConnection = (0< +kSyncPositivePolarityMask = (1<nXJ4h z(>B79Ia8DgCN$mBSdO@-dm{a#d&kllBhn^9BVBFL$hNJ?kg&=ij96sXSuZyY(VxcK z@ee-fE+w)^`H1RI9{GbZ{)7rp8Hw zt#wqt!*+5k?-M=CP!Gg2{UdGZ;lBQCbZ~Sm()J9CX^X?r*4H{i%p-dk zNbQttm{S%&`)%&Rfjp|FuateTQS{9~%tzW0t(@LN{%n~l*3U7EwpcxiVveE?`BOz5 zjt?9I(yzNh;1Ip=Yu<)%Lfm(FA3jM3OGoFJ{PTF$!?F}!nDtUD0=$cT4B2my0sXLZ znmdzKz8OFXd(zApx-4xCeM%z>VgdbN0vpQq3Go2kv6cPNh4Yar<*g;1cINt+$U5=b zO|S6znJ@YQ;G9JbEVH%&26!cRA$6^&ItNkr$W~dylnOl1B4<=$qx2%r*i^wAwcfEk zY3P|ppq$1&jXM*n=a~4cL`O##_`X1eZv223&yB)?z?Qh+0bu`ciayBr;iS-qm}ki? z!Fw6|vx0{iuNV>h4&&7y3m#$Ia9J?SqQHi$g0qY_ekNGy9bnAvP{2I20DrjvD>)Ow z^E1=WDg3M8Lrm|wP@+fW$S9s|f0XF4eI@?n`4T-LLAqUFIXja=@3kx=(8~~^WqR)h z!Mf1jT=LB+FR#d>7I;KlasH*0aO-+X3&mLrwHW9av8XY^o*9QGE3%7a^AZ{(ZdSo6 zOrtv^NRpczmp^|*M4!z}nhBb0hdnsW%u>9!l!g4+X*tLXXxOJQ|DS3~HEHtHrKx<~ z04`WR#ww}``tqLyEAj`-{ZyNO(*274&iCvWb!L@Bt)`JG&GVOYyCycblDDamyk;S* z$0ldrZ_mB$>Kr1kcZjOVJ6!iNuYH%TK5=-xcH65LIqIz&!TudzU8a z=*Cfg?i{_GyUCJQ1wFAzy3V7vD?UTj(dno=HXiiUr`Zt4Pd>BU_`FHX;QRNqhH5OU zkpijmU?bI>-B|xtY}~v>O|QqXyQ;mBe5rCH8E&9VX7%a1^`?=m?Vv+OMJkE4<*BHV zqy~uFXLNr!OBY|v(;LA7+DR^Rd$1W{S(ZQ39pCb8#o4B{W?>V1iFjPuZgkdeCwFZc z7mPQ!f-SEy67fVlI_)L4+(?t#NYoENlPBde+E1-hcKHoh literal 0 HcmV?d00001 diff --git a/DeclROM/gen_mode.c b/DeclROM/gen_mode.c new file mode 100644 index 0000000..f12b768 --- /dev/null +++ b/DeclROM/gen_mode.c @@ -0,0 +1,288 @@ +#include +#include +#include +#include + +struct one_res { + const unsigned short hres; + const unsigned short vres; + const unsigned char native_only; +}; + +#define NUM_RES 16 +#if 1 +static struct one_res res_db[NUM_RES] = { + { 1920, 1080, 0 }, + { 1680, 1050, 0 }, // should be unsuitable + { 1600, 900, 1 }, // freaks out my monitor on 1920x1080, it thinks it's 1680x1050... + { 1440, 900, 0 }, + + { 1280, 1024, 0 }, + { 1280, 960, 0 }, + { 1280, 800, 0 }, + { 1152, 870, 0 }, + + { 1152, 864, 0 }, + { 1024, 768, 0 }, + { 832, 624, 0 }, + { 800, 600, 0 }, + + { 768, 576, 0 }, + { 640, 480, 0 }, + { 512, 384, 0 }, + { 0, 0, 0 } +}; +#else +static struct one_res res_db[NUM_RES] = { + { 1920, 1080, 0 }, + { 1600, 900, 1 }, + /* { 640, 480, 0 }, */ + { 0, 0, 0} +}; +#endif + +int main(int argc, char **argv) { + unsigned short maxhres = 1920, maxvres = 1080; + const int depthdb[6] = { 8, 4, 2, 1, 32, 16 }; + int enabled[NUM_RES]; + int i, j; + unsigned char id; + + for (i = 0 ; i < NUM_RES ; i++) { + enabled[i] = 0; + } + + if (argc == 3) { + maxhres = atoi(argv[1]); + maxvres = atoi(argv[2]); + } + fprintf(stderr, "Resolution: %hu x %hu\n", maxhres, maxvres); + + id = 0x80; + for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) && (id < 0x90); i++) { // 0x90 is the ram disk + char filename[512]; + const unsigned short hres = res_db[i].hres; + const unsigned short vres = res_db[i].vres; + FILE *fd; + + if ((hres * vres) % 128) // unsuitable, safety net + continue; + + if (res_db[i].native_only && ((hres != maxhres) || (vres != maxvres))) + continue; + + if ((hres > maxhres) || (vres > maxvres)) + continue; + + snprintf(filename, 512, "VidRomRes_%hux%hu.s", hres, vres); + fd = fopen(filename, "w"); + if (fd == NULL) { + fprintf(stderr, "Generating '%s' failed.\n", filename); + return -1; + } + enabled[i] = 1; + id ++; + + for (j = 0 ; j < 6 ; j++) { + char modename[128]; + const unsigned short depth = depthdb[j]; + const unsigned short rowBytes = (hres * depth) / 8; + snprintf(modename, 128, "R%hux%huD%d", hres, vres, depth); + + fprintf(fd, "\tALIGN 2\n"); + fprintf(fd, "_%sModes: /* id 0x%02x */\n", modename, id-1); + fprintf(fd, "\tOSLstEntry\tmVidParams,_%sParms\t/* offset to vid parameters */\n", modename); + fprintf(fd, "\tDatLstEntry\tmPageCnt,%d\t/* number of video pages */\n", (depth == 32) ? 1 : 2); + fprintf(fd, "\tDatLstEntry\tmDevType,%s\t/* device type */\n", depth <= 8 ? "clutType" : "directType"); + fprintf(fd, "\t.long\tEndOfList\t/* end of list */\n"); + fprintf(fd, "_%sParms:\n", modename); + fprintf(fd, "\t.long\t_End%sParms-_%sParms\t/* physical block size */\n", modename, modename); + fprintf(fd, "\t.long\t0\t/* QuickDraw base offset ; vpBaseOffset */\n"); // defmBaseOffset + fprintf(fd, "\t.word\t%hu\t/* physRowBytes ; vpRowBytes */\n", rowBytes); + fprintf(fd, "\t.word\t0,0,%hu,%hu\t/* vpBounds */\n", vres, hres); + fprintf(fd, "\t.word\tdefVersion\t/* bmVersion ; vpVersion */\n"); + fprintf(fd, "\t.word\t0\t/* packType not used ; vpPackType */\n"); + fprintf(fd, "\t.long\t0\t/* packSize not used ; vpPackSize */\n"); + fprintf(fd, "\t.long\tdefmHRes\t/* bmHRes */\n"); + fprintf(fd, "\t.long\tdefmVRes\t/* bmVRes */\n"); + fprintf(fd, "\t.word\t%s\t/* bmPixelType */\n", depth <= 8 ? "ChunkyIndexed" : "ChunkyDirect"); + fprintf(fd, "\t.word\t%d\t/* bmPixelSize */\n", depth); + fprintf(fd, "\t.word\t%d\t/* bmCmpCount */\n", depth <= 8 ? 1 : 3); + fprintf(fd, "\t.word\t%d\t/* bmCmpSize */\n", depth <= 8 ? depth : (depth == 32 ? 8 : 5)); + fprintf(fd, "\t.long\t0\t/* bmPlaneBytes */\n"); // defmPlaneBytes + fprintf(fd, "_End%sParms:\n\n",modename); + } + fclose(fd); + } + + { + char filename[512]; + FILE *fd; + id = 0x80; + snprintf(filename, 512, "VidRomRes.s"); + fd = fopen(filename, "w"); + if (fd == NULL) { + fprintf(stderr, "Generating '%s' failed.\n", filename); + return -1; + } + + for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) ; i++) { + const unsigned short hres = res_db[i].hres; + const unsigned short vres = res_db[i].vres; + if (enabled[i]) { + fprintf(fd, ".include \"VidRomRes_%hux%hu.s\"\n", hres, vres); + } + } + + fclose(fd); + } + + { + char filename[512]; + FILE *fd; + snprintf(filename, 512, "VidRomName.s"); + fd = fopen(filename, "w"); + if (fd == NULL) { + fprintf(stderr, "Generating '%s' failed.\n", filename); + return -1; + } + fprintf(fd, "\tALIGN 2\n"); + fprintf(fd, "_VModeName:\n"); + + for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) ; i++) { + const unsigned short hres = res_db[i].hres; + const unsigned short vres = res_db[i].vres; + if (enabled[i]) { + fprintf(fd, "\tOSLstEntry\tsRsrc_GoboFB_R%hux%hu,_ScreenNameGoboFB_R%hux%hu\n", hres, vres, hres, vres); + } + } + fprintf(fd, "\tDatLstEntry endOfList, 0\n"); + + for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) ; i++) { + const unsigned short hres = res_db[i].hres; + const unsigned short vres = res_db[i].vres; + if (enabled[i]) { + int native = (hres == maxhres) && (vres == maxvres); + fprintf(fd, "\tALIGN 2\n"); + fprintf(fd, "_ScreenNameGoboFB_R%hux%hu:\n", hres, vres); + fprintf(fd, "\t.long\t_ScreenNameGoboFB_R%hux%huEnd - _ScreenNameGoboFB_R%hux%hu\n", hres, vres, hres, vres); + fprintf(fd, "\t.word\t0\n"); + fprintf(fd, "\t.string\t\"GoblinFB %hux%hu%s\\0\"\n", hres, vres, native ? " (N)": ""); + fprintf(fd, "_ScreenNameGoboFB_R%hux%huEnd:\n", hres, vres); + } + } + + fclose(fd); + } + + { + char filename[512]; + FILE *fd; + snprintf(filename, 512, "VidRomDir_%hux%hu.s", maxhres, maxvres); + fd = fopen(filename, "w"); + if (fd == NULL) { + fprintf(stderr, "Generating '%s' failed.\n", filename); + return -1; + } + for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) ; i++) { + const unsigned short hres = res_db[i].hres; + const unsigned short vres = res_db[i].vres; + if (enabled[i]) { + int native = (hres == maxhres) && (vres == maxvres); + fprintf(fd, "\tALIGN 2\n"); + fprintf(fd, "_sRsrc_GoboFB_R%hux%hu:\n", hres, vres); + fprintf(fd, "\tOSLstEntry\tsRsrcType,_GoboFBType\t/* video type descriptor */\n"); + fprintf(fd, "\tOSLstEntry\tsRsrcName,_GoboFBName\t/* offset to driver name string */\n"); + fprintf(fd, "\tOSLstEntry\tsRsrcDrvrDir,_GoboFBDrvrDir /* offset to driver directory */\n"); + fprintf(fd, "\tDatLstEntry\tsRsrcFlags,%d\t/* force 32 bits mode & open (native) - or not (others)*/\n", native ? 6 : 0); + fprintf(fd, "\tDatLstEntry\tsRsrcHWDevId,1\t/* hardware device ID */\n"); + fprintf(fd, "\tOSLstEntry\tMinorBaseOS,_MinorBase\t/* offset to frame buffer array */\n"); + fprintf(fd, "\tOSLstEntry\tMinorLength,_MinorLength\t/* offset to frame buffer length */\n"); + fprintf(fd, "\t/* OSLstEntry\tsGammaDir,_GammaDirS\t/* directory for 640x480 monitor */\n"); + fprintf(fd, "/* Parameters */\n"); + fprintf(fd, "\tOSLstEntry\tfirstVidMode,_R%hux%huD8Modes\t/* offset to 8 Bit Mode parms */\n", hres, vres); + fprintf(fd, "\tOSLstEntry\tsecondVidMode,_R%hux%huD4Modes\t/* offset to 4 Bit Mode parms */\n", hres, vres); + fprintf(fd, "\tOSLstEntry\tthirdVidMode,_R%hux%huD2Modes\t/* offset to 2 Bit Mode parms */\n", hres, vres); + fprintf(fd, "\tOSLstEntry\tfourthVidMode,_R%hux%huD1Modes\t/* offset to 1 Bit Mode parms */\n", hres, vres); + fprintf(fd, "\tOSLstEntry\tfifthVidMode,_R%hux%huD32Modes\t/* offset to 24/32 Bit Mode parms */\n", hres, vres); + fprintf(fd, "\tOSLstEntry\tsixthVidMode,_R%hux%huD16Modes\t/* offset to 15/16 Bit Mode parms */\n", hres, vres); + fprintf(fd, "\t.long EndOfList\t/* end of list */\n\n"); + } + } + fclose(fd); + } + + { + char filename[512]; + FILE *fd; + unsigned char id = 0x80; + snprintf(filename, 512, "VidRomDir.s"); + fd = fopen(filename, "w"); + if (fd == NULL) { + fprintf(stderr, "Generating '%s' failed.\n", filename); + return -1; + } + + fprintf(fd, "\t.include \"VidRomDir_%hux%hu.s\"\n", maxhres, maxvres); + + fclose(fd); + } + + + { + char filename[512]; + FILE *fd; + unsigned char id = 0x80; + snprintf(filename, 512, "VidRomDef.s"); + fd = fopen(filename, "w"); + if (fd == NULL) { + fprintf(stderr, "Generating '%s' failed.\n", filename); + return -1; + } + + for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) ; i++) { + const unsigned short hres = res_db[i].hres; + const unsigned short vres = res_db[i].vres; + if (enabled[i]) { + fprintf(fd, "sRsrc_GoboFB_R%hux%hu = 0x%02hhx\n", hres, vres, id++); + } + } + + fclose(fd); + } + + { + char filename[512]; + FILE *fd; + snprintf(filename, 512, "VidRomRsrcDir.s"); + fd = fopen(filename, "w"); + if (fd == NULL) { + fprintf(stderr, "Generating '%s' failed.\n", filename); + return -1; + } + fprintf(fd, "_sRsrcDir:\n"); + fprintf(fd, "\tOSLstEntry\tsRsrc_Board,_sRsrc_Board\t/* board sRsrc List */\n"); + for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) ; i++) { + const unsigned short hres = res_db[i].hres; + const unsigned short vres = res_db[i].vres; + if (enabled[i]) { + fprintf(fd, "\tOSLstEntry\tsRsrc_GoboFB_R%hux%hu,_sRsrc_GoboFB_R%hux%hu/* video sRsrc List */\n", hres, vres, hres, vres); + } + } +#ifdef ENABLE_RAMDSK + fprintf(fd, "\tOSLstEntry\tsRsrc_RAMDsk,_sRsrc_RAMDsk\n"); +#endif +#ifdef ENABLE_SDCARD + fprintf(fd, "\tOSLstEntry\tsRsrc_SDCard,_sRsrc_SDCard\n"); +#endif +#ifdef ENABLE_HDMIAUDIO + fprintf(fd, "\tOSLstEntry\tsRsrc_HDMIAudio,_sRsrc_HDMIAudio\n"); +#endif + fprintf(fd, "\tDatLstEntry endOfList, 0\n"); + + fclose(fd); + } + + + return 0; +} diff --git a/DeclROM/linker.ld b/DeclROM/linker.ld new file mode 100644 index 0000000..1ce9b55 --- /dev/null +++ b/DeclROM/linker.ld @@ -0,0 +1,50 @@ +OUTPUT_FORMAT("elf32-m68k"); +ENTRY(DeclROMDir); + +SECTIONS { + .text : { + /* first the resource dir & related */ + *(.text.begin) + *(.text .sdata .sdata.* .data .data.* .rodata .rodata.*) + + /* then various sections for the various bits of codes */ + PROVIDE(_sPInitRec = .); + PROVIDE(entry_sPInitRec = (0x22000000 | ((_sPInitRec - _sRsrc_Board - 12) & 0xFFFFFF))); /* fixme; offset 12 hardwired */ + *(.text.primary_init) + *(.text.primary) + PROVIDE(_EndsPInitRec = .); + PROVIDE(size_sPInitRec = _EndsPInitRec - _sPInitRec); + + PROVIDE(_sSInitRec = .); + PROVIDE(entry_sSInitRec = (0x24000000 | ((_sSInitRec - _sRsrc_Board - 20) & 0xFFFFFF))); /* fixme; offset 20 hardwired */ + *(.text.secondary_init) + *(.text.secondary) + PROVIDE(_EndsSInitRec = .); + PROVIDE(size_sSInitRec = _EndsSInitRec - _sSInitRec); + + PROVIDE(_GoboFBDrvrMacOS68020 = .); + PROVIDE(entry_GoboFBDrvrMacOS68020 = (0x02000000 | ((_GoboFBDrvrMacOS68020 - _GoboFBDrvrDir) & 0xFFFFFF))); + *(.text.fbdriver_init) + *(.text.fbdriver) + PROVIDE(_GoboFBEnd020Drvr = .); + + PROVIDE(_RAMDskDrvrMacOS68020 = .); + PROVIDE(entry_RAMDskDrvrMacOS68020 = (0x02000000 | ((_RAMDskDrvrMacOS68020 - _RAMDskDrvrDir) & 0xFFFFFF))); + *(.text.dskdriver_init) + *(.text.dskdriver) + PROVIDE(_RAMDskEnd020Drvr = .); + + PROVIDE(_SDCardDrvrMacOS68020 = .); + PROVIDE(entry_SDCardDrvrMacOS68020 = (0x02000000 | ((_SDCardDrvrMacOS68020 - _SDCardDrvrDir) & 0xFFFFFF))); + *(.text.sddriver_init) + *(.text.sddriver) + PROVIDE(_SDCardEnd020Drvr = .); + + /* and at the end the ROM block, missing only the CRC */ + . = ALIGN(4); + *(.romblock) + PROVIDE(ROMSize = .); + PROVIDE(RsrcDirOffset = ((0-.)+20) & 0xFFFFFF); + } + /DISCARD/ : { *(*) } +} diff --git a/DeclROM/myrle.c b/DeclROM/myrle.c new file mode 100644 index 0000000..facd340 --- /dev/null +++ b/DeclROM/myrle.c @@ -0,0 +1,151 @@ +#include + +//#include + +#include "NuBusFPGARAMDskDrvr.h" + +#ifndef SKIP_MAIN +uint32_t rleenc(uint32_t* out, const uint32_t* in, const uint32_t len) { + uint32_t i = 0, j = 0, p = 0, ib, k; + int32_t c = 0; + + p = in[0]; + + for (i = 1 ; i < len ; i++) { + if (c == 0) { // just started + if (in[i] == p) { // repeat + c++; + } else { // non-repeat + p = in[i]; + c--; + ib = i - 1; + } + } else if (c > 0) { // in-repeat + if (in[i] == p) { // keep repeating + c++; + } else { // exit repeat + out[j++] = __builtin_bswap32(c); // write result + out[j++] = p; + p = in[i]; // restart + c = 0; + } + } else { // c < 0 + if (in[i] == p) { // exit non-repeat + out[j++] = __builtin_bswap32(c+1); // write result, removing previous + for (k = 0 ; k < (-c) ; k++) + out[j++] = in[ib+k]; + p = in[i]; // restart + c = 1; // this and previous + } else { // non-repeat + p = in[i]; + c--; + } + } + + } + out[j++] = __builtin_bswap32(c); + out[j++] = p; + + return j; +} +#endif + + +uint32_t rledec(uint32_t* out, const uint32_t* in, const uint32_t len) { + uint32_t i = 0, j = 0, k = 0, chk = 0, ib; + + for (i = 0 ; i < len ; ) { +#ifndef __m68k__ + int32_t c = (int32_t)__builtin_bswap32(in[i]); +#else + int32_t c = (int32_t)(in[i]); +#endif + if (c >= 0) { + chk += (1 + c); + if (c < 300000) { // !!!!!!!!!!!!!!!!!!!!!!!!!! + for (k = 0 ; k < (c + 1) ; k++) + out[j++] = in[i+1]; + } else { // do a small subset at the beginning and end instead of the full range and assume this is padding otherwise + for (k = 0 ; k < 4 ; k++) + out[j+k] = in[i+1]; + for (k = c-3 ; k < (c + 1) ; k++) + out[j+k] = in[i+1]; + j += c+1; + } + i += 2; + } else { + chk += (1 + -c); + for (k = 0 ; k < (1 + -c) ; k++) + out[j++] = in[i+1+k]; + i += 2 + -c; + } + //fprintf(stderr, "%u: %u <> %u (%d, 0x%08x)\n", i, j, chk, c, in[i+1]); + } + return j; +} + +#ifndef SKIP_MAIN +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) { + int fd; + uint32_t len, k; + uint32_t *bufa, *bufb; + FILE* f; + + bufa = calloc(sizeof(uint32_t), 256*1024*1024/sizeof(uint32_t)); + bufb = calloc(sizeof(uint32_t), 256*1024*1024/sizeof(uint32_t)); + + fd = open("dump.raw", O_RDONLY); + len = read(fd, bufa, 248*1024*1024ull) / 4; + close(fd); + + printf("File : %d bytes\n", len*4); + + len = rleenc(bufb, bufa, len); + + printf("Compressed : %d bytes\n", len*4); + + /* for (k = 0 ; k < len ; k++) */ + /* bufb[k] = __builtin_bswap32(bufb[k]); */ + + fd = open("dump.cpr", O_WRONLY | O_CREAT, S_IRWXU); + /* len = */write (fd, bufb, len*4); + close(fd); + + /* for (k = 0 ; k < len ; k++) */ + /* bufb[k] = __builtin_bswap32(bufb[k]); */ + + f = fopen("dump_cpr.c", "w"); + /* fprintf(f, "unsigned char* compressed[%d] = {\n", len*4); */ + /* for (k = 0 ; k < len*4 ; k++) { */ + /* fprintf(f, "0x%02x%s", ((unsigned char*)bufb)[k], */ + /* k == (len*4-1) ? "};" : (k%16 == 15 ? ",\n" : ",") */ + /* ); */ + /* } */ + fprintf(f, "unsigned long* compressed[%d] = {\n", len); + for (k = 0 ; k < len ; k++) { + fprintf(f, "0x%08x%s", bufb[k], + k == (len-1) ? "};" : (k%8 == 7 ? ",\n" : ",") + ); + } + fclose(f); + + len = rledec(bufa, bufb, len); + + printf("Uncompressed : %d bytes\n", len*4); + + fd = open("dump.ucp", O_WRONLY | O_CREAT, S_IRWXU); + len = write (fd, bufa, len*4); + close(fd); + + return 0; +} + +#endif diff --git a/DeclROM/ns816-declrom b/DeclROM/ns816-declrom new file mode 160000 index 0000000..6182427 --- /dev/null +++ b/DeclROM/ns816-declrom @@ -0,0 +1 @@ +Subproject commit 618242763e1cda7da667e875c322f66c9b3afe96 diff --git a/DeclROM/nubusfpga_csr_common.h b/DeclROM/nubusfpga_csr_common.h new file mode 100644 index 0000000..ba5f615 --- /dev/null +++ b/DeclROM/nubusfpga_csr_common.h @@ -0,0 +1,214 @@ +#ifndef __NUBUSFPGA_CSR_COMMON_H__ +#define __NUBUSFPGA_CSR_COMMON_H__ + +/* from hw/common.h, +a32 */ + +#define CONFIG_CSR_DATA_WIDTH 32 + +/* CSR data width (subreg. width) in bytes, for direct comparson to sizeof() */ +#define CSR_DW_BYTES (CONFIG_CSR_DATA_WIDTH/8) +#define CSR_OFFSET_BYTES 4 + +/* Number of subregs required for various total byte sizes, by subreg width: + * NOTE: 1, 2, 4, and 8 bytes represent uint[8|16|32|64]_t C types; However, + * CSRs of intermediate byte sizes (24, 40, 48, and 56) are NOT padded + * (with extra unallocated subregisters) to the next valid C type! + * +-----+-----------------+ + * | csr | bytes | + * | _dw | 1 2 3 4 5 6 7 8 | + * | |-----=---=-=-=---| + * | 1 | 1 2 3 4 5 6 7 8 | + * | 2 | 1 1 2 2 3 3 4 4 | + * | 4 | 1 1 1 1 2 2 2 2 | + * | 8 | 1 1 1 1 1 1 1 1 | + * +-----+-----------------+ */ +static inline int num_subregs(int csr_bytes) +{ + return (csr_bytes - 1) / CSR_DW_BYTES + 1; +} + +/* Read a CSR of size 'csr_bytes' located at address 'a'. */ +static inline uint64_t _csr_rd(uint32_t a32, unsigned long a, int csr_bytes) +{ + uint64_t r = __builtin_bswap32(*((uint32_t*)(a32 + a))); + for (int i = 1; i < num_subregs(csr_bytes); i++) { + r <<= CONFIG_CSR_DATA_WIDTH; + a += CSR_OFFSET_BYTES; + r |= __builtin_bswap32(*((uint32_t*)(a32 + a))); + } + return r; +} + +/* Write value 'v' to a CSR of size 'csr_bytes' located at address 'a'. */ +static inline void _csr_wr(uint32_t a32, unsigned long a, uint64_t v, int csr_bytes) +{ + int ns = num_subregs(csr_bytes); + for (int i = 0; i < ns; i++) { + *((uint32_t*)(a32 + a)) = __builtin_bswap32(v >> (CONFIG_CSR_DATA_WIDTH * (ns - 1 - i))); + a += CSR_OFFSET_BYTES; + } +} + +// FIXME: - should we provide 24, 40, 48, and 56 bit csr_[rd|wr] methods? + +static inline uint8_t csr_rd_uint8(uint32_t a32, unsigned long a) +{ + return _csr_rd(a32, a, sizeof(uint8_t)); +} + +static inline void csr_wr_uint8(uint32_t a32, uint8_t v, unsigned long a) +{ + _csr_wr(a32, a, v, sizeof(uint8_t)); +} + +static inline uint16_t csr_rd_uint16(uint32_t a32, unsigned long a) +{ + return _csr_rd(a32, a, sizeof(uint16_t)); +} + +static inline void csr_wr_uint16(uint32_t a32, uint16_t v, unsigned long a) +{ + _csr_wr(a32, a, v, sizeof(uint16_t)); +} + +static inline uint32_t csr_rd_uint32(uint32_t a32, unsigned long a) +{ + return _csr_rd(a32, a, sizeof(uint32_t)); +} + +static inline void csr_wr_uint32(uint32_t a32, uint32_t v, unsigned long a) +{ + _csr_wr(a32, a, v, sizeof(uint32_t)); +} + +static inline uint64_t csr_rd_uint64(uint32_t a32, unsigned long a) +{ + return _csr_rd(a32, a, sizeof(uint64_t)); +} + +static inline void csr_wr_uint64(uint32_t a32, uint64_t v, unsigned long a) +{ + _csr_wr(a32, a, v, sizeof(uint64_t)); +} + +/* Read a CSR located at address 'a' into an array 'buf' of 'cnt' elements. + * + * NOTE: Since CSR_DW_BYTES is a constant here, we might be tempted to further + * optimize things by leaving out one or the other of the if() branches below, + * depending on each unsigned type width; + * However, this code is also meant to serve as a reference for how CSRs are + * to be manipulated by other programs (e.g., an OS kernel), which may benefit + * from dynamically handling multiple possible CSR subregister data widths + * (e.g., by passing a value in through the Device Tree). + * Ultimately, if CSR_DW_BYTES is indeed a constant, the compiler should be + * able to determine on its own whether it can automatically optimize away one + * of the if() branches! */ +#define _csr_rd_buf(a32, a, buf, cnt) \ + { \ + int i, j, nsubs, n_sub_elem; \ + uint64_t r; \ + if (sizeof(buf[0]) >= CSR_DW_BYTES) { \ + /* one or more subregisters per element */ \ + for (i = 0; i < cnt; i++) { \ + buf[i] = _csr_rd(a32, a, sizeof(buf[0])); \ + a += CSR_OFFSET_BYTES * num_subregs(sizeof(buf[0])); \ + } \ + } else { \ + /* multiple elements per subregister (2, 4, or 8) */ \ + nsubs = num_subregs(sizeof(buf[0]) * cnt); \ + n_sub_elem = CSR_DW_BYTES / sizeof(buf[0]); \ + for (i = 0; i < nsubs; i++) { \ + r = __builtin_bswap32(*(uint32_t*)(a32 + a)); \ + for (j = n_sub_elem - 1; j >= 0; j--) { \ + if (i * n_sub_elem + j < cnt) \ + buf[i * n_sub_elem + j] = r; \ + r >>= sizeof(buf[0]) * 8; \ + } \ + a += CSR_OFFSET_BYTES; \ + } \ + } \ + } +/* Write an array 'buf' of 'cnt' elements to a CSR located at address 'a'. + * + * NOTE: The same optimization considerations apply here as with _csr_rd_buf() + * above. + */ +#define _csr_wr_buf(a32, a, buf, cnt) \ +{ \ + int i, j, nsubs, n_sub_elem; \ + uint64_t v; \ + if (sizeof(buf[0]) >= CSR_DW_BYTES) { \ + /* one or more subregisters per element */ \ + for (i = 0; i < cnt; i++) { \ + _csr_wr(a32, a, buf[i], sizeof(buf[0])); \ + a += CSR_OFFSET_BYTES * num_subregs(sizeof(buf[0])); \ + } \ + } else { \ + /* multiple elements per subregister (2, 4, or 8) */ \ + nsubs = num_subregs(sizeof(buf[0]) * cnt); \ + n_sub_elem = CSR_DW_BYTES / sizeof(buf[0]); \ + for (i = 0; i < nsubs; i++) { \ + v = buf[i * n_sub_elem + 0]; \ + for (j = 1; j < n_sub_elem; j++) { \ + if (i * n_sub_elem + j == cnt) \ + break; \ + v <<= sizeof(buf[0]) * 8; \ + v |= buf[i * n_sub_elem + j]; \ + } \ + *((uint32_t*)(a32 + a)) = __builtin_bswap32(v); \ + a += CSR_OFFSET_BYTES; \ + } \ + } \ +} + +static inline void csr_rd_buf_uint8(uint32_t a32, unsigned long a, uint8_t *buf, int cnt) +{ + _csr_rd_buf(a32, a, buf, cnt); +} + +static inline void csr_wr_buf_uint8(uint32_t a32, unsigned long a, + const uint8_t *buf, int cnt) +{ + _csr_wr_buf(a32, a, buf, cnt); +} + +static inline void csr_rd_buf_uint16(uint32_t a32, unsigned long a, uint16_t *buf, int cnt) +{ + _csr_rd_buf(a32, a, buf, cnt); +} + +static inline void csr_wr_buf_uint16(uint32_t a32, unsigned long a, + const uint16_t *buf, int cnt) +{ + _csr_wr_buf(a32, a, buf, cnt); +} + +static inline void csr_rd_buf_uint32(uint32_t a32, unsigned long a, uint32_t *buf, int cnt) +{ + _csr_rd_buf(a32, a, buf, cnt); +} + +static inline void csr_wr_buf_uint32(uint32_t a32, unsigned long a, + const uint32_t *buf, int cnt) +{ + _csr_wr_buf(a32, a, buf, cnt); +} + +/* NOTE: the macros' "else" branch is unreachable, no need to be warned + * about a >= 64bit left shift! */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshift-count-overflow" +static inline void csr_rd_buf_uint64(uint32_t a32, unsigned long a, uint64_t *buf, int cnt) +{ + _csr_rd_buf(a32, a, buf, cnt); +} + +static inline void csr_wr_buf_uint64(uint32_t a32, unsigned long a, + const uint64_t *buf, int cnt) +{ + _csr_wr_buf(a32, a, buf, cnt); +} +#pragma GCC diagnostic pop + + +#endif // __NUBUSFPGA_CSR_COMMON_H__ diff --git a/DeclROM/vid_decl_rom.s b/DeclROM/vid_decl_rom.s new file mode 100644 index 0000000..473f446 --- /dev/null +++ b/DeclROM/vid_decl_rom.s @@ -0,0 +1,228 @@ + .include "atrap.inc" + .include "globals.inc" + .include "declrom.inc" + + .include "ROMDefs.inc" + .include "Video.inc" + .include "DepVideo.inc" + +sRsrc_Board = 1 /* board sResource (>0 & <128) */ + .include "VidRomDef.s" +sRsrc_RAMDsk = 0x90 /* functional sResources */ +sRsrc_SDCard = 0x91 /* functional sResources */ +sRsrc_HDMIAudio = 0xA0 /* functional sResources */ + + .global DeclROMDir + + .section .text.begin + + .include "VidRomRsrcDir.s" + + .global _sRsrc_Board +_sRsrc_Board: + OSLstEntry sRsrcType,_BoardType /* offset to board descriptor */ + OSLstEntry sRsrcName,_BoardName /* offset to name of board */ + DatLstEntry boardId,NuBusFPGAID /* board ID # (assigned by DTS) */ + /* OSLstEntry primaryInit,_sPInitRec */ /* offset to PrimaryInit exec blk */ + .long entry_sPInitRec + OSLstEntry vendorInfo,_VendorInfo /* offset to vendor info record */ + /* OSLstEntry secondaryInit,_sSInitRec */ /* offset to SecondaryInit block */ + .long entry_sSInitRec + OSLstEntry sRsrcVidNames, _VModeName /* video name directory */ + .long EndOfList + +_BoardType: + .short catBoard /* board sResource */ + .short typeBoard + .short 0 + .short 0 + +_BoardName: + .string "NuBusFPGA GoboFB\0" /* name of board */ + ALIGN 2 + +/* _VidICON ; optional icon, not needed */ +/* _sVidNameDir ; optional name(s), not needed */ + + .section .text.primary_init +/* _sPInitRec: */ + /* .long _EndsPInitRec-_sPInitRec */ /* physical block size */ + .long size_sPInitRec + .byte sExec2 /* Code revision (Primary init) */ + .byte sCPU68020 /* CPU type is 68020 */ + .short 0 /* Reserved */ + .long Primary-. /* Offset to C code. */ + ALIGN 2 +/* _EndsPInitRec: */ + + .section .text.secondary_init +/* _sSInitRec: */ + /* .long _EndsSInitRec-_sSInitRec */ /* physical block size */ + .long size_sSInitRec + .byte sExec2 /* Code revision (Primary init) */ + .byte sCPU68020 /* CPU type is 68020 */ + .short 0 /* Reserved */ + .long Secondary-. /* Offset to C code. */ + ALIGN 2 +/* _EndsSInitRec: */ + + .section .text.begin + ALIGN 2 +_VendorInfo: + OSLstEntry vendorId,_VendorId /* offset to vendor ID */ + OSLstEntry serialNum,_SerialNum /* offset to revision */ + OSLstEntry revLevel,_RevLevel /* offset to revision */ + OSLstEntry partNum,_PartNum /* offset to part number record */ + OSLstEntry date,_Date /* offset to ROM build date */ + .long EndOfList + +_VendorId: + .string "Romain Dolbeau\0" /* vendor ID */ +_SerialNum: + .string "0000000001\0" /* serial number */ +_RevLevel: + .string "NuBusFPGA V1.0\0" /* revision level */ +_PartNum: + .string "Part Number\0" /* part number */ +_Date: + .string "&SysDate" /* date */ + + .include "VidRomName.s" /* contains _VidName */ + + .include "VidRomDir.s" + + ALIGN 2 +_GoboFBType: + .short catDisplay /* */ + .short typeVideo /* */ + .short drSwApple /* */ + .short DrHwNuBusFPGA /* */ + +_GoboFBName: + .string "GoboFB_NuBusFPGA" /* video driver name */ + +_MinorBase: + .long defMinorBase /* frame buffer offset */ +_MinorLength: + .long defMinorLength /* frame buffer length */ + + ALIGN 2 + .section .text.begin + .global _GoboFBDrvrDir +_GoboFBDrvrDir: + /* OSLstEntry sMacOS68020,_GoboFBDrvrMacOS68020 */ /* driver directory for Mac OS */ + .long entry_GoboFBDrvrMacOS68020 + .long EndOfList + + ALIGN 2 + .section .text.fbdriver_init +/* _GoboFBDrvrMacOS68020: */ /* supplied by linker script */ + .long _GoboFBEnd020Drvr-. /* physical block size */ + .include "NuBusFPGADrvr.s" /* driver code */ +/* _GoboFBEnd020Drvr: */ /* supplied by linker script */ + + .section .text.begin + .include "VidRomRes.s" +/* ////////////////////////////////////////////// RAM DISK */ + .section .text.begin + ALIGN 2 +_sRsrc_RAMDsk: + OSLstEntry sRsrcType,_RAMDskType /* video type descriptor */ + OSLstEntry sRsrcName,_RAMDskName /* offset to driver name string */ + OSLstEntry sRsrcDrvrDir,_RAMDskDrvrDir /* offset to driver directory */ + DatLstEntry sRsrcFlags,6 /* force 32 bits mode & open */ + DatLstEntry sRsrcHWDevId,2 /* hardware device ID */ + .long EndOfList /* end of list */ + + ALIGN 2 +_RAMDskType: + .short catProto /* */ + .short typeDrive /* custom */ /* */ + .short drSwApple /* */ + .short DrHwNuBusFPGADsk /* */ + +_RAMDskName: + .string "RAMDsk_NuBusFPGA" /* video driver name */ + + ALIGN 2 + .section .text.begin + .global _RAMDskDrvrDir +_RAMDskDrvrDir: + /* OSLstEntry sMacOS68020,_RAMDskDrvrMacOS68020 */ /* driver directory for Mac OS */ + .long entry_RAMDskDrvrMacOS68020 + .long EndOfList + + ALIGN 2 + .section .text.dskdriver_init +/* _RAMDskDrvrMacOS68020: */ /* supplied by linker script */ + .long _RAMDskEnd020Drvr-. /* physical block size */ + .include "NuBusFPGARAMDskDrvr.s" /* driver code */ +/* _RAMDskEnd020Drvr: */ /* supplied by linker script */ + +/* ////////////////////////////////////////////// SDCARD */ + .section .text.begin + ALIGN 2 +_sRsrc_SDCard: + OSLstEntry sRsrcType,_SDCardType /* video type descriptor */ + OSLstEntry sRsrcName,_SDCardName /* offset to driver name string */ + OSLstEntry sRsrcDrvrDir,_SDCardDrvrDir /* offset to driver directory */ + DatLstEntry sRsrcFlags,6 /* force 32 bits mode & open */ + DatLstEntry sRsrcHWDevId,2 /* hardware device ID */ + .long EndOfList /* end of list */ + + ALIGN 2 +_SDCardType: + .short catProto /* */ + .short typeDrive /* custom */ /* */ + .short drSwApple /* */ + .short DrHwNuBusFPGASDCard /* */ + +_SDCardName: + .string "SDCard_NuBusFPGA" /* video driver name */ + + ALIGN 2 + .section .text.begin + .global _SDCardDrvrDir +_SDCardDrvrDir: + /* OSLstEntry sMacOS68020,_SDCardDrvrMacOS68020 */ /* driver directory for Mac OS */ + .long entry_SDCardDrvrMacOS68020 + .long EndOfList + + ALIGN 2 + .section .text.sddriver_init +/* _SDCardDrvrMacOS68020: */ /* supplied by linker script */ + .long _SDCardEnd020Drvr-. /* physical block size */ + .include "NuBusFPGASDCardDrvr.s" /* driver code */ +/* _SDCardEnd020Drvr: */ /* supplied by linker script */ + + +/* ////////////////////////////////////////////// HDMI AUDIO */ + .section .text.begin + ALIGN 2 +_sRsrc_HDMIAudio: + OSLstEntry sRsrcType,_HDMIAudioType /* video type descriptor */ + .long EndOfList /* end of list */ + + ALIGN 2 +_HDMIAudioType: + .short catProto /* */ + .short typeAudio /* custom */ /* */ + .short drSwApple /* */ + .short DrHwNuBusFPGAAudio /* */ + + + /* Declaration ROM directory at end */ + .section .romblock + ALIGN 2 +DeclROMDir: + .long RsrcDirOffset /* supplied by linker script, replace OSLstEntry 0, _sRsrcDir */ +DeclROMCRC: + .long ROMSize /* supplied by linker script */ + .long 0 /* crc TBComputed after the fact */ + .byte 1 /* Revision Level */ + .byte appleFormat /* Apple Format */ + .long testPattern /* magic TestPattern */ + .byte 0 /* reserved */ + .byte 0x0F /* byte lane marker */ +DeclRomEnd: + .end